From 8c6be0b796ed4948d6c4882a9cb68d9bab981ba8 Mon Sep 17 00:00:00 2001 From: Jinkun Jang Date: Wed, 13 Mar 2013 01:49:46 +0900 Subject: [PATCH] Tizen 2.1 base --- AUTHORS | 15 +- COPYING.LIB | 502 ++++ Makefile.am | 20 +- NEWS | 132 +- README | 82 +- autogen.sh | 41 +- configure.ac | 605 ++++- debian.upstream/Makefile.am | 52 + debian.upstream/changelog.in | 5 + debian.upstream/compat | 1 + debian.upstream/control.in | 99 + debian.upstream/copyright | 35 + debian.upstream/gstreamer-vaapi-doc.install.in | 1 + debian.upstream/gstreamer-vaapi.install.in | 1 + debian.upstream/libgstvaapi-dev.install.in | 3 + debian.upstream/libgstvaapi-drm.install.in | 1 + debian.upstream/libgstvaapi-glx.install.in | 1 + debian.upstream/libgstvaapi-wayland.install.in | 1 + debian.upstream/libgstvaapi-x11.install.in | 1 + debian.upstream/libgstvaapi.install.in | 1 + debian.upstream/rules | 29 + docs/Makefile.am | 10 + docs/reference/Makefile.am | 4 + docs/reference/libs/Makefile.am | 140 ++ docs/reference/libs/libs-docs.xml.in | 52 + docs/reference/libs/libs-overrides.txt | 0 docs/reference/libs/libs-sections.txt | 566 +++++ docs/reference/libs/libs.core.types | 14 + docs/reference/libs/libs.glx.types | 3 + docs/reference/libs/libs.x11.types | 2 + docs/reference/plugins/Makefile.am | 108 + docs/reference/plugins/plugins-docs.xml.in | 32 + docs/reference/plugins/plugins-overrides.txt | 0 docs/reference/plugins/plugins-sections.txt | 69 + docs/reference/plugins/plugins.types | 5 + gst-libs/gst/Makefile.am | 4 +- gst-libs/gst/codecparsers/Makefile.am | 43 + gst-libs/gst/codecparsers/gstjpegparser.c | 610 +++++ gst-libs/gst/codecparsers/gstjpegparser.h | 414 ++++ gst-libs/gst/vaapi/Makefile.am | 380 ++- gst-libs/gst/vaapi/glibcompat.h | 77 + gst-libs/gst/vaapi/gstvaapi_priv.h | 28 + gst-libs/gst/vaapi/gstvaapibaseencoder.c | 1006 ++++++++ gst-libs/gst/vaapi/gstvaapibaseencoder.h | 144 ++ gst-libs/gst/vaapi/gstvaapicodec_objects.c | 306 +++ gst-libs/gst/vaapi/gstvaapicodec_objects.h | 400 ++++ gst-libs/gst/vaapi/gstvaapicompat.h | 54 + gst-libs/gst/vaapi/gstvaapicontext.c | 1038 +++++++++ gst-libs/gst/vaapi/gstvaapicontext.h | 155 ++ gst-libs/gst/vaapi/gstvaapidebug.h | 64 + gst-libs/gst/vaapi/gstvaapidecoder.c | 670 ++++++ gst-libs/gst/vaapi/gstvaapidecoder.h | 138 ++ gst-libs/gst/vaapi/gstvaapidecoder_dpb.c | 340 +++ gst-libs/gst/vaapi/gstvaapidecoder_dpb.h | 192 ++ gst-libs/gst/vaapi/gstvaapidecoder_h264.c | 2536 +++++++++++++++++++++ gst-libs/gst/vaapi/gstvaapidecoder_h264.h | 87 + gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c | 718 ++++++ gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h | 88 + gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c | 1202 ++++++++++ gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h | 88 + gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c | 1205 ++++++++++ gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h | 88 + gst-libs/gst/vaapi/gstvaapidecoder_objects.c | 440 ++++ gst-libs/gst/vaapi/gstvaapidecoder_objects.h | 295 +++ gst-libs/gst/vaapi/gstvaapidecoder_priv.h | 196 ++ gst-libs/gst/vaapi/gstvaapidecoder_vc1.c | 1344 +++++++++++ gst-libs/gst/vaapi/gstvaapidecoder_vc1.h | 88 + gst-libs/gst/vaapi/gstvaapidisplay.c | 1719 ++++++++++++++ gst-libs/gst/vaapi/gstvaapidisplay.h | 264 +++ gst-libs/gst/vaapi/gstvaapidisplay_drm.c | 532 +++++ gst-libs/gst/vaapi/gstvaapidisplay_drm.h | 97 + gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h | 55 + gst-libs/gst/vaapi/gstvaapidisplay_glx.c | 116 + gst-libs/gst/vaapi/gstvaapidisplay_glx.h | 90 + gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h | 34 + gst-libs/gst/vaapi/gstvaapidisplay_priv.h | 98 + gst-libs/gst/vaapi/gstvaapidisplay_wayland.c | 538 +++++ gst-libs/gst/vaapi/gstvaapidisplay_wayland.h | 94 + gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h | 65 + gst-libs/gst/vaapi/gstvaapidisplay_x11.c | 605 +++++ gst-libs/gst/vaapi/gstvaapidisplay_x11.h | 98 + gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h | 68 + gst-libs/gst/vaapi/gstvaapidisplaycache.c | 380 +++ gst-libs/gst/vaapi/gstvaapidisplaycache.h | 76 + gst-libs/gst/vaapi/gstvaapiencoder.c | 440 ++++ gst-libs/gst/vaapi/gstvaapiencoder.h | 288 +++ gst-libs/gst/vaapi/gstvaapiencoder_h263.c | 326 +++ gst-libs/gst/vaapi/gstvaapiencoder_h263.h | 100 + gst-libs/gst/vaapi/gstvaapiencoder_h264.c | 2209 ++++++++++++++++++ gst-libs/gst/vaapi/gstvaapiencoder_h264.h | 143 ++ gst-libs/gst/vaapi/gstvaapiencoder_mpeg4.c | 523 +++++ gst-libs/gst/vaapi/gstvaapiencoder_mpeg4.h | 103 + gst-libs/gst/vaapi/gstvaapiimage.c | 1698 ++++++++++++++ gst-libs/gst/vaapi/gstvaapiimage.h | 217 ++ gst-libs/gst/vaapi/gstvaapiimageformat.c | 316 +++ gst-libs/gst/vaapi/gstvaapiimageformat.h | 94 + gst-libs/gst/vaapi/gstvaapiimagepool.c | 127 ++ gst-libs/gst/vaapi/gstvaapiimagepool.h | 88 + gst-libs/gst/vaapi/gstvaapiobject.c | 256 +++ gst-libs/gst/vaapi/gstvaapiobject.h | 101 + gst-libs/gst/vaapi/gstvaapiobject_priv.h | 166 ++ gst-libs/gst/vaapi/gstvaapiparamspecs.c | 140 ++ gst-libs/gst/vaapi/gstvaapiparamspecs.h | 71 + gst-libs/gst/vaapi/gstvaapiprofile.c | 392 ++++ gst-libs/gst/vaapi/gstvaapiprofile.h | 160 ++ gst-libs/gst/vaapi/gstvaapisubpicture.c | 334 +++ gst-libs/gst/vaapi/gstvaapisubpicture.h | 109 + gst-libs/gst/vaapi/gstvaapisurface.c | 942 ++++++++ gst-libs/gst/vaapi/gstvaapisurface.h | 252 ++ gst-libs/gst/vaapi/gstvaapisurface_priv.h | 39 + gst-libs/gst/vaapi/gstvaapisurface_userptr.c | 303 +++ gst-libs/gst/vaapi/gstvaapisurface_userptr.h | 98 + gst-libs/gst/vaapi/gstvaapisurfacepool.c | 142 ++ gst-libs/gst/vaapi/gstvaapisurfacepool.h | 88 + gst-libs/gst/vaapi/gstvaapisurfaceproxy.c | 431 ++++ gst-libs/gst/vaapi/gstvaapisurfaceproxy.h | 169 ++ gst-libs/gst/vaapi/gstvaapitexture.c | 683 ++++++ gst-libs/gst/vaapi/gstvaapitexture.h | 134 ++ gst-libs/gst/vaapi/gstvaapitypes.h | 175 ++ gst-libs/gst/vaapi/gstvaapiutils.c | 354 +++ gst-libs/gst/vaapi/gstvaapiutils.h | 104 + gst-libs/gst/vaapi/gstvaapiutils_glx.c | 1192 ++++++++++ gst-libs/gst/vaapi/gstvaapiutils_glx.h | 218 ++ gst-libs/gst/vaapi/gstvaapiutils_x11.c | 154 ++ gst-libs/gst/vaapi/gstvaapiutils_x11.h | 52 + gst-libs/gst/vaapi/gstvaapivalue.c | 241 ++ gst-libs/gst/vaapi/gstvaapivalue.h | 95 + gst-libs/gst/vaapi/gstvaapivideobuffer.c | 665 ++++++ gst-libs/gst/vaapi/gstvaapivideobuffer.h | 141 ++ gst-libs/gst/vaapi/gstvaapivideobuffer_glx.c | 55 + gst-libs/gst/vaapi/gstvaapivideobuffer_glx.h | 85 + gst-libs/gst/vaapi/gstvaapivideobuffer_priv.h | 59 + gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c | 143 ++ gst-libs/gst/vaapi/gstvaapivideoconverter_glx.h | 75 + gst-libs/gst/vaapi/gstvaapivideopool.c | 516 +++++ gst-libs/gst/vaapi/gstvaapivideopool.h | 123 + gst-libs/gst/vaapi/gstvaapiwindow.c | 512 +++++ gst-libs/gst/vaapi/gstvaapiwindow.h | 153 ++ gst-libs/gst/vaapi/gstvaapiwindow_drm.c | 161 ++ gst-libs/gst/vaapi/gstvaapiwindow_drm.h | 85 + gst-libs/gst/vaapi/gstvaapiwindow_glx.c | 604 +++++ gst-libs/gst/vaapi/gstvaapiwindow_glx.h | 113 + gst-libs/gst/vaapi/gstvaapiwindow_wayland.c | 340 +++ gst-libs/gst/vaapi/gstvaapiwindow_wayland.h | 89 + gst-libs/gst/vaapi/gstvaapiwindow_x11.c | 625 +++++ gst-libs/gst/vaapi/gstvaapiwindow_x11.h | 114 + gst-libs/gst/vaapi/gstvaapiworkarounds.h | 41 + gst-libs/gst/vaapi/sysdeps.h | 31 + gst/Makefile.am | 4 + gst/vaapi/Makefile.am | 91 + gst/vaapi/gstvaapi.c | 90 + gst/vaapi/gstvaapidecode.c | 790 +++++++ gst/vaapi/gstvaapidecode.h | 89 + gst/vaapi/gstvaapidownload.c | 620 +++++ gst/vaapi/gstvaapidownload.h | 67 + gst/vaapi/gstvaapiencode.c | 728 ++++++ gst/vaapi/gstvaapiencode.h | 95 + gst/vaapi/gstvaapiencode_h263.c | 245 ++ gst/vaapi/gstvaapiencode_h263.h | 69 + gst/vaapi/gstvaapiencode_h264.c | 457 ++++ gst/vaapi/gstvaapiencode_h264.h | 70 + gst/vaapi/gstvaapiencode_mpeg4.c | 270 +++ gst/vaapi/gstvaapiencode_mpeg4.h | 70 + gst/vaapi/gstvaapipluginbuffer.c | 137 ++ gst/vaapi/gstvaapipluginbuffer.h | 49 + gst/vaapi/gstvaapipluginutil.c | 333 +++ gst/vaapi/gstvaapipluginutil.h | 59 + gst/vaapi/gstvaapipostproc.c | 746 ++++++ gst/vaapi/gstvaapipostproc.h | 123 + gst/vaapi/gstvaapisink.c | 1310 +++++++++++ gst/vaapi/gstvaapisink.h | 110 + gst/vaapi/gstvaapiupload.c | 945 ++++++++ gst/vaapi/gstvaapiupload.h | 93 + packaging/gstreamer-vaapi.changes | 32 + packaging/gstreamer-vaapi.manifest | 5 + packaging/gstreamer-vaapi.spec | 70 + pkgconfig/Makefile.am | 33 + pkgconfig/gstreamer-vaapi-drm.pc.in | 12 + pkgconfig/gstreamer-vaapi-glx.pc.in | 12 + pkgconfig/gstreamer-vaapi-wayland.pc.in | 12 + pkgconfig/gstreamer-vaapi-x11.pc.in | 12 + pkgconfig/gstreamer-vaapi.pc.in | 12 + tests/Makefile.am | 99 + tests/image.c | 360 +++ tests/image.h | 49 + tests/output.c | 187 ++ tests/output.h | 55 + tests/test-decode.c | 199 ++ tests/test-decode.h | 37 + tests/test-display.c | 499 ++++ tests/test-h264.c | 1049 +++++++++ tests/test-h264.h | 30 + tests/test-jpeg.c | 2080 +++++++++++++++++ tests/test-jpeg.h | 30 + tests/test-mpeg2.c | 1649 ++++++++++++++ tests/test-mpeg2.h | 30 + tests/test-subpicture-data.c | 1430 ++++++++++++ tests/test-subpicture-data.h | 40 + tests/test-subpicture.c | 229 ++ tests/test-surfaces.c | 132 ++ tests/test-textures.c | 192 ++ tests/test-vc1.c | 1778 +++++++++++++++ tests/test-vc1.h | 30 + tests/test-windows.c | 235 ++ 204 files changed, 59193 insertions(+), 83 deletions(-) create mode 100644 COPYING.LIB create mode 100644 debian.upstream/Makefile.am create mode 100644 debian.upstream/changelog.in create mode 100644 debian.upstream/compat create mode 100644 debian.upstream/control.in create mode 100644 debian.upstream/copyright create mode 100644 debian.upstream/gstreamer-vaapi-doc.install.in create mode 100644 debian.upstream/gstreamer-vaapi.install.in create mode 100644 debian.upstream/libgstvaapi-dev.install.in create mode 100644 debian.upstream/libgstvaapi-drm.install.in create mode 100644 debian.upstream/libgstvaapi-glx.install.in create mode 100644 debian.upstream/libgstvaapi-wayland.install.in create mode 100644 debian.upstream/libgstvaapi-x11.install.in create mode 100644 debian.upstream/libgstvaapi.install.in create mode 100755 debian.upstream/rules create mode 100644 docs/Makefile.am create mode 100644 docs/reference/Makefile.am create mode 100644 docs/reference/libs/Makefile.am create mode 100644 docs/reference/libs/libs-docs.xml.in create mode 100644 docs/reference/libs/libs-overrides.txt create mode 100644 docs/reference/libs/libs-sections.txt create mode 100644 docs/reference/libs/libs.core.types create mode 100644 docs/reference/libs/libs.glx.types create mode 100644 docs/reference/libs/libs.x11.types create mode 100644 docs/reference/plugins/Makefile.am create mode 100644 docs/reference/plugins/plugins-docs.xml.in create mode 100644 docs/reference/plugins/plugins-overrides.txt create mode 100644 docs/reference/plugins/plugins-sections.txt create mode 100644 docs/reference/plugins/plugins.types create mode 100644 gst-libs/gst/codecparsers/Makefile.am create mode 100644 gst-libs/gst/codecparsers/gstjpegparser.c create mode 100644 gst-libs/gst/codecparsers/gstjpegparser.h create mode 100644 gst-libs/gst/vaapi/glibcompat.h create mode 100644 gst-libs/gst/vaapi/gstvaapi_priv.h create mode 100644 gst-libs/gst/vaapi/gstvaapibaseencoder.c create mode 100644 gst-libs/gst/vaapi/gstvaapibaseencoder.h create mode 100644 gst-libs/gst/vaapi/gstvaapicodec_objects.c create mode 100644 gst-libs/gst/vaapi/gstvaapicodec_objects.h create mode 100644 gst-libs/gst/vaapi/gstvaapicompat.h create mode 100644 gst-libs/gst/vaapi/gstvaapicontext.c create mode 100644 gst-libs/gst/vaapi/gstvaapicontext.h create mode 100644 gst-libs/gst/vaapi/gstvaapidebug.h create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder.c create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder.h create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_dpb.c create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_dpb.h create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_h264.c create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_h264.h create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_objects.c create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_objects.h create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_priv.h create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_vc1.c create mode 100644 gst-libs/gst/vaapi/gstvaapidecoder_vc1.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay.c create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_drm.c create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_drm.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_glx.c create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_glx.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_priv.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_wayland.c create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_wayland.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_x11.c create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_x11.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplaycache.c create mode 100644 gst-libs/gst/vaapi/gstvaapidisplaycache.h create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder.c create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder.h create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder_h263.c create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder_h263.h create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder_h264.c create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder_h264.h create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder_mpeg4.c create mode 100644 gst-libs/gst/vaapi/gstvaapiencoder_mpeg4.h create mode 100644 gst-libs/gst/vaapi/gstvaapiimage.c create mode 100644 gst-libs/gst/vaapi/gstvaapiimage.h create mode 100644 gst-libs/gst/vaapi/gstvaapiimageformat.c create mode 100644 gst-libs/gst/vaapi/gstvaapiimageformat.h create mode 100644 gst-libs/gst/vaapi/gstvaapiimagepool.c create mode 100644 gst-libs/gst/vaapi/gstvaapiimagepool.h create mode 100644 gst-libs/gst/vaapi/gstvaapiobject.c create mode 100644 gst-libs/gst/vaapi/gstvaapiobject.h create mode 100644 gst-libs/gst/vaapi/gstvaapiobject_priv.h create mode 100644 gst-libs/gst/vaapi/gstvaapiparamspecs.c create mode 100644 gst-libs/gst/vaapi/gstvaapiparamspecs.h create mode 100644 gst-libs/gst/vaapi/gstvaapiprofile.c create mode 100644 gst-libs/gst/vaapi/gstvaapiprofile.h create mode 100644 gst-libs/gst/vaapi/gstvaapisubpicture.c create mode 100644 gst-libs/gst/vaapi/gstvaapisubpicture.h create mode 100644 gst-libs/gst/vaapi/gstvaapisurface.c create mode 100644 gst-libs/gst/vaapi/gstvaapisurface.h create mode 100644 gst-libs/gst/vaapi/gstvaapisurface_priv.h create mode 100644 gst-libs/gst/vaapi/gstvaapisurface_userptr.c create mode 100644 gst-libs/gst/vaapi/gstvaapisurface_userptr.h create mode 100644 gst-libs/gst/vaapi/gstvaapisurfacepool.c create mode 100644 gst-libs/gst/vaapi/gstvaapisurfacepool.h create mode 100644 gst-libs/gst/vaapi/gstvaapisurfaceproxy.c create mode 100644 gst-libs/gst/vaapi/gstvaapisurfaceproxy.h create mode 100644 gst-libs/gst/vaapi/gstvaapitexture.c create mode 100644 gst-libs/gst/vaapi/gstvaapitexture.h create mode 100644 gst-libs/gst/vaapi/gstvaapitypes.h create mode 100644 gst-libs/gst/vaapi/gstvaapiutils.c create mode 100644 gst-libs/gst/vaapi/gstvaapiutils.h create mode 100644 gst-libs/gst/vaapi/gstvaapiutils_glx.c create mode 100644 gst-libs/gst/vaapi/gstvaapiutils_glx.h create mode 100644 gst-libs/gst/vaapi/gstvaapiutils_x11.c create mode 100644 gst-libs/gst/vaapi/gstvaapiutils_x11.h create mode 100644 gst-libs/gst/vaapi/gstvaapivalue.c create mode 100644 gst-libs/gst/vaapi/gstvaapivalue.h create mode 100644 gst-libs/gst/vaapi/gstvaapivideobuffer.c create mode 100644 gst-libs/gst/vaapi/gstvaapivideobuffer.h create mode 100644 gst-libs/gst/vaapi/gstvaapivideobuffer_glx.c create mode 100644 gst-libs/gst/vaapi/gstvaapivideobuffer_glx.h create mode 100644 gst-libs/gst/vaapi/gstvaapivideobuffer_priv.h create mode 100644 gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c create mode 100644 gst-libs/gst/vaapi/gstvaapivideoconverter_glx.h create mode 100644 gst-libs/gst/vaapi/gstvaapivideopool.c create mode 100644 gst-libs/gst/vaapi/gstvaapivideopool.h create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow.c create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow.h create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_drm.c create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_drm.h create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_glx.c create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_glx.h create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_wayland.c create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_wayland.h create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_x11.c create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_x11.h create mode 100644 gst-libs/gst/vaapi/gstvaapiworkarounds.h create mode 100644 gst-libs/gst/vaapi/sysdeps.h create mode 100644 gst/Makefile.am create mode 100644 gst/vaapi/Makefile.am create mode 100644 gst/vaapi/gstvaapi.c create mode 100644 gst/vaapi/gstvaapidecode.c create mode 100644 gst/vaapi/gstvaapidecode.h create mode 100644 gst/vaapi/gstvaapidownload.c create mode 100644 gst/vaapi/gstvaapidownload.h create mode 100644 gst/vaapi/gstvaapiencode.c create mode 100644 gst/vaapi/gstvaapiencode.h create mode 100644 gst/vaapi/gstvaapiencode_h263.c create mode 100644 gst/vaapi/gstvaapiencode_h263.h create mode 100644 gst/vaapi/gstvaapiencode_h264.c create mode 100644 gst/vaapi/gstvaapiencode_h264.h create mode 100644 gst/vaapi/gstvaapiencode_mpeg4.c create mode 100644 gst/vaapi/gstvaapiencode_mpeg4.h create mode 100644 gst/vaapi/gstvaapipluginbuffer.c create mode 100644 gst/vaapi/gstvaapipluginbuffer.h create mode 100644 gst/vaapi/gstvaapipluginutil.c create mode 100644 gst/vaapi/gstvaapipluginutil.h create mode 100644 gst/vaapi/gstvaapipostproc.c create mode 100644 gst/vaapi/gstvaapipostproc.h create mode 100644 gst/vaapi/gstvaapisink.c create mode 100644 gst/vaapi/gstvaapisink.h create mode 100644 gst/vaapi/gstvaapiupload.c create mode 100644 gst/vaapi/gstvaapiupload.h create mode 100644 packaging/gstreamer-vaapi.changes create mode 100644 packaging/gstreamer-vaapi.manifest create mode 100644 packaging/gstreamer-vaapi.spec create mode 100644 pkgconfig/Makefile.am create mode 100644 pkgconfig/gstreamer-vaapi-drm.pc.in create mode 100644 pkgconfig/gstreamer-vaapi-glx.pc.in create mode 100644 pkgconfig/gstreamer-vaapi-wayland.pc.in create mode 100644 pkgconfig/gstreamer-vaapi-x11.pc.in create mode 100644 pkgconfig/gstreamer-vaapi.pc.in create mode 100644 tests/Makefile.am create mode 100644 tests/image.c create mode 100644 tests/image.h create mode 100644 tests/output.c create mode 100644 tests/output.h create mode 100644 tests/test-decode.c create mode 100644 tests/test-decode.h create mode 100644 tests/test-display.c create mode 100644 tests/test-h264.c create mode 100644 tests/test-h264.h create mode 100644 tests/test-jpeg.c create mode 100644 tests/test-jpeg.h create mode 100644 tests/test-mpeg2.c create mode 100644 tests/test-mpeg2.h create mode 100644 tests/test-subpicture-data.c create mode 100644 tests/test-subpicture-data.h create mode 100644 tests/test-subpicture.c create mode 100644 tests/test-surfaces.c create mode 100644 tests/test-textures.c create mode 100644 tests/test-vc1.c create mode 100644 tests/test-vc1.h create mode 100644 tests/test-windows.c diff --git a/AUTHORS b/AUTHORS index 4558581..96d5fc7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1,14 @@ -Gwenole Beauchesne - Primary author +Maintainers: + +Gwenole Beauchesne - Lead developer +Halley Zhao - MPEG-4:2 decoder + +This project is maintained by Intel Corporation. + +Contributors (sorted by first name): + +Feng Yuan +Holger Kaelberer +Nicolas Dufresne +Sreerenj Balachandran +Thibault Saunier diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makefile.am b/Makefile.am index d931a82..a204514 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,25 @@ +ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} + AUTOMAKE_OPTIONS = foreign -SUBDIRS = gst-libs sys +SUBDIRS = debian.upstream gst-libs gst pkgconfig tests docs # Extra clean files so that maintainer-clean removes *everything* MAINTAINERCLEANFILES = \ aclocal.m4 compile config.guess config.sub \ configure depcomp install-sh ltmain.sh \ - Makefile.in missing config.h.in + Makefile.in missing config.h.in gtk-doc.make + +DEB_BUILDDIR = debian.build + +deb: + dpkg-buildpackage -rfakeroot -uc -us + +deb.upstream: dist + -mkdir -p $(DEB_BUILDDIR) + cd $(DEB_BUILDDIR) && \ + rm -rf $(PACKAGE)-$(VERSION) && \ + tar zxvf ../$(PACKAGE)-$(VERSION).tar.gz && \ + cd $(PACKAGE)-$(VERSION) && \ + $(LN_S) debian.upstream debian && \ + $(MAKE) deb -f Makefile.am diff --git a/NEWS b/NEWS index 297704a..2ad1dbe 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,131 @@ -gst-vaapi NEWS -- summary of changes. 2010-01-DD -Copyright (C) 2010 Splitted-Desktop Systems +gst-vaapi NEWS -- summary of changes. 2012-08-DD +Copyright (C) 2010-2011 Splitted-Desktop Systems +Copyright (C) 2011-2012 Intel Corporation +Copyright (C) 2011 Collabora -Version 0.1.0 - DD.Jan.2010 +Version 0.4.0 - DD.Aug.2012 +* Add support for Wayland +* Add support for headless pipelines (VA/DRM API) +* Drop FFmpeg-based decoders + +Version 0.3.7 - 26.Jun.2012 +* Fix vaapidecode to report unsupported codec profiles +* Fix MPEG-2 decoding of streams with extra slice() information +* Map MPEG-2 compatible High profile streams to Main profile +* Map MPEG-4 Simple Scalable profile streams to Advanced Simple (Feng Yuan) +* Fix various MPEG-4 decoding bugs (timestamps, reference frames) (Feng Yuan) +* Don't forcibly resize user provided X windows (Holger Kaelberer) +* Recalculate render rect only if caps are negotiated (Holger Kaelberer) + +Version 0.3.6 - 02.Apr.2012 +* Add support for decoding MPEG-2 interlaced streams +* Add support for interlaced streams with FFmpeg decoders (Holger Kaelberer) +* Add vaapipostproc element for video postprocessing (e.g. deinterlacing) +* Skip all H.264 Filler Data NALs +* Fix crashes in MPEG-4 decoder (Feng Yuan) +* Fix fallback from MPEG-2 Simple to Main profile +* Improve decoding of misformed MPEG-2 streams (+Feng Yuan) +* Avoid a hang in playbin2 for some MPEG-2 TS streams (Feng Yuan) + +Version 0.3.5 - 02.Mar.2012 +* Fix H.264 decoding when emulation prevention bytes are detected +* Skip all H.264 Access Unit (AU) NALs (Feng Yuan) +* Fix modification process of H.264 reference picture lists (Feng Yuan) +* Fix MPEG-2 stream size calculation (Sreerenj Balachandran) +* Fix MPEG-2 decoding on Intel Gen with multiple slices per MB line +* Fix crash when downloading/uploading VA images on PowerVR (Cedar Trail) +* Fix double buffer free issues with some VA drivers +* Fix crash when there is no free surface available for decoding +* Skip profiles which have no entrypoints (Halley Zhao) +* Fix minor memory leaks in plug-in elements + +Version 0.3.4 - 01.Feb.2012 +* Add H.264 decoder (based on codecparsers) +* Add workaround for qtdemux not exposing H.263 profiles (Halley Zhao) +* Alias H.263 Baseline profile to MPEG-4:2 Simple profile (Halley Zhao) +* Use optimized path to submit slice data buffers +* Fix possible memory leak in MPEG-2 decoder +* Fix vaapisink to cap window size to the maximum display size +* Fix MPEG-2, MPEG-4 and VC-1 decoders to refcount reference surfaces properly + +Version 0.3.3 - 16.Jan.2012 +* Add MPEG-2, MPEG-4 and VC-1 decoders (based on codecparsers) +* Add support for GstXOverlay::set_render_rectangle() in vaapisink +* Fix memory leak of GL texture (Nicolas Dufresne) +* Fix vaapisink to automatically fit video to window +* Fix vaapiupload to only set caps on newly created buffers (Nicolas Dufresne) +* Fix gst_vaapi_ensure_display() to honour DISPLAY environment variable + +Version 0.3.2 - 06.Jan.2012 +* Rename vaapiconvert element to vaapiupload +* Fix vaapiupload from NV12 buffers +* Fix possible leaks of VA surfaces in FFmpeg decoder +* Fix memory leak in vaapiupload initialization function +* Fix possible crash in vaapidecode deinitialization code +* Add vaapidownload element to convert from VA surfaces to YUV pixels + +Version 0.3.1 - 16.Dec.2011 +* Fix check for supported VA images +* Add support for partial VA image updates +* Add support for new subtitle/overlay infrastructure (Thibault Saunier) +* Add missing video context queries in vaapisink/vaapiconvert (Nicolas Dufresne) + +Version 0.3.0 - 09.Dec.2011 +* Group all plugins into the same bundle +* Use new XOverlay API (Sreerenj Balachandran) +* Use new GstVideoContext and GstSurfaceBuffer API (Nicolas Dufresne) +* Fix vaapidecode sink caps if decoder is in NULL state (Sreerenj Balachandran) +* Fix auto-plugging and downstream buffer allocation (Nicolas Dufresne) +* Fix crash in VA display init if no VA configs were found (Nicolas Dufresne) + +Version 0.2.7 - 07.Dec.2011 +* Relicense plugins and tests to LGPL v2.1 (SDS) +* Fix MPEG-2 decoding from TS & PS streams +* Fix build with newer versions of FFmpeg +* Fix vaapiconvert direct-rendering modes +* Fix use of invalid data at the end-of-stream + +Version 0.2.6 - 14.Jun.2011 +* Fix licensing terms (LGPL v2.1) + +Version 0.2.5 - 20.Jul.2010 +* Fix build with older VA-API 0.29-sds +* Fix decoding of some H.264 streams. e.g. Ice Age 2 trailer +* Fix VA/GLX support with texture-from-pixmap and GLX version < 1.3 + +Version 0.2.4 - 18.May.2010 +* Fix video rendering rect within an embedder window (Totem) +* Disable GLX rendering when vaapisink uses a foreign X window + +Version 0.2.3 - 16.May.2010 +* Fix memory leak of encoded buffers +* Fix decoder caps to report codec aliases +* Fix VC-1 decoding through the playbin2 pipeline + +Version 0.2.2 - 14.May.2010 +* Fix packaging dependencies +* Fix a crash in the FFmpeg decoder on close +* Fix OpenGL texture internal format (Clutter) +* Fix foreign window size for embedding (Totem) + +Version 0.2.1 - 12.May.2010 +* Fix integration within the playbin2 pipeline +* Fix vaapidecode to expose the HW supported caps only +* Add GstXOverlay interface to vaapisink (Totem media player) + +Version 0.2.0 - 05.May.2010 +* Relicense gst-libs/ code to LGPL v2.1+ +* Add FFmpeg/VAAPI decoder for the new `vaapidecode' element + +Version 0.1.2 - 30.Mar.2010 +* Add AYUV image format +* Add compatibility with the original VA-API 0.29 +* Add OpenGL support through VA/GLX extensions or TFP+FBO fallback + +Version 0.1.1 - 23.Mar.2010 +* Document public API for libgstvaapi-*.so.* +* Optimize `vaapiconvert' pipeline (direct-rendering) +* Allow `vaapisink` to render videos in fullscreen mode + +Version 0.1.0 - 16.Mar.2010 * Initial release diff --git a/README b/README index 3dcad3f..3c1e078 100644 --- a/README +++ b/README @@ -1,26 +1,88 @@ - gst-vaapi - VA API support to GStreamer + gstreamer-vaapi + VA-API support to GStreamer - Copyright (C) 2010 Splitted-Desktop Systems + Copyright (C) 2010-2011 Splitted-Desktop Systems + Copyright (C) 2011-2012 Intel Corporation + Copyright (C) 2011 Collabora Ltd. License ------- -gst-vaapi is available under the terms of the GNU General Public -License. - +gstreamer-vaapi helper libraries and plugin elements are available +under the terms of the GNU Lesser General Public License v2.1+ Overview -------- -gst-vaapi consists in a VA API based videosink for GStreamer and -helper libraries. +gstreamer-vaapi consists in a collection of VA-API based plugins for +GStreamer and helper libraries. + + * `vaapidecode' is used to decode MPEG-2, MPEG-4, H.264, VC-1, WMV3 + videos to video/x-vaapi-surfaces surfaces, depending on the + underlying HW capabilities. + + * `vaapiupload' is used to convert from video/x-raw-yuv pixels to + video/x-vaapi-surface surfaces. + + * `vaapidownload' is used to convert from video/x-vaapi-surface + surfaces to video/x-raw-yuv pixels. + + * `vaapipostproc' is used to postprocess video/x-vaapi-surface + surfaces, for e.g. deinterlacing. + + * `vaapisink' is used to display video/x-vaapi-surface surfaces to + screen. + + +Features +-------- + + * VA-API support from 0.29 to 0.32 + * MPEG-2, MPEG-4, H.264 and VC-1 ad-hoc decoders + * OpenGL rendering through VA/GLX or GLX texture-from-pixmap + FBO + * Support for major HW video decoding solutions on Linux (AMD, Intel, NVIDIA) Requirements ------------ -gstreamer-0.10 >= 0.10.0 -gstreamer-plugins-base-0.10 >= 0.10.0 +Software requirements + + * libva-dev >= 1.0.3 (VA/GLX) + * libgstreamer0.10-dev >= 0.10.35.1 + or with GstBaseSink::query() + * libgstreamer-plugins-base0.10-dev >= 0.10.35 + * libgstreamer-plugins-bad0.10-dev >= 0.10.22.1 + or with GstVideoContext, GstSurfaceBuffer, codecparsers + + If codecparsers-based decoders are not used: + + * libavcodec-dev >= 0.6 + or with + +Hardware requirements + + * AMD platforms with UVD2 (XvBA supported) + * Intel Eaglelake (G45) + * Intel Ironlake, Sandy Bridge and Ivy Bridge (HD Graphics) + * Intel Poulsbo (US15W) + * Intel Medfield or Cedar Trail + * NVIDIA platforms with PureVideo (VDPAU supported) + + +Usage +----- + + VA elements are automatically plugged into GStreamer pipelines. So, + using playbin2 should work as is. However, here are a few alternate + pipelines constructed manually. + + * Play an H.264 video with an MP4 container in fullscreen mode + $ gst-launch-0.10 -v filesrc location=/path/to/video.mp4 ! \ + qtdemux ! vaapidecode ! vaapisink fullscreen=true + + * Play a raw MPEG-2 interlaced stream + $ gst-launch-0.10 -v filesrc location=/path/to/mpeg2.bits ! \ + mpegvideoparse ! vaapidecode ! vaapipostproc ! vaapisink diff --git a/autogen.sh b/autogen.sh index 9c2f4f6..920e77e 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,3 +1,38 @@ -#! /bin/sh -autoreconf -v --install -./configure "$@" +#!/bin/sh + +PROJECT="gstreamer-vaapi" + +test -n "$srcdir" || srcdir="`dirname \"$0\"`" +test -n "$srcdir" || srcdir=. + +if ! test -f "$srcdir/configure.ac"; then + echo "Failed to find the top-level $PROJECT directory" + exit 1 +fi + +olddir="`pwd`" +cd "$srcdir" + +mkdir -p m4 + +GTKDOCIZE=`which gtkdocize` +if test -z $GTKDOCIZE; then + echo "*** No gtk-doc support ***" + echo "EXTRA_DIST =" > gtk-doc.make +else + gtkdocize || exit $? +fi + +AUTORECONF=`which autoreconf` +if test -z $AUTORECONF; then + echo "*** No autoreconf found ***" + exit 1 +else + autoreconf -v --install || exit $? +fi + +cd "$olddir" + +if test -z "$NO_CONFIGURE"; then + $srcdir/configure "$@" && echo "Now type 'make' to compile $PROJECT." +fi diff --git a/configure.ac b/configure.ac index 08c64a5..8ced37f 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,27 @@ +# gstreamer-vaapi package version number +m4_define([gst_vaapi_major_version], [0]) +m4_define([gst_vaapi_minor_version], [4]) +m4_define([gst_vaapi_micro_version], [0]) +m4_define([gst_vaapi_pre_version], [1]) +m4_define([gst_vaapi_version], + [gst_vaapi_major_version.gst_vaapi_minor_version.gst_vaapi_micro_version]) +m4_if(gst_vaapi_pre_version, [0], [], [ +m4_append([gst_vaapi_version], gst_vaapi_pre_version, [.pre]) +]) + +# glib version number +m4_define([glib_major_version], [2]) +m4_define([glib_minor_version], [28]) +m4_define([glib_micro_version], [0]) +m4_define([glib_major_minor_version], + [glib_major_version.glib_minor_version]) +m4_define([glib_version], + [glib_major_version.glib_minor_version.glib_micro_version]) + # gst version number m4_define([gst_major_version], [0]) m4_define([gst_minor_version], [10]) -m4_define([gst_micro_version], [0]) +m4_define([gst_micro_version], [14]) m4_define([gst_major_minor_version], [gst_major_version.gst_minor_version]) m4_define([gst_version], @@ -10,49 +30,252 @@ m4_define([gst_version], # gst plugins-base version number m4_define([gst_plugins_base_major_version], [0]) m4_define([gst_plugins_base_minor_version], [10]) -m4_define([gst_plugins_base_micro_version], [0]) +m4_define([gst_plugins_base_micro_version], [31]) m4_define([gst_plugins_base_version], [gst_plugins_base_major_version.gst_plugins_base_minor_version.gst_plugins_base_micro_version]) -# gst_vaapi package version number -m4_define([gst_vaapi_major_version], [0]) -m4_define([gst_vaapi_minor_version], [1]) -m4_define([gst_vaapi_micro_version], [0]) -m4_define([gst_vaapi_version], - [gst_vaapi_major_version.gst_vaapi_minor_version.gst_vaapi_micro_version]) +# gst plugins-bad version number +m4_define([gst_plugins_bad_major_version], [0]) +m4_define([gst_plugins_bad_minor_version], [10]) +m4_define([gst_plugins_bad_micro_version], [22]) +m4_define([gst_plugins_bad_version], + [gst_plugins_bad_major_version.gst_plugins_bad_minor_version.gst_plugins_bad_micro_version]) + +# VA-API minimum version number +m4_define([va_api_version], [0.30.4]) +m4_define([va_api_drm_version], [0.34.0]) +m4_define([va_api_x11_version], [0.31.0]) +m4_define([va_api_glx_version], [0.32.0]) +m4_define([va_api_wld_version], [0.34.0]) +m4_define([va_api_tpi_version], [0.33.0]) + +# libva package version number +m4_define([libva_drm_package_version], [1.2.0]) +m4_define([libva_x11_package_version], [1.0.3]) +m4_define([libva_glx_package_version], [1.0.9]) +m4_define([libva_wld_package_version], [1.2.0]) -AC_PREREQ([2.57]) +# gtk-doc version number +# XXX: introspection annotations require gtk-doc >= 1.12 +m4_define([gtkdoc_major_version], [1]) +m4_define([gtkdoc_minor_version], [9]) +m4_define([gtkdoc_version], [gtkdoc_major_version.gtkdoc_minor_version]) + +AC_PREREQ([2.58]) AC_INIT([gst_vaapi], [gst_vaapi_version], - [gbeauchesne@splitted-desktop.com], + [gwenole.beauchesne@intel.com], [gstreamer-vaapi]) + +AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) + AC_CANONICAL_TARGET + AM_INIT_AUTOMAKE -AM_CONFIG_HEADER([config.h]) + +TODAY="`LC_ALL=C date +'%a, %d %b %Y %X %z'`" +AC_SUBST(TODAY) + +GST_VAAPI_MAJOR_VERSION=gst_vaapi_major_version +AC_SUBST(GST_VAAPI_MAJOR_VERSION) + +LIBVA_PACKAGE_VERSION=libva_x11_package_version +AC_SUBST(LIBVA_PACKAGE_VERSION) dnl Versions for GStreamer and plugins-base GST_MAJORMINOR=gst_major_minor_version GST_VERSION_REQUIRED=gst_version GST_PLUGINS_BASE_VERSION_REQUIRED=gst_plugins_base_version +GST_PLUGINS_BAD_VERSION_REQUIRED=gst_plugins_bad_version AC_SUBST(GST_MAJORMINOR) +AC_SUBST(GST_VERSION_REQUIRED) +AC_SUBST(GST_PLUGINS_BASE_VERSION_REQUIRED) +AC_SUBST(GST_PLUGINS_BAD_VERSION_REQUIRED) + +dnl Use pretty build output with automake >= 1.11 +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])], [ + AM_DEFAULT_VERBOSITY=1 + AC_SUBST(AM_DEFAULT_VERBOSITY) +]) dnl Check for tools AC_PROG_CC -AC_PROG_LIBTOOL +AM_PROG_CC_C_O + +dnl Initialize libtool +LT_PREREQ([2.2]) +LT_INIT + +AC_ARG_ENABLE(drm, + AS_HELP_STRING([--enable-drm], + [enable DRM backend @<:@default=yes@:>@]), + [], [enable_drm="yes"]) + +AC_ARG_ENABLE(x11, + AS_HELP_STRING([--enable-x11], + [enable X11 output @<:@default=yes@:>@]), + [], [enable_x11="yes"]) + +AC_ARG_ENABLE(glx, + AS_HELP_STRING([--enable-glx], + [enable OpenGL/X11 output @<:@default=yes@:>@]), + [], [enable_glx="yes"]) -dnl Check for GStreamer -PKG_CHECK_MODULES([GST], - [gstreamer-$GST_MAJORMINOR >= $GST_VERSION_REQUIRED] -) -AC_SUBST(GST_CFLAGS) -AC_SUBST(GST_LIBS) +AC_ARG_ENABLE(wayland, + AC_HELP_STRING([--enable-wayland], + [enable Wayland output @<:@default=yes@:>@]), + [], [enable_wayland="yes"]) -dnl Check for GStreamer plugins-base +AC_ARG_ENABLE(encoders, + AC_HELP_STRING([--enable-encoders], + [enable encoders @<:@default=no@:>@]), + [], [enable_encoders="no"]) + +dnl Check for basic libraries +AC_CHECK_LIB(m, tan) + +dnl Check for Gtk doc +GTKDOC_VERSION=gtkdoc_version +# gtkdocize greps for '^GTK_DOC_CHECK', so it needs to be on its own line +m4_ifdef([GTK_DOC_CHECK], [ +GTK_DOC_CHECK([$GTKDOC_VERSION], [--flavour no-tmpl])], [ +AM_CONDITIONAL([ENABLE_GTK_DOC], [false])]) +AC_SUBST(GTKDOC_VERSION) + +dnl Check for GLib +GLIB_VERSION_REQUIRED=glib_version +PKG_CHECK_MODULES([GLIB], [glib-2.0 >= $GLIB_VERSION_REQUIRED]) +AC_SUBST(GLIB_VERSION_REQUIRED) + +dnl --------------------------------------------------------------------------- +dnl -- GStreamer -- +dnl --------------------------------------------------------------------------- + +dnl GStreamer Core +PKG_CHECK_MODULES([GST], [gstreamer-$GST_MAJORMINOR >= gst_version]) +PKG_CHECK_MODULES([GST_BASE], [gstreamer-base-$GST_MAJORMINOR >= gst_version]) + +AC_CACHE_CHECK([for GstBaseSink::query hook], ac_cv_have_gst_base_sink_query, [ + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $GST_BASE_CFLAGS" + saved_LIBS="$LIBS" + LIBS="$LIBS $GST_BASE_LIBS" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[GstBaseSinkClass klass; klass.query = NULL;]])], + [ac_cv_have_gst_base_sink_query="yes"], + [ac_cv_have_gst_base_sink_query="no"] + ) + CFLAGS="$saved_CFLAGS" + LIBS="$saved_LIBS" +]) +if test "$ac_cv_have_gst_base_sink_query" != "yes"; then + AC_MSG_ERROR([GstBaseSink does not contain the 'query' vfunc]) +fi + +dnl GStreamer -base plugins PKG_CHECK_MODULES([GST_PLUGINS_BASE], - [gstreamer-plugins-base-$GST_MAJORMINOR >= $GST_PLUGINS_BASE_VERSION_REQUIRED] -) -AC_SUBST(GST_PLUGINS_BASE_CFLAGS) -AC_SUBST(GST_PLUGINS_BASE_LIBS) + [gstreamer-plugins-base-$GST_MAJORMINOR >= gst_plugins_base_version]) +PKG_CHECK_MODULES([GST_INTERFACES], + [gstreamer-interfaces-$GST_MAJORMINOR >= gst_plugins_base_version]) + +dnl ... GstVideoOverlayComposition (gstreamer-video) +PKG_CHECK_MODULES([GST_VIDEO], + [gstreamer-video-$GST_MAJORMINOR >= gst_plugins_base_version]) + +AC_CACHE_CHECK([for GstVideoOverlayComposition], + ac_cv_have_gst_video_overlay_composition, [ + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $GST_CFLAGS" + saved_LIBS="$LIBS" + LIBS="$LIBS $GST_LIBS" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[GstVideoOverlayComposition *c = gst_video_overlay_composition_new(0);]])], + [ac_cv_have_gst_video_overlay_composition="yes"], + [ac_cv_have_gst_video_overlay_composition="no"] + ) + CFLAGS="$saved_CFLAGS" + LIBS="$saved_LIBS" +]) +if test "$ac_cv_have_gst_video_overlay_composition" != "yes"; then + AC_MSG_ERROR([GstVideoOverlayComposition is not available]) +fi + +dnl GStreamer -bad plugins +PKG_CHECK_MODULES([GST_BASEVIDEO], + [gstreamer-basevideo-$GST_MAJORMINOR >= gst_plugins_bad_version]) + +dnl ... bitstream parsers +USE_CODEC_PARSERS=1 +USE_LOCAL_CODEC_PARSERS=0 + +PKG_CHECK_MODULES([GST_CODEC_PARSERS], + [gstreamer-codecparsers-$GST_MAJORMINOR >= gst_plugins_bad_version]) + +dnl ... 0.10.23 addition, could be implemented otherwise +AC_CACHE_CHECK([for GstH264SliceHdr::n_emulation_prevention_bytes], + ac_cv_have_gst_h264_slice_hdr_epb_count, [ + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $GST_CFLAGS $GST_CODEC_PARSERS_CFLAGS" + saved_LIBS="$LIBS" + LIBS="$LIBS $GST_LIBS $GST_CODEC_PARSERS_LIBS" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[GstH264SliceHdr slice_hdr; + slice_hdr.n_emulation_prevention_bytes = 0;]])], + [ac_cv_have_gst_h264_slice_hdr_epb_count="yes"], + [ac_cv_have_gst_h264_slice_hdr_epb_count="no"] + ) + CFLAGS="$saved_CFLAGS" + LIBS="$saved_LIBS" +]) + +if test "$ac_cv_have_gst_h264_slice_hdr_epb_count" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_GST_H264_SLICE_HDR_EPB_COUNT, 1, + [Defined to 1 if GstH264SliceHdr::n_emulation_prevention_bytes exists.]) +fi + +dnl ... JPEG parser, not upstream yet +AC_CACHE_CHECK([for JPEG parser], + ac_cv_have_gst_jpeg_parser, [ + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $GST_CFLAGS $GST_CODEC_PARSERS_CFLAGS" + saved_LIBS="$LIBS" + LIBS="$LIBS $GST_LIBS $GST_CODEC_PARSERS_LIBS" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[GstJpegImage jpeg_image;]])], + [ac_cv_have_gst_jpeg_parser="yes"], + [ac_cv_have_gst_jpeg_parser="no" USE_LOCAL_CODEC_PARSERS=1] + ) + CFLAGS="$saved_CFLAGS" + LIBS="$saved_LIBS" +]) + +if test "$ac_cv_have_gst_jpeg_parser" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_GST_JPEG_PARSER, 1, + [Defined to 1 if JPEG parser exists.]) +fi +AM_CONDITIONAL(USE_LOCAL_CODEC_PARSERS, test $USE_LOCAL_CODEC_PARSERS -eq 1) + +dnl GST_ALL_LDFLAGS: +dnl LDFLAGS really should only contain flags, not libs - they get added before +dnl whatevertarget_LIBS and -L flags here affect the rest of the linking +GST_ALL_LDFLAGS="-no-undefined" +AC_SUBST(GST_ALL_LDFLAGS) + +dnl GST_PLUGIN_LDFLAGS: +dnl this really should only contain flags, not libs - they get added before +dnl whatevertarget_LIBS and -L flags here affect the rest of the linking +GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^([_]*gst_plugin_desc|gst_.*_get_type)\$\$' $GST_ALL_LDFLAGS" +AC_SUBST(GST_PLUGIN_LDFLAGS) dnl Check for the GStreamer plugins directory AC_MSG_CHECKING([for GStreamer plugins directory]) @@ -65,48 +288,314 @@ AC_MSG_RESULT([$GST_PLUGINS_DIR]) plugindir="$GST_PLUGINS_DIR" AC_SUBST(plugindir) -dnl Check for VA API -PKG_CHECK_MODULES(LIBVA_DEPS, [libva]) -PKG_CHECK_MODULES(LIBVA_X11_DEPS, [libva-x11]) - -dnl Check for SDS extensions to VA API -AC_CACHE_CHECK([for VA API], - ac_cv_libva_sds_extensions, [ - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $LIBVA_DEPS_CFLAGS" - AC_TRY_COMPILE([ - #include - #if VA_MAJOR_VERSION == 0 && VA_MINOR_VERSION == 29 - # if !defined(VA_SDS_VERSION) || (VA_SDS_VERSION < $LIBVA_SDS_VERSION_0_29) - # error "VA API version >= 0.29.0-sds$LIBVA_SDS_VERSION_0_29 is required" - # endif - #elif VA_MAJOR_VERSION == 0 && VA_MINOR_VERSION == 30 - # if !defined(VA_SDS_VERSION) || (VA_SDS_VERSION < $LIBVA_SDS_VERSION_0_30) - # error "VA API version >= 0.30.0-sds$LIBVA_SDS_VERSION_0_30 is required" - # endif - #elif !VA_CHECK_VERSION(0,31,0) - # error "VA API version >= 0.31 is required" - #endif - ], [], - [ac_cv_libva_sds_extensions="yes"], - [ac_cv_libva_sds_extensions="no"]) - CFLAGS="$saved_CFLAGS" -]) +dnl --------------------------------------------------------------------------- +dnl -- Renderers -- +dnl --------------------------------------------------------------------------- + +dnl Check for DRM/libudev +USE_DRM=0 +if test "$enable_drm" = "yes"; then + PKG_CHECK_MODULES(DRM, [libdrm], [USE_DRM=1], [USE_DRM=0]) + PKG_CHECK_MODULES(UDEV, [libudev], [:], [USE_DRM=0]) + + if test $USE_DRM -eq 1; then + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $DRM_CFLAGS" + AC_CHECK_HEADERS([drm_fourcc.h], [:], [USE_DRM=0]) + CPPFLAGS="$saved_CPPFLAGS" + fi +fi + +dnl Check for X11 +USE_X11=0 +if test "$enable_x11" = "yes"; then + PKG_CHECK_MODULES(X11, [x11], [USE_X11=1], [USE_X11=0]) + if test $USE_X11 -eq 1; then + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $X11_CFLAGS" + AC_CHECK_HEADERS([X11/Xlib.h X11/Xutil.h X11/Xatom.h], [:], [USE_X11=0]) + CPPFLAGS="$saved_CPPFLAGS" + fi +fi + +dnl Check for XRandR +HAVE_XRANDR=0 +if test $USE_X11 -eq 1; then + HAVE_XRANDR=1 + PKG_CHECK_MODULES([XRANDR], [xrandr], [:], [HAVE_XRANDR=0]) + if test $HAVE_XRANDR -eq 1; then + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $XRANDR_CFLAGS" + AC_CHECK_HEADERS([X11/extensions/Xrandr.h], [:], [HAVE_XRANDR=0]) + CPPFLAGS="$saved_CPPFLAGS" + fi +fi +if test $HAVE_XRANDR -eq 1; then + AC_DEFINE_UNQUOTED(HAVE_XRANDR, 1, + [Defined to 1 if the XRandR extension exists.]) +fi + +dnl OpenGL +enable_opengl="no" +if test "$enable_glx" = "yes"; then + enable_opengl="yes" +fi + +HAVE_GL=0 +if test "$enable_opengl" = "yes"; then + HAVE_GL=1 + PKG_CHECK_MODULES([GL], [gl], [:], [HAVE_GL=0]) + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $GL_CFLAGS" + AC_CHECK_HEADERS([GL/gl.h GL/glext.h], [:], [HAVE_GL=0], [ +#ifdef HAVE_GL_GL_H +# include +#endif + ]) + CPPFLAGS="$saved_CPPFLAGS" +fi + +dnl Check for encoders +USE_ENCODERS=0 +if test "$enable_encoders" = "yes"; then + USE_ENCODERS=1 +fi + +AC_DEFINE_UNQUOTED(USE_ENCODERS, $USE_ENCODERS, + [Defined to 1 if GStreamer Vaapi Encoder are used]) +AM_CONDITIONAL(USE_ENCODERS, test $USE_ENCODERS -eq 1) + +dnl ... GLX +USE_GLX=0 +if test "$enable_glx" = "yes" -a $HAVE_GL -eq 1 -a $USE_X11 -eq 1; then + USE_GLX=1 + saved_CPPFLAGS="$CPPFLAGS" + saved_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $GL_CFLAGS" + LIBS="$LIBS $GL_LIBS" + AC_CHECK_HEADERS([GL/glx.h], [:], [USE_GLX=0], [ +#ifdef HAVE_GL_GL_H +# include +#endif + ]) + AC_CHECK_LIB([GL], [glXCreateContext], [:], [USE_GLX=0]) + CPPFLAGS="$saved_CPPFLAGS" + LIBS="$saved_LIBS" +fi + +dnl Check for Wayland +USE_WAYLAND=0 +if test "$enable_wayland" = "yes"; then + PKG_CHECK_MODULES(WAYLAND, [wayland-client], + [USE_WAYLAND=1], [USE_WAYLAND=0]) + + if test $USE_WAYLAND -eq 1; then + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $WAYLAND_CFLAGS" + AC_CHECK_HEADERS([wayland-client.h], [:], [USE_WAYLAND=0]) + CPPFLAGS="$saved_CPPFLAGS" + fi +fi + +dnl --------------------------------------------------------------------------- +dnl -- VA-API -- +dnl --------------------------------------------------------------------------- + +dnl Core API +LIBVA_PKGNAME="libva" +PKG_CHECK_MODULES(LIBVA, [$LIBVA_PKGNAME >= va_api_version]) +AC_SUBST(LIBVA_PKGNAME) + +LIBVA_TPI_PKGNAME="libva-tpi" +PKG_CHECK_MODULES(LIBVA_TPI, [$LIBVA_TPI_PKGNAME >= va_api_tpi_version]) +AC_SUBST(LIBVA_TPI_PKGNAME) + VA_VERSION=`$PKG_CONFIG --modversion libva` VA_MAJOR_VERSION=`echo "$VA_VERSION" | cut -d'.' -f1` VA_MINOR_VERSION=`echo "$VA_VERSION" | cut -d'.' -f2` -VA_DRIVER_INIT_FUNC="__vaDriverInit_${VA_MAJOR_VERSION}_${VA_MINOR_VERSION}_sds" -if test "$ac_cv_libva_sds_extensions" = "yes"; then - AC_DEFINE_UNQUOTED([VA_DRIVER_INIT_FUNC], [$VA_DRIVER_INIT_FUNC], [Define driver entry-point]) -else - AC_MSG_ERROR([Your VA API SDK does not include SDS extensions]) +VA_MICRO_VERSION=`echo "$VA_VERSION" | cut -d'.' -f3` +VA_VERSION_STR="$VA_VERSION" + +dnl VA/DRM API +if test "$enable_drm" = "yes"; then + PKG_CHECK_MODULES([LIBVA_DRM], [libva-drm >= va_api_drm_version], + [:], [USE_DRM=0]) +fi + +dnl VA/X11 API +HAVE_VA_X11=0 +LIBVA_X11_PKGNAME="libva-x11" +if test $USE_X11 -eq 1; then + PKG_CHECK_MODULES(LIBVA_X11, [$LIBVA_X11_PKGNAME >= va_api_x11_version], + [HAVE_VA_X11=1], [USE_X11=0]) +fi +AC_SUBST(LIBVA_X11_PKGNAME) + +dnl VA/GLX API +HAVE_VA_GLX=0 +LIBVA_GLX_PKGNAME="libva-glx" +if test $USE_GLX -eq 1; then + PKG_CHECK_MODULES(LIBVA_GLX, [$LIBVA_GLX_PKGNAME >= va_api_glx_version], + [HAVE_VA_GLX=1], [LIBVA_GLX_PKGNAME="$LIBVA_X11_PKGNAME"]) + + if test $HAVE_VA_GLX -eq 1; then + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$LIBVA_GLX_CPPFLAGS" + AC_CHECK_HEADERS([va/va_glx.h], [:], [HAVE_VA_GLX=0]) + CPPFLAGS="$saved_CPPFLAGS" + fi fi +AC_SUBST(LIBVA_GLX_PKGNAME) -AC_OUTPUT([ +dnl Check for JPEG decoding API (0.32.1+) +USE_JPEG_DECODER=0 +AC_CACHE_CHECK([for JPEG decoding API], + ac_cv_have_jpeg_decoding_api, [ + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $LIBVA_CFLAGS" + saved_LIBS="$LIBS" + LIBS="$CFLAGS $LIBVA_LIBS" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[VAPictureParameterBufferJPEGBaseline pic_param; + VASliceParameterBufferJPEGBaseline slice_param; + VAHuffmanTableBufferJPEGBaseline huffman_table; + VAIQMatrixBufferJPEGBaseline iq_matrix;]])], + [ac_cv_have_jpeg_decoding_api="yes" USE_JPEG_DECODER=1], + [ac_cv_have_jpeg_decoding_api="no"] + ) + CFLAGS="$saved_CFLAGS" + LIBS="$saved_LIBS" +]) + +dnl Check libva old H.264 encoder API +HAVE_OLD_H264_ENCODER=0 +AC_CACHE_CHECK([for H264 encoder old structures], + ac_cv_have_old_h264_encoder, [ + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $LIBVA_CFLAGS" + saved_LIBS="$LIBS" + LIBS="$CFLAGS $LIBVA_LIBS" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[VAEncSequenceParameterBufferH264 seq; + seq.seq_fields.value = 0; + seq.vui_fields.value = 0;]])], + [ac_cv_have_old_h264_encoder="no" HAVE_OLD_H264_ENCODER=0], + [ac_cv_have_old_h264_encoder="yes" HAVE_OLD_H264_ENCODER=1] + ) + CFLAGS="$saved_CFLAGS" + LIBS="$saved_LIBS" +]) + +AC_DEFINE_UNQUOTED(HAVE_OLD_H264_ENCODER, $HAVE_OLD_H264_ENCODER, + [Defined to 1 if old h264 encoder API exists.]) + +dnl VA/Wayland API +if test "$enable_wayland" = "yes"; then + PKG_CHECK_MODULES([LIBVA_WAYLAND], [libva-wayland >= va_api_wld_version], + [:], [USE_WAYLAND=0]) +fi + +dnl --------------------------------------------------------------------------- +dnl -- Generate files and summary -- +dnl --------------------------------------------------------------------------- + +case ":$USE_X11:$USE_GLX:$USE_WAYLAND:$USE_DRM:" in +*:1:*) + ;; +*) + AC_MSG_ERROR([No renderer is enabled]) + ;; +esac + +AC_DEFINE_UNQUOTED(USE_JPEG_DECODER, $USE_JPEG_DECODER, + [Defined to 1 if JPEG decoder is used]) +AM_CONDITIONAL(USE_JPEG_DECODER, test $USE_JPEG_DECODER -eq 1) + +AC_DEFINE_UNQUOTED(USE_DRM, $USE_DRM, + [Defined to 1 if DRM is enabled]) +AM_CONDITIONAL(USE_DRM, test $USE_DRM -eq 1) + +AC_DEFINE_UNQUOTED(USE_X11, $USE_X11, + [Defined to 1 if X11 is enabled]) +AM_CONDITIONAL(USE_X11, test $USE_X11 -eq 1) + +AC_DEFINE_UNQUOTED(USE_GLX, $USE_GLX, + [Defined to 1 if GLX is enabled]) +AM_CONDITIONAL(USE_GLX, test $USE_GLX -eq 1) + +AC_DEFINE_UNQUOTED(USE_WAYLAND, $USE_WAYLAND, + [Defined to 1 if WAYLAND is enabled]) +AM_CONDITIONAL(USE_WAYLAND, test $USE_WAYLAND -eq 1) + +pkgconfigdir=${libdir}/pkgconfig +AC_SUBST(pkgconfigdir) + +AC_CONFIG_FILES([ Makefile + debian.upstream/Makefile + debian.upstream/changelog + debian.upstream/control + debian.upstream/gstreamer$GST_MAJORMINOR-vaapi-doc.install:\ +debian.upstream/gstreamer-vaapi-doc.install.in + debian.upstream/gstreamer$GST_MAJORMINOR-vaapi.install:\ +debian.upstream/gstreamer-vaapi.install.in + debian.upstream/libgstvaapi$GST_VAAPI_MAJOR_VERSION.install:\ +debian.upstream/libgstvaapi.install.in + debian.upstream/libgstvaapi-dev.install + debian.upstream/libgstvaapi-drm-$GST_VAAPI_MAJOR_VERSION.install:\ +debian.upstream/libgstvaapi-drm.install.in + debian.upstream/libgstvaapi-glx-$GST_VAAPI_MAJOR_VERSION.install:\ +debian.upstream/libgstvaapi-glx.install.in + debian.upstream/libgstvaapi-wayland-$GST_VAAPI_MAJOR_VERSION.install:\ +debian.upstream/libgstvaapi-wayland.install.in + debian.upstream/libgstvaapi-x11-$GST_VAAPI_MAJOR_VERSION.install:\ +debian.upstream/libgstvaapi-x11.install.in + docs/Makefile + docs/reference/Makefile + docs/reference/libs/Makefile + docs/reference/libs/libs-docs.xml + docs/reference/plugins/Makefile + docs/reference/plugins/plugins-docs.xml gst-libs/Makefile gst-libs/gst/Makefile + gst-libs/gst/codecparsers/Makefile gst-libs/gst/vaapi/Makefile - sys/Makefile - sys/vaapi/Makefile + gst/Makefile + gst/vaapi/Makefile + pkgconfig/Makefile + pkgconfig/gstreamer-vaapi-$GST_MAJORMINOR.pc:\ +pkgconfig/gstreamer-vaapi.pc.in + pkgconfig/gstreamer-vaapi-drm-$GST_MAJORMINOR.pc:\ +pkgconfig/gstreamer-vaapi-drm.pc.in + pkgconfig/gstreamer-vaapi-glx-$GST_MAJORMINOR.pc:\ +pkgconfig/gstreamer-vaapi-glx.pc.in + pkgconfig/gstreamer-vaapi-wayland-$GST_MAJORMINOR.pc:\ +pkgconfig/gstreamer-vaapi-wayland.pc.in + pkgconfig/gstreamer-vaapi-x11-$GST_MAJORMINOR.pc:\ +pkgconfig/gstreamer-vaapi-x11.pc.in + tests/Makefile ]) +AC_OUTPUT + +dnl Print summary +yesno() { + test $1 -eq 1 && echo yes || echo no +} + +VIDEO_OUTPUTS="" +AS_IF([test $USE_DRM -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS drm"]) +AS_IF([test $USE_X11 -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS x11"]) +AS_IF([test $USE_GLX -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS glx"]) +AS_IF([test $USE_WAYLAND -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS wayland"]) + +echo +echo $PACKAGE configuration summary: +echo +echo VA-API version ................... : $VA_VERSION_STR +echo Video outputs .................... : $VIDEO_OUTPUTS +echo VaapiEncoder support....... ...... : $(yesno $USE_ENCODERS) +echo diff --git a/debian.upstream/Makefile.am b/debian.upstream/Makefile.am new file mode 100644 index 0000000..cacc519 --- /dev/null +++ b/debian.upstream/Makefile.am @@ -0,0 +1,52 @@ +DOCS = \ + AUTHORS \ + COPYING \ + COPYING.LIB \ + NEWS \ + README \ + $(NULL) + +DEBIANFILES = \ + changelog \ + changelog.in \ + compat \ + control \ + control.in \ + copyright \ + gstreamer-vaapi.install.in \ + gstreamer$(GST_MAJORMINOR)-vaapi.install \ + gstreamer-vaapi-doc.install.in \ + gstreamer$(GST_MAJORMINOR)-vaapi-doc.install \ + libgstvaapi.install.in \ + libgstvaapi$(GST_VAAPI_MAJOR_VERSION).install \ + libgstvaapi-dev.install.in \ + libgstvaapi-dev.install \ + libgstvaapi-drm.install.in \ + libgstvaapi-drm-$(GST_VAAPI_MAJOR_VERSION).install \ + libgstvaapi-x11.install.in \ + libgstvaapi-x11-$(GST_VAAPI_MAJOR_VERSION).install \ + libgstvaapi-glx.install.in \ + libgstvaapi-glx-$(GST_VAAPI_MAJOR_VERSION).install \ + libgstvaapi-wayland.install.in \ + libgstvaapi-wayland-$(GST_VAAPI_MAJOR_VERSION).install \ + rules \ + $(NULL) + +DEBIANGENFILES = \ + control \ + changelog \ + gstreamer$(GST_MAJORMINOR)-vaapi.install \ + gstreamer$(GST_MAJORMINOR)-vaapi-doc.install \ + libgstvaapi$(GST_VAAPI_MAJOR_VERSION).install \ + libgstvaapi-dev.install \ + libgstvaapi-drm-$(GST_VAAPI_MAJOR_VERSION).install \ + libgstvaapi-x11-$(GST_VAAPI_MAJOR_VERSION).install \ + libgstvaapi-glx-$(GST_VAAPI_MAJOR_VERSION).install \ + libgstvaapi-wayland-$(GST_VAAPI_MAJOR_VERSION).install \ + $(NULL) + +EXTRA_DIST = \ + $(DEBIANFILES) + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in $(DEBIANGENFILES) diff --git a/debian.upstream/changelog.in b/debian.upstream/changelog.in new file mode 100644 index 0000000..92f9d3d --- /dev/null +++ b/debian.upstream/changelog.in @@ -0,0 +1,5 @@ +gstreamer@GST_MAJORMINOR@-vaapi (@PACKAGE_VERSION@-1) unstable; urgency=low + + * Autogenerated package, see NEWS file for ChangeLog. + + -- Gwenole Beauchesne @TODAY@ diff --git a/debian.upstream/compat b/debian.upstream/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian.upstream/compat @@ -0,0 +1 @@ +5 diff --git a/debian.upstream/control.in b/debian.upstream/control.in new file mode 100644 index 0000000..960f72e --- /dev/null +++ b/debian.upstream/control.in @@ -0,0 +1,99 @@ +Source: gstreamer@GST_MAJORMINOR@-vaapi +Section: libs +Priority: optional +Maintainer: Gwenole Beauchesne +Build-Depends: debhelper (>= 5), + cdbs, + libglib2.0-dev (>= @GLIB_VERSION_REQUIRED@), + libgstreamer@GST_MAJORMINOR@-dev (>= @GST_VERSION_REQUIRED@), + libgstreamer-plugins-base@GST_MAJORMINOR@-dev (>= @GST_PLUGINS_BASE_VERSION_REQUIRED@), + libva-dev (>= @LIBVA_PACKAGE_VERSION@) +Build-Depends-Indep: gtk-doc-tools (>= @GTKDOC_VERSION@) +Standards-Version: 3.7.2 + +Package: gstreamer@GST_MAJORMINOR@-vaapi +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Suggests: gstreamer@GST_MAJORMINOR@-vaapi-doc +Description: VA-API plugins for GStreamer + This package contains GStreamer plugins for VA-API support: + - `vaapidecode': decode bitstreams using VA-API + - `vaapiupload': converts from YUV pixels to VA surfaces + - `vaapidownload': convert from VA surfaces to YUV pixels + - `vaapipostproc': postprocess VA surfaces, e.g. deinterlacing + - `vaapisink': a VA-API based video sink + +Package: gstreamer@GST_MAJORMINOR@-vaapi-doc +Architecture: all +Section: doc +Recommends: libgstvaapi@GST_VAAPI_MAJOR_VERSION@-dev (= ${source:Version}) +Description: GStreamer VA-API documentation and manuals + This packages contains documentation for libraries and elements. + +Package: gstreamer@GST_MAJORMINOR@-vaapi-dbg +Section: libdevel +Architecture: any +Depends: gstreamer@GST_MAJORMINOR@-vaapi (= ${Source-Version}) +Description: VA-API plugins for GStreamer + VA-API support plugins for GStreamer. + . + This package contains the debug files. + +Package: libgstvaapi@GST_VAAPI_MAJOR_VERSION@ +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: GStreamer libraries from the "vaapi" set + VA-API support libraries for GStreamer. + . + This package contains common libraries for the "vaapi" set. + +Package: libgstvaapi-drm-@GST_VAAPI_MAJOR_VERSION@ +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: GStreamer libraries from the "vaapi" set + VA-API support libraries for GStreamer. + . + This package contains headless libraries for the "vaapi" set. + +Package: libgstvaapi-x11-@GST_VAAPI_MAJOR_VERSION@ +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: GStreamer libraries from the "vaapi" set + VA-API support libraries for GStreamer. + . + This package contains x11 libraries for the "vaapi" set. + +Package: libgstvaapi-glx-@GST_VAAPI_MAJOR_VERSION@ +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: GStreamer libraries from the "vaapi" set + VA-API support libraries for GStreamer. + . + This package contains glx libraries for the "vaapi" set. + +Package: libgstvaapi-wayland-@GST_VAAPI_MAJOR_VERSION@ +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: GStreamer libraries from the "vaapi" set + VA-API support libraries for GStreamer. + . + This package contains Wayland libraries for the "vaapi" set. + +Package: libgstvaapi-dev +Architecture: any +Section: libdevel +Depends: ${shlibs:Depends}, ${misc:Depends}, + libgstvaapi@GST_VAAPI_MAJOR_VERSION@ (= ${Source-Version}), + libgstvaapi-x11-@GST_VAAPI_MAJOR_VERSION@ (= ${Source-Version}), + libgstvaapi-glx-@GST_VAAPI_MAJOR_VERSION@ (= ${Source-Version}) +Description: GStreamer development files for libraries from the "vaapi" set + GStreamer/VA-API development files. + . + This package contains development files for GStreamer libraries for + the "vaapi" set. diff --git a/debian.upstream/copyright b/debian.upstream/copyright new file mode 100644 index 0000000..bb733ae --- /dev/null +++ b/debian.upstream/copyright @@ -0,0 +1,35 @@ +This package is maintained by: +Gwenole Beauchesne + +Copyright: + + gstreamer-vaapi helper libraries + and plugins elements: LGPL (v2.1 or later) + +License: + + Copyright (C) 2010-2011, Splitted-Desktop Systems. + Copyright (C) 2011-2012, Intel Corporation. + Copyright (C) 2011, Collabora Ltd. + + gstreamer-vaapi helper libraries and plugins elements are available under + the terms of the GNU Lesser General Public License v2.1+. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 + of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA + +On Debian GNU/Linux systems, the complete text of the GNU Lesser General +Public License can be found in `/usr/share/common-licenses/LGPL-2.1'. + diff --git a/debian.upstream/gstreamer-vaapi-doc.install.in b/debian.upstream/gstreamer-vaapi-doc.install.in new file mode 100644 index 0000000..ff84ca1 --- /dev/null +++ b/debian.upstream/gstreamer-vaapi-doc.install.in @@ -0,0 +1 @@ +debian/tmp/usr/share/doc/gstreamer@GST_MAJORMINOR@-vaapi diff --git a/debian.upstream/gstreamer-vaapi.install.in b/debian.upstream/gstreamer-vaapi.install.in new file mode 100644 index 0000000..5af8fbb --- /dev/null +++ b/debian.upstream/gstreamer-vaapi.install.in @@ -0,0 +1 @@ +debian/tmp/usr/lib/gstreamer-@GST_MAJORMINOR@/libgstvaapi*.so diff --git a/debian.upstream/libgstvaapi-dev.install.in b/debian.upstream/libgstvaapi-dev.install.in new file mode 100644 index 0000000..a940c52 --- /dev/null +++ b/debian.upstream/libgstvaapi-dev.install.in @@ -0,0 +1,3 @@ +debian/tmp/usr/lib/libgstvaapi*.so +debian/tmp/usr/lib/pkgconfig/gstreamer-vaapi*.pc +debian/tmp/usr/include/gstreamer-@GST_MAJORMINOR@/gst/vaapi/*.h diff --git a/debian.upstream/libgstvaapi-drm.install.in b/debian.upstream/libgstvaapi-drm.install.in new file mode 100644 index 0000000..de8b898 --- /dev/null +++ b/debian.upstream/libgstvaapi-drm.install.in @@ -0,0 +1 @@ +debian/tmp/usr/lib/libgstvaapi-drm-@GST_MAJORMINOR@.so.* diff --git a/debian.upstream/libgstvaapi-glx.install.in b/debian.upstream/libgstvaapi-glx.install.in new file mode 100644 index 0000000..cd7352a --- /dev/null +++ b/debian.upstream/libgstvaapi-glx.install.in @@ -0,0 +1 @@ +debian/tmp/usr/lib/libgstvaapi-glx-@GST_MAJORMINOR@.so.* diff --git a/debian.upstream/libgstvaapi-wayland.install.in b/debian.upstream/libgstvaapi-wayland.install.in new file mode 100644 index 0000000..e1740b5 --- /dev/null +++ b/debian.upstream/libgstvaapi-wayland.install.in @@ -0,0 +1 @@ +debian/tmp/usr/lib/libgstvaapi-wayland-@GST_MAJORMINOR@.so.* diff --git a/debian.upstream/libgstvaapi-x11.install.in b/debian.upstream/libgstvaapi-x11.install.in new file mode 100644 index 0000000..8754fb8 --- /dev/null +++ b/debian.upstream/libgstvaapi-x11.install.in @@ -0,0 +1 @@ +debian/tmp/usr/lib/libgstvaapi-x11-@GST_MAJORMINOR@.so.* diff --git a/debian.upstream/libgstvaapi.install.in b/debian.upstream/libgstvaapi.install.in new file mode 100644 index 0000000..e585a6b --- /dev/null +++ b/debian.upstream/libgstvaapi.install.in @@ -0,0 +1 @@ +debian/tmp/usr/lib/libgstvaapi-@GST_MAJORMINOR@.so.* diff --git a/debian.upstream/rules b/debian.upstream/rules new file mode 100755 index 0000000..0ec96be --- /dev/null +++ b/debian.upstream/rules @@ -0,0 +1,29 @@ +#!/usr/bin/make -f + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/autotools.mk +include /usr/share/cdbs/1/rules/simple-patchsys.mk +include /usr/share/cdbs/1/rules/utils.mk + +gst_pkgname = $(shell dpkg-parsechangelog | grep ^Source: | cut -d' ' -f2) + +# Allow SMP build +ifeq ($(DEBIAN_BUILD_NCPUS),) + DEBIAN_BUILD_NCPUS = $(shell /usr/bin/getconf _NPROCESSORS_ONLN) +endif +ifneq ($(DEBIAN_BUILD_NCPUS),) + EXTRA_MAKE_FLAGS += -j$(DEBIAN_BUILD_NCPUS) +endif +MAKE += $(EXTRA_MAKE_FLAGS) + +# Allow HTML documentation build +indep_conf_flags = \ + --with-html-dir=\$${prefix}/share/doc/$(gst_pkgname) + +# only build the docs if gtk-doc-tools is installed, i.e. binary-indep is +# called +ifeq ($(shell test "`dpkg -l gtk-doc-tools | grep ^ii`" && echo binary-indep),binary-indep) +indep_conf_flags += --enable-gtk-doc +endif + +DEB_CONFIGURE_EXTRA_FLAGS += $(indep_conf_flags) diff --git a/docs/Makefile.am b/docs/Makefile.am new file mode 100644 index 0000000..58bb287 --- /dev/null +++ b/docs/Makefile.am @@ -0,0 +1,10 @@ +SUBDIRS = + +if ENABLE_GTK_DOC +SUBDIRS += reference +endif + +DIST_SUBDIRS = reference + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am new file mode 100644 index 0000000..3eef00e --- /dev/null +++ b/docs/reference/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = libs plugins + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/docs/reference/libs/Makefile.am b/docs/reference/libs/Makefile.am new file mode 100644 index 0000000..d4747b3 --- /dev/null +++ b/docs/reference/libs/Makefile.am @@ -0,0 +1,140 @@ +## Process this file with automake to produce Makefile.in + +# We require automake 1.6 at least. +AUTOMAKE_OPTIONS = 1.6 + +# This is a blank Makefile.am for using gtk-doc. +# Copy this to your project's API docs directory and modify the variables to +# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples +# of using the various options. + +# The name of the module, e.g. 'glib'. +DOC_MODULE = libs + +# The top-level SGML file. You can change this if you want to. +DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.xml + +# The directory containing the source code. Relative to $(srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting the functions and macros. +# e.g. DOC_SOURCE_DIR=../../../gtk +DOC_SOURCE_DIR = $(top_srcdir)/gst-libs/gst/vaapi + +# Extra options to pass to gtkdoc-scangobj. Not normally needed. +SCANGOBJ_OPTIONS = --type-init-func="g_type_init()" + +# List files used by scanobj +SCANOBJ_TYPES = $(srcdir)/$(DOC_MODULE).core.types +SCANOBJ_TYPES += $(srcdir)/$(DOC_MODULE).x11.types +if USE_GLX +SCANOBJ_TYPES += $(srcdir)/$(DOC_MODULE).glx.types +endif + +# Extra options to supply to gtkdoc-scan. +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +SCAN_OPTIONS = --deprecated-guards="GST_VAAPI_DISABLE_DEPRECATED" + +# Extra options to supply to gtkdoc-mkdb. +# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml +MKDB_OPTIONS = --sgml-mode --output-format=xml --name-space=$(DOC_MODULE) + +# Extra options to supply to gtkdoc-mktmpl +# e.g. MKTMPL_OPTIONS=--only-section-tmpl +MKTMPL_OPTIONS = + +# Extra options to supply to gtkdoc-fixref. Not normally needed. +# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html +FIXXREF_OPTIONS = \ + --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/glib \ + --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gobject \ + --extra-dir=$(CAIRO_PREFIX)/share/gtk-doc/html/cairo \ + --extra-dir=$(PANGO_PREFIX)/share/gtk-doc/html/pango + +# Used for dependencies. The docs will be rebuilt if any of these change. +# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h +# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c +HFILE_GLOB = $(top_srcdir)/gst-libs/gst/vaapi/*.h +CFILE_GLOB = $(top_srcdir)/gst-libs/gst/vaapi/*.c $(srcdir)/$(DOC_MODULE).types + +# Header files to ignore when scanning. +# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h +IGNORE_HFILES = \ + gstvaapi_priv.h \ + gstvaapicompat.h \ + gstvaapidebug.h \ + gstvaapidecoder_priv.h \ + gstvaapidisplay_priv.h \ + gstvaapidisplay_glx_priv.h \ + gstvaapidisplay_x11_priv.h \ + gstvaapiobject_priv.h \ + gstvaapiutils.h \ + gstvaapiutils_glx.h \ + gstvaapiutils_gst.h \ + gstvaapiutils_x11.h \ + $(NULL) + +EXTRA_HFILES = \ + $(NULL) + +# Images to copy into HTML directory. +# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png +HTML_IMAGES = \ + $(NULL) + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +# e.g. content_files=running.sgml building.sgml changes-2.0.sgml +content_files = \ + $(NULL) + +# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded +# These files must be listed here *and* in content_files +# e.g. expand_content_files=running.sgml +expand_content_files = \ + $(NULL) + +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. +# Only needed if you are using gtkdoc-scangobj to dynamically query widget +# signals and properties. +# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) +# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) + +INCLUDES = \ + $(GLIB_CFLAGS) \ + $(GST_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/gst-libs \ + -I$(top_srcdir)/gst-libs/gst/vaapi + +GTKDOC_LIBS = \ + $(GLIB_LIBS) \ + $(GST_LIBS) \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-$(GST_MAJORMINOR).la + +GTKDOC_LIBS += \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-x11-$(GST_MAJORMINOR).la + +if USE_GLX +GTKDOC_LIBS += \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-glx-$(GST_MAJORMINOR).la +endif + +$(srcdir)/$(DOC_MODULE).types: $(SCANOBJ_TYPES) + cat $(SCANOBJ_TYPES) > $@ + +# This includes the standard gtk-doc make rules, copied by gtkdocize. +include $(top_srcdir)/gtk-doc.make + +# Other files to distribute +# e.g. EXTRA_DIST += version.xml.in +EXTRA_DIST += \ + libs-docs.xml.in \ + libs.core.types \ + libs.x11.types \ + libs.glx.types \ + $(NULL) + +DISTCLEANFILES = $(srcdir)/$(DOC_MODULE).types +BUILT_SOURCES = $(srcdir)/$(DOC_MODULE).types + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in lib-docs.xml diff --git a/docs/reference/libs/libs-docs.xml.in b/docs/reference/libs/libs-docs.xml.in new file mode 100644 index 0000000..34b1665 --- /dev/null +++ b/docs/reference/libs/libs-docs.xml.in @@ -0,0 +1,52 @@ + + + + + GStreamer VA-API Plugins @GST_MAJORMINOR@ Library Reference Manual + + + + gst-plugins-vaapi Library + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Object Hierarchy + + + + + API Index + + + + + diff --git a/docs/reference/libs/libs-overrides.txt b/docs/reference/libs/libs-overrides.txt new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/libs/libs-sections.txt b/docs/reference/libs/libs-sections.txt new file mode 100644 index 0000000..1d9869a --- /dev/null +++ b/docs/reference/libs/libs-sections.txt @@ -0,0 +1,566 @@ +
+gstvaapisurfacepool +GstVaapiSurfacePool +GstVaapiSurfacePool +GstVaapiSurfacePoolClass +gst_vaapi_surface_pool_new + +GST_VAAPI_SURFACE_POOL +GST_VAAPI_IS_SURFACE_POOL +GST_VAAPI_TYPE_SURFACE_POOL +gst_vaapi_surface_pool_get_type +GST_VAAPI_SURFACE_POOL_CLASS +GST_VAAPI_IS_SURFACE_POOL_CLASS +GST_VAAPI_SURFACE_POOL_GET_CLASS +
+ +
+gstvaapivideopool +GstVaapiVideoPool +GstVaapiVideoPool +GstVaapiVideoPoolClass +gst_vaapi_video_pool_get_display +gst_vaapi_video_pool_get_caps +gst_vaapi_video_pool_get_object +gst_vaapi_video_pool_put_object +gst_vaapi_video_pool_add_object +gst_vaapi_video_pool_add_objects +gst_vaapi_video_pool_get_capacity +gst_vaapi_video_pool_set_capacity +gst_vaapi_video_pool_get_size +gst_vaapi_video_pool_reserve + +GST_VAAPI_VIDEO_POOL +GST_VAAPI_IS_VIDEO_POOL +GST_VAAPI_TYPE_VIDEO_POOL +gst_vaapi_video_pool_get_type +GST_VAAPI_VIDEO_POOL_CLASS +GST_VAAPI_IS_VIDEO_POOL_CLASS +GST_VAAPI_VIDEO_POOL_GET_CLASS +
+ +
+gstvaapidisplay_x11 +GstVaapiDisplayX11 +GstVaapiDisplayX11 +GstVaapiDisplayX11Class +gst_vaapi_display_x11_new +gst_vaapi_display_x11_new_with_display +gst_vaapi_display_x11_get_display +gst_vaapi_display_x11_get_screen + +GST_VAAPI_DISPLAY_X11 +GST_VAAPI_IS_DISPLAY_X11 +GST_VAAPI_TYPE_DISPLAY_X11 +gst_vaapi_display_x11_get_type +GST_VAAPI_DISPLAY_X11_CLASS +GST_VAAPI_IS_DISPLAY_X11_CLASS +GST_VAAPI_DISPLAY_X11_GET_CLASS +
+ +
+gstvaapiwindow_x11 +GstVaapiWindowX11 +GstVaapiWindowX11 +GstVaapiWindowX11Class +GST_VAAPI_WINDOW_XWINDOW +gst_vaapi_window_x11_new +gst_vaapi_window_x11_new_with_xid +gst_vaapi_window_x11_get_xid +gst_vaapi_window_x11_is_foreign_xid + +GST_VAAPI_WINDOW_X11 +GST_VAAPI_IS_WINDOW_X11 +GST_VAAPI_TYPE_WINDOW_X11 +gst_vaapi_window_x11_get_type +GST_VAAPI_WINDOW_X11_CLASS +GST_VAAPI_IS_WINDOW_X11_CLASS +GST_VAAPI_WINDOW_X11_GET_CLASS +
+ +
+gstvaapidisplay_glx +GstVaapiDisplayGLX +GstVaapiDisplayGLX +GstVaapiDisplayGLXClass +gst_vaapi_display_glx_new +gst_vaapi_display_glx_new_with_display + +GST_VAAPI_DISPLAY_GLX +GST_VAAPI_IS_DISPLAY_GLX +GST_VAAPI_TYPE_DISPLAY_GLX +gst_vaapi_display_glx_get_type +GST_VAAPI_DISPLAY_GLX_CLASS +GST_VAAPI_IS_DISPLAY_GLX_CLASS +GST_VAAPI_DISPLAY_GLX_GET_CLASS +
+ +
+gstvaapiwindow_glx +GstVaapiWindowGLX +GstVaapiWindowGLX +GstVaapiWindowGLXClass +gst_vaapi_window_glx_new +gst_vaapi_window_glx_new_with_xid +gst_vaapi_window_glx_get_context +gst_vaapi_window_glx_set_context +gst_vaapi_window_glx_make_current +gst_vaapi_window_glx_swap_buffers +gst_vaapi_window_glx_put_texture + +GST_VAAPI_WINDOW_GLX +GST_VAAPI_IS_WINDOW_GLX +GST_VAAPI_TYPE_WINDOW_GLX +gst_vaapi_window_glx_get_type +GST_VAAPI_WINDOW_GLX_CLASS +GST_VAAPI_IS_WINDOW_GLX_CLASS +GST_VAAPI_WINDOW_GLX_GET_CLASS +
+ +
+gstvaapidisplay +GstVaapiDisplay +GstVaapiDisplay +GstVaapiDisplayClass +gst_vaapi_display_new_with_display +gst_vaapi_display_lock +gst_vaapi_display_unlock +gst_vaapi_display_sync +gst_vaapi_display_flush +gst_vaapi_display_get_display +gst_vaapi_display_get_width +gst_vaapi_display_get_height +gst_vaapi_display_get_size +gst_vaapi_display_get_pixel_aspect_ratio +gst_vaapi_display_get_decode_caps +gst_vaapi_display_has_decoder +gst_vaapi_display_get_encode_caps +gst_vaapi_display_has_encoder +gst_vaapi_display_get_image_caps +gst_vaapi_display_has_image_format +gst_vaapi_display_get_subpicture_caps +gst_vaapi_display_has_subpicture_format + +GST_VAAPI_DISPLAY +GST_VAAPI_IS_DISPLAY +GST_VAAPI_TYPE_DISPLAY +gst_vaapi_display_get_type +GST_VAAPI_DISPLAY_CLASS +GST_VAAPI_IS_DISPLAY_CLASS +GST_VAAPI_DISPLAY_GET_CLASS +
+ +
+gstvaapiimagepool +GstVaapiImagePool +GstVaapiImagePool +GstVaapiImagePoolClass +gst_vaapi_image_pool_new + +GST_VAAPI_IMAGE_POOL +GST_VAAPI_IS_IMAGE_POOL +GST_VAAPI_TYPE_IMAGE_POOL +gst_vaapi_image_pool_get_type +GST_VAAPI_IMAGE_POOL_CLASS +GST_VAAPI_IS_IMAGE_POOL_CLASS +GST_VAAPI_IMAGE_POOL_GET_CLASS +
+ +
+gstvaapivideobuffer +GstVaapiVideoBuffer +GstVaapiVideoBuffer +GstVaapiVideoBufferClass +gst_vaapi_video_buffer_typed_new +gst_vaapi_video_buffer_typed_new_from_pool +gst_vaapi_video_buffer_typed_new_from_buffer +gst_vaapi_video_buffer_typed_new_with_image +gst_vaapi_video_buffer_typed_new_with_surface +gst_vaapi_video_buffer_typed_new_with_surface_proxy +gst_vaapi_video_buffer_get_display +gst_vaapi_video_buffer_get_image +gst_vaapi_video_buffer_set_image +gst_vaapi_video_buffer_set_image_from_pool +gst_vaapi_video_buffer_get_surface +gst_vaapi_video_buffer_get_surface_proxy +gst_vaapi_video_buffer_set_surface +gst_vaapi_video_buffer_set_surface_proxy +gst_vaapi_video_buffer_set_surface_from_pool +gst_vaapi_video_buffer_get_render_flags +gst_vaapi_video_buffer_set_render_flags + +GST_VAAPI_VIDEO_BUFFER +GST_VAAPI_IS_VIDEO_BUFFER +GST_VAAPI_TYPE_VIDEO_BUFFER +gst_vaapi_video_buffer_get_type +GST_VAAPI_VIDEO_BUFFER_CLASS +GST_VAAPI_IS_VIDEO_BUFFER_CLASS +GST_VAAPI_VIDEO_BUFFER_GET_CLASS +
+ +
+gstvaapitypes +Basic data structures +GstVaapiID +GST_VAAPI_ID_FORMAT +GST_VAAPI_ID_ARGS +GST_VAAPI_ID +GST_VAAPI_ID_NONE +GstVaapiPoint +GstVaapiRectangle +
+ +
+gstvaapivalue + +GST_VAAPI_TYPE_ID +gst_vaapi_value_get_id +gst_vaapi_value_set_id +
+ +
+gstvaapiparamspecs + +GstVaapiParamSpecID +gst_vaapi_param_spec_id +
+ +
+gstvaapiwindow +GstVaapiWindow +GstVaapiWindow +GstVaapiWindowClass +gst_vaapi_window_get_display +gst_vaapi_window_show +gst_vaapi_window_hide +gst_vaapi_window_get_fullscreen +gst_vaapi_window_set_fullscreen +gst_vaapi_window_get_width +gst_vaapi_window_get_height +gst_vaapi_window_get_size +gst_vaapi_window_set_width +gst_vaapi_window_set_height +gst_vaapi_window_set_size +gst_vaapi_window_put_surface + +GST_VAAPI_WINDOW +GST_VAAPI_IS_WINDOW +GST_VAAPI_TYPE_WINDOW +gst_vaapi_window_get_type +GST_VAAPI_WINDOW_CLASS +GST_VAAPI_IS_WINDOW_CLASS +GST_VAAPI_WINDOW_GET_CLASS +
+ +
+gstvaapiobject +GstVaapiObject +GstVaapiObject +GstVaapiObjectClass +gst_vaapi_object_get_display +gst_vaapi_object_lock_display +gst_vaapi_object_unlock_display +gst_vaapi_object_get_id + +GST_VAAPI_OBJECT +GST_VAAPI_IS_OBJECT +GST_VAAPI_TYPE_OBJECT +gst_vaapi_object_get_type +GST_VAAPI_OBJECT_CLASS +GST_VAAPI_IS_OBJECT_CLASS +GST_VAAPI_OBJECT_GET_CLASS +
+ +
+gstvaapiimage +GST_VAAPI_IMAGE_FORMAT +GST_VAAPI_IMAGE_WIDTH +GST_VAAPI_IMAGE_HEIGHT +GstVaapiImage +GstVaapiImage +GstVaapiImageClass +gst_vaapi_image_new +gst_vaapi_image_new_with_image +gst_vaapi_image_get_id +gst_vaapi_image_get_image +gst_vaapi_image_get_format +gst_vaapi_image_get_width +gst_vaapi_image_get_height +gst_vaapi_image_get_size +gst_vaapi_image_is_linear +gst_vaapi_image_is_mapped +gst_vaapi_image_map +gst_vaapi_image_unmap +gst_vaapi_image_get_plane_count +gst_vaapi_image_get_plane +gst_vaapi_image_get_pitch +gst_vaapi_image_get_data_size +gst_vaapi_image_get_buffer +gst_vaapi_image_get_raw +gst_vaapi_image_update_from_buffer + +GST_VAAPI_IMAGE +GST_VAAPI_IS_IMAGE +GST_VAAPI_TYPE_IMAGE +gst_vaapi_image_get_type +GST_VAAPI_IMAGE_CLASS +GST_VAAPI_IS_IMAGE_CLASS +GST_VAAPI_IMAGE_GET_CLASS +
+ +
+gstvaapisurface +GstVaapiChromaType +GstVaapiSurfaceStatus +GstVaapiSurfaceRenderFlags +GstVaapiSurface +GstVaapiSurface +GstVaapiSurfaceClass +gst_vaapi_surface_new +gst_vaapi_surface_get_id +gst_vaapi_surface_get_chroma_type +gst_vaapi_surface_get_width +gst_vaapi_surface_get_height +gst_vaapi_surface_get_size +gst_vaapi_surface_derive_image +gst_vaapi_surface_get_image +gst_vaapi_surface_put_image +gst_vaapi_surface_associate_subpicture +gst_vaapi_surface_deassociate_subpicture +gst_vaapi_surface_sync +gst_vaapi_surface_query_status + +GST_VAAPI_SURFACE +GST_VAAPI_IS_SURFACE +GST_VAAPI_TYPE_SURFACE +gst_vaapi_surface_get_type +GST_VAAPI_SURFACE_CLASS +GST_VAAPI_IS_SURFACE_CLASS +GST_VAAPI_SURFACE_GET_CLASS +
+ +
+gstvaapisubpicture +GstVaapiSubpicture +GstVaapiSubpicture +GstVaapiSubpictureClass +gst_vaapi_subpicture_new +gst_vaapi_subpicture_get_id +gst_vaapi_subpicture_get_image +gst_vaapi_subpicture_set_image + +GST_VAAPI_SUBPICTURE +GST_VAAPI_IS_SUBPICTURE +GST_VAAPI_TYPE_SUBPICTURE +gst_vaapi_subpicture_get_type +GST_VAAPI_SUBPICTURE_CLASS +GST_VAAPI_IS_SUBPICTURE_CLASS +GST_VAAPI_SUBPICTURE_GET_CLASS +
+ +
+gstvaapiimageformat +GstVaapiImageFormat +GstVaapiImageFormat +gst_vaapi_image_format_is_rgb +gst_vaapi_image_format_is_yuv +gst_vaapi_image_format +gst_vaapi_image_format_from_caps +gst_vaapi_image_format_from_fourcc +gst_vaapi_image_format_from_video +gst_vaapi_image_format_get_va_format +gst_vaapi_image_format_get_caps +gst_vaapi_image_format_get_score +
+ +
+gstvaapiprofile +GstVaapiProfile +GstVaapiCodec +GstVaapiProfile +GstVaapiEntrypoint +gst_vaapi_profile +gst_vaapi_profile_from_caps +gst_vaapi_profile_get_va_profile +gst_vaapi_profile_get_caps +gst_vaapi_profile_get_codec +gst_vaapi_entrypoint +gst_vaapi_entrypoint_get_va_entrypoint +
+ +
+gstvaapitexture +GstVaapiTexture +GstVaapiTexture +GstVaapiTextureClass +gst_vaapi_texture_new +gst_vaapi_texture_new_with_texture +gst_vaapi_texture_get_id +gst_vaapi_texture_get_target +gst_vaapi_texture_get_format +gst_vaapi_texture_get_width +gst_vaapi_texture_get_height +gst_vaapi_texture_get_size +gst_vaapi_texture_put_surface + +GST_VAAPI_TEXTURE +GST_VAAPI_IS_TEXTURE +GST_VAAPI_TYPE_TEXTURE +gst_vaapi_texture_get_type +GST_VAAPI_TEXTURE_CLASS +GST_VAAPI_IS_TEXTURE_CLASS +GST_VAAPI_TEXTURE_GET_CLASS +
+ +
+gstvaapicontext +GstVaapiContext +GstVaapiContext +GstVaapiContextClass +gst_vaapi_context_new +gst_vaapi_context_reset +gst_vaapi_context_get_id +gst_vaapi_context_get_profile +gst_vaapi_context_set_profile +gst_vaapi_context_get_entrypoint +gst_vaapi_context_get_size +gst_vaapi_context_get_surface +gst_vaapi_context_get_surface_count +gst_vaapi_context_put_surface +gst_vaapi_context_find_surface_by_id +gst_vaapi_context_apply_composition + +GST_VAAPI_CONTEXT +GST_VAAPI_IS_CONTEXT +GST_VAAPI_TYPE_CONTEXT +gst_vaapi_context_get_type +GST_VAAPI_CONTEXT_CLASS +GST_VAAPI_IS_CONTEXT_CLASS +GST_VAAPI_CONTEXT_GET_CLASS +
+ +
+gstvaapidecoder +GstVaapiDecoderStatus +GstVaapiDecoder +GstVaapiDecoder +GstVaapiDecoderClass +gst_vaapi_decoder_get_caps +gst_vaapi_decoder_put_buffer +gst_vaapi_decoder_get_surface + +GST_VAAPI_DECODER +GST_VAAPI_IS_DECODER +GST_VAAPI_TYPE_DECODER +gst_vaapi_decoder_get_type +GST_VAAPI_DECODER_CLASS +GST_VAAPI_IS_DECODER_CLASS +GST_VAAPI_DECODER_GET_CLASS +
+ +
+gstvaapidecoder_jpeg +GstVaapiDecoderJpeg +GstVaapiDecoderJpeg +GstVaapiDecoderJpegClass +gst_vaapi_decoder_jpeg_new + +GST_VAAPI_DECODER_JPEG +GST_VAAPI_IS_DECODER_JPEG +GST_VAAPI_TYPE_DECODER_JPEG +gst_vaapi_decoder_jpeg_get_type +GST_VAAPI_DECODER_JPEG_CLASS +GST_VAAPI_IS_DECODER_JPEG_CLASS +GST_VAAPI_DECODER_JPEG_GET_CLASS +
+ +
+gstvaapidecoder_mpeg2 +GstVaapiDecoderMpeg2 +GstVaapiDecoderMpeg2 +GstVaapiDecoderMpeg2Class +gst_vaapi_decoder_mpeg2_new + +GST_VAAPI_DECODER_MPEG2 +GST_VAAPI_IS_DECODER_MPEG2 +GST_VAAPI_TYPE_DECODER_MPEG2 +gst_vaapi_decoder_mpeg2_get_type +GST_VAAPI_DECODER_MPEG2_CLASS +GST_VAAPI_IS_DECODER_MPEG2_CLASS +GST_VAAPI_DECODER_MPEG2_GET_CLASS +
+ +
+gstvaapidecoder_mpeg4 +GstVaapiDecoderMpeg4 +GstVaapiDecoderMpeg4 +GstVaapiDecoderMpeg4Class +gst_vaapi_decoder_mpeg4_new + +GST_VAAPI_DECODER_MPEG4 +GST_VAAPI_IS_DECODER_MPEG4 +GST_VAAPI_TYPE_DECODER_MPEG4 +gst_vaapi_decoder_mpeg4_get_type +GST_VAAPI_DECODER_MPEG4_CLASS +GST_VAAPI_IS_DECODER_MPEG4_CLASS +GST_VAAPI_DECODER_MPEG4_GET_CLASS +
+ +
+gstvaapidecoder_h264 +GstVaapiDecoderH264 +GstVaapiDecoderH264 +GstVaapiDecoderH264Class +gst_vaapi_decoder_h264_new + +GST_VAAPI_DECODER_H264 +GST_VAAPI_IS_DECODER_H264 +GST_VAAPI_TYPE_DECODER_H264 +gst_vaapi_decoder_h264_get_type +GST_VAAPI_DECODER_H264_CLASS +GST_VAAPI_IS_DECODER_H264_CLASS +GST_VAAPI_DECODER_H264_GET_CLASS +
+ +
+gstvaapidecoder_vc1 +GstVaapiDecoderVC1 +GstVaapiDecoderVC1 +GstVaapiDecoderVC1Class +gst_vaapi_decoder_vc1_new + +GST_VAAPI_DECODER_VC1 +GST_VAAPI_IS_DECODER_VC1 +GST_VAAPI_TYPE_DECODER_VC1 +gst_vaapi_decoder_vc1_get_type +GST_VAAPI_DECODER_VC1_CLASS +GST_VAAPI_IS_DECODER_VC1_CLASS +GST_VAAPI_DECODER_VC1_GET_CLASS +
+ +
+gstvaapisurfaceproxy +GstVaapiSurfaceProxy +GstVaapiSurfaceProxy +GstVaapiSurfaceProxyClass +gst_vaapi_surface_proxy_new +gst_vaapi_surface_proxy_get_context +gst_vaapi_surface_proxy_set_context +gst_vaapi_surface_proxy_get_surface +gst_vaapi_surface_proxy_get_surface_id +gst_vaapi_surface_proxy_set_surface +gst_vaapi_surface_proxy_get_timestamp +gst_vaapi_surface_proxy_set_timestamp +gst_vaapi_surface_proxy_get_interlaced +gst_vaapi_surface_proxy_set_interlaced +gst_vaapi_surface_proxy_get_tff +gst_vaapi_surface_proxy_set_tff + +GST_VAAPI_SURFACE_PROXY +GST_VAAPI_IS_SURFACE_PROXY +GST_VAAPI_TYPE_SURFACE_PROXY +gst_vaapi_surface_proxy_get_type +GST_VAAPI_SURFACE_PROXY_CLASS +GST_VAAPI_IS_SURFACE_PROXY_CLASS +GST_VAAPI_SURFACE_PROXY_GET_CLASS +
diff --git a/docs/reference/libs/libs.core.types b/docs/reference/libs/libs.core.types new file mode 100644 index 0000000..b779fd6 --- /dev/null +++ b/docs/reference/libs/libs.core.types @@ -0,0 +1,14 @@ +gst_vaapi_context_get_type +gst_vaapi_decoder_get_type +gst_vaapi_display_get_type +gst_vaapi_image_get_type +gst_vaapi_image_pool_get_type +gst_vaapi_object_get_type +gst_vaapi_subpicture_get_type +gst_vaapi_surface_get_type +gst_vaapi_surface_pool_get_type +gst_vaapi_surface_proxy_get_type +gst_vaapi_video_buffer_get_type +gst_vaapi_video_pool_get_type +gst_vaapi_video_sink_get_type +gst_vaapi_window_get_type diff --git a/docs/reference/libs/libs.glx.types b/docs/reference/libs/libs.glx.types new file mode 100644 index 0000000..6ecd354 --- /dev/null +++ b/docs/reference/libs/libs.glx.types @@ -0,0 +1,3 @@ +gst_vaapi_display_glx_get_type +gst_vaapi_texture_get_type +gst_vaapi_window_glx_get_type diff --git a/docs/reference/libs/libs.x11.types b/docs/reference/libs/libs.x11.types new file mode 100644 index 0000000..c083ce0 --- /dev/null +++ b/docs/reference/libs/libs.x11.types @@ -0,0 +1,2 @@ +gst_vaapi_display_x11_get_type +gst_vaapi_window_x11_get_type diff --git a/docs/reference/plugins/Makefile.am b/docs/reference/plugins/Makefile.am new file mode 100644 index 0000000..0bb388c --- /dev/null +++ b/docs/reference/plugins/Makefile.am @@ -0,0 +1,108 @@ +## Process this file with automake to produce Makefile.in + +# We require automake 1.6 at least. +AUTOMAKE_OPTIONS = 1.6 + +# This is a blank Makefile.am for using gtk-doc. +# Copy this to your project's API docs directory and modify the variables to +# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples +# of using the various options. + +# The name of the module, e.g. 'glib'. +DOC_MODULE = plugins + +# The top-level SGML file. You can change this if you want to. +DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.xml + +# The directory containing the source code. Relative to $(srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting the functions and macros. +# e.g. DOC_SOURCE_DIR=../../../gtk +DOC_SOURCE_DIR = $(top_srcdir)/gst + +# Extra options to pass to gtkdoc-scangobj. Not normally needed. +SCANGOBJ_OPTIONS = --type-init-func="gst_init(NULL, NULL)" + +# Extra options to supply to gtkdoc-scan. +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +SCAN_OPTIONS = --deprecated-guards="GST_VAAPI_DISABLE_DEPRECATED" + +# Extra options to supply to gtkdoc-mkdb. +# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml +MKDB_OPTIONS = --sgml-mode --output-format=xml --name-space=$(DOC_MODULE) + +# Extra options to supply to gtkdoc-mktmpl +# e.g. MKTMPL_OPTIONS=--only-section-tmpl +MKTMPL_OPTIONS = + +# Extra options to supply to gtkdoc-fixref. Not normally needed. +# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html +FIXXREF_OPTIONS = \ + --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/glib \ + --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gobject \ + --extra-dir=$(CAIRO_PREFIX)/share/gtk-doc/html/cairo \ + --extra-dir=$(PANGO_PREFIX)/share/gtk-doc/html/pango + +# Used for dependencies. The docs will be rebuilt if any of these change. +# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h +# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c +HFILE_GLOB = $(top_srcdir)/gst/*/*.h +CFILE_GLOB = $(top_srcdir)/gst/*/*.c + +# Header files to ignore when scanning. +# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h +IGNORE_HFILES = \ + $(NULL) + +EXTRA_HFILES = \ + $(NULL) + +# Images to copy into HTML directory. +# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png +HTML_IMAGES = \ + $(NULL) + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +# e.g. content_files=running.sgml building.sgml changes-2.0.sgml +content_files = \ + $(NULL) + +# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded +# These files must be listed here *and* in content_files +# e.g. expand_content_files=running.sgml +expand_content_files = \ + $(NULL) + +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. +# Only needed if you are using gtkdoc-scangobj to dynamically query widget +# signals and properties. +# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) +# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) + +INCLUDES = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/gst-libs \ + -I$(top_srcdir)/gst-libs/gst/vaapi \ + $(GLIB_CFLAGS) \ + $(GST_CFLAGS) \ + $(NULL) + +GTKDOC_LIBS = \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-$(GST_MAJORMINOR).la \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-x11-$(GST_MAJORMINOR).la \ + $(top_builddir)/gst/vaapi/libgstvaapi.la \ + $(GLIB_LIBS) \ + $(GST_LIBS) \ + $(NULL) + +# This includes the standard gtk-doc make rules, copied by gtkdocize. +include $(top_srcdir)/gtk-doc.make + +# Other files to distribute +# e.g. EXTRA_DIST += version.xml.in +EXTRA_DIST += \ + $(DOC_MODULE)-docs.xml.in \ + $(NULL) + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in $(DOC_MODULE)-docs.xml diff --git a/docs/reference/plugins/plugins-docs.xml.in b/docs/reference/plugins/plugins-docs.xml.in new file mode 100644 index 0000000..3532a55 --- /dev/null +++ b/docs/reference/plugins/plugins-docs.xml.in @@ -0,0 +1,32 @@ + + +]> + + + GStreamer VA-API Plugins @GST_MAJORMINOR@ Plugins Reference Manual + + + + gst-plugins-vaapi Plugins + + + + + + + + + Object Hierarchy + + + + + API Index + + + + + diff --git a/docs/reference/plugins/plugins-overrides.txt b/docs/reference/plugins/plugins-overrides.txt new file mode 100644 index 0000000..e69de29 diff --git a/docs/reference/plugins/plugins-sections.txt b/docs/reference/plugins/plugins-sections.txt new file mode 100644 index 0000000..58f3fe8 --- /dev/null +++ b/docs/reference/plugins/plugins-sections.txt @@ -0,0 +1,69 @@ +
+gstvaapisink +GstVaapiSink +GstVaapiSink + +GST_VAAPISINK +GST_IS_VAAPISINK +GST_TYPE_VAAPISINK +gst_vaapisink_get_type +GST_VAAPISINK_CLASS +GST_IS_VAAPISINK_CLASS +GST_VAAPISINK_GET_CLASS +
+ +
+gstvaapidecode +GstVaapiDecode +GstVaapiDecode + +GST_VAAPIDECODE +GST_IS_VAAPIDECODE +GST_TYPE_VAAPIDECODE +gst_vaapidecode_get_type +GST_VAAPIDECODE_CLASS +GST_IS_VAAPIDECODE_CLASS +GST_VAAPIDECODE_GET_CLASS +
+ +
+gstvaapipostproc +GstVaapiPostproc +GstVaapiPostproc + +GST_VAAPIPOSTPROC +GST_IS_VAAPIPOSTPROC +GST_TYPE_VAAPIPOSTPROC +gst_vaapipostproc_get_type +GST_VAAPIPOSTPROC_CLASS +GST_IS_VAAPIPOSTPROC_CLASS +GST_VAAPIPOSTPROC_GET_CLASS +
+ +
+gstvaapiupload +GstVaapiUpload +GstVaapiUpload + +GST_VAAPIUPLOAD +GST_IS_VAAPIUPLOAD +GST_TYPE_VAAPIUPLOAD +gst_vaapiupload_get_type +GST_VAAPIUPLOAD_CLASS +GST_IS_VAAPIUPLOAD_CLASS +GST_VAAPIUPLOAD_GET_CLASS +
+ +
+gstvaapidownload +GstVaapiDownload +GstVaapiDownload + +GST_VAAPIDOWNLOAD +GST_IS_VAAPIDOWNLOAD +GST_TYPE_VAAPIDOWNLOAD +gst_vaapidownload_get_type +GST_VAAPIDOWNLOAD_CLASS +GST_IS_VAAPIDOWNLOAD_CLASS +GST_VAAPIDOWNLOAD_GET_CLASS +
diff --git a/docs/reference/plugins/plugins.types b/docs/reference/plugins/plugins.types new file mode 100644 index 0000000..4117580 --- /dev/null +++ b/docs/reference/plugins/plugins.types @@ -0,0 +1,5 @@ +gst_vaapidecode_get_type +gst_vaapidownload_get_type +gst_vaapipostproc_get_type +gst_vaapisink_get_type +gst_vaapiupload_get_type diff --git a/gst-libs/gst/Makefile.am b/gst-libs/gst/Makefile.am index 37d365d..06d14db 100644 --- a/gst-libs/gst/Makefile.am +++ b/gst-libs/gst/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = vaapi +SUBDIRS = codecparsers vaapi # Extra clean files so that maintainer-clean removes *everything* -MAINTAINERCLEANFILES = Makefile.in +MAINTAINERCLEANFILES = Makefile.in $(gen_headers) diff --git a/gst-libs/gst/codecparsers/Makefile.am b/gst-libs/gst/codecparsers/Makefile.am new file mode 100644 index 0000000..aa10113 --- /dev/null +++ b/gst-libs/gst/codecparsers/Makefile.am @@ -0,0 +1,43 @@ +noinst_LTLIBRARIES = \ + libgstvaapi-codecparsers.la \ + $(NULL) + +libgstvaapi_codecparsers_cflags = \ + -DGST_USE_UNSTABLE_API \ + -I$(top_srcdir)/gst-libs \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) \ + $(NULL) + +libgstvaapi_codecparsers_libs = \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) \ + $(NULL) + +libgstvaapi_codecparsers_source_c = \ + gstjpegparser.c \ + $(NULL) + +libgstvaapi_codecparsers_source_h = \ + gstjpegparser.h \ + $(NULL) + +libgstvaapi_codecparsers_la_SOURCES = \ + $(libgstvaapi_codecparsers_source_c) \ + $(libgstvaapi_codecparsers_source_h) \ + $(NULL) + +libgstvaapi_codecparsers_la_CFLAGS = \ + $(libgstvaapi_codecparsers_cflags) \ + $(NULL) + +libgstvaapi_codecparsers_la_LIBADD = \ + $(libgstvaapi_codecparsers_libs) \ + $(NULL) + +libgstvaapi_codecparsers_la_LDFLAGS = \ + $(GST_ALL_LDFLAGS) \ + $(NULL) + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/gst-libs/gst/codecparsers/gstjpegparser.c b/gst-libs/gst/codecparsers/gstjpegparser.c new file mode 100644 index 0000000..ca597ad --- /dev/null +++ b/gst-libs/gst/codecparsers/gstjpegparser.c @@ -0,0 +1,610 @@ +/* + * gstjpegparser.c - JPEG parser + * + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include "gstjpegparser.h" + +#ifndef GST_DISABLE_GST_DEBUG + +#define GST_CAT_DEFAULT ensure_debug_category() + +static GstDebugCategory * +ensure_debug_category (void) +{ + static gsize cat_gonce = 0; + + if (g_once_init_enter (&cat_gonce)) { + gsize cat_done; + + cat_done = (gsize) _gst_debug_category_new ("codecparsers_jpeg", 0, + "GstJpegCodecParser"); + + g_once_init_leave (&cat_gonce, cat_done); + } + + return (GstDebugCategory *) cat_gonce; +} +#else + +#define ensure_debug_category() /* NOOP */ + +#endif /* GST_DISABLE_GST_DEBUG */ + +#define DEBUG_PRINT_COMMENT 0 + +#define READ_UINT8(reader, val) G_STMT_START { \ + if (!gst_byte_reader_get_uint8 ((reader), &(val))) { \ + GST_WARNING ("failed to read uint8"); \ + goto failed; \ + } \ + } G_STMT_END + +#define READ_UINT16(reader, val) G_STMT_START { \ + if (!gst_byte_reader_get_uint16_be ((reader), &(val))) { \ + GST_WARNING ("failed to read uint16"); \ + goto failed; \ + } \ + } G_STMT_END + +#define READ_BYTES(reader, buf, length) G_STMT_START { \ + const guint8 *vals; \ + if (!gst_byte_reader_get_data (reader, length, &vals)) { \ + GST_WARNING ("failed to read bytes, size:%d", length); \ + goto failed; \ + } \ + memcpy (buf, vals, length); \ + } G_STMT_END + +#define U_READ_UINT8(reader, val) G_STMT_START { \ + (val) = gst_byte_reader_get_uint8_unchecked(reader); \ + } G_STMT_END + +#define U_READ_UINT16(reader, val) G_STMT_START { \ + (val) = gst_byte_reader_get_uint16_be_unchecked(reader); \ + } G_STMT_END + + +/* Table used to address an 8x8 matrix in zig-zag order */ +/* *INDENT-OFF* */ +static const guint8 zigzag_index[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; +/* *INDENT-ON* */ + +/* Table K.1 - Luminance quantization table */ +/* *INDENT-OFF* */ +static const guint8 default_luminance_quant_table[64] = { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 +}; +/* *INDENT-ON* */ + +/* Table K.2 - Chrominance quantization table */ +/* *INDENT-OFF* */ +static const guint8 default_chrominance_quant_table[64] = { + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; +/* *INDENT-ON* */ + +typedef struct _GstJpegHuffmanTableEntry GstJpegHuffmanTableEntry; +struct _GstJpegHuffmanTableEntry +{ + guint8 value; /* category */ + guint8 length; /* code length in bits */ +}; + +/* Table K.3 - Table for luminance DC coefficient differences */ +static const GstJpegHuffmanTableEntry default_luminance_dc_table[] = { + {0x00, 2}, {0x01, 3}, {0x02, 3}, {0x03, 3}, {0x04, 3}, {0x05, 3}, + {0x06, 4}, {0x07, 5}, {0x08, 6}, {0x09, 7}, {0x0a, 8}, {0x0b, 9} +}; + +/* Table K.4 - Table for chrominance DC coefficient differences */ +static const GstJpegHuffmanTableEntry default_chrominance_dc_table[] = { + {0x00, 2}, {0x01, 2}, {0x02, 2}, {0x03, 3}, {0x04, 4}, {0x05, 5}, + {0x06, 6}, {0x07, 7}, {0x08, 8}, {0x09, 9}, {0x0a, 10}, {0x0b, 11} +}; + +/* Table K.5 - Table for luminance AC coefficients */ +/* *INDENT-OFF* */ +static const GstJpegHuffmanTableEntry default_luminance_ac_table[] = { + {0x00, 4}, {0x01, 2}, {0x02, 2}, {0x03, 3}, {0x04, 4}, {0x05, 5}, + {0x06, 7}, {0x07, 8}, {0x08, 10}, {0x09, 16}, {0x0a, 16}, {0x11, 4}, + {0x12, 5}, {0x13, 7}, {0x14, 9}, {0x15, 11}, {0x16, 16}, {0x17, 16}, + {0x18, 16}, {0x19, 16}, {0x1a, 16}, {0x21, 5}, {0x22, 8}, {0x23, 10}, + {0x24, 12}, {0x25, 16}, {0x26, 16}, {0x27, 16}, {0x28, 16}, {0x29, 16}, + {0x2a, 16}, {0x31, 6}, {0x32, 9}, {0x33, 12}, {0x34, 16}, {0x35, 16}, + {0x36, 16}, {0x37, 16}, {0x38, 16}, {0x39, 16}, {0x3a, 16}, {0x41, 6}, + {0x42, 10}, {0x43, 16}, {0x44, 16}, {0x45, 16}, {0x46, 16}, {0x47, 16}, + {0x48, 16}, {0x49, 16}, {0x4a, 16}, {0x51, 7}, {0x52, 11}, {0x53, 16}, + {0x54, 16}, {0x55, 16}, {0x56, 16}, {0x57, 16}, {0x58, 16}, {0x59, 16}, + {0x5a, 16}, {0x61, 7}, {0x62, 12}, {0x63, 16}, {0x64, 16}, {0x65, 16}, + {0x66, 16}, {0x67, 16}, {0x68, 16}, {0x69, 16}, {0x6a, 16}, {0x71, 8}, + {0x72, 12}, {0x73, 16}, {0x74, 16}, {0x75, 16}, {0x76, 16}, {0x77, 16}, + {0x78, 16}, {0x79, 16}, {0x7a, 16}, {0x81, 9}, {0x82, 15}, {0x83, 16}, + {0x84, 16}, {0x85, 16}, {0x86, 16}, {0x87, 16}, {0x88, 16}, {0x89, 16}, + {0x8a, 16}, {0x91, 9}, {0x92, 16}, {0x93, 16}, {0x94, 16}, {0x95, 16}, + {0x96, 16}, {0x97, 16}, {0x98, 16}, {0x99, 16}, {0x9a, 16}, {0xa1, 9}, + {0xa2, 16}, {0xa3, 16}, {0xa4, 16}, {0xa5, 16}, {0xa6, 16}, {0xa7, 16}, + {0xa8, 16}, {0xa9, 16}, {0xaa, 16}, {0xb1, 10}, {0xb2, 16}, {0xb3, 16}, + {0xb4, 16}, {0xb5, 16}, {0xb6, 16}, {0xb7, 16}, {0xb8, 16}, {0xb9, 16}, + {0xba, 16}, {0xc1, 10}, {0xc2, 16}, {0xc3, 16}, {0xc4, 16}, {0xc5, 16}, + {0xc6, 16}, {0xc7, 16}, {0xc8, 16}, {0xc9, 16}, {0xca, 16}, {0xd1, 11}, + {0xd2, 16}, {0xd3, 16}, {0xd4, 16}, {0xd5, 16}, {0xd6, 16}, {0xd7, 16}, + {0xd8, 16}, {0xd9, 16}, {0xda, 16}, {0xe1, 16}, {0xe2, 16}, {0xe3, 16}, + {0xe4, 16}, {0xe5, 16}, {0xe6, 16}, {0xe7, 16}, {0xe8, 16}, {0xe9, 16}, + {0xea, 16}, {0xf0, 11}, {0xf1, 16}, {0xf2, 16}, {0xf3, 16}, {0xf4, 16}, + {0xf5, 16}, {0xf6, 16}, {0xf7, 16}, {0xf8, 16}, {0xf9, 16}, {0xfa, 16} +}; +/* *INDENT-ON* */ + +/* Table K.6 - Table for chrominance AC coefficients */ +/* *INDENT-OFF* */ +static const GstJpegHuffmanTableEntry default_chrominance_ac_table[] = { + {0x00, 2}, {0x01, 2}, {0x02, 3}, {0x03, 4}, {0x04, 5}, {0x05, 5}, + {0x06, 6}, {0x07, 7}, {0x08, 9}, {0x09, 10}, {0x0a, 12}, {0x11, 4}, + {0x12, 6}, {0x13, 8}, {0x14, 9}, {0x15, 11}, {0x16, 12}, {0x17, 16}, + {0x18, 16}, {0x19, 16}, {0x1a, 16}, {0x21, 5}, {0x22, 8}, {0x23, 10}, + {0x24, 12}, {0x25, 15}, {0x26, 16}, {0x27, 16}, {0x28, 16}, {0x29, 16}, + {0x2a, 16}, {0x31, 5}, {0x32, 8}, {0x33, 10}, {0x34, 12}, {0x35, 16}, + {0x36, 16}, {0x37, 16}, {0x38, 16}, {0x39, 16}, {0x3a, 16}, {0x41, 6}, + {0x42, 9}, {0x43, 16}, {0x44, 16}, {0x45, 16}, {0x46, 16}, {0x47, 16}, + {0x48, 16}, {0x49, 16}, {0x4a, 16}, {0x51, 6}, {0x52, 10}, {0x53, 16}, + {0x54, 16}, {0x55, 16}, {0x56, 16}, {0x57, 16}, {0x58, 16}, {0x59, 16}, + {0x5a, 16}, {0x61, 7}, {0x62, 11}, {0x63, 16}, {0x64, 16}, {0x65, 16}, + {0x66, 16}, {0x67, 16}, {0x68, 16}, {0x69, 16}, {0x6a, 16}, {0x71, 7}, + {0x72, 11}, {0x73, 16}, {0x74, 16}, {0x75, 16}, {0x76, 16}, {0x77, 16}, + {0x78, 16}, {0x79, 16}, {0x7a, 16}, {0x81, 8}, {0x82, 16}, {0x83, 16}, + {0x84, 16}, {0x85, 16}, {0x86, 16}, {0x87, 16}, {0x88, 16}, {0x89, 16}, + {0x8a, 16}, {0x91, 9}, {0x92, 16}, {0x93, 16}, {0x94, 16}, {0x95, 16}, + {0x96, 16}, {0x97, 16}, {0x98, 16}, {0x99, 16}, {0x9a, 16}, {0xa1, 9}, + {0xa2, 16}, {0xa3, 16}, {0xa4, 16}, {0xa5, 16}, {0xa6, 16}, {0xa7, 16}, + {0xa8, 16}, {0xa9, 16}, {0xaa, 16}, {0xb1, 9}, {0xb2, 16}, {0xb3, 16}, + {0xb4, 16}, {0xb5, 16}, {0xb6, 16}, {0xb7, 16}, {0xb8, 16}, {0xb9, 16}, + {0xba, 16}, {0xc1, 9}, {0xc2, 16}, {0xc3, 16}, {0xc4, 16}, {0xc5, 16}, + {0xc6, 16}, {0xc7, 16}, {0xc8, 16}, {0xc9, 16}, {0xca, 16}, {0xd1, 11}, + {0xd2, 16}, {0xd3, 16}, {0xd4, 16}, {0xd5, 16}, {0xd6, 16}, {0xd7, 16}, + {0xd8, 16}, {0xd9, 16}, {0xda, 16}, {0xe1, 14}, {0xe2, 16}, {0xe3, 16}, + {0xe4, 16}, {0xe5, 16}, {0xe6, 16}, {0xe7, 16}, {0xe8, 16}, {0xe9, 16}, + {0xea, 16}, {0xf0, 10}, {0xf1, 15}, {0xf2, 16}, {0xf3, 16}, {0xf4, 16}, + {0xf5, 16}, {0xf6, 16}, {0xf7, 16}, {0xf8, 16}, {0xf9, 16}, {0xfa, 16} +}; +/* *INDENT-ON* */ + +static inline gboolean +jpeg_parse_to_next_marker (GstByteReader * br, guint8 * marker) +{ + gint ofs; + + ofs = gst_jpeg_scan_for_marker_code (br->data, br->size, br->byte); + if (ofs < 0) + return FALSE; + + if (marker) + *marker = br->data[ofs + 1]; + gst_byte_reader_skip (br, ofs - br->byte + 2); + return TRUE; +} + +gint +gst_jpeg_scan_for_marker_code (const guint8 * data, gsize size, guint offset) +{ + guint i; + + g_return_val_if_fail (data != NULL, -1); + g_return_val_if_fail (size > offset, -1); + + for (i = offset; i < size - 1;) { + if (data[i] != 0xff) + i++; + else { + const guint8 v = data[i + 1]; + if (v >= 0xc0 && v <= 0xfe) + return i; + i += 2; + } + } + return -1; +} + +gboolean +gst_jpeg_parse_frame_hdr (GstJpegFrameHdr * frame_hdr, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + guint16 length; + guint8 val; + guint i; + + g_return_val_if_fail (frame_hdr != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size > offset, FALSE); + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + g_return_val_if_fail (size >= 8, FALSE); + + U_READ_UINT16 (&br, length); /* Lf */ + g_return_val_if_fail (size >= length, FALSE); + + U_READ_UINT8 (&br, frame_hdr->sample_precision); + U_READ_UINT16 (&br, frame_hdr->height); + U_READ_UINT16 (&br, frame_hdr->width); + U_READ_UINT8 (&br, frame_hdr->num_components); + g_return_val_if_fail (frame_hdr->num_components <= + GST_JPEG_MAX_SCAN_COMPONENTS, FALSE); + + length -= 8; + g_return_val_if_fail (length >= 3 * frame_hdr->num_components, FALSE); + for (i = 0; i < frame_hdr->num_components; i++) { + U_READ_UINT8 (&br, frame_hdr->components[i].identifier); + U_READ_UINT8 (&br, val); + frame_hdr->components[i].horizontal_factor = (val >> 4) & 0x0F; + frame_hdr->components[i].vertical_factor = (val & 0x0F); + U_READ_UINT8 (&br, frame_hdr->components[i].quant_table_selector); + g_return_val_if_fail ((frame_hdr->components[i].horizontal_factor <= 4 && + frame_hdr->components[i].vertical_factor <= 4 && + frame_hdr->components[i].quant_table_selector < 4), FALSE); + length -= 3; + } + + g_assert (length == 0); + return TRUE; +} + +gboolean +gst_jpeg_parse_scan_hdr (GstJpegScanHdr * scan_hdr, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + guint16 length; + guint8 val; + guint i; + + g_return_val_if_fail (scan_hdr != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size > offset, FALSE); + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + g_return_val_if_fail (size >= 3, FALSE); + + U_READ_UINT16 (&br, length); /* Ls */ + g_return_val_if_fail (size >= length, FALSE); + + U_READ_UINT8 (&br, scan_hdr->num_components); + g_return_val_if_fail (scan_hdr->num_components <= + GST_JPEG_MAX_SCAN_COMPONENTS, FALSE); + + length -= 3; + g_return_val_if_fail (length >= 2 * scan_hdr->num_components, FALSE); + for (i = 0; i < scan_hdr->num_components; i++) { + U_READ_UINT8 (&br, scan_hdr->components[i].component_selector); + U_READ_UINT8 (&br, val); + scan_hdr->components[i].dc_selector = (val >> 4) & 0x0F; + scan_hdr->components[i].ac_selector = val & 0x0F; + g_return_val_if_fail ((scan_hdr->components[i].dc_selector < 4 && + scan_hdr->components[i].ac_selector < 4), FALSE); + length -= 2; + } + + /* FIXME: Ss, Se, Ah, Al */ + g_assert (length == 3); + return TRUE; +} + +gboolean +gst_jpeg_parse_huffman_table (GstJpegHuffmanTables * huf_tables, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + GstJpegHuffmanTable *huf_table; + guint16 length; + guint8 val, table_class, table_index; + guint32 value_count; + guint i; + + g_return_val_if_fail (huf_tables != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size > offset, FALSE); + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + g_return_val_if_fail (size >= 2, FALSE); + + U_READ_UINT16 (&br, length); /* Lh */ + g_return_val_if_fail (size >= length, FALSE); + + while (gst_byte_reader_get_remaining (&br)) { + U_READ_UINT8 (&br, val); + table_class = ((val >> 4) & 0x0F); + table_index = (val & 0x0F); + g_return_val_if_fail (table_index < GST_JPEG_MAX_SCAN_COMPONENTS, FALSE); + if (table_class == 0) { + huf_table = &huf_tables->dc_tables[table_index]; + } else { + huf_table = &huf_tables->ac_tables[table_index]; + } + READ_BYTES (&br, huf_table->huf_bits, 16); + value_count = 0; + for (i = 0; i < 16; i++) + value_count += huf_table->huf_bits[i]; + READ_BYTES (&br, huf_table->huf_values, value_count); + huf_table->valid = TRUE; + } + return TRUE; + +failed: + return FALSE; +} + +gboolean +gst_jpeg_parse_quant_table (GstJpegQuantTables * quant_tables, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + GstJpegQuantTable *quant_table; + guint16 length; + guint8 val, table_index; + guint i; + + g_return_val_if_fail (quant_tables != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size > offset, FALSE); + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + g_return_val_if_fail (size >= 2, FALSE); + + U_READ_UINT16 (&br, length); /* Lq */ + g_return_val_if_fail (size >= length, FALSE); + + while (gst_byte_reader_get_remaining (&br)) { + U_READ_UINT8 (&br, val); + table_index = (val & 0x0f); + g_return_val_if_fail (table_index < GST_JPEG_MAX_SCAN_COMPONENTS, FALSE); + quant_table = &quant_tables->quant_tables[table_index]; + quant_table->quant_precision = ((val >> 4) & 0x0f); + + g_return_val_if_fail (gst_byte_reader_get_remaining (&br) >= + GST_JPEG_MAX_QUANT_ELEMENTS * (1 + ! !quant_table->quant_precision), + FALSE); + for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) { + if (!quant_table->quant_precision) { /* 8-bit values */ + U_READ_UINT8 (&br, val); + quant_table->quant_table[i] = val; + } else { /* 16-bit values */ + U_READ_UINT16 (&br, quant_table->quant_table[i]); + } + } + quant_table->valid = TRUE; + } + return TRUE; +} + +gboolean +gst_jpeg_parse_restart_interval (guint * interval, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + guint16 length, val; + + g_return_val_if_fail (interval != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size > offset, FALSE); + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + g_return_val_if_fail (size >= 4, FALSE); + + U_READ_UINT16 (&br, length); /* Lr */ + g_return_val_if_fail (size >= length, FALSE); + + U_READ_UINT16 (&br, val); + *interval = val; + return TRUE; +} + +static int +compare_huffman_table_entry (const void *a, const void *b) +{ + const GstJpegHuffmanTableEntry *const e1 = *(GstJpegHuffmanTableEntry **) a; + const GstJpegHuffmanTableEntry *const e2 = *(GstJpegHuffmanTableEntry **) b; + + if (e1->length == e2->length) + return (gint) e1->value - (gint) e2->value; + return (gint) e1->length - (gint) e2->length; +} + +static void +build_huffman_table (GstJpegHuffmanTable * huf_table, + const GstJpegHuffmanTableEntry * entries, guint num_entries) +{ + const GstJpegHuffmanTableEntry *sorted_entries[256]; + guint i, j, n; + + g_assert (num_entries <= G_N_ELEMENTS (sorted_entries)); + + for (i = 0; i < num_entries; i++) + sorted_entries[i] = &entries[i]; + qsort (sorted_entries, num_entries, sizeof (sorted_entries[0]), + compare_huffman_table_entry); + + for (i = 0, j = 1, n = 0; i < num_entries; i++) { + const GstJpegHuffmanTableEntry *const e = sorted_entries[i]; + if (e->length != j) { + huf_table->huf_bits[j++ - 1] = n; + for (; j < e->length; j++) + huf_table->huf_bits[j - 1] = 0; + n = 0; + } + huf_table->huf_values[i] = e->value; + n++; + } + + for (; j < G_N_ELEMENTS (huf_table->huf_bits); j++) + huf_table->huf_bits[j] = 0; + for (; i < G_N_ELEMENTS (huf_table->huf_values); i++) + huf_table->huf_values[i] = 0; + huf_table->valid = TRUE; +} + +void +gst_jpeg_get_default_huffman_tables (GstJpegHuffmanTables * huf_tables) +{ + g_assert (huf_tables); + + /* Build DC tables */ + build_huffman_table (&huf_tables->dc_tables[0], default_luminance_dc_table, + G_N_ELEMENTS (default_luminance_dc_table)); + build_huffman_table (&huf_tables->dc_tables[1], default_chrominance_dc_table, + G_N_ELEMENTS (default_chrominance_dc_table)); + memcpy (&huf_tables->dc_tables[2], &huf_tables->dc_tables[1], + sizeof (huf_tables->dc_tables[2])); + + /* Build AC tables */ + build_huffman_table (&huf_tables->ac_tables[0], default_luminance_ac_table, + G_N_ELEMENTS (default_luminance_ac_table)); + build_huffman_table (&huf_tables->ac_tables[1], default_chrominance_ac_table, + G_N_ELEMENTS (default_chrominance_ac_table)); + memcpy (&huf_tables->ac_tables[2], &huf_tables->ac_tables[1], + sizeof (huf_tables->ac_tables[2])); +} + +static void +build_quant_table (GstJpegQuantTable * quant_table, const guint8 values[64]) +{ + guint i; + + for (i = 0; i < 64; i++) + quant_table->quant_table[i] = values[zigzag_index[i]]; + quant_table->quant_precision = 0; /* Pq = 0 (8-bit precision) */ + quant_table->valid = TRUE; +} + +void +gst_jpeg_get_default_quantization_tables (GstJpegQuantTables * quant_tables) +{ + g_assert (quant_tables); + + build_quant_table (&quant_tables->quant_tables[0], + default_luminance_quant_table); + build_quant_table (&quant_tables->quant_tables[1], + default_chrominance_quant_table); + build_quant_table (&quant_tables->quant_tables[2], + default_chrominance_quant_table); +} + +gboolean +gst_jpeg_parse (GstJpegMarkerSegment * seg, + const guint8 * data, gsize size, guint offset) +{ + GstByteReader br; + guint16 length; + + g_return_val_if_fail (seg != NULL, FALSE); + + if (size <= offset) { + GST_DEBUG ("failed to parse from offset %u, buffer is too small", offset); + return FALSE; + } + + size -= offset; + gst_byte_reader_init (&br, &data[offset], size); + + if (!jpeg_parse_to_next_marker (&br, &seg->marker)) { + GST_DEBUG ("failed to find marker code"); + return FALSE; + } + + seg->offset = offset + gst_byte_reader_get_pos (&br); + seg->size = -1; + + /* Try to find end of segment */ + switch (seg->marker) { + case GST_JPEG_MARKER_SOI: + case GST_JPEG_MARKER_EOI: + fixed_size_segment: + seg->size = 2; + break; + + case (GST_JPEG_MARKER_SOF_MIN + 0): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 1): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 2): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 3): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 9): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 10): /* Lf */ + case (GST_JPEG_MARKER_SOF_MIN + 11): /* Lf */ + case GST_JPEG_MARKER_SOS: /* Ls */ + case GST_JPEG_MARKER_DQT: /* Lq */ + case GST_JPEG_MARKER_DHT: /* Lh */ + case GST_JPEG_MARKER_DAC: /* La */ + case GST_JPEG_MARKER_DRI: /* Lr */ + case GST_JPEG_MARKER_COM: /* Lc */ + case GST_JPEG_MARKER_DNL: /* Ld */ + variable_size_segment: + READ_UINT16 (&br, length); + seg->size = length; + break; + + default: + /* Application data segment length (Lp) */ + if (seg->marker >= GST_JPEG_MARKER_APP_MIN && + seg->marker <= GST_JPEG_MARKER_APP_MAX) + goto variable_size_segment; + + /* Restart markers (fixed size, two bytes only) */ + if (seg->marker >= GST_JPEG_MARKER_RST_MIN && + seg->marker <= GST_JPEG_MARKER_RST_MAX) + goto fixed_size_segment; + + /* Fallback: scan for next marker */ + if (!jpeg_parse_to_next_marker (&br, NULL)) + goto failed; + seg->size = gst_byte_reader_get_pos (&br) - seg->offset; + break; + } + return TRUE; + +failed: + return FALSE; +} diff --git a/gst-libs/gst/codecparsers/gstjpegparser.h b/gst-libs/gst/codecparsers/gstjpegparser.h new file mode 100644 index 0000000..7237584 --- /dev/null +++ b/gst-libs/gst/codecparsers/gstjpegparser.h @@ -0,0 +1,414 @@ +/* + * gstjpegparser.h - JPEG parser + * + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_JPEG_PARSER_H +#define GST_JPEG_PARSER_H + +#ifndef GST_USE_UNSTABLE_API +# warning "The JPEG parsing library is unstable API and may change in future." +# warning "You can define GST_USE_UNSTABLE_API to avoid this warning." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GST_JPEG_MAX_FRAME_COMPONENTS: + * + * Maximum number of image components in a frame (Nf). + */ +#define GST_JPEG_MAX_FRAME_COMPONENTS 256 + +/** + * GST_JPEG_MAX_SCAN_COMPONENTS: + * + * Maximum number of image components in a scan (Ns). + */ +#define GST_JPEG_MAX_SCAN_COMPONENTS 4 + +/** + * GST_JPEG_MAX_QUANT_ELEMENTS: + * + * Number of elements in the quantization table. + */ +#define GST_JPEG_MAX_QUANT_ELEMENTS 64 + +typedef struct _GstJpegQuantTable GstJpegQuantTable; +typedef struct _GstJpegQuantTables GstJpegQuantTables; +typedef struct _GstJpegHuffmanTable GstJpegHuffmanTable; +typedef struct _GstJpegHuffmanTables GstJpegHuffmanTables; +typedef struct _GstJpegScanComponent GstJpegScanComponent; +typedef struct _GstJpegScanHdr GstJpegScanHdr; +typedef struct _GstJpegFrameComponent GstJpegFrameComponent; +typedef struct _GstJpegFrameHdr GstJpegFrameHdr; +typedef struct _GstJpegMarkerSegment GstJpegMarkerSegment; + +/** + * GstJpegMarkerCode: + * @GST_JPEG_MARKER_SOF_MIN: Start of frame min marker code + * @GST_JPEG_MARKER_SOF_MAX: Start of frame max marker code + * @GST_JPEG_MARKER_DHT: Huffman tabler marker code + * @GST_JPEG_MARKER_DAC: Arithmetic coding marker code + * @GST_JPEG_MARKER_RST_MIN: Restart interval min marker code + * @GST_JPEG_MARKER_RST_MAX: Restart interval max marker code + * @GST_JPEG_MARKER_SOI: Start of image marker code + * @GST_JPEG_MARKER_EOI: End of image marker code + * @GST_JPEG_MARKER_SOS: Start of scan marker code + * @GST_JPEG_MARKER_DQT: Define quantization table marker code + * @GST_JPEG_MARKER_DNL: Define number of lines marker code + * @GST_JPEG_MARKER_DRI: Define restart interval marker code + * @GST_JPEG_MARKER_APP_MIN: Application segment min marker code + * @GST_JPEG_MARKER_APP_MAX: Application segment max marker code + * @GST_JPEG_MARKER_COM: Comment marker code + * + * Indicates the type of JPEG segment. + */ +typedef enum { + GST_JPEG_MARKER_SOF_MIN = 0xC0, + GST_JPEG_MARKER_SOF_MAX = 0xCF, + GST_JPEG_MARKER_DHT = 0xC4, + GST_JPEG_MARKER_DAC = 0xCC, + GST_JPEG_MARKER_RST_MIN = 0xD0, + GST_JPEG_MARKER_RST_MAX = 0xD7, + GST_JPEG_MARKER_SOI = 0xD8, + GST_JPEG_MARKER_EOI = 0xD9, + GST_JPEG_MARKER_SOS = 0xDA, + GST_JPEG_MARKER_DQT = 0xDB, + GST_JPEG_MARKER_DNL = 0xDC, + GST_JPEG_MARKER_DRI = 0xDD, + GST_JPEG_MARKER_APP_MIN = 0xE0, + GST_JPEG_MARKER_APP_MAX = 0xEF, + GST_JPEG_MARKER_COM = 0xFE, +} GstJpegMarkerCode; + +/** + * GstJpegProfile: + * @GST_JPEG_PROFILE_BASELINE: Baseline DCT + * @GST_JPEG_PROFILE_EXTENDED: Extended sequential DCT + * @GST_JPEG_PROFILE_PROGRESSIVE: Progressive DCT + * @GST_JPEG_PROFILE_LOSSLESS: Lossless (sequential) + * + * JPEG encoding processes. + */ +typedef enum { + GST_JPEG_PROFILE_BASELINE = 0x00, + GST_JPEG_PROFILE_EXTENDED = 0x01, + GST_JPEG_PROFILE_PROGRESSIVE = 0x02, + GST_JPEG_PROFILE_LOSSLESS = 0x03, +} GstJpegProfile; + +/** + * GstJpegEntropyCodingMode: + * @GST_JPEG_ENTROPY_CODING_HUFFMAN: Huffman coding + * @GST_JPEG_ENTROPY_CODING_ARITHMETIC: arithmetic coding + * + * JPEG entropy coding mode. + */ +typedef enum { + GST_JPEG_ENTROPY_CODING_HUFFMAN = 0x00, + GST_JPEG_ENTROPY_CODING_ARITHMETIC = 0x08 +} GstJpegEntropyCodingMode; + +/** + * GstJpegQuantTable: + * @quant_precision: Quantization table element precision (Pq) + * @quant_table: Quantization table elements (Qk) + * @valid: If the quantization table is valid, which means it has + * already been parsed + * + * Quantization table. + */ +struct _GstJpegQuantTable +{ + guint8 quant_precision; + guint16 quant_table[GST_JPEG_MAX_QUANT_ELEMENTS]; + gboolean valid; +}; + +/** + * GstJpegQuantTables: + * @quant_tables: All quantization tables + * + * Helper data structure that holds all quantization tables used to + * decode an image. + */ +struct _GstJpegQuantTables +{ + GstJpegQuantTable quant_tables[GST_JPEG_MAX_SCAN_COMPONENTS]; +}; + +/** + * GstJpegHuffmanTable: + * @huf_bits: Number of Huffman codes of length i + 1 (Li) + * @huf_vales: Value associated with each Huffman code (Vij) + * @valid: If the Huffman table is valid, which means it has already + * been parsed + * + * Huffman table. + */ +struct _GstJpegHuffmanTable +{ + guint8 huf_bits[16]; + guint8 huf_values[256]; + gboolean valid; +}; + +/** + * GstJpegHuffmanTables: + * @dc_tables: DC Huffman tables + * @ac_tables: AC Huffman tables + * + * Helper data structure that holds all AC/DC Huffman tables used to + * decode an image. + */ +struct _GstJpegHuffmanTables +{ + GstJpegHuffmanTable dc_tables[GST_JPEG_MAX_SCAN_COMPONENTS]; + GstJpegHuffmanTable ac_tables[GST_JPEG_MAX_SCAN_COMPONENTS]; +}; + +/** + * GstJpegScanComponent: + * @component_selector: Scan component selector (Csj) + * @dc_selector: DC entropy coding table destination selector (Tdj) + * @ac_selector: AC entropy coding table destination selector (Taj) + + * Component-specification parameters. + */ +struct _GstJpegScanComponent +{ + guint8 component_selector; /* 0 .. 255 */ + guint8 dc_selector; /* 0 .. 3 */ + guint8 ac_selector; /* 0 .. 3 */ +}; + +/** + * GstJpegScanHdr: + * @num_components: Number of image components in scan (Ns) + * @components: Image components + * + * Scan header. + */ +struct _GstJpegScanHdr +{ + guint8 num_components; /* 1 .. 4 */ + GstJpegScanComponent components[GST_JPEG_MAX_SCAN_COMPONENTS]; +}; + +/** + * GstJpegFrameComponent: + * @identifier: Component identifier (Ci) + * @horizontal_factor: Horizontal sampling factor (Hi) + * @vertical_factor: Vertical sampling factor (Vi) + * @quant_table_selector: Quantization table destination selector (Tqi) + * + * Component-specification parameters. + */ +struct _GstJpegFrameComponent +{ + guint8 identifier; /* 0 .. 255 */ + guint8 horizontal_factor; /* 1 .. 4 */ + guint8 vertical_factor; /* 1 .. 4 */ + guint8 quant_table_selector; /* 0 .. 3 */ +}; + +/** + * GstJpegFrameHdr: + * @sample_precision: Sample precision (P) + * @height: Number of lines (Y) + * @width: Number of samples per line (X) + * @num_components: Number of image components in frame (Nf) + * @components: Image components + * @restart_interval: Number of MCU in the restart interval (Ri) + * + * Frame header. + */ +struct _GstJpegFrameHdr +{ + guint8 sample_precision; /* 2 .. 16 */ + guint16 width; /* 1 .. 65535 */ + guint16 height; /* 0 .. 65535 */ + guint8 num_components; /* 1 .. 255 */ + GstJpegFrameComponent components[GST_JPEG_MAX_FRAME_COMPONENTS]; +}; + +/** + * GstJpegMarkerSegment: + * @type: The type of the segment that starts at @offset + * @offset: The offset to the segment start in bytes. This is the + * exact start of the segment, no marker code included + * @size: The size in bytes of the segment, or -1 if the end was not + * found. It is the exact size of the segment, no marker code included + * + * A structure that contains the type of a segment, its offset and its size. + */ +struct _GstJpegMarkerSegment +{ + guint8 marker; + guint offset; + gint size; +}; + +/** + * gst_jpeg_scan_for_marker_code: + * @data: The data to parse + * @size: The size of @data + * @offset: The offset from which to start parsing + * + * Scans the JPEG bitstream contained in @data for the next marker + * code. If found, the function returns an offset to the marker code, + * including the 0xff prefix code but excluding any extra fill bytes. + * + * Returns: offset to the marker code if found, or -1 if not found. + */ +gint gst_jpeg_scan_for_marker_code (const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse: + * @data: The data to parse + * @size: The size of @data + * @offset: The offset from which to start parsing + * + * Parses the JPEG bitstream contained in @data, and returns the + * detected segment as a #GstJpegMarkerSegment. + * + * Returns: TRUE if a packet start code was found. + */ +gboolean gst_jpeg_parse (GstJpegMarkerSegment * seg, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse_frame_hdr: + * @hdr: (out): The #GstJpegFrameHdr structure to fill in + * @data: The data from which to parse the frame header + * @size: The size of @data + * @offset: The offset in bytes from which to start parsing @data + * + * Parses the @hdr JPEG frame header structure members from @data. + * + * Returns: TRUE if the frame header was correctly parsed. + */ +gboolean gst_jpeg_parse_frame_hdr (GstJpegFrameHdr * hdr, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse_scan_hdr: + * @hdr: (out): The #GstJpegScanHdr structure to fill in + * @data: The data from which to parse the scan header + * @size: The size of @data + * @offset: The offset in bytes from which to start parsing @data + * + * Parses the @hdr JPEG scan header structure members from @data. + * + * Returns: TRUE if the scan header was correctly parsed + */ +gboolean gst_jpeg_parse_scan_hdr (GstJpegScanHdr * hdr, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse_quantization_table: + * @quant_tables: (out): The #GstJpegQuantizationTable structure to fill in + * @num_quant_tables: The number of allocated quantization tables in @quant_tables + * @data: The data from which to parse the quantization table + * @size: The size of @data + * @offset: The offset in bytes from which to start parsing @data + * + * Parses the JPEG quantization table structure members from @data. + * + * Note: @quant_tables represents the complete set of possible + * quantization tables. However, the parser will only write to the + * quantization table specified by the table destination identifier + * (Tq). While doing so, the @valid flag of the specified quantization + * table will also be set to %TRUE. + * + * Returns: TRUE if the quantization table was correctly parsed. + */ +gboolean gst_jpeg_parse_quant_table (GstJpegQuantTables *quant_tables, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse_huffman_table: + * @huf_tables: (out): The #GstJpegHuffmanTable structure to fill in + * @data: The data from which to parse the Huffman table + * @size: The size of @data + * @offset: The offset in bytes from which to start parsing @data + * + * Parses the JPEG Huffman table structure members from @data. + * + * Note: @huf_tables represents the complete set of possible Huffman + * tables. However, the parser will only write to the Huffman table + * specified by the table destination identifier (Th). While doing so, + * the @valid flag of the specified Huffman table will also be set to + * %TRUE; + * + * Returns: TRUE if the Huffman table was correctly parsed. + */ +gboolean gst_jpeg_parse_huffman_table (GstJpegHuffmanTables *huf_tables, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_parse_restart_interval: + * @interval: (out): The parsed restart interval value + * @data: The data from which to parse the restart interval specification + * @size: The size of @data + * @offset: The offset in bytes from which to start parsing @data + * + * Returns: TRUE if the restart interval value was correctly parsed. + */ +gboolean gst_jpeg_parse_restart_interval (guint * interval, + const guint8 * data, + gsize size, + guint offset); + +/** + * gst_jpeg_get_default_huffman_tables: + * @huf_tables: (out): The default DC/AC Huffman tables to fill in + * + * Fills in @huf_tables with the default AC/DC Huffman tables, as + * specified by the JPEG standard. + */ +void gst_jpeg_get_default_huffman_tables (GstJpegHuffmanTables *huf_tables); + +/** + * gst_jpeg_get_default_quantization_table: + * @quant_tables: (out): The default luma/chroma quant-tables in zigzag mode + * + * Fills in @quant_tables with the default quantization tables, as + * specified by the JPEG standard. + */ +void gst_jpeg_get_default_quantization_tables (GstJpegQuantTables *quant_tables); + +G_END_DECLS + +#endif /* GST_JPEG_PARSER_H */ diff --git a/gst-libs/gst/vaapi/Makefile.am b/gst-libs/gst/vaapi/Makefile.am index 0984d1c..76ff704 100644 --- a/gst-libs/gst/vaapi/Makefile.am +++ b/gst-libs/gst/vaapi/Makefile.am @@ -1,12 +1,384 @@ lib_LTLIBRARIES = libgstvaapi-@GST_MAJORMINOR@.la -libgstvaapi_@GST_MAJORMINOR@_la_SOURCES = \ - $(NULL) +if USE_DRM +lib_LTLIBRARIES += libgstvaapi-drm-@GST_MAJORMINOR@.la +endif + +if USE_X11 +lib_LTLIBRARIES += libgstvaapi-x11-@GST_MAJORMINOR@.la +endif + +if USE_GLX +lib_LTLIBRARIES += libgstvaapi-glx-@GST_MAJORMINOR@.la +endif -libgstvaapi_@GST_MAJORMINOR@includedir = \ +if USE_WAYLAND +lib_LTLIBRARIES += libgstvaapi-wayland-@GST_MAJORMINOR@.la +endif + +libgstvaapi_includedir = \ $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/vaapi -libgstvaapi_@GST_MAJORMINOR@include_HEADERS = \ +libgstvaapi_cflags = \ + -DGST_USE_UNSTABLE_API \ + -I$(top_srcdir)/gst-libs \ + $(GST_BASE_CFLAGS) \ + $(GST_BASEVIDEO_CFLAGS) \ + $(GST_VIDEO_CFLAGS) \ + $(GST_CFLAGS) \ + $(GST_CODEC_PARSERS_CFLAGS) \ + $(LIBVA_CFLAGS) \ + $(LIBVA_TPI_CFLAGS) \ + $(NULL) + +libgstvaapi_libs = \ + $(GST_BASE_LIBS) \ + $(GST_BASEVIDEO_LIBS) \ + $(GST_LIBS) \ + $(GST_VIDEO_LIBS) \ + $(GST_CODEC_PARSERS_LIBS) \ + $(LIBVA_LIBS) \ + $(LIBVA_TPI_LIBS) \ + $(NULL) + +libgstvaapi_source_c = \ + gstvaapicodec_objects.c \ + gstvaapicontext.c \ + gstvaapidecoder.c \ + gstvaapidecoder_dpb.c \ + gstvaapidecoder_h264.c \ + gstvaapidecoder_mpeg2.c \ + gstvaapidecoder_mpeg4.c \ + gstvaapidecoder_objects.c \ + gstvaapidecoder_vc1.c \ + gstvaapidisplay.c \ + gstvaapidisplaycache.c \ + gstvaapiimage.c \ + gstvaapiimageformat.c \ + gstvaapiimagepool.c \ + gstvaapiobject.c \ + gstvaapiparamspecs.c \ + gstvaapiprofile.c \ + gstvaapisubpicture.c \ + gstvaapisurface.c \ + gstvaapisurfacepool.c \ + gstvaapisurfaceproxy.c \ + gstvaapisurface_userptr.c \ + gstvaapiutils.c \ + gstvaapivalue.c \ + gstvaapivideobuffer.c \ + gstvaapivideopool.c \ + gstvaapiwindow.c \ + $(NULL) + +libgstvaapi_source_h = \ + gstvaapicontext.h \ + gstvaapidecoder.h \ + gstvaapidecoder_h264.h \ + gstvaapidecoder_mpeg2.h \ + gstvaapidecoder_mpeg4.h \ + gstvaapidecoder_vc1.h \ + gstvaapidisplay.h \ + gstvaapidisplaycache.h \ + gstvaapiimage.h \ + gstvaapiimageformat.h \ + gstvaapiimagepool.h \ + gstvaapiobject.h \ + gstvaapiparamspecs.h \ + gstvaapiprofile.h \ + gstvaapisubpicture.h \ + gstvaapisurface.h \ + gstvaapisurfacepool.h \ + gstvaapisurfaceproxy.h \ + gstvaapisurface_userptr.h \ + gstvaapitypes.h \ + gstvaapivalue.h \ + gstvaapivideobuffer.h \ + gstvaapivideopool.h \ + gstvaapiwindow.h \ + $(NULL) + +if USE_ENCODERS +libgstvaapi_source_c += \ + gstvaapiencoder.c \ + gstvaapibaseencoder.c \ + gstvaapiencoder_h264.c \ + gstvaapiencoder_h263.c \ + gstvaapiencoder_mpeg4.c \ + $(NULL) + +libgstvaapi_source_h += \ + gstvaapiencoder.h \ + gstvaapibaseencoder.h \ + gstvaapiencoder_h264.h \ + gstvaapiencoder_h263.h \ + gstvaapiencoder_mpeg4.h \ + $(NULL) + +endif + +libgstvaapi_source_priv_h = \ + glibcompat.h \ + gstvaapi_priv.h \ + gstvaapicodec_objects.h \ + gstvaapicompat.h \ + gstvaapidebug.h \ + gstvaapidecoder_dpb.h \ + gstvaapidecoder_objects.h \ + gstvaapidecoder_priv.h \ + gstvaapidisplay_priv.h \ + gstvaapiobject_priv.h \ + gstvaapisurface_priv.h \ + gstvaapiutils.h \ + gstvaapivideobuffer_priv.h \ + gstvaapiworkarounds.h \ + sysdeps.h \ + $(NULL) + +if USE_JPEG_DECODER +libgstvaapi_source_c += gstvaapidecoder_jpeg.c +libgstvaapi_source_h += gstvaapidecoder_jpeg.h +endif + +libgstvaapi_drm_source_c = \ + gstvaapidisplay_drm.c \ + gstvaapiwindow_drm.c \ + gstvaapiutils.c \ + $(NULL) + +libgstvaapi_drm_source_h = \ + gstvaapidisplay_drm.h \ + gstvaapiwindow_drm.h \ + $(NULL) + +libgstvaapi_drm_source_priv_h = \ + gstvaapicompat.h \ + gstvaapidisplay_drm_priv.h \ + gstvaapiutils.h \ + $(NULL) + +libgstvaapi_x11_source_c = \ + gstvaapidisplay_x11.c \ + gstvaapiutils.c \ + gstvaapiutils_x11.c \ + gstvaapiwindow_x11.c \ + $(NULL) + +libgstvaapi_x11_source_h = \ + gstvaapidisplay_x11.h \ + gstvaapiwindow_x11.h \ + $(NULL) + +libgstvaapi_x11_source_priv_h = \ + gstvaapicompat.h \ + gstvaapidisplay_x11_priv.h \ + gstvaapiutils.h \ + gstvaapiutils_x11.h \ + $(NULL) + +libgstvaapi_glx_source_c = \ + gstvaapidisplay_glx.c \ + gstvaapitexture.c \ + gstvaapiutils.c \ + gstvaapiutils_glx.c \ + gstvaapiutils_x11.c \ + gstvaapivideobuffer_glx.c \ + gstvaapivideoconverter_glx.c \ + gstvaapiwindow_glx.c \ + $(NULL) + +libgstvaapi_glx_source_h = \ + gstvaapidisplay_glx.h \ + gstvaapitexture.h \ + gstvaapivideobuffer_glx.h \ + gstvaapivideoconverter_glx.h \ + gstvaapiwindow_glx.h \ + $(NULL) + +libgstvaapi_glx_source_priv_h = \ + gstvaapicompat.h \ + gstvaapidisplay_glx_priv.h \ + gstvaapiutils.h \ + gstvaapiutils_glx.h \ + gstvaapiutils_x11.h \ + $(NULL) + +libgstvaapi_wayland_source_c = \ + gstvaapidisplay_wayland.c \ + gstvaapiutils.c \ + gstvaapiwindow_wayland.c \ + $(NULL) + +libgstvaapi_wayland_source_h = \ + gstvaapidisplay_wayland.h \ + gstvaapiwindow_wayland.h \ + $(NULL) + +libgstvaapi_wayland_source_priv_h = \ + gstvaapicompat.h \ + gstvaapidisplay_wayland_priv.h \ + gstvaapiutils.h \ + $(NULL) + +if USE_LOCAL_CODEC_PARSERS +libgstvaapi_libs += \ + $(top_builddir)/gst-libs/gst/codecparsers/libgstvaapi-codecparsers.la +endif + +libgstvaapi_@GST_MAJORMINOR@_la_SOURCES = \ + $(libgstvaapi_source_c) \ + $(libgstvaapi_source_priv_h) \ + $(NULL) + +libgstvaapi_@GST_MAJORMINOR@include_HEADERS = \ + $(libgstvaapi_source_h) \ + $(NULL) + +libgstvaapi_@GST_MAJORMINOR@includedir = \ + $(libgstvaapi_includedir) + +libgstvaapi_@GST_MAJORMINOR@_la_CFLAGS = \ + $(libgstvaapi_cflags) \ + $(NULL) + +libgstvaapi_@GST_MAJORMINOR@_la_LIBADD = \ + $(libgstvaapi_libs) \ + $(NULL) + +libgstvaapi_@GST_MAJORMINOR@_la_LDFLAGS = \ + $(GST_ALL_LDFLAGS) \ + $(NULL) + +libgstvaapi_drm_@GST_MAJORMINOR@_la_SOURCES = \ + $(libgstvaapi_drm_source_c) \ + $(libgstvaapi_drm_source_priv_h) \ + $(NULL) + +libgstvaapi_drm_@GST_MAJORMINOR@include_HEADERS = \ + $(libgstvaapi_drm_source_h) \ + $(NULL) + +libgstvaapi_drm_@GST_MAJORMINOR@includedir = \ + $(libgstvaapi_includedir) + +libgstvaapi_drm_@GST_MAJORMINOR@_la_CFLAGS = \ + -DGST_USE_UNSTABLE_API \ + -I$(top_srcdir)/gst-libs \ + $(GLIB_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(UDEV_CFLAGS) \ + $(DRM_CFLAGS) \ + $(LIBVA_DRM_CFLAGS) \ + $(NULL) + +libgstvaapi_drm_@GST_MAJORMINOR@_la_LIBADD = \ + $(GLIB_LIBS) \ + $(UDEV_LIBS) \ + $(DRM_LIBS) \ + $(LIBVA_DRM_LIBS) \ + libgstvaapi-@GST_MAJORMINOR@.la \ + $(NULL) + +libgstvaapi_drm_@GST_MAJORMINOR@_la_LDFLAGS = \ + $(GST_ALL_LDFLAGS) \ + $(NULL) + +libgstvaapi_x11_@GST_MAJORMINOR@_la_SOURCES = \ + $(libgstvaapi_x11_source_c) \ + $(libgstvaapi_x11_source_priv_h) \ + $(NULL) + +libgstvaapi_x11_@GST_MAJORMINOR@include_HEADERS = \ + $(libgstvaapi_x11_source_h) \ + $(NULL) + +libgstvaapi_x11_@GST_MAJORMINOR@includedir = \ + $(libgstvaapi_includedir) + +libgstvaapi_x11_@GST_MAJORMINOR@_la_CFLAGS = \ + -DGST_USE_UNSTABLE_API \ + -I$(top_srcdir)/gst-libs \ + $(GLIB_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(X11_CFLAGS) \ + $(XRANDR_CFLAGS) \ + $(LIBVA_X11_CFLAGS) \ + $(NULL) + +libgstvaapi_x11_@GST_MAJORMINOR@_la_LIBADD = \ + $(GLIB_LIBS) \ + $(X11_LIBS) \ + $(XRANDR_LIBS) \ + $(LIBVA_X11_LIBS) \ + libgstvaapi-@GST_MAJORMINOR@.la \ + $(NULL) + +libgstvaapi_x11_@GST_MAJORMINOR@_la_LDFLAGS = \ + $(GST_ALL_LDFLAGS) \ + $(NULL) + +libgstvaapi_glx_@GST_MAJORMINOR@_la_SOURCES = \ + $(libgstvaapi_glx_source_c) \ + $(libgstvaapi_glx_source_priv_h) \ + $(NULL) + +libgstvaapi_glx_@GST_MAJORMINOR@include_HEADERS = \ + $(libgstvaapi_glx_source_h) \ + $(NULL) + +libgstvaapi_glx_@GST_MAJORMINOR@includedir = \ + $(libgstvaapi_includedir) + +libgstvaapi_glx_@GST_MAJORMINOR@_la_CFLAGS = \ + -DGST_USE_UNSTABLE_API \ + -I$(top_srcdir)/gst-libs \ + $(GLIB_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GL_CFLAGS) \ + $(LIBVA_GLX_CFLAGS) \ + $(NULL) + +libgstvaapi_glx_@GST_MAJORMINOR@_la_LIBADD = \ + $(GLIB_LIBS) \ + $(GL_LIBS) \ + $(LIBVA_GLX_LIBS) \ + libgstvaapi-x11-@GST_MAJORMINOR@.la \ + $(NULL) + +libgstvaapi_glx_@GST_MAJORMINOR@_la_LDFLAGS = \ + $(GST_ALL_LDFLAGS) \ + $(NULL) + +libgstvaapi_wayland_@GST_MAJORMINOR@_la_SOURCES = \ + $(libgstvaapi_wayland_source_c) \ + $(libgstvaapi_wayland_source_priv_h) \ + $(NULL) + +libgstvaapi_wayland_@GST_MAJORMINOR@include_HEADERS = \ + $(libgstvaapi_wayland_source_h) \ + $(NULL) + +libgstvaapi_wayland_@GST_MAJORMINOR@includedir = \ + $(libgstvaapi_includedir) + +libgstvaapi_wayland_@GST_MAJORMINOR@_la_CFLAGS = \ + -DGST_USE_UNSTABLE_API \ + -I$(top_srcdir)/gst-libs \ + $(GLIB_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(WAYLAND_CFLAGS) \ + $(LIBVA_WAYLAND_CFLAGS) \ + $(NULL) + +libgstvaapi_wayland_@GST_MAJORMINOR@_la_LIBADD = \ + $(GLIB_LIBS) \ + $(WAYLAND_LIBS) \ + $(LIBVA_WAYLAND_LIBS) \ + libgstvaapi-@GST_MAJORMINOR@.la \ + $(NULL) + +libgstvaapi_wayland_@GST_MAJORMINOR@_la_LDFLAGS = \ + $(GST_ALL_LDFLAGS) \ $(NULL) # Extra clean files so that maintainer-clean removes *everything* diff --git a/gst-libs/gst/vaapi/glibcompat.h b/gst-libs/gst/vaapi/glibcompat.h new file mode 100644 index 0000000..30a8563 --- /dev/null +++ b/gst-libs/gst/vaapi/glibcompat.h @@ -0,0 +1,77 @@ +/* + * glibcompat.h - System-dependent definitions + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GLIB_COMPAT_H +#define GLIB_COMPAT_H + +#include +#include + +#if !GLIB_CHECK_VERSION(2,27,2) +static inline void +g_list_free_full(GList *list, GDestroyNotify free_func) +{ + g_list_foreach(list, (GFunc)free_func, NULL); + g_list_free(list); +} +#endif + +#if !GLIB_CHECK_VERSION(2,28,0) +static inline void +g_clear_object_inline(volatile GObject **object_ptr) +{ + gpointer * const ptr = (gpointer)object_ptr; + gpointer old; + + do { + old = g_atomic_pointer_get(ptr); + } while G_UNLIKELY(!g_atomic_pointer_compare_and_exchange(ptr, old, NULL)); + + if (old) + g_object_unref(old); +} +#undef g_clear_object +#define g_clear_object(obj) g_clear_object_inline((volatile GObject **)(obj)) +#endif + +#if GLIB_CHECK_VERSION(2,31,2) +#define GStaticMutex GMutex +#undef g_static_mutex_init +#define g_static_mutex_init(mutex) g_mutex_init(mutex) +#undef g_static_mutex_free +#define g_static_mutex_free(mutex) g_mutex_clear(mutex) +#undef g_static_mutex_lock +#define g_static_mutex_lock(mutex) g_mutex_lock(mutex) +#undef g_static_mutex_unlock +#define g_static_mutex_unlock(mutex) g_mutex_unlock(mutex) + +#define GStaticRecMutex GRecMutex +#undef g_static_rec_mutex_init +#define g_static_rec_mutex_init(mutex) g_rec_mutex_init(mutex) +#undef g_static_rec_mutex_free +#define g_static_rec_mutex_free(mutex) g_rec_mutex_clear(mutex) +#undef g_static_rec_mutex_lock +#define g_static_rec_mutex_lock(mutex) g_rec_mutex_lock(mutex) +#undef g_static_rec_mutex_unlock +#define g_static_rec_mutex_unlock(m) g_rec_mutex_unlock(m) +#endif + +#endif /* GLIB_COMPAT_H */ diff --git a/gst-libs/gst/vaapi/gstvaapi_priv.h b/gst-libs/gst/vaapi/gstvaapi_priv.h new file mode 100644 index 0000000..8416b83 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapi_priv.h @@ -0,0 +1,28 @@ +/* + * gstvaapi_priv.h - Helper to include all private headers + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_PRIV_H +#define GST_VAAPI_PRIV_H + +#include +#include + +#endif /* GST_VAAPI_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapibaseencoder.c b/gst-libs/gst/vaapi/gstvaapibaseencoder.c new file mode 100644 index 0000000..d4fefec --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapibaseencoder.c @@ -0,0 +1,1006 @@ +/* + * gstvaapibaseencoder.c - VA-API base encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstvaapibaseencoder.h" + +#include +#include +#include +#include + +#include + +#include +#include "va/va_x11.h" + +#include "gst/gstclock.h" +#include "gst/gstvalue.h" + +#include "gstvaapiobject.h" +#include "gstvaapiobject_priv.h" +#include "gstvaapicontext.h" +#include "gstvaapisurface.h" +#include "gstvaapisurfacepool.h" +#include "gstvaapivideobuffer.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapidebug.h" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_base_encoder_debug); +#define GST_CAT_DEFAULT gst_vaapi_base_encoder_debug + +#define VA_INVALID_PROFILE 0xffffffff +#define DEFAULT_VA_CODEDBUF_NUM 4 +#define GST_VAAPI_ENCODER_SURFACE_COUNT 3 + +#define GST_VAAPI_BASE_ENCODER_LOCK(encoder) \ + G_STMT_START { \ + g_static_rec_mutex_lock( \ + &((GstVaapiBaseEncoder*)(encoder))->priv->mutex); \ + } G_STMT_END + +#define GST_VAAPI_BASE_ENCODER_UNLOCK(encoder) \ + G_STMT_START { \ + g_static_rec_mutex_unlock( \ + &((GstVaapiBaseEncoder*)(encoder))->priv->mutex); \ + } G_STMT_END + +struct _GstVaapiBaseEncoderPrivate { + guint32 format; /*NV12, I420,*/ + VAProfile profile; + /*total encoded frames*/ + guint32 frame_count; + VABufferID *coded_bufs; + guint32 coded_buf_num; + GStaticRecMutex mutex; + GQueue *idle_buf_queue; + GQueue *busy_buf_queue; + + GstVaapiSurfacePool *surfaces_pool; + GstVaapiBaseEncoderNotifyStatus notify_status; + gpointer user_data; + + guint buffer_sharing_flag : 1; + guint buffer_notify_flag : 1; + guint need_flush : 1; +}; + +G_DEFINE_TYPE(GstVaapiBaseEncoder, gst_vaapi_base_encoder, GST_TYPE_VAAPI_ENCODER) + +typedef struct _GstVaapiEncoderBufferInfo GstVaapiEncoderBufferInfo; +typedef struct _GstVaapiEncoderBufferInfoClass GstVaapiEncoderBufferInfoClass; + +#define GST_TYPE_VAAPI_ENCODER_BUFFER_INFO \ + (gst_vaapi_encoder_buffer_info_get_type()) + +#define GST_VAAPI_ENCODER_BUFFER_INFO(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_VAAPI_ENCODER_BUFFER_INFO,\ + GstVaapiEncoderBufferInfo)) + +struct _GstVaapiEncoderBufferInfo { + GObject base; + GstVaapiBaseEncoder *encoder; + VABufferID *id; + GstClockTime timestamp; + GstClockTime duration; + + void *data; + + guint32 is_key : 1; + guint32 is_mapped : 1; +}; + +struct _GstVaapiEncoderBufferInfoClass { + GObjectClass base_class; +}; + +G_DEFINE_TYPE( + GstVaapiEncoderBufferInfo, + gst_vaapi_encoder_buffer_info, + G_TYPE_OBJECT) + +static gboolean +gst_vaapi_encoder_buffer_info_map( + GstVaapiEncoderBufferInfo *info, + void **buf +) +{ + g_return_val_if_fail(info, FALSE); + g_return_val_if_fail(info->encoder && info->id && buf, FALSE); + + GstVaapiDisplay *display = ENCODER_DISPLAY(info->encoder); + VADisplay va_dpy = ENCODER_VA_DISPLAY(info->encoder); + VAStatus va_status = VA_STATUS_SUCCESS; + + if (info->is_mapped) + return TRUE; + + GST_VAAPI_DISPLAY_LOCK(display); + va_status = vaMapBuffer(va_dpy, *info->id, &info->data); + GST_VAAPI_DISPLAY_UNLOCK(display); + + g_return_val_if_fail(va_status == VA_STATUS_SUCCESS, FALSE); + info->is_mapped = TRUE; + *buf = info->data; + return TRUE; +} + +static gboolean +gst_vaapi_encoder_buffer_info_unmap( + GstVaapiEncoderBufferInfo *info +) +{ + g_return_val_if_fail(info, FALSE); + g_return_val_if_fail(info->encoder && info->id, FALSE); + + GstVaapiDisplay *display = ENCODER_DISPLAY(info->encoder); + VADisplay va_dpy = ENCODER_VA_DISPLAY(info->encoder); + VAStatus va_status = VA_STATUS_SUCCESS; + + if (!info->is_mapped) + return TRUE; + + GST_VAAPI_DISPLAY_LOCK(display); + va_status = vaUnmapBuffer(va_dpy, *info->id); + GST_VAAPI_DISPLAY_UNLOCK(display); + info->data = NULL; + info->is_mapped = FALSE; + + g_return_val_if_fail(va_status == VA_STATUS_SUCCESS, FALSE); + return TRUE; +} + +static GstVaapiEncoderBufferInfo* +pop_busy_buffer_info(GstVaapiBaseEncoder *encoder) +{ + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + GstVaapiEncoderBufferInfo *info = NULL; + + g_return_val_if_fail(priv->busy_buf_queue, NULL); + + GST_VAAPI_BASE_ENCODER_LOCK(encoder); + + if (g_queue_is_empty(priv->busy_buf_queue)) + goto end; + + info = (GstVaapiEncoderBufferInfo*)g_queue_pop_head(priv->busy_buf_queue); + +end: + GST_VAAPI_BASE_ENCODER_UNLOCK(encoder); + return info; +} + +static void +push_busy_buffer_info( + GstVaapiBaseEncoder *encoder, + GstVaapiEncoderBufferInfo *info) +{ + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + + GST_VAAPI_BASE_ENCODER_LOCK(encoder); + g_queue_push_tail(priv->busy_buf_queue, info); + GST_VAAPI_BASE_ENCODER_UNLOCK(encoder); +} + +static VABufferID * +pop_idle_buffer_id(GstVaapiBaseEncoder *encoder) +{ + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + VABufferID *coded_buf = NULL; + + g_return_val_if_fail(priv->idle_buf_queue, NULL); + + GST_VAAPI_BASE_ENCODER_LOCK(encoder); + + if (g_queue_is_empty(priv->idle_buf_queue)) + goto end; + + coded_buf = (VABufferID*)g_queue_pop_head(priv->idle_buf_queue); + +end: + GST_VAAPI_BASE_ENCODER_UNLOCK(encoder); + return coded_buf; +} + +static void +push_idle_buffer_id( + GstVaapiBaseEncoder *encoder, + VABufferID *buf +) +{ + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + + GST_VAAPI_BASE_ENCODER_LOCK(encoder); + g_queue_push_tail(priv->idle_buf_queue, buf); + GST_VAAPI_BASE_ENCODER_UNLOCK(encoder); +} + +static void +gst_vaapi_encoder_buffer_info_init( + GstVaapiEncoderBufferInfo *info +) +{ + info->encoder = NULL; + info->id = NULL; + info->timestamp = 0; + info->duration = 0; + info->data = NULL; + info->is_key = FALSE; + info->is_mapped = FALSE; +} + +static void +gst_vaapi_encoder_buffer_info_finalize(GObject *object) +{ + GstVaapiEncoderBufferInfo *info = GST_VAAPI_ENCODER_BUFFER_INFO(object); + + if (info->id && *info->id != VA_INVALID_ID && info->encoder) { + if (info->is_mapped) + gst_vaapi_encoder_buffer_info_unmap(info); + push_idle_buffer_id(info->encoder, info->id); + } + + if (info->encoder) { + g_object_unref(info->encoder); + info->encoder = NULL; + } + info->id = NULL; +} + +static GstVaapiEncoderBufferInfo* +gst_vaapi_encoder_buffer_info_new( + GstVaapiBaseEncoder *encoder +) +{ + GstVaapiEncoderBufferInfo *ret; + + g_return_val_if_fail(encoder, NULL); + + ret = GST_VAAPI_ENCODER_BUFFER_INFO( + g_object_new(GST_TYPE_VAAPI_ENCODER_BUFFER_INFO, + NULL)); + if (!ret) + return NULL; + ret->encoder = g_object_ref(encoder); + return ret; +} + +static void +gst_vaapi_encoder_buffer_info_class_init( + GstVaapiEncoderBufferInfoClass *klass +) +{ + GObjectClass * const obj_class = G_OBJECT_CLASS(klass); + + obj_class->finalize = gst_vaapi_encoder_buffer_info_finalize; +} + +void +gst_vaapi_base_encoder_set_frame_notify( + GstVaapiBaseEncoder *encoder, + gboolean flag +) +{ + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + priv->buffer_notify_flag = flag; +} + +gboolean +gst_vaapi_base_encoder_set_va_profile( + GstVaapiBaseEncoder *encoder, + guint profile +) +{ + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + priv->profile = profile; + return TRUE; +} + +void +gst_vaapi_base_encoder_set_input_format( + GstVaapiBaseEncoder* encoder, + guint32 format +) +{ + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + priv->format = format; +} + +gboolean +gst_vaapi_base_encoder_set_notify_status( + GstVaapiBaseEncoder *encoder, + GstVaapiBaseEncoderNotifyStatus func, + gpointer user_data +) +{ + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + + priv->notify_status = func; + priv->user_data = user_data; + return TRUE; +} + +void +gst_vaapi_base_encoder_set_buffer_sharing( + GstVaapiBaseEncoder *encoder, + gboolean is_buffer_sharing +) +{ + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + + priv->buffer_sharing_flag = is_buffer_sharing; +} + +static gboolean +default_validate_encoder_parameters( + GstVaapiBaseEncoder *encoder +) +{ + if (!ENCODER_WIDTH(encoder) || + !ENCODER_HEIGHT(encoder) || + !ENCODER_FPS(encoder)) { + return FALSE; + } + return TRUE; +} + +static gboolean +base_encoder_alloc_coded_buffers( + GstVaapiBaseEncoder *base_encoder, + GstVaapiContext *context +) +{ + GstVaapiBaseEncoderPrivate *priv = base_encoder->priv; + VADisplay va_dpy; + VAContextID context_id; + VAStatus va_status = VA_STATUS_SUCCESS; + guint i = 0; + gboolean ret = TRUE; + guint32 buffer_size = + (ENCODER_WIDTH(base_encoder) * ENCODER_HEIGHT(base_encoder) * 400) / + (16*16); + + ENCODER_ASSERT(context); + ENCODER_ASSERT(priv->idle_buf_queue); + ENCODER_ASSERT(!priv->coded_bufs); + + va_dpy = ENCODER_VA_DISPLAY(base_encoder); + context_id = gst_vaapi_context_get_id(context); + + priv->coded_bufs = (VABufferID*) + g_malloc0(priv->coded_buf_num * sizeof(priv->coded_bufs[0])); + + for (i = 0; i < priv->coded_buf_num; i++) { + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncCodedBufferType, + buffer_size, 1, + NULL, + &priv->coded_bufs[i]); + if (VA_STATUS_SUCCESS != va_status) + break; + } + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + FALSE, + "create coded buffer failed."); + + /* init queue idle_buf_queue */ + GST_VAAPI_BASE_ENCODER_LOCK(base_encoder); + for (i = 0; i < priv->coded_buf_num; i++) { + g_queue_push_head(priv->idle_buf_queue, &priv->coded_bufs[i]); + } + GST_VAAPI_BASE_ENCODER_UNLOCK(base_encoder); + +end: + return ret; + +} + +static EncoderStatus +release_coded_buffers(GstVaapiBaseEncoder *base_encoder) +{ + VAStatus va_status = VA_STATUS_SUCCESS; + GstVaapiBaseEncoderPrivate *priv = base_encoder->priv; + GstVaapiDisplay *display = ENCODER_DISPLAY(base_encoder); + guint32 available_buf_count = priv->coded_buf_num; + GstVaapiEncoderBufferInfo *info; + guint32 i; + + ENCODER_ASSERT(display); + VAAPI_UNUSED_ARG(va_status); + VADisplay va_dpy = gst_vaapi_display_get_display(display); + + /* wait clear all available coded buffers */ + GST_VAAPI_BASE_ENCODER_LOCK(base_encoder); + if (available_buf_count) { + while (!g_queue_is_empty(priv->busy_buf_queue)) { + info = (GstVaapiEncoderBufferInfo*)g_queue_pop_head(priv->busy_buf_queue); + g_object_unref(info); + } + while(!g_queue_is_empty(priv->idle_buf_queue)) { + g_queue_pop_head(priv->idle_buf_queue); + available_buf_count--; + } + } + GST_VAAPI_BASE_ENCODER_UNLOCK(base_encoder); + ENCODER_ASSERT(available_buf_count == 0); + + for (i = 0; i < priv->coded_buf_num; i++) { + va_status = vaDestroyBuffer(va_dpy, priv->coded_bufs[i]); + } + + return ENCODER_NO_ERROR; +} + +static EncoderStatus +gst_vaapi_base_encoder_close_default(GstVaapiEncoder* encoder) +{ + GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder); + GstVaapiBaseEncoderClass *base_class = + GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder); + GstVaapiBaseEncoderPrivate *priv = base_encoder->priv; + EncoderStatus ret = ENCODER_NO_ERROR; + + /* release buffers first */ + priv->need_flush = FALSE; + + if (base_class->release_resource) { + base_class->release_resource(base_encoder); + } + release_coded_buffers(base_encoder); + priv->frame_count = 0; + + return ret; +} + +static EncoderStatus +gst_vaapi_base_encoder_open_default( + GstVaapiEncoder* encoder, + GstVaapiContext **context +) +{ + GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder); + GstVaapiBaseEncoderClass *base_class = + GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder); + GstVaapiBaseEncoderPrivate *priv = base_encoder->priv; + GstVaapiDisplay *display = ENCODER_DISPLAY(encoder); + + GstVaapiContext *out_context = NULL; + + EncoderStatus ret = ENCODER_NO_ERROR; + gboolean check_attri_ret = TRUE; + /*check and set default values*/ + if (base_class->validate_attributes) { + check_attri_ret = base_class->validate_attributes(base_encoder); + } else { + check_attri_ret = default_validate_encoder_parameters(base_encoder); + } + ENCODER_CHECK_STATUS(check_attri_ret, + ENCODER_PARAMETER_ERR, + "vaapi encoder paramerter error."); + ENCODER_CHECK_STATUS(VA_INVALID_PROFILE != priv->profile, + ENCODER_PROFILE_ERR, + "vaapi encoder profile not set."); + + ENCODER_ASSERT(ENCODER_DISPLAY(encoder)); + + out_context = gst_vaapi_context_new(display, + gst_vaapi_profile(priv->profile), + gst_vaapi_entrypoint(VAEntrypointEncSlice), + ENCODER_RATE_CONTROL(encoder), + ENCODER_WIDTH(encoder), + ENCODER_HEIGHT(encoder), + GST_VAAPI_ENCODER_SURFACE_COUNT); + ENCODER_CHECK_STATUS(out_context, + ENCODER_CONTEXT_ERR, + "gst_vaapi_context_new failed."); + ENCODER_CHECK_STATUS(VA_INVALID_ID != GST_VAAPI_OBJECT_ID(out_context), + ENCODER_CONTEXT_ERR, + "gst_vaapi_context_new failed."); + + if (base_class->pre_alloc_resource) { + ENCODER_CHECK_STATUS( + base_class->pre_alloc_resource(base_encoder, out_context), + ENCODER_MEM_ERR, + "encoder failed." + ); + } + ENCODER_CHECK_STATUS( + base_encoder_alloc_coded_buffers(base_encoder, out_context), + ENCODER_MEM_ERR, + "encoder failed." + ); + *context = out_context; + + return ENCODER_NO_ERROR; + +end: + // clear resources + if (ENCODER_NO_ERROR != ret) { + gst_vaapi_base_encoder_close_default(encoder); + if (out_context) { + g_object_unref(out_context); + } + } + return ret; +} + +static EncoderStatus +query_encoding_status( + GstVaapiBaseEncoder *base_encoder, + GstVaapiSurface *buffer_surface +) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiSurfaceStatus surface_status; + + ENCODER_CHECK_STATUS(gst_vaapi_surface_sync(buffer_surface), + ENCODER_SURFACE_ERR, + "gst_vaapi_surface_sync failed."); + + ENCODER_CHECK_STATUS( + gst_vaapi_surface_query_status(buffer_surface, &surface_status), + ENCODER_SURFACE_ERR, + "gst_vaapi_surface_query_status failed." + ); + if (GST_VAAPI_SURFACE_STATUS_SKIPPED & surface_status) { + ENCODER_LOG_ERROR("frame skipped"); /* not sure continue or not */ + } + + return ENCODER_NO_ERROR; + +end: + return ret; +} + +static inline guint +get_buf_list_size(VACodedBufferSegment *buf_list) +{ + guint size = 0; + while(buf_list) { + size += buf_list->size; + buf_list = (VACodedBufferSegment*)buf_list->next; + } + return size; +} + +static inline guint +move_buf_list_to_buf( + VACodedBufferSegment *buf_list, + guint8 *data, + guint max_len +) +{ + guint left_size = max_len; + guint cur_size; + while (buf_list && left_size) { + if (buf_list->size <= left_size) + cur_size = buf_list->size; + else + cur_size = left_size; + memcpy(data, buf_list->buf, cur_size); + data += cur_size; + buf_list = (VACodedBufferSegment*)buf_list->next; + left_size -= cur_size; + } + return max_len - left_size; +} + +static EncoderStatus +gst_vaapi_base_encoder_get_coded_buffer( + GstVaapiEncoder* base, + GstBuffer **out_buf +) +{ + GstVaapiBaseEncoder *encoder = GST_VAAPI_BASE_ENCODER(base); + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + GstVaapiBaseEncoderClass *klass = + GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder); + GstVaapiEncoderBufferInfo* info; + EncoderStatus ret; + VACodedBufferSegment *buf_list = NULL; + GstBuffer* buffer = NULL; + guint buf_size; + + while((info = pop_busy_buffer_info(encoder)) == NULL){ + ret = ENCODER_NO_BUSY_BUF; + if (!priv->notify_status || + !priv->notify_status(encoder, ret, priv->user_data)) + goto end; + } + ret = ENCODER_NO_ERROR; + + ENCODER_CHECK_STATUS( + info->id && *info->id != VA_INVALID_ID, + ENCODER_DATA_ERR, + "get invalid buffer info" + ); + + ENCODER_CHECK_STATUS( + gst_vaapi_encoder_buffer_info_map(info, (void**)&buf_list), + ENCODER_DATA_ERR, + "vaMapBuffer failed"); + + buf_size = get_buf_list_size(buf_list); + ENCODER_CHECK_STATUS( + buf_size, + ENCODER_DATA_ERR, + "encoded size:0"); + buffer = gst_buffer_new_and_alloc(buf_size); + GST_BUFFER_SIZE(buffer) = move_buf_list_to_buf( + buf_list, + GST_BUFFER_DATA(buffer), + buf_size); + + if (priv->buffer_notify_flag && klass->notify_buffer) { + klass->notify_buffer( + encoder, + GST_BUFFER_DATA(buffer), + GST_BUFFER_SIZE(buffer)); + } + + if (klass->wrap_buffer) { + GstBuffer *new_buf = klass->wrap_buffer(encoder, buffer); + gst_buffer_unref(buffer); + buffer = new_buf; + } + + if (buffer) { + GST_BUFFER_TIMESTAMP(buffer) = info->timestamp; + GST_BUFFER_DURATION(buffer) = info->duration; + if (!info->is_key) + GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT); + } + FPS_CALCULATION(vaapiencode); + + *out_buf = buffer; + +end: + if (info) { + gst_vaapi_encoder_buffer_info_unmap(info); + g_object_unref(info); + } + return ret; +} + +static GstVaapiVideoBuffer * +_get_video_buffer( + GstVaapiBaseEncoder* encoder, + GstBuffer *buf +) +{ + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + GstBuffer *video_buffer; + + if (priv->buffer_sharing_flag) + video_buffer = (GstBuffer *)buf->data; + else + video_buffer = buf; + + if (GST_VAAPI_IS_VIDEO_BUFFER(video_buffer)) + return GST_VAAPI_VIDEO_BUFFER(video_buffer); + return NULL; +} + +static EncoderStatus +gst_vaapi_base_encoder_encode_default( + GstVaapiEncoder* base, + GstBuffer *pic +) +{ + GstVaapiBaseEncoder* encoder = GST_VAAPI_BASE_ENCODER(base); + GstVaapiBaseEncoderClass *base_class = + GST_VAAPI_BASE_ENCODER_GET_CLASS(encoder); + GstVaapiBaseEncoderPrivate *priv = encoder->priv; + GstVaapiDisplay *display = ENCODER_DISPLAY(encoder); + GstVaapiContext *context = ENCODER_CONTEXT(encoder); + EncoderStatus ret = ENCODER_NO_ERROR; + gboolean is_key = FALSE; + VABufferID* coded_buf = NULL; + GstVaapiSurface *buffer_surface = NULL; + gboolean is_prepared_buffer = FALSE; + + ENCODER_ASSERT(display && context); + + /* Video Buffer */ + GstVaapiVideoBuffer *video_buffer = NULL; + + ENCODER_CHECK_STATUS(pic || base_class->prepare_next_input_buffer, + ENCODER_DATA_ERR, + "Need a picture to encode"); + if (!pic) + priv->need_flush = TRUE; + +again: + if (base_class->prepare_next_input_buffer) { + GstBuffer* tmp_buf = NULL; + ret = base_class->prepare_next_input_buffer(encoder, + pic, + priv->need_flush, + &tmp_buf); + priv->need_flush = FALSE; + if (ret != ENCODER_NO_ERROR || !tmp_buf) + goto end; + + is_prepared_buffer = TRUE; + pic = tmp_buf; + } + + video_buffer = _get_video_buffer(encoder, pic); + ENCODER_CHECK_STATUS( + video_buffer, + ENCODER_SURFACE_ERR, + "vaapi encoder doesn't has video buffer"); + + buffer_surface = gst_vaapi_video_buffer_get_surface(video_buffer); + + while ((coded_buf = pop_idle_buffer_id(encoder)) == NULL) { + ret = ENCODER_NO_IDLE_BUF; + if (!priv->notify_status || + !priv->notify_status(encoder, ret, priv->user_data)) + goto end; + } + ret = ENCODER_NO_ERROR; + + /* prepare frame*/ + ret = base_class->render_frame(encoder, + buffer_surface, + priv->frame_count, + *coded_buf, + &is_key); + /* prepare failed, push back */ + if (ENCODER_NO_ERROR != ret) { + push_idle_buffer_id(encoder, coded_buf); + } + ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret, + ENCODER_PICTURE_ERR, + "base_prepare_encoding failed"); + + /*query surface result*/ + ret = query_encoding_status(encoder, buffer_surface); + if (ENCODER_NO_ERROR != ret) { + goto end; + } + + /* Push coded buffer to another task */ + GstVaapiEncoderBufferInfo* info = gst_vaapi_encoder_buffer_info_new(encoder); + info->id = coded_buf; + info->timestamp = GST_BUFFER_TIMESTAMP(pic); + info->duration = GST_BUFFER_DURATION(pic); + info->is_key = is_key; + push_busy_buffer_info(encoder, info); + + priv->frame_count++; + + if (is_prepared_buffer) { + if (pic) + gst_buffer_unref(pic); + pic = NULL; + buffer_surface = NULL; + coded_buf = NULL; + goto again; + } + +end: + if (ret < ENCODER_NO_ERROR && base_class->encode_frame_failed) { + base_class->encode_frame_failed(encoder, video_buffer); + } + if (pic && is_prepared_buffer) + gst_buffer_unref(pic); + + return ret; +} + +#if 0 +static EncoderStatus +base_put_raw_buffer_to_surface(GstVaapiBaseEncoder *base_encoder, + GstVaapiDisplay *display, + GstBuffer *raw_pic, + GstVaapiSurface *surface) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiImage *image; + GstVaapiImageFormat image_format; + guint8 *y_src = NULL, *u_src = NULL, *v_src = NULL; + guint8 *y_dst = NULL, *u_dst = NULL, *v_dst = NULL; + int y_size = 0, u_size = 0; + int row = 0, col = 0; + guint32 plane_count = 0; + guint32 image_width = 0, image_height = 0; + guint32 pitchy = 0, pitchu = 0, pitchv = 0; + GstVaapiBaseEncoderPrivate *priv = base_encoder->priv; + + ENCODER_ASSERT(display); + VAAPI_UNUSED_ARG(pitchv); + VAAPI_UNUSED_ARG(v_dst); + /*map image*/ + image = gst_vaapi_surface_derive_image(surface); + gst_vaapi_image_map(image); + + image_format = gst_vaapi_image_get_format(image); + image_width = gst_vaapi_image_get_width(image); + image_height = gst_vaapi_image_get_height(image); + + /* copy buffer to surface */ + ENCODER_ASSERT(GST_BUFFER_SIZE(raw_pic) >= y_size + (y_size>>1)); + + y_size = ENCODER_WIDTH(base_encoder) * ENCODER_HEIGHT(base_encoder); + u_size = ((ENCODER_WIDTH(base_encoder)+1) >> 1) * ((ENCODER_HEIGHT(base_encoder)+1) >> 1); + + y_src = GST_BUFFER_DATA(raw_pic); + u_src = y_src + y_size; + v_src = u_src + u_size; + + plane_count = gst_vaapi_image_get_plane_count(image); + y_dst = gst_vaapi_image_get_plane(image, 0); + u_dst = gst_vaapi_image_get_plane(image, 1); + pitchy = gst_vaapi_image_get_pitch(image, 0); + pitchu = gst_vaapi_image_get_pitch(image, 1); + + if (plane_count > 2) { + v_dst = gst_vaapi_image_get_plane(image, 2); + pitchv = gst_vaapi_image_get_pitch(image, 2); + } + + /* copy from avcenc.c*/ + /* Y plane */ + for (row = 0; row < image_height; row++) { + memcpy(y_dst, y_src, image_width); + y_dst += pitchy; + y_src += ENCODER_WIDTH(base_encoder); + } + + if (GST_VAAPI_IMAGE_NV12 == image_format) { /* UV plane */ + if (GST_VAAPI_IMAGE_I420 == priv->format) { + for (row = 0; row < image_height / 2; row++) { + for (col = 0; col < image_width / 2; col++) { + u_dst[col * 2] = u_src[col]; + u_dst[col * 2 + 1] = v_src[col]; + } + + u_dst += pitchu; + u_src += (ENCODER_WIDTH(base_encoder)>>1); + v_src += (ENCODER_WIDTH(base_encoder)>>1); + } + } else if (GST_VAAPI_IMAGE_NV12 == priv->format){ + for (row = 0; row < image_height / 2; row++) { + memcpy(u_dst, u_src, image_width); + u_src += ENCODER_WIDTH(base_encoder); + u_dst += pitchu; + } + } else { + ENCODER_ASSERT(0); + } + } else { + /* FIXME: fix this later */ + ENCODER_ASSERT(0); + } + + /*unmap image*/ + g_object_unref(image); + + return ret; +} +#endif + +static EncoderStatus +gst_vaapi_base_encoder_flush_default( + GstVaapiEncoder* encoder +) +{ + GstVaapiBaseEncoder* base_encoder = GST_VAAPI_BASE_ENCODER(encoder); + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiBaseEncoderPrivate *priv = base_encoder->priv; + + priv->frame_count = 0; + priv->need_flush = TRUE; + /*do we need destroy priv->seq_parameter? */ + + //end: + return ret; +} + + +static void +gst_vaapi_base_encoder_finalize(GObject *object) +{ + /*free private buffers*/ + GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object); + GstVaapiBaseEncoderPrivate *priv = + GST_VAAPI_BASE_ENCODER_GET_PRIVATE(object); + + if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) { + gst_vaapi_encoder_uninitialize(encoder); + } + + g_static_rec_mutex_free(&priv->mutex); + if (priv->idle_buf_queue) + g_queue_free(priv->idle_buf_queue); + + if (priv->busy_buf_queue) + g_queue_free(priv->busy_buf_queue); + + G_OBJECT_CLASS(gst_vaapi_base_encoder_parent_class)->finalize(object); +} + +static void +gst_vaapi_base_encoder_init(GstVaapiBaseEncoder *encoder) +{ + GstVaapiBaseEncoderPrivate *priv = + GST_VAAPI_BASE_ENCODER_GET_PRIVATE(encoder); + ENCODER_ASSERT(priv); + encoder->priv = priv; + + /* init private values*/ + priv->format = 0; + priv->profile= VA_INVALID_PROFILE; + priv->frame_count = 0; + priv->buffer_sharing_flag = FALSE; + priv->buffer_notify_flag = FALSE; + + priv->coded_bufs = NULL; + priv->coded_buf_num = DEFAULT_VA_CODEDBUF_NUM; + priv->idle_buf_queue = g_queue_new(); + priv->busy_buf_queue = g_queue_new(); + g_static_rec_mutex_init(&priv->mutex); + + priv->notify_status = NULL; + priv->user_data = NULL; + + priv->need_flush = FALSE; +} + +static void +gst_vaapi_base_encoder_class_init(GstVaapiBaseEncoderClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass); + g_type_class_add_private(klass, sizeof(GstVaapiBaseEncoderPrivate)); + + GST_DEBUG_CATEGORY_INIT (gst_vaapi_base_encoder_debug, + "gst_vaapi_base_encoder", + 0, + "gst_vaapi_base_encoder element"); + + object_class->finalize = gst_vaapi_base_encoder_finalize; + + encoder_class->open = gst_vaapi_base_encoder_open_default; + encoder_class->close = gst_vaapi_base_encoder_close_default; + encoder_class->encode = gst_vaapi_base_encoder_encode_default; + encoder_class->flush = gst_vaapi_base_encoder_flush_default; + encoder_class->get_buf = gst_vaapi_base_encoder_get_coded_buffer; + encoder_class->get_codec_data = NULL; + + /* user defined functions*/ + klass->validate_attributes = NULL; + klass->pre_alloc_resource = NULL; + klass->release_resource = NULL; + klass->prepare_next_input_buffer = NULL; + klass->render_frame = NULL; + klass->notify_buffer = NULL; + klass->wrap_buffer = NULL; + klass->encode_frame_failed = NULL; + + /* + object_class->set_property = gst_vaapi_base_encoder_set_property; + object_class->get_property = gst_vaapi_base_encoder_get_property; + */ +} diff --git a/gst-libs/gst/vaapi/gstvaapibaseencoder.h b/gst-libs/gst/vaapi/gstvaapibaseencoder.h new file mode 100644 index 0000000..fe9679d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapibaseencoder.h @@ -0,0 +1,144 @@ +/* + * gstvaapibaseencoder.h - VA-API base encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_BASE_ENCODER_H +#define GST_VAAPI_BASE_ENCODER_H + +#include "gst/vaapi/gstvaapiencoder.h" +#include "gst/vaapi/gstvaapivideobuffer.h" + +G_BEGIN_DECLS + +typedef struct _GstVaapiBaseEncoder GstVaapiBaseEncoder; +typedef struct _GstVaapiBaseEncoderPrivate GstVaapiBaseEncoderPrivate; +typedef struct _GstVaapiBaseEncoderClass GstVaapiBaseEncoderClass; + +#define GST_TYPE_VAAPI_BASE_ENCODER \ + (gst_vaapi_base_encoder_get_type()) + +#define GST_IS_VAAPI_BASE_ENCODER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_BASE_ENCODER)) + +#define GST_IS_VAAPI_BASE_ENCODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_BASE_ENCODER)) + +#define GST_VAAPI_BASE_ENCODER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GST_TYPE_VAAPI_BASE_ENCODER, \ + GstVaapiBaseEncoderClass)) + +#define GST_VAAPI_BASE_ENCODER(obj) \ +(G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_VAAPI_BASE_ENCODER, \ + GstVaapiBaseEncoder)) + +#define GST_VAAPI_BASE_ENCODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GST_TYPE_VAAPI_BASE_ENCODER, \ + GstVaapiBaseEncoderClass)) + +#define GST_VAAPI_BASE_ENCODER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_TYPE_VAAPI_BASE_ENCODER, \ + GstVaapiBaseEncoderPrivate)) + +/* return: if true, continue; else, stop*/ +typedef gboolean + (*GstVaapiBaseEncoderNotifyStatus)( + GstVaapiBaseEncoder* encoder, + EncoderStatus status, + void* userdata); + +struct _GstVaapiBaseEncoder { + GstVaapiEncoder parent; + + GstVaapiBaseEncoderPrivate *priv; +}; + +struct _GstVaapiBaseEncoderClass { + GstVaapiEncoderClass parent_class; + + /* in function*/ + gboolean (*validate_attributes) (GstVaapiBaseEncoder* encoder); + gboolean (*pre_alloc_resource) (GstVaapiBaseEncoder *encoder, + GstVaapiContext* context); + + /* in function */ + gboolean (*release_resource) (GstVaapiBaseEncoder* encoder); + + /* in function */ + EncoderStatus (*prepare_next_input_buffer)(GstVaapiBaseEncoder* encoder, + GstBuffer *display_buf, + gboolean need_flush, + GstBuffer **out_buf); + + EncoderStatus (*render_frame) (GstVaapiBaseEncoder *encoder, + GstVaapiSurface *surface, + guint frame_index, + VABufferID coded_buf, + gboolean *is_key); + + void (*encode_frame_failed) (GstVaapiBaseEncoder *encoder, + GstVaapiVideoBuffer* buffer); + + void (*notify_buffer) (GstVaapiBaseEncoder *encoder, + guint8 *buf, guint32 size); + + GstBuffer *(*wrap_buffer) (GstVaapiBaseEncoder *encoder, + GstBuffer *buf); +}; + +GType +gst_vaapi_base_encoder_get_type(void); + +void +gst_vaapi_base_encoder_set_frame_notify( + GstVaapiBaseEncoder *encoder, + gboolean flag +); + +gboolean +gst_vaapi_base_encoder_set_va_profile( + GstVaapiBaseEncoder *encoder, + guint profile +); +void +gst_vaapi_base_encoder_set_input_format( + GstVaapiBaseEncoder* encoder, + guint32 format +); + +gboolean +gst_vaapi_base_encoder_set_notify_status( + GstVaapiBaseEncoder *encoder, + GstVaapiBaseEncoderNotifyStatus func, + gpointer user_data +); + +void +gst_vaapi_base_encoder_set_buffer_sharing( + GstVaapiBaseEncoder *encoder, + gboolean is_buffer_sharing +); + +G_END_DECLS + +#endif /* GST_VAAPI_BASE_ENCODER_H */ diff --git a/gst-libs/gst/vaapi/gstvaapicodec_objects.c b/gst-libs/gst/vaapi/gstvaapicodec_objects.c new file mode 100644 index 0000000..e79341d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodec_objects.c @@ -0,0 +1,306 @@ +/* + * gstvaapicodec_objects.c - VA codec objects abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapicodec_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/* ------------------------------------------------------------------------- */ +/* --- Base Codec Object --- */ +/* ------------------------------------------------------------------------- */ + +G_DEFINE_TYPE(GstVaapiCodecObject, gst_vaapi_codec_object, GST_TYPE_MINI_OBJECT) + +static void +gst_vaapi_codec_object_finalize(GstMiniObject *object) +{ + GstVaapiCodecObject * const obj = GST_VAAPI_CODEC_OBJECT(object); + + obj->codec = NULL; +} + +static void +gst_vaapi_codec_object_init(GstVaapiCodecObject *obj) +{ + obj->codec = NULL; +} + +static gboolean +gst_vaapi_codec_object_create( + GstVaapiCodecObject *obj, + const GstVaapiCodecObjectConstructorArgs *args +) +{ + obj->codec = args->codec; + return TRUE; +} + +static void +gst_vaapi_codec_object_class_init(GstVaapiCodecObjectClass *klass) +{ + GstMiniObjectClass * const object_class = GST_MINI_OBJECT_CLASS(klass); + + object_class->finalize = gst_vaapi_codec_object_finalize; + klass->construct = gst_vaapi_codec_object_create; +} + +GstVaapiCodecObject * +gst_vaapi_codec_object_new( + GType type, + GstVaapiCodecBase *codec, + gconstpointer param, + guint param_size, + gconstpointer data, + guint data_size +) +{ + GstMiniObject *obj; + GstVaapiCodecObject *va_obj; + GstVaapiCodecObjectConstructorArgs args; + + obj = gst_mini_object_new(type); + if (!obj) + return NULL; + + va_obj = GST_VAAPI_CODEC_OBJECT(obj); + args.codec = codec; + args.param = param; + args.param_size = param_size; + args.data = data; + args.data_size = data_size; + args.flags = 0; + if (gst_vaapi_codec_object_construct(va_obj, &args)) + return va_obj; + + gst_mini_object_unref(obj); + return NULL; +} + +gboolean +gst_vaapi_codec_object_construct( + GstVaapiCodecObject *obj, + const GstVaapiCodecObjectConstructorArgs *args +) +{ + GstVaapiCodecObjectClass *klass; + + g_return_val_if_fail(GST_VAAPI_CODEC_OBJECT(obj), FALSE); + g_return_val_if_fail(args->codec != NULL, FALSE); + g_return_val_if_fail(args->param_size > 0, FALSE); + + if (GST_MINI_OBJECT_FLAG_IS_SET(obj, GST_VAAPI_CODEC_OBJECT_FLAG_CONSTRUCTED)) + return TRUE; + + klass = GST_VAAPI_CODEC_OBJECT_GET_CLASS(obj); + if (!klass || !klass->construct || !klass->construct(obj, args)) + return FALSE; + + GST_MINI_OBJECT_FLAG_SET(obj, GST_VAAPI_CODEC_OBJECT_FLAG_CONSTRUCTED); + return TRUE; +} + +#define GET_DECODER(obj) GST_VAAPI_DECODER_CAST((obj)->parent_instance.codec) +#define GET_CONTEXT(obj) GET_DECODER(obj)->priv->context +#define GET_VA_DISPLAY(obj) GET_DECODER(obj)->priv->va_display +#define GET_VA_CONTEXT(obj) GET_DECODER(obj)->priv->va_context + +/* ------------------------------------------------------------------------- */ +/* --- Inverse Quantization Matrices --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiIqMatrix, + gst_vaapi_iq_matrix, + GST_VAAPI_TYPE_CODEC_OBJECT) + +static void +gst_vaapi_iq_matrix_destroy(GstVaapiIqMatrix *iq_matrix) +{ + vaapi_destroy_buffer(GET_VA_DISPLAY(iq_matrix), &iq_matrix->param_id); + iq_matrix->param = NULL; +} + +static gboolean +gst_vaapi_iq_matrix_create( + GstVaapiIqMatrix *iq_matrix, + const GstVaapiCodecObjectConstructorArgs *args +) +{ + return vaapi_create_buffer(GET_VA_DISPLAY(iq_matrix), + GET_VA_CONTEXT(iq_matrix), + VAIQMatrixBufferType, + args->param_size, + args->param, + &iq_matrix->param_id, + &iq_matrix->param); +} + +static void +gst_vaapi_iq_matrix_init(GstVaapiIqMatrix *iq_matrix) +{ + iq_matrix->param = NULL; + iq_matrix->param_id = VA_INVALID_ID; +} + +GstVaapiIqMatrix * +gst_vaapi_iq_matrix_new( + GstVaapiDecoder *decoder, + gconstpointer param, + guint param_size +) +{ + GstVaapiCodecObject *object; + + g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL); + + object = gst_vaapi_codec_object_new( + GST_VAAPI_TYPE_IQ_MATRIX, + GST_VAAPI_CODEC_BASE(decoder), + param, param_size, + NULL, 0 + ); + if (!object) + return NULL; + return GST_VAAPI_IQ_MATRIX_CAST(object); +} + +/* ------------------------------------------------------------------------- */ +/* --- VC-1 Bit Planes --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiBitPlane, + gst_vaapi_bitplane, + GST_VAAPI_TYPE_CODEC_OBJECT) + +static void +gst_vaapi_bitplane_destroy(GstVaapiBitPlane *bitplane) +{ + vaapi_destroy_buffer(GET_VA_DISPLAY(bitplane), &bitplane->data_id); + bitplane->data = NULL; +} + +static gboolean +gst_vaapi_bitplane_create( + GstVaapiBitPlane *bitplane, + const GstVaapiCodecObjectConstructorArgs *args +) +{ + return vaapi_create_buffer(GET_VA_DISPLAY(bitplane), + GET_VA_CONTEXT(bitplane), + VABitPlaneBufferType, + args->param_size, + args->param, + &bitplane->data_id, + (void **)&bitplane->data); +} + +static void +gst_vaapi_bitplane_init(GstVaapiBitPlane *bitplane) +{ + bitplane->data = NULL; + bitplane->data_id = VA_INVALID_ID; +} + +GstVaapiBitPlane * +gst_vaapi_bitplane_new(GstVaapiDecoder *decoder, guint8 *data, guint data_size) +{ + GstVaapiCodecObject *object; + + g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL); + + object = gst_vaapi_codec_object_new( + GST_VAAPI_TYPE_BITPLANE, + GST_VAAPI_CODEC_BASE(decoder), + data, data_size, + NULL, 0 + ); + if (!object) + return NULL; + return GST_VAAPI_BITPLANE_CAST(object); +} + +/* ------------------------------------------------------------------------- */ +/* --- JPEG Huffman Tables --- */ +/* ------------------------------------------------------------------------- */ + +#if USE_JPEG_DECODER +GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiHuffmanTable, + gst_vaapi_huffman_table, + GST_VAAPI_TYPE_CODEC_OBJECT) + +static void +gst_vaapi_huffman_table_destroy(GstVaapiHuffmanTable *huf_table) +{ + vaapi_destroy_buffer(GET_VA_DISPLAY(huf_table), &huf_table->param_id); + huf_table->param = NULL; +} + +static gboolean +gst_vaapi_huffman_table_create( + GstVaapiHuffmanTable *huf_table, + const GstVaapiCodecObjectConstructorArgs *args +) +{ + return vaapi_create_buffer(GET_VA_DISPLAY(huf_table), + GET_VA_CONTEXT(huf_table), + VAHuffmanTableBufferType, + args->param_size, + args->param, + &huf_table->param_id, + (void **)&huf_table->param); +} + +static void +gst_vaapi_huffman_table_init(GstVaapiHuffmanTable *huf_table) +{ + huf_table->param = NULL; + huf_table->param_id = VA_INVALID_ID; +} + +GstVaapiHuffmanTable * +gst_vaapi_huffman_table_new( + GstVaapiDecoder *decoder, + guint8 *data, + guint data_size +) +{ + GstVaapiCodecObject *object; + + g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL); + + object = gst_vaapi_codec_object_new( + GST_VAAPI_TYPE_HUFFMAN_TABLE, + GST_VAAPI_CODEC_BASE(decoder), + data, data_size, + NULL, 0 + ); + if (!object) + return NULL; + return GST_VAAPI_HUFFMAN_TABLE_CAST(object); +} +#endif diff --git a/gst-libs/gst/vaapi/gstvaapicodec_objects.h b/gst-libs/gst/vaapi/gstvaapicodec_objects.h new file mode 100644 index 0000000..a064c15 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicodec_objects.h @@ -0,0 +1,400 @@ +/* + * gstvaapicodec_objects.h - VA codec objects abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_CODEC_COMMON_H +#define GST_VAAPI_CODEC_COMMON_H + +#include +#include + +G_BEGIN_DECLS + +typedef gpointer GstVaapiCodecBase; +typedef struct _GstVaapiCodecObject GstVaapiCodecObject; +typedef struct _GstVaapiCodecObjectClass GstVaapiCodecObjectClass; +typedef struct _GstVaapiIqMatrix GstVaapiIqMatrix; +typedef struct _GstVaapiIqMatrixClass GstVaapiIqMatrixClass; +typedef struct _GstVaapiBitPlane GstVaapiBitPlane; +typedef struct _GstVaapiBitPlaneClass GstVaapiBitPlaneClass; +typedef struct _GstVaapiHuffmanTable GstVaapiHuffmanTable; +typedef struct _GstVaapiHuffmanTableClass GstVaapiHuffmanTableClass; + +/* ------------------------------------------------------------------------- */ +/* --- Base Codec Object --- */ +/* ------------------------------------------------------------------------- */ + +/* XXX: remove when a common base class for decoder and encoder is available */ +#define GST_VAAPI_CODEC_BASE(obj) \ + ((GstVaapiCodecBase *)(obj)) + +#define GST_VAAPI_TYPE_CODEC_OBJECT \ + (gst_vaapi_codec_object_get_type()) + +#define GST_VAAPI_CODEC_OBJECT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_CODEC_OBJECT, \ + GstVaapiCodecObject)) + +#define GST_VAAPI_CODEC_OBJECT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_CODEC_OBJECT, \ + GstVaapiCodecObjectClass)) + +#define GST_VAAPI_IS_CODEC_OBJECT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_CODEC_OBJECT)) + +#define GST_VAAPI_IS_CODEC_OBJECT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_CODEC_OBJECT)) + +#define GST_VAAPI_CODEC_OBJECT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_CODEC_OBJECT, \ + GstVaapiCodecObjectClass)) + +enum { + GST_VAAPI_CODEC_OBJECT_FLAG_CONSTRUCTED = (GST_MINI_OBJECT_FLAG_LAST << 0), + GST_VAAPI_CODEC_OBJECT_FLAG_LAST = (GST_MINI_OBJECT_FLAG_LAST << 1) +}; + +typedef struct { + GstVaapiCodecObject *obj; + GstVaapiCodecBase *codec; + gconstpointer param; + guint param_size; + gconstpointer data; + guint data_size; + guint flags; +} GstVaapiCodecObjectConstructorArgs; + +/** + * GstVaapiCodecObject: + * + * A #GstMiniObject holding the base codec object data + */ +struct _GstVaapiCodecObject { + /*< private >*/ + GstMiniObject parent_instance; + GstVaapiCodecBase *codec; +}; + +/** + * GstVaapiCodecObjectClass: + * + * The #GstVaapiCodecObject base class. + */ +struct _GstVaapiCodecObjectClass { + /*< private >*/ + GstMiniObjectClass parent_class; + + gboolean (*construct) (GstVaapiCodecObject *obj, + const GstVaapiCodecObjectConstructorArgs *args); +}; + +G_GNUC_INTERNAL +GType +gst_vaapi_codec_object_get_type(void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstVaapiCodecObject * +gst_vaapi_codec_object_new( + GType type, + GstVaapiCodecBase *codec, + gconstpointer param, + guint param_size, + gconstpointer data, + guint data_size +); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_codec_object_construct( + GstVaapiCodecObject *obj, + const GstVaapiCodecObjectConstructorArgs *args +); + +/* ------------------------------------------------------------------------- */ +/* --- Inverse Quantization Matrices --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_TYPE_IQ_MATRIX \ + (gst_vaapi_iq_matrix_get_type()) + +#define GST_VAAPI_IQ_MATRIX_CAST(obj) \ + ((GstVaapiIqMatrix *)(obj)) + +#define GST_VAAPI_IQ_MATRIX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_IQ_MATRIX, \ + GstVaapiIqMatrix)) + +#define GST_VAAPI_IQ_MATRIX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_IQ_MATRIX, \ + GstVaapiIqMatrixClass)) + +#define GST_VAAPI_IS_IQ_MATRIX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_IQ_MATRIX)) + +#define GST_VAAPI_IS_IQ_MATRIX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_IQ_MATRIX)) + +#define GST_VAAPI_IQ_MATRIX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_IQ_MATRIX, \ + GstVaapiIqMatrixClass)) + +/** + * GstVaapiIqMatrix: + * + * A #GstVaapiCodecObject holding an inverse quantization matrix parameter. + */ +struct _GstVaapiIqMatrix { + /*< private >*/ + GstVaapiCodecObject parent_instance; + VABufferID param_id; + + /*< public >*/ + gpointer param; +}; + +/** + * GstVaapiIqMatrixClass: + * + * The #GstVaapiIqMatrix base class. + */ +struct _GstVaapiIqMatrixClass { + /*< private >*/ + GstVaapiCodecObjectClass parent_class; +}; + +G_GNUC_INTERNAL +GType +gst_vaapi_iq_matrix_get_type(void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstVaapiIqMatrix * +gst_vaapi_iq_matrix_new( + GstVaapiDecoder *decoder, + gconstpointer param, + guint param_size +); + +/* ------------------------------------------------------------------------- */ +/* --- VC-1 Bit Planes --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_TYPE_BITPLANE \ + (gst_vaapi_bitplane_get_type()) + +#define GST_VAAPI_BITPLANE_CAST(obj) \ + ((GstVaapiBitPlane *)(obj)) + +#define GST_VAAPI_BITPLANE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_BITPLANE, \ + GstVaapiBitPlane)) + +#define GST_VAAPI_BITPLANE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_BITPLANE, \ + GstVaapiBitPlaneClass)) + +#define GST_VAAPI_IS_BITPLANE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_BITPLANE)) + +#define GST_VAAPI_IS_BITPLANE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_BITPLANE)) + +#define GST_VAAPI_BITPLANE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_BITPLANE, \ + GstVaapiBitPlaneClass)) + +/** + * GstVaapiBitPlane: + * + * A #GstVaapiCodecObject holding a VC-1 bit plane parameter. + */ +struct _GstVaapiBitPlane { + /*< private >*/ + GstVaapiCodecObject parent_instance; + VABufferID data_id; + + /*< public >*/ + guint8 *data; +}; + +/** + * GstVaapiBitPlaneClass: + * + * The #GstVaapiBitPlane base class. + */ +struct _GstVaapiBitPlaneClass { + /*< private >*/ + GstVaapiCodecObjectClass parent_class; +}; + +G_GNUC_INTERNAL +GType +gst_vaapi_bitplane_get_type(void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstVaapiBitPlane * +gst_vaapi_bitplane_new(GstVaapiDecoder *decoder, guint8 *data, guint data_size); + +/* ------------------------------------------------------------------------- */ +/* --- JPEG Huffman Tables --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_TYPE_HUFFMAN_TABLE \ + (gst_vaapi_huffman_table_get_type()) + +#define GST_VAAPI_HUFFMAN_TABLE_CAST(obj) \ + ((GstVaapiHuffmanTable *)(obj)) + +#define GST_VAAPI_HUFFMAN_TABLE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_HUFFMAN_TABLE, \ + GstVaapiHuffmanTable)) + +#define GST_VAAPI_HUFFMAN_TABLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_HUFFMAN_TABLE, \ + GstVaapiHuffmanTableClass)) + +#define GST_VAAPI_IS_HUFFMAN_TABLE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_HUFFMAN_TABLE)) + +#define GST_VAAPI_IS_HUFFMAN_TABLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_HUFFMAN_TABLE)) + +#define GST_VAAPI_HUFFMAN_TABLE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_HUFFMAN_TABLE, \ + GstVaapiHuffmanTableClass)) + +/** + * GstVaapiHuffmanTable: + * + * A #GstVaapiCodecObject holding huffman table. + */ +struct _GstVaapiHuffmanTable { + /*< private >*/ + GstVaapiCodecObject parent_instance; + VABufferID param_id; + + /*< public >*/ + gpointer param; +}; + +/** + * GstVaapiHuffmanTableClass: + * + * The #GstVaapiHuffmanTable base class. + */ +struct _GstVaapiHuffmanTableClass { + /*< private >*/ + GstVaapiCodecObjectClass parent_class; +}; + +G_GNUC_INTERNAL +GType +gst_vaapi_huffman_table_get_type(void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstVaapiHuffmanTable * +gst_vaapi_huffman_table_new( + GstVaapiDecoder *decoder, + guint8 *data, + guint data_size +); + +/* ------------------------------------------------------------------------- */ +/* --- Helpers to create codec-dependent objects --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_CODEC_DEFINE_TYPE(type, prefix, base_type) \ +G_DEFINE_TYPE(type, prefix, base_type) \ + \ +static void \ +prefix##_destroy(type *); \ + \ +static gboolean \ +prefix##_create( \ + type *, \ + const GstVaapiCodecObjectConstructorArgs *args \ +); \ + \ +static void \ +prefix##_finalize(GstMiniObject *object) \ +{ \ + GstMiniObjectClass *parent_class; \ + \ + prefix##_destroy((type *)object); \ + \ + parent_class = GST_MINI_OBJECT_CLASS(prefix##_parent_class); \ + if (parent_class->finalize) \ + parent_class->finalize(object); \ +} \ + \ +static gboolean \ +prefix##_construct( \ + GstVaapiCodecObject *object, \ + const GstVaapiCodecObjectConstructorArgs *args \ +) \ +{ \ + GstVaapiCodecObjectClass *parent_class; \ + \ + parent_class = GST_VAAPI_CODEC_OBJECT_CLASS(prefix##_parent_class); \ + if (parent_class->construct) { \ + if (!parent_class->construct(object, args)) \ + return FALSE; \ + } \ + return prefix##_create((type *)object, args); \ +} \ + \ +static void \ +prefix##_class_init(type##Class *klass) \ +{ \ + GstMiniObjectClass * const object_class = \ + GST_MINI_OBJECT_CLASS(klass); \ + GstVaapiCodecObjectClass * const codec_class = \ + GST_VAAPI_CODEC_OBJECT_CLASS(klass); \ + \ + object_class->finalize = prefix##_finalize; \ + codec_class->construct = prefix##_construct; \ +} + +#define GST_VAAPI_IQ_MATRIX_NEW(codec, decoder) \ + gst_vaapi_iq_matrix_new(GST_VAAPI_DECODER_CAST(decoder), \ + NULL, sizeof(VAIQMatrixBuffer##codec)) + +#define GST_VAAPI_BITPLANE_NEW(decoder, size) \ + gst_vaapi_bitplane_new(GST_VAAPI_DECODER_CAST(decoder), NULL, size) + +#define GST_VAAPI_HUFFMAN_TABLE_NEW(codec, decoder) \ + gst_vaapi_huffman_table_new(GST_VAAPI_DECODER_CAST(decoder), \ + NULL, sizeof(VAHuffmanTableBuffer##codec)) + +G_END_DECLS + +#endif /* GST_VAAPI_CODEC_OBJECTS_H */ diff --git a/gst-libs/gst/vaapi/gstvaapicompat.h b/gst-libs/gst/vaapi/gstvaapicompat.h new file mode 100644 index 0000000..4a1f93d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicompat.h @@ -0,0 +1,54 @@ +/* + * gstvapicompat.h - VA-API compatibility glue + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_COMPAT_H +#define GST_VAAPI_COMPAT_H + +#include + +#ifdef HAVE_VA_VA_GLX_H +# define USE_VAAPI_GLX 1 +#else +# define USE_VAAPI_GLX 0 +#endif + +#if USE_VAAPI_GLX +# include +#else +# define vaGetDisplayGLX(dpy) vaGetDisplay(dpy) +#endif + +/* Compatibility glue with VA-API < 0.31 */ +#if !VA_CHECK_VERSION(0,31,0) +#undef vaSyncSurface +#define vaSyncSurface(dpy, s) (vaSyncSurface)((dpy), VA_INVALID_ID, (s)) +#undef vaPutImage +#define vaPutImage vaPutImage2 +#undef vaAssociateSubpicture +#define vaAssociateSubpicture vaAssociateSubpicture2 +#endif + +/* Compatibility glue with VA-API 0.34 */ +#if VA_CHECK_VERSION(0,34,0) +# include +#endif + +#endif /* GST_VAAPI_COMPAT_H */ diff --git a/gst-libs/gst/vaapi/gstvaapicontext.c b/gst-libs/gst/vaapi/gstvaapicontext.c new file mode 100644 index 0000000..69f43a1 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicontext.c @@ -0,0 +1,1038 @@ +/* + * gstvaapicontext.c - VA context abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapicontext + * @short_description: VA context abstraction + */ + +#include "sysdeps.h" +#include +#include "gstvaapicompat.h" +#include "gstvaapicontext.h" +#include "gstvaapisurface.h" +#include "gstvaapisurface_priv.h" +#include "gstvaapisurfacepool.h" +#include "gstvaapiimage.h" +#include "gstvaapisubpicture.h" +#include "gstvaapiutils.h" +#include "gstvaapi_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiContext, gst_vaapi_context, GST_VAAPI_TYPE_OBJECT); + +#define GST_VAAPI_CONTEXT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_CONTEXT, \ + GstVaapiContextPrivate)) + +typedef struct _GstVaapiOverlayRectangle GstVaapiOverlayRectangle; +struct _GstVaapiOverlayRectangle { + GstVaapiContext *context; + GstVaapiSubpicture *subpicture; + GstVaapiRectangle rect; + guint seq_num; +}; + +/* XXX: optimize for the effective number of reference frames */ +struct _GstVaapiContextPrivate { + VAConfigID config_id; + GPtrArray *surfaces; + GstVaapiVideoPool *surfaces_pool; + guint surface_num; + GPtrArray *overlay; + GstVaapiProfile profile; + GstVaapiEntrypoint entrypoint; + GstVaapiRateControl rate_control; + guint width; + guint height; + guint is_constructed : 1; +}; + +enum { + PROP_0, + + PROP_PROFILE, + PROP_ENTRYPOINT, + PROP_WIDTH, + PROP_HEIGHT, + PROP_SURFACE_NUM, + PROP_RATE_CONTROL +}; + +static GstVaapiOverlayRectangle * +overlay_rectangle_new(GstVaapiContext *context) +{ + GstVaapiOverlayRectangle *overlay; + + overlay = g_slice_new0(GstVaapiOverlayRectangle); + if (!overlay) + return NULL; + + overlay->context = context; + return overlay; +} + +static void +overlay_rectangle_destroy(GstVaapiOverlayRectangle *overlay) +{ + GstVaapiContextPrivate *priv; + guint i; + + if (!overlay) + return; + priv = overlay->context->priv; + + if (overlay->subpicture) { + if (priv->surfaces) { + GstVaapiSubpicture * const subpicture = overlay->subpicture; + for (i = 0; i < priv->surfaces->len; i++) { + GstVaapiSurface * const surface = + g_ptr_array_index(priv->surfaces, i); + gst_vaapi_surface_deassociate_subpicture(surface, subpicture); + } + } + g_object_unref(overlay->subpicture); + overlay->subpicture = NULL; + } + g_slice_free(GstVaapiOverlayRectangle, overlay); +} + +static void +destroy_overlay_cb(gpointer data, gpointer user_data) +{ + GstVaapiOverlayRectangle * const overlay = data; + + overlay_rectangle_destroy(overlay); +} + +static void +gst_vaapi_context_destroy_overlay(GstVaapiContext *context) +{ + GstVaapiContextPrivate * const priv = context->priv; + + if (!priv->overlay) + return; + + g_ptr_array_foreach(priv->overlay, destroy_overlay_cb, priv); + g_ptr_array_free(priv->overlay, TRUE); + priv->overlay = NULL; +} + +static void +unref_surface_cb(gpointer data, gpointer user_data) +{ + GstVaapiSurface * const surface = GST_VAAPI_SURFACE(data); + + gst_vaapi_surface_set_parent_context(surface, NULL); + g_object_unref(surface); +} + +static void +gst_vaapi_context_destroy_surfaces(GstVaapiContext *context) +{ + GstVaapiContextPrivate * const priv = context->priv; + + gst_vaapi_context_destroy_overlay(context); + + if (priv->surfaces) { + g_ptr_array_foreach(priv->surfaces, unref_surface_cb, NULL); + g_ptr_array_free(priv->surfaces, TRUE); + priv->surfaces = NULL; + } + + g_clear_object(&priv->surfaces_pool); +} + +static void +gst_vaapi_context_destroy(GstVaapiContext *context) +{ + GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(context); + GstVaapiContextPrivate * const priv = context->priv; + VAContextID context_id; + VAStatus status; + + context_id = GST_VAAPI_OBJECT_ID(context); + GST_DEBUG("context %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(context_id)); + + if (context_id != VA_INVALID_ID) { + GST_VAAPI_DISPLAY_LOCK(display); + status = vaDestroyContext( + GST_VAAPI_DISPLAY_VADISPLAY(display), + context_id + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaDestroyContext()")) + g_warning("failed to destroy context %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS(context_id)); + GST_VAAPI_OBJECT_ID(context) = VA_INVALID_ID; + } + + if (priv->config_id != VA_INVALID_ID) { + GST_VAAPI_DISPLAY_LOCK(display); + status = vaDestroyConfig( + GST_VAAPI_DISPLAY_VADISPLAY(display), + priv->config_id + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaDestroyConfig()")) + g_warning("failed to destroy config %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS(priv->config_id)); + priv->config_id = VA_INVALID_ID; + } +} + +static gboolean +gst_vaapi_context_create_overlay(GstVaapiContext *context) +{ + GstVaapiContextPrivate * const priv = context->priv; + + if (!priv->overlay) { + priv->overlay = g_ptr_array_new(); + if (!priv->overlay) + return FALSE; + } + return TRUE; +} + +static gboolean +gst_vaapi_context_increase_surfaces(GstVaapiContext *context,guint increment) +{ + GstVaapiContextPrivate * const priv = context->priv; + GstVaapiVideoPool * surface_pool; + GstVaapiSurface *surface; + guint i; + + surface_pool = priv->surfaces_pool; + if (!priv->surfaces || !surface_pool) + return FALSE; + + if ((priv->surfaces->len + increment) > + gst_vaapi_video_pool_get_capacity(surface_pool)) + return FALSE; + + for (i = 0; i < increment; ++i) { + surface = gst_vaapi_surface_new( + GST_VAAPI_OBJECT_DISPLAY(context), + GST_VAAPI_CHROMA_TYPE_YUV420, + priv->width, priv->height + ); + if (!surface) + return FALSE; + g_ptr_array_add(priv->surfaces, surface); + if (!gst_vaapi_video_pool_add_object(priv->surfaces_pool, surface)) + return FALSE; + } + priv->surface_num = priv->surfaces->len; + return TRUE; +} + + +static gboolean +gst_vaapi_context_create_surfaces(GstVaapiContext *context, guint surface_num) +{ + GstVaapiContextPrivate * const priv = context->priv; + GstCaps *caps; + GstVaapiSurface *surface; + guint i, pool_capacity; + + if (!gst_vaapi_context_create_overlay(context)) + return FALSE; + + if (!priv->surfaces) { + priv->surfaces = g_ptr_array_new(); + if (!priv->surfaces) + return FALSE; + } + + if (!priv->surfaces_pool) { + caps = gst_caps_new_simple( + GST_VAAPI_SURFACE_CAPS_NAME, + "type", G_TYPE_STRING, "vaapi", + "width", G_TYPE_INT, priv->width, + "height", G_TYPE_INT, priv->height, + NULL + ); + if (!caps) + return FALSE; + priv->surfaces_pool = gst_vaapi_surface_pool_new( + GST_VAAPI_OBJECT_DISPLAY(context), + caps + ); + gst_caps_unref(caps); + if (!priv->surfaces_pool) + return FALSE; + } + + pool_capacity = + ((gst_vaapi_profile_get_codec(priv->profile) == GST_VAAPI_CODEC_H264) ? 20 : 6); + if (pool_capacity < surface_num) + pool_capacity = surface_num; + gst_vaapi_video_pool_set_capacity(priv->surfaces_pool, pool_capacity); + + for (i = priv->surfaces->len; i < surface_num; i++) { + surface = gst_vaapi_surface_new( + GST_VAAPI_OBJECT_DISPLAY(context), + GST_VAAPI_CHROMA_TYPE_YUV420, + priv->width, priv->height + ); + if (!surface) + return FALSE; + g_ptr_array_add(priv->surfaces, surface); + if (!gst_vaapi_video_pool_add_object(priv->surfaces_pool, surface)) + return FALSE; + } + priv->surface_num = priv->surfaces->len; + return TRUE; +} + +static gboolean +gst_vaapi_context_create(GstVaapiContext *context) +{ + GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(context); + GstVaapiContextPrivate * const priv = context->priv; + VAProfile va_profile; + VAEntrypoint va_entrypoint; + guint va_rate_control; + VAConfigAttrib attribs[2]; + guint attribs_num; + VAContextID context_id; + VASurfaceID surface_id; + VAStatus status; + GArray *surfaces = NULL; + gboolean success = FALSE; + guint i; + + if (!priv->surfaces && !gst_vaapi_context_create_surfaces(context, priv->surface_num)) + goto end; + + surfaces = g_array_sized_new( + FALSE, + FALSE, + sizeof(VASurfaceID), + priv->surfaces->len + ); + if (!surfaces) + goto end; + + for (i = 0; i < priv->surfaces->len; i++) { + GstVaapiSurface * const surface = g_ptr_array_index(priv->surfaces, i); + if (!surface) + goto end; + surface_id = GST_VAAPI_OBJECT_ID(surface); + g_array_append_val(surfaces, surface_id); + } + assert(surfaces->len == priv->surfaces->len); + + if (!priv->profile || !priv->entrypoint) + goto end; + va_profile = gst_vaapi_profile_get_va_profile(priv->profile); + va_entrypoint = gst_vaapi_entrypoint_get_va_entrypoint(priv->entrypoint); + + GST_VAAPI_DISPLAY_LOCK(display); + attribs[0].type = VAConfigAttribRTFormat; + attribs[1].type = VAConfigAttribRateControl; + if (GST_VAAPI_ENTRYPOINT_SLICE_ENCODE == priv->entrypoint) + attribs_num = 2; + else + attribs_num = 1; + + status = vaGetConfigAttributes( + GST_VAAPI_DISPLAY_VADISPLAY(display), + va_profile, + va_entrypoint, + attribs, attribs_num + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaGetConfigAttributes()")) + goto end; + if (!(attribs[0].value & VA_RT_FORMAT_YUV420)) + goto end; + if (GST_VAAPI_ENTRYPOINT_SLICE_ENCODE == priv->entrypoint) { + va_rate_control = from_GstVaapiRateControl(priv->rate_control); + if (va_rate_control == VA_RC_NONE) + attribs[1].value = VA_RC_NONE; + if ((attribs[1].value & va_rate_control) != va_rate_control) { + GST_ERROR("encoder rate control:%s unsupported", + string_of_VARateControl(va_rate_control)); + goto end; + } + attribs[1].value = va_rate_control; + } + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaCreateConfig( + GST_VAAPI_DISPLAY_VADISPLAY(display), + va_profile, + va_entrypoint, + attribs, attribs_num, + &priv->config_id + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaCreateConfig()")) + goto end; + + VASurfaceID *surface_ids = (VASurfaceID*)surfaces->data; + int surface_num = surfaces->len; + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaCreateContext( + GST_VAAPI_DISPLAY_VADISPLAY(display), + priv->config_id, + priv->width, priv->height, + VA_PROGRESSIVE, + (VASurfaceID *)surface_ids, surface_num, + &context_id + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaCreateContext()")) + goto end; + + GST_DEBUG("context %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(context_id)); + GST_VAAPI_OBJECT_ID(context) = context_id; + success = TRUE; +end: + if (surfaces) + g_array_free(surfaces, TRUE); + return success; +} + +static void +gst_vaapi_context_finalize(GObject *object) +{ + GstVaapiContext * const context = GST_VAAPI_CONTEXT(object); + + gst_vaapi_context_destroy(context); + gst_vaapi_context_destroy_surfaces(context); + + G_OBJECT_CLASS(gst_vaapi_context_parent_class)->finalize(object); +} + +static void +gst_vaapi_context_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiContext * const context = GST_VAAPI_CONTEXT(object); + GstVaapiContextPrivate * const priv = context->priv; + + switch (prop_id) { + case PROP_PROFILE: + gst_vaapi_context_set_profile(context, g_value_get_uint(value)); + break; + case PROP_ENTRYPOINT: + priv->entrypoint = g_value_get_uint(value); + break; + case PROP_WIDTH: + priv->width = g_value_get_uint(value); + break; + case PROP_HEIGHT: + priv->height = g_value_get_uint(value); + break; + case PROP_SURFACE_NUM: + priv->surface_num = g_value_get_uint(value); + break; + case PROP_RATE_CONTROL: + priv->rate_control = g_value_get_uint(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_context_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiContext * const context = GST_VAAPI_CONTEXT(object); + GstVaapiContextPrivate * const priv = context->priv; + + switch (prop_id) { + case PROP_PROFILE: + g_value_set_uint(value, gst_vaapi_context_get_profile(context)); + break; + case PROP_ENTRYPOINT: + g_value_set_uint(value, gst_vaapi_context_get_entrypoint(context)); + break; + case PROP_WIDTH: + g_value_set_uint(value, priv->width); + break; + case PROP_HEIGHT: + g_value_set_uint(value, priv->height); + break; + case PROP_SURFACE_NUM: + g_value_set_uint(value, priv->surface_num); + break; + case PROP_RATE_CONTROL: + g_value_set_uint(value, priv->rate_control); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_context_class_init(GstVaapiContextClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiContextPrivate)); + + object_class->finalize = gst_vaapi_context_finalize; + object_class->set_property = gst_vaapi_context_set_property; + object_class->get_property = gst_vaapi_context_get_property; + + g_object_class_install_property + (object_class, + PROP_PROFILE, + g_param_spec_uint("profile", + "Profile", + "The profile used for decoding", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, + PROP_ENTRYPOINT, + g_param_spec_uint("entrypoint", + "Entrypoint", + "The decoder entrypoint", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, + PROP_WIDTH, + g_param_spec_uint("width", + "Width", + "The width of decoded surfaces", + 0, G_MAXINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, + PROP_HEIGHT, + g_param_spec_uint("height", + "Height", + "The height of the decoded surfaces", + 0, G_MAXINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, + PROP_SURFACE_NUM, + g_param_spec_uint("surface_num", + "Surface Number", + "The decoded surfaces number", + 0, G_MAXINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property + (object_class, + PROP_RATE_CONTROL, + g_param_spec_uint("rate-control", + "Bitrate Control", + "Bitrate Control", + 0, G_MAXINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gst_vaapi_context_init(GstVaapiContext *context) +{ + GstVaapiContextPrivate *priv = GST_VAAPI_CONTEXT_GET_PRIVATE(context); + + context->priv = priv; + priv->config_id = VA_INVALID_ID; + priv->surfaces = NULL; + priv->surfaces_pool = NULL; + priv->overlay = NULL; + priv->profile = 0; + priv->entrypoint = 0; + priv->rate_control = GST_VAAPI_RATECONTROL_NONE; + priv->width = 0; + priv->height = 0; + priv->surface_num = 0; +} + +/** + * gst_vaapi_context_new: + * @display: a #GstVaapiDisplay + * @profile: a #GstVaapiProfile + * @entrypoint: a #GstVaapiEntrypoint + * @width: coded width from the bitstream + * @height: coded height from the bitstream + * + * Creates a new #GstVaapiContext with the specified codec @profile + * and @entrypoint. + * + * Return value: the newly allocated #GstVaapiContext object + */ +GstVaapiContext * +gst_vaapi_context_new( + GstVaapiDisplay *display, + GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint, + GstVaapiRateControl rate_control, + unsigned int width, + unsigned int height, + unsigned int surface_num +) +{ + GstVaapiContext *context; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(profile, NULL); + g_return_val_if_fail(entrypoint, NULL); + g_return_val_if_fail(width > 0, NULL); + g_return_val_if_fail(height > 0, NULL); + + context = g_object_new( + GST_VAAPI_TYPE_CONTEXT, + "display", display, + "id", GST_VAAPI_ID(VA_INVALID_ID), + "profile", profile, + "entrypoint", entrypoint, + "rate-control", rate_control, + "width", width, + "height", height, + "surface_num", surface_num, + NULL + ); + if (!context->priv->is_constructed) { + g_object_unref(context); + return NULL; + } + return context; +} + +/** + * gst_vaapi_context_reset: + * @context: a #GstVaapiContext + * @profile: a #GstVaapiProfile + * @entrypoint: a #GstVaapiEntrypoint + * @width: coded width from the bitstream + * @height: coded height from the bitstream + * + * Resets @context to the specified codec @profile and @entrypoint. + * The surfaces will be reallocated if the coded size changed. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_context_reset( + GstVaapiContext *context, + GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint, + unsigned int width, + unsigned int height, + unsigned int surface_num +) +{ + GstVaapiContextPrivate * const priv = context->priv; + gboolean size_changed, codec_changed, surface_increased; + + size_changed = priv->width != width || priv->height != height; + if (size_changed) { + gst_vaapi_context_destroy_surfaces(context); + priv->width = width; + priv->height = height; + } + + codec_changed = priv->profile != profile || priv->entrypoint != entrypoint; + if (codec_changed) { + gst_vaapi_context_destroy(context); + priv->profile = profile; + priv->entrypoint = entrypoint; + } + + surface_increased = !size_changed && priv->surfaces && + (priv->surfaces->len < surface_num); + + if (size_changed && !gst_vaapi_context_create_surfaces(context, surface_num)) + return FALSE; + if (surface_increased && + !gst_vaapi_context_increase_surfaces(context, + surface_num - priv->surfaces->len)) + return FALSE; + + if (codec_changed && !gst_vaapi_context_create(context)) + return FALSE; + + priv->is_constructed = TRUE; + return TRUE; +} + +/** + * gst_vaapi_context_get_id: + * @context: a #GstVaapiContext + * + * Returns the underlying VAContextID of the @context. + * + * Return value: the underlying VA context id + */ +GstVaapiID +gst_vaapi_context_get_id(GstVaapiContext *context) +{ + g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), VA_INVALID_ID); + + return GST_VAAPI_OBJECT_ID(context); +} + +/** + * gst_vaapi_context_get_profile: + * @context: a #GstVaapiContext + * + * Returns the VA profile used by the @context. + * + * Return value: the VA profile used by the @context + */ +GstVaapiProfile +gst_vaapi_context_get_profile(GstVaapiContext *context) +{ + g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), 0); + + return context->priv->profile; +} + +/** + * gst_vaapi_context_set_profile: + * @context: a #GstVaapiContext + * @profile: the new #GstVaapiProfile to use + * + * Sets the new @profile to use with the @context. If @profile matches + * the previous profile, this call has no effect. Otherwise, the + * underlying VA context is recreated, while keeping the previously + * allocated surfaces. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_context_set_profile(GstVaapiContext *context, GstVaapiProfile profile) +{ + g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), FALSE); + g_return_val_if_fail(profile, FALSE); + + return gst_vaapi_context_reset(context, + profile, + context->priv->entrypoint, + context->priv->width, + context->priv->height, + context->priv->surface_num); +} + +/** + * gst_vaapi_context_get_entrypoint: + * @context: a #GstVaapiContext + * + * Returns the VA entrypoint used by the @context + * + * Return value: the VA entrypoint used by the @context + */ +GstVaapiEntrypoint +gst_vaapi_context_get_entrypoint(GstVaapiContext *context) +{ + g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), 0); + + return context->priv->entrypoint; +} + +/** + * gst_vaapi_context_get_size: + * @context: a #GstVaapiContext + * @pwidth: return location for the width, or %NULL + * @pheight: return location for the height, or %NULL + * + * Retrieves the size of the surfaces attached to @context. + */ +void +gst_vaapi_context_get_size( + GstVaapiContext *context, + guint *pwidth, + guint *pheight +) +{ + g_return_if_fail(GST_VAAPI_IS_CONTEXT(context)); + + if (pwidth) + *pwidth = context->priv->width; + + if (pheight) + *pheight = context->priv->height; +} + +/** + * gst_vaapi_context_get_surface: + * @context: a #GstVaapiContext + * + * Acquires a free surface. The returned surface but be released with + * gst_vaapi_context_put_surface(). This function returns %NULL if + * there is no free surface available in the pool. The surfaces are + * pre-allocated during context creation though. + * + * Return value: a free surface, or %NULL if none is available + */ +GstVaapiSurface * +gst_vaapi_context_get_surface(GstVaapiContext *context) +{ + GstVaapiSurface *surface; + + g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), NULL); + + surface = gst_vaapi_video_pool_get_object(context->priv->surfaces_pool); + if (!surface) + return NULL; + + gst_vaapi_surface_set_parent_context(surface, context); + return surface; +} + +/** + * gst_vaapi_context_get_surface_pool: + * @context: a #GstVaapiContext + * + * Reference the surface pool. The returned surface pool should be released with + * g_object_unref(). This function returns %NULL if + * there is the surface pool is empty. The surface pool is + * created during context creation though. + * + * Return value: surface pool, or %NULL if it is not created. + */ + +GstVaapiSurfacePool * +gst_vaapi_context_get_surface_pool(GstVaapiContext *context) +{ + g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), NULL); + return (GstVaapiSurfacePool*)g_object_ref(context->priv->surfaces_pool); +} + + +/** + * gst_vaapi_context_get_surface_count: + * @context: a #GstVaapiContext + * + * Retrieves the number of free surfaces left in the pool. + * + * Return value: the number of free surfaces available in the pool + */ +guint +gst_vaapi_context_get_surface_count(GstVaapiContext *context) +{ + g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), 0); + + return gst_vaapi_video_pool_get_size(context->priv->surfaces_pool); +} + +/** + * gst_vaapi_context_get_surface_left_capability: + * @context: a #GstVaapiContext + * + * Retrieves the number of unallocated surfaces left in the pool. + * + * Return value: the number of unallocated surfaces in the pool + */ + +guint +gst_vaapi_context_get_surface_left_capability(GstVaapiContext *context) +{ + GstVaapiContextPrivate * const priv = context->priv; + + g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), 0); + g_return_val_if_fail(priv->surfaces, 0); + + return (gst_vaapi_video_pool_get_capacity(priv->surfaces_pool) - + priv->surfaces->len); +} + +/** + * gst_vaapi_context_put_surface: + * @context: a #GstVaapiContext + * @surface: the #GstVaapiSurface to release + * + * Releases a surface acquired by gst_vaapi_context_get_surface(). + */ +void +gst_vaapi_context_put_surface(GstVaapiContext *context, GstVaapiSurface *surface) +{ + g_return_if_fail(GST_VAAPI_IS_CONTEXT(context)); + g_return_if_fail(GST_VAAPI_IS_SURFACE(surface)); + + gst_vaapi_surface_set_parent_context(surface, NULL); + gst_vaapi_video_pool_put_object(context->priv->surfaces_pool, surface); +} + +/** + * gst_vaapi_context_find_surface_by_id: + * @context: a #GstVaapiContext + * @id: the VA surface id to find + * + * Finds VA surface by @id in the list of surfaces attached to the @context. + * + * Return value: the matching #GstVaapiSurface object, or %NULL if + * none was found + */ +GstVaapiSurface * +gst_vaapi_context_find_surface_by_id(GstVaapiContext *context, GstVaapiID id) +{ + GstVaapiContextPrivate *priv; + GstVaapiSurface *surface; + guint i; + + g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), NULL); + + priv = context->priv; + g_return_val_if_fail(priv->surfaces, NULL); + + for (i = 0; i < priv->surfaces->len; i++) { + surface = g_ptr_array_index(priv->surfaces, i); + if (GST_VAAPI_OBJECT_ID(surface) == id) + return surface; + } + return NULL; +} + +/* Check if composition changed */ +static gboolean +gst_vaapi_context_composition_changed( + GstVaapiContext *context, + GstVideoOverlayComposition *composition +) +{ + GstVaapiContextPrivate * const priv = context->priv; + GstVaapiOverlayRectangle *overlay; + GstVideoOverlayRectangle *rect; + guint i, n_rectangles; + + if (!priv->overlay || !composition) + return TRUE; + + n_rectangles = gst_video_overlay_composition_n_rectangles(composition); + if (priv->overlay->len != n_rectangles) + return TRUE; + + for (i = 0; i < n_rectangles; i++) { + rect = gst_video_overlay_composition_get_rectangle(composition, i); + g_return_val_if_fail(rect, TRUE); + overlay = g_ptr_array_index(priv->overlay, i); + g_return_val_if_fail(overlay, TRUE); + if (overlay->seq_num != gst_video_overlay_rectangle_get_seqnum(rect)) + return TRUE; + } + return FALSE; +} + +/** + * gst_vaapi_context_apply_composition: + * @context: a #GstVaapiContext + * @composition: a #GstVideoOverlayComposition + * + * Applies video composition planes to all surfaces bound to @context. + * This helper function resets any additional subpictures the user may + * have associated himself. A %NULL @composition will also clear all + * the existing subpictures. + * + * Return value: %TRUE if all composition planes could be applied, + * %FALSE otherwise + */ +gboolean +gst_vaapi_context_apply_composition( + GstVaapiContext *context, + GstVideoOverlayComposition *composition +) +{ + GstVaapiContextPrivate *priv; + GstVideoOverlayRectangle *rect; + GstVaapiOverlayRectangle *overlay = NULL; + GstVaapiDisplay *display; + guint i, j, n_rectangles; + + g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), FALSE); + + priv = context->priv; + if (!priv->surfaces) + return FALSE; + + display = GST_VAAPI_OBJECT_DISPLAY(context); + if (!display) + return FALSE; + + if (!gst_vaapi_context_composition_changed(context, composition)) + return TRUE; + gst_vaapi_context_destroy_overlay(context); + + if (!composition) + return TRUE; + if (!gst_vaapi_context_create_overlay(context)) + return FALSE; + + n_rectangles = gst_video_overlay_composition_n_rectangles(composition); + for (i = 0; i < n_rectangles; i++) { + rect = gst_video_overlay_composition_get_rectangle(composition, i); + + overlay = overlay_rectangle_new(context); + if (!overlay) { + GST_WARNING("could not create VA overlay rectangle"); + return FALSE; + } + overlay->seq_num = gst_video_overlay_rectangle_get_seqnum(rect); + + overlay->subpicture = gst_vaapi_subpicture_new_from_overlay_rectangle( + display, + rect + ); + if (!overlay->subpicture) { + overlay_rectangle_destroy(overlay); + return FALSE; + } + + gst_video_overlay_rectangle_get_render_rectangle( + rect, + (gint *)&overlay->rect.x, + (gint *)&overlay->rect.y, + &overlay->rect.width, + &overlay->rect.height + ); + + for (j = 0; j < priv->surfaces->len; j++) { + GstVaapiSurface * const surface = + g_ptr_array_index(priv->surfaces, j); + if (!gst_vaapi_surface_associate_subpicture(surface, + overlay->subpicture, NULL, &overlay->rect)) { + GST_WARNING("could not render overlay rectangle %p", rect); + overlay_rectangle_destroy(overlay); + return FALSE; + } + } + g_ptr_array_add(priv->overlay, overlay); + } + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapicontext.h b/gst-libs/gst/vaapi/gstvaapicontext.h new file mode 100644 index 0000000..14b5e27 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicontext.h @@ -0,0 +1,155 @@ +/* + * gstvaapicontext.h - VA context abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_CONTEXT_H +#define GST_VAAPI_CONTEXT_H + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_CONTEXT \ + (gst_vaapi_context_get_type()) + +#define GST_VAAPI_CONTEXT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_CONTEXT, \ + GstVaapiContext)) + +#define GST_VAAPI_CONTEXT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_CONTEXT, \ + GstVaapiContextClass)) + +#define GST_VAAPI_IS_CONTEXT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_CONTEXT)) + +#define GST_VAAPI_IS_CONTEXT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_CONTEXT)) + +#define GST_VAAPI_CONTEXT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_CONTEXT, \ + GstVaapiContextClass)) + +typedef struct _GstVaapiContext GstVaapiContext; +typedef struct _GstVaapiContextPrivate GstVaapiContextPrivate; +typedef struct _GstVaapiContextClass GstVaapiContextClass; + +/** + * GstVaapiContext: + * + * A VA context wrapper. + */ +struct _GstVaapiContext { + /*< private >*/ + GstVaapiObject parent_instance; + + GstVaapiContextPrivate *priv; +}; + +/** + * GstVaapiContextClass: + * + * A VA context wrapper class. + */ +struct _GstVaapiContextClass { + /*< private >*/ + GstVaapiObjectClass parent_class; +}; + +GType +gst_vaapi_context_get_type(void) G_GNUC_CONST; + +GstVaapiContext * +gst_vaapi_context_new( + GstVaapiDisplay *display, + GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint, + GstVaapiRateControl rate_control, + guint width, + guint height, + guint surface_num +); + +gboolean +gst_vaapi_context_reset( + GstVaapiContext *context, + GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint, + unsigned int width, + unsigned int height, + unsigned int surface_num +); + +GstVaapiID +gst_vaapi_context_get_id(GstVaapiContext *context); + +GstVaapiProfile +gst_vaapi_context_get_profile(GstVaapiContext *context); + +gboolean +gst_vaapi_context_set_profile(GstVaapiContext *context, GstVaapiProfile profile); + +GstVaapiEntrypoint +gst_vaapi_context_get_entrypoint(GstVaapiContext *context); + +void +gst_vaapi_context_get_size( + GstVaapiContext *context, + guint *pwidth, + guint *pheight +); + +GstVaapiSurface * +gst_vaapi_context_get_surface(GstVaapiContext *context); + +GstVaapiSurfacePool * +gst_vaapi_context_get_surface_pool(GstVaapiContext *context); + + +guint +gst_vaapi_context_get_surface_count(GstVaapiContext *context); + +guint +gst_vaapi_context_get_surface_left_capability(GstVaapiContext *context); + +void +gst_vaapi_context_put_surface(GstVaapiContext *context, GstVaapiSurface *surface); + +GstVaapiSurface * +gst_vaapi_context_find_surface_by_id(GstVaapiContext *context, GstVaapiID id); + +gboolean +gst_vaapi_context_apply_composition( + GstVaapiContext *context, + GstVideoOverlayComposition *composition +); + +G_END_DECLS + +#endif /* GST_VAAPI_CONTEXT_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidebug.h b/gst-libs/gst/vaapi/gstvaapidebug.h new file mode 100644 index 0000000..efcafaa --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidebug.h @@ -0,0 +1,64 @@ +/* + * gstvaapidebug.h - VA-API debugging utilities + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DEBUG_H +#define GST_VAAPI_DEBUG_H + +#include +#include +#include +#include +#include + +#if DEBUG +GST_DEBUG_CATEGORY_EXTERN(gst_debug_vaapi); +#define GST_CAT_DEFAULT gst_debug_vaapi +#endif +/* FPS Calculation for DEBUG */ +#define FPS_CALCULATION(objname) \ + do{ \ + static guint num_frame = 0; \ + static struct timeval last_sys_time; \ + static struct timeval first_sys_time; \ + static int b_last_sys_time_init = FALSE; \ + if (!b_last_sys_time_init) { \ + gettimeofday (&last_sys_time, NULL); \ + gettimeofday (&first_sys_time, NULL); \ + b_last_sys_time_init = TRUE; \ + } else { \ + if ((num_frame%50)==0) { \ + double total, current; \ + struct timeval cur_sys_time; \ + gettimeofday (&cur_sys_time, NULL); \ + total = (cur_sys_time.tv_sec - first_sys_time.tv_sec)*1.0f + \ + (cur_sys_time.tv_usec - first_sys_time.tv_usec)/1000000.0f; \ + current = (cur_sys_time.tv_sec - last_sys_time.tv_sec)*1.0f + \ + (cur_sys_time.tv_usec - last_sys_time.tv_usec)/1000000.0f; \ + printf("%s Current fps: %.2f, Total avg fps: %.2f\n", \ + #objname, (float)50.0f/current, (float)num_frame/total); \ + last_sys_time = cur_sys_time; \ + } \ + } \ + ++num_frame; \ + }while(0) + + +#endif /* GST_VAAPI_DEBUG_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder.c b/gst-libs/gst/vaapi/gstvaapidecoder.c new file mode 100644 index 0000000..041967c --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder.c @@ -0,0 +1,670 @@ +/* + * gstvaapidecoder.c - VA decoder abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidecoder + * @short_description: VA decoder abstraction + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapidecoder.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapiutils.h" +#include "gstvaapi_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDecoder, gst_vaapi_decoder, G_TYPE_OBJECT); + +enum { + PROP_0, + + PROP_DISPLAY, + PROP_CAPS, + + N_PROPERTIES +}; + +static GParamSpec *g_properties[N_PROPERTIES] = { NULL, }; + +static void +destroy_buffer(GstBuffer *buffer) +{ + gst_buffer_unref(buffer); +} + +static gboolean +push_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + + if (!buffer) { + buffer = gst_buffer_new(); + if (!buffer) + return FALSE; + GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_EOS); + } + + GST_DEBUG("queue encoded data buffer %p (%d bytes)", + buffer, GST_BUFFER_SIZE(buffer)); + + g_queue_push_tail(priv->buffers, buffer); + return TRUE; +} + +static void +push_back_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + + GST_DEBUG("requeue encoded data buffer %p (%d bytes)", + buffer, GST_BUFFER_SIZE(buffer)); + + g_queue_push_head(priv->buffers, buffer); +} + +static GstBuffer * +pop_buffer(GstVaapiDecoder *decoder) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + GstBuffer *buffer; + + buffer = g_queue_pop_head(priv->buffers); + if (!buffer) + return NULL; + + GST_DEBUG("dequeue buffer %p for decoding (%d bytes)", + buffer, GST_BUFFER_SIZE(buffer)); + + return buffer; +} + +static GstVaapiDecoderStatus +decode_step(GstVaapiDecoder *decoder) +{ + GstVaapiDecoderStatus status; + GstBuffer *buffer; + + /* Decoding will fail if there is no surface left */ + status = gst_vaapi_decoder_check_status(decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + do { + buffer = pop_buffer(decoder); + if (!buffer) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + status = GST_VAAPI_DECODER_GET_CLASS(decoder)->decode(decoder, buffer); + GST_DEBUG("decode frame (status = %d)", status); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS && GST_BUFFER_IS_EOS(buffer)) + status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM; + gst_buffer_unref(buffer); + } while (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA); + return status; +} + +static inline void +push_surface(GstVaapiDecoder *decoder, GstVaapiSurfaceProxy *proxy) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + + GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS(gst_vaapi_surface_proxy_get_surface_id(proxy))); + + g_queue_push_tail(priv->surfaces, proxy); +} + +static inline GstVaapiSurfaceProxy * +pop_surface(GstVaapiDecoder *decoder) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + + return g_queue_pop_head(priv->surfaces); +} + +static inline void +set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + + if (priv->codec_data) { + gst_buffer_unref(priv->codec_data); + priv->codec_data = NULL; + } + + if (codec_data) + priv->codec_data = gst_buffer_ref(codec_data); +} + +static void +set_caps(GstVaapiDecoder *decoder, GstCaps *caps) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + GstStructure * const structure = gst_caps_get_structure(caps, 0); + GstVaapiProfile profile; + const GValue *v_codec_data; + gint v1, v2; + gboolean b; + + profile = gst_vaapi_profile_from_caps(caps); + if (!profile) + return; + + priv->caps = gst_caps_copy(caps); + + priv->codec = gst_vaapi_profile_get_codec(profile); + if (!priv->codec) + return; + + if (gst_structure_get_int(structure, "width", &v1)) + priv->width = v1; + if (gst_structure_get_int(structure, "height", &v2)) + priv->height = v2; + + if (gst_structure_get_fraction(structure, "framerate", &v1, &v2)) { + priv->fps_n = v1; + priv->fps_d = v2; + } + + if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &v1, &v2)) { + priv->par_n = v1; + priv->par_d = v2; + } + + if (gst_structure_get_boolean(structure, "interlaced", &b)) + priv->is_interlaced = b; + + v_codec_data = gst_structure_get_value(structure, "codec_data"); + if (v_codec_data) + set_codec_data(decoder, gst_value_get_buffer(v_codec_data)); +} + +static void +clear_queue(GQueue *q, GDestroyNotify destroy) +{ + while (!g_queue_is_empty(q)) + destroy(g_queue_pop_head(q)); +} + +static void +gst_vaapi_decoder_finalize(GObject *object) +{ + GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(object); + GstVaapiDecoderPrivate * const priv = decoder->priv; + + set_codec_data(decoder, NULL); + + if (priv->caps) { + gst_caps_unref(priv->caps); + priv->caps = NULL; + } + + if (priv->context) { + g_object_unref(priv->context); + priv->context = NULL; + priv->va_context = VA_INVALID_ID; + } + + if (priv->buffers) { + clear_queue(priv->buffers, (GDestroyNotify)destroy_buffer); + g_queue_free(priv->buffers); + priv->buffers = NULL; + } + + if (priv->surfaces) { + clear_queue(priv->surfaces, (GDestroyNotify)g_object_unref); + g_queue_free(priv->surfaces); + priv->surfaces = NULL; + } + + if (priv->display) { + g_object_unref(priv->display); + priv->display = NULL; + priv->va_display = NULL; + } + + G_OBJECT_CLASS(gst_vaapi_decoder_parent_class)->finalize(object); +} + +static void +gst_vaapi_decoder_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(object); + GstVaapiDecoderPrivate * const priv = decoder->priv; + + switch (prop_id) { + case PROP_DISPLAY: + priv->display = g_object_ref(g_value_get_object(value)); + if (priv->display) + priv->va_display = gst_vaapi_display_get_display(priv->display); + else + priv->va_display = NULL; + break; + case PROP_CAPS: + set_caps(decoder, g_value_get_pointer(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_decoder_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDecoderPrivate * const priv = GST_VAAPI_DECODER(object)->priv; + + switch (prop_id) { + case PROP_DISPLAY: + g_value_set_object(value, priv->display); + break; + case PROP_CAPS: + gst_value_set_caps(value, priv->caps); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_decoder_class_init(GstVaapiDecoderClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiDecoderPrivate)); + + object_class->finalize = gst_vaapi_decoder_finalize; + object_class->set_property = gst_vaapi_decoder_set_property; + object_class->get_property = gst_vaapi_decoder_get_property; + + /** + * GstVaapiDecoder:display: + * + * The #GstVaapiDisplay this decoder is bound to. + */ + g_properties[PROP_DISPLAY] = + g_param_spec_object("display", + "Display", + "The GstVaapiDisplay this decoder is bound to", + GST_VAAPI_TYPE_DISPLAY, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY); + + g_properties[PROP_CAPS] = + g_param_spec_pointer("caps", + "Decoder caps", + "The decoder caps", + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties(object_class, N_PROPERTIES, g_properties); +} + +static void +gst_vaapi_decoder_init(GstVaapiDecoder *decoder) +{ + GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder); + + decoder->priv = priv; + priv->display = NULL; + priv->va_display = NULL; + priv->context = NULL; + priv->va_context = VA_INVALID_ID; + priv->caps = NULL; + priv->codec = 0; + priv->codec_data = NULL; + priv->width = 0; + priv->height = 0; + priv->fps_n = 0; + priv->fps_d = 0; + priv->par_n = 0; + priv->par_d = 0; + priv->buffers = g_queue_new(); + priv->surfaces = g_queue_new(); + priv->is_interlaced = FALSE; +} + +/** + * gst_vaapi_decoder_get_caps: + * @decoder: a #GstVaapiDecoder + * + * Retrieves the @decoder caps. The deocder owns the returned caps, so + * use gst_caps_ref() whenever necessary. + * + * Return value: the @decoder caps + */ +GstCaps * +gst_vaapi_decoder_get_caps(GstVaapiDecoder *decoder) +{ + return decoder->priv->caps; +} + +/** + * gst_vaapi_decoder_put_buffer: + * @decoder: a #GstVaapiDecoder + * @buf: a #GstBuffer + * + * Queues a #GstBuffer to the HW decoder. The decoder holds a + * reference to @buf. + * + * Caller can notify an End-Of-Stream with @buf set to %NULL. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf) +{ + g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE); + + return push_buffer(decoder, buf ? gst_buffer_ref(buf) : NULL); +} + +/** + * gst_vaapi_decoder_get_surface: + * @decoder: a #GstVaapiDecoder + * @pstatus: return location for the decoder status, or %NULL + * + * Flushes encoded buffers to the decoder and returns a decoded + * surface, if any. + * + * Return value: a #GstVaapiSurfaceProxy holding the decoded surface, + * or %NULL if none is available (e.g. an error). Caller owns the + * returned object. g_object_unref() after usage. + */ +GstVaapiSurfaceProxy * +gst_vaapi_decoder_get_surface( + GstVaapiDecoder *decoder, + GstVaapiDecoderStatus *pstatus +) +{ + GstVaapiSurfaceProxy *proxy; + GstVaapiDecoderStatus status; + + if (pstatus) + *pstatus = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL); + + proxy = pop_surface(decoder); + if (!proxy) { + do { + status = decode_step(decoder); + } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS); + proxy = pop_surface(decoder); + } + + if (proxy) + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (pstatus) + *pstatus = status; + return proxy; +} + +void +gst_vaapi_decoder_clear_buffer(GstVaapiDecoder *decoder) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder); + + if (klass->clear_buffer) + klass->clear_buffer(decoder); + + if (priv->buffers) + clear_queue(priv->buffers, (GDestroyNotify)destroy_buffer); + + if (priv->surfaces) + clear_queue(priv->surfaces, (GDestroyNotify)g_object_unref); +} + +void +gst_vaapi_decoder_set_picture_size( + GstVaapiDecoder *decoder, + guint width, + guint height +) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + gboolean size_changed = FALSE; + + if (priv->width != width) { + GST_DEBUG("picture width changed to %d", width); + priv->width = width; + gst_caps_set_simple(priv->caps, "width", G_TYPE_INT, width, NULL); + size_changed = TRUE; + } + + if (priv->height != height) { + GST_DEBUG("picture height changed to %d", height); + priv->height = height; + gst_caps_set_simple(priv->caps, "height", G_TYPE_INT, height, NULL); + size_changed = TRUE; + } + + if (size_changed) + g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]); +} + +void +gst_vaapi_decoder_set_framerate( + GstVaapiDecoder *decoder, + guint fps_n, + guint fps_d +) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + + if (!fps_n || !fps_d) + return; + + if (priv->fps_n != fps_n || priv->fps_d != fps_d) { + GST_DEBUG("framerate changed to %u/%u", fps_n, fps_d); + priv->fps_n = fps_n; + priv->fps_d = fps_d; + gst_caps_set_simple( + priv->caps, + "framerate", GST_TYPE_FRACTION, fps_n, fps_d, + NULL + ); + g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]); + } +} + +void +gst_vaapi_decoder_set_pixel_aspect_ratio( + GstVaapiDecoder *decoder, + guint par_n, + guint par_d +) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + + if (!par_n || !par_d) + return; + + if (priv->par_n != par_n || priv->par_d != par_d) { + GST_DEBUG("pixel-aspect-ratio changed to %u/%u", par_n, par_d); + priv->par_n = par_n; + priv->par_d = par_d; + gst_caps_set_simple( + priv->caps, + "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d, + NULL + ); + g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]); + } +} + +void +gst_vaapi_decoder_set_interlaced(GstVaapiDecoder *decoder, gboolean interlaced) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + + if (priv->is_interlaced != interlaced) { + GST_DEBUG("interlaced changed to %s", interlaced ? "true" : "false"); + priv->is_interlaced = interlaced; + gst_caps_set_simple( + priv->caps, + "interlaced", G_TYPE_BOOLEAN, interlaced, + NULL + ); + g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]); + } +} + +gboolean +gst_vaapi_decoder_ensure_context( + GstVaapiDecoder *decoder, + GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint, + guint width, + guint height, + guint surface_num +) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + gboolean ret = TRUE; + + gst_vaapi_decoder_set_picture_size(decoder, width, height); + + if (priv->context) { + ret = gst_vaapi_context_reset(priv->context, + profile, entrypoint, + width, height, + surface_num); + goto end; + } + + priv->context = gst_vaapi_context_new( + priv->display, + profile, + entrypoint, + GST_VAAPI_RATECONTROL_NONE, + width, + height, + surface_num + ); + if (!priv->context) + return FALSE; +end: + priv->va_context = gst_vaapi_context_get_id(priv->context); + return ret; +} + +gboolean +gst_vaapi_decoder_push_buffer_sub( + GstVaapiDecoder *decoder, + GstBuffer *buffer, + guint offset, + guint size +) +{ + GstBuffer *subbuffer; + + subbuffer = gst_buffer_create_sub(buffer, offset, size); + if (!subbuffer) + return FALSE; + + push_back_buffer(decoder, subbuffer); + return TRUE; +} + +void +gst_vaapi_decoder_push_surface_proxy( + GstVaapiDecoder *decoder, + GstVaapiSurfaceProxy *proxy +) +{ + return push_surface(decoder, proxy); +} + +static gboolean +gst_vaapi_decoder_context_increase_surfaces( + GstVaapiDecoder *decoder, + guint increment +) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + guint profile, entrypoint; + guint width, height; + guint surface_num; + gboolean ret = TRUE; + + if (!increment) + return TRUE; + + if (!priv->context || + (gst_vaapi_context_get_surface_left_capability(priv->context) < increment)) + return FALSE; + g_object_get(G_OBJECT(priv->context), + "profile", &profile, + "entrypoint", &entrypoint, + "width", &width, + "height", &height, + "surface_num", &surface_num, + NULL); + surface_num += increment; + ret = gst_vaapi_context_reset(priv->context, + (GstVaapiProfile)profile, + (GstVaapiEntrypoint)entrypoint, + width, + height, + surface_num); + priv->va_context = gst_vaapi_context_get_id(priv->context); + return ret; +} + +GstVaapiDecoderStatus +gst_vaapi_decoder_check_status(GstVaapiDecoder *decoder) +{ + GstVaapiDecoderPrivate * const priv = decoder->priv; + guint increment; + + if (!priv->context || gst_vaapi_context_get_surface_count(priv->context) > 0) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + increment = gst_vaapi_context_get_surface_left_capability(priv->context); + if (increment < 1) { + GST_DEBUG("decoder context surface pool is out of capability"); + return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE; + } + if (increment > 2) + increment = 2; + + if (!gst_vaapi_decoder_context_increase_surfaces(decoder, increment)) { + GST_ERROR("increase decoder surface failed"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder.h b/gst-libs/gst/vaapi/gstvaapidecoder.h new file mode 100644 index 0000000..6858e4b --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder.h @@ -0,0 +1,138 @@ +/* + * gstvaapidecoder.h - VA decoder abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_H +#define GST_VAAPI_DECODER_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DECODER \ + (gst_vaapi_decoder_get_type()) + +#define GST_VAAPI_DECODER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DECODER, \ + GstVaapiDecoder)) + +#define GST_VAAPI_DECODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DECODER, \ + GstVaapiDecoderClass)) + +#define GST_VAAPI_IS_DECODER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DECODER)) + +#define GST_VAAPI_IS_DECODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DECODER)) + +#define GST_VAAPI_DECODER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DECODER, \ + GstVaapiDecoderClass)) + +typedef enum _GstVaapiDecoderStatus GstVaapiDecoderStatus; +typedef struct _GstVaapiDecoder GstVaapiDecoder; +typedef struct _GstVaapiDecoderPrivate GstVaapiDecoderPrivate; +typedef struct _GstVaapiDecoderClass GstVaapiDecoderClass; + +/** + * GstVaapiDecoderStatus: + * @GST_VAAPI_DECODER_STATUS_SUCCESS: Success. + * @GST_VAAPI_DECODER_STATUS_END_OF_STREAM: End-Of-Stream. + * @GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED: No memory left. + * @GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED: Decoder initialization failure. + * @GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC: Unsupported codec. + * @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA: Not enough input data to decode. + * @GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE: No surface left to hold the decoded picture. + * @GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE: Invalid surface. + * @GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER: Invalid or unsupported bitstream data. + * @GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE: Unsupported codec profile. + * @GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT: Unsupported chroma format. + * @GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN: Unknown error. + * + * Decoder status for gst_vaapi_decoder_get_surface(). + */ +enum _GstVaapiDecoderStatus { + GST_VAAPI_DECODER_STATUS_SUCCESS = 0, + GST_VAAPI_DECODER_STATUS_END_OF_STREAM, + GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED, + GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED, + GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC, + GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA, + GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE, + GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE, + GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER, + GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE, + GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT, + GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN = -1 +}; + +/** + * GstVaapiDecoder: + * + * A VA decoder base instance. + */ +struct _GstVaapiDecoder { + /*< private >*/ + GObject parent_instance; + + GstVaapiDecoderPrivate *priv; +}; + +/** + * GstVaapiDecoderClass: + * + * A VA decoder base class. + */ +struct _GstVaapiDecoderClass { + /*< private >*/ + GObjectClass parent_class; + + GstVaapiDecoderStatus (*decode)(GstVaapiDecoder *decoder, GstBuffer *buffer); + void (*clear_buffer)(GstVaapiDecoder *decoder); +}; + +GType +gst_vaapi_decoder_get_type(void) G_GNUC_CONST; + +GstCaps * +gst_vaapi_decoder_get_caps(GstVaapiDecoder *decoder); + +gboolean +gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf); + +GstVaapiSurfaceProxy * +gst_vaapi_decoder_get_surface( + GstVaapiDecoder *decoder, + GstVaapiDecoderStatus *pstatus +); + +void +gst_vaapi_decoder_clear_buffer(GstVaapiDecoder *decoder); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_dpb.c b/gst-libs/gst/vaapi/gstvaapidecoder_dpb.c new file mode 100644 index 0000000..c5a5a76 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_dpb.c @@ -0,0 +1,340 @@ +/* + * gstvaapidecoder_dpb.c - Decoded Picture Buffer + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapidecoder_dpb.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/* ------------------------------------------------------------------------- */ +/* --- Common Decoded Picture Buffer utilities --- */ +/* ------------------------------------------------------------------------- */ + +static GstVaapiDpb * +dpb_new(GType type, guint max_pictures) +{ + GstMiniObject *obj; + GstVaapiDpb *dpb; + + g_return_val_if_fail(max_pictures > 0, NULL); + + obj = gst_mini_object_new(type); + if (!obj) + return NULL; + + dpb = GST_VAAPI_DPB_CAST(obj); + dpb->pictures = g_new0(GstVaapiPicture *, max_pictures); + if (!dpb->pictures) + goto error; + dpb->max_pictures = max_pictures; + return dpb; + +error: + gst_mini_object_unref(obj); + return NULL; +} + +static gint +dpb_get_oldest(GstVaapiDpb *dpb, gboolean output) +{ + gint i, lowest_pts_index; + + for (i = 0; i < dpb->num_pictures; i++) { + if ((GST_VAAPI_PICTURE_IS_OUTPUT(dpb->pictures[i]) ^ output) == 0) + break; + } + if (i == dpb->num_pictures) + return -1; + + lowest_pts_index = i++; + for (; i < dpb->num_pictures; i++) { + GstVaapiPicture * const picture = dpb->pictures[i]; + if ((GST_VAAPI_PICTURE_IS_OUTPUT(picture) ^ output) != 0) + continue; + if (picture->poc < dpb->pictures[lowest_pts_index]->poc) + lowest_pts_index = i; + } + return lowest_pts_index; +} + +static void +dpb_remove_index(GstVaapiDpb *dpb, guint index) +{ + GstVaapiPicture ** const pictures = dpb->pictures; + guint num_pictures = --dpb->num_pictures; + + if (index != num_pictures) + gst_vaapi_picture_replace(&pictures[index], pictures[num_pictures]); + gst_vaapi_picture_replace(&pictures[num_pictures], NULL); +} + +static inline gboolean +dpb_output(GstVaapiDpb *dpb, GstVaapiPicture *picture) +{ + return gst_vaapi_picture_output(picture); +} + +static gboolean +dpb_bump(GstVaapiDpb *dpb) +{ + gint index; + gboolean success; + + index = dpb_get_oldest(dpb, FALSE); + if (index < 0) + return FALSE; + + success = dpb_output(dpb, dpb->pictures[index]); + if (!GST_VAAPI_PICTURE_IS_REFERENCE(dpb->pictures[index])) + dpb_remove_index(dpb, index); + return success; +} + +static void +dpb_clear(GstVaapiDpb *dpb) +{ + guint i; + + for (i = 0; i < dpb->num_pictures; i++) + gst_vaapi_picture_replace(&dpb->pictures[i], NULL); + dpb->num_pictures = 0; +} + +/* ------------------------------------------------------------------------- */ +/* --- Base Decoded Picture Buffer --- */ +/* ------------------------------------------------------------------------- */ + +G_DEFINE_TYPE(GstVaapiDpb, gst_vaapi_dpb, GST_TYPE_MINI_OBJECT) + +static void +gst_vaapi_dpb_base_flush(GstVaapiDpb *dpb) +{ + while (dpb_bump(dpb)) + ; + dpb_clear(dpb); +} + +static gboolean +gst_vaapi_dpb_base_add(GstVaapiDpb *dpb, GstVaapiPicture *picture) +{ + guint i; + + // Remove all unused pictures + i = 0; + while (i < dpb->num_pictures) { + GstVaapiPicture * const picture = dpb->pictures[i]; + if (GST_VAAPI_PICTURE_IS_OUTPUT(picture) && + !GST_VAAPI_PICTURE_IS_REFERENCE(picture)) + dpb_remove_index(dpb, i); + else + i++; + } + + // Store reference decoded picture into the DPB + if (GST_VAAPI_PICTURE_IS_REFERENCE(picture)) { + while (dpb->num_pictures == dpb->max_pictures) { + if (!dpb_bump(dpb)) + return FALSE; + } + } + + // Store non-reference decoded picture into the DPB + else { + if (GST_VAAPI_PICTURE_IS_SKIPPED(picture)) + return TRUE; + while (dpb->num_pictures == dpb->max_pictures) { + for (i = 0; i < dpb->num_pictures; i++) { + if (!GST_VAAPI_PICTURE_IS_OUTPUT(picture) && + dpb->pictures[i]->poc < picture->poc) + break; + } + if (i == dpb->num_pictures) + return dpb_output(dpb, picture); + if (!dpb_bump(dpb)) + return FALSE; + } + } + gst_vaapi_picture_replace(&dpb->pictures[dpb->num_pictures++], picture); + return TRUE; +} + +static void +gst_vaapi_dpb_finalize(GstMiniObject *object) +{ + GstVaapiDpb * const dpb = GST_VAAPI_DPB_CAST(object); + GstMiniObjectClass *parent_class; + + if (dpb->pictures) { + dpb_clear(dpb); + g_free(dpb->pictures); + } + + parent_class = GST_MINI_OBJECT_CLASS(gst_vaapi_dpb_parent_class); + if (parent_class->finalize) + parent_class->finalize(object); +} + +static void +gst_vaapi_dpb_init(GstVaapiDpb *dpb) +{ + dpb->pictures = NULL; + dpb->num_pictures = 0; + dpb->max_pictures = 0; +} + +static void +gst_vaapi_dpb_class_init(GstVaapiDpbClass *klass) +{ + GstMiniObjectClass * const object_class = GST_MINI_OBJECT_CLASS(klass); + + object_class->finalize = gst_vaapi_dpb_finalize; + klass->flush = gst_vaapi_dpb_base_flush; + klass->add = gst_vaapi_dpb_base_add; +} + +void +gst_vaapi_dpb_flush(GstVaapiDpb *dpb) +{ + GstVaapiDpbClass *klass; + + g_return_if_fail(GST_VAAPI_IS_DPB(dpb)); + + klass = GST_VAAPI_DPB_GET_CLASS(dpb); + if (G_UNLIKELY(!klass || !klass->add)) + return; + klass->flush(dpb); +} + +gboolean +gst_vaapi_dpb_add(GstVaapiDpb *dpb, GstVaapiPicture *picture) +{ + GstVaapiDpbClass *klass; + + g_return_val_if_fail(GST_VAAPI_IS_DPB(dpb), FALSE); + g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE); + + klass = GST_VAAPI_DPB_GET_CLASS(dpb); + if (G_UNLIKELY(!klass || !klass->add)) + return FALSE; + return klass->add(dpb, picture); +} + +guint +gst_vaapi_dpb_size(GstVaapiDpb *dpb) +{ + g_return_val_if_fail(GST_VAAPI_IS_DPB(dpb), 0); + + return dpb->num_pictures; +} + +/* ------------------------------------------------------------------------- */ +/* --- MPEG-2 Decoded Picture Buffer --- */ +/* ------------------------------------------------------------------------- */ + +/* At most two reference pictures for MPEG-2 */ +#define MAX_MPEG2_REFERENCES 2 + +G_DEFINE_TYPE(GstVaapiDpbMpeg2, gst_vaapi_dpb_mpeg2, GST_VAAPI_TYPE_DPB) + +static gboolean +gst_vaapi_dpb_mpeg2_add(GstVaapiDpb *dpb, GstVaapiPicture *picture) +{ + GstVaapiPicture *ref_picture; + gint index = -1; + + g_return_val_if_fail(GST_VAAPI_IS_DPB_MPEG2(dpb), FALSE); + + /* + * Purpose: only store reference decoded pictures into the DPB + * + * This means: + * - non-reference decoded pictures are output immediately + * - ... thus causing older reference pictures to be output, if not already + * - the oldest reference picture is replaced with the new reference picture + */ + if (G_LIKELY(dpb->num_pictures == MAX_MPEG2_REFERENCES)) { + index = (dpb->pictures[0]->poc > dpb->pictures[1]->poc); + ref_picture = dpb->pictures[index]; + if (!GST_VAAPI_PICTURE_IS_OUTPUT(ref_picture)) { + if (!dpb_output(dpb, ref_picture)) + return FALSE; + } + } + + if (!GST_VAAPI_PICTURE_IS_REFERENCE(picture)) + return dpb_output(dpb, picture); + + if (index < 0) + index = dpb->num_pictures++; + gst_vaapi_picture_replace(&dpb->pictures[index], picture); + return TRUE; +} + +static void +gst_vaapi_dpb_mpeg2_init(GstVaapiDpbMpeg2 *dpb) +{ +} + +static void +gst_vaapi_dpb_mpeg2_class_init(GstVaapiDpbMpeg2Class *klass) +{ + GstVaapiDpbClass * const dpb_class = GST_VAAPI_DPB_CLASS(klass); + + dpb_class->add = gst_vaapi_dpb_mpeg2_add; +} + +GstVaapiDpb * +gst_vaapi_dpb_mpeg2_new(void) +{ + return dpb_new(GST_VAAPI_TYPE_DPB_MPEG2, MAX_MPEG2_REFERENCES); +} + +void +gst_vaapi_dpb_mpeg2_get_references( + GstVaapiDpb *dpb, + GstVaapiPicture *picture, + GstVaapiPicture **prev_picture_ptr, + GstVaapiPicture **next_picture_ptr +) +{ + GstVaapiPicture *ref_picture, *ref_pictures[MAX_MPEG2_REFERENCES]; + GstVaapiPicture **picture_ptr; + guint i, index; + + g_return_if_fail(GST_VAAPI_IS_DPB_MPEG2(dpb)); + g_return_if_fail(GST_VAAPI_IS_PICTURE(picture)); + + ref_pictures[0] = NULL; + ref_pictures[1] = NULL; + for (i = 0; i < dpb->num_pictures; i++) { + ref_picture = dpb->pictures[i]; + index = ref_picture->poc > picture->poc; + picture_ptr = &ref_pictures[index]; + if (!*picture_ptr || ((*picture_ptr)->poc > ref_picture->poc) == index) + *picture_ptr = ref_picture; + } + + if (prev_picture_ptr) + *prev_picture_ptr = ref_pictures[0]; + if (next_picture_ptr) + *next_picture_ptr = ref_pictures[1]; +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_dpb.h b/gst-libs/gst/vaapi/gstvaapidecoder_dpb.h new file mode 100644 index 0000000..3cbaa48 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_dpb.h @@ -0,0 +1,192 @@ +/* + * gstvaapidecoder_dpb.h - Decoded Picture Buffer + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_DPB_H +#define GST_VAAPI_DECODER_DPB_H + +#include + +G_BEGIN_DECLS + +typedef struct _GstVaapiDpb GstVaapiDpb; +typedef struct _GstVaapiDpbClass GstVaapiDpbClass; +typedef struct _GstVaapiDpbMpeg2 GstVaapiDpbMpeg2; +typedef struct _GstVaapiDpbMpeg2Class GstVaapiDpbMpeg2Class; + +/* ------------------------------------------------------------------------- */ +/* --- Base Decoded Picture Buffer --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_TYPE_DPB \ + (gst_vaapi_dpb_get_type()) + +#define GST_VAAPI_DPB_CAST(obj) \ + ((GstVaapiDpb *)(obj)) + +#define GST_VAAPI_DPB(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DPB, \ + GstVaapiDpb)) + +#define GST_VAAPI_DPB_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DPB, \ + GstVaapiDpbClass)) + +#define GST_VAAPI_IS_DPB(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DPB)) + +#define GST_VAAPI_IS_DPB_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DPB)) + +#define GST_VAAPI_DPB_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DPB, \ + GstVaapiDpbClass)) + +/** + * GstVaapiDpb: + * + * A decoded picture buffer (DPB) object. + */ +struct _GstVaapiDpb { + /*< private >*/ + GstMiniObject parent_instance; + + /*< protected >*/ + GstVaapiPicture **pictures; + guint num_pictures; + guint max_pictures; +}; + +/** + * GstVaapiDpbClass: + * + * The #GstVaapiDpb base class. + */ +struct _GstVaapiDpbClass { + /*< private >*/ + GstMiniObjectClass parent_class; + + /*< protected >*/ + void (*flush) (GstVaapiDpb *dpb); + gboolean (*add) (GstVaapiDpb *dpb, GstVaapiPicture *picture); +}; + +G_GNUC_INTERNAL +GType +gst_vaapi_dpb_get_type(void) G_GNUC_CONST; + +G_GNUC_INTERNAL +void +gst_vaapi_dpb_flush(GstVaapiDpb *dpb); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_dpb_add(GstVaapiDpb *dpb, GstVaapiPicture *picture); + +G_GNUC_INTERNAL +guint +gst_vaapi_dpb_size(GstVaapiDpb *dpb); + +static inline gpointer +gst_vaapi_dpb_ref(gpointer ptr) +{ + return gst_mini_object_ref(GST_MINI_OBJECT(ptr)); +} + +static inline void +gst_vaapi_dpb_unref(gpointer ptr) +{ + gst_mini_object_unref(GST_MINI_OBJECT(ptr)); +} + +/* ------------------------------------------------------------------------- */ +/* --- MPEG-2 Decoded Picture Buffer --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_TYPE_DPB_MPEG2 \ + (gst_vaapi_dpb_mpeg2_get_type()) + +#define GST_VAAPI_DPB_MPEG2_CAST(obj) \ + ((GstVaapiDpbMpeg2 *)(obj)) + +#define GST_VAAPI_DPB_MPEG2(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DPB_MPEG2, \ + GstVaapiDpbMpeg2)) + +#define GST_VAAPI_DPB_MPEG2_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DPB_MPEG2, \ + GstVaapiDpbMpeg2Class)) + +#define GST_VAAPI_IS_DPB_MPEG2(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DPB_MPEG2)) + +#define GST_VAAPI_IS_DPB_MPEG2_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DPB_MPEG2)) + +#define GST_VAAPI_DPB_MPEG2_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DPB_MPEG2, \ + GstVaapiDpbMpeg2Class)) + +/** + * GstVaapiDpbMpeg2: + * + * A decoded picture buffer (DPB_MPEG2) object. + */ +struct _GstVaapiDpbMpeg2 { + /*< private >*/ + GstVaapiDpb parent_instance; +}; + +/** + * GstVaapiDpbMpeg2Class: + * + * The #GstVaapiDpbMpeg2 base class. + */ +struct _GstVaapiDpbMpeg2Class { + /*< private >*/ + GstVaapiDpbClass parent_class; +}; + +G_GNUC_INTERNAL +GType +gst_vaapi_dpb_mpeg2_get_type(void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstVaapiDpb * +gst_vaapi_dpb_mpeg2_new(void); + +G_GNUC_INTERNAL +void +gst_vaapi_dpb_mpeg2_get_references( + GstVaapiDpb *dpb, + GstVaapiPicture *picture, + GstVaapiPicture **prev_picture_ptr, + GstVaapiPicture **next_picture_ptr +); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_DPB */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_h264.c b/gst-libs/gst/vaapi/gstvaapidecoder_h264.c new file mode 100644 index 0000000..232fc6f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_h264.c @@ -0,0 +1,2536 @@ +/* + * gstvaapidecoder_h264.c - H.264 decoder + * + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidecoder_h264 + * @short_description: H.264 decoder + */ + +#include "sysdeps.h" +#include +#include +#include +#include +#include "gstvaapidecoder_h264.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiobject_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +typedef struct _GstVaapiPictureH264 GstVaapiPictureH264; +typedef struct _GstVaapiPictureH264Class GstVaapiPictureH264Class; +typedef struct _GstVaapiSliceH264 GstVaapiSliceH264; +typedef struct _GstVaapiSliceH264Class GstVaapiSliceH264Class; + +/* ------------------------------------------------------------------------- */ +/* --- H.264 Pictures --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_TYPE_PICTURE_H264 \ + (gst_vaapi_picture_h264_get_type()) + +#define GST_VAAPI_PICTURE_H264_CAST(obj) \ + ((GstVaapiPictureH264 *)(obj)) + +#define GST_VAAPI_PICTURE_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_PICTURE_H264, \ + GstVaapiPictureH264)) + +#define GST_VAAPI_PICTURE_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_PICTURE_H264, \ + GstVaapiPictureH264Class)) + +#define GST_VAAPI_IS_PICTURE_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_PICTURE_H264)) + +#define GST_VAAPI_IS_PICTURE_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_PICTURE_H264)) + +#define GST_VAAPI_PICTURE_H264_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_PICTURE_H264, \ + GstVaapiPictureH264Class)) + +struct _GstVaapiPictureH264 { + GstVaapiPicture base; + VAPictureH264 info; + gint32 poc; + gint32 frame_num; // Original frame_num from slice_header() + gint32 frame_num_wrap; // Temporary for ref pic marking: FrameNumWrap + gint32 pic_num; // Temporary for ref pic marking: PicNum + gint32 long_term_pic_num; // Temporary for ref pic marking: LongTermPicNum + guint is_idr : 1; + guint is_long_term : 1; + guint field_pic_flag : 1; + guint bottom_field_flag : 1; + guint has_mmco_5 : 1; + guint output_flag : 1; + guint output_needed : 1; +}; + +struct _GstVaapiPictureH264Class { + /*< private >*/ + GstVaapiPictureClass parent_class; +}; + +GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiPictureH264, + gst_vaapi_picture_h264, + GST_VAAPI_TYPE_PICTURE) + +static void +gst_vaapi_picture_h264_destroy(GstVaapiPictureH264 *decoder) +{ +} + +static gboolean +gst_vaapi_picture_h264_create( + GstVaapiPictureH264 *picture, + const GstVaapiCodecObjectConstructorArgs *args +) +{ + return TRUE; +} + +static void +gst_vaapi_picture_h264_init(GstVaapiPictureH264 *picture) +{ + VAPictureH264 *va_pic; + + va_pic = &picture->info; + va_pic->flags = 0; + va_pic->TopFieldOrderCnt = 0; + va_pic->BottomFieldOrderCnt = 0; + + picture->poc = 0; + picture->is_long_term = FALSE; + picture->is_idr = FALSE; + picture->has_mmco_5 = FALSE; + picture->output_needed = FALSE; +} + +static inline GstVaapiPictureH264 * +gst_vaapi_picture_h264_new(GstVaapiDecoderH264 *decoder) +{ + GstVaapiCodecObject *object; + + g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL); + + object = gst_vaapi_codec_object_new( + GST_VAAPI_TYPE_PICTURE_H264, + GST_VAAPI_CODEC_BASE(decoder), + NULL, sizeof(VAPictureParameterBufferH264), + NULL, 0 + ); + if (!object) + return NULL; + return GST_VAAPI_PICTURE_H264_CAST(object); +} + +/* ------------------------------------------------------------------------- */ +/* --- Slices --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_TYPE_SLICE_H264 \ + (gst_vaapi_slice_h264_get_type()) + +#define GST_VAAPI_SLICE_H264_CAST(obj) \ + ((GstVaapiSliceH264 *)(obj)) + +#define GST_VAAPI_SLICE_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_SLICE_H264, \ + GstVaapiSliceH264)) + +#define GST_VAAPI_SLICE_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_SLICE_H264, \ + GstVaapiSliceH264Class)) + +#define GST_VAAPI_IS_SLICE_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_SLICE_H264)) + +#define GST_VAAPI_IS_SLICE_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_SLICE_H264)) + +#define GST_VAAPI_SLICE_H264_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_SLICE_H264, \ + GstVaapiSliceH264Class)) + +struct _GstVaapiSliceH264 { + GstVaapiSlice base; + GstH264SliceHdr slice_hdr; // parsed slice_header() +}; + +struct _GstVaapiSliceH264Class { + /*< private >*/ + GstVaapiSliceClass parent_class; +}; + +GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiSliceH264, + gst_vaapi_slice_h264, + GST_VAAPI_TYPE_SLICE) + +static void +gst_vaapi_slice_h264_destroy(GstVaapiSliceH264 *slice) +{ +} + +static gboolean +gst_vaapi_slice_h264_create( + GstVaapiSliceH264 *slice, + const GstVaapiCodecObjectConstructorArgs *args +) +{ + return TRUE; +} + +static void +gst_vaapi_slice_h264_init(GstVaapiSliceH264 *slice) +{ +} + +static inline GstVaapiSliceH264 * +gst_vaapi_slice_h264_new( + GstVaapiDecoderH264 *decoder, + const guint8 *data, + guint data_size +) +{ + GstVaapiCodecObject *object; + + g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL); + + object = gst_vaapi_codec_object_new( + GST_VAAPI_TYPE_SLICE_H264, + GST_VAAPI_CODEC_BASE(decoder), + NULL, sizeof(VASliceParameterBufferH264), + data, data_size + ); + if (!object) + return NULL; + return GST_VAAPI_SLICE_H264_CAST(object); +} + +/* ------------------------------------------------------------------------- */ +/* --- H.264 Decoder --- */ +/* ------------------------------------------------------------------------- */ + +G_DEFINE_TYPE(GstVaapiDecoderH264, + gst_vaapi_decoder_h264, + GST_VAAPI_TYPE_DECODER); + +#define GST_VAAPI_DECODER_H264_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DECODER_H264, \ + GstVaapiDecoderH264Private)) + +// Used for field_poc[] +#define TOP_FIELD 0 +#define BOTTOM_FIELD 1 + +struct _GstVaapiDecoderH264Private { + GstAdapter *adapter; + GstBuffer *sub_buffer; + GstH264NalParser *parser; + GstH264SPS *sps; + GstH264SPS last_sps; + GstH264PPS *pps; + GstH264PPS last_pps; + GstVaapiPictureH264 *current_picture; + GstVaapiPictureH264 *dpb[16]; + guint dpb_count; + guint dpb_size; + GstVaapiProfile profile; + GstVaapiPictureH264 *short_ref[32]; + guint short_ref_count; + GstVaapiPictureH264 *long_ref[32]; + guint long_ref_count; + GstVaapiPictureH264 *RefPicList0[32]; + guint RefPicList0_count; + GstVaapiPictureH264 *RefPicList1[32]; + guint RefPicList1_count; + guint nal_length_size; + guint width; + guint height; + guint mb_x; + guint mb_y; + guint mb_width; + guint mb_height; + guint8 scaling_list_4x4[6][16]; + guint8 scaling_list_8x8[6][64]; + gint32 field_poc[2]; // 0:TopFieldOrderCnt / 1:BottomFieldOrderCnt + gint32 poc_msb; // PicOrderCntMsb + gint32 poc_lsb; // pic_order_cnt_lsb (from slice_header()) + gint32 prev_poc_msb; // prevPicOrderCntMsb + gint32 prev_poc_lsb; // prevPicOrderCntLsb + gint32 frame_num_offset; // FrameNumOffset + gint32 prev_frame_num_offset; // prevFrameNumOffset + gint32 frame_num; // frame_num (from slice_header()) + gint32 prev_frame_num; // prevFrameNum + guint is_constructed : 1; + guint is_opened : 1; + guint is_avc : 1; + guint has_context : 1; +}; + +static gboolean +decode_picture_end(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture); + +static void +clear_references( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 **pictures, + guint *picture_count +); + +static void +dpb_remove_index(GstVaapiDecoderH264 *decoder, guint index) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + guint num_pictures = --priv->dpb_count; + + if (index != num_pictures) + gst_vaapi_picture_replace(&priv->dpb[index], priv->dpb[num_pictures]); + gst_vaapi_picture_replace(&priv->dpb[num_pictures], NULL); +} + +static inline gboolean +dpb_output(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture) +{ + /* XXX: update cropping rectangle */ + picture->output_needed = FALSE; + return gst_vaapi_picture_output(GST_VAAPI_PICTURE_CAST(picture)); +} + +static gboolean +dpb_bump(GstVaapiDecoderH264 *decoder) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + guint i, lowest_poc_index; + gboolean success; + + for (i = 0; i < priv->dpb_count; i++) { + if (priv->dpb[i]->output_needed) + break; + } + if (i == priv->dpb_count) + return FALSE; + + lowest_poc_index = i++; + for (; i < priv->dpb_count; i++) { + GstVaapiPictureH264 * const picture = priv->dpb[i]; + if (picture->output_needed && picture->poc < priv->dpb[lowest_poc_index]->poc) + lowest_poc_index = i; + } + + success = dpb_output(decoder, priv->dpb[lowest_poc_index]); + if (!GST_VAAPI_PICTURE_IS_REFERENCE(priv->dpb[lowest_poc_index])) + dpb_remove_index(decoder, lowest_poc_index); + return success; +} + +static void +dpb_flush(GstVaapiDecoderH264 *decoder) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + + while (dpb_bump(decoder)) + ; + clear_references(decoder, priv->dpb, &priv->dpb_count); +} + +static gboolean +dpb_add(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + guint i; + + // Remove all unused pictures + if (picture->is_idr) + dpb_flush(decoder); + else { + i = 0; + while (i < priv->dpb_count) { + GstVaapiPictureH264 * const picture = priv->dpb[i]; + if (!picture->output_needed && + !GST_VAAPI_PICTURE_IS_REFERENCE(picture)) + dpb_remove_index(decoder, i); + else + i++; + } + } + + // C.4.5.1 - Storage and marking of a reference decoded picture into the DPB + if (GST_VAAPI_PICTURE_IS_REFERENCE(picture)) { + while (priv->dpb_count == priv->dpb_size) { + if (!dpb_bump(decoder)) + return FALSE; + } + gst_vaapi_picture_replace(&priv->dpb[priv->dpb_count++], picture); + if (picture->output_flag) + picture->output_needed = TRUE; + } + + // C.4.5.2 - Storage and marking of a non-reference decoded picture into the DPB + else { + if (!picture->output_flag) + return TRUE; + while (priv->dpb_count == priv->dpb_size) { + for (i = 0; i < priv->dpb_count; i++) { + if (priv->dpb[i]->output_needed && + priv->dpb[i]->poc < picture->poc) + break; + } + if (i == priv->dpb_count) + return dpb_output(decoder, picture); + if (!dpb_bump(decoder)) + return FALSE; + } + gst_vaapi_picture_replace(&priv->dpb[priv->dpb_count++], picture); + picture->output_needed = TRUE; + } + return TRUE; +} + +static void +dpb_reset(GstVaapiDecoderH264 *decoder, GstH264SPS *sps) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + guint max_dec_frame_buffering, MaxDpbMbs, PicSizeMbs; + + /* Table A-1 - Level limits */ + switch (sps->level_idc) { + case 10: MaxDpbMbs = 396; break; + case 11: MaxDpbMbs = 900; break; + case 12: MaxDpbMbs = 2376; break; + case 13: MaxDpbMbs = 2376; break; + case 20: MaxDpbMbs = 2376; break; + case 21: MaxDpbMbs = 4752; break; + case 22: MaxDpbMbs = 8100; break; + case 30: MaxDpbMbs = 8100; break; + case 31: MaxDpbMbs = 18000; break; + case 32: MaxDpbMbs = 20480; break; + case 40: MaxDpbMbs = 32768; break; + case 41: MaxDpbMbs = 32768; break; + case 42: MaxDpbMbs = 34816; break; + case 50: MaxDpbMbs = 110400; break; + case 51: MaxDpbMbs = 184320; break; + default: + g_assert(0 && "unhandled level"); + break; + } + + PicSizeMbs = ((sps->pic_width_in_mbs_minus1 + 1) * + (sps->pic_height_in_map_units_minus1 + 1) * + (sps->frame_mbs_only_flag ? 1 : 2)); + max_dec_frame_buffering = MaxDpbMbs / PicSizeMbs; + if (max_dec_frame_buffering > 8) + max_dec_frame_buffering = 8; + + /* VUI parameters */ + if (sps->vui_parameters_present_flag) { + GstH264VUIParams * const vui_params = &sps->vui_parameters; + if (vui_params->bitstream_restriction_flag) + max_dec_frame_buffering = vui_params->max_dec_frame_buffering; + else { + switch (sps->profile_idc) { + case 44: // CAVLC 4:4:4 Intra profile + case 86: // Scalable High profile + case 100: // High profile + case 110: // High 10 profile + case 122: // High 4:2:2 profile + case 244: // High 4:4:4 Predictive profile + if (sps->constraint_set3_flag) + max_dec_frame_buffering = 0; + break; + } + } + } + + if (max_dec_frame_buffering > 16) + max_dec_frame_buffering = 16; + else if (max_dec_frame_buffering < sps->num_ref_frames) + max_dec_frame_buffering = sps->num_ref_frames; + priv->dpb_size = MAX(1, max_dec_frame_buffering); + GST_DEBUG("DPB size %u", priv->dpb_size); +} + +static GstVaapiDecoderStatus +get_status(GstH264ParserResult result) +{ + GstVaapiDecoderStatus status; + + switch (result) { + case GST_H264_PARSER_OK: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + case GST_H264_PARSER_NO_NAL_END: + status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + break; + case GST_H264_PARSER_ERROR: + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + default: + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + break; + } + return status; +} + +static inline GstH264DecRefPicMarking * +get_dec_ref_pic_marking(GstVaapiPictureH264 *picture_h264) +{ + GstVaapiPicture * const picture = GST_VAAPI_PICTURE_CAST(picture_h264); + GstVaapiSliceH264 *slice; + + slice = g_ptr_array_index(picture->slices, picture->slices->len - 1); + return &slice->slice_hdr.dec_ref_pic_marking; +} + +static void +gst_vaapi_decoder_h264_clear_buffer(GstVaapiDecoder *base) +{ + GstVaapiDecoderH264 * const decoder = GST_VAAPI_DECODER_H264(base); + GstVaapiDecoderH264Private * const priv = decoder->priv; + + gst_vaapi_picture_replace(&priv->current_picture, NULL); + clear_references(decoder, priv->short_ref, &priv->short_ref_count); + clear_references(decoder, priv->long_ref, &priv->long_ref_count ); + clear_references(decoder, priv->dpb, &priv->dpb_count ); + + if (priv->sub_buffer) { + gst_buffer_unref(priv->sub_buffer); + priv->sub_buffer = NULL; + } + + if (priv->adapter) { + gst_adapter_clear(priv->adapter); + } +} + +static void +gst_vaapi_decoder_h264_close(GstVaapiDecoderH264 *decoder) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + + gst_vaapi_decoder_h264_clear_buffer(GST_VAAPI_DECODER_CAST(decoder)); + + if (priv->parser) { + gst_h264_nal_parser_free(priv->parser); + priv->parser = NULL; + } + + if (priv->adapter) { + g_object_unref(priv->adapter); + priv->adapter = NULL; + } +} + +static gboolean +gst_vaapi_decoder_h264_open(GstVaapiDecoderH264 *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + + gst_vaapi_decoder_h264_close(decoder); + + priv->adapter = gst_adapter_new(); + if (!priv->adapter) + return FALSE; + + priv->parser = gst_h264_nal_parser_new(); + if (!priv->parser) + return FALSE; + return TRUE; +} + +static void +gst_vaapi_decoder_h264_destroy(GstVaapiDecoderH264 *decoder) +{ + gst_vaapi_decoder_h264_close(decoder); +} + +static gboolean +gst_vaapi_decoder_h264_create(GstVaapiDecoderH264 *decoder) +{ + if (!GST_VAAPI_DECODER_CODEC(decoder)) + return FALSE; + return TRUE; +} + +static inline guint +min_surfaces_count(guint dbp_size) +{ + guint count = dbp_size + 4; + + if (count < GST_DECODER_DEFAULT_SURFACES_COUNT) + count = GST_DECODER_DEFAULT_SURFACES_COUNT; + return count; +} + +static GstVaapiDecoderStatus +ensure_context(GstVaapiDecoderH264 *decoder, GstH264SPS *sps) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiProfile profiles[2]; + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + guint i, n_profiles = 0; + gboolean success, reset_context = FALSE; + + if (!priv->has_context || priv->sps->profile_idc != sps->profile_idc) { + GST_DEBUG("profile changed"); + reset_context = TRUE; + + switch (sps->profile_idc) { + case 66: + profiles[n_profiles++] = GST_VAAPI_PROFILE_H264_BASELINE; + break; + case 77: + profiles[n_profiles++] = GST_VAAPI_PROFILE_H264_MAIN; + // fall-through + case 100: + profiles[n_profiles++] = GST_VAAPI_PROFILE_H264_HIGH; + break; + default: + GST_DEBUG("unsupported profile %d", sps->profile_idc); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + for (i = 0; i < n_profiles; i++) { + success = gst_vaapi_display_has_decoder( + GST_VAAPI_DECODER_DISPLAY(decoder), + profiles[i], + entrypoint + ); + if (success) + break; + } + if (i == n_profiles) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + priv->profile = profiles[i]; + } + + if (!priv->has_context || + priv->sps->chroma_format_idc != sps->chroma_format_idc) { + GST_DEBUG("chroma format changed"); + reset_context = TRUE; + + /* XXX: theoritically, we could handle 4:2:2 format */ + if (sps->chroma_format_idc != 1) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT; + } + + if (!priv->has_context || + priv->sps->width != sps->width || + priv->sps->height != sps->height) { + GST_DEBUG("size changed"); + reset_context = TRUE; + + priv->width = sps->width; + priv->height = sps->height; + priv->mb_width = sps->pic_width_in_mbs_minus1 + 1; + priv->mb_height = sps->pic_height_in_map_units_minus1 + 1; + priv->mb_height *= 2 - sps->frame_mbs_only_flag; + } + + if (reset_context) { + /* Reset DPB first*/ + dpb_reset(decoder, sps); + + success = gst_vaapi_decoder_ensure_context( + GST_VAAPI_DECODER(decoder), + priv->profile, + entrypoint, + priv->width, + priv->height, + min_surfaces_count(priv->dpb_size) + ); + if (!success) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + priv->has_context = TRUE; + + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +ensure_quant_matrix(GstVaapiDecoderH264 *decoder, GstH264PPS *pps) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + + if (priv->pps != pps) { + memcpy(priv->scaling_list_4x4, pps->scaling_lists_4x4, + sizeof(priv->scaling_list_4x4)); + memcpy(priv->scaling_list_8x8, pps->scaling_lists_8x8, + sizeof(priv->scaling_list_8x8)); + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static gboolean +decode_current_picture(GstVaapiDecoderH264 *decoder) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiPictureH264 * const picture = priv->current_picture; + gboolean success = FALSE; + + if (!picture) + return TRUE; + + if (!decode_picture_end(decoder, picture)) + goto end; + if (!gst_vaapi_picture_decode(GST_VAAPI_PICTURE_CAST(picture))) + goto end; + success = TRUE; +end: + gst_vaapi_picture_replace(&priv->current_picture, NULL); + return success; +} + +static GstVaapiDecoderStatus +decode_sps(GstVaapiDecoderH264 *decoder, GstH264NalUnit *nalu) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstH264SPS * const sps = &priv->last_sps; + GstH264ParserResult result; + + GST_DEBUG("decode SPS"); + + if (priv->current_picture && !decode_current_picture(decoder)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + memset(sps, 0, sizeof(*sps)); + result = gst_h264_parser_parse_sps(priv->parser, nalu, sps, TRUE); + if (result != GST_H264_PARSER_OK) + return get_status(result); + + return ensure_context(decoder, sps); +} + +static GstVaapiDecoderStatus +decode_pps(GstVaapiDecoderH264 *decoder, GstH264NalUnit *nalu) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstH264PPS * const pps = &priv->last_pps; + GstH264ParserResult result; + + GST_DEBUG("decode PPS"); + + if (priv->current_picture && !decode_current_picture(decoder)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + memset(pps, 0, sizeof(*pps)); + result = gst_h264_parser_parse_pps(priv->parser, nalu, pps); + if (result != GST_H264_PARSER_OK) + return get_status(result); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sei(GstVaapiDecoderH264 *decoder, GstH264NalUnit *nalu) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstH264SEIMessage sei; + GstH264ParserResult result; + + GST_DEBUG("decode SEI"); + + memset(&sei, 0, sizeof(sei)); + result = gst_h264_parser_parse_sei(priv->parser, nalu, &sei); + if (result != GST_H264_PARSER_OK) { + GST_WARNING("failed to decode SEI, payload type:%d", sei.payloadType); + return get_status(result); + } + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_end(GstVaapiDecoderH264 *decoder) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + + GST_DEBUG("decode sequence-end"); + + if (priv->current_picture && !decode_current_picture(decoder)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + dpb_flush(decoder); + return GST_VAAPI_DECODER_STATUS_END_OF_STREAM; +} + +/* 8.2.1.1 - Decoding process for picture order count type 0 */ +static void +init_picture_poc_0( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstH264PPS * const pps = slice_hdr->pps; + GstH264SPS * const sps = pps->sequence; + const gint32 MaxPicOrderCntLsb = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + + GST_DEBUG("decode picture order count type 0"); + + // (8-3) + priv->poc_lsb = slice_hdr->pic_order_cnt_lsb; + if (priv->poc_lsb < priv->prev_poc_lsb && + (priv->prev_poc_lsb - priv->poc_lsb) >= (MaxPicOrderCntLsb / 2)) + priv->poc_msb = priv->prev_poc_msb + MaxPicOrderCntLsb; + else if (priv->poc_lsb > priv->prev_poc_lsb && + (priv->poc_lsb - priv->prev_poc_lsb) > (MaxPicOrderCntLsb / 2)) + priv->poc_msb = priv->prev_poc_msb - MaxPicOrderCntLsb; + else + priv->poc_msb = priv->prev_poc_msb; + + // (8-4) + if (!slice_hdr->field_pic_flag || !slice_hdr->bottom_field_flag) + priv->field_poc[TOP_FIELD] = priv->poc_msb + priv->poc_lsb; + + // (8-5) + if (!slice_hdr->field_pic_flag) + priv->field_poc[BOTTOM_FIELD] = priv->field_poc[TOP_FIELD] + + slice_hdr->delta_pic_order_cnt_bottom; + else if (slice_hdr->bottom_field_flag) + priv->field_poc[BOTTOM_FIELD] = priv->poc_msb + priv->poc_lsb; +} + +/* 8.2.1.2 - Decoding process for picture order count type 1 */ +static void +init_picture_poc_1( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstH264PPS * const pps = slice_hdr->pps; + GstH264SPS * const sps = pps->sequence; + const gint32 MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4); + gint32 abs_frame_num, expected_poc; + guint i; + + GST_DEBUG("decode picture order count type 1"); + + // (8-6) + if (picture->is_idr) + priv->frame_num_offset = 0; + else if (priv->prev_frame_num > priv->frame_num) + priv->frame_num_offset = priv->prev_frame_num_offset + MaxFrameNum; + else + priv->frame_num_offset = priv->prev_frame_num_offset; + + // (8-7) + if (sps->num_ref_frames_in_pic_order_cnt_cycle != 0) + abs_frame_num = priv->frame_num_offset + priv->frame_num; + else + abs_frame_num = 0; + if (!GST_VAAPI_PICTURE_IS_REFERENCE(picture) && abs_frame_num > 0) + abs_frame_num = abs_frame_num - 1; + + if (abs_frame_num > 0) { + gint32 expected_delta_per_poc_cycle; + gint32 poc_cycle_cnt, frame_num_in_poc_cycle; + + expected_delta_per_poc_cycle = 0; + for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++) + expected_delta_per_poc_cycle += sps->offset_for_ref_frame[i]; + + // (8-8) + poc_cycle_cnt = (abs_frame_num - 1) / + sps->num_ref_frames_in_pic_order_cnt_cycle; + frame_num_in_poc_cycle = (abs_frame_num - 1) % + sps->num_ref_frames_in_pic_order_cnt_cycle; + + // (8-9) + expected_poc = poc_cycle_cnt * expected_delta_per_poc_cycle; + for (i = 0; i <= frame_num_in_poc_cycle; i++) + expected_poc += sps->offset_for_ref_frame[i]; + } + else + expected_poc = 0; + if (!GST_VAAPI_PICTURE_IS_REFERENCE(picture)) + expected_poc += sps->offset_for_non_ref_pic; + + // (8-10) + if (!slice_hdr->field_pic_flag) { + priv->field_poc[TOP_FIELD] = expected_poc + + slice_hdr->delta_pic_order_cnt[0]; + priv->field_poc[BOTTOM_FIELD] = priv->field_poc[TOP_FIELD] + + sps->offset_for_top_to_bottom_field + + slice_hdr->delta_pic_order_cnt[1]; + } + else if (!slice_hdr->bottom_field_flag) + priv->field_poc[TOP_FIELD] = expected_poc + + slice_hdr->delta_pic_order_cnt[0]; + else + priv->field_poc[BOTTOM_FIELD] = expected_poc + + sps->offset_for_top_to_bottom_field + slice_hdr->delta_pic_order_cnt[0]; +} + +/* 8.2.1.3 - Decoding process for picture order count type 2 */ +static void +init_picture_poc_2( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstH264PPS * const pps = slice_hdr->pps; + GstH264SPS * const sps = pps->sequence; + const gint32 MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4); + guint temp_poc; + + GST_DEBUG("decode picture order count type 2"); + + // (8-11) + if (picture->is_idr) + priv->frame_num_offset = 0; + else if (priv->prev_frame_num > priv->frame_num) + priv->frame_num_offset = priv->prev_frame_num_offset + MaxFrameNum; + else + priv->frame_num_offset = priv->prev_frame_num_offset; + + // (8-12) + if (picture->is_idr) + temp_poc = 0; + else if (!GST_VAAPI_PICTURE_IS_REFERENCE(picture)) + temp_poc = 2 * (priv->frame_num_offset + priv->frame_num) - 1; + else + temp_poc = 2 * (priv->frame_num_offset + priv->frame_num); + + // (8-13) + if (!slice_hdr->field_pic_flag) { + priv->field_poc[TOP_FIELD] = temp_poc; + priv->field_poc[BOTTOM_FIELD] = temp_poc; + } + else if (slice_hdr->bottom_field_flag) + priv->field_poc[BOTTOM_FIELD] = temp_poc; + else + priv->field_poc[TOP_FIELD] = temp_poc; +} + +/* 8.2.1 - Decoding process for picture order count */ +static void +init_picture_poc( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + VAPictureH264 * const pic = &picture->info; + GstH264PPS * const pps = slice_hdr->pps; + GstH264SPS * const sps = pps->sequence; + + switch (sps->pic_order_cnt_type) { + case 0: + init_picture_poc_0(decoder, picture, slice_hdr); + break; + case 1: + init_picture_poc_1(decoder, picture, slice_hdr); + break; + case 2: + init_picture_poc_2(decoder, picture, slice_hdr); + break; + } + + if (!(pic->flags & VA_PICTURE_H264_BOTTOM_FIELD)) + pic->TopFieldOrderCnt = priv->field_poc[TOP_FIELD]; + if (!(pic->flags & VA_PICTURE_H264_TOP_FIELD)) + pic->BottomFieldOrderCnt = priv->field_poc[BOTTOM_FIELD]; + picture->poc = MIN(pic->TopFieldOrderCnt, pic->BottomFieldOrderCnt); +} + +static int +compare_picture_pic_num_dec(const void *a, const void *b) +{ + const GstVaapiPictureH264 * const picA = *(GstVaapiPictureH264 **)a; + const GstVaapiPictureH264 * const picB = *(GstVaapiPictureH264 **)b; + + return picB->pic_num - picA->pic_num; +} + +static int +compare_picture_long_term_pic_num_inc(const void *a, const void *b) +{ + const GstVaapiPictureH264 * const picA = *(GstVaapiPictureH264 **)a; + const GstVaapiPictureH264 * const picB = *(GstVaapiPictureH264 **)b; + + return picA->long_term_pic_num - picB->long_term_pic_num; +} + +static int +compare_picture_poc_dec(const void *a, const void *b) +{ + const GstVaapiPictureH264 * const picA = *(GstVaapiPictureH264 **)a; + const GstVaapiPictureH264 * const picB = *(GstVaapiPictureH264 **)b; + + return picB->poc - picA->poc; +} + +static int +compare_picture_poc_inc(const void *a, const void *b) +{ + const GstVaapiPictureH264 * const picA = *(GstVaapiPictureH264 **)a; + const GstVaapiPictureH264 * const picB = *(GstVaapiPictureH264 **)b; + + return picA->poc - picB->poc; +} + +static int +compare_picture_frame_num_wrap_dec(const void *a, const void *b) +{ + const GstVaapiPictureH264 * const picA = *(GstVaapiPictureH264 **)a; + const GstVaapiPictureH264 * const picB = *(GstVaapiPictureH264 **)b; + + return picB->frame_num_wrap - picA->frame_num_wrap; +} + +static int +compare_picture_long_term_frame_idx_inc(const void *a, const void *b) +{ + const GstVaapiPictureH264 * const picA = *(GstVaapiPictureH264 **)a; + const GstVaapiPictureH264 * const picB = *(GstVaapiPictureH264 **)b; + + return picA->info.frame_idx - picB->info.frame_idx; +} + +/* 8.2.4.1 - Decoding process for picture numbers */ +static void +init_picture_refs_pic_num( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstH264PPS * const pps = slice_hdr->pps; + GstH264SPS * const sps = pps->sequence; + const gint32 MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4); + const guint field_flags = VA_PICTURE_H264_TOP_FIELD | VA_PICTURE_H264_BOTTOM_FIELD; + guint i; + + GST_DEBUG("decode picture numbers"); + + for (i = 0; i < priv->short_ref_count; i++) { + GstVaapiPictureH264 * const pic = priv->short_ref[i]; + + // (8-27) + if (pic->frame_num > priv->frame_num) + pic->frame_num_wrap = pic->frame_num - MaxFrameNum; + else + pic->frame_num_wrap = pic->frame_num; + + // (8-28, 8-30, 8-31) + if (!pic->field_pic_flag) + pic->pic_num = pic->frame_num_wrap; + else { + if (((picture->info.flags ^ pic->info.flags) & field_flags) == 0) + pic->pic_num = 2 * pic->frame_num_wrap + 1; + else + pic->pic_num = 2 * pic->frame_num_wrap; + } + } + + for (i = 0; i < priv->long_ref_count; i++) { + GstVaapiPictureH264 * const pic = priv->long_ref[i]; + + // (8-29, 8-32, 8-33) + if (!pic->field_pic_flag) + pic->long_term_pic_num = pic->info.frame_idx; + else { + if (((picture->info.flags ^ pic->info.flags) & field_flags) == 0) + pic->long_term_pic_num = 2 * pic->info.frame_idx + 1; + else + pic->long_term_pic_num = 2 * pic->info.frame_idx; + } + } +} + +#define SORT_REF_LIST(list, n, compare_func) \ + qsort(list, n, sizeof(*(list)), compare_picture_##compare_func) + +static void +init_picture_refs_p_slice( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiPictureH264 **ref_list; + guint i; + + GST_DEBUG("decode reference picture list for P and SP slices"); + + if (!picture->field_pic_flag) { + /* 8.2.4.2.1 - P and SP slices in frames */ + if (priv->short_ref_count > 0) { + ref_list = priv->RefPicList0; + for (i = 0; i < priv->short_ref_count; i++) + ref_list[i] = priv->short_ref[i]; + SORT_REF_LIST(ref_list, i, pic_num_dec); + priv->RefPicList0_count += i; + } + + if (priv->long_ref_count > 0) { + ref_list = &priv->RefPicList0[priv->RefPicList0_count]; + for (i = 0; i < priv->long_ref_count; i++) + ref_list[i] = priv->long_ref[i]; + SORT_REF_LIST(ref_list, i, long_term_pic_num_inc); + priv->RefPicList0_count += i; + } + } + else { + /* 8.2.4.2.2 - P and SP slices in fields */ + GstVaapiPictureH264 *short_ref[32]; + guint short_ref_count = 0; + GstVaapiPictureH264 *long_ref[32]; + guint long_ref_count = 0; + + // XXX: handle second field if current field is marked as + // "used for short-term reference" + if (priv->short_ref_count > 0) { + for (i = 0; i < priv->short_ref_count; i++) + short_ref[i] = priv->short_ref[i]; + SORT_REF_LIST(short_ref, i, frame_num_wrap_dec); + short_ref_count = i; + } + + // XXX: handle second field if current field is marked as + // "used for long-term reference" + if (priv->long_ref_count > 0) { + for (i = 0; i < priv->long_ref_count; i++) + long_ref[i] = priv->long_ref[i]; + SORT_REF_LIST(long_ref, i, long_term_frame_idx_inc); + long_ref_count = i; + } + + // XXX: handle 8.2.4.2.5 + } +} + +static void +init_picture_refs_b_slice( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiPictureH264 **ref_list; + guint i, n; + + GST_DEBUG("decode reference picture list for B slices"); + + if (!picture->field_pic_flag) { + /* 8.2.4.2.3 - B slices in frames */ + + /* RefPicList0 */ + if (priv->short_ref_count > 0) { + // 1. Short-term references + ref_list = priv->RefPicList0; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->poc < picture->poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST(ref_list, n, poc_dec); + priv->RefPicList0_count += n; + + ref_list = &priv->RefPicList0[priv->RefPicList0_count]; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->poc >= picture->poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST(ref_list, n, poc_inc); + priv->RefPicList0_count += n; + } + + if (priv->long_ref_count > 0) { + // 2. Long-term references + ref_list = &priv->RefPicList0[priv->RefPicList0_count]; + for (n = 0, i = 0; i < priv->long_ref_count; i++) + ref_list[n++] = priv->long_ref[i]; + SORT_REF_LIST(ref_list, n, long_term_pic_num_inc); + priv->RefPicList0_count += n; + } + + /* RefPicList1 */ + if (priv->short_ref_count > 0) { + // 1. Short-term references + ref_list = priv->RefPicList1; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->poc > picture->poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST(ref_list, n, poc_inc); + priv->RefPicList1_count += n; + + ref_list = &priv->RefPicList1[priv->RefPicList1_count]; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->poc <= picture->poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST(ref_list, n, poc_dec); + priv->RefPicList1_count += n; + } + + if (priv->long_ref_count > 0) { + // 2. Long-term references + ref_list = &priv->RefPicList1[priv->RefPicList1_count]; + for (n = 0, i = 0; i < priv->long_ref_count; i++) + ref_list[n++] = priv->long_ref[i]; + SORT_REF_LIST(ref_list, n, long_term_pic_num_inc); + priv->RefPicList1_count += n; + } + } + else { + /* 8.2.4.2.4 - B slices in fields */ + GstVaapiPictureH264 *short_ref0[32]; + guint short_ref0_count = 0; + GstVaapiPictureH264 *short_ref1[32]; + guint short_ref1_count = 0; + GstVaapiPictureH264 *long_ref[32]; + guint long_ref_count = 0; + + /* refFrameList0ShortTerm */ + if (priv->short_ref_count > 0) { + ref_list = short_ref0; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->poc <= picture->poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST(ref_list, n, poc_dec); + short_ref0_count += n; + + ref_list = &short_ref0[short_ref0_count]; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->poc > picture->poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST(ref_list, n, poc_inc); + short_ref0_count += n; + } + + /* refFrameList1ShortTerm */ + if (priv->short_ref_count > 0) { + ref_list = short_ref1; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->poc > picture->poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST(ref_list, n, poc_inc); + short_ref1_count += n; + + ref_list = &short_ref1[short_ref1_count]; + for (n = 0, i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->poc <= picture->poc) + ref_list[n++] = priv->short_ref[i]; + } + SORT_REF_LIST(ref_list, n, poc_dec); + short_ref1_count += n; + } + + /* refFrameListLongTerm */ + if (priv->long_ref_count > 0) { + for (i = 0; i < priv->long_ref_count; i++) + long_ref[i] = priv->long_ref[i]; + SORT_REF_LIST(long_ref, i, long_term_frame_idx_inc); + long_ref_count = i; + } + + // XXX: handle 8.2.4.2.5 + } + + /* Check whether RefPicList1 is identical to RefPicList0, then + swap if necessary */ + if (priv->RefPicList1_count > 1 && + priv->RefPicList1_count == priv->RefPicList0_count && + memcmp(priv->RefPicList0, priv->RefPicList1, + priv->RefPicList0_count * sizeof(priv->RefPicList0[0])) == 0) { + GstVaapiPictureH264 * const tmp = priv->RefPicList1[0]; + priv->RefPicList1[0] = priv->RefPicList1[1]; + priv->RefPicList1[1] = tmp; + } +} + +#undef SORT_REF_LIST + +static void +clear_references( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 **pictures, + guint *picture_count +) +{ + const guint num_pictures = *picture_count; + guint i; + + for (i = 0; i < num_pictures; i++) + gst_vaapi_picture_replace(&pictures[i], NULL); + *picture_count = 0; +} + +static gboolean +remove_reference_at( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 **pictures, + guint *picture_count, + guint index +) +{ + guint num_pictures = *picture_count; + + g_return_val_if_fail(index < num_pictures, FALSE); + + GST_VAAPI_PICTURE_FLAG_UNSET(pictures[index], GST_VAAPI_PICTURE_FLAG_REFERENCE); + if (index != --num_pictures) + gst_vaapi_picture_replace(&pictures[index], pictures[num_pictures]); + gst_vaapi_picture_replace(&pictures[num_pictures], NULL); + *picture_count = num_pictures; + return TRUE; +} + +static gint +find_short_term_reference(GstVaapiDecoderH264 *decoder, gint32 pic_num) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + guint i; + + for (i = 0; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->pic_num == pic_num) + return i; + } + GST_ERROR("found no short-term reference picture with PicNum = %d", + pic_num); + return -1; +} + +static gint +find_long_term_reference(GstVaapiDecoderH264 *decoder, gint32 long_term_pic_num) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + guint i; + + for (i = 0; i < priv->long_ref_count; i++) { + if (priv->long_ref[i]->long_term_pic_num == long_term_pic_num) + return i; + } + GST_ERROR("found no long-term reference picture with LongTermPicNum = %d", + long_term_pic_num); + return -1; +} + +static void +exec_picture_refs_modification_1( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr, + guint list +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstH264PPS * const pps = slice_hdr->pps; + GstH264SPS * const sps = pps->sequence; + GstH264RefPicListModification *ref_pic_list_modification; + guint num_ref_pic_list_modifications; + GstVaapiPictureH264 **ref_list; + guint *ref_list_count_ptr, ref_list_count, ref_list_idx = 0; + guint i, j, n, num_refs; + gint found_ref_idx; + gint32 MaxPicNum, CurrPicNum, picNumPred; + + GST_DEBUG("modification process of reference picture list %u", list); + + if (list == 0) { + ref_pic_list_modification = slice_hdr->ref_pic_list_modification_l0; + num_ref_pic_list_modifications = slice_hdr->n_ref_pic_list_modification_l0; + ref_list = priv->RefPicList0; + ref_list_count_ptr = &priv->RefPicList0_count; + num_refs = slice_hdr->num_ref_idx_l0_active_minus1 + 1; + } + else { + ref_pic_list_modification = slice_hdr->ref_pic_list_modification_l1; + num_ref_pic_list_modifications = slice_hdr->n_ref_pic_list_modification_l1; + ref_list = priv->RefPicList1; + ref_list_count_ptr = &priv->RefPicList1_count; + num_refs = slice_hdr->num_ref_idx_l1_active_minus1 + 1; + } + ref_list_count = *ref_list_count_ptr; + + if (picture->field_pic_flag) { + MaxPicNum = 1 << (sps->log2_max_frame_num_minus4 + 5); // 2 * MaxFrameNum + CurrPicNum = 2 * slice_hdr->frame_num + 1; // 2 * frame_num + 1 + } + else { + MaxPicNum = 1 << (sps->log2_max_frame_num_minus4 + 4); // MaxFrameNum + CurrPicNum = slice_hdr->frame_num; // frame_num + } + + picNumPred = CurrPicNum; + + for (i = 0; i < num_ref_pic_list_modifications; i++) { + GstH264RefPicListModification * const l = &ref_pic_list_modification[i]; + if (l->modification_of_pic_nums_idc == 3) + break; + + /* 8.2.4.3.1 - Short-term reference pictures */ + if (l->modification_of_pic_nums_idc == 0 || l->modification_of_pic_nums_idc == 1) { + gint32 abs_diff_pic_num = l->value.abs_diff_pic_num_minus1 + 1; + gint32 picNum, picNumNoWrap; + + // (8-34) + if (l->modification_of_pic_nums_idc == 0) { + picNumNoWrap = picNumPred - abs_diff_pic_num; + if (picNumNoWrap < 0) + picNumNoWrap += MaxPicNum; + } + + // (8-35) + else { + picNumNoWrap = picNumPred + abs_diff_pic_num; + if (picNumNoWrap >= MaxPicNum) + picNumNoWrap -= MaxPicNum; + } + picNumPred = picNumNoWrap; + + // (8-36) + picNum = picNumNoWrap; + if (picNum > CurrPicNum) + picNum -= MaxPicNum; + + // (8-37) + for (j = num_refs; j > ref_list_idx; j--) + ref_list[j] = ref_list[j - 1]; + found_ref_idx = find_short_term_reference(decoder, picNum); + ref_list[ref_list_idx++] = + found_ref_idx >= 0 ? priv->short_ref[found_ref_idx] : NULL; + n = ref_list_idx; + for (j = ref_list_idx; j <= num_refs; j++) { + gint32 PicNumF; + if (!ref_list[j]) + continue; + PicNumF = ref_list[j]->is_long_term ? + MaxPicNum : ref_list[j]->pic_num; + if (PicNumF != picNum) + ref_list[n++] = ref_list[j]; + } + } + + /* 8.2.4.3.2 - Long-term reference pictures */ + else { + + for (j = num_refs; j > ref_list_idx; j--) + ref_list[j] = ref_list[j - 1]; + found_ref_idx = + find_long_term_reference(decoder, l->value.long_term_pic_num); + ref_list[ref_list_idx++] = + found_ref_idx >= 0 ? priv->long_ref[found_ref_idx] : NULL; + n = ref_list_idx; + for (j = ref_list_idx; j <= num_refs; j++) { + gint32 LongTermPicNumF; + if (!ref_list[j]) + continue; + LongTermPicNumF = ref_list[j]->is_long_term ? + ref_list[j]->long_term_pic_num : INT_MAX; + if (LongTermPicNumF != l->value.long_term_pic_num) + ref_list[n++] = ref_list[j]; + } + } + } + +#if DEBUG + for (i = 0; i < num_refs; i++) + if (!ref_list[i]) + GST_ERROR("list %u entry %u is empty", list, i); +#endif + *ref_list_count_ptr = num_refs; +} + +/* 8.2.4.3 - Modification process for reference picture lists */ +static void +exec_picture_refs_modification( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr +) +{ + GST_DEBUG("execute ref_pic_list_modification()"); + + /* RefPicList0 */ + if (!GST_H264_IS_I_SLICE(slice_hdr) && !GST_H264_IS_SI_SLICE(slice_hdr) && + slice_hdr->ref_pic_list_modification_flag_l0) + exec_picture_refs_modification_1(decoder, picture, slice_hdr, 0); + + /* RefPicList1 */ + if (GST_H264_IS_B_SLICE(slice_hdr) && + slice_hdr->ref_pic_list_modification_flag_l1) + exec_picture_refs_modification_1(decoder, picture, slice_hdr, 1); +} + +static gboolean +init_picture_refs( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiPicture * const base_picture = &picture->base; + guint i, num_refs; + + init_picture_refs_pic_num(decoder, picture, slice_hdr); + + priv->RefPicList0_count = 0; + priv->RefPicList1_count = 0; + + switch (base_picture->type) { + case GST_VAAPI_PICTURE_TYPE_P: + case GST_VAAPI_PICTURE_TYPE_SP: + init_picture_refs_p_slice(decoder, picture, slice_hdr); + break; + case GST_VAAPI_PICTURE_TYPE_B: + init_picture_refs_b_slice(decoder, picture, slice_hdr); + break; + default: + break; + } + + exec_picture_refs_modification(decoder, picture, slice_hdr); + + switch (base_picture->type) { + case GST_VAAPI_PICTURE_TYPE_B: + num_refs = 1 + slice_hdr->num_ref_idx_l1_active_minus1; + for (i = priv->RefPicList1_count; i < num_refs; i++) + priv->RefPicList1[i] = NULL; + priv->RefPicList1_count = num_refs; + + // fall-through + case GST_VAAPI_PICTURE_TYPE_P: + case GST_VAAPI_PICTURE_TYPE_SP: + num_refs = 1 + slice_hdr->num_ref_idx_l0_active_minus1; + for (i = priv->RefPicList0_count; i < num_refs; i++) + priv->RefPicList0[i] = NULL; + priv->RefPicList0_count = num_refs; + break; + default: + break; + } + return TRUE; +} + +static gboolean +init_picture( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr, + GstH264NalUnit *nalu +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiPicture * const base_picture = &picture->base; + VAPictureH264 *pic; + guint i; + + priv->frame_num = slice_hdr->frame_num; + picture->frame_num = priv->frame_num; + picture->frame_num_wrap = priv->frame_num; + picture->is_idr = nalu->type == GST_H264_NAL_SLICE_IDR; + picture->field_pic_flag = slice_hdr->field_pic_flag; + picture->bottom_field_flag = slice_hdr->bottom_field_flag; + picture->output_flag = TRUE; /* XXX: conformant to Annex A only */ + base_picture->pts = gst_adapter_prev_timestamp(priv->adapter, NULL); + + /* Reset decoder state for IDR pictures */ + if (picture->is_idr) { + GST_DEBUG(""); + clear_references(decoder, priv->short_ref, &priv->short_ref_count); + clear_references(decoder, priv->long_ref, &priv->long_ref_count ); + priv->prev_poc_msb = 0; + priv->prev_poc_lsb = 0; + } + + /* Initialize VA picture info */ + pic = &picture->info; + pic->picture_id = picture->base.surface_id; + pic->frame_idx = priv->frame_num; + if (picture->field_pic_flag) { + if (picture->bottom_field_flag) + pic->flags |= VA_PICTURE_H264_BOTTOM_FIELD; + else + pic->flags |= VA_PICTURE_H264_TOP_FIELD; + } + + /* Initialize base picture */ + switch (slice_hdr->type % 5) { + case GST_H264_P_SLICE: + base_picture->type = GST_VAAPI_PICTURE_TYPE_P; + break; + case GST_H264_B_SLICE: + base_picture->type = GST_VAAPI_PICTURE_TYPE_B; + break; + case GST_H264_I_SLICE: + base_picture->type = GST_VAAPI_PICTURE_TYPE_I; + break; + case GST_H264_SP_SLICE: + base_picture->type = GST_VAAPI_PICTURE_TYPE_SP; + break; + case GST_H264_SI_SLICE: + base_picture->type = GST_VAAPI_PICTURE_TYPE_SI; + break; + } + + if (nalu->ref_idc) { + GstH264DecRefPicMarking * const dec_ref_pic_marking = + &slice_hdr->dec_ref_pic_marking; + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + if (picture->is_idr) { + if (dec_ref_pic_marking->long_term_reference_flag) + picture->is_long_term = TRUE; + } + else if (dec_ref_pic_marking->adaptive_ref_pic_marking_mode_flag) { + for (i = 0; i < dec_ref_pic_marking->n_ref_pic_marking; i++) { + GstH264RefPicMarking * const ref_pic_marking = + &dec_ref_pic_marking->ref_pic_marking[i]; + switch (ref_pic_marking->memory_management_control_operation) { + case 3: + case 6: + picture->is_long_term = TRUE; + pic->frame_idx = ref_pic_marking->long_term_frame_idx; + break; + case 5: + picture->has_mmco_5 = TRUE; + break; + } + } + } + if (picture->is_long_term) + pic->flags |= VA_PICTURE_H264_LONG_TERM_REFERENCE; + else + pic->flags |= VA_PICTURE_H264_SHORT_TERM_REFERENCE; + } + + init_picture_poc(decoder, picture, slice_hdr); + if (!init_picture_refs(decoder, picture, slice_hdr)) { + GST_DEBUG("failed to initialize references"); + return FALSE; + } + return TRUE; +} + +/* 8.2.5.3 - Sliding window decoded reference picture marking process */ +static gboolean +exec_ref_pic_marking_sliding_window(GstVaapiDecoderH264 *decoder) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstH264SPS * const sps = priv->sps; + guint i, max_num_ref_frames, lowest_frame_num_index; + gint32 lowest_frame_num; + + GST_DEBUG("reference picture marking process (sliding window)"); + + max_num_ref_frames = sps->num_ref_frames; + if (max_num_ref_frames == 0) + max_num_ref_frames = 1; + + if (priv->short_ref_count + priv->long_ref_count < max_num_ref_frames) + return TRUE; + if (priv->short_ref_count < 1) + return FALSE; + + lowest_frame_num = priv->short_ref[0]->frame_num_wrap; + lowest_frame_num_index = 0; + for (i = 1; i < priv->short_ref_count; i++) { + if (priv->short_ref[i]->frame_num_wrap < lowest_frame_num) { + lowest_frame_num = priv->short_ref[i]->frame_num_wrap; + lowest_frame_num_index = i; + } + } + + remove_reference_at( + decoder, + priv->short_ref, &priv->short_ref_count, + lowest_frame_num_index + ); + return TRUE; +} + +/* 8.2.5.4. Adaptive memory control decoded reference picture marking process */ +static gboolean +exec_ref_pic_marking_adaptive( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264DecRefPicMarking *dec_ref_pic_marking +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + gint32 pic_num, ref_idx; + guint i; + + GST_DEBUG("reference picture marking process (adaptive memory control)"); + + for (i = 0; i < dec_ref_pic_marking->n_ref_pic_marking; i++) { + GstH264RefPicMarking * const ref_pic_marking = + &dec_ref_pic_marking->ref_pic_marking[i]; + + switch (ref_pic_marking->memory_management_control_operation) { + case 1: + // Mark short-term reference picture as "unused for reference" + if (!picture->field_pic_flag) + pic_num = picture->frame_num_wrap; + else + pic_num = 2 * picture->frame_num_wrap + 1; + pic_num -= ref_pic_marking->difference_of_pic_nums_minus1 + 1; + ref_idx = find_short_term_reference(decoder, pic_num); + if (ref_idx < 0) + break; + remove_reference_at( + decoder, + priv->short_ref, &priv->short_ref_count, + ref_idx + ); + break; + case 2: + // Mark long-term reference picture as "unused for reference" + pic_num = picture->long_term_pic_num; + ref_idx = find_long_term_reference(decoder, pic_num); + if (ref_idx < 0) + break; + remove_reference_at( + decoder, + priv->long_ref, &priv->long_ref_count, + ref_idx + ); + break; + case 3: + // Assign LongTermFrameIdx to a short-term reference picture + if (!picture->field_pic_flag) + pic_num = picture->frame_num_wrap; + else + pic_num = 2 * picture->frame_num_wrap + 1; + pic_num -= ref_pic_marking->difference_of_pic_nums_minus1 + 1; + ref_idx = find_short_term_reference(decoder, pic_num); + if (ref_idx < 0) + break; + break; + case 5: + // Mark all reference pictures as "unused for reference" + clear_references(decoder, priv->short_ref, &priv->short_ref_count); + clear_references(decoder, priv->long_ref, &priv->long_ref_count ); + break; + default: + g_assert(0 && "unhandled MMCO"); + break; + } + } + return TRUE; +} + +/* 8.2.5 - Execute reference picture marking process */ +static gboolean +exec_ref_pic_marking(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiPictureH264 **picture_ptr; + + if (!GST_VAAPI_PICTURE_IS_REFERENCE(picture)) + return TRUE; + + if (!picture->is_idr) { + GstH264DecRefPicMarking * const dec_ref_pic_marking = + get_dec_ref_pic_marking(picture); + if (dec_ref_pic_marking->adaptive_ref_pic_marking_mode_flag) { + if (!exec_ref_pic_marking_adaptive(decoder, picture, dec_ref_pic_marking)) + return FALSE; + } + else { + if (!exec_ref_pic_marking_sliding_window(decoder)) + return FALSE; + } + } + + if (picture->is_long_term) + picture_ptr = &priv->long_ref[priv->long_ref_count++]; + else + picture_ptr = &priv->short_ref[priv->short_ref_count++]; + gst_vaapi_picture_replace(picture_ptr, picture); + return TRUE; +} + +/* Update picture order count */ +static void +exit_picture_poc(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstH264SPS * const sps = priv->sps; + + switch (sps->pic_order_cnt_type) { + case 0: + if (!GST_VAAPI_PICTURE_IS_REFERENCE(picture)) + break; + if (picture->has_mmco_5) { + priv->prev_poc_msb = 0; + if (!picture->field_pic_flag || !picture->bottom_field_flag) + priv->prev_poc_lsb = picture->info.TopFieldOrderCnt; + else + priv->prev_poc_lsb = 0; + } + else { + priv->prev_poc_msb = priv->poc_msb; + priv->prev_poc_lsb = priv->poc_lsb; + } + break; + case 1: + case 2: + priv->prev_frame_num = priv->frame_num; + if (picture->has_mmco_5) + priv->prev_frame_num_offset = 0; + else + priv->prev_frame_num_offset = priv->frame_num_offset; + break; + } +} + +static inline gboolean +exit_picture(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture) +{ + /* Update picture order count */ + exit_picture_poc(decoder, picture); + + /* Decoded reference picture marking process */ + if (!exec_ref_pic_marking(decoder, picture)) + return FALSE; + return TRUE; +} + +static void +vaapi_init_picture(VAPictureH264 *pic) +{ + pic->picture_id = VA_INVALID_ID; + pic->frame_idx = 0; + pic->flags = VA_PICTURE_H264_INVALID; + pic->TopFieldOrderCnt = 0; + pic->BottomFieldOrderCnt = 0; +} + +static gboolean +fill_picture( + GstVaapiDecoderH264 *decoder, + GstVaapiPictureH264 *picture, + GstH264SliceHdr *slice_hdr, + GstH264NalUnit *nalu +) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiPicture * const base_picture = &picture->base; + GstH264SPS * const sps = priv->sps; + GstH264PPS * const pps = priv->pps; + VAPictureParameterBufferH264 * const pic_param = base_picture->param; + guint i, n; + + /* Fill in VAPictureParameterBufferH264 */ + pic_param->CurrPic = picture->info; + for (i = 0, n = 0; i < priv->short_ref_count; i++) + pic_param->ReferenceFrames[n++] = priv->short_ref[i]->info; + for (i = 0; i < priv->long_ref_count; i++) + pic_param->ReferenceFrames[n++] = priv->long_ref[i]->info; + for (; n < G_N_ELEMENTS(pic_param->ReferenceFrames); n++) + vaapi_init_picture(&pic_param->ReferenceFrames[n]); + +#define COPY_FIELD(s, f) \ + pic_param->f = (s)->f + +#define COPY_BFM(a, s, f) \ + pic_param->a.bits.f = (s)->f + + pic_param->picture_width_in_mbs_minus1 = priv->mb_width - 1; + pic_param->picture_height_in_mbs_minus1 = priv->mb_height - 1; + pic_param->frame_num = priv->frame_num; + + COPY_FIELD(sps, bit_depth_luma_minus8); + COPY_FIELD(sps, bit_depth_chroma_minus8); + COPY_FIELD(sps, num_ref_frames); + COPY_FIELD(pps, num_slice_groups_minus1); + COPY_FIELD(pps, slice_group_map_type); + COPY_FIELD(pps, slice_group_change_rate_minus1); + COPY_FIELD(pps, pic_init_qp_minus26); + COPY_FIELD(pps, pic_init_qs_minus26); + COPY_FIELD(pps, chroma_qp_index_offset); + COPY_FIELD(pps, second_chroma_qp_index_offset); + + pic_param->seq_fields.value = 0; /* reset all bits */ + pic_param->seq_fields.bits.residual_colour_transform_flag = sps->separate_colour_plane_flag; + pic_param->seq_fields.bits.MinLumaBiPredSize8x8 = sps->level_idc >= 31; /* A.3.3.2 */ + + COPY_BFM(seq_fields, sps, chroma_format_idc); + COPY_BFM(seq_fields, sps, gaps_in_frame_num_value_allowed_flag); + COPY_BFM(seq_fields, sps, frame_mbs_only_flag); + COPY_BFM(seq_fields, sps, mb_adaptive_frame_field_flag); + COPY_BFM(seq_fields, sps, direct_8x8_inference_flag); + COPY_BFM(seq_fields, sps, log2_max_frame_num_minus4); + COPY_BFM(seq_fields, sps, pic_order_cnt_type); + COPY_BFM(seq_fields, sps, log2_max_pic_order_cnt_lsb_minus4); + COPY_BFM(seq_fields, sps, delta_pic_order_always_zero_flag); + + pic_param->pic_fields.value = 0; /* reset all bits */ + pic_param->pic_fields.bits.field_pic_flag = slice_hdr->field_pic_flag; + pic_param->pic_fields.bits.reference_pic_flag = GST_VAAPI_PICTURE_IS_REFERENCE(picture); + + COPY_BFM(pic_fields, pps, entropy_coding_mode_flag); + COPY_BFM(pic_fields, pps, weighted_pred_flag); + COPY_BFM(pic_fields, pps, weighted_bipred_idc); + COPY_BFM(pic_fields, pps, transform_8x8_mode_flag); + COPY_BFM(pic_fields, pps, constrained_intra_pred_flag); + COPY_BFM(pic_fields, pps, pic_order_present_flag); + COPY_BFM(pic_fields, pps, deblocking_filter_control_present_flag); + COPY_BFM(pic_fields, pps, redundant_pic_cnt_present_flag); + return TRUE; +} + +static gboolean +fill_quant_matrix(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + VAIQMatrixBufferH264 * const iq_matrix = picture->base.iq_matrix->param; + + /* XXX: we can only support 4:2:0 or 4:2:2 since ScalingLists8x8[] + is not large enough to hold lists for 4:4:4 */ + if (priv->sps->chroma_format_idc == 3 && + sizeof(iq_matrix->ScalingList8x8) != sizeof(priv->scaling_list_8x8)) + return FALSE; + + /* Fill in VAIQMatrixBufferH264 */ + memcpy(iq_matrix->ScalingList4x4, priv->scaling_list_4x4, + sizeof(iq_matrix->ScalingList4x4)); + memcpy(iq_matrix->ScalingList8x8, priv->scaling_list_8x8, + sizeof(iq_matrix->ScalingList8x8)); + return TRUE; +} + +static GstVaapiDecoderStatus +decode_picture(GstVaapiDecoderH264 *decoder, GstH264NalUnit *nalu, GstH264SliceHdr *slice_hdr) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiPictureH264 *picture; + GstVaapiDecoderStatus status; + GstH264PPS * const pps = slice_hdr->pps; + GstH264SPS * const sps = pps->sequence; + + status = ensure_context(decoder, sps); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_DEBUG("failed to reset context"); + return status; + } + + if (priv->current_picture && !decode_current_picture(decoder)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + picture = gst_vaapi_picture_h264_new(decoder); + if (!picture) { + GST_DEBUG("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + priv->current_picture = picture; + + picture->base.iq_matrix = GST_VAAPI_IQ_MATRIX_NEW(H264, decoder); + if (!picture->base.iq_matrix) { + GST_DEBUG("failed to allocate IQ matrix"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + status = ensure_quant_matrix(decoder, pps); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_DEBUG("failed to reset quantizer matrix"); + return status; + } + + priv->sps = sps; + priv->pps = pps; + + if (!init_picture(decoder, picture, slice_hdr, nalu)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + if (!fill_picture(decoder, picture, slice_hdr, nalu)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static gboolean +decode_picture_end(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture) +{ + if (!fill_quant_matrix(decoder, picture)) + return FALSE; + if (!exit_picture(decoder, picture)) + return FALSE; + if (!dpb_add(decoder, picture)) + return FALSE; + return TRUE; +} + +#ifndef HAVE_GST_H264_SLICE_HDR_EPB_COUNT +static guint +get_epb_count(const guint8 *buf, guint buf_size, guint header_size) +{ + guint i, n = 0; + + if (buf_size > header_size) + buf_size = header_size; + + for (i = 2; i < buf_size; i++) { + if (!buf[i - 2] && !buf[i - 1] && buf[i] == 0x03) + i += 2, n++; + } + return n; +} +#endif + +static inline guint +get_slice_data_bit_offset(GstH264SliceHdr *slice_hdr, GstH264NalUnit *nalu) +{ + guint epb_count; + +#ifdef HAVE_GST_H264_SLICE_HDR_EPB_COUNT + epb_count = slice_hdr->n_emulation_prevention_bytes; +#else + epb_count = get_epb_count( + nalu->data + nalu->offset, + nalu->size, + slice_hdr->header_size / 8 + ); +#endif + return 8 /* nal_unit_type */ + slice_hdr->header_size - epb_count * 8; +} + +static gboolean +fill_pred_weight_table(GstVaapiDecoderH264 *decoder, GstVaapiSliceH264 *slice) +{ + GstH264SliceHdr * const slice_hdr = &slice->slice_hdr; + GstH264PPS * const pps = slice_hdr->pps; + GstH264SPS * const sps = pps->sequence; + GstH264PredWeightTable * const w = &slice_hdr->pred_weight_table; + VASliceParameterBufferH264 * const slice_param = slice->base.param; + guint num_weight_tables = 0; + gint i, j; + + if (pps->weighted_pred_flag && + (GST_H264_IS_P_SLICE(slice_hdr) || GST_H264_IS_SP_SLICE(slice_hdr))) + num_weight_tables = 1; + else if (pps->weighted_bipred_idc == 1 && GST_H264_IS_B_SLICE(slice_hdr)) + num_weight_tables = 2; + else + num_weight_tables = 0; + + slice_param->luma_log2_weight_denom = w->luma_log2_weight_denom; + slice_param->chroma_log2_weight_denom = w->chroma_log2_weight_denom; + slice_param->luma_weight_l0_flag = 0; + slice_param->chroma_weight_l0_flag = 0; + slice_param->luma_weight_l1_flag = 0; + slice_param->chroma_weight_l1_flag = 0; + + if (num_weight_tables < 1) + return TRUE; + + slice_param->luma_weight_l0_flag = 1; + for (i = 0; i <= slice_param->num_ref_idx_l0_active_minus1; i++) { + slice_param->luma_weight_l0[i] = w->luma_weight_l0[i]; + slice_param->luma_offset_l0[i] = w->luma_offset_l0[i]; + } + + slice_param->chroma_weight_l0_flag = sps->chroma_array_type != 0; + if (slice_param->chroma_weight_l0_flag) { + for (i = 0; i <= slice_param->num_ref_idx_l0_active_minus1; i++) { + for (j = 0; j < 2; j++) { + slice_param->chroma_weight_l0[i][j] = w->chroma_weight_l0[i][j]; + slice_param->chroma_offset_l0[i][j] = w->chroma_offset_l0[i][j]; + } + } + } + + if (num_weight_tables < 2) + return TRUE; + + slice_param->luma_weight_l1_flag = 1; + for (i = 0; i <= slice_param->num_ref_idx_l1_active_minus1; i++) { + slice_param->luma_weight_l1[i] = w->luma_weight_l1[i]; + slice_param->luma_offset_l1[i] = w->luma_offset_l1[i]; + } + + slice_param->chroma_weight_l1_flag = sps->chroma_array_type != 0; + if (slice_param->chroma_weight_l1_flag) { + for (i = 0; i <= slice_param->num_ref_idx_l1_active_minus1; i++) { + for (j = 0; j < 2; j++) { + slice_param->chroma_weight_l1[i][j] = w->chroma_weight_l1[i][j]; + slice_param->chroma_offset_l1[i][j] = w->chroma_offset_l1[i][j]; + } + } + } + return TRUE; +} + +static gboolean +fill_RefPicList(GstVaapiDecoderH264 *decoder, GstVaapiSliceH264 *slice) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstH264SliceHdr * const slice_hdr = &slice->slice_hdr; + VASliceParameterBufferH264 * const slice_param = slice->base.param; + guint i, num_ref_lists = 0; + + slice_param->num_ref_idx_l0_active_minus1 = 0; + slice_param->num_ref_idx_l1_active_minus1 = 0; + + if (GST_H264_IS_B_SLICE(slice_hdr)) + num_ref_lists = 2; + else if (GST_H264_IS_I_SLICE(slice_hdr)) + num_ref_lists = 0; + else + num_ref_lists = 1; + + if (num_ref_lists < 1) + return TRUE; + + slice_param->num_ref_idx_l0_active_minus1 = + slice_hdr->num_ref_idx_l0_active_minus1; + + for (i = 0; i < priv->RefPicList0_count && priv->RefPicList0[i]; i++) + slice_param->RefPicList0[i] = priv->RefPicList0[i]->info; + for (; i <= slice_param->num_ref_idx_l0_active_minus1; i++) + vaapi_init_picture(&slice_param->RefPicList0[i]); + + if (num_ref_lists < 2) + return TRUE; + + slice_param->num_ref_idx_l1_active_minus1 = + slice_hdr->num_ref_idx_l1_active_minus1; + + for (i = 0; i < priv->RefPicList1_count && priv->RefPicList1[i]; i++) + slice_param->RefPicList1[i] = priv->RefPicList1[i]->info; + for (; i <= slice_param->num_ref_idx_l1_active_minus1; i++) + vaapi_init_picture(&slice_param->RefPicList1[i]); + return TRUE; +} + +static gboolean +fill_slice( + GstVaapiDecoderH264 *decoder, + GstVaapiSliceH264 *slice, + GstH264NalUnit *nalu +) +{ + GstH264SliceHdr * const slice_hdr = &slice->slice_hdr; + VASliceParameterBufferH264 * const slice_param = slice->base.param; + + /* Fill in VASliceParameterBufferH264 */ + slice_param->slice_data_bit_offset = get_slice_data_bit_offset(slice_hdr, nalu); + slice_param->first_mb_in_slice = slice_hdr->first_mb_in_slice; + slice_param->slice_type = slice_hdr->type % 5; + slice_param->direct_spatial_mv_pred_flag = slice_hdr->direct_spatial_mv_pred_flag; + slice_param->cabac_init_idc = slice_hdr->cabac_init_idc; + slice_param->slice_qp_delta = slice_hdr->slice_qp_delta; + slice_param->disable_deblocking_filter_idc = slice_hdr->disable_deblocking_filter_idc; + slice_param->slice_alpha_c0_offset_div2 = slice_hdr->slice_alpha_c0_offset_div2; + slice_param->slice_beta_offset_div2 = slice_hdr->slice_beta_offset_div2; + + if (!fill_RefPicList(decoder, slice)) + return FALSE; + if (!fill_pred_weight_table(decoder, slice)) + return FALSE; + return TRUE; +} + +static GstVaapiDecoderStatus +decode_slice(GstVaapiDecoderH264 *decoder, GstH264NalUnit *nalu) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiDecoderStatus status; + GstVaapiPictureH264 *picture; + GstVaapiSliceH264 *slice = NULL; + GstH264SliceHdr *slice_hdr; + GstH264ParserResult result; + + GST_DEBUG("slice (%u bytes)", nalu->size); + + slice = gst_vaapi_slice_h264_new( + decoder, + nalu->data + nalu->offset, + nalu->size + ); + if (!slice) { + GST_DEBUG("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + slice_hdr = &slice->slice_hdr; + memset(slice_hdr, 0, sizeof(*slice_hdr)); + result = gst_h264_parser_parse_slice_hdr(priv->parser, nalu, slice_hdr, TRUE, TRUE); + if (result != GST_H264_PARSER_OK) { + status = get_status(result); + goto error; + } + + if (slice_hdr->first_mb_in_slice == 0) { + status = decode_picture(decoder, nalu, slice_hdr); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + goto error; + } + picture = priv->current_picture; + + priv->mb_x = slice_hdr->first_mb_in_slice % priv->mb_width; + priv->mb_y = slice_hdr->first_mb_in_slice / priv->mb_width; // FIXME: MBAFF or field + + if (!fill_slice(decoder, slice, nalu)) { + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + goto error; + } + gst_vaapi_picture_add_slice( + GST_VAAPI_PICTURE_CAST(picture), + GST_VAAPI_SLICE_CAST(slice) + ); + + /* Commit picture for decoding if we reached the last slice */ + if (++priv->mb_y >= priv->mb_height) { + if (!decode_current_picture(decoder)) { + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + goto error; + } + GST_DEBUG("done"); + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; + +error: + if (slice) + gst_mini_object_unref(GST_MINI_OBJECT(slice)); + return status; +} + +static GstVaapiDecoderStatus +decode_buffer(GstVaapiDecoderH264 *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiDecoderStatus status; + GstH264ParserResult result; + GstH264NalUnit nalu; + guchar *buf; + guint buf_size, ofs; + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + if (!buf && buf_size == 0) + return decode_sequence_end(decoder); + + gst_buffer_ref(buffer); + gst_adapter_push(priv->adapter, buffer); + + if (priv->sub_buffer) { + buffer = gst_buffer_merge(priv->sub_buffer, buffer); + if (!buffer) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + gst_buffer_unref(priv->sub_buffer); + priv->sub_buffer = NULL; + } + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + ofs = 0; + do { + if (priv->is_avc) { + result = gst_h264_parser_identify_nalu_avc( + priv->parser, + buf, ofs, buf_size, priv->nal_length_size, + &nalu + ); + } + else { + result = gst_h264_parser_identify_nalu( + priv->parser, + buf, ofs, buf_size, + &nalu + ); + } + status = get_status(result); + + if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA) { + priv->sub_buffer = gst_buffer_create_sub(buffer, ofs, buf_size - ofs); + break; + } + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + break; + + ofs = nalu.offset - ofs; + if (gst_adapter_available(priv->adapter) >= ofs) + gst_adapter_flush(priv->adapter, ofs); + + switch (nalu.type) { + case GST_H264_NAL_SLICE_IDR: + /* fall-through. IDR specifics are handled in init_picture() */ + case GST_H264_NAL_SLICE: + status = decode_slice(decoder, &nalu); + break; + case GST_H264_NAL_SPS: + status = decode_sps(decoder, &nalu); + break; + case GST_H264_NAL_PPS: + status = decode_pps(decoder, &nalu); + break; + case GST_H264_NAL_SEI: + status = decode_sei(decoder, &nalu); + break; + case GST_H264_NAL_SEQ_END: + status = decode_sequence_end(decoder); + break; + case GST_H264_NAL_AU_DELIMITER: + /* skip all Access Unit NALs */ + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + case GST_H264_NAL_FILLER_DATA: + /* skip all Filler Data NALs */ + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + default: + GST_DEBUG("unsupported NAL unit type %d", nalu.type); + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + } + + if (gst_adapter_available(priv->adapter) >= nalu.size) + gst_adapter_flush(priv->adapter, nalu.size); + ofs = nalu.offset + nalu.size; + } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS && ofs < buf_size); + return status; +} + +static GstVaapiDecoderStatus +decode_codec_data(GstVaapiDecoderH264 *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiDecoderStatus status; + GstH264NalUnit nalu; + GstH264ParserResult result; + guchar *buf; + guint buf_size; + guint i, ofs, num_sps, num_pps; + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + if (!buf || buf_size == 0) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (buf_size < 8) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + if (buf[0] != 1) { + GST_DEBUG("failed to decode codec-data, not in avcC format"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + priv->nal_length_size = (buf[4] & 0x03) + 1; + + num_sps = buf[5] & 0x1f; + ofs = 6; + + for (i = 0; i < num_sps; i++) { + result = gst_h264_parser_identify_nalu_avc( + priv->parser, + buf, ofs, buf_size, 2, + &nalu + ); + if (result != GST_H264_PARSER_OK) + return get_status(result); + + status = decode_sps(decoder, &nalu); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + ofs = nalu.offset + nalu.size; + } + + num_pps = buf[ofs]; + ofs++; + + for (i = 0; i < num_pps; i++) { + result = gst_h264_parser_identify_nalu_avc( + priv->parser, + buf, ofs, buf_size, 2, + &nalu + ); + if (result != GST_H264_PARSER_OK) + return get_status(result); + + status = decode_pps(decoder, &nalu); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + ofs = nalu.offset + nalu.size; + } + + priv->is_avc = TRUE; + return status; +} + +GstVaapiDecoderStatus +gst_vaapi_decoder_h264_decode(GstVaapiDecoder *base, GstBuffer *buffer) +{ + GstVaapiDecoderH264 * const decoder = GST_VAAPI_DECODER_H264(base); + GstVaapiDecoderH264Private * const priv = decoder->priv; + GstVaapiDecoderStatus status; + GstBuffer *codec_data; + + g_return_val_if_fail(priv->is_constructed, + GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED); + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_h264_open(decoder, buffer); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + + codec_data = GST_VAAPI_DECODER_CODEC_DATA(decoder); + if (codec_data) { + status = decode_codec_data(decoder, codec_data); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + } + return decode_buffer(decoder, buffer); +} + +static void +gst_vaapi_decoder_h264_finalize(GObject *object) +{ + GstVaapiDecoderH264 * const decoder = GST_VAAPI_DECODER_H264(object); + + gst_vaapi_decoder_h264_destroy(decoder); + + G_OBJECT_CLASS(gst_vaapi_decoder_h264_parent_class)->finalize(object); +} + +static void +gst_vaapi_decoder_h264_constructed(GObject *object) +{ + GstVaapiDecoderH264 * const decoder = GST_VAAPI_DECODER_H264(object); + GstVaapiDecoderH264Private * const priv = decoder->priv; + GObjectClass *parent_class; + + parent_class = G_OBJECT_CLASS(gst_vaapi_decoder_h264_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); + + priv->is_constructed = gst_vaapi_decoder_h264_create(decoder); +} + +static void +gst_vaapi_decoder_h264_class_init(GstVaapiDecoderH264Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiDecoderH264Private)); + + object_class->finalize = gst_vaapi_decoder_h264_finalize; + object_class->constructed = gst_vaapi_decoder_h264_constructed; + + decoder_class->decode = gst_vaapi_decoder_h264_decode; + decoder_class->clear_buffer = gst_vaapi_decoder_h264_clear_buffer; +} + +static void +gst_vaapi_decoder_h264_init(GstVaapiDecoderH264 *decoder) +{ + GstVaapiDecoderH264Private *priv; + + priv = GST_VAAPI_DECODER_H264_GET_PRIVATE(decoder); + decoder->priv = priv; + priv->parser = NULL; + priv->sps = &priv->last_sps; + priv->pps = &priv->last_pps; + priv->current_picture = NULL; + priv->dpb_count = 0; + priv->dpb_size = 0; + priv->profile = GST_VAAPI_PROFILE_H264_HIGH; + priv->short_ref_count = 0; + priv->long_ref_count = 0; + priv->RefPicList0_count = 0; + priv->RefPicList1_count = 0; + priv->nal_length_size = 0; + priv->width = 0; + priv->height = 0; + priv->mb_x = 0; + priv->mb_y = 0; + priv->mb_width = 0; + priv->mb_height = 0; + priv->adapter = NULL; + priv->sub_buffer = NULL; + priv->field_poc[0] = 0; + priv->field_poc[1] = 0; + priv->poc_msb = 0; + priv->poc_lsb = 0; + priv->prev_poc_msb = 0; + priv->prev_poc_lsb = 0; + priv->frame_num_offset = 0; + priv->prev_frame_num_offset = 0; + priv->frame_num = 0; + priv->prev_frame_num = 0; + priv->is_constructed = FALSE; + priv->is_opened = FALSE; + priv->is_avc = FALSE; + priv->has_context = FALSE; + + memset(priv->dpb, 0, sizeof(priv->dpb)); + memset(priv->short_ref, 0, sizeof(priv->short_ref)); + memset(priv->long_ref, 0, sizeof(priv->long_ref)); + memset(priv->RefPicList0, 0, sizeof(priv->RefPicList0)); + memset(priv->RefPicList1, 0, sizeof(priv->RefPicList1)); +} + +/** + * gst_vaapi_decoder_h264_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for MPEG-2 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_h264_new(GstVaapiDisplay *display, GstCaps *caps) +{ + GstVaapiDecoderH264 *decoder; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(GST_IS_CAPS(caps), NULL); + + decoder = g_object_new( + GST_VAAPI_TYPE_DECODER_H264, + "display", display, + "caps", caps, + NULL + ); + if (!decoder->priv->is_constructed) { + g_object_unref(decoder); + return NULL; + } + return GST_VAAPI_DECODER_CAST(decoder); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_h264.h b/gst-libs/gst/vaapi/gstvaapidecoder_h264.h new file mode 100644 index 0000000..79a08f1 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_h264.h @@ -0,0 +1,87 @@ +/* + * gstvaapidecoder_h264.h - H.264 decoder + * + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_H264_H +#define GST_VAAPI_DECODER_H264_H + +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DECODER_H264 \ + (gst_vaapi_decoder_h264_get_type()) + +#define GST_VAAPI_DECODER_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DECODER_H264, \ + GstVaapiDecoderH264)) + +#define GST_VAAPI_DECODER_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DECODER_H264, \ + GstVaapiDecoderH264Class)) + +#define GST_VAAPI_IS_DECODER_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DECODER_H264)) + +#define GST_VAAPI_IS_DECODER_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DECODER_H264)) + +#define GST_VAAPI_DECODER_H264_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DECODER_H264, \ + GstVaapiDecoderH264Class)) + +typedef struct _GstVaapiDecoderH264 GstVaapiDecoderH264; +typedef struct _GstVaapiDecoderH264Private GstVaapiDecoderH264Private; +typedef struct _GstVaapiDecoderH264Class GstVaapiDecoderH264Class; + +/** + * GstVaapiDecoderH264: + * + * A decoder based on H264. + */ +struct _GstVaapiDecoderH264 { + /*< private >*/ + GstVaapiDecoder parent_instance; + + GstVaapiDecoderH264Private *priv; +}; + +/** + * GstVaapiDecoderH264Class: + * + * A decoder class based on H264. + */ +struct _GstVaapiDecoderH264Class { + /*< private >*/ + GstVaapiDecoderClass parent_class; +}; + +GType +gst_vaapi_decoder_h264_get_type(void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_h264_new(GstVaapiDisplay *display, GstCaps *caps); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_H264_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c new file mode 100644 index 0000000..121f067 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c @@ -0,0 +1,718 @@ +/* + * gstvaapidecoder_jpeg.c - JPEG decoder + * + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidecoder_jpeg + * @short_description: JPEG decoder + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapicompat.h" +#include "gstvaapidecoder_jpeg.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiobject_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDecoderJpeg, + gst_vaapi_decoder_jpeg, + GST_VAAPI_TYPE_DECODER); + +#define GST_VAAPI_DECODER_JPEG_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DECODER_JPEG, \ + GstVaapiDecoderJpegPrivate)) + +struct _GstVaapiDecoderJpegPrivate { + GstVaapiProfile profile; + guint width; + guint height; + GstVaapiPicture *current_picture; + GstJpegFrameHdr frame_hdr; + GstJpegHuffmanTables huf_tables; + GstJpegQuantTables quant_tables; + gboolean has_huf_table; + gboolean has_quant_table; + guint mcu_restart; + guint is_opened : 1; + guint profile_changed : 1; + guint is_constructed : 1; +}; + +typedef struct _GstJpegScanSegment GstJpegScanSegment; +struct _GstJpegScanSegment { + guint header_offset; + guint header_size; + guint data_offset; + guint data_size; + guint is_valid : 1; +}; + +static void +gst_vaapi_decoder_jpeg_close(GstVaapiDecoderJpeg *decoder) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + + gst_vaapi_picture_replace(&priv->current_picture, NULL); + + /* Reset all */ + priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + priv->width = 0; + priv->height = 0; + priv->is_opened = FALSE; + priv->profile_changed = TRUE; +} + +static gboolean +gst_vaapi_decoder_jpeg_open(GstVaapiDecoderJpeg *decoder, GstBuffer *buffer) +{ + gst_vaapi_decoder_jpeg_close(decoder); + + return TRUE; +} + +static void +gst_vaapi_decoder_jpeg_destroy(GstVaapiDecoderJpeg *decoder) +{ + gst_vaapi_decoder_jpeg_close(decoder); +} + +static gboolean +gst_vaapi_decoder_jpeg_create(GstVaapiDecoderJpeg *decoder) +{ + if (!GST_VAAPI_DECODER_CODEC(decoder)) + return FALSE; + return TRUE; +} + +static GstVaapiDecoderStatus +ensure_context(GstVaapiDecoderJpeg *decoder) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + GstVaapiProfile profiles[2]; + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + guint i, n_profiles = 0; + gboolean reset_context = FALSE; + + if (priv->profile_changed) { + GST_DEBUG("profile changed"); + priv->profile_changed = FALSE; + reset_context = TRUE; + + profiles[n_profiles++] = priv->profile; + //if (priv->profile == GST_VAAPI_PROFILE_JPEG_EXTENDED) + // profiles[n_profiles++] = GST_VAAPI_PROFILE_JPEG_BASELINE; + + for (i = 0; i < n_profiles; i++) { + if (gst_vaapi_display_has_decoder(GST_VAAPI_DECODER_DISPLAY(decoder), + profiles[i], entrypoint)) + break; + } + if (i == n_profiles) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + priv->profile = profiles[i]; + } + + if (reset_context) { + reset_context = gst_vaapi_decoder_ensure_context( + GST_VAAPI_DECODER(decoder), + priv->profile, + entrypoint, + priv->width, + priv->height, + GST_DECODER_DEFAULT_SURFACES_COUNT + ); + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static gboolean +decode_current_picture(GstVaapiDecoderJpeg *decoder) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + GstVaapiPicture * const picture = priv->current_picture; + gboolean success = TRUE; + + if (picture) { + if (!gst_vaapi_picture_decode(picture)) + success = FALSE; + else if (!gst_vaapi_picture_output(picture)) + success = FALSE; + gst_vaapi_picture_replace(&priv->current_picture, NULL); + } + return success; +} + +static gboolean +fill_picture( + GstVaapiDecoderJpeg *decoder, + GstVaapiPicture *picture, + GstJpegFrameHdr *jpeg_frame_hdr +) +{ + VAPictureParameterBufferJPEGBaseline *pic_param = picture->param; + guint i; + + g_assert(pic_param); + + memset(pic_param, 0, sizeof(VAPictureParameterBufferJPEGBaseline)); + pic_param->picture_width = jpeg_frame_hdr->width; + pic_param->picture_height = jpeg_frame_hdr->height; + + pic_param->num_components = jpeg_frame_hdr->num_components; + if (jpeg_frame_hdr->num_components > 4) + return FALSE; + for (i = 0; i < pic_param->num_components; i++) { + pic_param->components[i].component_id = + jpeg_frame_hdr->components[i].identifier; + pic_param->components[i].h_sampling_factor = + jpeg_frame_hdr->components[i].horizontal_factor; + pic_param->components[i].v_sampling_factor = + jpeg_frame_hdr->components[i].vertical_factor; + pic_param->components[i].quantiser_table_selector = + jpeg_frame_hdr->components[i].quant_table_selector; + } + return TRUE; +} + +static gboolean +fill_quantization_table( + GstVaapiDecoderJpeg *decoder, + GstVaapiPicture *picture +) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + VAIQMatrixBufferJPEGBaseline *iq_matrix; + guint i, j, num_tables; + + if (!priv->has_quant_table) + gst_jpeg_get_default_quantization_tables(&priv->quant_tables); + + picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW(JPEGBaseline, decoder); + g_assert(picture->iq_matrix); + iq_matrix = picture->iq_matrix->param; + + num_tables = MIN(G_N_ELEMENTS(iq_matrix->quantiser_table), + GST_JPEG_MAX_QUANT_ELEMENTS); + + for (i = 0; i < num_tables; i++) { + GstJpegQuantTable * const quant_table = + &priv->quant_tables.quant_tables[i]; + + iq_matrix->load_quantiser_table[i] = quant_table->valid; + if (!iq_matrix->load_quantiser_table[i]) + continue; + + g_assert(quant_table->quant_precision == 0); + for (j = 0; j < GST_JPEG_MAX_QUANT_ELEMENTS; j++) + iq_matrix->quantiser_table[i][j] = quant_table->quant_table[j]; + iq_matrix->load_quantiser_table[i] = 1; + quant_table->valid = FALSE; + } + return TRUE; +} + +static gboolean +fill_huffman_table( + GstVaapiDecoderJpeg *decoder, + GstVaapiPicture *picture +) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + GstJpegHuffmanTables * const huf_tables = &priv->huf_tables; + VAHuffmanTableBufferJPEGBaseline *huffman_table; + guint i, num_tables; + + if (!priv->has_huf_table) + gst_jpeg_get_default_huffman_tables(&priv->huf_tables); + + picture->huf_table = GST_VAAPI_HUFFMAN_TABLE_NEW(JPEGBaseline, decoder); + g_assert(picture->huf_table); + huffman_table = picture->huf_table->param; + + num_tables = MIN(G_N_ELEMENTS(huffman_table->huffman_table), + GST_JPEG_MAX_SCAN_COMPONENTS); + + for (i = 0; i < num_tables; i++) { + huffman_table->load_huffman_table[i] = + huf_tables->dc_tables[i].valid && huf_tables->ac_tables[i].valid; + if (!huffman_table->load_huffman_table[i]) + continue; + + memcpy(huffman_table->huffman_table[i].num_dc_codes, + huf_tables->dc_tables[i].huf_bits, + sizeof(huffman_table->huffman_table[i].num_dc_codes)); + memcpy(huffman_table->huffman_table[i].dc_values, + huf_tables->dc_tables[i].huf_values, + sizeof(huffman_table->huffman_table[i].dc_values)); + memcpy(huffman_table->huffman_table[i].num_ac_codes, + huf_tables->ac_tables[i].huf_bits, + sizeof(huffman_table->huffman_table[i].num_ac_codes)); + memcpy(huffman_table->huffman_table[i].ac_values, + huf_tables->ac_tables[i].huf_values, + sizeof(huffman_table->huffman_table[i].ac_values)); + memset(huffman_table->huffman_table[i].pad, + 0, + sizeof(huffman_table->huffman_table[i].pad)); + } + return TRUE; +} + +static guint +get_max_horizontal_samples(GstJpegFrameHdr *frame_hdr) +{ + guint i, max_factor = 0; + + for (i = 0; i < frame_hdr->num_components; i++) { + if (frame_hdr->components[i].horizontal_factor > max_factor) + max_factor = frame_hdr->components[i].horizontal_factor; + } + return max_factor; +} + +static guint +get_max_vertical_samples(GstJpegFrameHdr *frame_hdr) +{ + guint i, max_factor = 0; + + for (i = 0; i < frame_hdr->num_components; i++) { + if (frame_hdr->components[i].vertical_factor > max_factor) + max_factor = frame_hdr->components[i].vertical_factor; + } + return max_factor; +} + +static GstVaapiDecoderStatus +decode_picture( + GstVaapiDecoderJpeg *decoder, + guint8 profile, + guchar *buf, + guint buf_size, + GstClockTime pts +) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + GstJpegFrameHdr * const frame_hdr = &priv->frame_hdr; + GstVaapiPicture *picture; + GstVaapiDecoderStatus status; + + switch (profile) { + case GST_JPEG_MARKER_SOF_MIN: + priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + break; + default: + GST_ERROR("unsupported profile %d", profile); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + memset(frame_hdr, 0, sizeof(*frame_hdr)); + if (!gst_jpeg_parse_frame_hdr(frame_hdr, buf, buf_size, 0)) { + GST_ERROR("failed to parse image"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + priv->height = frame_hdr->height; + priv->width = frame_hdr->width; + + status = ensure_context(decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_ERROR("failed to reset context"); + return status; + } + + if (priv->current_picture && !decode_current_picture(decoder)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + picture = GST_VAAPI_PICTURE_NEW(JPEGBaseline, decoder); + if (!picture) { + GST_ERROR("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_replace(&priv->current_picture, picture); + gst_vaapi_picture_unref(picture); + + if (!fill_picture(decoder, picture, frame_hdr)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + /* Update presentation time */ + picture->pts = pts; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_huffman_table( + GstVaapiDecoderJpeg *decoder, + guchar *buf, + guint buf_size +) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + + if (!gst_jpeg_parse_huffman_table(&priv->huf_tables, buf, buf_size, 0)) { + GST_DEBUG("failed to parse Huffman table"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + priv->has_huf_table = TRUE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_quant_table( + GstVaapiDecoderJpeg *decoder, + guchar *buf, + guint buf_size +) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + + if (!gst_jpeg_parse_quant_table(&priv->quant_tables, buf, buf_size, 0)) { + GST_DEBUG("failed to parse quantization table"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + priv->has_quant_table = TRUE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_restart_interval( + GstVaapiDecoderJpeg *decoder, + guchar *buf, + guint buf_size +) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + + if (!gst_jpeg_parse_restart_interval(&priv->mcu_restart, buf, buf_size, 0)) { + GST_DEBUG("failed to parse restart interval"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_scan( + GstVaapiDecoderJpeg *decoder, + guchar *scan_header, + guint scan_header_size, + guchar *scan_data, + guint scan_data_size) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + GstVaapiPicture *picture = priv->current_picture; + VASliceParameterBufferJPEGBaseline *slice_param; + GstVaapiSlice *gst_slice; + guint total_h_samples, total_v_samples; + GstJpegScanHdr scan_hdr; + guint i; + + if (!picture) { + GST_ERROR("There is no VAPicture before decoding scan."); + return GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE; + } + + if (!fill_quantization_table(decoder, picture)) { + GST_ERROR("failed to fill in quantization table"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!fill_huffman_table(decoder, picture)) { + GST_ERROR("failed to fill in huffman table"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + memset(&scan_hdr, 0, sizeof(scan_hdr)); + if (!gst_jpeg_parse_scan_hdr(&scan_hdr, scan_header, scan_header_size, 0)) { + GST_DEBUG("Jpeg parsed scan failed."); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + gst_slice = GST_VAAPI_SLICE_NEW(JPEGBaseline, decoder, scan_data, scan_data_size); + gst_vaapi_picture_add_slice(picture, gst_slice); + + slice_param = gst_slice->param; + slice_param->num_components = scan_hdr.num_components; + for (i = 0; i < scan_hdr.num_components; i++) { + slice_param->components[i].component_selector = + scan_hdr.components[i].component_selector; + slice_param->components[i].dc_table_selector = + scan_hdr.components[i].dc_selector; + slice_param->components[i].ac_table_selector = + scan_hdr.components[i].ac_selector; + } + slice_param->restart_interval = priv->mcu_restart; + if (scan_hdr.num_components == 1) { /*non-interleaved*/ + slice_param->slice_horizontal_position = 0; + slice_param->slice_vertical_position = 0; + /* Y mcu numbers*/ + if (slice_param->components[0].component_selector == priv->frame_hdr.components[0].identifier) { + slice_param->num_mcus = (priv->frame_hdr.width/8)*(priv->frame_hdr.height/8); + } else { /*Cr, Cb mcu numbers*/ + slice_param->num_mcus = (priv->frame_hdr.width/16)*(priv->frame_hdr.height/16); + } + } else { /* interleaved */ + slice_param->slice_horizontal_position = 0; + slice_param->slice_vertical_position = 0; + total_v_samples = get_max_vertical_samples(&priv->frame_hdr); + total_h_samples = get_max_horizontal_samples(&priv->frame_hdr); + slice_param->num_mcus = ((priv->frame_hdr.width + total_h_samples*8 - 1)/(total_h_samples*8)) * + ((priv->frame_hdr.height + total_v_samples*8 -1)/(total_v_samples*8)); + } + + if (picture->slices && picture->slices->len) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; +} + +static GstVaapiDecoderStatus +decode_buffer(GstVaapiDecoderJpeg *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + GstJpegMarkerSegment seg; + GstJpegScanSegment scan_seg; + GstClockTime pts; + guchar *buf; + guint buf_size, ofs; + gboolean append_ecs; + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + if (!buf && buf_size == 0) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + memset(&scan_seg, 0, sizeof(scan_seg)); + + pts = GST_BUFFER_TIMESTAMP(buffer); + ofs = 0; + while (gst_jpeg_parse(&seg, buf, buf_size, ofs)) { + if (seg.size < 0) { + GST_DEBUG("buffer to short for parsing"); + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } + ofs += seg.size; + + /* Decode scan, if complete */ + if (seg.marker == GST_JPEG_MARKER_EOI && scan_seg.header_size > 0) { + scan_seg.data_size = seg.offset - scan_seg.data_offset; + scan_seg.is_valid = TRUE; + } + if (scan_seg.is_valid) { + status = decode_scan( + decoder, + buf + scan_seg.header_offset, + scan_seg.header_size, + buf + scan_seg.data_offset, + scan_seg.data_size + ); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + break; + memset(&scan_seg, 0, sizeof(scan_seg)); + } + + append_ecs = TRUE; + switch (seg.marker) { + case GST_JPEG_MARKER_SOI: + priv->has_quant_table = FALSE; + priv->has_huf_table = FALSE; + priv->mcu_restart = 0; + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + case GST_JPEG_MARKER_EOI: + if (decode_current_picture(decoder)) { + /* Get out of the loop, trailing data is not needed */ + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + goto end; + } + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + break; + case GST_JPEG_MARKER_DHT: + status = decode_huffman_table(decoder, buf + seg.offset, seg.size); + break; + case GST_JPEG_MARKER_DQT: + status = decode_quant_table(decoder, buf + seg.offset, seg.size); + break; + case GST_JPEG_MARKER_DRI: + status = decode_restart_interval(decoder, buf + seg.offset, seg.size); + break; + case GST_JPEG_MARKER_DAC: + GST_ERROR("unsupported arithmetic coding mode"); + status = GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + break; + case GST_JPEG_MARKER_SOS: + scan_seg.header_offset = seg.offset; + scan_seg.header_size = seg.size; + scan_seg.data_offset = seg.offset + seg.size; + scan_seg.data_size = 0; + append_ecs = FALSE; + break; + default: + /* Restart marker */ + if (seg.marker >= GST_JPEG_MARKER_RST_MIN && + seg.marker <= GST_JPEG_MARKER_RST_MAX) { + append_ecs = FALSE; + break; + } + + /* Frame header */ + if (seg.marker >= GST_JPEG_MARKER_SOF_MIN && + seg.marker <= GST_JPEG_MARKER_SOF_MAX) { + status = decode_picture( + decoder, + seg.marker, + buf + seg.offset, seg.size, + pts + ); + break; + } + + /* Application segments */ + if (seg.marker >= GST_JPEG_MARKER_APP_MIN && + seg.marker <= GST_JPEG_MARKER_APP_MAX) { + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + } + + GST_WARNING("unsupported marker (0x%02x)", seg.marker); + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + } + + /* Append entropy coded segments */ + if (append_ecs) + scan_seg.data_size = seg.offset - scan_seg.data_offset; + + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + break; + } +end: + return status; +} + +GstVaapiDecoderStatus +gst_vaapi_decoder_jpeg_decode(GstVaapiDecoder *base, GstBuffer *buffer) +{ + GstVaapiDecoderJpeg * const decoder = GST_VAAPI_DECODER_JPEG(base); + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_jpeg_open(decoder, buffer); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + } + return decode_buffer(decoder, buffer); +} + +static void +gst_vaapi_decoder_jpeg_finalize(GObject *object) +{ + GstVaapiDecoderJpeg * const decoder = GST_VAAPI_DECODER_JPEG(object); + + gst_vaapi_decoder_jpeg_destroy(decoder); + + G_OBJECT_CLASS(gst_vaapi_decoder_jpeg_parent_class)->finalize(object); +} + +static void +gst_vaapi_decoder_jpeg_constructed(GObject *object) +{ + GstVaapiDecoderJpeg * const decoder = GST_VAAPI_DECODER_JPEG(object); + GstVaapiDecoderJpegPrivate * const priv = decoder->priv; + GObjectClass *parent_class; + + parent_class = G_OBJECT_CLASS(gst_vaapi_decoder_jpeg_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); + + priv->is_constructed = gst_vaapi_decoder_jpeg_create(decoder); +} + +static void +gst_vaapi_decoder_jpeg_class_init(GstVaapiDecoderJpegClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiDecoderJpegPrivate)); + + object_class->finalize = gst_vaapi_decoder_jpeg_finalize; + object_class->constructed = gst_vaapi_decoder_jpeg_constructed; + + decoder_class->decode = gst_vaapi_decoder_jpeg_decode; +} + +static void +gst_vaapi_decoder_jpeg_init(GstVaapiDecoderJpeg *decoder) +{ + GstVaapiDecoderJpegPrivate *priv; + + priv = GST_VAAPI_DECODER_JPEG_GET_PRIVATE(decoder); + decoder->priv = priv; + priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + priv->width = 0; + priv->height = 0; + priv->current_picture = NULL; + priv->has_huf_table = FALSE; + priv->has_quant_table = FALSE; + priv->mcu_restart = 0; + priv->is_opened = FALSE; + priv->profile_changed = TRUE; + priv->is_constructed = FALSE; + memset(&priv->frame_hdr, 0, sizeof(priv->frame_hdr)); + memset(&priv->huf_tables, 0, sizeof(priv->huf_tables)); + memset(&priv->quant_tables, 0, sizeof(priv->quant_tables)); +} + +/** + * gst_vaapi_decoder_jpeg_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for JPEG decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_jpeg_new(GstVaapiDisplay *display, GstCaps *caps) +{ + GstVaapiDecoderJpeg *decoder; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(GST_IS_CAPS(caps), NULL); + + decoder = g_object_new( + GST_VAAPI_TYPE_DECODER_JPEG, + "display", display, + "caps", caps, + NULL + ); + if (!decoder->priv->is_constructed) { + g_object_unref(decoder); + return NULL; + } + return GST_VAAPI_DECODER_CAST(decoder); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h new file mode 100644 index 0000000..cd3b975 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h @@ -0,0 +1,88 @@ +/* + * gstvaapidecoder_jpeg.h - JPEG decoder + * + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_JPEG_H +#define GST_VAAPI_DECODER_JPEG_H + +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DECODER_JPEG \ + (gst_vaapi_decoder_jpeg_get_type()) + +#define GST_VAAPI_DECODER_JPEG(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DECODER_JPEG, \ + GstVaapiDecoderJpeg)) + +#define GST_VAAPI_DECODER_JPEG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DECODER_JPEG, \ + GstVaapiDecoderJpegClass)) + +#define GST_VAAPI_IS_DECODER_JPEG(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DECODER_JPEG)) + +#define GST_VAAPI_IS_DECODER_JPEG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DECODER_JPEG)) + +#define GST_VAAPI_DECODER_JPEG_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DECODER_JPEG, \ + GstVaapiDecoderJpegClass)) + +typedef struct _GstVaapiDecoderJpeg GstVaapiDecoderJpeg; +typedef struct _GstVaapiDecoderJpegPrivate GstVaapiDecoderJpegPrivate; +typedef struct _GstVaapiDecoderJpegClass GstVaapiDecoderJpegClass; + +/** + * GstVaapiDecoderJpeg: + * + * A decoder based on Jpeg. + */ +struct _GstVaapiDecoderJpeg { + /*< private >*/ + GstVaapiDecoder parent_instance; + + GstVaapiDecoderJpegPrivate *priv; +}; + +/** + * GstVaapiDecoderJpegClass: + * + * A decoder class based on Jpeg. + */ +struct _GstVaapiDecoderJpegClass { + /*< private >*/ + GstVaapiDecoderClass parent_class; +}; + +GType +gst_vaapi_decoder_jpeg_get_type(void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_jpeg_new(GstVaapiDisplay *display, GstCaps *caps); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_JPEG_H */ + diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c new file mode 100644 index 0000000..136c9b1 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c @@ -0,0 +1,1202 @@ +/* + * gstvaapidecoder_mpeg2.c - MPEG-2 decoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidecoder_mpeg2 + * @short_description: MPEG-2 decoder + */ + +#include "sysdeps.h" +#include +#include +#include +#include "gstvaapidecoder_mpeg2.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_dpb.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiobject_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDecoderMpeg2, + gst_vaapi_decoder_mpeg2, + GST_VAAPI_TYPE_DECODER); + +#define GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DECODER_MPEG2, \ + GstVaapiDecoderMpeg2Private)) + +#define READ_UINT8(br, val, nbits) G_STMT_START { \ + if (!gst_bit_reader_get_bits_uint8 (br, &val, nbits)) { \ + GST_WARNING ("failed to read uint8, nbits: %d", nbits); \ + goto failed; \ + } \ +} G_STMT_END + +#define SKIP(reader, nbits) G_STMT_START { \ + if (!gst_bit_reader_skip (reader, nbits)) { \ + GST_WARNING ("failed to skip nbits: %d", nbits); \ + goto failed; \ + } \ +} G_STMT_END + +/* PTS Generator */ +typedef struct _PTSGenerator PTSGenerator; +struct _PTSGenerator { + GstClockTime gop_pts; // Current GOP PTS + GstClockTime max_pts; // Max picture PTS + guint gop_tsn; // Absolute GOP TSN + guint max_tsn; // Max picture TSN, relative to last GOP TSN + guint ovl_tsn; // How many times TSN overflowed since GOP + guint lst_tsn; // Last picture TSN + guint fps_n; + guint fps_d; +}; + +static void +pts_init(PTSGenerator *tsg) +{ + tsg->gop_pts = GST_CLOCK_TIME_NONE; + tsg->max_pts = GST_CLOCK_TIME_NONE; + tsg->gop_tsn = 0; + tsg->max_tsn = 0; + tsg->ovl_tsn = 0; + tsg->lst_tsn = 0; + tsg->fps_n = 0; + tsg->fps_d = 0; +} + +static inline GstClockTime +pts_get_duration(PTSGenerator *tsg, guint num_frames) +{ + return gst_util_uint64_scale(num_frames, + GST_SECOND * tsg->fps_d, tsg->fps_n); +} + +static inline guint +pts_get_poc(PTSGenerator *tsg) +{ + return tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->lst_tsn; +} + +static void +pts_set_framerate(PTSGenerator *tsg, guint fps_n, guint fps_d) +{ + tsg->fps_n = fps_n; + tsg->fps_d = fps_d; +} + +static void +pts_sync(PTSGenerator *tsg, GstClockTime gop_pts) +{ + guint gop_tsn; + + if (!GST_CLOCK_TIME_IS_VALID(gop_pts) || + (GST_CLOCK_TIME_IS_VALID(tsg->max_pts) && tsg->max_pts >= gop_pts)) { + /* Invalid GOP PTS, interpolate from the last known picture PTS */ + if (GST_CLOCK_TIME_IS_VALID(tsg->max_pts)) { + gop_pts = tsg->max_pts + pts_get_duration(tsg, 1); + gop_tsn = tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->max_tsn + 1; + } + else { + gop_pts = 0; + gop_tsn = 0; + } + } + else { + /* Interpolate GOP TSN from this valid PTS */ + if (GST_CLOCK_TIME_IS_VALID(tsg->gop_pts)) + gop_tsn = tsg->gop_tsn + gst_util_uint64_scale( + gop_pts - tsg->gop_pts + pts_get_duration(tsg, 1) - 1, + tsg->fps_n, GST_SECOND * tsg->fps_d); + else + gop_tsn = 0; + } + + tsg->gop_pts = gop_pts; + tsg->gop_tsn = gop_tsn; + tsg->max_tsn = 0; + tsg->ovl_tsn = 0; + tsg->lst_tsn = 0; +} + +static GstClockTime +pts_eval(PTSGenerator *tsg, GstClockTime pic_pts, guint pic_tsn) +{ + GstClockTime pts; + + if (!GST_CLOCK_TIME_IS_VALID(tsg->gop_pts)) + tsg->gop_pts = 0; + + pts = tsg->gop_pts + pts_get_duration(tsg, tsg->ovl_tsn * 1024 + pic_tsn); + + if (!GST_CLOCK_TIME_IS_VALID(tsg->max_pts) || tsg->max_pts < pts) + tsg->max_pts = pts; + + if (tsg->max_tsn < pic_tsn) + tsg->max_tsn = pic_tsn; + else if (tsg->max_tsn == 1023 && pic_tsn < tsg->lst_tsn) { /* TSN wrapped */ + tsg->max_tsn = pic_tsn; + tsg->ovl_tsn++; + } + tsg->lst_tsn = pic_tsn; + return pts; +} + +struct _GstVaapiDecoderMpeg2Private { + GstVaapiProfile profile; + GstVaapiProfile hw_profile; + guint width; + guint height; + guint fps_n; + guint fps_d; + GstMpegVideoSequenceHdr seq_hdr; + GstMpegVideoSequenceExt seq_ext; + GstMpegVideoPictureHdr pic_hdr; + GstMpegVideoPictureExt pic_ext; + GstMpegVideoQuantMatrixExt quant_matrix_ext; + GstVaapiPicture *current_picture; + GstVaapiDpb *dpb; + GstAdapter *adapter; + PTSGenerator tsg; + guint is_constructed : 1; + guint is_opened : 1; + guint has_seq_ext : 1; + guint has_seq_scalable_ext : 1; + guint has_pic_ext : 1; + guint has_quant_matrix_ext : 1; + guint size_changed : 1; + guint profile_changed : 1; + guint quant_matrix_changed : 1; + guint progressive_sequence : 1; + guint closed_gop : 1; + guint broken_link : 1; +}; + +/* VLC decoder from gst-plugins-bad */ +typedef struct _VLCTable VLCTable; +struct _VLCTable { + gint value; + guint cword; + guint cbits; +}; + +static gboolean +decode_vlc(GstBitReader *br, gint *res, const VLCTable *table, guint length) +{ + guint8 i; + guint cbits = 0; + guint32 value = 0; + + for (i = 0; i < length; i++) { + if (cbits != table[i].cbits) { + cbits = table[i].cbits; + if (!gst_bit_reader_peek_bits_uint32(br, &value, cbits)) { + goto failed; + } + } + + if (value == table[i].cword) { + SKIP(br, cbits); + if (res) + *res = table[i].value; + return TRUE; + } + } + GST_DEBUG("failed to find VLC code"); + +failed: + GST_WARNING("failed to decode VLC, returning"); + return FALSE; +} + +enum { + GST_MPEG_VIDEO_MACROBLOCK_ESCAPE = -1, +}; + +/* Table B-1: Variable length codes for macroblock_address_increment */ +static const VLCTable mpeg2_mbaddr_vlc_table[] = { + { 1, 0x01, 1 }, + { 2, 0x03, 3 }, + { 3, 0x02, 3 }, + { 4, 0x03, 4 }, + { 5, 0x02, 4 }, + { 6, 0x03, 5 }, + { 7, 0x02, 5 }, + { 8, 0x07, 7 }, + { 9, 0x06, 7 }, + { 10, 0x0b, 8 }, + { 11, 0x0a, 8 }, + { 12, 0x09, 8 }, + { 13, 0x08, 8 }, + { 14, 0x07, 8 }, + { 15, 0x06, 8 }, + { 16, 0x17, 10 }, + { 17, 0x16, 10 }, + { 18, 0x15, 10 }, + { 19, 0x14, 10 }, + { 20, 0x13, 10 }, + { 21, 0x12, 10 }, + { 22, 0x23, 11 }, + { 23, 0x22, 11 }, + { 24, 0x21, 11 }, + { 25, 0x20, 11 }, + { 26, 0x1f, 11 }, + { 27, 0x1e, 11 }, + { 28, 0x1d, 11 }, + { 29, 0x1c, 11 }, + { 30, 0x1b, 11 }, + { 31, 0x1a, 11 }, + { 32, 0x19, 11 }, + { 33, 0x18, 11 }, + { GST_MPEG_VIDEO_MACROBLOCK_ESCAPE, 0x08, 11 } +}; + +static void +gst_vaapi_decoder_mpeg2_clear_buffer(GstVaapiDecoder *base) +{ + GstVaapiDecoderMpeg2* const decoder = GST_VAAPI_DECODER_MPEG2(base); + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + + priv->closed_gop = FALSE; + priv->broken_link = FALSE; + + gst_vaapi_picture_replace(&priv->current_picture, NULL); + + pts_init(&priv->tsg); + pts_set_framerate(&priv->tsg, priv->fps_n, priv->fps_d); + + if (priv->dpb) { + gst_vaapi_dpb_flush(priv->dpb); + } + + if (priv->adapter) { + gst_adapter_clear(priv->adapter); + } +} + +static void +gst_vaapi_decoder_mpeg2_close(GstVaapiDecoderMpeg2 *decoder) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + + gst_vaapi_picture_replace(&priv->current_picture, NULL); + + if (priv->dpb) { + gst_vaapi_dpb_unref(priv->dpb); + priv->dpb = NULL; + } + + if (priv->adapter) { + gst_adapter_clear(priv->adapter); + g_object_unref(priv->adapter); + priv->adapter = NULL; + } +} + +static gboolean +gst_vaapi_decoder_mpeg2_open(GstVaapiDecoderMpeg2 *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + + gst_vaapi_decoder_mpeg2_close(decoder); + + priv->adapter = gst_adapter_new(); + if (!priv->adapter) + return FALSE; + + priv->dpb = gst_vaapi_dpb_mpeg2_new(); + if (!priv->dpb) + return FALSE; + + pts_init(&priv->tsg); + return TRUE; +} + +static void +gst_vaapi_decoder_mpeg2_destroy(GstVaapiDecoderMpeg2 *decoder) +{ + gst_vaapi_decoder_mpeg2_close(decoder); +} + +static gboolean +gst_vaapi_decoder_mpeg2_create(GstVaapiDecoderMpeg2 *decoder) +{ + if (!GST_VAAPI_DECODER_CODEC(decoder)) + return FALSE; + return TRUE; +} + +static inline void +copy_quant_matrix(guint8 dst[64], const guint8 src[64]) +{ + memcpy(dst, src, 64); +} + +static const char * +get_profile_str(GstVaapiProfile profile) +{ + char *str; + + switch (profile) { + case GST_VAAPI_PROFILE_MPEG2_SIMPLE: str = "simple"; break; + case GST_VAAPI_PROFILE_MPEG2_MAIN: str = "main"; break; + case GST_VAAPI_PROFILE_MPEG2_HIGH: str = "high"; break; + default: str = ""; break; + } + return str; +} + +static GstVaapiProfile +get_profile(GstVaapiDecoderMpeg2 *decoder, GstVaapiEntrypoint entrypoint) +{ + GstVaapiDisplay * const va_display = GST_VAAPI_DECODER_DISPLAY(decoder); + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GstVaapiProfile profile = priv->profile; + + do { + /* Return immediately if the exact same profile was found */ + if (gst_vaapi_display_has_decoder(va_display, profile, entrypoint)) + break; + + /* Otherwise, try to map to a higher profile */ + switch (profile) { + case GST_VAAPI_PROFILE_MPEG2_SIMPLE: + profile = GST_VAAPI_PROFILE_MPEG2_MAIN; + break; + case GST_VAAPI_PROFILE_MPEG2_MAIN: + profile = GST_VAAPI_PROFILE_MPEG2_HIGH; + break; + case GST_VAAPI_PROFILE_MPEG2_HIGH: + // Try to map to main profile if no high profile specific bits used + if (priv->profile == profile && + !priv->has_seq_scalable_ext && + (priv->has_seq_ext && priv->seq_ext.chroma_format == 1)) { + profile = GST_VAAPI_PROFILE_MPEG2_MAIN; + break; + } + // fall-through + default: + profile = GST_VAAPI_PROFILE_UNKNOWN; + break; + } + } while (profile != GST_VAAPI_PROFILE_UNKNOWN); + + if (profile != priv->profile) + GST_INFO("forced %s profile to %s profile", + get_profile_str(priv->profile), get_profile_str(profile)); + return profile; +} + +static GstVaapiDecoderStatus +ensure_context(GstVaapiDecoderMpeg2 *decoder) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + gboolean reset_context = FALSE; + + if (priv->profile_changed) { + GST_DEBUG("profile changed"); + priv->profile_changed = FALSE; + reset_context = TRUE; + + priv->hw_profile = get_profile(decoder, entrypoint); + if (priv->hw_profile == GST_VAAPI_PROFILE_UNKNOWN) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + if (priv->size_changed) { + GST_DEBUG("size changed"); + priv->size_changed = FALSE; + reset_context = TRUE; + } + + if (reset_context) { + reset_context = gst_vaapi_decoder_ensure_context( + GST_VAAPI_DECODER(decoder), + priv->hw_profile, + entrypoint, + priv->width, + priv->height, + GST_DECODER_DEFAULT_SURFACES_COUNT + ); + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +ensure_quant_matrix(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + VAIQMatrixBufferMPEG2 *iq_matrix; + guint8 *intra_quant_matrix = NULL; + guint8 *non_intra_quant_matrix = NULL; + guint8 *chroma_intra_quant_matrix = NULL; + guint8 *chroma_non_intra_quant_matrix = NULL; + + if (!priv->quant_matrix_changed) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + priv->quant_matrix_changed = FALSE; + + picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW(MPEG2, decoder); + if (!picture->iq_matrix) { + GST_ERROR("failed to allocate IQ matrix"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + iq_matrix = picture->iq_matrix->param; + + intra_quant_matrix = priv->seq_hdr.intra_quantizer_matrix; + non_intra_quant_matrix = priv->seq_hdr.non_intra_quantizer_matrix; + if (priv->has_quant_matrix_ext) { + if (priv->quant_matrix_ext.load_intra_quantiser_matrix) + intra_quant_matrix = priv->quant_matrix_ext.intra_quantiser_matrix; + if (priv->quant_matrix_ext.load_non_intra_quantiser_matrix) + non_intra_quant_matrix = priv->quant_matrix_ext.non_intra_quantiser_matrix; + if (priv->quant_matrix_ext.load_chroma_intra_quantiser_matrix) + chroma_intra_quant_matrix = priv->quant_matrix_ext.chroma_intra_quantiser_matrix; + if (priv->quant_matrix_ext.load_chroma_non_intra_quantiser_matrix) + chroma_non_intra_quant_matrix = priv->quant_matrix_ext.chroma_non_intra_quantiser_matrix; + } + + iq_matrix->load_intra_quantiser_matrix = intra_quant_matrix != NULL; + if (intra_quant_matrix) + copy_quant_matrix(iq_matrix->intra_quantiser_matrix, + intra_quant_matrix); + + iq_matrix->load_non_intra_quantiser_matrix = non_intra_quant_matrix != NULL; + if (non_intra_quant_matrix) + copy_quant_matrix(iq_matrix->non_intra_quantiser_matrix, + non_intra_quant_matrix); + + iq_matrix->load_chroma_intra_quantiser_matrix = chroma_intra_quant_matrix != NULL; + if (chroma_intra_quant_matrix) + copy_quant_matrix(iq_matrix->chroma_intra_quantiser_matrix, + chroma_intra_quant_matrix); + + iq_matrix->load_chroma_non_intra_quantiser_matrix = chroma_non_intra_quant_matrix != NULL; + if (chroma_non_intra_quant_matrix) + copy_quant_matrix(iq_matrix->chroma_non_intra_quantiser_matrix, + chroma_non_intra_quant_matrix); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static gboolean +decode_current_picture(GstVaapiDecoderMpeg2 *decoder) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GstVaapiPicture * const picture = priv->current_picture; + + if (picture) { + if (!gst_vaapi_picture_decode(picture)) + return FALSE; + if (GST_VAAPI_PICTURE_IS_COMPLETE(picture)) { + if (!gst_vaapi_dpb_add(priv->dpb, picture)) + return FALSE; + gst_vaapi_picture_replace(&priv->current_picture, NULL); + } + } + return TRUE; +} + +static GstVaapiDecoderStatus +decode_sequence(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size) +{ + GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder); + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GstMpegVideoSequenceHdr * const seq_hdr = &priv->seq_hdr; + + if (!gst_mpeg_video_parse_sequence_header(seq_hdr, buf, buf_size, 4)) { + GST_ERROR("failed to parse sequence header"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + priv->fps_n = seq_hdr->fps_n; + priv->fps_d = seq_hdr->fps_d; + pts_set_framerate(&priv->tsg, priv->fps_n, priv->fps_d); + gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d); + + priv->width = seq_hdr->width; + priv->height = seq_hdr->height; + priv->has_seq_ext = FALSE; + priv->size_changed = TRUE; + priv->quant_matrix_changed = TRUE; + priv->progressive_sequence = TRUE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size) +{ + GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder); + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GstMpegVideoSequenceExt * const seq_ext = &priv->seq_ext; + GstVaapiProfile profile; + guint width, height; + + if (!gst_mpeg_video_parse_sequence_extension(seq_ext, buf, buf_size, 4)) { + GST_ERROR("failed to parse sequence-extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + priv->has_seq_ext = TRUE; + priv->progressive_sequence = seq_ext->progressive; + gst_vaapi_decoder_set_interlaced(base_decoder, !priv->progressive_sequence); + + width = (priv->width & 0x0fff) | ((guint32)seq_ext->horiz_size_ext << 12); + height = (priv->height & 0x0fff) | ((guint32)seq_ext->vert_size_ext << 12); + GST_DEBUG("video resolution %ux%u", width, height); + + if (seq_ext->fps_n_ext && seq_ext->fps_d_ext) { + priv->fps_n *= seq_ext->fps_n_ext + 1; + priv->fps_d *= seq_ext->fps_d_ext + 1; + pts_set_framerate(&priv->tsg, priv->fps_n, priv->fps_d); + gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d); + } + + if (priv->width != width) { + priv->width = width; + priv->size_changed = TRUE; + } + + if (priv->height != height) { + priv->height = height; + priv->size_changed = TRUE; + } + + switch (seq_ext->profile) { + case GST_MPEG_VIDEO_PROFILE_SIMPLE: + profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE; + break; + case GST_MPEG_VIDEO_PROFILE_MAIN: + profile = GST_VAAPI_PROFILE_MPEG2_MAIN; + break; + case GST_MPEG_VIDEO_PROFILE_HIGH: + profile = GST_VAAPI_PROFILE_MPEG2_HIGH; + break; + default: + GST_ERROR("unsupported profile %d", seq_ext->profile); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + if (priv->profile != profile) { + priv->profile = profile; + priv->profile_changed = TRUE; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_end(GstVaapiDecoderMpeg2 *decoder) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + + if (priv->current_picture && !decode_current_picture(decoder)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + gst_vaapi_dpb_flush(priv->dpb); + return GST_VAAPI_DECODER_STATUS_END_OF_STREAM; +} + +static GstVaapiDecoderStatus +decode_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GstMpegVideoQuantMatrixExt * const quant_matrix_ext = &priv->quant_matrix_ext; + + if (!gst_mpeg_video_parse_quant_matrix_extension(quant_matrix_ext, buf, buf_size, 4)) { + GST_ERROR("failed to parse quant-matrix-extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + priv->has_quant_matrix_ext = TRUE; + priv->quant_matrix_changed = TRUE; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_gop(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GstMpegVideoGop gop; + GstClockTime pts; + + if (!gst_mpeg_video_parse_gop(&gop, buf, buf_size, 4)) { + GST_ERROR("failed to parse GOP"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + priv->closed_gop = gop.closed_gop; + priv->broken_link = gop.broken_link; + + GST_DEBUG("GOP %02u:%02u:%02u:%02u (closed_gop %d, broken_link %d)", + gop.hour, gop.minute, gop.second, gop.frame, + priv->closed_gop, priv->broken_link); + + pts = gst_adapter_prev_timestamp(priv->adapter, NULL); + pts_sync(&priv->tsg, pts); + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_picture(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr; + GstVaapiPicture *picture; + GstVaapiDecoderStatus status; + GstClockTime pts; + + status = ensure_context(decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_ERROR("failed to reset context"); + return status; + } + + if (priv->current_picture && !decode_current_picture(decoder)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + if (priv->current_picture) { + /* Re-use current picture where the first field was decoded */ + picture = gst_vaapi_picture_new_field(priv->current_picture); + if (!picture) { + GST_ERROR("failed to allocate field picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + } + else { + /* Create new picture */ + picture = GST_VAAPI_PICTURE_NEW(MPEG2, decoder); + if (!picture) { + GST_ERROR("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + } + gst_vaapi_picture_replace(&priv->current_picture, picture); + gst_vaapi_picture_unref(picture); + + status = ensure_quant_matrix(decoder, picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_ERROR("failed to reset quantizer matrix"); + return status; + } + + if (!gst_mpeg_video_parse_picture_header(pic_hdr, buf, buf_size, 4)) { + GST_ERROR("failed to parse picture header"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + priv->has_pic_ext = FALSE; + + switch (pic_hdr->pic_type) { + case GST_MPEG_VIDEO_PICTURE_TYPE_I: + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + picture->type = GST_VAAPI_PICTURE_TYPE_I; + break; + case GST_MPEG_VIDEO_PICTURE_TYPE_P: + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + picture->type = GST_VAAPI_PICTURE_TYPE_P; + break; + case GST_MPEG_VIDEO_PICTURE_TYPE_B: + picture->type = GST_VAAPI_PICTURE_TYPE_B; + break; + default: + GST_ERROR("unsupported picture type %d", pic_hdr->pic_type); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + /* Update presentation time */ + pts = gst_adapter_prev_timestamp(priv->adapter, NULL); + picture->pts = pts_eval(&priv->tsg, pts, pic_hdr->tsn); + picture->poc = pts_get_poc(&priv->tsg); + return status; +} + +static GstVaapiDecoderStatus +decode_picture_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext; + GstVaapiPicture * const picture = priv->current_picture; + + if (!gst_mpeg_video_parse_picture_extension(pic_ext, buf, buf_size, 4)) { + GST_ERROR("failed to parse picture-extension"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + priv->has_pic_ext = TRUE; + + if (priv->progressive_sequence && !pic_ext->progressive_frame) { + GST_WARNING("invalid interlaced frame in progressive sequence, fixing"); + pic_ext->progressive_frame = 1; + } + + if (pic_ext->picture_structure == 0 || + (pic_ext->progressive_frame && + pic_ext->picture_structure != GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME)) { + GST_WARNING("invalid picture_structure %d, replacing with \"frame\"", + pic_ext->picture_structure); + pic_ext->picture_structure = GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME; + } + + if (!priv->progressive_sequence && !pic_ext->progressive_frame) { + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_INTERLACED); + if (pic_ext->top_field_first) + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_TFF); + } + + switch (pic_ext->picture_structure) { + case GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD: + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD; + break; + case GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD: + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD; + break; + case GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME: + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + break; + } + + /* Allocate dummy picture for first field based I-frame */ + if (picture->type == GST_VAAPI_PICTURE_TYPE_I && + !GST_VAAPI_PICTURE_IS_FRAME(picture) && + gst_vaapi_dpb_size(priv->dpb) == 0) { + GstVaapiPicture *dummy_picture; + gboolean success; + + dummy_picture = GST_VAAPI_PICTURE_NEW(MPEG2, decoder); + if (!dummy_picture) { + GST_ERROR("failed to allocate dummy picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + dummy_picture->type = GST_VAAPI_PICTURE_TYPE_I; + dummy_picture->pts = GST_CLOCK_TIME_NONE; + dummy_picture->poc = -1; + dummy_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + + GST_VAAPI_PICTURE_FLAG_SET( + dummy_picture, + (GST_VAAPI_PICTURE_FLAG_SKIPPED | + GST_VAAPI_PICTURE_FLAG_REFERENCE) + ); + + success = gst_vaapi_dpb_add(priv->dpb, dummy_picture); + gst_vaapi_picture_unref(dummy_picture); + if (!success) { + GST_ERROR("failed to add dummy picture into DPB"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + GST_INFO("allocated dummy picture for first field based I-frame"); + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline guint32 +pack_f_code(guint8 f_code[2][2]) +{ + return (((guint32)f_code[0][0] << 12) | + ((guint32)f_code[0][1] << 8) | + ((guint32)f_code[1][0] << 4) | + ( f_code[1][1] )); +} + +static gboolean +fill_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + VAPictureParameterBufferMPEG2 * const pic_param = picture->param; + GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr; + GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext; + GstVaapiPicture *prev_picture, *next_picture; + + if (!priv->has_pic_ext) + return FALSE; + + /* Fill in VAPictureParameterBufferMPEG2 */ + pic_param->horizontal_size = priv->width; + pic_param->vertical_size = priv->height; + pic_param->forward_reference_picture = VA_INVALID_ID; + pic_param->backward_reference_picture = VA_INVALID_ID; + pic_param->picture_coding_type = pic_hdr->pic_type; + pic_param->f_code = pack_f_code(pic_ext->f_code); + +#define COPY_FIELD(a, b, f) \ + pic_param->a.b.f = pic_ext->f + pic_param->picture_coding_extension.value = 0; + pic_param->picture_coding_extension.bits.is_first_field = GST_VAAPI_PICTURE_IS_FIRST_FIELD(picture); + COPY_FIELD(picture_coding_extension, bits, intra_dc_precision); + COPY_FIELD(picture_coding_extension, bits, picture_structure); + COPY_FIELD(picture_coding_extension, bits, top_field_first); + COPY_FIELD(picture_coding_extension, bits, frame_pred_frame_dct); + COPY_FIELD(picture_coding_extension, bits, concealment_motion_vectors); + COPY_FIELD(picture_coding_extension, bits, q_scale_type); + COPY_FIELD(picture_coding_extension, bits, intra_vlc_format); + COPY_FIELD(picture_coding_extension, bits, alternate_scan); + COPY_FIELD(picture_coding_extension, bits, repeat_first_field); + COPY_FIELD(picture_coding_extension, bits, progressive_frame); + + gst_vaapi_dpb_mpeg2_get_references( + priv->dpb, + picture, + &prev_picture, + &next_picture + ); + + switch (pic_hdr->pic_type) { + case GST_MPEG_VIDEO_PICTURE_TYPE_B: + if (next_picture) + pic_param->backward_reference_picture = next_picture->surface_id; + if (prev_picture) + pic_param->forward_reference_picture = prev_picture->surface_id; + else if (!priv->closed_gop) + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_SKIPPED); + break; + case GST_MPEG_VIDEO_PICTURE_TYPE_P: + if (prev_picture) + pic_param->forward_reference_picture = prev_picture->surface_id; + break; + } + return TRUE; +} + +static GstVaapiDecoderStatus +decode_slice( + GstVaapiDecoderMpeg2 *decoder, + int slice_no, + guchar *buf, + guint buf_size +) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GstVaapiPicture * const picture = priv->current_picture; + GstVaapiSlice *slice; + VASliceParameterBufferMPEG2 *slice_param; + GstBitReader br; + gint mb_x, mb_y, mb_inc; + guint macroblock_offset; + guint8 slice_vertical_position_extension; + guint8 quantiser_scale_code; + guint8 intra_slice = 0; + guint8 extra_bit_slice, junk8; + + GST_DEBUG("slice %d @ %p, %u bytes)", slice_no, buf, buf_size); + + if (picture->slices->len == 0 && !fill_picture(decoder, picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + slice = GST_VAAPI_SLICE_NEW(MPEG2, decoder, buf, buf_size); + if (!slice) { + GST_ERROR("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_add_slice(picture, slice); + + /* Parse slice */ + gst_bit_reader_init(&br, buf, buf_size); + SKIP(&br, 32); /* slice_start_code */ + if (priv->height > 2800) + READ_UINT8(&br, slice_vertical_position_extension, 3); + if (priv->has_seq_scalable_ext) { + GST_ERROR("failed to parse slice %d. Unsupported sequence_scalable_extension()", slice_no); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + READ_UINT8(&br, quantiser_scale_code, 5); + READ_UINT8(&br, extra_bit_slice, 1); + if (extra_bit_slice == 1) { + READ_UINT8(&br, intra_slice, 1); + READ_UINT8(&br, junk8, 7); + READ_UINT8(&br, extra_bit_slice, 1); + while (extra_bit_slice == 1) { + READ_UINT8(&br, junk8, 8); + READ_UINT8(&br, extra_bit_slice, 1); + } + } + macroblock_offset = gst_bit_reader_get_pos(&br); + + mb_y = slice_no; + mb_x = -1; + do { + if (!decode_vlc(&br, &mb_inc, mpeg2_mbaddr_vlc_table, + G_N_ELEMENTS(mpeg2_mbaddr_vlc_table))) { + GST_WARNING("failed to decode first macroblock_address_increment"); + goto failed; + } + mb_x += mb_inc == GST_MPEG_VIDEO_MACROBLOCK_ESCAPE ? 33 : mb_inc; + } while (mb_inc == GST_MPEG_VIDEO_MACROBLOCK_ESCAPE); + + /* Fill in VASliceParameterBufferMPEG2 */ + slice_param = slice->param; + slice_param->macroblock_offset = macroblock_offset; + slice_param->slice_horizontal_position = mb_x; + slice_param->slice_vertical_position = mb_y; + slice_param->quantiser_scale_code = quantiser_scale_code; + slice_param->intra_slice_flag = intra_slice; + return GST_VAAPI_DECODER_STATUS_SUCCESS; + +failed: + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; +} + +static inline gint +scan_for_start_code(GstAdapter *adapter, guint ofs, guint size, guint32 *scp) +{ + return (gint)gst_adapter_masked_scan_uint32_peek(adapter, + 0xffffff00, 0x00000100, + ofs, size, + scp); +} + +static GstVaapiDecoderStatus +decode_buffer(GstVaapiDecoderMpeg2 *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GstVaapiDecoderStatus status; + guchar *buf; + guint buf_size, size; + guint32 start_code; + guint8 type; + gint ofs; + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + if (!buf && buf_size == 0) + return decode_sequence_end(decoder); + + gst_adapter_push(priv->adapter, gst_buffer_ref(buffer)); + + size = gst_adapter_available(priv->adapter); + status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + do { + if (size < 8) + break; + ofs = scan_for_start_code(priv->adapter, 0, size, &start_code); + if (ofs < 0) + break; + gst_adapter_flush(priv->adapter, ofs); + size -= ofs; + + status = gst_vaapi_decoder_check_status(GST_VAAPI_DECODER(decoder)); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + break; + + if (size < 8) + break; + ofs = scan_for_start_code(priv->adapter, 4, size - 4, NULL); + if (ofs < 0) + break; + buffer = gst_adapter_take_buffer(priv->adapter, ofs); + size -= ofs; + + if (ofs == 4) { + // Ignore empty user-data packets + if ((start_code & 0xff) == GST_MPEG_VIDEO_PACKET_USER_DATA) + continue; + GST_ERROR("failed to get a valid packet (SC: 0x%08x)", start_code); + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + } + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + + type = start_code & 0xff; + switch (type) { + case GST_MPEG_VIDEO_PACKET_PICTURE: + if (!priv->width || !priv->height) + break; + status = decode_picture(decoder, buf, buf_size); + break; + case GST_MPEG_VIDEO_PACKET_SEQUENCE: + status = decode_sequence(decoder, buf, buf_size); + break; + case GST_MPEG_VIDEO_PACKET_EXTENSION: { + const guchar id = buf[4] >> 4; + switch (id) { + case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE: + status = decode_sequence_ext(decoder, buf, buf_size); + break; + case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX: + status = decode_quant_matrix_ext(decoder, buf, buf_size); + break; + case GST_MPEG_VIDEO_PACKET_EXT_PICTURE: + if (!priv->width || !priv->height) + break; + status = decode_picture_ext(decoder, buf, buf_size); + break; + default: + // Ignore unknown extensions + GST_WARNING("unsupported start-code extension (0x%02x)", id); + break; + } + break; + } + case GST_MPEG_VIDEO_PACKET_SEQUENCE_END: + status = decode_sequence_end(decoder); + break; + case GST_MPEG_VIDEO_PACKET_GOP: + status = decode_gop(decoder, buf, buf_size); + break; + case GST_MPEG_VIDEO_PACKET_USER_DATA: + // Ignore user-data packets + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + default: + if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN && + type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) { + if (!priv->current_picture) + break; + status = decode_slice( + decoder, + type - GST_MPEG_VIDEO_PACKET_SLICE_MIN, + buf, buf_size + ); + break; + } + else if (type >= 0xb9 && type <= 0xff) { + // Ignore system start codes (PES headers) + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + } + GST_WARNING("unsupported start code (0x%02x)", type); + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + } + gst_buffer_unref(buffer); + } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS); + return status; +} + +GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg2_decode(GstVaapiDecoder *base, GstBuffer *buffer) +{ + GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(base); + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + + g_return_val_if_fail(priv->is_constructed, + GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED); + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_mpeg2_open(decoder, buffer); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + } + return decode_buffer(decoder, buffer); +} + +static void +gst_vaapi_decoder_mpeg2_finalize(GObject *object) +{ + GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(object); + + gst_vaapi_decoder_mpeg2_destroy(decoder); + + G_OBJECT_CLASS(gst_vaapi_decoder_mpeg2_parent_class)->finalize(object); +} + +static void +gst_vaapi_decoder_mpeg2_constructed(GObject *object) +{ + GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(object); + GstVaapiDecoderMpeg2Private * const priv = decoder->priv; + GObjectClass *parent_class; + + parent_class = G_OBJECT_CLASS(gst_vaapi_decoder_mpeg2_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); + + priv->is_constructed = gst_vaapi_decoder_mpeg2_create(decoder); +} + +static void +gst_vaapi_decoder_mpeg2_class_init(GstVaapiDecoderMpeg2Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiDecoderMpeg2Private)); + + object_class->finalize = gst_vaapi_decoder_mpeg2_finalize; + object_class->constructed = gst_vaapi_decoder_mpeg2_constructed; + + decoder_class->decode = gst_vaapi_decoder_mpeg2_decode; + decoder_class->clear_buffer = gst_vaapi_decoder_mpeg2_clear_buffer; +} + +static void +gst_vaapi_decoder_mpeg2_init(GstVaapiDecoderMpeg2 *decoder) +{ + GstVaapiDecoderMpeg2Private *priv; + + priv = GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(decoder); + decoder->priv = priv; + priv->width = 0; + priv->height = 0; + priv->fps_n = 0; + priv->fps_d = 0; + priv->hw_profile = GST_VAAPI_PROFILE_UNKNOWN; + priv->profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE; + priv->current_picture = NULL; + priv->adapter = NULL; + priv->is_constructed = FALSE; + priv->is_opened = FALSE; + priv->has_seq_ext = FALSE; + priv->has_seq_scalable_ext = FALSE; + priv->has_pic_ext = FALSE; + priv->has_quant_matrix_ext = FALSE; + priv->size_changed = FALSE; + priv->profile_changed = TRUE; /* Allow fallbacks to work */ + priv->quant_matrix_changed = FALSE; + priv->progressive_sequence = FALSE; + priv->closed_gop = FALSE; + priv->broken_link = FALSE; +} + +/** + * gst_vaapi_decoder_mpeg2_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for MPEG-2 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_mpeg2_new(GstVaapiDisplay *display, GstCaps *caps) +{ + GstVaapiDecoderMpeg2 *decoder; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(GST_IS_CAPS(caps), NULL); + + decoder = g_object_new( + GST_VAAPI_TYPE_DECODER_MPEG2, + "display", display, + "caps", caps, + NULL + ); + if (!decoder->priv->is_constructed) { + g_object_unref(decoder); + return NULL; + } + return GST_VAAPI_DECODER_CAST(decoder); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h new file mode 100644 index 0000000..e438c39 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h @@ -0,0 +1,88 @@ +/* + * gstvaapidecoder_mpeg2.h - MPEG-2 decoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_MPEG2_H +#define GST_VAAPI_DECODER_MPEG2_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DECODER_MPEG2 \ + (gst_vaapi_decoder_mpeg2_get_type()) + +#define GST_VAAPI_DECODER_MPEG2(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DECODER_MPEG2, \ + GstVaapiDecoderMpeg2)) + +#define GST_VAAPI_DECODER_MPEG2_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DECODER_MPEG2, \ + GstVaapiDecoderMpeg2Class)) + +#define GST_VAAPI_IS_DECODER_MPEG2(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DECODER_MPEG2)) + +#define GST_VAAPI_IS_DECODER_MPEG2_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DECODER_MPEG2)) + +#define GST_VAAPI_DECODER_MPEG2_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DECODER_MPEG2, \ + GstVaapiDecoderMpeg2Class)) + +typedef struct _GstVaapiDecoderMpeg2 GstVaapiDecoderMpeg2; +typedef struct _GstVaapiDecoderMpeg2Private GstVaapiDecoderMpeg2Private; +typedef struct _GstVaapiDecoderMpeg2Class GstVaapiDecoderMpeg2Class; + +/** + * GstVaapiDecoderMpeg2: + * + * A decoder based on Mpeg2. + */ +struct _GstVaapiDecoderMpeg2 { + /*< private >*/ + GstVaapiDecoder parent_instance; + + GstVaapiDecoderMpeg2Private *priv; +}; + +/** + * GstVaapiDecoderMpeg2Class: + * + * A decoder class based on Mpeg2. + */ +struct _GstVaapiDecoderMpeg2Class { + /*< private >*/ + GstVaapiDecoderClass parent_class; +}; + +GType +gst_vaapi_decoder_mpeg2_get_type(void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_mpeg2_new(GstVaapiDisplay *display, GstCaps *caps); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_MPEG2_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c new file mode 100644 index 0000000..4b4279b --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c @@ -0,0 +1,1205 @@ +/* + * gstvaapidecoder_mpeg4.c - MPEG-4 decoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidecoder_mpeg4 + * @short_description: MPEG-4 decoder, include h263/divx/xvid support + */ + +#include "sysdeps.h" +#include +#include +#include +#include +#include "gstvaapidecoder_mpeg4.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiobject_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDecoderMpeg4, + gst_vaapi_decoder_mpeg4, + GST_VAAPI_TYPE_DECODER); + +#define GST_VAAPI_DECODER_MPEG4_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DECODER_MPEG4, \ + GstVaapiDecoderMpeg4Private)) + +struct _GstVaapiDecoderMpeg4Private { + GstVaapiProfile profile; + guint level; + guint width; + guint height; + guint fps_n; + guint fps_d; + guint coding_type; + GstMpeg4VisualObjectSequence vos_hdr; + GstMpeg4VisualObject vo_hdr; + GstMpeg4VideoSignalType signal_type; + GstMpeg4VideoObjectLayer vol_hdr; + GstMpeg4VideoObjectPlane vop_hdr; + GstMpeg4VideoPlaneShortHdr svh_hdr; + GstMpeg4VideoPacketHdr packet_hdr; + GstMpeg4SpriteTrajectory sprite_trajectory; + VAIQMatrixBufferMPEG4 iq_matrix; + GstVaapiPicture *curr_picture; + // forward reference pic + GstVaapiPicture *next_picture; + // backward reference pic + GstVaapiPicture *prev_picture; + GstAdapter *adapter; + GstBuffer *sub_buffer; + GstClockTime seq_pts; + GstClockTime gop_pts; + GstClockTime pts_diff; + GstClockTime max_pts; + // anchor sync time base for any picture type, + // it is time base of backward reference frame + GstClockTime last_sync_time; + // time base for recent I/P/S frame, + // it is time base of forward reference frame for B frame + GstClockTime sync_time; + + /* last non-b-frame time by resolution */ + GstClockTime last_non_b_scale_time; + GstClockTime non_b_scale_time; + GstClockTime trb; + GstClockTime trd; + // temporal_reference of previous frame of svh + guint8 prev_t_ref; + guint is_constructed : 1; + guint is_opened : 1; + guint is_first_field : 1; + guint size_changed : 1; + guint profile_changed : 1; + guint progressive_sequence : 1; + guint closed_gop : 1; + guint broken_link : 1; + guint calculate_pts_diff : 1; + guint is_svh : 1; +}; + +static void +gst_vaapi_decoder_mpeg4_clear_buffer(GstVaapiDecoder *base) +{ + GstVaapiDecoderMpeg4* const decoder = GST_VAAPI_DECODER_MPEG4(base); + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + + priv->seq_pts = GST_CLOCK_TIME_NONE; + priv->gop_pts = GST_CLOCK_TIME_NONE; + priv->max_pts = GST_CLOCK_TIME_NONE; + priv->pts_diff = 0; + priv->prev_t_ref = -1; + priv->calculate_pts_diff = TRUE; + priv->is_first_field = FALSE; + priv->closed_gop = FALSE; + priv->broken_link = FALSE; + priv->last_non_b_scale_time = 0; + priv->non_b_scale_time = 0; + priv->trb = 0; + priv->trd = 0; + + gst_vaapi_picture_replace(&priv->curr_picture, NULL); + gst_vaapi_picture_replace(&priv->next_picture, NULL); + gst_vaapi_picture_replace(&priv->prev_picture, NULL); + + if (priv->sub_buffer) { + gst_buffer_unref(priv->sub_buffer); + priv->sub_buffer = NULL; + } + + if (priv->adapter) { + gst_adapter_clear(priv->adapter); + } +} + +static void +gst_vaapi_decoder_mpeg4_close(GstVaapiDecoderMpeg4 *decoder) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + + gst_vaapi_decoder_mpeg4_clear_buffer(GST_VAAPI_DECODER_CAST(decoder)); + + if (priv->adapter) { + g_object_unref(priv->adapter); + priv->adapter = NULL; + } +} + +static gboolean +gst_vaapi_decoder_mpeg4_open(GstVaapiDecoderMpeg4 *decoder, GstBuffer *buffer) +{ + GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER(decoder); + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstCaps *caps = NULL; + GstStructure *structure = NULL; + + gst_vaapi_decoder_mpeg4_close(decoder); + + priv->adapter = gst_adapter_new(); + if (!priv->adapter) + return FALSE; + + priv->is_svh = 0; + caps = gst_vaapi_decoder_get_caps(base_decoder); + if (caps) { + structure = gst_caps_get_structure(caps, 0); + if (structure) { + if (gst_structure_has_name(structure, "video/x-h263")) { + priv->is_svh = 1; + priv->profile = GST_VAAPI_PROFILE_MPEG4_SIMPLE; + priv->prev_t_ref = -1; + } + } + } + return TRUE; +} + +static void +gst_vaapi_decoder_mpeg4_destroy(GstVaapiDecoderMpeg4 *decoder) +{ + gst_vaapi_decoder_mpeg4_close(decoder); +} + +static gboolean +gst_vaapi_decoder_mpeg4_create(GstVaapiDecoderMpeg4 *decoder) +{ + if (!GST_VAAPI_DECODER_CODEC(decoder)) + return FALSE; + return TRUE; +} + +static inline void +copy_quant_matrix(guint8 dst[64], const guint8 src[64]) +{ + memcpy(dst, src, 64); +} + +static GstVaapiDecoderStatus +ensure_context(GstVaapiDecoderMpeg4 *decoder) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstVaapiProfile profiles[2]; + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + guint i, n_profiles = 0; + gboolean reset_context = FALSE; + + if (priv->profile_changed) { + GST_DEBUG("profile changed"); + priv->profile_changed = FALSE; + reset_context = TRUE; + + profiles[n_profiles++] = priv->profile; + if (priv->profile == GST_VAAPI_PROFILE_MPEG4_SIMPLE) + profiles[n_profiles++] = GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE; + + for (i = 0; i < n_profiles; i++) { + if (gst_vaapi_display_has_decoder(GST_VAAPI_DECODER_DISPLAY(decoder), + profiles[i], entrypoint)) + break; + } + if (i == n_profiles) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + priv->profile = profiles[i]; + } + + if (priv->size_changed) { + GST_DEBUG("size changed"); + priv->size_changed = FALSE; + reset_context = TRUE; + } + + if (reset_context) { + reset_context = gst_vaapi_decoder_ensure_context( + GST_VAAPI_DECODER(decoder), + priv->profile, + entrypoint, + priv->width, + priv->height, + GST_DECODER_DEFAULT_SURFACES_COUNT + ); + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +ensure_quant_matrix(GstVaapiDecoderMpeg4 *decoder, GstVaapiPicture *picture) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + VAIQMatrixBufferMPEG4 *iq_matrix; + + if (!priv->vol_hdr.load_intra_quant_mat && !priv->vol_hdr.load_non_intra_quant_mat) { + return GST_VAAPI_DECODER_STATUS_SUCCESS; + } + + picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW(MPEG4, decoder); + if (!picture->iq_matrix) { + GST_DEBUG("failed to allocate IQ matrix"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + iq_matrix = picture->iq_matrix->param; + + if (priv->vol_hdr.load_intra_quant_mat) { + iq_matrix->load_intra_quant_mat = 1; + copy_quant_matrix(iq_matrix->intra_quant_mat, + priv->vol_hdr.intra_quant_mat); + } + else + iq_matrix->load_intra_quant_mat = 0; + + if (priv->vol_hdr.load_non_intra_quant_mat) { + iq_matrix->load_non_intra_quant_mat = 1; + copy_quant_matrix(iq_matrix->non_intra_quant_mat, + priv->vol_hdr.non_intra_quant_mat); + } + else + iq_matrix->load_non_intra_quant_mat = 0; + + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline GstVaapiDecoderStatus +render_picture(GstVaapiDecoderMpeg4 *decoder, GstVaapiPicture *picture) +{ + if (!gst_vaapi_picture_output(picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +/* decode_picture() start to decode a frame/picture + * decode_current_picture() finishe decoding a frame/picture + * (commit buffer to driver for decoding) + */ +static GstVaapiDecoderStatus +decode_current_picture(GstVaapiDecoderMpeg4 *decoder) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstVaapiPicture * const picture = priv->curr_picture; + GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (picture) { + if (!gst_vaapi_picture_decode(picture)) + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + if (!GST_VAAPI_PICTURE_IS_REFERENCE(picture)) { + if ((priv->prev_picture && priv->next_picture) || + (priv->closed_gop && priv->next_picture)) + status = render_picture(decoder, picture); + } + gst_vaapi_picture_replace(&priv->curr_picture, NULL); + } + return status; +} + +static GstVaapiDecoderStatus +decode_sequence(GstVaapiDecoderMpeg4 *decoder, const guint8 *buf, guint buf_size) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstMpeg4VisualObjectSequence * const vos_hdr = &priv->vos_hdr; + GstVaapiProfile profile; + + if (gst_mpeg4_parse_visual_object_sequence(vos_hdr, buf, buf_size) != GST_MPEG4_PARSER_OK) { + GST_DEBUG("failed to parse sequence header"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + priv->level = vos_hdr->level; + switch (vos_hdr->profile) { + case GST_MPEG4_PROFILE_SIMPLE: + profile = GST_VAAPI_PROFILE_MPEG4_SIMPLE; + break; + case GST_MPEG4_PROFILE_ADVANCED_SIMPLE: + case GST_MPEG4_PROFILE_SIMPLE_SCALABLE: /* shared profile with ADVANCED_SIMPLE */ + profile = GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE; + break; + default: + GST_DEBUG("unsupported profile %d", profile); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + if (priv->profile != profile) { + priv->profile = profile; + priv->profile_changed = TRUE; + } + priv->seq_pts = gst_adapter_prev_timestamp(priv->adapter, NULL); + priv->size_changed = TRUE; + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_end(GstVaapiDecoderMpeg4 *decoder) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstVaapiDecoderStatus status; + + if (priv->curr_picture) { + status = decode_current_picture(decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + status = render_picture(decoder, priv->curr_picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + + if (priv->next_picture) { + status = render_picture(decoder, priv->next_picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + return GST_VAAPI_DECODER_STATUS_END_OF_STREAM; +} + +static GstVaapiDecoderStatus +decode_visual_object(GstVaapiDecoderMpeg4 *decoder, const guint8 *buf, guint buf_size) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstMpeg4VisualObject * vo_hdr = &priv->vo_hdr; + GstMpeg4VideoSignalType * signal_type = &priv->signal_type; + + if (gst_mpeg4_parse_visual_object (vo_hdr, signal_type, buf, buf_size) != GST_MPEG4_PARSER_OK) { + GST_DEBUG("failed to parse visual object"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + /* XXX: video_signal_type isn't used for decoding */ + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_video_object_layer(GstVaapiDecoderMpeg4 *decoder, const guint8 *buf, guint buf_size) +{ + GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder); + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstMpeg4VisualObject * vo_hdr = &priv->vo_hdr; + GstMpeg4VideoObjectLayer * vol_hdr = &priv->vol_hdr; + + if (gst_mpeg4_parse_video_object_layer (vol_hdr, vo_hdr, buf, buf_size) != GST_MPEG4_PARSER_OK) { + GST_DEBUG("failed to parse video object layer"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + priv->width = vol_hdr->width; + priv->height = vol_hdr->height; + + priv->progressive_sequence = !vol_hdr->interlaced; + + if (vol_hdr->fixed_vop_rate) { + priv->fps_n = vol_hdr->vop_time_increment_resolution; + priv->fps_d = vol_hdr->fixed_vop_time_increment; + gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d); + } + + gst_vaapi_decoder_set_pixel_aspect_ratio(base_decoder, priv->vol_hdr.par_width, priv->vol_hdr.par_height); + gst_vaapi_decoder_set_picture_size(base_decoder, priv->width, priv->height); + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_gop(GstVaapiDecoderMpeg4 *decoder, const guint8 *buf, guint buf_size) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstMpeg4GroupOfVOP gop; + GstClockTime gop_time; + + if (buf_size >4) { + if (gst_mpeg4_parse_group_of_vop(&gop, buf, buf_size) != GST_MPEG4_PARSER_OK) { + GST_DEBUG("failed to parse GOP"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + } + else { + gop.closed = 1; + gop.broken_link = 0; + gop.hours = 0; + gop.minutes = 0; + gop.seconds = 0; + } + + priv->closed_gop = gop.closed; + priv->broken_link = gop.broken_link; + + GST_DEBUG("GOP %02u:%02u:%02u (closed_gop %d, broken_link %d)", + gop.hours, gop.minutes, gop.seconds, + priv->closed_gop, priv->broken_link); + + gop_time = gop.hours * 3600 + gop.minutes * 60 + gop.seconds; + priv->last_sync_time = gop_time; + priv->sync_time = gop_time; + + if (priv->gop_pts != GST_CLOCK_TIME_NONE) + priv->pts_diff += gop_time * GST_SECOND - priv->gop_pts; + priv->gop_pts = gop_time * GST_SECOND; + priv->calculate_pts_diff = TRUE; + priv->is_first_field = TRUE; + + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +void +calculate_pts_diff(GstVaapiDecoderMpeg4 *decoder, + GstMpeg4VideoObjectLayer *vol_hdr, + GstMpeg4VideoObjectPlane *vop_hdr) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstClockTime frame_timestamp; + + frame_timestamp = gst_adapter_prev_timestamp(priv->adapter, NULL); + if (frame_timestamp && frame_timestamp != GST_CLOCK_TIME_NONE) { + /* Buffer with timestamp */ + if (priv->max_pts != GST_CLOCK_TIME_NONE && + frame_timestamp < priv->max_pts) { + frame_timestamp = priv->max_pts + + gst_util_uint64_scale((vol_hdr->fixed_vop_rate ? + vol_hdr->fixed_vop_time_increment : 1), + GST_SECOND, + vol_hdr->vop_time_increment_resolution); + } + } else { + /* Buffer without timestamp set */ + if (priv->max_pts == GST_CLOCK_TIME_NONE) /* first buffer */ + frame_timestamp = 0; + else { + GstClockTime tmp_pts; + tmp_pts = priv->pts_diff + priv->gop_pts + + vop_hdr->modulo_time_base * GST_SECOND + + gst_util_uint64_scale(vop_hdr->time_increment, + GST_SECOND, + vol_hdr->vop_time_increment_resolution); + if (tmp_pts > priv->max_pts) + frame_timestamp = tmp_pts; + else + frame_timestamp = priv->max_pts + + gst_util_uint64_scale((vol_hdr->fixed_vop_rate ? + vol_hdr->fixed_vop_time_increment : 1), + GST_SECOND, + vol_hdr->vop_time_increment_resolution); + } + } + + priv->pts_diff = frame_timestamp - + (priv->gop_pts + vop_hdr->modulo_time_base * GST_SECOND + + gst_util_uint64_scale(vop_hdr->time_increment, GST_SECOND, + vol_hdr->vop_time_increment_resolution)); +} + +static GstVaapiDecoderStatus +decode_picture(GstVaapiDecoderMpeg4 *decoder, const guint8 *buf, guint buf_size) +{ + GstMpeg4ParseResult parser_result = GST_MPEG4_PARSER_OK; + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstMpeg4VideoObjectPlane * const vop_hdr = &priv->vop_hdr; + GstMpeg4VideoObjectLayer * const vol_hdr = &priv->vol_hdr; + GstMpeg4SpriteTrajectory * const sprite_trajectory = &priv->sprite_trajectory; + GstVaapiPicture *picture; + GstVaapiDecoderStatus status; + GstClockTime pts; + + // context depends on priv->width and priv->height, so we move parse_vop a little earlier + if (priv->is_svh) { + parser_result = gst_mpeg4_parse_video_plane_short_header(&priv->svh_hdr, buf, buf_size); + + } + else { + parser_result = gst_mpeg4_parse_video_object_plane(vop_hdr, sprite_trajectory, vol_hdr, buf, buf_size); + /* Need to skip this frame if VOP was not coded */ + if (GST_MPEG4_PARSER_OK == parser_result && !vop_hdr->coded) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } + + if (parser_result != GST_MPEG4_PARSER_OK) { + GST_DEBUG("failed to parse picture header"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + + if (priv->is_svh) { + priv->width = priv->svh_hdr.vop_width; + priv->height = priv->svh_hdr.vop_height; + } + else { + if (!vop_hdr->width && !vop_hdr->height) { + vop_hdr->width = vol_hdr->width; + vop_hdr->height = vol_hdr->height; + } + priv->width = vop_hdr->width; + priv->height = vop_hdr->height; + } + + status = ensure_context(decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_DEBUG("failed to reset context"); + return status; + } + + if (priv->curr_picture) { + status = decode_current_picture(decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + + priv->curr_picture = GST_VAAPI_PICTURE_NEW(MPEG4, decoder); + if (!priv->curr_picture) { + GST_DEBUG("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + picture = priv->curr_picture; + + status = ensure_quant_matrix(decoder, picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_DEBUG("failed to reset quantizer matrix"); + return status; + } + + /* 7.6.7 Temporal prediction structure + * forward reference frame B B B B B B backward reference frame + * | | + * nearest I/P/S in the past with vop_coded ==1 | + * nearest I/P/S in the future with any vop_coded + * fixme, it said that B frame shouldn't use backward reference frame + * when backward reference frame coded is 0 + */ + if (priv->is_svh) { + priv->coding_type = priv->svh_hdr.picture_coding_type; + } + else { + priv->coding_type = priv->vop_hdr.coding_type; + } + switch (priv->coding_type) { + case GST_MPEG4_I_VOP: + picture->type = GST_VAAPI_PICTURE_TYPE_I; + if (priv->is_svh || vop_hdr->coded) + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + break; + case GST_MPEG4_P_VOP: + picture->type = GST_VAAPI_PICTURE_TYPE_P; + if (priv->is_svh || vop_hdr->coded) + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + break; + case GST_MPEG4_B_VOP: + picture->type = GST_VAAPI_PICTURE_TYPE_B; + break; + case GST_MPEG4_S_VOP: + picture->type = GST_VAAPI_PICTURE_TYPE_S; + // see 3.175 reference VOP + if (vop_hdr->coded) + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + break; + default: + GST_DEBUG("unsupported picture type %d", priv->coding_type); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!priv->is_svh && !vop_hdr->coded) { + status = render_picture(decoder, priv->prev_picture); + return status; + } + + if (priv->is_svh) { + if (priv->calculate_pts_diff) { + priv->prev_t_ref = priv->svh_hdr.temporal_reference; + priv->sync_time = gst_adapter_prev_timestamp(priv->adapter, NULL); + if (priv->sync_time == GST_CLOCK_TIME_NONE) + priv->sync_time = 0; + priv->calculate_pts_diff = FALSE; + } + + pts = gst_adapter_prev_timestamp(priv->adapter, NULL); + if (pts == GST_CLOCK_TIME_NONE) { /* Buffer without timestamp set*/ + guint temp_ref = priv->svh_hdr.temporal_reference; + if (temp_ref < priv->prev_t_ref) { + temp_ref += 256; + } + guint delta_ref = temp_ref - priv->prev_t_ref; + + pts = priv->sync_time; + // see temporal_reference definition in spec, 30000/1001Hz + pts += gst_util_uint64_scale(delta_ref, GST_SECOND*1001, 30000); + } + priv->sync_time = pts; + priv->prev_t_ref = priv->svh_hdr.temporal_reference; + } + else { + /* Update priv->pts_diff */ + if (priv->calculate_pts_diff) { + calculate_pts_diff(decoder, vol_hdr, vop_hdr); + priv->calculate_pts_diff = FALSE; + } + + /* Update presentation time, 6.3.5 */ + if(vop_hdr->coding_type != GST_MPEG4_B_VOP) { + // increment basing on decoding order + priv->last_sync_time = priv->sync_time; + priv->sync_time = priv->last_sync_time + vop_hdr->modulo_time_base; + pts = priv->sync_time * GST_SECOND; + pts += gst_util_uint64_scale(vop_hdr->time_increment, GST_SECOND, vol_hdr->vop_time_increment_resolution); + priv->last_non_b_scale_time = priv->non_b_scale_time; + priv->non_b_scale_time = priv->sync_time * vol_hdr->vop_time_increment_resolution + vop_hdr->time_increment; + priv->trd = priv->non_b_scale_time - priv->last_non_b_scale_time; + } + else { + // increment basing on display oder + pts = (priv->last_sync_time + vop_hdr->modulo_time_base) * GST_SECOND; + pts += gst_util_uint64_scale(vop_hdr->time_increment, GST_SECOND, vol_hdr->vop_time_increment_resolution); + priv->trb = (priv->last_sync_time + vop_hdr->modulo_time_base) * vol_hdr->vop_time_increment_resolution + + vop_hdr->time_increment - priv->last_non_b_scale_time; + } + } + picture->pts = pts + priv->pts_diff; + if (priv->max_pts == GST_CLOCK_TIME_NONE || priv->max_pts < picture->pts) + priv->max_pts = picture->pts; + + /* Update reference pictures */ + /* XXX: consider priv->vol_hdr.low_delay, consider packed video frames for DivX/XviD */ + if (GST_VAAPI_PICTURE_IS_REFERENCE(picture)) { + if (priv->next_picture) + status = render_picture(decoder, priv->next_picture); + gst_vaapi_picture_replace(&priv->prev_picture, priv->next_picture); + gst_vaapi_picture_replace(&priv->next_picture, picture); + } + return status; +} + +static inline guint +get_vop_coding_type(GstVaapiPicture *picture) +{ + return picture->type - GST_VAAPI_PICTURE_TYPE_I; +} + +static gboolean +fill_picture(GstVaapiDecoderMpeg4 *decoder, GstVaapiPicture *picture) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + VAPictureParameterBufferMPEG4 * const pic_param = picture->param; + GstMpeg4VideoObjectPlane * const vop_hdr = &priv->vop_hdr; + + /* Fill in VAPictureParameterBufferMPEG4 */ + pic_param->forward_reference_picture = VA_INVALID_ID; + pic_param->backward_reference_picture = VA_INVALID_ID; + + pic_param->vol_fields.value = 0; + pic_param->vop_fields.value = 0; + if(priv->is_svh) { + // vol_hdr Parameters + pic_param->vol_fields.bits.short_video_header = 1; + // does the following vol_hdr parameters matter for short video header? + pic_param->vol_fields.bits.chroma_format = 1; // I420, see table 6-15. + pic_param->vol_fields.bits.interlaced = 0; + pic_param->vol_fields.bits.obmc_disable = 1; + pic_param->vol_fields.bits.sprite_enable = 0; + pic_param->vol_fields.bits.sprite_warping_accuracy = 0; + pic_param->vol_fields.bits.quant_type = 0; //method 1; $7.4.4 + pic_param->vol_fields.bits.quarter_sample = 0; + pic_param->vol_fields.bits.data_partitioned = 0; + pic_param->vol_fields.bits.reversible_vlc = 0; + pic_param->vol_fields.bits.resync_marker_disable = 1; + pic_param->no_of_sprite_warping_points = 0; + pic_param->quant_precision = 5; + // VOP parameters + pic_param->vop_width = priv->svh_hdr.vop_width; + pic_param->vop_height = priv->svh_hdr.vop_height; + pic_param->vop_fields.bits.vop_coding_type = priv->svh_hdr.picture_coding_type; + pic_param->vop_time_increment_resolution = priv->vol_hdr.vop_time_increment_resolution; + + pic_param->num_gobs_in_vop = priv->svh_hdr.num_gobs_in_vop; + pic_param->num_macroblocks_in_gob = priv->svh_hdr.num_macroblocks_in_gob; + } + else { + // VOL parameters + pic_param->vol_fields.bits.short_video_header = 0; + pic_param->vol_fields.bits.chroma_format = priv->vol_hdr.chroma_format; + pic_param->vol_fields.bits.interlaced = priv->vol_hdr.interlaced; + pic_param->vol_fields.bits.obmc_disable = priv->vol_hdr.obmc_disable; + pic_param->vol_fields.bits.sprite_enable = priv->vol_hdr.sprite_enable; + pic_param->vol_fields.bits.sprite_warping_accuracy = priv->vol_hdr.sprite_warping_accuracy; + pic_param->vol_fields.bits.quant_type = priv->vol_hdr.quant_type; + pic_param->vol_fields.bits.quarter_sample = priv->vol_hdr.quarter_sample; + pic_param->vol_fields.bits.data_partitioned = priv->vol_hdr.data_partitioned; + pic_param->vol_fields.bits.reversible_vlc = priv->vol_hdr.reversible_vlc; + pic_param->vol_fields.bits.resync_marker_disable = priv->vol_hdr.resync_marker_disable; + pic_param->no_of_sprite_warping_points = priv->vol_hdr.no_of_sprite_warping_points; + int i =0; + for (i=0; i<3 && ivol_hdr.no_of_sprite_warping_points ; i++) { + pic_param->sprite_trajectory_du[i] = priv->sprite_trajectory.vop_ref_points[i]; + pic_param->sprite_trajectory_dv[i] = priv->sprite_trajectory.sprite_ref_points[i]; + } + pic_param->quant_precision = priv->vol_hdr.quant_precision; + + // VOP parameters + pic_param->vop_width = vop_hdr->width; + pic_param->vop_height = vop_hdr->height; + pic_param->vop_fields.bits.vop_coding_type = vop_hdr->coding_type; + pic_param->vop_fields.bits.vop_rounding_type = vop_hdr->rounding_type; + pic_param->vop_fields.bits.intra_dc_vlc_thr = vop_hdr->intra_dc_vlc_thr; + pic_param->vop_fields.bits.top_field_first = vop_hdr->top_field_first; + pic_param->vop_fields.bits.alternate_vertical_scan_flag = vop_hdr->alternate_vertical_scan_flag; + + pic_param->vop_fcode_forward = vop_hdr->fcode_forward; + pic_param->vop_fcode_backward = vop_hdr->fcode_backward; + pic_param->vop_time_increment_resolution = priv->vol_hdr.vop_time_increment_resolution; + } + + pic_param->TRB = 0; + pic_param->TRD = 0; + switch (priv->coding_type) { + case GST_MPEG4_B_VOP: + pic_param->TRB = priv->trb; + pic_param->backward_reference_picture = priv->next_picture->surface_id; + pic_param->vop_fields.bits.backward_reference_vop_coding_type = get_vop_coding_type(priv->next_picture); + // fall-through + case GST_MPEG4_P_VOP: + pic_param->TRD = priv->trd; + if (priv->prev_picture) + pic_param->forward_reference_picture = priv->prev_picture->surface_id; + break; + } + + if (priv->vol_hdr.interlaced) { + priv->is_first_field ^= 1; + } + return TRUE; +} + +static GstVaapiDecoderStatus +decode_slice( + GstVaapiDecoderMpeg4 *decoder, + const guint8 *buf, + guint buf_size, + gboolean has_packet_header +) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstVaapiPicture * const picture = priv->curr_picture; + GstVaapiSlice *slice; + VASliceParameterBufferMPEG4 *slice_param; + + GST_DEBUG("decoder silce: %p, %u bytes)", buf, buf_size); + + // has_packet_header is ture for the 2+ slice + if (!has_packet_header && !fill_picture(decoder, picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + slice = GST_VAAPI_SLICE_NEW(MPEG4, decoder, buf, buf_size); + if (!slice) { + GST_DEBUG("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_add_slice(picture, slice); + + /* Fill in VASliceParameterBufferMPEG4 */ + slice_param = slice->param; + if (priv->is_svh) { + slice_param->macroblock_offset = (priv->svh_hdr.size)%8; + slice_param->macroblock_number = 0; + // the header of first gob_layer is empty (gob_header_empty=1), use vop_quant + slice_param->quant_scale = priv->svh_hdr.vop_quant; + } + else { + if (has_packet_header) { + slice_param->macroblock_offset = priv->packet_hdr.size % 8; + slice_param->macroblock_number = priv->packet_hdr.macroblock_number; + slice_param->quant_scale = priv->packet_hdr.quant_scale; + } + else { + slice_param->macroblock_offset = priv->vop_hdr.size % 8; + slice_param->macroblock_number = 0; + slice_param->quant_scale = priv->vop_hdr.quant; + } + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_packet(GstVaapiDecoderMpeg4 *decoder, GstMpeg4Packet packet) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstMpeg4Packet *tos = &packet; + GstVaapiDecoderStatus status; + + if (tos->size < 0) + return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + + status = gst_vaapi_decoder_check_status(GST_VAAPI_DECODER(decoder)); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + // packet.size is the size from current marker to the next. + if (tos->type == GST_MPEG4_VISUAL_OBJ_SEQ_START) { + status = decode_sequence(decoder, packet.data + packet.offset, packet.size); + } + else if (tos->type == GST_MPEG4_VISUAL_OBJ_SEQ_END) { + status = decode_sequence_end(decoder); + } + else if (tos->type == GST_MPEG4_VISUAL_OBJ) { + status = decode_visual_object(decoder, packet.data + packet.offset, packet.size); + } + else if (tos->type >= GST_MPEG4_VIDEO_OBJ_FIRST && tos->type <= GST_MPEG4_VIDEO_OBJ_LAST) { + GST_WARNING("unexpected marker: (GST_MPEG4_VIDEO_OBJ_FIRST, GST_MPEG4_VIDEO_OBJ_LAST)"); + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + } + else if (tos->type >= GST_MPEG4_VIDEO_LAYER_FIRST && tos->type <= GST_MPEG4_VIDEO_LAYER_LAST) { + status = decode_video_object_layer(decoder, packet.data + packet.offset, packet.size); + } + else if (tos->type == GST_MPEG4_GROUP_OF_VOP) { + status = decode_gop(decoder, packet.data + packet.offset, packet.size); + } + else if (tos->type == GST_MPEG4_VIDEO_OBJ_PLANE) { + status = decode_picture(decoder, packet.data + packet.offset, packet.size); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + + /* decode slice + * A resync marker shall only be located immediately before a macroblock + * (or video packet header if exists) and aligned with a byte + * either start_code or resync_marker are scaned/measured by byte, + * while the header itself are parsed/measured in bit + * it means: resync_marker(video_packet_header) start from byte boundary, + * while MB doesn't start from byte boundary -- it is what 'macroblock_offset' + * in slice refer to + */ + const guint8 *_data = packet.data + packet.offset + priv->vop_hdr.size/8; + gint _data_size = packet.size - (priv->vop_hdr.size/8); + GstMpeg4Packet video_packet; + + if (priv->vol_hdr.resync_marker_disable) { + status = decode_slice(decoder, _data, _data_size, FALSE); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + else { + // next start_code is required to determine the end of last slice + _data_size += 4; + GstMpeg4ParseResult ret = GST_MPEG4_PARSER_OK; + + gboolean first_slice = TRUE; + while (_data_size > 0) { + // we can skip user data here + ret = gst_mpeg4_parse(&video_packet, TRUE, &priv->vop_hdr, _data, 0, _data_size); + if(ret != GST_MPEG4_PARSER_OK) { + break; + } + + if (first_slice) { + status = decode_slice(decoder, _data, video_packet.size, FALSE); + first_slice = FALSE; + } + else { + _data += video_packet.offset; + _data_size -= video_packet.offset; + + ret = gst_mpeg4_parse_video_packet_header (&priv->packet_hdr, &priv->vol_hdr, &priv->vop_hdr, &priv->sprite_trajectory, _data, _data_size); + status = decode_slice(decoder,_data + priv->packet_hdr.size/8, video_packet.size - priv->packet_hdr.size/8, TRUE); + } + + _data += video_packet.size; + _data_size -= video_packet.size; + } + } + status = decode_current_picture(decoder); + } + else if (tos->type == GST_MPEG4_USER_DATA + || tos->type == GST_MPEG4_VIDEO_SESSION_ERR + || tos->type == GST_MPEG4_FBA + || tos->type == GST_MPEG4_FBA_PLAN + || tos->type == GST_MPEG4_MESH + || tos->type == GST_MPEG4_MESH_PLAN + || tos->type == GST_MPEG4_STILL_TEXTURE_OBJ + || tos->type == GST_MPEG4_TEXTURE_SPATIAL + || tos->type == GST_MPEG4_TEXTURE_SNR_LAYER + || tos->type == GST_MPEG4_TEXTURE_TILE + || tos->type == GST_MPEG4_SHAPE_LAYER + || tos->type == GST_MPEG4_STUFFING + || tos->type == GST_MPEG4_SYSTEM_FIRST + || tos->type == GST_MPEG4_SYSTEM_LAST) { + GST_WARNING("Ignore marker: %x\n", tos->type); + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + } + + return status; +} + +static GstVaapiDecoderStatus +decode_buffer(GstVaapiDecoderMpeg4 *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + guchar *buf; + guint pos, buf_size; + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + + // visual object sequence end + if (!buf && buf_size == 0) + return decode_sequence_end(decoder); + + gst_buffer_ref(buffer); + gst_adapter_push(priv->adapter, buffer); + + if (priv->sub_buffer) { + buffer = gst_buffer_merge(priv->sub_buffer, buffer); + if (!buffer) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + gst_buffer_unref(priv->sub_buffer); + priv->sub_buffer = NULL; + } + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + pos = 0; + + GstMpeg4Packet packet; + GstMpeg4ParseResult result = GST_MPEG4_PARSER_OK; + guint consumed_size = 0; + + if (priv->is_svh) { + while (result == GST_MPEG4_PARSER_OK && pos < buf_size) { + result = gst_h263_parse (&packet,buf, pos, buf_size); + if (result != GST_MPEG4_PARSER_OK) { + break; + } + status = decode_picture(decoder, packet.data+packet.offset, packet.size); + if (GST_VAAPI_DECODER_STATUS_SUCCESS == status) { + // MBs are not byte aligned, so we set the start address with byte aligned + // and mb offset with (priv->svh_hdr.size)%8 + status = decode_slice(decoder, packet.data+packet.offset+(priv->svh_hdr.size)/8, + packet.size - (priv->svh_hdr.size)/8, FALSE); + status = decode_current_picture(decoder); + + consumed_size = packet.offset + packet.size; + pos += consumed_size; + if (gst_adapter_available(priv->adapter) >= consumed_size) + gst_adapter_flush(priv->adapter, consumed_size); + } + else { + GST_WARNING("decode h263 packet failed\n"); + break; + } + } + } + else { + while (pos < buf_size) { + // don't skip user data, we need the size to pop tsb buffer + result = gst_mpeg4_parse(&packet, FALSE, NULL, buf, pos, buf_size); + if (result != GST_MPEG4_PARSER_OK) { + break; + } + status = decode_packet(decoder, packet); + if (GST_VAAPI_DECODER_STATUS_SUCCESS == status || + GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA == status) { + consumed_size = packet.offset + packet.size - pos; + pos = packet.offset + packet.size; + if (gst_adapter_available(priv->adapter) >= consumed_size) + gst_adapter_flush(priv->adapter, consumed_size); + } + else { + GST_WARNING("decode mp4 packet failed\n"); + break; + } + } + } + + if ((result == GST_MPEG4_PARSER_NO_PACKET || + result == GST_MPEG4_PARSER_NO_PACKET_END || + status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) && + pos < buf_size) { + priv->sub_buffer = gst_buffer_create_sub(buffer, pos, buf_size-pos); + status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + } + return status; +} + +static GstVaapiDecoderStatus +decode_codec_data(GstVaapiDecoderMpeg4 *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderStatus status; + guchar *buf, *_buf; + guint pos, buf_size, _buf_size; + + _buf = GST_BUFFER_DATA(buffer); + _buf_size = GST_BUFFER_SIZE(buffer); + // add additional 0x000001b2 to enclose the last header + buf_size = _buf_size + 4; + buf = malloc(buf_size); + memcpy(buf, _buf, buf_size); + buf[buf_size-4] = 0; + buf[buf_size-3] = 0; + buf[buf_size-2] = 1; + buf[buf_size-1] = 0xb2; + + pos = 0; + GstMpeg4Packet packet; + GstMpeg4ParseResult result = GST_MPEG4_PARSER_OK; + + while (result == GST_MPEG4_PARSER_OK && pos < buf_size) { + result = gst_mpeg4_parse(&packet, FALSE, NULL, buf, pos, buf_size); + if (result != GST_MPEG4_PARSER_OK) { + break; + } + status = decode_packet(decoder, packet); + if (GST_VAAPI_DECODER_STATUS_SUCCESS == status) { + pos = packet.offset + packet.size; + } + else { + GST_WARNING("decode mp4 packet failed when decoding codec data\n"); + break; + } + } + free(buf); + return status; +} + +GstVaapiDecoderStatus +gst_vaapi_decoder_mpeg4_decode(GstVaapiDecoder *base, GstBuffer *buffer) +{ + GstVaapiDecoderMpeg4 * const decoder = GST_VAAPI_DECODER_MPEG4(base); + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GstBuffer *codec_data = NULL; + GstVaapiDecoderStatus status; + + g_return_val_if_fail(priv->is_constructed, + GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED); + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_mpeg4_open(decoder, buffer); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + + codec_data = GST_VAAPI_DECODER_CODEC_DATA(decoder); + if (codec_data) { + status = decode_codec_data(decoder, codec_data); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + } + return decode_buffer(decoder, buffer); +} + +static void +gst_vaapi_decoder_mpeg4_finalize(GObject *object) +{ + GstVaapiDecoderMpeg4 * const decoder = GST_VAAPI_DECODER_MPEG4(object); + + gst_vaapi_decoder_mpeg4_destroy(decoder); + + G_OBJECT_CLASS(gst_vaapi_decoder_mpeg4_parent_class)->finalize(object); +} + +static void +gst_vaapi_decoder_mpeg4_constructed(GObject *object) +{ + GstVaapiDecoderMpeg4 * const decoder = GST_VAAPI_DECODER_MPEG4(object); + GstVaapiDecoderMpeg4Private * const priv = decoder->priv; + GObjectClass *parent_class; + + parent_class = G_OBJECT_CLASS(gst_vaapi_decoder_mpeg4_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); + + priv->is_constructed = gst_vaapi_decoder_mpeg4_create(decoder); +} + +static void +gst_vaapi_decoder_mpeg4_class_init(GstVaapiDecoderMpeg4Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiDecoderMpeg4Private)); + + object_class->finalize = gst_vaapi_decoder_mpeg4_finalize; + object_class->constructed = gst_vaapi_decoder_mpeg4_constructed; + + decoder_class->decode = gst_vaapi_decoder_mpeg4_decode; + decoder_class->clear_buffer = gst_vaapi_decoder_mpeg4_clear_buffer; +} + +static void +gst_vaapi_decoder_mpeg4_init(GstVaapiDecoderMpeg4 *decoder) +{ + GstVaapiDecoderMpeg4Private *priv; + + priv = GST_VAAPI_DECODER_MPEG4_GET_PRIVATE(decoder); + decoder->priv = priv; + priv->width = 0; + priv->height = 0; + priv->fps_n = 0; + priv->fps_d = 0; + priv->profile = GST_VAAPI_PROFILE_MPEG4_SIMPLE; + priv->curr_picture = NULL; + priv->next_picture = NULL; + priv->prev_picture = NULL; + priv->adapter = NULL; + priv->sub_buffer = NULL; + priv->seq_pts = GST_CLOCK_TIME_NONE; + priv->gop_pts = GST_CLOCK_TIME_NONE; + priv->max_pts = GST_CLOCK_TIME_NONE; + priv->pts_diff = 0; + priv->calculate_pts_diff = TRUE; + priv->is_constructed = FALSE; + priv->is_opened = FALSE; + priv->is_first_field = FALSE; + priv->size_changed = TRUE; + priv->profile_changed = TRUE; + priv->progressive_sequence = FALSE; + priv->closed_gop = FALSE; + priv->broken_link = FALSE; + priv->last_non_b_scale_time = 0; + priv->non_b_scale_time = 0; + priv->trb = 0; + priv->trd = 0; +} + +/** + * gst_vaapi_decoder_mpeg4_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for MPEG-2 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_mpeg4_new(GstVaapiDisplay *display, GstCaps *caps) +{ + GstVaapiDecoderMpeg4 *decoder; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(GST_IS_CAPS(caps), NULL); + + decoder = g_object_new( + GST_VAAPI_TYPE_DECODER_MPEG4, + "display", display, + "caps", caps, + NULL + ); + if (!decoder->priv->is_constructed) { + g_object_unref(decoder); + return NULL; + } + return GST_VAAPI_DECODER_CAST(decoder); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h new file mode 100644 index 0000000..4c877bb --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h @@ -0,0 +1,88 @@ +/* + * gstvaapidecoder_mpeg4.h - MPEG-4 decoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_MPEG4_H +#define GST_VAAPI_DECODER_MPEG4_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DECODER_MPEG4 \ + (gst_vaapi_decoder_mpeg4_get_type()) + +#define GST_VAAPI_DECODER_MPEG4(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DECODER_MPEG4, \ + GstVaapiDecoderMpeg4)) + +#define GST_VAAPI_DECODER_MPEG4_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DECODER_MPEG4, \ + GstVaapiDecoderMpeg4Class)) + +#define GST_VAAPI_IS_DECODER_MPEG4(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DECODER_MPEG4)) + +#define GST_VAAPI_IS_DECODER_MPEG4_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DECODER_MPEG4)) + +#define GST_VAAPI_DECODER_MPEG4_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DECODER_MPEG4, \ + GstVaapiDecoderMpeg4Class)) + +typedef struct _GstVaapiDecoderMpeg4 GstVaapiDecoderMpeg4; +typedef struct _GstVaapiDecoderMpeg4Private GstVaapiDecoderMpeg4Private; +typedef struct _GstVaapiDecoderMpeg4Class GstVaapiDecoderMpeg4Class; + +/** + * GstVaapiDecoderMpeg4: + * + * A decoder based on Mpeg4. + */ +struct _GstVaapiDecoderMpeg4 { + /*< private >*/ + GstVaapiDecoder parent_instance; + + GstVaapiDecoderMpeg4Private *priv; +}; + +/** + * GstVaapiDecoderMpeg4Class: + * + * A decoder class based on Mpeg4. + */ +struct _GstVaapiDecoderMpeg4Class { + /*< private >*/ + GstVaapiDecoderClass parent_class; +}; + +GType +gst_vaapi_decoder_mpeg4_get_type(void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_mpeg4_new(GstVaapiDisplay *display, GstCaps *caps); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_MPEG4_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_objects.c b/gst-libs/gst/vaapi/gstvaapidecoder_objects.c new file mode 100644 index 0000000..5f90fb0 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_objects.c @@ -0,0 +1,440 @@ +/* + * gstvaapidecoder_objects.c - VA decoder objects helpers + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define GET_DECODER(obj) GST_VAAPI_DECODER_CAST((obj)->parent_instance.codec) +#define GET_CONTEXT(obj) GET_DECODER(obj)->priv->context +#define GET_VA_DISPLAY(obj) GET_DECODER(obj)->priv->va_display +#define GET_VA_CONTEXT(obj) GET_DECODER(obj)->priv->va_context + +/* ------------------------------------------------------------------------- */ +/* --- Pictures --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiPicture, + gst_vaapi_picture, + GST_VAAPI_TYPE_CODEC_OBJECT) + +enum { + GST_VAAPI_CREATE_PICTURE_FLAG_CLONE = 1 << 0, + GST_VAAPI_CREATE_PICTURE_FLAG_FIELD = 1 << 1, +}; + +static void +destroy_slice_cb(gpointer data, gpointer user_data) +{ + GstMiniObject * const object = data; + + gst_mini_object_unref(object); +} + +static void +gst_vaapi_picture_destroy(GstVaapiPicture *picture) +{ + if (picture->slices) { + g_ptr_array_foreach(picture->slices, destroy_slice_cb, NULL); + g_ptr_array_free(picture->slices, TRUE); + picture->slices = NULL; + } + + if (picture->iq_matrix) { + gst_mini_object_unref(GST_MINI_OBJECT(picture->iq_matrix)); + picture->iq_matrix = NULL; + } + + if (picture->huf_table) { + gst_mini_object_unref(GST_MINI_OBJECT(picture->huf_table)); + picture->huf_table = NULL; + } + + if (picture->bitplane) { + gst_mini_object_unref(GST_MINI_OBJECT(picture->bitplane)); + picture->bitplane = NULL; + } + + if (picture->proxy) { + g_object_unref(picture->proxy); + picture->proxy = NULL; + } + else if (picture->surface) { + /* Explicitly release any surface that was not bound to a proxy */ + gst_vaapi_context_put_surface(GET_CONTEXT(picture), picture->surface); + } + picture->surface_id = VA_INVALID_ID; + picture->surface = NULL; + + vaapi_destroy_buffer(GET_VA_DISPLAY(picture), &picture->param_id); + picture->param = NULL; +} + +static gboolean +gst_vaapi_picture_create( + GstVaapiPicture *picture, + const GstVaapiCodecObjectConstructorArgs *args +) +{ + gboolean success; + + if (args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_CLONE) { + GstVaapiPicture * const parent_picture = GST_VAAPI_PICTURE(args->data); + + picture->proxy = g_object_ref(parent_picture->proxy); + picture->surface = gst_vaapi_surface_proxy_get_surface(picture->proxy); + picture->type = parent_picture->type; + picture->pts = parent_picture->pts; + picture->poc = parent_picture->poc; + + // Copy all picture flags but "output" + GST_VAAPI_PICTURE_FLAG_SET( + picture, + GST_VAAPI_PICTURE_FLAGS(parent_picture) & + (GST_VAAPI_PICTURE_FLAG_SKIPPED | + GST_VAAPI_PICTURE_FLAG_REFERENCE | + GST_VAAPI_PICTURE_FLAG_INTERLACED | + GST_VAAPI_PICTURE_FLAG_FF | + GST_VAAPI_PICTURE_FLAG_TFF) + ); + + picture->structure = parent_picture->structure; + if ((args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_FIELD) && + GST_VAAPI_PICTURE_IS_INTERLACED(picture)) { + switch (picture->structure) { + case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD: + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD; + break; + case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD: + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD; + break; + } + GST_VAAPI_PICTURE_FLAG_UNSET(picture, GST_VAAPI_PICTURE_FLAG_FF); + } + } + else { + picture->surface = gst_vaapi_context_get_surface(GET_CONTEXT(picture)); + if (!picture->surface) + return FALSE; + + picture->proxy = + gst_vaapi_surface_proxy_new(GET_CONTEXT(picture), picture->surface); + if (!picture->proxy) + return FALSE; + + picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_FF); + } + picture->surface_id = gst_vaapi_surface_get_id(picture->surface); + + success = vaapi_create_buffer( + GET_VA_DISPLAY(picture), + GET_VA_CONTEXT(picture), + VAPictureParameterBufferType, + args->param_size, + args->param, + &picture->param_id, + &picture->param + ); + if (!success) + return FALSE; + picture->param_size = args->param_size; + + picture->slices = g_ptr_array_new(); + if (!picture->slices) + return FALSE; + return TRUE; +} + +static void +gst_vaapi_picture_init(GstVaapiPicture *picture) +{ + picture->type = GST_VAAPI_PICTURE_TYPE_NONE; + picture->surface = NULL; + picture->proxy = NULL; + picture->surface_id = VA_INVALID_ID; + picture->param = NULL; + picture->param_id = VA_INVALID_ID; + picture->param_size = 0; + picture->slices = NULL; + picture->iq_matrix = NULL; + picture->huf_table = NULL; + picture->bitplane = NULL; + picture->pts = GST_CLOCK_TIME_NONE; + picture->poc = 0; +} + +GstVaapiPicture * +gst_vaapi_picture_new( + GstVaapiDecoder *decoder, + gconstpointer param, + guint param_size +) +{ + GstVaapiCodecObject *object; + + g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL); + + object = gst_vaapi_codec_object_new( + GST_VAAPI_TYPE_PICTURE, + GST_VAAPI_CODEC_BASE(decoder), + param, param_size, + NULL, 0 + ); + if (!object) + return NULL; + return GST_VAAPI_PICTURE_CAST(object); +} + +GstVaapiPicture * +gst_vaapi_picture_new_field(GstVaapiPicture *picture) +{ + GstMiniObject *obj; + GstVaapiCodecObject *va_obj; + GstVaapiCodecObjectConstructorArgs args; + + g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), NULL); + + obj = gst_mini_object_new(GST_VAAPI_TYPE_PICTURE); + if (!obj) + return NULL; + + va_obj = GST_VAAPI_CODEC_OBJECT(obj); + args.codec = GST_VAAPI_CODEC_BASE(GET_DECODER(picture)); + args.param = NULL; + args.param_size = picture->param_size; + args.data = picture; + args.data_size = 0; + args.flags = (GST_VAAPI_CREATE_PICTURE_FLAG_CLONE| + GST_VAAPI_CREATE_PICTURE_FLAG_FIELD); + if (gst_vaapi_codec_object_construct(va_obj, &args)) + return GST_VAAPI_PICTURE_CAST(va_obj); + + gst_mini_object_unref(obj); + return NULL; +} + +void +gst_vaapi_picture_add_slice(GstVaapiPicture *picture, GstVaapiSlice *slice) +{ + g_return_if_fail(GST_VAAPI_IS_PICTURE(picture)); + g_return_if_fail(GST_VAAPI_IS_SLICE(slice)); + + g_ptr_array_add(picture->slices, slice); +} + +static gboolean +do_decode(VADisplay dpy, VAContextID ctx, VABufferID *buf_id, void **buf_ptr) +{ + VAStatus status; + + vaapi_unmap_buffer(dpy, *buf_id, buf_ptr); + + status = vaRenderPicture(dpy, ctx, buf_id, 1); + if (!vaapi_check_status(status, "vaRenderPicture()")) + return FALSE; + + /* XXX: vaRenderPicture() is meant to destroy the VA buffer implicitly */ + vaapi_destroy_buffer(dpy, buf_id); + return TRUE; +} + +gboolean +gst_vaapi_picture_decode(GstVaapiPicture *picture) +{ + GstVaapiIqMatrix *iq_matrix; + GstVaapiBitPlane *bitplane; + GstVaapiHuffmanTable *huf_table; + VADisplay va_display; + VAContextID va_context; + VAStatus status; + guint i; + + g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE); + + va_display = GET_VA_DISPLAY(picture); + va_context = GET_VA_CONTEXT(picture); + + GST_DEBUG("decode picture 0x%08x", picture->surface_id); + + status = vaBeginPicture(va_display, va_context, picture->surface_id); + if (!vaapi_check_status(status, "vaBeginPicture()")) + return FALSE; + + if (!do_decode(va_display, va_context, &picture->param_id, &picture->param)) + return FALSE; + + iq_matrix = picture->iq_matrix; + if (iq_matrix && !do_decode(va_display, va_context, + &iq_matrix->param_id, &iq_matrix->param)) + return FALSE; + + bitplane = picture->bitplane; + if (bitplane && !do_decode(va_display, va_context, + &bitplane->data_id, (void **)&bitplane->data)) + return FALSE; + + huf_table = picture->huf_table; + if (huf_table && !do_decode(va_display, va_context, + &huf_table->param_id, + (void **)&huf_table->param)) + return FALSE; + + for (i = 0; i < picture->slices->len; i++) { + GstVaapiSlice * const slice = g_ptr_array_index(picture->slices, i); + VABufferID va_buffers[2]; + + vaapi_unmap_buffer(va_display, slice->param_id, NULL); + va_buffers[0] = slice->param_id; + va_buffers[1] = slice->data_id; + + status = vaRenderPicture(va_display, va_context, va_buffers, 2); + if (!vaapi_check_status(status, "vaRenderPicture()")) + return FALSE; + + vaapi_destroy_buffer(va_display, &slice->param_id); + vaapi_destroy_buffer(va_display, &slice->data_id); + } + + status = vaEndPicture(va_display, va_context); + if (!vaapi_check_status(status, "vaEndPicture()")) + return FALSE; + return TRUE; +} + +gboolean +gst_vaapi_picture_output(GstVaapiPicture *picture) +{ + GstVaapiSurfaceProxy *proxy; + + g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE); + + if (!picture->proxy) + return FALSE; + + if (!GST_VAAPI_PICTURE_IS_SKIPPED(picture)) { + proxy = g_object_ref(picture->proxy); + gst_vaapi_surface_proxy_set_timestamp(proxy, picture->pts); + if (GST_VAAPI_PICTURE_IS_INTERLACED(picture)) + gst_vaapi_surface_proxy_set_interlaced(proxy, TRUE); + if (GST_VAAPI_PICTURE_IS_TFF(picture)) + gst_vaapi_surface_proxy_set_tff(proxy, TRUE); + gst_vaapi_decoder_push_surface_proxy(GET_DECODER(picture), proxy); + } + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_OUTPUT); + return TRUE; +} + +/* ------------------------------------------------------------------------- */ +/* --- Slices --- */ +/* ------------------------------------------------------------------------- */ + +GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiSlice, + gst_vaapi_slice, + GST_VAAPI_TYPE_CODEC_OBJECT) + +static void +gst_vaapi_slice_destroy(GstVaapiSlice *slice) +{ + VADisplay const va_display = GET_VA_DISPLAY(slice); + + vaapi_destroy_buffer(va_display, &slice->data_id); + vaapi_destroy_buffer(va_display, &slice->param_id); + slice->param = NULL; +} + +static gboolean +gst_vaapi_slice_create( + GstVaapiSlice *slice, + const GstVaapiCodecObjectConstructorArgs *args +) +{ + VASliceParameterBufferBase *slice_param; + gboolean success; + + success = vaapi_create_buffer( + GET_VA_DISPLAY(slice), + GET_VA_CONTEXT(slice), + VASliceDataBufferType, + args->data_size, + args->data, + &slice->data_id, + NULL + ); + if (!success) + return FALSE; + + success = vaapi_create_buffer( + GET_VA_DISPLAY(slice), + GET_VA_CONTEXT(slice), + VASliceParameterBufferType, + args->param_size, + args->param, + &slice->param_id, + &slice->param + ); + if (!success) + return FALSE; + + slice_param = slice->param; + slice_param->slice_data_size = args->data_size; + slice_param->slice_data_offset = 0; + slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL; + return TRUE; +} + +static void +gst_vaapi_slice_init(GstVaapiSlice *slice) +{ + slice->param = NULL; + slice->param_id = VA_INVALID_ID; + slice->data_id = VA_INVALID_ID; +} + +GstVaapiSlice * +gst_vaapi_slice_new( + GstVaapiDecoder *decoder, + gconstpointer param, + guint param_size, + const guchar *data, + guint data_size +) +{ + GstVaapiCodecObject *object; + + g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL); + + object = gst_vaapi_codec_object_new( + GST_VAAPI_TYPE_SLICE, + GST_VAAPI_CODEC_BASE(decoder), + param, param_size, + data, data_size + ); + return GST_VAAPI_SLICE_CAST(object); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_objects.h b/gst-libs/gst/vaapi/gstvaapidecoder_objects.h new file mode 100644 index 0000000..f7a7ea6 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_objects.h @@ -0,0 +1,295 @@ +/* + * gstvaapidecoder_objects.h - VA decoder objects + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_OBJECTS_H +#define GST_VAAPI_DECODER_OBJECTS_H + +#include + +G_BEGIN_DECLS + +typedef enum _GstVaapiPictureType GstVaapiPictureType; +typedef struct _GstVaapiPicture GstVaapiPicture; +typedef struct _GstVaapiPictureClass GstVaapiPictureClass; +typedef struct _GstVaapiSlice GstVaapiSlice; +typedef struct _GstVaapiSliceClass GstVaapiSliceClass; + +/* ------------------------------------------------------------------------- */ +/* --- Pictures --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_TYPE_PICTURE \ + (gst_vaapi_picture_get_type()) + +#define GST_VAAPI_PICTURE_CAST(obj) \ + ((GstVaapiPicture *)(obj)) + +#define GST_VAAPI_PICTURE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_PICTURE, \ + GstVaapiPicture)) + +#define GST_VAAPI_PICTURE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_PICTURE, \ + GstVaapiPictureClass)) + +#define GST_VAAPI_IS_PICTURE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_PICTURE)) + +#define GST_VAAPI_IS_PICTURE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_PICTURE)) + +#define GST_VAAPI_PICTURE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_PICTURE, \ + GstVaapiPictureClass)) + +enum _GstVaapiPictureType { + GST_VAAPI_PICTURE_TYPE_NONE = 0, // Undefined + GST_VAAPI_PICTURE_TYPE_I, // Intra + GST_VAAPI_PICTURE_TYPE_P, // Predicted + GST_VAAPI_PICTURE_TYPE_B, // Bi-directional predicted + GST_VAAPI_PICTURE_TYPE_S, // S(GMC)-VOP (MPEG-4) + GST_VAAPI_PICTURE_TYPE_SI, // Switching Intra + GST_VAAPI_PICTURE_TYPE_SP, // Switching Predicted + GST_VAAPI_PICTURE_TYPE_BI, // BI type (VC-1) +}; + +/** + * Picture flags: + * @GST_VAAPI_PICTURE_FLAG_SKIPPED: skipped frame + * @GST_VAAPI_PICTURE_FLAG_REFERENCE: reference frame + * @GST_VAAPI_PICTURE_FLAG_OUTPUT: frame was output + * @GST_VAAPI_PICTURE_FLAG_INTERLACED: interlaced frame + * @GST_VAAPI_PICTURE_FLAG_FF: first-field + * @GST_VAAPI_PICTURE_FLAG_TFF: top-field-first + * @GST_VAAPI_PICTURE_FLAG_LAST: first flag that can be used by subclasses + * + * Enum values used for #GstVaapiPicture flags. + */ +enum { + GST_VAAPI_PICTURE_FLAG_SKIPPED = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 0), + GST_VAAPI_PICTURE_FLAG_REFERENCE = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 1), + GST_VAAPI_PICTURE_FLAG_OUTPUT = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 2), + GST_VAAPI_PICTURE_FLAG_INTERLACED = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 3), + GST_VAAPI_PICTURE_FLAG_FF = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 4), + GST_VAAPI_PICTURE_FLAG_TFF = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 5), + GST_VAAPI_PICTURE_FLAG_LAST = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 6), +}; + +#define GST_VAAPI_PICTURE_FLAGS GST_MINI_OBJECT_FLAGS +#define GST_VAAPI_PICTURE_FLAG_IS_SET GST_MINI_OBJECT_FLAG_IS_SET +#define GST_VAAPI_PICTURE_FLAG_SET GST_MINI_OBJECT_FLAG_SET +#define GST_VAAPI_PICTURE_FLAG_UNSET GST_MINI_OBJECT_FLAG_UNSET + +#define GST_VAAPI_PICTURE_IS_SKIPPED(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_SKIPPED) + +#define GST_VAAPI_PICTURE_IS_REFERENCE(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE) + +#define GST_VAAPI_PICTURE_IS_OUTPUT(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_OUTPUT) + +#define GST_VAAPI_PICTURE_IS_INTERLACED(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_INTERLACED) + +#define GST_VAAPI_PICTURE_IS_FIRST_FIELD(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_FF) + +#define GST_VAAPI_PICTURE_IS_TFF(picture) \ + GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_TFF) + +#define GST_VAAPI_PICTURE_IS_FRAME(picture) \ + (GST_VAAPI_PICTURE(picture)->structure == GST_VAAPI_PICTURE_STRUCTURE_FRAME) + +#define GST_VAAPI_PICTURE_IS_COMPLETE(picture) \ + (GST_VAAPI_PICTURE_IS_FRAME(picture) || \ + !GST_VAAPI_PICTURE_IS_FIRST_FIELD(picture)) + +/** + * GstVaapiPicture: + * + * A #GstVaapiCodecObject holding a picture parameter. + */ +struct _GstVaapiPicture { + /*< private >*/ + GstVaapiCodecObject parent_instance; + GstVaapiSurface *surface; + GstVaapiSurfaceProxy *proxy; + VABufferID param_id; + guint param_size; + + /*< public >*/ + GstVaapiPictureType type; + VASurfaceID surface_id; + gpointer param; + GPtrArray *slices; + GstVaapiIqMatrix *iq_matrix; + GstVaapiHuffmanTable *huf_table; + GstVaapiBitPlane *bitplane; + GstClockTime pts; + gint32 poc; + guint structure; +}; + +/** + * GstVaapiPictureClass: + * + * The #GstVaapiPicture base class. + */ +struct _GstVaapiPictureClass { + /*< private >*/ + GstVaapiCodecObjectClass parent_class; +}; + +G_GNUC_INTERNAL +GType +gst_vaapi_picture_get_type(void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstVaapiPicture * +gst_vaapi_picture_new( + GstVaapiDecoder *decoder, + gconstpointer param, + guint param_size +); + +G_GNUC_INTERNAL +GstVaapiPicture * +gst_vaapi_picture_new_field(GstVaapiPicture *picture); + +G_GNUC_INTERNAL +void +gst_vaapi_picture_add_slice(GstVaapiPicture *picture, GstVaapiSlice *slice); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_picture_decode(GstVaapiPicture *picture); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_picture_output(GstVaapiPicture *picture); + +static inline gpointer +gst_vaapi_picture_ref(gpointer ptr) +{ + return gst_mini_object_ref(GST_MINI_OBJECT(ptr)); +} + +static inline void +gst_vaapi_picture_unref(gpointer ptr) +{ + gst_mini_object_unref(GST_MINI_OBJECT(ptr)); +} + +#define gst_vaapi_picture_replace(old_picture_p, new_picture) \ + gst_mini_object_replace((GstMiniObject **)(old_picture_p), \ + (GstMiniObject *)(new_picture)) + +/* ------------------------------------------------------------------------- */ +/* --- Slices --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_TYPE_SLICE \ + (gst_vaapi_slice_get_type()) + +#define GST_VAAPI_SLICE_CAST(obj) \ + ((GstVaapiSlice *)(obj)) + +#define GST_VAAPI_SLICE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_SLICE, \ + GstVaapiSlice)) + +#define GST_VAAPI_SLICE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_SLICE, \ + GstVaapiSliceClass)) + +#define GST_VAAPI_IS_SLICE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_SLICE)) + +#define GST_VAAPI_IS_SLICE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_SLICE)) + +#define GST_VAAPI_SLICE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_SLICE, \ + GstVaapiSliceClass)) + +/** + * GstVaapiSlice: + * + * A #GstVaapiCodecObject holding a slice parameter. + */ +struct _GstVaapiSlice { + /*< private >*/ + GstVaapiCodecObject parent_instance; + + /*< public >*/ + VABufferID param_id; + VABufferID data_id; + gpointer param; +}; + +/** + * GstVaapiSliceClass: + * + * The #GstVaapiSlice base class. + */ +struct _GstVaapiSliceClass { + /*< private >*/ + GstVaapiCodecObjectClass parent_class; +}; + +G_GNUC_INTERNAL +GType +gst_vaapi_slice_get_type(void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GstVaapiSlice * +gst_vaapi_slice_new( + GstVaapiDecoder *decoder, + gconstpointer param, + guint param_size, + const guchar *data, + guint data_size +); + +/* ------------------------------------------------------------------------- */ +/* --- Helpers to create codec-dependent objects --- */ +/* ------------------------------------------------------------------------- */ + +#define GST_VAAPI_PICTURE_NEW(codec, decoder) \ + gst_vaapi_picture_new(GST_VAAPI_DECODER_CAST(decoder), \ + NULL, sizeof(VAPictureParameterBuffer##codec)) + +#define GST_VAAPI_SLICE_NEW(codec, decoder, buf, buf_size) \ + gst_vaapi_slice_new(GST_VAAPI_DECODER_CAST(decoder), \ + NULL, sizeof(VASliceParameterBuffer##codec), \ + buf, buf_size) + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_OBJECTS_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_priv.h b/gst-libs/gst/vaapi/gstvaapidecoder_priv.h new file mode 100644 index 0000000..686a16b --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_priv.h @@ -0,0 +1,196 @@ +/* + * gstvaapidecoder_priv.h - VA decoder abstraction (private definitions) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_PRIV_H +#define GST_VAAPI_DECODER_PRIV_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_DECODER_CAST(decoder) ((GstVaapiDecoder *)(decoder)) + +/** + * GST_VAAPI_DECODER_DISPLAY: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the #GstVaapiDisplay of @decoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_DISPLAY +#define GST_VAAPI_DECODER_DISPLAY(decoder) \ + GST_VAAPI_DECODER_CAST(decoder)->priv->display + +/** + * GST_VAAPI_DECODER_CONTEXT: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the #GstVaapiContext of @decoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_CONTEXT +#define GST_VAAPI_DECODER_CONTEXT(decoder) \ + GST_VAAPI_DECODER_CAST(decoder)->priv->context + +/** + * GST_VAAPI_DECODER_CODEC: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the #GstVaapiCodec of @decoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_CODEC +#define GST_VAAPI_DECODER_CODEC(decoder) \ + GST_VAAPI_DECODER_CAST(decoder)->priv->codec + +/** + * GST_VAAPI_DECODER_CODEC_DATA: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the #GstBuffer holding optional codec data + * for @decoder. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_CODEC_DATA +#define GST_VAAPI_DECODER_CODEC_DATA(decoder) \ + GST_VAAPI_DECODER_CAST(decoder)->priv->codec_data + +/** + * GST_VAAPI_DECODER_WIDTH: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the coded width of the picture + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_WIDTH +#define GST_VAAPI_DECODER_WIDTH(decoder) \ + GST_VAAPI_DECODER_CAST(decoder)->priv->width + +/** + * GST_VAAPI_DECODER_HEIGHT: + * @decoder: a #GstVaapiDecoder + * + * Macro that evaluates to the coded height of the picture + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DECODER_HEIGHT +#define GST_VAAPI_DECODER_HEIGHT(decoder) \ + GST_VAAPI_DECODER_CAST(decoder)->priv->height + +/* End-of-Stream buffer */ +#define GST_BUFFER_FLAG_EOS (GST_BUFFER_FLAG_LAST + 0) + +#define GST_BUFFER_IS_EOS(buffer) \ + GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_EOS) + +#define GST_VAAPI_DECODER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DECODER, \ + GstVaapiDecoderPrivate)) + +/* Number of scratch surfaces beyond those used as reference */ +/* 5 = 2 + 4; 2 for reference, 4 for scratch*/ +#define GST_DECODER_DEFAULT_SURFACES_COUNT 6 + +struct _GstVaapiDecoderPrivate { + GstVaapiDisplay *display; + VADisplay va_display; + GstVaapiContext *context; + VAContextID va_context; + GstCaps *caps; + GstVaapiCodec codec; + GstBuffer *codec_data; + guint width; + guint height; + guint fps_n; + guint fps_d; + guint par_n; + guint par_d; + GQueue *buffers; + GQueue *surfaces; + guint is_interlaced : 1; +}; + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_set_picture_size( + GstVaapiDecoder *decoder, + guint width, + guint height +); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_set_framerate( + GstVaapiDecoder *decoder, + guint fps_n, + guint fps_d +); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_set_pixel_aspect_ratio( + GstVaapiDecoder *decoder, + guint par_n, + guint par_d +); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_set_interlaced(GstVaapiDecoder *decoder, gboolean interlaced); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_decoder_ensure_context( + GstVaapiDecoder *decoder, + GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint, + guint width, + guint height, + guint surface_num +); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_decoder_push_buffer_sub( + GstVaapiDecoder *decoder, + GstBuffer *buffer, + guint offset, + guint size +); + +G_GNUC_INTERNAL +void +gst_vaapi_decoder_push_surface_proxy( + GstVaapiDecoder *decoder, + GstVaapiSurfaceProxy *proxy +); + +G_GNUC_INTERNAL +GstVaapiDecoderStatus +gst_vaapi_decoder_check_status(GstVaapiDecoder *decoder); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c b/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c new file mode 100644 index 0000000..f91a6d5 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c @@ -0,0 +1,1344 @@ +/* + * gstvaapidecoder_vc1.c - VC-1 decoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidecoder_vc1 + * @short_description: VC-1 decoder + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapidecoder_vc1.h" +#include "gstvaapidecoder_objects.h" +#include "gstvaapidecoder_priv.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiobject_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDecoderVC1, + gst_vaapi_decoder_vc1, + GST_VAAPI_TYPE_DECODER); + +#define GST_VAAPI_DECODER_VC1_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DECODER_VC1, \ + GstVaapiDecoderVC1Private)) + +struct _GstVaapiDecoderVC1Private { + GstVaapiProfile profile; + guint width; + guint height; + guint fps_n; + guint fps_d; + GstVC1SeqHdr seq_hdr; + GstVC1EntryPointHdr entrypoint_hdr; + GstVC1FrameHdr frame_hdr; + GstVC1BitPlanes *bitplanes; + GstVaapiPicture *current_picture; + GstVaapiPicture *next_picture; + GstVaapiPicture *prev_picture; + GstAdapter *adapter; + GstBuffer *sub_buffer; + guint8 *rbdu_buffer; + guint rbdu_buffer_size; + guint is_constructed : 1; + guint is_opened : 1; + guint is_first_field : 1; + guint has_entrypoint : 1; + guint size_changed : 1; + guint profile_changed : 1; + guint closed_entry : 1; + guint broken_link : 1; +}; + +static GstVaapiDecoderStatus +get_status(GstVC1ParserResult result) +{ + GstVaapiDecoderStatus status; + + switch (result) { + case GST_VC1_PARSER_OK: + status = GST_VAAPI_DECODER_STATUS_SUCCESS; + break; + case GST_VC1_PARSER_NO_BDU_END: + status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; + break; + case GST_VC1_PARSER_ERROR: + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + default: + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + break; + } + return status; +} + +static void +gst_vaapi_decoder_vc1_close(GstVaapiDecoderVC1 *decoder) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + + gst_vaapi_picture_replace(&priv->current_picture, NULL); + gst_vaapi_picture_replace(&priv->next_picture, NULL); + gst_vaapi_picture_replace(&priv->prev_picture, NULL); + + if (priv->sub_buffer) { + gst_buffer_unref(priv->sub_buffer); + priv->sub_buffer = NULL; + } + + if (priv->bitplanes) { + gst_vc1_bitplanes_free(priv->bitplanes); + priv->bitplanes = NULL; + } + + if (priv->adapter) { + gst_adapter_clear(priv->adapter); + g_object_unref(priv->adapter); + priv->adapter = NULL; + } +} + +static gboolean +gst_vaapi_decoder_vc1_open(GstVaapiDecoderVC1 *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + + gst_vaapi_decoder_vc1_close(decoder); + + priv->adapter = gst_adapter_new(); + if (!priv->adapter) + return FALSE; + + priv->bitplanes = gst_vc1_bitplanes_new(); + if (!priv->bitplanes) + return FALSE; + return TRUE; +} + +static void +gst_vaapi_decoder_vc1_destroy(GstVaapiDecoderVC1 *decoder) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + + gst_vaapi_decoder_vc1_close(decoder); + + if (priv->rbdu_buffer) { + g_free(priv->rbdu_buffer); + priv->rbdu_buffer = NULL; + priv->rbdu_buffer_size = 0; + } +} + +static gboolean +gst_vaapi_decoder_vc1_create(GstVaapiDecoderVC1 *decoder) +{ + if (!GST_VAAPI_DECODER_CODEC(decoder)) + return FALSE; + return TRUE; +} + +static GstVaapiDecoderStatus +ensure_context(GstVaapiDecoderVC1 *decoder) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVaapiProfile profiles[2]; + GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD; + guint i, n_profiles = 0; + gboolean reset_context = FALSE; + + if (priv->profile_changed) { + GST_DEBUG("profile changed"); + priv->profile_changed = FALSE; + reset_context = TRUE; + + profiles[n_profiles++] = priv->profile; + if (priv->profile == GST_VAAPI_PROFILE_VC1_SIMPLE) + profiles[n_profiles++] = GST_VAAPI_PROFILE_VC1_MAIN; + + for (i = 0; i < n_profiles; i++) { + if (gst_vaapi_display_has_decoder(GST_VAAPI_DECODER_DISPLAY(decoder), + profiles[i], entrypoint)) + break; + } + if (i == n_profiles) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + priv->profile = profiles[i]; + } + + if (priv->size_changed) { + GST_DEBUG("size changed"); + priv->size_changed = FALSE; + reset_context = TRUE; + } + + if (reset_context) { + reset_context = gst_vaapi_decoder_ensure_context( + GST_VAAPI_DECODER(decoder), + priv->profile, + entrypoint, + priv->width, + priv->height, + GST_DECODER_DEFAULT_SURFACES_COUNT + ); + if (!reset_context) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static inline GstVaapiDecoderStatus +render_picture(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture) +{ + if (!gst_vaapi_picture_output(picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_current_picture(GstVaapiDecoderVC1 *decoder) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVaapiPicture * const picture = priv->current_picture; + GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS; + + if (picture) { + if (!gst_vaapi_picture_decode(picture)) + status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + if (!GST_VAAPI_PICTURE_IS_REFERENCE(picture)) { + if (priv->prev_picture && priv->next_picture) + status = render_picture(decoder, picture); + } + gst_vaapi_picture_replace(&priv->current_picture, NULL); + } + return status; +} + +static GstVaapiDecoderStatus +decode_sequence(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu) +{ + GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder); + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr; + GstVC1AdvancedSeqHdr * const adv_hdr = &seq_hdr->advanced; + GstVC1SeqStructC * const structc = &seq_hdr->struct_c; + GstVC1ParserResult result; + GstVaapiProfile profile; + guint width, height, fps_n, fps_d; + + result = gst_vc1_parse_sequence_header( + rbdu->data + rbdu->offset, + rbdu->size, + seq_hdr + ); + if (result != GST_VC1_PARSER_OK) { + GST_DEBUG("failed to parse sequence layer"); + return get_status(result); + } + + priv->has_entrypoint = FALSE; + + /* Validate profile */ + switch (seq_hdr->profile) { + case GST_VC1_PROFILE_SIMPLE: + case GST_VC1_PROFILE_MAIN: + case GST_VC1_PROFILE_ADVANCED: + break; + default: + GST_DEBUG("unsupported profile %d", seq_hdr->profile); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + } + + fps_n = 0; + fps_d = 0; + switch (seq_hdr->profile) { + case GST_VC1_PROFILE_SIMPLE: + case GST_VC1_PROFILE_MAIN: + if (structc->wmvp) { + fps_n = structc->framerate; + fps_d = 1; + } + break; + case GST_VC1_PROFILE_ADVANCED: + if (adv_hdr->display_ext && adv_hdr->framerate_flag) { + if (adv_hdr->framerateind) { + // 6.1.14.4.4 - Frame Rate Explicit + fps_n = adv_hdr->framerateexp + 1; + fps_d = 32; + } + else { + // 6.1.14.4.2 - Frame Rate Numerator + static const guint frameratenr_table[] = { + [1] = 24000, + [2] = 25000, + [3] = 30000, + [4] = 50000, + [5] = 60000, + [6] = 48000, + [7] = 72000 + }; + + // 6.1.14.4.3 - Frame Rate Denominator + static const guint frameratedr_table[] = { + [1] = 1000, + [2] = 1001 + }; + + if (adv_hdr->frameratenr < 1 || adv_hdr->frameratenr > 7) { + GST_DEBUG("unsupported FRAMERATENR value"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + fps_n = frameratenr_table[adv_hdr->frameratenr]; + + if (adv_hdr->frameratedr < 1 || adv_hdr->frameratedr > 2) { + GST_DEBUG("unsupported FRAMERATEDR value"); + return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + } + fps_d = frameratedr_table[adv_hdr->frameratedr]; + } + } + break; + default: + g_assert(0 && "XXX: we already validated the profile above"); + break; + } + if (fps_n && fps_d) { + priv->fps_n = fps_n; + priv->fps_d = fps_d; + gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d); + } + + switch (seq_hdr->profile) { + case GST_VC1_PROFILE_SIMPLE: + case GST_VC1_PROFILE_MAIN: + width = seq_hdr->struct_c.coded_width; + height = seq_hdr->struct_c.coded_height; + break; + case GST_VC1_PROFILE_ADVANCED: + width = seq_hdr->advanced.max_coded_width; + height = seq_hdr->advanced.max_coded_height; + break; + default: + g_assert(0 && "XXX: we already validated the profile above"); + break; + } + + if (priv->width != width) { + priv->width = width; + priv->size_changed = TRUE; + } + + if (priv->height != height) { + priv->height = height; + priv->size_changed = TRUE; + } + + switch (seq_hdr->profile) { + case GST_VC1_PROFILE_SIMPLE: + profile = GST_VAAPI_PROFILE_VC1_SIMPLE; + break; + case GST_VC1_PROFILE_MAIN: + profile = GST_VAAPI_PROFILE_VC1_MAIN; + break; + case GST_VC1_PROFILE_ADVANCED: + profile = GST_VAAPI_PROFILE_VC1_ADVANCED; + break; + default: + g_assert(0 && "XXX: we already validated the profile above"); + break; + } + if (priv->profile != profile) { + priv->profile = profile; + priv->profile_changed = TRUE; + } + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +static GstVaapiDecoderStatus +decode_sequence_end(GstVaapiDecoderVC1 *decoder) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVaapiDecoderStatus status; + + if (priv->current_picture) { + status = decode_current_picture(decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + status = render_picture(decoder, priv->current_picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + + if (priv->next_picture) { + status = render_picture(decoder, priv->next_picture); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + return GST_VAAPI_DECODER_STATUS_END_OF_STREAM; +} + +static GstVaapiDecoderStatus +decode_entry_point(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr; + GstVC1EntryPointHdr * const entrypoint_hdr = &priv->entrypoint_hdr; + GstVC1ParserResult result; + + result = gst_vc1_parse_entry_point_header( + rbdu->data + rbdu->offset, + rbdu->size, + entrypoint_hdr, + seq_hdr + ); + if (result != GST_VC1_PARSER_OK) { + GST_DEBUG("failed to parse entrypoint layer"); + return get_status(result); + } + + if (entrypoint_hdr->coded_size_flag) { + priv->width = entrypoint_hdr->coded_width; + priv->height = entrypoint_hdr->coded_height; + priv->size_changed = TRUE; + } + + priv->has_entrypoint = TRUE; + priv->closed_entry = entrypoint_hdr->closed_entry; + priv->broken_link = entrypoint_hdr->broken_link; + return GST_VAAPI_DECODER_STATUS_SUCCESS; +} + +/* Reconstruct bitstream PTYPE (7.1.1.4, index into Table-35) */ +static guint +get_PTYPE(guint ptype) +{ + switch (ptype) { + case GST_VC1_PICTURE_TYPE_I: return 0; + case GST_VC1_PICTURE_TYPE_P: return 1; + case GST_VC1_PICTURE_TYPE_B: return 2; + case GST_VC1_PICTURE_TYPE_BI: return 3; + } + return 4; /* skipped P-frame */ +} + +/* Reconstruct bitstream BFRACTION (7.1.1.14, index into Table-40) */ +static guint +get_BFRACTION(guint bfraction) +{ + guint i; + + static const struct { + guint16 index; + guint16 value; + } + bfraction_map[] = { + { 0, GST_VC1_BFRACTION_BASIS / 2 }, + { 1, GST_VC1_BFRACTION_BASIS / 3 }, + { 2, (GST_VC1_BFRACTION_BASIS * 2) / 3 }, + { 3, GST_VC1_BFRACTION_BASIS / 4 }, + { 4, (GST_VC1_BFRACTION_BASIS * 3) / 4 }, + { 5, GST_VC1_BFRACTION_BASIS / 5 }, + { 6, (GST_VC1_BFRACTION_BASIS * 2) / 5 }, + { 7, (GST_VC1_BFRACTION_BASIS * 3) / 5 }, + { 8, (GST_VC1_BFRACTION_BASIS * 4) / 5 }, + { 9, GST_VC1_BFRACTION_BASIS / 6 }, + { 10, (GST_VC1_BFRACTION_BASIS * 5) / 6 }, + { 11, GST_VC1_BFRACTION_BASIS / 7 }, + { 12, (GST_VC1_BFRACTION_BASIS * 2) / 7 }, + { 13, (GST_VC1_BFRACTION_BASIS * 3) / 7 }, + { 14, (GST_VC1_BFRACTION_BASIS * 4) / 7 }, + { 15, (GST_VC1_BFRACTION_BASIS * 5) / 7 }, + { 16, (GST_VC1_BFRACTION_BASIS * 6) / 7 }, + { 17, GST_VC1_BFRACTION_BASIS / 8 }, + { 18, (GST_VC1_BFRACTION_BASIS * 3) / 8 }, + { 19, (GST_VC1_BFRACTION_BASIS * 5) / 8 }, + { 20, (GST_VC1_BFRACTION_BASIS * 7) / 8 }, + { 21, GST_VC1_BFRACTION_RESERVED }, + { 22, GST_VC1_BFRACTION_PTYPE_BI } + }; + + if (!bfraction) + return 0; + + for (i = 0; i < G_N_ELEMENTS(bfraction_map); i++) { + if (bfraction_map[i].value == bfraction) + return bfraction_map[i].index; + } + return 21; /* RESERVED */ +} + +/* Translate GStreamer MV modes to VA-API */ +static guint +get_VAMvModeVC1(guint mvmode) +{ + switch (mvmode) { + case GST_VC1_MVMODE_1MV_HPEL_BILINEAR: return VAMvMode1MvHalfPelBilinear; + case GST_VC1_MVMODE_1MV: return VAMvMode1Mv; + case GST_VC1_MVMODE_1MV_HPEL: return VAMvMode1MvHalfPel; + case GST_VC1_MVMODE_MIXED_MV: return VAMvModeMixedMv; + case GST_VC1_MVMODE_INTENSITY_COMP: return VAMvModeIntensityCompensation; + } + return 0; +} + +/* Reconstruct bitstream MVMODE (7.1.1.32) */ +static guint +get_MVMODE(GstVC1FrameHdr *frame_hdr) +{ + guint mvmode; + + if (frame_hdr->profile == GST_VC1_PROFILE_ADVANCED) + mvmode = frame_hdr->pic.advanced.mvmode; + else + mvmode = frame_hdr->pic.simple.mvmode; + + if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P || + frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B) + return get_VAMvModeVC1(mvmode); + return 0; +} + +/* Reconstruct bitstream MVMODE2 (7.1.1.33) */ +static guint +get_MVMODE2(GstVC1FrameHdr *frame_hdr) +{ + guint mvmode, mvmode2; + + if (frame_hdr->profile == GST_VC1_PROFILE_ADVANCED) { + mvmode = frame_hdr->pic.advanced.mvmode; + mvmode2 = frame_hdr->pic.advanced.mvmode2; + } + else { + mvmode = frame_hdr->pic.simple.mvmode; + mvmode2 = frame_hdr->pic.simple.mvmode2; + } + + if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P && + mvmode == GST_VC1_MVMODE_INTENSITY_COMP) + return get_VAMvModeVC1(mvmode2); + return 0; +} + +static inline int +has_MVTYPEMB_bitplane(GstVaapiDecoderVC1 *decoder) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr; + GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr; + guint mvmode, mvmode2; + + if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) { + GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced; + if (pic->mvtypemb) + return 0; + mvmode = pic->mvmode; + mvmode2 = pic->mvmode2; + } + else { + GstVC1PicSimpleMain * const pic = &frame_hdr->pic.simple; + if (pic->mvtypemb) + return 0; + mvmode = pic->mvmode; + mvmode2 = pic->mvmode2; + } + return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P && + (mvmode == GST_VC1_MVMODE_MIXED_MV || + (mvmode == GST_VC1_MVMODE_INTENSITY_COMP && + mvmode2 == GST_VC1_MVMODE_MIXED_MV))); +} + +static inline int +has_SKIPMB_bitplane(GstVaapiDecoderVC1 *decoder) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr; + GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr; + + if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) { + GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced; + if (pic->skipmb) + return 0; + } + else { + GstVC1PicSimpleMain * const pic = &frame_hdr->pic.simple; + if (pic->skipmb) + return 0; + } + return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P || + frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B); +} + +static inline int +has_DIRECTMB_bitplane(GstVaapiDecoderVC1 *decoder) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr; + GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr; + + if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) { + GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced; + if (pic->directmb) + return 0; + } + else { + GstVC1PicSimpleMain * const pic = &frame_hdr->pic.simple; + if (pic->directmb) + return 0; + } + return frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B; +} + +static inline int +has_ACPRED_bitplane(GstVaapiDecoderVC1 *decoder) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr; + GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr; + GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced; + + if (seq_hdr->profile != GST_VC1_PROFILE_ADVANCED) + return 0; + if (pic->acpred) + return 0; + return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_I || + frame_hdr->ptype == GST_VC1_PICTURE_TYPE_BI); +} + +static inline int +has_OVERFLAGS_bitplane(GstVaapiDecoderVC1 *decoder) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr; + GstVC1EntryPointHdr * const entrypoint_hdr = &priv->entrypoint_hdr; + GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr; + GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced; + + if (seq_hdr->profile != GST_VC1_PROFILE_ADVANCED) + return 0; + if (pic->overflags) + return 0; + return ((frame_hdr->ptype == GST_VC1_PICTURE_TYPE_I || + frame_hdr->ptype == GST_VC1_PICTURE_TYPE_BI) && + (entrypoint_hdr->overlap && frame_hdr->pquant <= 8) && + pic->condover == GST_VC1_CONDOVER_SELECT); +} + +static inline void +pack_bitplanes(GstVaapiBitPlane *bitplane, guint n, const guint8 *bitplanes[3], guint x, guint y, guint stride) +{ + const guint dst_index = n / 2; + const guint src_index = y * stride + x; + guint8 v = 0; + + if (bitplanes[0]) + v |= bitplanes[0][src_index]; + if (bitplanes[1]) + v |= bitplanes[1][src_index] << 1; + if (bitplanes[2]) + v |= bitplanes[2][src_index] << 2; + bitplane->data[dst_index] = (bitplane->data[dst_index] << 4) | v; +} + +static gboolean +fill_picture_structc(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + VAPictureParameterBufferVC1 * const pic_param = picture->param; + GstVC1SeqStructC * const structc = &priv->seq_hdr.struct_c; + GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr; + GstVC1PicSimpleMain * const pic = &frame_hdr->pic.simple; + + /* Fill in VAPictureParameterBufferVC1 (simple/main profile bits) */ + pic_param->sequence_fields.bits.finterpflag = structc->finterpflag; + pic_param->sequence_fields.bits.multires = structc->multires; + pic_param->sequence_fields.bits.overlap = structc->overlap; + pic_param->sequence_fields.bits.syncmarker = structc->syncmarker; + pic_param->sequence_fields.bits.rangered = structc->rangered; + pic_param->sequence_fields.bits.max_b_frames = structc->maxbframes; + pic_param->conditional_overlap_flag = 0; /* advanced profile only */ + pic_param->fast_uvmc_flag = structc->fastuvmc; + pic_param->b_picture_fraction = get_BFRACTION(pic->bfraction); + pic_param->cbp_table = pic->cbptab; + pic_param->mb_mode_table = 0; /* XXX: interlaced frame */ + pic_param->range_reduction_frame = pic->rangeredfrm; + pic_param->rounding_control = 0; /* advanced profile only */ + pic_param->post_processing = 0; /* advanced profile only */ + pic_param->picture_resolution_index = pic->respic; + pic_param->luma_scale = pic->lumscale; + pic_param->luma_shift = pic->lumshift; + pic_param->raw_coding.flags.mv_type_mb = pic->mvtypemb; + pic_param->raw_coding.flags.direct_mb = pic->directmb; + pic_param->raw_coding.flags.skip_mb = pic->skipmb; + pic_param->bitplane_present.flags.bp_mv_type_mb = has_MVTYPEMB_bitplane(decoder); + pic_param->bitplane_present.flags.bp_direct_mb = has_DIRECTMB_bitplane(decoder); + pic_param->bitplane_present.flags.bp_skip_mb = has_SKIPMB_bitplane(decoder); + pic_param->mv_fields.bits.mv_table = pic->mvtab; + pic_param->mv_fields.bits.extended_mv_flag = structc->extended_mv; + pic_param->mv_fields.bits.extended_mv_range = pic->mvrange; + pic_param->transform_fields.bits.variable_sized_transform_flag = structc->vstransform; + pic_param->transform_fields.bits.mb_level_transform_type_flag = pic->ttmbf; + pic_param->transform_fields.bits.frame_level_transform_type = pic->ttfrm; + pic_param->transform_fields.bits.transform_ac_codingset_idx2 = pic->transacfrm2; + return TRUE; +} + +static gboolean +fill_picture_advanced(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + VAPictureParameterBufferVC1 * const pic_param = picture->param; + GstVC1AdvancedSeqHdr * const adv_hdr = &priv->seq_hdr.advanced; + GstVC1EntryPointHdr * const entrypoint_hdr = &priv->entrypoint_hdr; + GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr; + GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced; + + if (!priv->has_entrypoint) + return FALSE; + + /* Fill in VAPictureParameterBufferVC1 (advanced profile bits) */ + pic_param->sequence_fields.bits.pulldown = adv_hdr->pulldown; + pic_param->sequence_fields.bits.interlace = adv_hdr->interlace; + pic_param->sequence_fields.bits.tfcntrflag = adv_hdr->tfcntrflag; + pic_param->sequence_fields.bits.finterpflag = adv_hdr->finterpflag; + pic_param->sequence_fields.bits.psf = adv_hdr->psf; + pic_param->sequence_fields.bits.overlap = entrypoint_hdr->overlap; + pic_param->entrypoint_fields.bits.broken_link = entrypoint_hdr->broken_link; + pic_param->entrypoint_fields.bits.closed_entry = entrypoint_hdr->closed_entry; + pic_param->entrypoint_fields.bits.panscan_flag = entrypoint_hdr->panscan_flag; + pic_param->entrypoint_fields.bits.loopfilter = entrypoint_hdr->loopfilter; + pic_param->conditional_overlap_flag = pic->condover; + pic_param->fast_uvmc_flag = entrypoint_hdr->fastuvmc; + pic_param->range_mapping_fields.bits.luma_flag = entrypoint_hdr->range_mapy_flag; + pic_param->range_mapping_fields.bits.luma = entrypoint_hdr->range_mapy; + pic_param->range_mapping_fields.bits.chroma_flag = entrypoint_hdr->range_mapuv_flag; + pic_param->range_mapping_fields.bits.chroma = entrypoint_hdr->range_mapuv; + pic_param->b_picture_fraction = get_BFRACTION(pic->bfraction); + pic_param->cbp_table = pic->cbptab; + pic_param->mb_mode_table = 0; /* XXX: interlaced frame */ + pic_param->range_reduction_frame = 0; /* simple/main profile only */ + pic_param->rounding_control = pic->rndctrl; + pic_param->post_processing = pic->postproc; + pic_param->picture_resolution_index = 0; /* simple/main profile only */ + pic_param->luma_scale = pic->lumscale; + pic_param->luma_shift = pic->lumshift; + pic_param->picture_fields.bits.frame_coding_mode = pic->fcm; + pic_param->picture_fields.bits.top_field_first = pic->tff; + pic_param->picture_fields.bits.is_first_field = pic->fcm == 0; /* XXX: interlaced frame */ + pic_param->picture_fields.bits.intensity_compensation = pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP; + pic_param->raw_coding.flags.mv_type_mb = pic->mvtypemb; + pic_param->raw_coding.flags.direct_mb = pic->directmb; + pic_param->raw_coding.flags.skip_mb = pic->skipmb; + pic_param->raw_coding.flags.ac_pred = pic->acpred; + pic_param->raw_coding.flags.overflags = pic->overflags; + pic_param->bitplane_present.flags.bp_mv_type_mb = has_MVTYPEMB_bitplane(decoder); + pic_param->bitplane_present.flags.bp_direct_mb = has_DIRECTMB_bitplane(decoder); + pic_param->bitplane_present.flags.bp_skip_mb = has_SKIPMB_bitplane(decoder); + pic_param->bitplane_present.flags.bp_ac_pred = has_ACPRED_bitplane(decoder); + pic_param->bitplane_present.flags.bp_overflags = has_OVERFLAGS_bitplane(decoder); + pic_param->reference_fields.bits.reference_distance_flag = entrypoint_hdr->refdist_flag; + pic_param->mv_fields.bits.mv_table = pic->mvtab; + pic_param->mv_fields.bits.extended_mv_flag = entrypoint_hdr->extended_mv; + pic_param->mv_fields.bits.extended_mv_range = pic->mvrange; + pic_param->mv_fields.bits.extended_dmv_flag = entrypoint_hdr->extended_dmv; + pic_param->pic_quantizer_fields.bits.dquant = entrypoint_hdr->dquant; + pic_param->pic_quantizer_fields.bits.quantizer = entrypoint_hdr->quantizer; + pic_param->transform_fields.bits.variable_sized_transform_flag = entrypoint_hdr->vstransform; + pic_param->transform_fields.bits.mb_level_transform_type_flag = pic->ttmbf; + pic_param->transform_fields.bits.frame_level_transform_type = pic->ttfrm; + pic_param->transform_fields.bits.transform_ac_codingset_idx2 = pic->transacfrm2; + return TRUE; +} + +static gboolean +fill_picture(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + VAPictureParameterBufferVC1 * const pic_param = picture->param; + GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr; + GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr; + + /* Fill in VAPictureParameterBufferVC1 (common fields) */ + pic_param->forward_reference_picture = VA_INVALID_ID; + pic_param->backward_reference_picture = VA_INVALID_ID; + pic_param->inloop_decoded_picture = VA_INVALID_ID; + pic_param->sequence_fields.value = 0; +#if VA_CHECK_VERSION(0,32,0) + pic_param->sequence_fields.bits.profile = seq_hdr->profile; +#endif + pic_param->coded_width = priv->width; + pic_param->coded_height = priv->height; + pic_param->entrypoint_fields.value = 0; + pic_param->range_mapping_fields.value = 0; + pic_param->picture_fields.value = 0; + pic_param->picture_fields.bits.picture_type = get_PTYPE(frame_hdr->ptype); + pic_param->raw_coding.value = 0; + pic_param->bitplane_present.value = 0; + pic_param->reference_fields.value = 0; + pic_param->mv_fields.value = 0; + pic_param->mv_fields.bits.mv_mode = get_MVMODE(frame_hdr); + pic_param->mv_fields.bits.mv_mode2 = get_MVMODE2(frame_hdr); + pic_param->pic_quantizer_fields.value = 0; + pic_param->pic_quantizer_fields.bits.half_qp = frame_hdr->halfqp; + pic_param->pic_quantizer_fields.bits.pic_quantizer_scale = frame_hdr->pquant; + pic_param->pic_quantizer_fields.bits.pic_quantizer_type = frame_hdr->pquantizer; + pic_param->pic_quantizer_fields.bits.dq_frame = frame_hdr->vopdquant.dquantfrm; + pic_param->pic_quantizer_fields.bits.dq_profile = frame_hdr->vopdquant.dqprofile; + pic_param->pic_quantizer_fields.bits.dq_sb_edge = frame_hdr->vopdquant.dqsbedge; + pic_param->pic_quantizer_fields.bits.dq_db_edge = frame_hdr->vopdquant.dqsbedge; + pic_param->pic_quantizer_fields.bits.dq_binary_level = frame_hdr->vopdquant.dqbilevel; + pic_param->pic_quantizer_fields.bits.alt_pic_quantizer = frame_hdr->vopdquant.altpquant; + pic_param->transform_fields.value = 0; + pic_param->transform_fields.bits.transform_ac_codingset_idx1 = frame_hdr->transacfrm; + pic_param->transform_fields.bits.intra_transform_dc_table = frame_hdr->transdctab; + + if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) { + if (!fill_picture_advanced(decoder, picture)) + return FALSE; + } + else { + if (!fill_picture_structc(decoder, picture)) + return FALSE; + } + + switch (picture->type) { + case GST_VAAPI_PICTURE_TYPE_B: + if (priv->next_picture) + pic_param->backward_reference_picture = priv->next_picture->surface_id; + // fall-through + case GST_VAAPI_PICTURE_TYPE_P: + if (priv->prev_picture) + pic_param->forward_reference_picture = priv->prev_picture->surface_id; + break; + default: + break; + } + + if (pic_param->bitplane_present.value) { + const guint8 *bitplanes[3]; + guint x, y, n; + + switch (picture->type) { + case GST_VAAPI_PICTURE_TYPE_P: + bitplanes[0] = pic_param->bitplane_present.flags.bp_direct_mb ? priv->bitplanes->directmb : NULL; + bitplanes[1] = pic_param->bitplane_present.flags.bp_skip_mb ? priv->bitplanes->skipmb : NULL; + bitplanes[2] = pic_param->bitplane_present.flags.bp_mv_type_mb ? priv->bitplanes->mvtypemb : NULL; + break; + case GST_VAAPI_PICTURE_TYPE_B: + bitplanes[0] = pic_param->bitplane_present.flags.bp_direct_mb ? priv->bitplanes->directmb : NULL; + bitplanes[1] = pic_param->bitplane_present.flags.bp_skip_mb ? priv->bitplanes->skipmb : NULL; + bitplanes[2] = NULL; /* XXX: interlaced frame (FORWARD plane) */ + break; + case GST_VAAPI_PICTURE_TYPE_BI: + case GST_VAAPI_PICTURE_TYPE_I: + bitplanes[0] = NULL; /* XXX: interlaced frame (FIELDTX plane) */ + bitplanes[1] = pic_param->bitplane_present.flags.bp_ac_pred ? priv->bitplanes->acpred : NULL; + bitplanes[2] = pic_param->bitplane_present.flags.bp_overflags ? priv->bitplanes->overflags : NULL; + break; + default: + bitplanes[0] = NULL; + bitplanes[1] = NULL; + bitplanes[2] = NULL; + break; + } + + picture->bitplane = GST_VAAPI_BITPLANE_NEW( + decoder, + (seq_hdr->mb_width * seq_hdr->mb_height + 1) / 2 + ); + if (!picture->bitplane) + return FALSE; + + n = 0; + for (y = 0; y < seq_hdr->mb_height; y++) + for (x = 0; x < seq_hdr->mb_width; x++, n++) + pack_bitplanes(picture->bitplane, n, bitplanes, x, y, seq_hdr->mb_stride); + if (n & 1) /* move last nibble to the high order */ + picture->bitplane->data[n/2] <<= 4; + } + return TRUE; +} + +static GstVaapiDecoderStatus +decode_frame(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr; + GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr; + GstVC1ParserResult result; + GstVaapiPicture *picture; + GstVaapiSlice *slice; + GstVaapiDecoderStatus status; + VASliceParameterBufferVC1 *slice_param; + GstClockTime pts; + + status = ensure_context(decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) { + GST_DEBUG("failed to reset context"); + return status; + } + + if (priv->current_picture) { + status = decode_current_picture(decoder); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + + priv->current_picture = GST_VAAPI_PICTURE_NEW(VC1, decoder); + if (!priv->current_picture) { + GST_DEBUG("failed to allocate picture"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + picture = priv->current_picture; + + if (!gst_vc1_bitplanes_ensure_size(priv->bitplanes, seq_hdr)) { + GST_DEBUG("failed to allocate bitplanes"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + + memset(frame_hdr, 0, sizeof(*frame_hdr)); + result = gst_vc1_parse_frame_header( + rbdu->data + rbdu->offset, + rbdu->size, + frame_hdr, + seq_hdr, + priv->bitplanes + ); + if (result != GST_VC1_PARSER_OK) { + GST_DEBUG("failed to parse frame layer"); + return get_status(result); + } + + switch (frame_hdr->ptype) { + case GST_VC1_PICTURE_TYPE_I: + picture->type = GST_VAAPI_PICTURE_TYPE_I; + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + break; + case GST_VC1_PICTURE_TYPE_SKIPPED: + case GST_VC1_PICTURE_TYPE_P: + picture->type = GST_VAAPI_PICTURE_TYPE_P; + GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE); + break; + case GST_VC1_PICTURE_TYPE_B: + picture->type = GST_VAAPI_PICTURE_TYPE_B; + break; + case GST_VC1_PICTURE_TYPE_BI: + picture->type = GST_VAAPI_PICTURE_TYPE_BI; + break; + default: + GST_DEBUG("unsupported picture type %d", frame_hdr->ptype); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + /* Update presentation time */ + pts = gst_adapter_prev_timestamp(priv->adapter, NULL); + picture->pts = pts; + + /* Update reference pictures */ + if (GST_VAAPI_PICTURE_IS_REFERENCE(picture)) { + if (priv->next_picture) + status = render_picture(decoder, priv->next_picture); + gst_vaapi_picture_replace(&priv->prev_picture, priv->next_picture); + gst_vaapi_picture_replace(&priv->next_picture, picture); + } + + if (!fill_picture(decoder, picture)) + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + + slice = GST_VAAPI_SLICE_NEW( + VC1, + decoder, + ebdu->data + ebdu->sc_offset, + ebdu->size + ebdu->offset - ebdu->sc_offset + ); + if (!slice) { + GST_DEBUG("failed to allocate slice"); + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + } + gst_vaapi_picture_add_slice(picture, slice); + + /* Fill in VASliceParameterBufferVC1 */ + slice_param = slice->param; + slice_param->macroblock_offset = 8 * (ebdu->offset - ebdu->sc_offset) + frame_hdr->header_size; + slice_param->slice_vertical_position = 0; + + /* Decode picture right away, we got the full frame */ + return decode_current_picture(decoder); +} + +static gboolean +decode_rbdu(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + guint8 *rbdu_buffer; + guint i, j, rbdu_buffer_size; + + /* BDU are encapsulated in advanced profile mode only */ + if (priv->profile != GST_VAAPI_PROFILE_VC1_ADVANCED) { + memcpy(rbdu, ebdu, sizeof(*rbdu)); + return TRUE; + } + + /* Reallocate unescaped bitstream buffer */ + rbdu_buffer = priv->rbdu_buffer; + if (!rbdu_buffer || ebdu->size > priv->rbdu_buffer_size) { + rbdu_buffer = g_realloc(priv->rbdu_buffer, ebdu->size); + if (!rbdu_buffer) + return FALSE; + priv->rbdu_buffer = rbdu_buffer; + priv->rbdu_buffer_size = ebdu->size; + } + + /* Unescape bitstream buffer */ + if (ebdu->size < 4) { + memcpy(rbdu_buffer, ebdu->data + ebdu->offset, ebdu->size); + rbdu_buffer_size = ebdu->size; + } + else { + guint8 * const bdu_buffer = ebdu->data + ebdu->offset; + for (i = 0, j = 0; i < ebdu->size; i++) { + if (i >= 2 && i < ebdu->size - 1 && + bdu_buffer[i - 1] == 0x00 && + bdu_buffer[i - 2] == 0x00 && + bdu_buffer[i ] == 0x03 && + bdu_buffer[i + 1] <= 0x03) + i++; + rbdu_buffer[j++] = bdu_buffer[i]; + } + rbdu_buffer_size = j; + } + + /* Reconstruct RBDU */ + rbdu->type = ebdu->type; + rbdu->size = rbdu_buffer_size; + rbdu->sc_offset = 0; + rbdu->offset = 0; + rbdu->data = rbdu_buffer; + return TRUE; +} + +static GstVaapiDecoderStatus +decode_ebdu(GstVaapiDecoderVC1 *decoder, GstVC1BDU *ebdu) +{ + GstVaapiDecoderStatus status; + GstVC1BDU rbdu; + + if (!decode_rbdu(decoder, &rbdu, ebdu)) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + + switch (ebdu->type) { + case GST_VC1_SEQUENCE: + status = decode_sequence(decoder, &rbdu, ebdu); + break; + case GST_VC1_ENTRYPOINT: + status = decode_entry_point(decoder, &rbdu, ebdu); + break; + case GST_VC1_FRAME: + status = decode_frame(decoder, &rbdu, ebdu); + break; + case GST_VC1_SLICE: + GST_DEBUG("decode slice"); + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + case GST_VC1_END_OF_SEQ: + status = decode_sequence_end(decoder); + break; + default: + GST_DEBUG("unsupported BDU type %d", ebdu->type); + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + } + return status; +} + +static GstVaapiDecoderStatus +decode_buffer(GstVaapiDecoderVC1 *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVaapiDecoderStatus status; + GstVC1ParserResult result; + GstVC1BDU ebdu; + GstBuffer *codec_data; + guchar *buf; + guint buf_size, ofs; + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + if (!buf && buf_size == 0) + return decode_sequence_end(decoder); + + gst_buffer_ref(buffer); + gst_adapter_push(priv->adapter, buffer); + + /* Assume demuxer sends out plain frames if codec-data */ + codec_data = GST_VAAPI_DECODER_CODEC_DATA(decoder); + if (codec_data && codec_data != buffer) { + ebdu.type = GST_VC1_FRAME; + ebdu.size = buf_size; + ebdu.sc_offset = 0; + ebdu.offset = 0; + ebdu.data = buf; + status = decode_ebdu(decoder, &ebdu); + + if (gst_adapter_available(priv->adapter) >= buf_size) + gst_adapter_flush(priv->adapter, buf_size); + return status; + } + + if (priv->sub_buffer) { + buffer = gst_buffer_merge(priv->sub_buffer, buffer); + if (!buffer) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + gst_buffer_unref(priv->sub_buffer); + priv->sub_buffer = NULL; + } + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + ofs = 0; + do { + result = gst_vc1_identify_next_bdu( + buf + ofs, + buf_size - ofs, + &ebdu + ); + status = get_status(result); + + if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA) { + priv->sub_buffer = gst_buffer_create_sub(buffer, ofs, buf_size - ofs); + break; + } + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + break; + + ofs += ebdu.offset + ebdu.size; + if (gst_adapter_available(priv->adapter) >= ebdu.offset) + gst_adapter_flush(priv->adapter, ebdu.offset); + + status = decode_ebdu(decoder, &ebdu); + if (gst_adapter_available(priv->adapter) >= ebdu.size) + gst_adapter_flush(priv->adapter, ebdu.size); + } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS); + return status; +} + +static GstVaapiDecoderStatus +decode_codec_data(GstVaapiDecoderVC1 *decoder, GstBuffer *buffer) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr; + GstVaapiDecoderStatus status; + GstVC1ParserResult result; + GstVC1BDU ebdu; + GstCaps *caps; + GstStructure *structure; + guchar *buf; + guint buf_size, ofs; + gint width, height; + guint32 format; + + buf = GST_BUFFER_DATA(buffer); + buf_size = GST_BUFFER_SIZE(buffer); + if (!buf || buf_size == 0) + return GST_VAAPI_DECODER_STATUS_SUCCESS; + + caps = GST_VAAPI_DECODER_CAST(decoder)->priv->caps; + structure = gst_caps_get_structure(caps, 0); + + if (!gst_structure_get_int(structure, "width", &width) || + !gst_structure_get_int(structure, "height", &height)) { + GST_DEBUG("failed to parse size from codec-data"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; + } + + if (!gst_structure_get_fourcc(structure, "format", &format)) { + GST_DEBUG("failed to parse profile from codec-data"); + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + } + + /* WMV3 -- expecting sequence header */ + if (format == GST_MAKE_FOURCC('W','M','V','3')) { + seq_hdr->struct_c.coded_width = width; + seq_hdr->struct_c.coded_height = height; + ebdu.type = GST_VC1_SEQUENCE; + ebdu.size = buf_size; + ebdu.sc_offset = 0; + ebdu.offset = 0; + ebdu.data = buf; + return decode_ebdu(decoder, &ebdu); + } + + /* WVC1 -- expecting bitstream data units */ + if (format != GST_MAKE_FOURCC('W','V','C','1')) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE; + seq_hdr->advanced.max_coded_width = width; + seq_hdr->advanced.max_coded_height = height; + + ofs = 0; + do { + result = gst_vc1_identify_next_bdu( + buf + ofs, + buf_size - ofs, + &ebdu + ); + + switch (result) { + case GST_VC1_PARSER_NO_BDU_END: + /* Assume the EBDU is complete within codec-data bounds */ + ebdu.size = buf_size - ofs - (ebdu.offset - ebdu.sc_offset); + // fall-through + case GST_VC1_PARSER_OK: + status = decode_ebdu(decoder, &ebdu); + ofs += ebdu.offset + ebdu.size; + break; + default: + status = get_status(result); + break; + } + } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS && ofs < buf_size); + return status; +} + +GstVaapiDecoderStatus +gst_vaapi_decoder_vc1_decode(GstVaapiDecoder *base, GstBuffer *buffer) +{ + GstVaapiDecoderVC1 * const decoder = GST_VAAPI_DECODER_VC1(base); + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GstVaapiDecoderStatus status; + GstBuffer *codec_data; + + g_return_val_if_fail(priv->is_constructed, + GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED); + + if (!priv->is_opened) { + priv->is_opened = gst_vaapi_decoder_vc1_open(decoder, buffer); + if (!priv->is_opened) + return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC; + + codec_data = GST_VAAPI_DECODER_CODEC_DATA(decoder); + if (codec_data) { + status = decode_codec_data(decoder, codec_data); + if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) + return status; + } + } + return decode_buffer(decoder, buffer); +} + +static void +gst_vaapi_decoder_vc1_finalize(GObject *object) +{ + GstVaapiDecoderVC1 * const decoder = GST_VAAPI_DECODER_VC1(object); + + gst_vaapi_decoder_vc1_destroy(decoder); + + G_OBJECT_CLASS(gst_vaapi_decoder_vc1_parent_class)->finalize(object); +} + +static void +gst_vaapi_decoder_vc1_constructed(GObject *object) +{ + GstVaapiDecoderVC1 * const decoder = GST_VAAPI_DECODER_VC1(object); + GstVaapiDecoderVC1Private * const priv = decoder->priv; + GObjectClass *parent_class; + + parent_class = G_OBJECT_CLASS(gst_vaapi_decoder_vc1_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); + + priv->is_constructed = gst_vaapi_decoder_vc1_create(decoder); +} + +static void +gst_vaapi_decoder_vc1_class_init(GstVaapiDecoderVC1Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiDecoderVC1Private)); + + object_class->finalize = gst_vaapi_decoder_vc1_finalize; + object_class->constructed = gst_vaapi_decoder_vc1_constructed; + + decoder_class->decode = gst_vaapi_decoder_vc1_decode; +} + +static void +gst_vaapi_decoder_vc1_init(GstVaapiDecoderVC1 *decoder) +{ + GstVaapiDecoderVC1Private *priv; + + priv = GST_VAAPI_DECODER_VC1_GET_PRIVATE(decoder); + decoder->priv = priv; + priv->width = 0; + priv->height = 0; + priv->fps_n = 0; + priv->fps_d = 0; + priv->profile = (GstVaapiProfile)0; + priv->current_picture = NULL; + priv->next_picture = NULL; + priv->prev_picture = NULL; + priv->adapter = NULL; + priv->sub_buffer = NULL; + priv->rbdu_buffer = NULL; + priv->rbdu_buffer_size = 0; + priv->is_constructed = FALSE; + priv->is_opened = FALSE; + priv->is_first_field = FALSE; + priv->has_entrypoint = FALSE; + priv->size_changed = FALSE; + priv->profile_changed = FALSE; + priv->closed_entry = FALSE; + priv->broken_link = FALSE; +} + +/** + * gst_vaapi_decoder_vc1_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps holding codec information + * + * Creates a new #GstVaapiDecoder for VC-1 decoding. The @caps can + * hold extra information like codec-data and pictured coded size. + * + * Return value: the newly allocated #GstVaapiDecoder object + */ +GstVaapiDecoder * +gst_vaapi_decoder_vc1_new(GstVaapiDisplay *display, GstCaps *caps) +{ + GstVaapiDecoderVC1 *decoder; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(GST_IS_CAPS(caps), NULL); + + decoder = g_object_new( + GST_VAAPI_TYPE_DECODER_VC1, + "display", display, + "caps", caps, + NULL + ); + if (!decoder->priv->is_constructed) { + g_object_unref(decoder); + return NULL; + } + return GST_VAAPI_DECODER_CAST(decoder); +} diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vc1.h b/gst-libs/gst/vaapi/gstvaapidecoder_vc1.h new file mode 100644 index 0000000..1bed606 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidecoder_vc1.h @@ -0,0 +1,88 @@ +/* + * gstvaapidecoder_vc1.h - VC-1 decoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DECODER_VC1_H +#define GST_VAAPI_DECODER_VC1_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DECODER_VC1 \ + (gst_vaapi_decoder_vc1_get_type()) + +#define GST_VAAPI_DECODER_VC1(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DECODER_VC1, \ + GstVaapiDecoderVC1)) + +#define GST_VAAPI_DECODER_VC1_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DECODER_VC1, \ + GstVaapiDecoderVC1Class)) + +#define GST_VAAPI_IS_DECODER_VC1(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DECODER_VC1)) + +#define GST_VAAPI_IS_DECODER_VC1_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DECODER_VC1)) + +#define GST_VAAPI_DECODER_VC1_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DECODER_VC1, \ + GstVaapiDecoderVC1Class)) + +typedef struct _GstVaapiDecoderVC1 GstVaapiDecoderVC1; +typedef struct _GstVaapiDecoderVC1Private GstVaapiDecoderVC1Private; +typedef struct _GstVaapiDecoderVC1Class GstVaapiDecoderVC1Class; + +/** + * GstVaapiDecoderVC1: + * + * A decoder based on VC1. + */ +struct _GstVaapiDecoderVC1 { + /*< private >*/ + GstVaapiDecoder parent_instance; + + GstVaapiDecoderVC1Private *priv; +}; + +/** + * GstVaapiDecoderVC1Class: + * + * A decoder class based on VC1. + */ +struct _GstVaapiDecoderVC1Class { + /*< private >*/ + GstVaapiDecoderClass parent_class; +}; + +GType +gst_vaapi_decoder_vc1_get_type(void) G_GNUC_CONST; + +GstVaapiDecoder * +gst_vaapi_decoder_vc1_new(GstVaapiDisplay *display, GstCaps *caps); + +G_END_DECLS + +#endif /* GST_VAAPI_DECODER_VC1_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay.c b/gst-libs/gst/vaapi/gstvaapidisplay.c new file mode 100644 index 0000000..8876643 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay.c @@ -0,0 +1,1719 @@ +/* + * gstvaapidisplay.c - VA display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidisplay + * @short_description: VA display abstraction + */ + +#include "sysdeps.h" +#include +#include "gstvaapiutils.h" +#include "gstvaapivalue.h" +#include "gstvaapidisplay.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapiworkarounds.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +GST_DEBUG_CATEGORY(gst_debug_vaapi); + +G_DEFINE_TYPE(GstVaapiDisplay, gst_vaapi_display, G_TYPE_OBJECT); + +typedef struct _GstVaapiConfig GstVaapiConfig; +struct _GstVaapiConfig { + GstVaapiProfile profile; + GstVaapiEntrypoint entrypoint; +}; + +typedef struct _GstVaapiProperty GstVaapiProperty; +struct _GstVaapiProperty { + const gchar *name; + VADisplayAttribute attribute; + gint old_value; +}; + +#define DEFAULT_RENDER_MODE GST_VAAPI_RENDER_MODE_TEXTURE +#define DEFAULT_ROTATION GST_VAAPI_ROTATION_0 + +enum { + PROP_0, + + PROP_DISPLAY, + PROP_DISPLAY_TYPE, + PROP_WIDTH, + PROP_HEIGHT, + PROP_RENDER_MODE, + PROP_ROTATION, + PROP_HUE, + PROP_SATURATION, + PROP_BRIGHTNESS, + PROP_CONTRAST, + + N_PROPERTIES +}; + +static GstVaapiDisplayCache *g_display_cache = NULL; + +static GParamSpec *g_properties[N_PROPERTIES] = { NULL, }; + +static gboolean +get_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint *value); + +static gboolean +set_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint value); + +static gboolean +get_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat *v); + +static gboolean +set_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat v); + +static inline GstVaapiDisplayCache * +get_display_cache(void) +{ + if (!g_display_cache) + g_display_cache = gst_vaapi_display_cache_new(); + return g_display_cache; +} + +GstVaapiDisplayCache * +gst_vaapi_display_get_cache(void) +{ + return get_display_cache(); +} + +static void +free_display_cache(void) +{ + if (!g_display_cache) + return; + if (gst_vaapi_display_cache_get_size(g_display_cache) > 0) + return; + gst_vaapi_display_cache_free(g_display_cache); + g_display_cache = NULL; +} + +/* GstVaapiDisplayType enumerations */ +GType +gst_vaapi_display_type_get_type(void) +{ + static GType g_type = 0; + + static const GEnumValue display_types[] = { + { GST_VAAPI_DISPLAY_TYPE_ANY, + "Auto detection", "any" }, +#if USE_X11 + { GST_VAAPI_DISPLAY_TYPE_X11, + "VA/X11 display", "x11" }, +#endif +#if USE_GLX + { GST_VAAPI_DISPLAY_TYPE_GLX, + "VA/GLX display", "glx" }, +#endif +#if USE_WAYLAND + { GST_VAAPI_DISPLAY_TYPE_WAYLAND, + "VA/Wayland display", "wayland" }, +#endif +#if USE_DRM + { GST_VAAPI_DISPLAY_TYPE_DRM, + "VA/DRM display", "drm" }, +#endif + { 0, NULL, NULL }, + }; + + if (!g_type) + g_type = g_enum_register_static("GstVaapiDisplayType", display_types); + return g_type; +} + +/* Append GstVaapiImageFormat to formats array */ +static inline void +append_format(GArray *formats, GstVaapiImageFormat format) +{ + g_array_append_val(formats, format); +} + +/* Append VAImageFormats to formats array */ +static void +append_formats(GArray *formats, const VAImageFormat *va_formats, guint n) +{ + GstVaapiImageFormat format; + gboolean has_YV12 = FALSE; + gboolean has_I420 = FALSE; + guint i; + + for (i = 0; i < n; i++) { + const VAImageFormat * const va_format = &va_formats[i]; + + format = gst_vaapi_image_format(va_format); + if (!format) { + GST_DEBUG("unsupported format %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS(va_format->fourcc)); + continue; + } + + switch (format) { + case GST_VAAPI_IMAGE_YV12: + has_YV12 = TRUE; + break; + case GST_VAAPI_IMAGE_I420: + has_I420 = TRUE; + break; + default: + break; + } + append_format(formats, format); + } + + /* Append I420 (resp. YV12) format if YV12 (resp. I420) is not + supported by the underlying driver */ + if (has_YV12 && !has_I420) + append_format(formats, GST_VAAPI_IMAGE_I420); + else if (has_I420 && !has_YV12) + append_format(formats, GST_VAAPI_IMAGE_YV12); +} + +/* Sort image formats. Prefer YUV formats first */ +static gint +compare_yuv_formats(gconstpointer a, gconstpointer b) +{ + const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a; + const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b; + + const gboolean is_fmt1_yuv = gst_vaapi_image_format_is_yuv(fmt1); + const gboolean is_fmt2_yuv = gst_vaapi_image_format_is_yuv(fmt2); + + if (is_fmt1_yuv != is_fmt2_yuv) + return is_fmt1_yuv ? -1 : 1; + + return ((gint)gst_vaapi_image_format_get_score(fmt1) - + (gint)gst_vaapi_image_format_get_score(fmt2)); +} + +/* Sort subpicture formats. Prefer RGB formats first */ +static gint +compare_rgb_formats(gconstpointer a, gconstpointer b) +{ + const GstVaapiImageFormat fmt1 = *(GstVaapiImageFormat *)a; + const GstVaapiImageFormat fmt2 = *(GstVaapiImageFormat *)b; + + const gboolean is_fmt1_rgb = gst_vaapi_image_format_is_rgb(fmt1); + const gboolean is_fmt2_rgb = gst_vaapi_image_format_is_rgb(fmt2); + + if (is_fmt1_rgb != is_fmt2_rgb) + return is_fmt1_rgb ? -1 : 1; + + return ((gint)gst_vaapi_image_format_get_score(fmt1) - + (gint)gst_vaapi_image_format_get_score(fmt2)); +} + +/* Check if configs array contains profile at entrypoint */ +static inline gboolean +find_config( + GArray *configs, + GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint +) +{ + GstVaapiConfig *config; + guint i; + + if (!configs) + return FALSE; + + for (i = 0; i < configs->len; i++) { + config = &g_array_index(configs, GstVaapiConfig, i); + if (config->profile == profile && config->entrypoint == entrypoint) + return TRUE; + } + return FALSE; +} + +/* HACK: append H.263 Baseline profile if MPEG-4:2 Simple profile is supported */ +static void +append_h263_config(GArray *configs) +{ + GstVaapiConfig *config, tmp_config; + GstVaapiConfig *mpeg4_simple_config = NULL; + GstVaapiConfig *h263_baseline_config = NULL; + guint i; + + if (!WORKAROUND_H263_BASELINE_DECODE_PROFILE) + return; + + if (!configs) + return; + + for (i = 0; i < configs->len; i++) { + config = &g_array_index(configs, GstVaapiConfig, i); + if (config->profile == GST_VAAPI_PROFILE_MPEG4_SIMPLE) + mpeg4_simple_config = config; + else if (config->profile == GST_VAAPI_PROFILE_H263_BASELINE) + h263_baseline_config = config; + } + + if (mpeg4_simple_config && !h263_baseline_config) { + tmp_config = *mpeg4_simple_config; + tmp_config.profile = GST_VAAPI_PROFILE_H263_BASELINE; + g_array_append_val(configs, tmp_config); + } +} + +/* Convert configs array to profiles as GstCaps */ +static GstCaps * +get_profile_caps(GArray *configs) +{ + GstVaapiConfig *config; + GstCaps *out_caps, *caps; + guint i; + + if (!configs) + return NULL; + + out_caps = gst_caps_new_empty(); + if (!out_caps) + return NULL; + + for (i = 0; i < configs->len; i++) { + config = &g_array_index(configs, GstVaapiConfig, i); + caps = gst_vaapi_profile_get_caps(config->profile); + if (caps) + gst_caps_merge(out_caps, caps); + } + return out_caps; +} + +/* Check if formats array contains format */ +static inline gboolean +find_format(GArray *formats, GstVaapiImageFormat format) +{ + guint i; + + for (i = 0; i < formats->len; i++) + if (g_array_index(formats, GstVaapiImageFormat, i) == format) + return TRUE; + return FALSE; +} + +/* Convert formats array to GstCaps */ +static GstCaps * +get_format_caps(GArray *formats) +{ + GstVaapiImageFormat format; + GstCaps *out_caps, *caps; + guint i; + + out_caps = gst_caps_new_empty(); + if (!out_caps) + return NULL; + + for (i = 0; i < formats->len; i++) { + format = g_array_index(formats, GstVaapiImageFormat, i); + caps = gst_vaapi_image_format_get_caps(format); + if (caps) + gst_caps_append(out_caps, caps); + } + return out_caps; +} + +/* Find display attribute */ +static const GstVaapiProperty * +find_property(GArray *properties, const gchar *name) +{ + GstVaapiProperty *prop; + guint i; + + if (!name) + return NULL; + + for (i = 0; i < properties->len; i++) { + prop = &g_array_index(properties, GstVaapiProperty, i); + if (strcmp(prop->name, name) == 0) + return prop; + } + return NULL; +} + +#if 0 +static const GstVaapiProperty * +find_property_by_type(GArray *properties, VADisplayAttribType type) +{ + GstVaapiProperty *prop; + guint i; + + for (i = 0; i < properties->len; i++) { + prop = &g_array_index(properties, GstVaapiProperty, i); + if (prop->attribute.type == type) + return prop; + } + return NULL; +} +#endif + +static inline const GstVaapiProperty * +find_property_by_pspec(GstVaapiDisplay *display, GParamSpec *pspec) +{ + return find_property(display->priv->properties, pspec->name); +} + +static void +gst_vaapi_display_calculate_pixel_aspect_ratio(GstVaapiDisplay *display) +{ + GstVaapiDisplayPrivate * const priv = display->priv; + gdouble ratio, delta; + gint i, j, index, windex; + + static const gint par[][2] = { + {1, 1}, /* regular screen */ + {16, 15}, /* PAL TV */ + {11, 10}, /* 525 line Rec.601 video */ + {54, 59}, /* 625 line Rec.601 video */ + {64, 45}, /* 1280x1024 on 16:9 display */ + {5, 3}, /* 1280x1024 on 4:3 display */ + {4, 3} /* 800x600 on 16:9 display */ + }; + + /* First, calculate the "real" ratio based on the X values; + * which is the "physical" w/h divided by the w/h in pixels of the + * display */ + if (!priv->width || !priv->height || !priv->width_mm || !priv->height_mm) + ratio = 1.0; + else + ratio = (gdouble)(priv->width_mm * priv->height) / + (priv->height_mm * priv->width); + GST_DEBUG("calculated pixel aspect ratio: %f", ratio); + + /* Now, find the one from par[][2] with the lowest delta to the real one */ +#define DELTA(idx, w) (ABS(ratio - ((gdouble)par[idx][w] / par[idx][!(w)]))) + delta = DELTA(0, 0); + index = 0; + windex = 0; + + for (i = 1; i < G_N_ELEMENTS(par); i++) { + for (j = 0; j < 2; j++) { + const gdouble this_delta = DELTA(i, j); + if (this_delta < delta) { + index = i; + windex = j; + delta = this_delta; + } + } + } +#undef DELTA + + priv->par_n = par[index][windex]; + priv->par_d = par[index][windex ^ 1]; +} + +static void +gst_vaapi_display_destroy(GstVaapiDisplay *display) +{ + GstVaapiDisplayPrivate * const priv = display->priv; + + if (priv->decoders) { + g_array_free(priv->decoders, TRUE); + priv->decoders = NULL; + } + + if (priv->encoders) { + g_array_free(priv->encoders, TRUE); + priv->encoders = NULL; + } + + if (priv->image_formats) { + g_array_free(priv->image_formats, TRUE); + priv->image_formats = NULL; + } + + if (priv->subpicture_formats) { + g_array_free(priv->subpicture_formats, TRUE); + priv->subpicture_formats = NULL; + } + + if (priv->properties) { + g_array_free(priv->properties, TRUE); + priv->properties = NULL; + } + + if (priv->display) { + if (!priv->parent) + vaTerminate(priv->display); + priv->display = NULL; + } + + if (priv->create_display) { + GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display); + if (klass->close_display) + klass->close_display(display); + } + + g_clear_object(&priv->parent); + + if (g_display_cache) { + gst_vaapi_display_cache_remove(get_display_cache(), display); + free_display_cache(); + } +} + +static gboolean +gst_vaapi_display_create(GstVaapiDisplay *display) +{ + GstVaapiDisplayPrivate * const priv = display->priv; + GstVaapiDisplayCache *cache; + gboolean has_errors = TRUE; + VADisplayAttribute *display_attrs = NULL; + VAProfile *profiles = NULL; + VAEntrypoint *entrypoints = NULL; + VAImageFormat *formats = NULL; + unsigned int *flags = NULL; + gint i, j, n, num_entrypoints, major_version, minor_version; + VAStatus status; + GstVaapiDisplayInfo info; + const GstVaapiDisplayInfo *cached_info = NULL; + + memset(&info, 0, sizeof(info)); + info.display = display; + info.display_type = priv->display_type; + + if (priv->display) + info.va_display = priv->display; + else if (priv->create_display) { + GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display); + if (klass->open_display && !klass->open_display(display)) + return FALSE; + if (!klass->get_display || !klass->get_display(display, &info)) + return FALSE; + priv->display = info.va_display; + priv->display_type = info.display_type; + if (klass->get_size) + klass->get_size(display, &priv->width, &priv->height); + if (klass->get_size_mm) + klass->get_size_mm(display, &priv->width_mm, &priv->height_mm); + gst_vaapi_display_calculate_pixel_aspect_ratio(display); + } + if (!priv->display) + return FALSE; + + cache = get_display_cache(); + if (!cache) + return FALSE; + cached_info = gst_vaapi_display_cache_lookup_by_va_display( + cache, + info.va_display + ); + if (cached_info) { + g_clear_object(&priv->parent); + priv->parent = g_object_ref(cached_info->display); + priv->display_type = cached_info->display_type; + } + + if (!priv->parent) { + status = vaInitialize(priv->display, &major_version, &minor_version); + if (!vaapi_check_status(status, "vaInitialize()")) + goto end; + GST_DEBUG("VA-API version %d.%d", major_version, minor_version); + } + + /* VA profiles */ + profiles = g_new(VAProfile, vaMaxNumProfiles(priv->display)); + if (!profiles) + goto end; + entrypoints = g_new(VAEntrypoint, vaMaxNumEntrypoints(priv->display)); + if (!entrypoints) + goto end; + status = vaQueryConfigProfiles(priv->display, profiles, &n); + if (!vaapi_check_status(status, "vaQueryConfigProfiles()")) + goto end; + + GST_DEBUG("%d profiles", n); + for (i = 0; i < n; i++) { +#if VA_CHECK_VERSION(0,34,0) + /* Introduced in VA/VPP API */ + if (profiles[i] == VAProfileNone) + continue; +#endif + GST_DEBUG(" %s", string_of_VAProfile(profiles[i])); + } + + priv->decoders = g_array_new(FALSE, FALSE, sizeof(GstVaapiConfig)); + if (!priv->decoders) + goto end; + priv->encoders = g_array_new(FALSE, FALSE, sizeof(GstVaapiConfig)); + if (!priv->encoders) + goto end; + + for (i = 0; i < n; i++) { + GstVaapiConfig config; + + config.profile = gst_vaapi_profile(profiles[i]); + if (!config.profile) + continue; + + status = vaQueryConfigEntrypoints( + priv->display, + profiles[i], + entrypoints, &num_entrypoints + ); + if (!vaapi_check_status(status, "vaQueryConfigEntrypoints()")) + continue; + + for (j = 0; j < num_entrypoints; j++) { + config.entrypoint = gst_vaapi_entrypoint(entrypoints[j]); + switch (config.entrypoint) { + case GST_VAAPI_ENTRYPOINT_VLD: + case GST_VAAPI_ENTRYPOINT_IDCT: + case GST_VAAPI_ENTRYPOINT_MOCO: + g_array_append_val(priv->decoders, config); + break; + case GST_VAAPI_ENTRYPOINT_SLICE_ENCODE: + g_array_append_val(priv->encoders, config); + break; + } + } + } + append_h263_config(priv->decoders); + + /* VA display attributes */ + display_attrs = + g_new(VADisplayAttribute, vaMaxNumDisplayAttributes(priv->display)); + if (!display_attrs) + goto end; + + n = 0; /* XXX: workaround old GMA500 bug */ + status = vaQueryDisplayAttributes(priv->display, display_attrs, &n); + if (!vaapi_check_status(status, "vaQueryDisplayAttributes()")) + goto end; + + priv->properties = g_array_new(FALSE, FALSE, sizeof(GstVaapiProperty)); + if (!priv->properties) + goto end; + + GST_DEBUG("%d display attributes", n); + for (i = 0; i < n; i++) { + VADisplayAttribute * const attr = &display_attrs[i]; + GstVaapiProperty prop; + gint value; + + GST_DEBUG(" %s", string_of_VADisplayAttributeType(attr->type)); + + switch (attr->type) { +#if !VA_CHECK_VERSION(0,34,0) + case VADisplayAttribDirectSurface: + prop.name = GST_VAAPI_DISPLAY_PROP_RENDER_MODE; + break; +#endif + case VADisplayAttribRenderMode: + prop.name = GST_VAAPI_DISPLAY_PROP_RENDER_MODE; + break; + case VADisplayAttribRotation: + prop.name = GST_VAAPI_DISPLAY_PROP_ROTATION; + break; + case VADisplayAttribHue: + prop.name = GST_VAAPI_DISPLAY_PROP_HUE; + break; + case VADisplayAttribSaturation: + prop.name = GST_VAAPI_DISPLAY_PROP_SATURATION; + break; + case VADisplayAttribBrightness: + prop.name = GST_VAAPI_DISPLAY_PROP_BRIGHTNESS; + break; + case VADisplayAttribContrast: + prop.name = GST_VAAPI_DISPLAY_PROP_CONTRAST; + break; + default: + prop.name = NULL; + break; + } + if (!prop.name) + continue; + + /* Assume the attribute is really supported if we can get the + * actual and current value */ + if (!get_attribute(display, attr->type, &value)) + continue; + + /* Some drivers (e.g. EMGD) have completely random initial + * values */ + if (value < attr->min_value || value > attr->max_value) + continue; + + prop.attribute = *attr; + prop.old_value = value; + g_array_append_val(priv->properties, prop); + } + + /* VA image formats */ + formats = g_new(VAImageFormat, vaMaxNumImageFormats(priv->display)); + if (!formats) + goto end; + status = vaQueryImageFormats(priv->display, formats, &n); + if (!vaapi_check_status(status, "vaQueryImageFormats()")) + goto end; + + GST_DEBUG("%d image formats", n); + for (i = 0; i < n; i++) + GST_DEBUG(" %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(formats[i].fourcc)); + + priv->image_formats = + g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat)); + if (!priv->image_formats) + goto end; + append_formats(priv->image_formats, formats, n); + g_array_sort(priv->image_formats, compare_yuv_formats); + + /* VA subpicture formats */ + n = vaMaxNumSubpictureFormats(priv->display); + formats = g_renew(VAImageFormat, formats, n); + flags = g_new(guint, n); + if (!formats || !flags) + goto end; + status = vaQuerySubpictureFormats(priv->display, formats, flags, (guint *)&n); + if (!vaapi_check_status(status, "vaQuerySubpictureFormats()")) + goto end; + + GST_DEBUG("%d subpicture formats", n); + for (i = 0; i < n; i++) + GST_DEBUG(" %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(formats[i].fourcc)); + + priv->subpicture_formats = + g_array_new(FALSE, FALSE, sizeof(GstVaapiImageFormat)); + if (!priv->subpicture_formats) + goto end; + append_formats(priv->subpicture_formats, formats, n); + g_array_sort(priv->subpicture_formats, compare_rgb_formats); + + if (!cached_info) { + if (!gst_vaapi_display_cache_add(cache, &info)) + goto end; + } + + has_errors = FALSE; +end: + g_free(display_attrs); + g_free(profiles); + g_free(entrypoints); + g_free(formats); + g_free(flags); + return !has_errors; +} + +static void +gst_vaapi_display_lock_default(GstVaapiDisplay *display) +{ + GstVaapiDisplayPrivate *priv = display->priv; + + if (priv->parent) + priv = priv->parent->priv; + g_static_rec_mutex_lock(&priv->mutex); +} + +static void +gst_vaapi_display_unlock_default(GstVaapiDisplay *display) +{ + GstVaapiDisplayPrivate *priv = display->priv; + + if (priv->parent) + priv = priv->parent->priv; + g_static_rec_mutex_unlock(&priv->mutex); +} + +static void +gst_vaapi_display_finalize(GObject *object) +{ + GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object); + + gst_vaapi_display_destroy(display); + + g_static_rec_mutex_free(&display->priv->mutex); + + G_OBJECT_CLASS(gst_vaapi_display_parent_class)->finalize(object); +} + +static void +gst_vaapi_display_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object); + + switch (prop_id) { + case PROP_DISPLAY: + display->priv->display = g_value_get_pointer(value); + break; + case PROP_DISPLAY_TYPE: + display->priv->display_type = g_value_get_enum(value); + break; + case PROP_RENDER_MODE: + gst_vaapi_display_set_render_mode(display, g_value_get_enum(value)); + break; + case PROP_ROTATION: + gst_vaapi_display_set_rotation(display, g_value_get_enum(value)); + break; + case PROP_HUE: + case PROP_SATURATION: + case PROP_BRIGHTNESS: + case PROP_CONTRAST: + set_color_balance(display, prop_id, g_value_get_float(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_display_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object); + + switch (prop_id) { + case PROP_DISPLAY: + g_value_set_pointer(value, gst_vaapi_display_get_display(display)); + break; + case PROP_DISPLAY_TYPE: + g_value_set_enum(value, gst_vaapi_display_get_display_type(display)); + break; + case PROP_WIDTH: + g_value_set_uint(value, gst_vaapi_display_get_width(display)); + break; + case PROP_HEIGHT: + g_value_set_uint(value, gst_vaapi_display_get_height(display)); + break; + case PROP_RENDER_MODE: { + GstVaapiRenderMode mode; + if (!gst_vaapi_display_get_render_mode(display, &mode)) + mode = DEFAULT_RENDER_MODE; + g_value_set_enum(value, mode); + break; + } + case PROP_ROTATION: + g_value_set_enum(value, gst_vaapi_display_get_rotation(display)); + break; + case PROP_HUE: + case PROP_SATURATION: + case PROP_BRIGHTNESS: + case PROP_CONTRAST: { + gfloat v; + if (!get_color_balance(display, prop_id, &v)) + v = G_PARAM_SPEC_FLOAT(pspec)->default_value; + g_value_set_float(value, v); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_display_constructed(GObject *object) +{ + GstVaapiDisplay * const display = GST_VAAPI_DISPLAY(object); + GObjectClass *parent_class; + + display->priv->create_display = display->priv->display == NULL; + if (!gst_vaapi_display_create(display)) + gst_vaapi_display_destroy(display); + + parent_class = G_OBJECT_CLASS(gst_vaapi_display_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static void +gst_vaapi_display_class_init(GstVaapiDisplayClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass); + + GST_DEBUG_CATEGORY_INIT(gst_debug_vaapi, "vaapi", 0, "VA-API helper"); + + g_type_class_add_private(klass, sizeof(GstVaapiDisplayPrivate)); + + object_class->finalize = gst_vaapi_display_finalize; + object_class->set_property = gst_vaapi_display_set_property; + object_class->get_property = gst_vaapi_display_get_property; + object_class->constructed = gst_vaapi_display_constructed; + + dpy_class->lock = gst_vaapi_display_lock_default; + dpy_class->unlock = gst_vaapi_display_unlock_default; + + g_properties[PROP_DISPLAY] = + g_param_spec_pointer("display", + "VA display", + "VA display", + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY); + + g_properties[PROP_DISPLAY_TYPE] = + g_param_spec_enum("display-type", + "VA display type", + "VA display type", + GST_VAAPI_TYPE_DISPLAY_TYPE, + GST_VAAPI_DISPLAY_TYPE_ANY, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY); + + g_properties[PROP_WIDTH] = + g_param_spec_uint("width", + "Width", + "The display width", + 1, G_MAXUINT32, 1, + G_PARAM_READABLE); + + g_properties[PROP_HEIGHT] = + g_param_spec_uint("height", + "height", + "The display height", + 1, G_MAXUINT32, 1, + G_PARAM_READABLE); + + /** + * GstVaapiDisplay:render-mode: + * + * The VA display rendering mode, expressed as a #GstVaapiRenderMode. + */ + g_properties[PROP_RENDER_MODE] = + g_param_spec_enum(GST_VAAPI_DISPLAY_PROP_RENDER_MODE, + "render mode", + "The display rendering mode", + GST_VAAPI_TYPE_RENDER_MODE, + DEFAULT_RENDER_MODE, + G_PARAM_READWRITE); + + /** + * GstVaapiDisplay:rotation: + * + * The VA display rotation mode, expressed as a #GstVaapiRotation. + */ + g_properties[PROP_ROTATION] = + g_param_spec_enum(GST_VAAPI_DISPLAY_PROP_ROTATION, + "rotation", + "The display rotation mode", + GST_VAAPI_TYPE_ROTATION, + DEFAULT_ROTATION, + G_PARAM_READWRITE); + + /** + * GstVaapiDisplay:hue: + * + * The VA display hue, expressed as a float value. Range is -180.0 + * to 180.0. Default value is 0.0 and represents no modification. + */ + g_properties[PROP_HUE] = + g_param_spec_float(GST_VAAPI_DISPLAY_PROP_HUE, + "hue", + "The display hue value", + -180.0, 180.0, 0.0, + G_PARAM_READWRITE); + + /** + * GstVaapiDisplay:saturation: + * + * The VA display saturation, expressed as a float value. Range is + * 0.0 to 2.0. Default value is 1.0 and represents no modification. + */ + g_properties[PROP_SATURATION] = + g_param_spec_float(GST_VAAPI_DISPLAY_PROP_SATURATION, + "saturation", + "The display saturation value", + 0.0, 2.0, 1.0, + G_PARAM_READWRITE); + + /** + * GstVaapiDisplay:brightness: + * + * The VA display brightness, expressed as a float value. Range is + * -1.0 to 1.0. Default value is 0.0 and represents no modification. + */ + g_properties[PROP_BRIGHTNESS] = + g_param_spec_float(GST_VAAPI_DISPLAY_PROP_BRIGHTNESS, + "brightness", + "The display brightness value", + -1.0, 1.0, 0.0, + G_PARAM_READWRITE); + + /** + * GstVaapiDisplay:contrast: + * + * The VA display contrast, expressed as a float value. Range is + * 0.0 to 2.0. Default value is 1.0 and represents no modification. + */ + g_properties[PROP_CONTRAST] = + g_param_spec_float(GST_VAAPI_DISPLAY_PROP_CONTRAST, + "contrast", + "The display contrast value", + 0.0, 2.0, 1.0, + G_PARAM_READWRITE); + + g_object_class_install_properties(object_class, N_PROPERTIES, g_properties); +} + +static void +gst_vaapi_display_init(GstVaapiDisplay *display) +{ + GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE(display); + + display->priv = priv; + priv->parent = NULL; + priv->display_type = GST_VAAPI_DISPLAY_TYPE_ANY; + priv->display = NULL; + priv->width = 0; + priv->height = 0; + priv->width_mm = 0; + priv->height_mm = 0; + priv->par_n = 1; + priv->par_d = 1; + priv->decoders = NULL; + priv->encoders = NULL; + priv->image_formats = NULL; + priv->subpicture_formats = NULL; + priv->properties = NULL; + priv->create_display = TRUE; + + g_static_rec_mutex_init(&priv->mutex); +} + +/** + * gst_vaapi_display_new_with_display: + * @va_display: a #VADisplay + * + * Creates a new #GstVaapiDisplay, using @va_display as the VA + * display. + * + * Return value: the newly created #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_new_with_display(VADisplay va_display) +{ + GstVaapiDisplayCache * const cache = get_display_cache(); + const GstVaapiDisplayInfo *info; + + g_return_val_if_fail(va_display != NULL, NULL); + g_return_val_if_fail(cache != NULL, NULL); + + info = gst_vaapi_display_cache_lookup_by_va_display(cache, va_display); + if (info) + return g_object_ref(info->display); + + return g_object_new(GST_VAAPI_TYPE_DISPLAY, + "display", va_display, + NULL); +} + +/** + * gst_vaapi_display_lock: + * @display: a #GstVaapiDisplay + * + * Locks @display. If @display is already locked by another thread, + * the current thread will block until @display is unlocked by the + * other thread. + */ +void +gst_vaapi_display_lock(GstVaapiDisplay *display) +{ + GstVaapiDisplayClass *klass; + + g_return_if_fail(GST_VAAPI_IS_DISPLAY(display)); + + klass = GST_VAAPI_DISPLAY_GET_CLASS(display); + if (klass->lock) + klass->lock(display); +} + +/** + * gst_vaapi_display_unlock: + * @display: a #GstVaapiDisplay + * + * Unlocks @display. If another thread is blocked in a + * gst_vaapi_display_lock() call for @display, it will be woken and + * can lock @display itself. + */ +void +gst_vaapi_display_unlock(GstVaapiDisplay *display) +{ + GstVaapiDisplayClass *klass; + + g_return_if_fail(GST_VAAPI_IS_DISPLAY(display)); + + klass = GST_VAAPI_DISPLAY_GET_CLASS(display); + if (klass->unlock) + klass->unlock(display); +} + +/** + * gst_vaapi_display_sync: + * @display: a #GstVaapiDisplay + * + * Flushes any requests queued for the windowing system and waits until + * all requests have been handled. This is often used for making sure + * that the display is synchronized with the current state of the program. + * + * This is most useful for X11. On windowing systems where requests are + * handled synchronously, this function will do nothing. + */ +void +gst_vaapi_display_sync(GstVaapiDisplay *display) +{ + GstVaapiDisplayClass *klass; + + g_return_if_fail(GST_VAAPI_IS_DISPLAY(display)); + + klass = GST_VAAPI_DISPLAY_GET_CLASS(display); + if (klass->sync) + klass->sync(display); + else if (klass->flush) + klass->flush(display); +} + +/** + * gst_vaapi_display_flush: + * @display: a #GstVaapiDisplay + * + * Flushes any requests queued for the windowing system. + * + * This is most useful for X11. On windowing systems where requests + * are handled synchronously, this function will do nothing. + */ +void +gst_vaapi_display_flush(GstVaapiDisplay *display) +{ + GstVaapiDisplayClass *klass; + + g_return_if_fail(GST_VAAPI_IS_DISPLAY(display)); + + klass = GST_VAAPI_DISPLAY_GET_CLASS(display); + if (klass->flush) + klass->flush(display); +} + +/** + * gst_vaapi_display_get_display: + * @display: a #GstVaapiDisplay + * + * Returns the #GstVaapiDisplayType bound to @display. + * + * Return value: the #GstVaapiDisplayType + */ +GstVaapiDisplayType +gst_vaapi_display_get_display_type(GstVaapiDisplay *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), + GST_VAAPI_DISPLAY_TYPE_ANY); + + return display->priv->display_type; +} + +/** + * gst_vaapi_display_get_display: + * @display: a #GstVaapiDisplay + * + * Returns the #VADisplay bound to @display. + * + * Return value: the #VADisplay + */ +VADisplay +gst_vaapi_display_get_display(GstVaapiDisplay *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + + return display->priv->display; +} + +/** + * gst_vaapi_display_get_width: + * @display: a #GstVaapiDisplay + * + * Retrieves the width of a #GstVaapiDisplay. + * + * Return value: the width of the @display, in pixels + */ +guint +gst_vaapi_display_get_width(GstVaapiDisplay *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), 0); + + return display->priv->width; +} + +/** + * gst_vaapi_display_get_height: + * @display: a #GstVaapiDisplay + * + * Retrieves the height of a #GstVaapiDisplay + * + * Return value: the height of the @display, in pixels + */ +guint +gst_vaapi_display_get_height(GstVaapiDisplay *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), 0); + + return display->priv->height; +} + +/** + * gst_vaapi_display_get_size: + * @display: a #GstVaapiDisplay + * @pwidth: return location for the width, or %NULL + * @pheight: return location for the height, or %NULL + * + * Retrieves the dimensions of a #GstVaapiDisplay. + */ +void +gst_vaapi_display_get_size(GstVaapiDisplay *display, guint *pwidth, guint *pheight) +{ + g_return_if_fail(GST_VAAPI_DISPLAY(display)); + + if (pwidth) + *pwidth = display->priv->width; + + if (pheight) + *pheight = display->priv->height; +} + +/** + * gst_vaapi_display_get_pixel_aspect_ratio: + * @display: a #GstVaapiDisplay + * @par_n: return location for the numerator of pixel aspect ratio, or %NULL + * @par_d: return location for the denominator of pixel aspect ratio, or %NULL + * + * Retrieves the pixel aspect ratio of a #GstVaapiDisplay. + */ +void +gst_vaapi_display_get_pixel_aspect_ratio( + GstVaapiDisplay *display, + guint *par_n, + guint *par_d +) +{ + g_return_if_fail(GST_VAAPI_IS_DISPLAY(display)); + + if (par_n) + *par_n = display->priv->par_n; + + if (par_d) + *par_d = display->priv->par_d; +} + +/** + * gst_vaapi_display_get_decode_caps: + * @display: a #GstVaapiDisplay + * + * Gets the supported profiles for decoding as #GstCaps capabilities. + * + * Return value: a newly allocated #GstCaps object, possibly empty + */ +GstCaps * +gst_vaapi_display_get_decode_caps(GstVaapiDisplay *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + + return get_profile_caps(display->priv->decoders); +} + +/** + * gst_vaapi_display_has_decoder: + * @display: a #GstVaapiDisplay + * @profile: a #VAProfile + * @entrypoint: a #GstVaaiEntrypoint + * + * Returns whether VA @display supports @profile for decoding at the + * specified @entrypoint. + * + * Return value: %TRUE if VA @display supports @profile for decoding. + */ +gboolean +gst_vaapi_display_has_decoder( + GstVaapiDisplay *display, + GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint +) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE); + + return find_config(display->priv->decoders, profile, entrypoint); +} + +/** + * gst_vaapi_display_get_encode_caps: + * @display: a #GstVaapiDisplay + * + * Gets the supported profiles for decoding as #GstCaps capabilities. + * + * Return value: a newly allocated #GstCaps object, possibly empty + */ +GstCaps * +gst_vaapi_display_get_encode_caps(GstVaapiDisplay *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + + return get_profile_caps(display->priv->encoders); +} + +/** + * gst_vaapi_display_has_encoder: + * @display: a #GstVaapiDisplay + * @profile: a #VAProfile + * @entrypoint: a #GstVaapiEntrypoint + * + * Returns whether VA @display supports @profile for encoding at the + * specified @entrypoint. + * + * Return value: %TRUE if VA @display supports @profile for encoding. + */ +gboolean +gst_vaapi_display_has_encoder( + GstVaapiDisplay *display, + GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint +) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE); + + return find_config(display->priv->encoders, profile, entrypoint); +} + +/** + * gst_vaapi_display_get_image_caps: + * @display: a #GstVaapiDisplay + * + * Gets the supported image formats for gst_vaapi_surface_get_image() + * or gst_vaapi_surface_put_image() as #GstCaps capabilities. + * + * Note that this method does not necessarily map image formats + * returned by vaQueryImageFormats(). The set of capabilities can be + * stripped down, if gstreamer-vaapi does not support the format, or + * expanded to cover compatible formats not exposed by the underlying + * driver. e.g. I420 can be supported even if the driver only exposes + * YV12. + * + * Return value: a newly allocated #GstCaps object, possibly empty + */ +GstCaps * +gst_vaapi_display_get_image_caps(GstVaapiDisplay *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + + return get_format_caps(display->priv->image_formats); +} + +/** + * gst_vaapi_display_has_image_format: + * @display: a #GstVaapiDisplay + * @format: a #GstVaapiFormat + * + * Returns whether VA @display supports @format image format. + * + * Return value: %TRUE if VA @display supports @format image format + */ +gboolean +gst_vaapi_display_has_image_format( + GstVaapiDisplay *display, + GstVaapiImageFormat format +) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE); + g_return_val_if_fail(format, FALSE); + + if (find_format(display->priv->image_formats, format)) + return TRUE; + + /* XXX: try subpicture formats since some drivers could report a + * set of VA image formats that is not a superset of the set of VA + * subpicture formats + */ + return find_format(display->priv->subpicture_formats, format); +} + +/** + * gst_vaapi_display_get_subpicture_caps: + * @display: a #GstVaapiDisplay + * + * Gets the supported subpicture formats as #GstCaps capabilities. + * + * Note that this method does not necessarily map subpicture formats + * returned by vaQuerySubpictureFormats(). The set of capabilities can + * be stripped down if gstreamer-vaapi does not support the + * format. e.g. this is the case for paletted formats like IA44. + * + * Return value: a newly allocated #GstCaps object, possibly empty + */ +GstCaps * +gst_vaapi_display_get_subpicture_caps(GstVaapiDisplay *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + + return get_format_caps(display->priv->subpicture_formats); +} + +/** + * gst_vaapi_display_has_subpicture_format: + * @display: a #GstVaapiDisplay + * @format: a #GstVaapiFormat + * + * Returns whether VA @display supports @format subpicture format. + * + * Return value: %TRUE if VA @display supports @format subpicture format + */ +gboolean +gst_vaapi_display_has_subpicture_format( + GstVaapiDisplay *display, + GstVaapiImageFormat format +) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE); + g_return_val_if_fail(format, FALSE); + + return find_format(display->priv->subpicture_formats, format); +} + +/** + * gst_vaapi_display_has_property: + * @display: a #GstVaapiDisplay + * @name: the property name to check + * + * Returns whether VA @display supports the requested property. The + * check is performed against the property @name. So, the client + * application may perform this check only once and cache this + * information. + * + * Return value: %TRUE if VA @display supports property @name + */ +gboolean +gst_vaapi_display_has_property(GstVaapiDisplay *display, const gchar *name) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE); + g_return_val_if_fail(name, FALSE); + + return find_property(display->priv->properties, name) != NULL; +} + +static gboolean +get_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint *value) +{ + VADisplayAttribute attr; + VAStatus status; + + attr.type = type; + attr.flags = VA_DISPLAY_ATTRIB_GETTABLE; + status = vaGetDisplayAttributes(display->priv->display, &attr, 1); + if (!vaapi_check_status(status, "vaGetDisplayAttributes()")) + return FALSE; + *value = attr.value; + return TRUE; +} + +static gboolean +set_attribute(GstVaapiDisplay *display, VADisplayAttribType type, gint value) +{ + VADisplayAttribute attr; + VAStatus status; + + attr.type = type; + attr.value = value; + attr.flags = VA_DISPLAY_ATTRIB_SETTABLE; + status = vaSetDisplayAttributes(display->priv->display, &attr, 1); + if (!vaapi_check_status(status, "vaSetDisplayAttributes()")) + return FALSE; + return TRUE; +} + +static gboolean +get_render_mode_VADisplayAttribRenderMode( + GstVaapiDisplay *display, + GstVaapiRenderMode *pmode +) +{ + gint modes, devices; + + if (!get_attribute(display, VADisplayAttribRenderDevice, &devices)) + return FALSE; + if (!devices) + return FALSE; + if (!get_attribute(display, VADisplayAttribRenderMode, &modes)) + return FALSE; + + /* Favor "overlay" mode since it is the most restrictive one */ + if (modes & (VA_RENDER_MODE_LOCAL_OVERLAY|VA_RENDER_MODE_EXTERNAL_OVERLAY)) + *pmode = GST_VAAPI_RENDER_MODE_OVERLAY; + else + *pmode = GST_VAAPI_RENDER_MODE_TEXTURE; + return TRUE; +} + +static gboolean +get_render_mode_VADisplayAttribDirectSurface( + GstVaapiDisplay *display, + GstVaapiRenderMode *pmode +) +{ +#if VA_CHECK_VERSION(0,34,0) + /* VADisplayAttribDirectsurface was removed in VA-API >= 0.34.0 */ + return FALSE; +#else + gint direct_surface; + + if (!get_attribute(display, VADisplayAttribDirectSurface, &direct_surface)) + return FALSE; + if (direct_surface) + *pmode = GST_VAAPI_RENDER_MODE_OVERLAY; + else + *pmode = GST_VAAPI_RENDER_MODE_TEXTURE; + return TRUE; +#endif +} + +static gboolean +get_render_mode_default( + GstVaapiDisplay *display, + GstVaapiRenderMode *pmode +) +{ + switch (display->priv->display_type) { +#if USE_WAYLAND + case GST_VAAPI_DISPLAY_TYPE_WAYLAND: + /* wl_buffer mapped from VA surface through vaGetSurfaceBufferWl() */ + *pmode = GST_VAAPI_RENDER_MODE_OVERLAY; + break; +#endif +#if USE_DRM + case GST_VAAPI_DISPLAY_TYPE_DRM: + /* vaGetSurfaceBufferDRM() returns the underlying DRM buffer handle */ + *pmode = GST_VAAPI_RENDER_MODE_OVERLAY; + break; +#endif + default: + /* This includes VA/X11 and VA/GLX modes */ + *pmode = DEFAULT_RENDER_MODE; + break; + } + return TRUE; +} + +/** + * gst_vaapi_display_get_render_mode: + * @display: a #GstVaapiDisplay + * @pmode: return location for the VA @display rendering mode + * + * Returns the current VA @display rendering mode. + * + * Return value: %TRUE if VA @display rendering mode could be determined + */ +gboolean +gst_vaapi_display_get_render_mode( + GstVaapiDisplay *display, + GstVaapiRenderMode *pmode +) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE); + + /* Try with render-mode attribute */ + if (get_render_mode_VADisplayAttribRenderMode(display, pmode)) + return TRUE; + + /* Try with direct-surface attribute */ + if (get_render_mode_VADisplayAttribDirectSurface(display, pmode)) + return TRUE; + + /* Default: determine from the display type */ + return get_render_mode_default(display, pmode); +} + +/** + * gst_vaapi_display_set_render_mode: + * @display: a #GstVaapiDisplay + * @mode: the #GstVaapiRenderMode to set + * + * Sets the VA @display rendering mode to the supplied @mode. This + * function returns %FALSE if the rendering mode could not be set, + * e.g. run-time switching rendering mode is not supported. + * + * Return value: %TRUE if VA @display rendering @mode could be changed + * to the requested value + */ +gboolean +gst_vaapi_display_set_render_mode( + GstVaapiDisplay *display, + GstVaapiRenderMode mode +) +{ + gint modes, devices; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE); + + if (!get_attribute(display, VADisplayAttribRenderDevice, &devices)) + return FALSE; + + modes = 0; + switch (mode) { + case GST_VAAPI_RENDER_MODE_OVERLAY: + if (devices & VA_RENDER_DEVICE_LOCAL) + modes |= VA_RENDER_MODE_LOCAL_OVERLAY; + if (devices & VA_RENDER_DEVICE_EXTERNAL) + modes |= VA_RENDER_MODE_EXTERNAL_OVERLAY; + break; + case GST_VAAPI_RENDER_MODE_TEXTURE: + if (devices & VA_RENDER_DEVICE_LOCAL) + modes |= VA_RENDER_MODE_LOCAL_GPU; + if (devices & VA_RENDER_DEVICE_EXTERNAL) + modes |= VA_RENDER_MODE_EXTERNAL_GPU; + break; + } + if (!modes) + return FALSE; + if (!set_attribute(display, VADisplayAttribRenderMode, modes)) + return FALSE; + + g_object_notify_by_pspec(G_OBJECT(display), g_properties[PROP_RENDER_MODE]); + return TRUE; +} + +/** + * gst_vaapi_display_get_rotation: + * @display: a #GstVaapiDisplay + * + * Returns the current VA @display rotation angle. If the VA driver + * does not support "rotation" display attribute, then the display is + * assumed to be un-rotated. + * + * Return value: the current #GstVaapiRotation value + */ +GstVaapiRotation +gst_vaapi_display_get_rotation(GstVaapiDisplay *display) +{ + gint value; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), DEFAULT_ROTATION); + + if (!get_attribute(display, VADisplayAttribRotation, &value)) + value = VA_ROTATION_NONE; + return to_GstVaapiRotation(value); +} + +/** + * gst_vaapi_display_set_rotation: + * @display: a #GstVaapiDisplay + * @rotation: the #GstVaapiRotation value to set + * + * Sets the VA @display rotation angle to the supplied @rotation + * value. This function returns %FALSE if the rotation angle could not + * be set, e.g. the VA driver does not allow to change the display + * rotation angle. + * + * Return value: %TRUE if VA @display rotation angle could be changed + * to the requested value + */ +gboolean +gst_vaapi_display_set_rotation( + GstVaapiDisplay *display, + GstVaapiRotation rotation +) +{ + guint value; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE); + + value = from_GstVaapiRotation(rotation); + if (!set_attribute(display, VADisplayAttribRotation, value)) + return FALSE; + + g_object_notify_by_pspec(G_OBJECT(display), g_properties[PROP_ROTATION]); + return TRUE; +} + +/* Get color balance attributes */ +static gboolean +get_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat *v) +{ + GParamSpecFloat * const pspec = G_PARAM_SPEC_FLOAT(g_properties[prop_id]); + const GstVaapiProperty *prop; + const VADisplayAttribute *attr; + gfloat out_value; + gint value; + + if (!pspec) + return FALSE; + + prop = find_property_by_pspec(display, &pspec->parent_instance); + if (!prop) + return FALSE; + attr = &prop->attribute; + + if (!get_attribute(display, attr->type, &value)) + return FALSE; + + /* Scale wrt. the medium ("default") value */ + out_value = pspec->default_value; + if (value > attr->value) + out_value += ((gfloat)(value - attr->value) / + (attr->max_value - attr->value) * + (pspec->maximum - pspec->default_value)); + else if (value < attr->value) + out_value -= ((gfloat)(attr->value - value) / + (attr->value - attr->min_value) * + (pspec->default_value - pspec->minimum)); + *v = out_value; + return TRUE; +} + +/* Set color balance attribute */ +static gboolean +set_color_balance(GstVaapiDisplay *display, guint prop_id, gfloat v) +{ + GParamSpecFloat * const pspec = G_PARAM_SPEC_FLOAT(g_properties[prop_id]); + const GstVaapiProperty *prop; + const VADisplayAttribute *attr; + gint value; + + if (!pspec) + return FALSE; + + prop = find_property_by_pspec(display, &pspec->parent_instance); + if (!prop) + return FALSE; + attr = &prop->attribute; + + /* Scale wrt. the medium ("default") value */ + value = attr->value; + if (v > pspec->default_value) + value += ((v - pspec->default_value) / + (pspec->maximum - pspec->default_value) * + (attr->max_value - attr->value)); + else if (v < pspec->default_value) + value -= ((pspec->default_value - v) / + (pspec->default_value - pspec->minimum) * + (attr->value - attr->min_value)); + if (!set_attribute(display, attr->type, value)) + return FALSE; + + g_object_notify_by_pspec(G_OBJECT(display), g_properties[prop_id]); + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay.h b/gst-libs/gst/vaapi/gstvaapidisplay.h new file mode 100644 index 0000000..56ca042 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay.h @@ -0,0 +1,264 @@ +/* + * gstvaapidisplay.h - VA display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_H +#define GST_VAAPI_DISPLAY_H + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DISPLAY \ + (gst_vaapi_display_get_type()) + +#define GST_VAAPI_DISPLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DISPLAY, \ + GstVaapiDisplay)) + +#define GST_VAAPI_DISPLAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DISPLAY, \ + GstVaapiDisplayClass)) + +#define GST_VAAPI_IS_DISPLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DISPLAY)) + +#define GST_VAAPI_IS_DISPLAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DISPLAY)) + +#define GST_VAAPI_DISPLAY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DISPLAY, \ + GstVaapiDisplayClass)) + +typedef enum _GstVaapiDisplayType GstVaapiDisplayType; +typedef struct _GstVaapiDisplayInfo GstVaapiDisplayInfo; +typedef struct _GstVaapiDisplay GstVaapiDisplay; +typedef struct _GstVaapiDisplayPrivate GstVaapiDisplayPrivate; +typedef struct _GstVaapiDisplayClass GstVaapiDisplayClass; + +/** + * GstVaapiDisplayType: + * @GST_VAAPI_DISPLAY_TYPE_ANY: Automatic detection of the display type. + * @GST_VAAPI_DISPLAY_TYPE_X11: VA/X11 display. + * @GST_VAAPI_DISPLAY_TYPE_GLX: VA/GLX display. + * @GST_VAAPI_DISPLAY_TYPE_WAYLAND: VA/Wayland display. + * @GST_VAAPI_DISPLAY_TYPE_DRM: VA/DRM display. + */ +enum _GstVaapiDisplayType { + GST_VAAPI_DISPLAY_TYPE_ANY = 0, + GST_VAAPI_DISPLAY_TYPE_X11, + GST_VAAPI_DISPLAY_TYPE_GLX, + GST_VAAPI_DISPLAY_TYPE_WAYLAND, + GST_VAAPI_DISPLAY_TYPE_DRM, +}; + +#define GST_VAAPI_TYPE_DISPLAY_TYPE \ + (gst_vaapi_display_type_get_type()) + +GType +gst_vaapi_display_type_get_type(void) G_GNUC_CONST; + +/** + * GstVaapiDisplayInfo: + * + * Generic class to retrieve VA display info + */ +struct _GstVaapiDisplayInfo { + GstVaapiDisplay *display; + GstVaapiDisplayType display_type; + gchar *display_name; + VADisplay va_display; + gpointer native_display; +}; + +/** + * GstVaapiDisplayProperties: + * @GST_VAAPI_DISPLAY_PROP_RENDER_MODE: rendering mode (#GstVaapiRenderMode). + * @GST_VAAPI_DISPLAY_PROP_ROTATION: rotation angle (#GstVaapiRotation). + * @GST_VAAPI_DISPLAY_PROP_HUE: hue (float: [-180 ; 180], default: 0). + * @GST_VAAPI_DISPLAY_PROP_SATURATION: saturation (float: [0 ; 2], default: 1). + * @GST_VAAPI_DISPLAY_PROP_BRIGHTNESS: brightness (float: [-1 ; 1], default: 0). + * @GST_VAAPI_DISPLAY_PROP_CONTRAST: contrast (float: [0 ; 2], default: 1). + */ +#define GST_VAAPI_DISPLAY_PROP_RENDER_MODE "render-mode" +#define GST_VAAPI_DISPLAY_PROP_ROTATION "rotation" +#define GST_VAAPI_DISPLAY_PROP_HUE "hue" +#define GST_VAAPI_DISPLAY_PROP_SATURATION "saturation" +#define GST_VAAPI_DISPLAY_PROP_BRIGHTNESS "brightness" +#define GST_VAAPI_DISPLAY_PROP_CONTRAST "contrast" + +/** + * GstVaapiDisplay: + * + * Base class for VA displays. + */ +struct _GstVaapiDisplay { + /*< private >*/ + GObject parent_instance; + + GstVaapiDisplayPrivate *priv; +}; + +/** + * GstVaapiDisplayClass: + * @open_display: virtual function to open a display + * @close_display: virtual function to close a display + * @lock: (optional) virtual function to lock a display + * @unlock: (optional) virtual function to unlock a display + * @sync: (optional) virtual function to sync a display + * @flush: (optional) virtual function to flush pending requests of a display + * @get_display: virtual function to retrieve the #GstVaapiDisplayInfo + * @get_size: virtual function to retrieve the display dimensions, in pixels + * @get_size_mm: virtual function to retrieve the display dimensions, in millimeters + * + * Base class for VA displays. + */ +struct _GstVaapiDisplayClass { + /*< private >*/ + GObjectClass parent_class; + + /*< public >*/ + gboolean (*open_display) (GstVaapiDisplay *display); + void (*close_display) (GstVaapiDisplay *display); + void (*lock) (GstVaapiDisplay *display); + void (*unlock) (GstVaapiDisplay *display); + void (*sync) (GstVaapiDisplay *display); + void (*flush) (GstVaapiDisplay *display); + gboolean (*get_display) (GstVaapiDisplay *display, + GstVaapiDisplayInfo *info); + void (*get_size) (GstVaapiDisplay *display, + guint *pwidth, guint *pheight); + void (*get_size_mm) (GstVaapiDisplay *display, + guint *pwidth, guint *pheight); +}; + +GType +gst_vaapi_display_get_type(void) G_GNUC_CONST; + +GstVaapiDisplay * +gst_vaapi_display_new_with_display(VADisplay va_display); + +void +gst_vaapi_display_lock(GstVaapiDisplay *display); + +void +gst_vaapi_display_unlock(GstVaapiDisplay *display); + +void +gst_vaapi_display_sync(GstVaapiDisplay *display); + +void +gst_vaapi_display_flush(GstVaapiDisplay *display); + +GstVaapiDisplayType +gst_vaapi_display_get_display_type(GstVaapiDisplay *display); + +VADisplay +gst_vaapi_display_get_display(GstVaapiDisplay *display); + +guint +gst_vaapi_display_get_width(GstVaapiDisplay *display); + +guint +gst_vaapi_display_get_height(GstVaapiDisplay *display); + +void +gst_vaapi_display_get_size(GstVaapiDisplay *display, guint *pwidth, guint *pheight); + +void +gst_vaapi_display_get_pixel_aspect_ratio( + GstVaapiDisplay *display, + guint *par_n, + guint *par_d +); + +GstCaps * +gst_vaapi_display_get_decode_caps(GstVaapiDisplay *display); + +gboolean +gst_vaapi_display_has_decoder( + GstVaapiDisplay *display, + GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint +); + +GstCaps * +gst_vaapi_display_get_encode_caps(GstVaapiDisplay *display); + +gboolean +gst_vaapi_display_has_encoder( + GstVaapiDisplay *display, + GstVaapiProfile profile, + GstVaapiEntrypoint entrypoint +); + +GstCaps * +gst_vaapi_display_get_image_caps(GstVaapiDisplay *display); + +gboolean +gst_vaapi_display_has_image_format( + GstVaapiDisplay *display, + GstVaapiImageFormat format +); + +GstCaps * +gst_vaapi_display_get_subpicture_caps(GstVaapiDisplay *display); + +gboolean +gst_vaapi_display_has_subpicture_format( + GstVaapiDisplay *display, + GstVaapiImageFormat format +); + +gboolean +gst_vaapi_display_has_property(GstVaapiDisplay *display, const gchar *name); + +gboolean +gst_vaapi_display_get_render_mode( + GstVaapiDisplay *display, + GstVaapiRenderMode *pmode +); + +gboolean +gst_vaapi_display_set_render_mode( + GstVaapiDisplay *display, + GstVaapiRenderMode mode +); + +GstVaapiRotation +gst_vaapi_display_get_rotation(GstVaapiDisplay *display); + +gboolean +gst_vaapi_display_set_rotation( + GstVaapiDisplay *display, + GstVaapiRotation rotation +); + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_drm.c b/gst-libs/gst/vaapi/gstvaapidisplay_drm.c new file mode 100644 index 0000000..6a1d148 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_drm.c @@ -0,0 +1,532 @@ +/* + * gstvaapidisplay_drm.c - VA/DRM display abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidisplay_drm + * @short_description: VA/DRM display abstraction + */ + +#include "sysdeps.h" +#include +#include +#include +#include +#include +#include +#include "gstvaapiutils.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapidisplay_drm.h" +#include "gstvaapidisplay_drm_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDisplayDRM, + gst_vaapi_display_drm, + GST_VAAPI_TYPE_DISPLAY); + +enum { + PROP_0, + + PROP_DEVICE_PATH, + PROP_DRM_DEVICE +}; + +#define NAME_PREFIX "DRM:" +#define NAME_PREFIX_LENGTH 4 + +static inline gboolean +is_device_path(const gchar *device_path) +{ + return strncmp(device_path, NAME_PREFIX, NAME_PREFIX_LENGTH) == 0; +} + +static gboolean +compare_device_path(gconstpointer a, gconstpointer b, gpointer user_data) +{ + const gchar *cached_name = a; + const gchar *tested_name = b; + + if (!cached_name || !is_device_path(cached_name)) + return FALSE; + g_return_val_if_fail(tested_name && is_device_path(tested_name), FALSE); + + cached_name += NAME_PREFIX_LENGTH; + tested_name += NAME_PREFIX_LENGTH; + return strcmp(cached_name, tested_name) == 0; +} + +static void +gst_vaapi_display_drm_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_display_drm_parent_class)->finalize(object); +} + +/* Get default device path. Actually, the first match in the DRM subsystem */ +static const gchar * +get_default_device_path(gpointer ptr) +{ + GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(ptr); + GstVaapiDisplayDRMPrivate * const priv = display->priv; + const gchar *syspath, *devpath; + struct udev *udev = NULL; + struct udev_device *device, *parent; + struct udev_enumerate *e = NULL; + struct udev_list_entry *l; + int fd; + + if (!priv->device_path_default) { + udev = udev_new(); + if (!udev) + goto end; + + e = udev_enumerate_new(udev); + if (!e) + goto end; + + udev_enumerate_add_match_subsystem(e, "drm"); + udev_enumerate_scan_devices(e); + udev_list_entry_foreach(l, udev_enumerate_get_list_entry(e)) { + syspath = udev_list_entry_get_name(l); + device = udev_device_new_from_syspath(udev, syspath); + parent = udev_device_get_parent(device); + if (strcmp(udev_device_get_subsystem(parent), "pci") != 0) { + udev_device_unref(device); + continue; + } + + devpath = udev_device_get_devnode(device); + fd = open(devpath, O_RDWR|O_CLOEXEC); + if (fd < 0) { + udev_device_unref(device); + continue; + } + + priv->device_path_default = g_strdup(devpath); + close(fd); + udev_device_unref(device); + break; + } + + end: + if (e) + udev_enumerate_unref(e); + if (udev) + udev_unref(udev); + } + return priv->device_path_default; +} + +/* Reconstruct a device path without our prefix */ +static const gchar * +get_device_path(gpointer ptr) +{ + GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(ptr); + const gchar *device_path = display->priv->device_path; + + if (!device_path) + return NULL; + + g_return_val_if_fail(is_device_path(device_path), NULL); + + device_path += NAME_PREFIX_LENGTH; + if (*device_path == '\0') + return NULL; + return device_path; +} + +/* Mangle device path with our prefix */ +static void +set_device_path(GstVaapiDisplayDRM *display, const gchar *device_path) +{ + GstVaapiDisplayDRMPrivate * const priv = display->priv; + + g_free(priv->device_path); + priv->device_path = NULL; + + if (!device_path) { + device_path = get_default_device_path(display); + if (!device_path) + return; + } + priv->device_path = g_strdup_printf("%s%s", NAME_PREFIX, device_path); +} + +/* Set device path from file descriptor */ +static void +set_device_path_from_fd(GstVaapiDisplayDRM *display, gint drm_device) +{ + GstVaapiDisplayDRMPrivate * const priv = display->priv; + const gchar *busid, *path, *str; + gsize busid_length, path_length; + struct udev *udev = NULL; + struct udev_device *device; + struct udev_enumerate *e = NULL; + struct udev_list_entry *l; + + g_free(priv->device_path); + priv->device_path = NULL; + + if (drm_device < 0) + return; + + busid = drmGetBusid(drm_device); + if (!busid) + return; + if (strncmp(busid, "pci:", 4) != 0) + return; + busid += 4; + busid_length = strlen(busid); + + udev = udev_new(); + if (!udev) + goto end; + + e = udev_enumerate_new(udev); + if (!e) + goto end; + + udev_enumerate_add_match_subsystem(e, "drm"); + udev_enumerate_scan_devices(e); + udev_list_entry_foreach(l, udev_enumerate_get_list_entry(e)) { + path = udev_list_entry_get_name(l); + str = strstr(path, busid); + if (!str || str <= path || str[-1] != '/') + continue; + + path_length = strlen(path); + if (str + busid_length >= path + path_length) + continue; + if (strncmp(&str[busid_length], "/drm/card", 9) != 0) + continue; + + device = udev_device_new_from_syspath(udev, path); + if (!device) + continue; + + path = udev_device_get_devnode(device); + priv->device_path = g_strdup_printf("%s%s", NAME_PREFIX, path); + udev_device_unref(device); + break; + } + +end: + if (e) + udev_enumerate_unref(e); + if (udev) + udev_unref(udev); +} + +static void +gst_vaapi_display_drm_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(object); + + switch (prop_id) { + case PROP_DEVICE_PATH: + set_device_path(display, g_value_get_string(value)); + break; + case PROP_DRM_DEVICE: + display->priv->drm_device = g_value_get_int(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_display_drm_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(object); + + switch (prop_id) { + case PROP_DEVICE_PATH: + g_value_set_string(value, get_device_path(display)); + break; + case PROP_DRM_DEVICE: + g_value_set_int(value, display->priv->drm_device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_display_drm_constructed(GObject *object) +{ + GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(object); + GstVaapiDisplayDRMPrivate * const priv = display->priv; + GstVaapiDisplayCache * const cache = gst_vaapi_display_get_cache(); + const GstVaapiDisplayInfo *info; + GObjectClass *parent_class; + + priv->create_display = priv->drm_device < 0; + + /* Don't create DRM display if there is one in the cache already */ + if (priv->create_display) { + info = gst_vaapi_display_cache_lookup_by_name( + cache, + priv->device_path, + compare_device_path, NULL + ); + if (info) { + priv->drm_device = GPOINTER_TO_INT(info->native_display); + priv->create_display = FALSE; + } + } + + /* Reset device-path if the user provided his own DRM display */ + if (!priv->create_display) + set_device_path_from_fd(display, priv->drm_device); + + parent_class = G_OBJECT_CLASS(gst_vaapi_display_drm_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static gboolean +gst_vaapi_display_drm_open_display(GstVaapiDisplay *display) +{ + GstVaapiDisplayDRMPrivate * const priv = + GST_VAAPI_DISPLAY_DRM(display)->priv; + + if (priv->create_display) { + const gchar *device_path = get_device_path(display); + if (!device_path) + return FALSE; + priv->drm_device = open(device_path, O_RDWR|O_CLOEXEC); + if (priv->drm_device < 0) + return FALSE; + } + if (priv->drm_device < 0) + return FALSE; + return TRUE; +} + +static void +gst_vaapi_display_drm_close_display(GstVaapiDisplay *display) +{ + GstVaapiDisplayDRMPrivate * const priv = + GST_VAAPI_DISPLAY_DRM(display)->priv; + + if (priv->drm_device >= 0) { + if (priv->create_display) + close(priv->drm_device); + priv->drm_device = -1; + } + + if (priv->device_path) { + g_free(priv->device_path); + priv->device_path = NULL; + } + + if (priv->device_path_default) { + g_free(priv->device_path_default); + priv->device_path_default = NULL; + } +} + +static gboolean +gst_vaapi_display_drm_get_display_info( + GstVaapiDisplay *display, + GstVaapiDisplayInfo *info +) +{ + GstVaapiDisplayDRMPrivate * const priv = + GST_VAAPI_DISPLAY_DRM(display)->priv; + GstVaapiDisplayCache *cache; + const GstVaapiDisplayInfo *cached_info; + + /* Return any cached info even if child has its own VA display */ + cache = gst_vaapi_display_get_cache(); + if (!cache) + return FALSE; + cached_info = gst_vaapi_display_cache_lookup_by_native_display( + cache, GINT_TO_POINTER(priv->drm_device)); + if (cached_info) { + *info = *cached_info; + return TRUE; + } + + /* Otherwise, create VA display if there is none already */ + info->native_display = GINT_TO_POINTER(priv->drm_device); + info->display_name = priv->device_path; + if (!info->va_display) { + info->va_display = vaGetDisplayDRM(priv->drm_device); + if (!info->va_display) + return FALSE; + info->display_type = GST_VAAPI_DISPLAY_TYPE_DRM; + } + return TRUE; +} + +static void +gst_vaapi_display_drm_class_init(GstVaapiDisplayDRMClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiDisplayDRMPrivate)); + + object_class->finalize = gst_vaapi_display_drm_finalize; + object_class->set_property = gst_vaapi_display_drm_set_property; + object_class->get_property = gst_vaapi_display_drm_get_property; + object_class->constructed = gst_vaapi_display_drm_constructed; + + dpy_class->open_display = gst_vaapi_display_drm_open_display; + dpy_class->close_display = gst_vaapi_display_drm_close_display; + dpy_class->get_display = gst_vaapi_display_drm_get_display_info; + + /** + * GstVaapiDisplayDRM:drm-device: + * + * The DRM device (file descriptor). + */ + g_object_class_install_property + (object_class, + PROP_DRM_DEVICE, + g_param_spec_int("drm-device", + "DRM device", + "DRM device", + -1, G_MAXINT32, -1, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + /** + * GstVaapiDisplayDRM:device-path: + * + * The DRM device path. + */ + g_object_class_install_property + (object_class, + PROP_DEVICE_PATH, + g_param_spec_string("device-path", + "DRM device path", + "DRM device path", + NULL, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gst_vaapi_display_drm_init(GstVaapiDisplayDRM *display) +{ + GstVaapiDisplayDRMPrivate * const priv = + GST_VAAPI_DISPLAY_DRM_GET_PRIVATE(display); + + display->priv = priv; + priv->device_path_default = NULL; + priv->device_path = NULL; + priv->drm_device = -1; + priv->create_display = TRUE; +} + +/** + * gst_vaapi_display_drm_new: + * @device_path: the DRM device path + * + * Opens an DRM file descriptor using @device_path and returns a newly + * allocated #GstVaapiDisplay object. The DRM display will be cloed + * when the reference count of the object reaches zero. + * + * If @device_path is NULL, the DRM device path will be automatically + * determined as the first positive match in the list of available DRM + * devices. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_drm_new(const gchar *device_path) +{ + return g_object_new(GST_VAAPI_TYPE_DISPLAY_DRM, + "device-path", device_path, + NULL); +} + +/** + * gst_vaapi_display_drm_new_with_device: + * @device: an open DRM device (file descriptor) + * + * Creates a #GstVaapiDisplay based on the open DRM @device. The + * caller still owns the device file descriptor and must call close() + * when all #GstVaapiDisplay references are released. Doing so too + * early can yield undefined behaviour. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_drm_new_with_device(gint device) +{ + g_return_val_if_fail(device >= 0, NULL); + + return g_object_new(GST_VAAPI_TYPE_DISPLAY_DRM, + "drm-device", device, + NULL); +} + +/** + * gst_vaapi_display_drm_get_device: + * @display: a #GstVaapiDisplayDRM + * + * Returns the underlying DRM device file descriptor that was created + * by gst_vaapi_display_drm_new() or that was bound from + * gst_vaapi_display_drm_new_with_device(). + * + * Return value: the DRM file descriptor attached to @display + */ +gint +gst_vaapi_display_drm_get_device(GstVaapiDisplayDRM *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_DRM(display), -1); + + return display->priv->drm_device; +} + +/** + * gst_vaapi_display_drm_get_device_path: + * @display: a #GstVaapiDisplayDRM + * + * Returns the underlying DRM device path name was created by + * gst_vaapi_display_drm_new() or that was bound from + * gst_vaapi_display_drm_new_with_device(). + * + * Note: the #GstVaapiDisplayDRM object owns the resulting string, so + * it shall not be deallocated. + * + * Return value: the DRM device path name attached to @display + */ +const gchar * +gst_vaapi_display_drm_get_device_path(GstVaapiDisplayDRM *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_DRM(display), NULL); + + return display->priv->device_path; +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_drm.h b/gst-libs/gst/vaapi/gstvaapidisplay_drm.h new file mode 100644 index 0000000..fad0d53 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_drm.h @@ -0,0 +1,97 @@ +/* + * gstvaapidisplay_drm.h - VA/DRM display abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_DRM_H +#define GST_VAAPI_DISPLAY_DRM_H + +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DISPLAY_DRM \ + (gst_vaapi_display_drm_get_type()) + +#define GST_VAAPI_DISPLAY_DRM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DISPLAY_DRM, \ + GstVaapiDisplayDRM)) + +#define GST_VAAPI_DISPLAY_DRM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DISPLAY_DRM, \ + GstVaapiDisplayDRMClass)) + +#define GST_VAAPI_IS_DISPLAY_DRM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DISPLAY_DRM)) + +#define GST_VAAPI_IS_DISPLAY_DRM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DISPLAY_DRM)) + +#define GST_VAAPI_DISPLAY_DRM_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DISPLAY_DRM, \ + GstVaapiDisplayDRMClass)) + +typedef struct _GstVaapiDisplayDRM GstVaapiDisplayDRM; +typedef struct _GstVaapiDisplayDRMPrivate GstVaapiDisplayDRMPrivate; +typedef struct _GstVaapiDisplayDRMClass GstVaapiDisplayDRMClass; + +/** + * GstVaapiDisplayDRM: + * + * VA/DRM display wrapper. + */ +struct _GstVaapiDisplayDRM { + /*< private >*/ + GstVaapiDisplay parent_instance; + + GstVaapiDisplayDRMPrivate *priv; +}; + + +/** + * GstVaapiDisplayDRMClass: + * + * VA/DRM display wrapper clas. + */ +struct _GstVaapiDisplayDRMClass { + /*< private >*/ + GstVaapiDisplayClass parent_class; +}; + +GType +gst_vaapi_display_drm_get_type(void) G_GNUC_CONST; + +GstVaapiDisplay * +gst_vaapi_display_drm_new(const gchar *device_path); + +GstVaapiDisplay * +gst_vaapi_display_drm_new_with_device(gint device); + +gint +gst_vaapi_display_drm_get_device(GstVaapiDisplayDRM *display); + +const gchar * +gst_vaapi_display_drm_get_device_path(GstVaapiDisplayDRM *display); + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_DRM_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h new file mode 100644 index 0000000..f6211a7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h @@ -0,0 +1,55 @@ +/* + * gstvaapidisplay_drm_priv.h - Internal VA/DRM interface + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_DRM_PRIV_H +#define GST_VAAPI_DISPLAY_DRM_PRIV_H + +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_DISPLAY_DRM_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DISPLAY_DRM, \ + GstVaapiDisplayDRMPrivate)) + +#define GST_VAAPI_DISPLAY_DRM_CAST(display) ((GstVaapiDisplayDRM *)(display)) + +/** + * GST_VAAPI_DISPLAY_DRM_DEVICE: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to the underlying DRM file descriptor of @display + */ +#undef GST_VAAPI_DISPLAY_DRM_DEVICE +#define GST_VAAPI_DISPLAY_DRM_DEVICE(display) \ + GST_VAAPI_DISPLAY_DRM_CAST(display)->priv->drm_device + +struct _GstVaapiDisplayDRMPrivate { + gchar *device_path_default; + gchar *device_path; + gint drm_device; + guint create_display : 1; +}; + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_DRM_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_glx.c b/gst-libs/gst/vaapi/gstvaapidisplay_glx.c new file mode 100644 index 0000000..87ac84a --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_glx.c @@ -0,0 +1,116 @@ +/* + * gstvaapidisplay_glx.c - VA/GLX display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidisplay_glx + * @short_description: VA/GLX display abstraction + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapiutils_glx.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapidisplay_x11_priv.h" +#include "gstvaapidisplay_glx.h" +#include "gstvaapidisplay_glx_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDisplayGLX, + gst_vaapi_display_glx, + GST_VAAPI_TYPE_DISPLAY_X11); + +static void +gst_vaapi_display_glx_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_display_glx_parent_class)->finalize(object); +} + +static gboolean +gst_vaapi_display_glx_get_display_info( + GstVaapiDisplay *display, + GstVaapiDisplayInfo *info +) +{ + GstVaapiDisplayClass * const dpy_class = + GST_VAAPI_DISPLAY_CLASS(gst_vaapi_display_glx_parent_class); + + info->va_display = vaGetDisplayGLX(GST_VAAPI_DISPLAY_XDISPLAY(display)); + if (!info->va_display) + return FALSE; + info->display_type = GST_VAAPI_DISPLAY_TYPE_GLX; + return dpy_class->get_display(display, info); +} + +static void +gst_vaapi_display_glx_class_init(GstVaapiDisplayGLXClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass); + + object_class->finalize = gst_vaapi_display_glx_finalize; + dpy_class->get_display = gst_vaapi_display_glx_get_display_info; +} + +static void +gst_vaapi_display_glx_init(GstVaapiDisplayGLX *display) +{ +} + +/** + * gst_vaapi_display_glx_new: + * @display_name: the X11 display name + * + * Opens an X11 #Display using @display_name and returns a newly + * allocated #GstVaapiDisplay object. The X11 display will be cloed + * when the reference count of the object reaches zero. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_glx_new(const gchar *display_name) +{ + return g_object_new(GST_VAAPI_TYPE_DISPLAY_GLX, + "display-name", display_name, + NULL); +} + +/** + * gst_vaapi_display_glx_new_with_display: + * @x11_display: an X11 #Display + * + * Creates a #GstVaapiDisplay based on the X11 @x11_display + * display. The caller still owns the display and must call + * XCloseDisplay() when all #GstVaapiDisplay references are + * released. Doing so too early can yield undefined behaviour. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_glx_new_with_display(Display *x11_display) +{ + return g_object_new(GST_VAAPI_TYPE_DISPLAY_GLX, + "x11-display", x11_display, + NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_glx.h b/gst-libs/gst/vaapi/gstvaapidisplay_glx.h new file mode 100644 index 0000000..6f115e5 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_glx.h @@ -0,0 +1,90 @@ +/* + * gstvaapidisplay_glx.h - VA/GLX display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_GLX_H +#define GST_VAAPI_DISPLAY_GLX_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DISPLAY_GLX \ + (gst_vaapi_display_glx_get_type()) + +#define GST_VAAPI_DISPLAY_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DISPLAY_GLX, \ + GstVaapiDisplayGLX)) + +#define GST_VAAPI_DISPLAY_GLX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DISPLAY_GLX, \ + GstVaapiDisplayGLXClass)) + +#define GST_VAAPI_IS_DISPLAY_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DISPLAY_GLX)) + +#define GST_VAAPI_IS_DISPLAY_GLX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DISPLAY_GLX)) + +#define GST_VAAPI_DISPLAY_GLX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DISPLAY_GLX, \ + GstVaapiDisplayGLXClass)) + +typedef struct _GstVaapiDisplayGLX GstVaapiDisplayGLX; +typedef struct _GstVaapiDisplayGLXClass GstVaapiDisplayGLXClass; + +/** + * GstVaapiDisplayGLX: + * + * VA/GLX display wrapper. + */ +struct _GstVaapiDisplayGLX { + /*< private >*/ + GstVaapiDisplayX11 parent_instance; +}; + + +/** + * GstVaapiDisplayGLXClass: + * + * VA/GLX display wrapper clas. + */ +struct _GstVaapiDisplayGLXClass { + /*< private >*/ + GstVaapiDisplayX11Class parent_class; +}; + +GType +gst_vaapi_display_glx_get_type(void) G_GNUC_CONST; + +GstVaapiDisplay * +gst_vaapi_display_glx_new(const gchar *display_name); + +GstVaapiDisplay * +gst_vaapi_display_glx_new_with_display(Display *x11_display); + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_GLX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h new file mode 100644 index 0000000..a843b38 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h @@ -0,0 +1,34 @@ +/* + * gstvaapidisplay_glx_priv.h - Internal VA/GLX interface + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_GLX_PRIV_H +#define GST_VAAPI_DISPLAY_GLX_PRIV_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_DISPLAY_GLX_CAST(display) ((GstVaapiDisplayGLX *)(display)) + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_GLX_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_priv.h new file mode 100644 index 0000000..ac0555e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_priv.h @@ -0,0 +1,98 @@ +/* + * gstvaapidisplay_priv.h - Base VA display (private definitions) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_PRIV_H +#define GST_VAAPI_DISPLAY_PRIV_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_DISPLAY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DISPLAY, \ + GstVaapiDisplayPrivate)) + +#define GST_VAAPI_DISPLAY_CAST(display) ((GstVaapiDisplay *)(display)) + +/** + * GST_VAAPI_DISPLAY_VADISPLAY: + * @display_: a #GstVaapiDisplay + * + * Macro that evaluates to the #VADisplay of @display. + * This is an internal macro that does not do any run-time type check. + */ +#undef GST_VAAPI_DISPLAY_VADISPLAY +#define GST_VAAPI_DISPLAY_VADISPLAY(display_) \ + GST_VAAPI_DISPLAY_CAST(display_)->priv->display + +/** + * GST_VAAPI_DISPLAY_LOCK: + * @display: a #GstVaapiDisplay + * + * Locks @display + */ +#undef GST_VAAPI_DISPLAY_LOCK +#define GST_VAAPI_DISPLAY_LOCK(display) \ + gst_vaapi_display_lock(GST_VAAPI_DISPLAY_CAST(display)) + +/** + * GST_VAAPI_DISPLAY_UNLOCK: + * @display: a #GstVaapiDisplay + * + * Unlocks @display + */ +#undef GST_VAAPI_DISPLAY_UNLOCK +#define GST_VAAPI_DISPLAY_UNLOCK(display) \ + gst_vaapi_display_unlock(GST_VAAPI_DISPLAY_CAST(display)) + +/** + * GstVaapiDisplayPrivate: + * + * Base class for VA displays. + */ +struct _GstVaapiDisplayPrivate { + GstVaapiDisplay *parent; + GStaticRecMutex mutex; + GstVaapiDisplayType display_type; + VADisplay display; + guint width; + guint height; + guint width_mm; + guint height_mm; + guint par_n; + guint par_d; + GArray *decoders; + GArray *encoders; + GArray *image_formats; + GArray *subpicture_formats; + GArray *properties; + guint create_display : 1; +}; + +GstVaapiDisplayCache * +gst_vaapi_display_get_cache(void); + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_wayland.c b/gst-libs/gst/vaapi/gstvaapidisplay_wayland.c new file mode 100644 index 0000000..6ebf9da --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_wayland.c @@ -0,0 +1,538 @@ +/* + * gstvaapidisplay_wayland.c - VA/Wayland display abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidisplay_wayland + * @short_description: VA/Wayland display abstraction + */ + +#include "sysdeps.h" +#include +#include "gstvaapidisplay_priv.h" +#include "gstvaapidisplay_wayland.h" +#include "gstvaapidisplay_wayland_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDisplayWayland, + gst_vaapi_display_wayland, + GST_VAAPI_TYPE_DISPLAY); + +enum { + PROP_0, + + PROP_DISPLAY_NAME, + PROP_WL_DISPLAY +}; + +#define NAME_PREFIX "WLD:" +#define NAME_PREFIX_LENGTH 4 + +static inline gboolean +is_display_name(const gchar *display_name) +{ + return strncmp(display_name, NAME_PREFIX, NAME_PREFIX_LENGTH) == 0; +} + +static inline const gchar * +get_default_display_name(void) +{ + static const gchar *g_display_name; + + if (!g_display_name) + g_display_name = getenv("WAYLAND_DISPLAY"); + return g_display_name; +} + +static inline guint +get_display_name_length(const gchar *display_name) +{ + const gchar *str; + + str = strchr(display_name, '-'); + if (str) + return str - display_name; + return strlen(display_name); +} + +static gboolean +compare_display_name(gconstpointer a, gconstpointer b, gpointer user_data) +{ + const gchar *cached_name = a; + const gchar *tested_name = b; + guint cached_name_length, tested_name_length; + + if (!cached_name || !is_display_name(cached_name)) + return FALSE; + cached_name += NAME_PREFIX_LENGTH; + cached_name_length = get_display_name_length(cached_name); + + g_return_val_if_fail(tested_name && is_display_name(tested_name), FALSE); + tested_name += NAME_PREFIX_LENGTH; + tested_name_length = get_display_name_length(tested_name); + + /* XXX: handle screen number and default WAYLAND_DISPLAY name */ + if (cached_name_length != tested_name_length) + return FALSE; + if (strncmp(cached_name, tested_name, cached_name_length) != 0) + return FALSE; + return TRUE; +} + +static void +gst_vaapi_display_wayland_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_display_wayland_parent_class)->finalize(object); +} + +/* Reconstruct a display name without our prefix */ +static const gchar * +get_display_name(gpointer ptr) +{ + GstVaapiDisplayWayland * const display = GST_VAAPI_DISPLAY_WAYLAND(ptr); + const gchar *display_name = display->priv->display_name; + + if (!display_name) + return NULL; + + if (is_display_name(display_name)) { + display_name += NAME_PREFIX_LENGTH; + if (*display_name == '\0') + return NULL; + return display_name; + } + + /* XXX: this should not happen */ + g_assert(0 && "display name without prefix"); + return display_name; +} + +/* Mangle display name with our prefix */ +static void +set_display_name(GstVaapiDisplayWayland *display, const gchar *display_name) +{ + GstVaapiDisplayWaylandPrivate * const priv = display->priv; + + g_free(priv->display_name); + + if (!display_name) { + display_name = get_default_display_name(); + if (!display_name) + display_name = ""; + } + priv->display_name = g_strdup_printf("%s%s", NAME_PREFIX, display_name); +} + +static void +gst_vaapi_display_wayland_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDisplayWayland * const display = GST_VAAPI_DISPLAY_WAYLAND(object); + + switch (prop_id) { + case PROP_DISPLAY_NAME: + set_display_name(display, g_value_get_string(value)); + break; + case PROP_WL_DISPLAY: + display->priv->wl_display = g_value_get_pointer(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} +static void +gst_vaapi_display_wayland_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDisplayWayland * const display = GST_VAAPI_DISPLAY_WAYLAND(object); + + switch (prop_id) { + case PROP_DISPLAY_NAME: + g_value_set_string(value, get_display_name(display)); + break; + case PROP_WL_DISPLAY: + g_value_set_pointer(value, gst_vaapi_display_wayland_get_display(display)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_display_wayland_constructed(GObject *object) +{ + GstVaapiDisplayWayland * const display = GST_VAAPI_DISPLAY_WAYLAND(object); + GstVaapiDisplayWaylandPrivate * const priv = display->priv; + GstVaapiDisplayCache * const cache = gst_vaapi_display_get_cache(); + const GstVaapiDisplayInfo *info; + GObjectClass *parent_class; + + priv->create_display = priv->wl_display == NULL; + + /* Don't create Wayland display if there is one in the cache already */ + if (priv->create_display) { + info = gst_vaapi_display_cache_lookup_by_name( + cache, + priv->display_name, + compare_display_name, NULL + ); + if (info) { + priv->wl_display = info->native_display; + priv->create_display = FALSE; + } + } + + /* Reset display-name if the user provided his own Wayland display */ + if (!priv->create_display) { + /* XXX: how to get socket/display name? */ + GST_WARNING("wayland: get display name"); + set_display_name(display, NULL); + } + + parent_class = G_OBJECT_CLASS(gst_vaapi_display_wayland_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static void +output_handle_geometry(void *data, struct wl_output *output, + int x, int y, int physical_width, int physical_height, + int subpixel, const char *make, const char *model, + int transform) +{ + GstVaapiDisplayWaylandPrivate * const priv = data; + + priv->phys_width = physical_width; + priv->phys_height = physical_height; +} + +static void +output_handle_mode(void *data, struct wl_output *wl_output, + uint32_t flags, int width, int height, int refresh) +{ + GstVaapiDisplayWaylandPrivate * const priv = data; + + if (flags & WL_OUTPUT_MODE_CURRENT) { + priv->width = width; + priv->height = height; + } +} + +static const struct wl_output_listener output_listener = { + output_handle_geometry, + output_handle_mode, +}; + +static void +display_handle_global( + struct wl_display *display, + uint32_t id, + const char *interface, + uint32_t version, + void *data +) +{ + GstVaapiDisplayWaylandPrivate * const priv = data; + + if (strcmp(interface, "wl_compositor") == 0) + priv->compositor = wl_display_bind(display, id, &wl_compositor_interface); + else if (strcmp(interface, "wl_shell") == 0) + priv->shell = wl_display_bind(display, id, &wl_shell_interface); + else if (strcmp(interface, "wl_output") == 0) { + priv->output = wl_display_bind(display, id, &wl_output_interface); + wl_output_add_listener(priv->output, &output_listener, priv); + } +} + +static int +event_mask_update(uint32_t mask, void *data) +{ + GstVaapiDisplayWaylandPrivate * const priv = data; + + priv->event_mask = mask; + return 0; +} + +static gboolean +gst_vaapi_display_wayland_open_display(GstVaapiDisplay * display) +{ + GstVaapiDisplayWaylandPrivate * const priv = + GST_VAAPI_DISPLAY_WAYLAND(display)->priv; + + if (!priv->create_display) + return priv->wl_display != NULL; + + priv->wl_display = wl_display_connect(get_display_name(display)); + if (!priv->wl_display) + return FALSE; + + wl_display_set_user_data(priv->wl_display, priv); + wl_display_add_global_listener(priv->wl_display, display_handle_global, priv); + priv->event_fd = wl_display_get_fd(priv->wl_display, event_mask_update, priv); + wl_display_iterate(priv->wl_display, priv->event_mask); + wl_display_roundtrip(priv->wl_display); + + if (!priv->compositor) { + GST_ERROR("failed to bind compositor interface"); + return FALSE; + } + + if (!priv->shell) { + GST_ERROR("failed to bind shell interface"); + return FALSE; + } + return TRUE; +} + +static void +gst_vaapi_display_wayland_close_display(GstVaapiDisplay * display) +{ + GstVaapiDisplayWaylandPrivate * const priv = + GST_VAAPI_DISPLAY_WAYLAND(display)->priv; + + if (priv->compositor) { + wl_compositor_destroy(priv->compositor); + priv->compositor = NULL; + } + + if (priv->wl_display) { + if (priv->create_display) + wl_display_disconnect(priv->wl_display); + priv->wl_display = NULL; + } + + if (priv->display_name) { + g_free(priv->display_name); + priv->display_name = NULL; + } +} + +static gboolean +gst_vaapi_display_wayland_get_display_info( + GstVaapiDisplay *display, + GstVaapiDisplayInfo *info +) +{ + GstVaapiDisplayWaylandPrivate * const priv = + GST_VAAPI_DISPLAY_WAYLAND(display)->priv; + GstVaapiDisplayCache *cache; + const GstVaapiDisplayInfo *cached_info; + + /* Return any cached info even if child has its own VA display */ + cache = gst_vaapi_display_get_cache(); + if (!cache) + return FALSE; + cached_info = + gst_vaapi_display_cache_lookup_by_native_display(cache, priv->wl_display); + if (cached_info) { + *info = *cached_info; + return TRUE; + } + + /* Otherwise, create VA display if there is none already */ + info->native_display = priv->wl_display; + info->display_name = priv->display_name; + if (!info->va_display) { + info->va_display = vaGetDisplayWl(priv->wl_display); + if (!info->va_display) + return FALSE; + info->display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND; + } + return TRUE; +} + +static void +gst_vaapi_display_wayland_get_size( + GstVaapiDisplay *display, + guint *pwidth, + guint *pheight +) +{ + GstVaapiDisplayWaylandPrivate * const priv = + GST_VAAPI_DISPLAY_WAYLAND(display)->priv; + + if (!priv->output) + return; + + if (pwidth) + *pwidth = priv->width; + + if (pheight) + *pheight = priv->height; +} + +static void +gst_vaapi_display_wayland_get_size_mm( + GstVaapiDisplay *display, + guint *pwidth, + guint *pheight +) +{ + GstVaapiDisplayWaylandPrivate * const priv = + GST_VAAPI_DISPLAY_WAYLAND(display)->priv; + + if (!priv->output) + return; + + if (pwidth) + *pwidth = priv->phys_width; + + if (pheight) + *pheight = priv->phys_height; +} + +static void +gst_vaapi_display_wayland_class_init(GstVaapiDisplayWaylandClass * klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiDisplayWaylandPrivate)); + + object_class->finalize = gst_vaapi_display_wayland_finalize; + object_class->set_property = gst_vaapi_display_wayland_set_property; + object_class->get_property = gst_vaapi_display_wayland_get_property; + object_class->constructed = gst_vaapi_display_wayland_constructed; + + dpy_class->open_display = gst_vaapi_display_wayland_open_display; + dpy_class->close_display = gst_vaapi_display_wayland_close_display; + dpy_class->get_display = gst_vaapi_display_wayland_get_display_info; + dpy_class->get_size = gst_vaapi_display_wayland_get_size; + dpy_class->get_size_mm = gst_vaapi_display_wayland_get_size_mm; + + /** + * GstVaapiDisplayWayland:wayland-display: + * + * The Wayland #wl_display that was created by + * gst_vaapi_display_wayland_new() or that was bound from + * gst_vaapi_display_wayland_new_with_display(). + */ + g_object_class_install_property + (object_class, + PROP_WL_DISPLAY, + g_param_spec_pointer("wl-display", + "Wayland display", + "Wayland display", + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + /** + * GstVaapiDisplayWayland:display-name: + * + * The Wayland display name. + */ + g_object_class_install_property + (object_class, + PROP_DISPLAY_NAME, + g_param_spec_string("display-name", + "Wayland display name", + "Wayland display name", + NULL, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gst_vaapi_display_wayland_init(GstVaapiDisplayWayland *display) +{ + GstVaapiDisplayWaylandPrivate * const priv = + GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE(display); + + display->priv = priv; + priv->create_display = TRUE; + priv->display_name = NULL; + priv->wl_display = NULL; + priv->compositor = NULL; + priv->shell = NULL; + priv->output = NULL; + priv->width = 0; + priv->height = 0; + priv->phys_width = 0; + priv->phys_height = 0; + priv->event_fd = -1; + priv->event_mask = 0; +} + +/** + * gst_vaapi_display_wayland_new: + * @display_name: the Wayland display name + * + * Opens an Wayland #wl_display using @display_name and returns a + * newly allocated #GstVaapiDisplay object. The Wayland display will + * be cloed when the reference count of the object reaches zero. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_wayland_new(const gchar *display_name) +{ + return g_object_new(GST_VAAPI_TYPE_DISPLAY_WAYLAND, + "display-name", display_name, + NULL); +} + +/** + * gst_vaapi_display_wayland_new_with_display: + * @wl_display: an Wayland #wl_display + * + * Creates a #GstVaapiDisplay based on the Wayland @wl_display + * display. The caller still owns the display and must call + * wl_display_disconnect() when all #GstVaapiDisplay references are + * released. Doing so too early can yield undefined behaviour. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_wayland_new_with_display(struct wl_display *wl_display) +{ + g_return_val_if_fail(wl_display, NULL); + + return g_object_new(GST_VAAPI_TYPE_DISPLAY_WAYLAND, + "wl-display", wl_display, + NULL); +} + +/** + * gst_vaapi_display_wayland_get_display: + * @display: a #GstVaapiDisplayWayland + * + * Returns the underlying Wayland #wl_display that was created by + * gst_vaapi_display_wayland_new() or that was bound from + * gst_vaapi_display_wayland_new_with_display(). + * + * Return value: the Wayland #wl_display attached to @display + */ +struct wl_display * +gst_vaapi_display_wayland_get_display(GstVaapiDisplayWayland *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_WAYLAND(display), NULL); + + return display->priv->wl_display; +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_wayland.h b/gst-libs/gst/vaapi/gstvaapidisplay_wayland.h new file mode 100644 index 0000000..c5fc0f6 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_wayland.h @@ -0,0 +1,94 @@ +/* + * gstvaapidisplay_wayland.h - VA/Wayland display abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_WAYLAND_H +#define GST_VAAPI_DISPLAY_WAYLAND_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DISPLAY_WAYLAND \ + (gst_vaapi_display_wayland_get_type()) + +#define GST_VAAPI_DISPLAY_WAYLAND(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DISPLAY_WAYLAND, \ + GstVaapiDisplayWayland)) + +#define GST_VAAPI_DISPLAY_WAYLAND_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DISPLAY_WAYLAND, \ + GstVaapiDisplayWaylandClass)) + +#define GST_VAAPI_IS_DISPLAY_WAYLAND(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DISPLAY_WAYLAND)) + +#define GST_VAAPI_IS_DISPLAY_WAYLAND_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DISPLAY_WAYLAND)) + +#define GST_VAAPI_DISPLAY_WAYLAND_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DISPLAY_WAYLAND, \ + GstVaapiDisplayWaylandClass)) + +typedef struct _GstVaapiDisplayWayland GstVaapiDisplayWayland; +typedef struct _GstVaapiDisplayWaylandPrivate GstVaapiDisplayWaylandPrivate; +typedef struct _GstVaapiDisplayWaylandClass GstVaapiDisplayWaylandClass; + +/** + * GstVaapiDisplayWayland: + * + * VA/Wayland display wrapper. + */ +struct _GstVaapiDisplayWayland { + /*< private >*/ + GstVaapiDisplay parent_instance; + + GstVaapiDisplayWaylandPrivate *priv; +}; + +/** + * GstVaapiDisplayWaylandClass: + * + * VA/Wayland display wrapper clas. + */ +struct _GstVaapiDisplayWaylandClass { + /*< private >*/ + GstVaapiDisplayClass parent_class; +}; + +GType +gst_vaapi_display_wayland_get_type(void) G_GNUC_CONST; + +GstVaapiDisplay * +gst_vaapi_display_wayland_new(const gchar *display_name); + +GstVaapiDisplay * +gst_vaapi_display_wayland_new_with_display(struct wl_display *wl_display); + +struct wl_display * +gst_vaapi_display_wayland_get_display(GstVaapiDisplayWayland *display); + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_WAYLAND_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h new file mode 100644 index 0000000..b98303e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h @@ -0,0 +1,65 @@ +/* + * gstvaapidisplay_wayland_priv.h - Internal VA/Wayland interface + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_WAYLAND_PRIV_H +#define GST_VAAPI_DISPLAY_WAYLAND_PRIV_H + +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DISPLAY_WAYLAND, \ + GstVaapiDisplayWaylandPrivate)) + +#define GST_VAAPI_DISPLAY_WAYLAND_CAST(display) \ + ((GstVaapiDisplayWayland *)(display)) + +/** + * GST_VAAPI_DISPLAY_WL_DISPLAY: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to the underlying Wayland #wl_display object + * of @display + */ +#undef GST_VAAPI_DISPLAY_WL_DISPLAY +#define GST_VAAPI_DISPLAY_WL_DISPLAY(display) \ + GST_VAAPI_DISPLAY_WAYLAND_CAST(display)->priv->wl_display + +struct _GstVaapiDisplayWaylandPrivate { + gchar *display_name; + struct wl_display *wl_display; + struct wl_compositor *compositor; + struct wl_shell *shell; + struct wl_output *output; + guint width; + guint height; + guint phys_width; + guint phys_height; + gint event_fd; + guint32 event_mask; + guint create_display : 1; +}; + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_WAYLAND_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_x11.c b/gst-libs/gst/vaapi/gstvaapidisplay_x11.c new file mode 100644 index 0000000..f00b5af --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_x11.c @@ -0,0 +1,605 @@ +/* + * gstvaapidisplay_x11.c - VA/X11 display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidisplay_x11 + * @short_description: VA/X11 display abstraction + */ + +#include "sysdeps.h" +#include +#include "gstvaapiutils.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapidisplay_x11.h" +#include "gstvaapidisplay_x11_priv.h" + +#ifdef HAVE_XRANDR +# include +#endif + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDisplayX11, + gst_vaapi_display_x11, + GST_VAAPI_TYPE_DISPLAY); + +enum { + PROP_0, + + PROP_SYNCHRONOUS, + PROP_DISPLAY_NAME, + PROP_X11_DISPLAY, + PROP_X11_SCREEN +}; + +#define NAME_PREFIX "X11:" +#define NAME_PREFIX_LENGTH 4 + +static inline gboolean +is_display_name(const gchar *display_name) +{ + return strncmp(display_name, NAME_PREFIX, NAME_PREFIX_LENGTH) == 0; +} + +static inline const gchar * +get_default_display_name(void) +{ + static const gchar *g_display_name; + + if (!g_display_name) + g_display_name = getenv("DISPLAY"); + return g_display_name; +} + +static gboolean +compare_display_name(gconstpointer a, gconstpointer b, gpointer user_data) +{ + const gchar *cached_name = a, *cached_name_end; + const gchar *tested_name = b, *tested_name_end; + guint cached_name_length, tested_name_length; + + if (!cached_name || !is_display_name(cached_name)) + return FALSE; + g_return_val_if_fail(tested_name && is_display_name(tested_name), FALSE); + + cached_name += NAME_PREFIX_LENGTH; + cached_name_end = strchr(cached_name, ':'); + if (cached_name_end) + cached_name_length = cached_name_end - cached_name; + else + cached_name_length = strlen(cached_name); + + tested_name += NAME_PREFIX_LENGTH; + tested_name_end = strchr(tested_name, ':'); + if (tested_name_end) + tested_name_length = tested_name_end - tested_name; + else + tested_name_length = strlen(tested_name); + + if (cached_name_length != tested_name_length) + return FALSE; + if (strncmp(cached_name, tested_name, cached_name_length) != 0) + return FALSE; + + /* XXX: handle screen number? */ + return TRUE; +} + +static void +gst_vaapi_display_x11_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_display_x11_parent_class)->finalize(object); +} + +/* Reconstruct a display name without our prefix */ +static const gchar * +get_display_name(gpointer ptr) +{ + GstVaapiDisplayX11 * const display = GST_VAAPI_DISPLAY_X11(ptr); + const gchar *display_name = display->priv->display_name; + + if (!display_name) + return NULL; + + if (is_display_name(display_name)) { + display_name += NAME_PREFIX_LENGTH; + if (*display_name == '\0') + return NULL; + return display_name; + } + + /* XXX: this should not happen */ + g_assert(0 && "display name without prefix"); + return display_name; +} + +/* Mangle display name with our prefix */ +static void +set_display_name(GstVaapiDisplayX11 *display, const gchar *display_name) +{ + GstVaapiDisplayX11Private * const priv = display->priv; + + g_free(priv->display_name); + + if (!display_name) { + display_name = get_default_display_name(); + if (!display_name) + display_name = ""; + } + priv->display_name = g_strdup_printf("%s%s", NAME_PREFIX, display_name); +} + +static void +set_synchronous(GstVaapiDisplayX11 *display, gboolean synchronous) +{ + GstVaapiDisplayX11Private * const priv = display->priv; + + if (priv->synchronous != synchronous) { + priv->synchronous = synchronous; + if (priv->x11_display) + XSynchronize(priv->x11_display, synchronous); + } +} + +static void +gst_vaapi_display_x11_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDisplayX11 * const display = GST_VAAPI_DISPLAY_X11(object); + + switch (prop_id) { + case PROP_SYNCHRONOUS: + set_synchronous(display, g_value_get_boolean(value)); + break; + case PROP_DISPLAY_NAME: + set_display_name(display, g_value_get_string(value)); + break; + case PROP_X11_DISPLAY: + display->priv->x11_display = g_value_get_pointer(value); + break; + case PROP_X11_SCREEN: + display->priv->x11_screen = g_value_get_int(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_display_x11_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDisplayX11 * const display = GST_VAAPI_DISPLAY_X11(object); + + switch (prop_id) { + case PROP_SYNCHRONOUS: + g_value_set_boolean(value, display->priv->synchronous); + break; + case PROP_DISPLAY_NAME: + g_value_set_string(value, get_display_name(display)); + break; + case PROP_X11_DISPLAY: + g_value_set_pointer(value, gst_vaapi_display_x11_get_display(display)); + break; + case PROP_X11_SCREEN: + g_value_set_int(value, gst_vaapi_display_x11_get_screen(display)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_display_x11_constructed(GObject *object) +{ + GstVaapiDisplayX11 * const display = GST_VAAPI_DISPLAY_X11(object); + GstVaapiDisplayX11Private * const priv = display->priv; + GstVaapiDisplayCache * const cache = gst_vaapi_display_get_cache(); + const GstVaapiDisplayInfo *info; + GObjectClass *parent_class; + + priv->create_display = priv->x11_display == NULL; + + /* Don't create X11 display if there is one in the cache already */ + if (priv->create_display) { + info = gst_vaapi_display_cache_lookup_by_name( + cache, + priv->display_name, + compare_display_name, NULL + ); + if (info) { + priv->x11_display = info->native_display; + priv->create_display = FALSE; + } + } + + /* Reset display-name if the user provided his own X11 display */ + if (!priv->create_display) + set_display_name(display, XDisplayString(priv->x11_display)); + + parent_class = G_OBJECT_CLASS(gst_vaapi_display_x11_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static gboolean +gst_vaapi_display_x11_open_display(GstVaapiDisplay *display) +{ + GstVaapiDisplayX11Private * const priv = + GST_VAAPI_DISPLAY_X11(display)->priv; + + if (priv->create_display) { + priv->x11_display = XOpenDisplay(get_display_name(display)); + if (!priv->x11_display) + return FALSE; + priv->x11_screen = DefaultScreen(priv->x11_display); + } + if (!priv->x11_display) + return FALSE; + + if (priv->synchronous) + XSynchronize(priv->x11_display, True); + +#ifdef HAVE_XRANDR + { + int evt_base, err_base; + priv->use_xrandr = XRRQueryExtension( + priv->x11_display, &evt_base, &err_base); + } +#endif + return TRUE; +} + +static void +gst_vaapi_display_x11_close_display(GstVaapiDisplay *display) +{ + GstVaapiDisplayX11Private * const priv = + GST_VAAPI_DISPLAY_X11(display)->priv; + + if (priv->x11_display) { + if (priv->create_display) + XCloseDisplay(priv->x11_display); + priv->x11_display = NULL; + } + + if (priv->display_name) { + g_free(priv->display_name); + priv->display_name = NULL; + } +} + +static void +gst_vaapi_display_x11_sync(GstVaapiDisplay *display) +{ + GstVaapiDisplayX11Private * const priv = + GST_VAAPI_DISPLAY_X11(display)->priv; + + if (priv->x11_display) { + GST_VAAPI_DISPLAY_LOCK(display); + XSync(priv->x11_display, False); + GST_VAAPI_DISPLAY_UNLOCK(display); + } +} + +static void +gst_vaapi_display_x11_flush(GstVaapiDisplay *display) +{ + GstVaapiDisplayX11Private * const priv = + GST_VAAPI_DISPLAY_X11(display)->priv; + + if (priv->x11_display) { + GST_VAAPI_DISPLAY_LOCK(display); + XFlush(priv->x11_display); + GST_VAAPI_DISPLAY_UNLOCK(display); + } +} + +static gboolean +gst_vaapi_display_x11_get_display_info( + GstVaapiDisplay *display, + GstVaapiDisplayInfo *info +) +{ + GstVaapiDisplayX11Private * const priv = + GST_VAAPI_DISPLAY_X11(display)->priv; + GstVaapiDisplayCache *cache; + const GstVaapiDisplayInfo *cached_info; + + /* Return any cached info even if child has its own VA display */ + cache = gst_vaapi_display_get_cache(); + if (!cache) + return FALSE; + cached_info = gst_vaapi_display_cache_lookup_by_native_display( + cache, priv->x11_display); + if (cached_info) { + *info = *cached_info; + return TRUE; + } + + /* Otherwise, create VA display if there is none already */ + info->native_display = priv->x11_display; + info->display_name = priv->display_name; + if (!info->va_display) { + info->va_display = vaGetDisplay(priv->x11_display); + if (!info->va_display) + return FALSE; + info->display_type = GST_VAAPI_DISPLAY_TYPE_X11; + } + return TRUE; +} + +static void +gst_vaapi_display_x11_get_size( + GstVaapiDisplay *display, + guint *pwidth, + guint *pheight +) +{ + GstVaapiDisplayX11Private * const priv = + GST_VAAPI_DISPLAY_X11(display)->priv; + + if (!priv->x11_display) + return; + + if (pwidth) + *pwidth = DisplayWidth(priv->x11_display, priv->x11_screen); + + if (pheight) + *pheight = DisplayHeight(priv->x11_display, priv->x11_screen); +} + +static void +gst_vaapi_display_x11_get_size_mm( + GstVaapiDisplay *display, + guint *pwidth, + guint *pheight +) +{ + GstVaapiDisplayX11Private * const priv = + GST_VAAPI_DISPLAY_X11(display)->priv; + guint width_mm, height_mm; + + if (!priv->x11_display) + return; + + width_mm = DisplayWidthMM(priv->x11_display, priv->x11_screen); + height_mm = DisplayHeightMM(priv->x11_display, priv->x11_screen); + +#ifdef HAVE_XRANDR + /* XXX: fix up physical size if the display is rotated */ + if (priv->use_xrandr) { + XRRScreenConfiguration *xrr_config = NULL; + XRRScreenSize *xrr_sizes; + Window win; + int num_xrr_sizes, size_id, screen; + Rotation rotation; + + do { + win = DefaultRootWindow(priv->x11_display); + screen = XRRRootToScreen(priv->x11_display, win); + + xrr_config = XRRGetScreenInfo(priv->x11_display, win); + if (!xrr_config) + break; + + size_id = XRRConfigCurrentConfiguration(xrr_config, &rotation); + if (rotation == RR_Rotate_0 || rotation == RR_Rotate_180) + break; + + xrr_sizes = XRRSizes(priv->x11_display, screen, &num_xrr_sizes); + if (!xrr_sizes || size_id >= num_xrr_sizes) + break; + + width_mm = xrr_sizes[size_id].mheight; + height_mm = xrr_sizes[size_id].mwidth; + } while (0); + if (xrr_config) + XRRFreeScreenConfigInfo(xrr_config); + } +#endif + + if (pwidth) + *pwidth = width_mm; + + if (pheight) + *pheight = height_mm; +} + +static void +gst_vaapi_display_x11_class_init(GstVaapiDisplayX11Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiDisplayX11Private)); + + object_class->finalize = gst_vaapi_display_x11_finalize; + object_class->set_property = gst_vaapi_display_x11_set_property; + object_class->get_property = gst_vaapi_display_x11_get_property; + object_class->constructed = gst_vaapi_display_x11_constructed; + + dpy_class->open_display = gst_vaapi_display_x11_open_display; + dpy_class->close_display = gst_vaapi_display_x11_close_display; + dpy_class->sync = gst_vaapi_display_x11_sync; + dpy_class->flush = gst_vaapi_display_x11_flush; + dpy_class->get_display = gst_vaapi_display_x11_get_display_info; + dpy_class->get_size = gst_vaapi_display_x11_get_size; + dpy_class->get_size_mm = gst_vaapi_display_x11_get_size_mm; + + /** + * GstVaapiDisplayX11:synchronous: + * + * When enabled, runs the X display in synchronous mode. Note that + * this is used only for debugging. + */ + g_object_class_install_property + (object_class, + PROP_SYNCHRONOUS, + g_param_spec_boolean("synchronous", + "Synchronous mode", + "Toggles X display synchronous mode", + FALSE, + G_PARAM_READWRITE)); + + /** + * GstVaapiDisplayX11:x11-display: + * + * The X11 #Display that was created by gst_vaapi_display_x11_new() + * or that was bound from gst_vaapi_display_x11_new_with_display(). + */ + g_object_class_install_property + (object_class, + PROP_X11_DISPLAY, + g_param_spec_pointer("x11-display", + "X11 display", + "X11 display", + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + /** + * GstVaapiDisplayX11:x11-screen: + * + * The X11 screen that was created by gst_vaapi_display_x11_new() + * or that was bound from gst_vaapi_display_x11_new_with_display(). + */ + g_object_class_install_property + (object_class, + PROP_X11_SCREEN, + g_param_spec_int("x11-screen", + "X11 screen", + "X11 screen", + 0, G_MAXINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + /** + * GstVaapiDisplayX11:display-name: + * + * The X11 display name. + */ + g_object_class_install_property + (object_class, + PROP_DISPLAY_NAME, + g_param_spec_string("display-name", + "X11 display name", + "X11 display name", + NULL, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gst_vaapi_display_x11_init(GstVaapiDisplayX11 *display) +{ + GstVaapiDisplayX11Private *priv = GST_VAAPI_DISPLAY_X11_GET_PRIVATE(display); + + display->priv = priv; + priv->create_display = TRUE; + priv->x11_display = NULL; + priv->x11_screen = 0; + priv->display_name = NULL; + priv->use_xrandr = FALSE; +} + +/** + * gst_vaapi_display_x11_new: + * @display_name: the X11 display name + * + * Opens an X11 #Display using @display_name and returns a newly + * allocated #GstVaapiDisplay object. The X11 display will be cloed + * when the reference count of the object reaches zero. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_x11_new(const gchar *display_name) +{ + return g_object_new(GST_VAAPI_TYPE_DISPLAY_X11, + "display-name", display_name, + NULL); +} + +/** + * gst_vaapi_display_x11_new_with_display: + * @x11_display: an X11 #Display + * + * Creates a #GstVaapiDisplay based on the X11 @x11_display + * display. The caller still owns the display and must call + * XCloseDisplay() when all #GstVaapiDisplay references are + * released. Doing so too early can yield undefined behaviour. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_x11_new_with_display(Display *x11_display) +{ + g_return_val_if_fail(x11_display, NULL); + + return g_object_new(GST_VAAPI_TYPE_DISPLAY_X11, + "x11-display", x11_display, + "x11-screen", DefaultScreen(x11_display), + NULL); +} + +/** + * gst_vaapi_display_x11_get_display: + * @display: a #GstVaapiDisplayX11 + * + * Returns the underlying X11 #Display that was created by + * gst_vaapi_display_x11_new() or that was bound from + * gst_vaapi_display_x11_new_with_display(). + * + * Return value: the X11 #Display attached to @display + */ +Display * +gst_vaapi_display_x11_get_display(GstVaapiDisplayX11 *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), NULL); + + return display->priv->x11_display; +} + +/** + * gst_vaapi_display_x11_get_screen: + * @display: a #GstVaapiDisplayX11 + * + * Returns the default X11 screen that was created by + * gst_vaapi_display_x11_new() or that was bound from + * gst_vaapi_display_x11_new_with_display(). + * + * Return value: the X11 #Display attached to @display + */ +int +gst_vaapi_display_x11_get_screen(GstVaapiDisplayX11 *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), -1); + + return display->priv->x11_screen; +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_x11.h b/gst-libs/gst/vaapi/gstvaapidisplay_x11.h new file mode 100644 index 0000000..358f59f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_x11.h @@ -0,0 +1,98 @@ +/* + * gstvaapidisplay_x11.h - VA/X11 display abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_X11_H +#define GST_VAAPI_DISPLAY_X11_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DISPLAY_X11 \ + (gst_vaapi_display_x11_get_type()) + +#define GST_VAAPI_DISPLAY_X11(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DISPLAY_X11, \ + GstVaapiDisplayX11)) + +#define GST_VAAPI_DISPLAY_X11_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DISPLAY_X11, \ + GstVaapiDisplayX11Class)) + +#define GST_VAAPI_IS_DISPLAY_X11(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DISPLAY_X11)) + +#define GST_VAAPI_IS_DISPLAY_X11_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DISPLAY_X11)) + +#define GST_VAAPI_DISPLAY_X11_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DISPLAY_X11, \ + GstVaapiDisplayX11Class)) + +typedef struct _GstVaapiDisplayX11 GstVaapiDisplayX11; +typedef struct _GstVaapiDisplayX11Private GstVaapiDisplayX11Private; +typedef struct _GstVaapiDisplayX11Class GstVaapiDisplayX11Class; + +/** + * GstVaapiDisplayX11: + * + * VA/X11 display wrapper. + */ +struct _GstVaapiDisplayX11 { + /*< private >*/ + GstVaapiDisplay parent_instance; + + GstVaapiDisplayX11Private *priv; +}; + + +/** + * GstVaapiDisplayX11Class: + * + * VA/X11 display wrapper clas. + */ +struct _GstVaapiDisplayX11Class { + /*< private >*/ + GstVaapiDisplayClass parent_class; +}; + +GType +gst_vaapi_display_x11_get_type(void) G_GNUC_CONST; + +GstVaapiDisplay * +gst_vaapi_display_x11_new(const gchar *display_name); + +GstVaapiDisplay * +gst_vaapi_display_x11_new_with_display(Display *x11_display); + +Display * +gst_vaapi_display_x11_get_display(GstVaapiDisplayX11 *display); + +int +gst_vaapi_display_x11_get_screen(GstVaapiDisplayX11 *display); + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_X11_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h new file mode 100644 index 0000000..bc04ecb --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h @@ -0,0 +1,68 @@ +/* + * gstvaapidisplay_x11_priv.h - Internal VA/X11 interface + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_X11_PRIV_H +#define GST_VAAPI_DISPLAY_X11_PRIV_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_DISPLAY_X11_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DISPLAY_X11, \ + GstVaapiDisplayX11Private)) + +#define GST_VAAPI_DISPLAY_X11_CAST(display) ((GstVaapiDisplayX11 *)(display)) + +/** + * GST_VAAPI_DISPLAY_XDISPLAY: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to the underlying X11 #Display of @display + */ +#undef GST_VAAPI_DISPLAY_XDISPLAY +#define GST_VAAPI_DISPLAY_XDISPLAY(display) \ + GST_VAAPI_DISPLAY_X11_CAST(display)->priv->x11_display + +/** + * GST_VAAPI_DISPLAY_XSCREEN: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to the underlying X11 screen of @display + */ +#undef GST_VAAPI_DISPLAY_XSCREEN +#define GST_VAAPI_DISPLAY_XSCREEN(display) \ + GST_VAAPI_DISPLAY_X11_CAST(display)->priv->x11_screen + +struct _GstVaapiDisplayX11Private { + gchar *display_name; + Display *x11_display; + int x11_screen; + guint create_display : 1; + guint synchronous : 1; + guint use_xrandr : 1; +}; + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_X11_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplaycache.c b/gst-libs/gst/vaapi/gstvaapidisplaycache.c new file mode 100644 index 0000000..0e6ef36 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplaycache.c @@ -0,0 +1,380 @@ +/* + * gstvaapidisplaycache.c - VA display cache + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapidisplaycache.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +typedef struct _CacheEntry CacheEntry; +struct _CacheEntry { + GstVaapiDisplayInfo info; +}; + +struct _GstVaapiDisplayCache { + GStaticMutex mutex; + GList *list; +}; + +static void +cache_entry_free(CacheEntry *entry) +{ + GstVaapiDisplayInfo *info; + + if (!entry) + return; + + info = &entry->info; + + if (info->display_name) { + g_free(info->display_name); + info->display_name = NULL; + } + g_slice_free(CacheEntry, entry); +} + +static CacheEntry * +cache_entry_new(const GstVaapiDisplayInfo *di) +{ + GstVaapiDisplayInfo *info; + CacheEntry *entry; + + entry = g_slice_new(CacheEntry); + if (!entry) + return NULL; + + info = &entry->info; + info->display = di->display; + info->va_display = di->va_display; + info->native_display = di->native_display; + info->display_type = di->display_type; + info->display_name = NULL; + + if (di->display_name) { + info->display_name = g_strdup(di->display_name); + if (!info->display_name) + goto error; + } + return entry; + +error: + cache_entry_free(entry); + return NULL; +} + +#define CACHE_LOOKUP(cache, res, prop, comp_func, comp_data, user_data) do { \ + GList *l; \ + \ + g_static_mutex_lock(&(cache)->mutex); \ + for (l = (cache)->list; l != NULL; l = l->next) { \ + GstVaapiDisplayInfo * const info = \ + &((CacheEntry *)l->data)->info; \ + if (comp_func(info->prop, comp_data, user_data)) \ + break; \ + } \ + g_static_mutex_unlock(&(cache)->mutex); \ + res = l; \ + } while (0) + +#define compare_equal(a, b, user_data) \ + ((a) == (b)) + +#define compare_string(a, b, user_data) \ + ((a) == (b) || ((a) && (b) && strcmp(a, b) == 0)) + +static GList * +cache_lookup_display(GstVaapiDisplayCache *cache, GstVaapiDisplay *display) +{ + GList *m; + + CACHE_LOOKUP(cache, m, display, compare_equal, display, NULL); + return m; +} + +static GList * +cache_lookup_va_display(GstVaapiDisplayCache *cache, VADisplay va_display) +{ + GList *m; + + CACHE_LOOKUP(cache, m, va_display, compare_equal, va_display, NULL); + return m; +} + +static GList * +cache_lookup_native_display(GstVaapiDisplayCache *cache, gpointer native_display) +{ + GList *m; + + CACHE_LOOKUP(cache, m, native_display, compare_equal, native_display, NULL); + return m; +} + +/** + * gst_vaapi_display_cache_new: + * + * Creates a new VA display cache. + * + * Return value: the newly created #GstVaapiDisplayCache object + */ +GstVaapiDisplayCache * +gst_vaapi_display_cache_new(void) +{ + GstVaapiDisplayCache *cache; + + cache = g_slice_new0(GstVaapiDisplayCache); + if (!cache) + return NULL; + + g_static_mutex_init(&cache->mutex); + return cache; +} + +/** + * gst_vaapi_display_cache_new: + * @cache: the #GstVaapiDisplayCache to destroy + * + * Destroys a VA display cache. + */ +void +gst_vaapi_display_cache_free(GstVaapiDisplayCache *cache) +{ + GList *l; + + if (!cache) + return; + + if (cache->list) { + for (l = cache->list; l != NULL; l = l->next) + cache_entry_free(l->data); + g_list_free(cache->list); + cache->list = NULL; + } + g_static_mutex_free(&cache->mutex); + g_slice_free(GstVaapiDisplayCache, cache); +} + +/** + * gst_vaapi_display_cache_get_size: + * @cache: the #GstVaapiDisplayCache + * + * Gets the size of the display cache @cache. + * + * Return value: the size of the display cache + */ +guint +gst_vaapi_display_cache_get_size(GstVaapiDisplayCache *cache) +{ + guint size; + + g_return_val_if_fail(cache != NULL, 0); + + g_static_mutex_lock(&cache->mutex); + size = g_list_length(cache->list); + g_static_mutex_unlock(&cache->mutex); + return size; +} + +/** + * gst_vaapi_display_cache_add: + * @cache: the #GstVaapiDisplayCache + * @info: the display cache info to add + * + * Adds a new entry with data from @info. The display @info data is + * copied into the newly created cache entry. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_display_cache_add( + GstVaapiDisplayCache *cache, + GstVaapiDisplayInfo *info +) +{ + CacheEntry *entry; + + g_return_val_if_fail(cache != NULL, FALSE); + g_return_val_if_fail(info != NULL, FALSE); + + entry = cache_entry_new(info); + if (!entry) + return FALSE; + + g_static_mutex_lock(&cache->mutex); + cache->list = g_list_prepend(cache->list, entry); + g_static_mutex_unlock(&cache->mutex); + return TRUE; +} + +/** + * gst_vaapi_display_cache_remove: + * @cache: the #GstVaapiDisplayCache + * @display: the display to remove from cache + * + * Removes any cache entry that matches the specified #GstVaapiDisplay. + */ +void +gst_vaapi_display_cache_remove( + GstVaapiDisplayCache *cache, + GstVaapiDisplay *display +) +{ + GList *m; + + m = cache_lookup_display(cache, display); + if (!m) + return; + + cache_entry_free(m->data); + g_static_mutex_lock(&cache->mutex); + cache->list = g_list_delete_link(cache->list, m); + g_static_mutex_unlock(&cache->mutex); +} + +/** + * gst_vaapi_display_cache_lookup: + * @cache: the #GstVaapiDisplayCache + * @display: the display to find + * + * Looks up the display cache for the specified #GstVaapiDisplay. + * + * Return value: a #GstVaapiDisplayInfo matching @display, or %NULL if + * none was found + */ +const GstVaapiDisplayInfo * +gst_vaapi_display_cache_lookup( + GstVaapiDisplayCache *cache, + GstVaapiDisplay *display +) +{ + CacheEntry *entry; + GList *m; + + g_return_val_if_fail(cache != NULL, NULL); + g_return_val_if_fail(display != NULL, NULL); + + m = cache_lookup_display(cache, display); + if (!m) + return NULL; + + entry = m->data; + return &entry->info; +} + +/** + * gst_vaapi_display_cache_lookup_by_va_display: + * @cache: the #GstVaapiDisplayCache + * @va_display: the VA display to find + * + * Looks up the display cache for the specified VA display. + * + * Return value: a #GstVaapiDisplayInfo matching @va_display, or %NULL + * if none was found + */ +const GstVaapiDisplayInfo * +gst_vaapi_display_cache_lookup_by_va_display( + GstVaapiDisplayCache *cache, + VADisplay va_display +) +{ + CacheEntry *entry; + GList *m; + + g_return_val_if_fail(cache != NULL, NULL); + g_return_val_if_fail(va_display != NULL, NULL); + + m = cache_lookup_va_display(cache, va_display); + if (!m) + return NULL; + + entry = m->data; + return &entry->info; +} + +/** + * gst_vaapi_display_cache_lookup_by_native_display: + * @cache: the #GstVaapiDisplayCache + * @native_display: the native display to find + * + * Looks up the display cache for the specified native display. + * + * Return value: a #GstVaapiDisplayInfo matching @native_display, or + * %NULL if none was found + */ +const GstVaapiDisplayInfo * +gst_vaapi_display_cache_lookup_by_native_display( + GstVaapiDisplayCache *cache, + gpointer native_display +) +{ + CacheEntry *entry; + GList *m; + + g_return_val_if_fail(cache != NULL, NULL); + g_return_val_if_fail(native_display != NULL, NULL); + + m = cache_lookup_native_display(cache, native_display); + if (!m) + return NULL; + + entry = m->data; + return &entry->info; +} + +/** + * gst_vaapi_display_cache_lookup_by_name: + * @cache: the #GstVaapiDisplayCache + * @display_name: the display name to match + * @compare_func: an optional string comparison function + * @user_data: any relevant data pointer to the comparison function + * + * Looks up the display cache for the specified display name. A + * specific comparison function can be provided to avoid a plain + * strcmp(). + * + * Return value: a #GstVaapiDisplayInfo matching @display_name, or + * %NULL if none was found + */ +const GstVaapiDisplayInfo * +gst_vaapi_display_cache_lookup_by_name( + GstVaapiDisplayCache *cache, + const gchar *display_name, + GCompareDataFunc compare_func, + gpointer user_data +) +{ + CacheEntry *entry; + GList *m; + + g_return_val_if_fail(cache != NULL, NULL); + + if (compare_func) + CACHE_LOOKUP(cache, m, display_name, compare_func, display_name, user_data); + else + CACHE_LOOKUP(cache, m, display_name, compare_string, display_name, NULL); + if (!m) + return NULL; + + entry = m->data; + return &entry->info; +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplaycache.h b/gst-libs/gst/vaapi/gstvaapidisplaycache.h new file mode 100644 index 0000000..12c2953 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplaycache.h @@ -0,0 +1,76 @@ +/* + * gstvaapidisplaycache.h - VA display cache + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GSTVAAPIDISPLAYCACHE_H +#define GSTVAAPIDISPLAYCACHE_H + +#include + +typedef struct _GstVaapiDisplayCache GstVaapiDisplayCache; + +GstVaapiDisplayCache * +gst_vaapi_display_cache_new(void); + +void +gst_vaapi_display_cache_free(GstVaapiDisplayCache *cache); + +guint +gst_vaapi_display_cache_get_size(GstVaapiDisplayCache *cache); + +gboolean +gst_vaapi_display_cache_add( + GstVaapiDisplayCache *cache, + GstVaapiDisplayInfo *info +); + +void +gst_vaapi_display_cache_remove( + GstVaapiDisplayCache *cache, + GstVaapiDisplay *display +); + +const GstVaapiDisplayInfo * +gst_vaapi_display_cache_lookup( + GstVaapiDisplayCache *cache, + GstVaapiDisplay *display +); + +const GstVaapiDisplayInfo * +gst_vaapi_display_cache_lookup_by_va_display( + GstVaapiDisplayCache *cache, + VADisplay va_display +); + +const GstVaapiDisplayInfo * +gst_vaapi_display_cache_lookup_by_native_display( + GstVaapiDisplayCache *cache, + gpointer native_display +); + +const GstVaapiDisplayInfo * +gst_vaapi_display_cache_lookup_by_name( + GstVaapiDisplayCache *cache, + const gchar *display_name, + GCompareDataFunc compare_func, + gpointer user_data +); + +#endif /* GSTVAAPIDISPLAYCACHE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder.c b/gst-libs/gst/vaapi/gstvaapiencoder.c new file mode 100644 index 0000000..a49c719 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder.c @@ -0,0 +1,440 @@ +/* + * gstvaapiencoder.c - VA-API encoder interface + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstvaapiencoder.h" + +#include + +#include "gstvaapidisplay_x11.h" +#include "gstvaapiobject_priv.h" +#include "gstvaapidisplay_priv.h" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encoder_debug); +#define GST_CAT_DEFAULT gst_vaapi_encoder_debug + + +G_DEFINE_TYPE(GstVaapiEncoder, gst_vaapi_encoder, G_TYPE_OBJECT) + +gboolean +gst_vaapi_encoder_set_display( + GstVaapiEncoder* encoder, + GstVaapiDisplay *display +) +{ + GstVaapiEncoderPrivate *priv = encoder->priv; + if (display == priv->display) { + return TRUE; + } + + if (VAAPI_ENC_INIT < priv->state) { + return FALSE; + } + if (priv->display) { + g_object_unref(priv->display); + priv->display = NULL; + priv->va_display = NULL; + } + if (display) { + priv->display = g_object_ref(display); + priv->va_display = gst_vaapi_display_get_display(display); + } + return TRUE; +} + +GstVaapiDisplay * +gst_vaapi_encoder_get_display(GstVaapiEncoder* encoder) +{ + GstVaapiEncoderPrivate *priv = encoder->priv; + return (priv->display ? g_object_ref(priv->display) : NULL); +} + +GstVaapiContext * +gst_vaapi_encoder_get_context(GstVaapiEncoder* encoder) +{ + GstVaapiEncoderPrivate *priv = encoder->priv; + return (priv->context ? g_object_ref(priv->context) : NULL); +} + + +VAAPI_Encode_State +gst_vaapi_encoder_get_state(GstVaapiEncoder* encoder) +{ + GstVaapiEncoderPrivate *priv = encoder->priv; + return priv->state; +} + + +EncoderStatus +gst_vaapi_encoder_initialize(GstVaapiEncoder* encoder) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder); + GstVaapiEncoderPrivate *priv = encoder->priv; + + /* check state */ + if (VAAPI_ENC_INIT == priv->state) { + return ENCODER_NO_ERROR; + } + ENCODER_ASSERT(VAAPI_ENC_NULL == priv->state); + if (VAAPI_ENC_NULL != priv->state) { + return ENCODER_STATE_ERR; + } + + /* create va_dpy*/ + if (!priv->display) { + priv->display = gst_vaapi_display_x11_new(NULL); + ENCODER_CHECK_STATUS(priv->display, + ENCODER_DISPLAY_ERR, + "gst_vaapi_display_x11_new failed."); + } + priv->va_display = gst_vaapi_display_get_display(priv->display); + + if (encoder_class->initialize) { + ret = encoder_class->initialize(encoder); + ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == ret, + ret, + "encoder failed."); + } + priv->state = VAAPI_ENC_INIT; + +end: + return ret; +} + +EncoderStatus +gst_vaapi_encoder_open(GstVaapiEncoder* encoder) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder); + GstVaapiEncoderPrivate *priv = encoder->priv; + + /* check state */ + if (VAAPI_ENC_OPENED == priv->state) { + return ENCODER_NO_ERROR; + } + ENCODER_ASSERT(VAAPI_ENC_INIT == priv->state); + if (VAAPI_ENC_INIT != priv->state) { + return ENCODER_STATE_ERR; + } + ENCODER_ASSERT(!priv->context); + + ENCODER_CHECK_STATUS(encoder_class->open, + ENCODER_FUNC_PTR_ERR, + "encoder function pointer empty."); + ret = encoder_class->open(encoder, &priv->context); + ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret, + ret, + "encoder failed."); + ENCODER_CHECK_STATUS(priv->context, + ENCODER_CONTEXT_ERR, + "encoder context failed."); + priv->va_context = gst_vaapi_context_get_id(priv->context); + priv->state = VAAPI_ENC_OPENED; + +end: + return ret; +} + +EncoderStatus +gst_vaapi_encoder_encode( + GstVaapiEncoder* encoder, + GstBuffer *pic +) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder); + GstVaapiEncoderPrivate *priv = encoder->priv; + + ENCODER_CHECK_STATUS(priv->state >= VAAPI_ENC_OPENED, + ENCODER_STATE_ERR, + "encoder was not opened before ."); + ENCODER_CHECK_STATUS(encoder_class->encode, + ENCODER_FUNC_PTR_ERR, + "encoder function pointer empty."); + ret = encoder_class->encode(encoder, pic); + ENCODER_CHECK_STATUS(ENCODER_NO_ERROR <= ret, + ret, + "encoder failed."); + if (priv->state < VAAPI_ENC_ENCODING) { + priv->state = VAAPI_ENC_ENCODING; + } +end: + return ret; +} + +EncoderStatus +gst_vaapi_encoder_get_encoded_buffer( + GstVaapiEncoder* encoder, + GstBuffer **buf +) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder); + GstVaapiEncoderPrivate *priv = encoder->priv; + + ENCODER_CHECK_STATUS(priv->state >= VAAPI_ENC_OPENED, + ENCODER_STATE_ERR, + "encoder was not encoding ."); + ENCODER_CHECK_STATUS(encoder_class->get_buf, + ENCODER_FUNC_PTR_ERR, + "encoder function pointer empty."); + ret = encoder_class->get_buf(encoder, buf); + ENCODER_CHECK_STATUS(ENCODER_NO_ERROR <= ret, + ret, + "encoder failed."); +end: + return ret; +} + + +EncoderStatus +gst_vaapi_encoder_get_codec_data( + GstVaapiEncoder* encoder, + GstBuffer **codec_data +) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder); + GstVaapiEncoderPrivate *priv = encoder->priv; + + ENCODER_CHECK_STATUS(priv->state >= VAAPI_ENC_OPENED, + ENCODER_STATE_ERR, + "encoder was not opened before ."); + if (!encoder_class->get_codec_data) { + *codec_data = NULL; + ENCODER_LOG_INFO("There's no codec_data"); + return ret; + } + ret = encoder_class->get_codec_data(encoder, codec_data); + +end: + return ret; +} + +EncoderStatus +gst_vaapi_encoder_flush( + GstVaapiEncoder* encoder +) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder); + GstVaapiEncoderPrivate *priv = encoder->priv; + + if (priv->state < VAAPI_ENC_OPENED) { + return ENCODER_STATE_ERR; + } + ENCODER_CHECK_STATUS(encoder_class->flush, + ENCODER_FUNC_PTR_ERR, + "encoder function pointer empty."); + ret = encoder_class->flush(encoder); + ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret, + ret, + "encoder failed."); +end: + return ret; +} + +EncoderStatus +gst_vaapi_encoder_close(GstVaapiEncoder* encoder) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder); + GstVaapiEncoderPrivate *priv = encoder->priv; + + if (VAAPI_ENC_INIT >= priv->state) { + return ENCODER_NO_ERROR; + } + ENCODER_CHECK_STATUS(encoder_class->close, + ENCODER_FUNC_PTR_ERR, + "encoder function pointers empty."); + ret = encoder_class->close(encoder); + ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret, + ret, + "encoder failed."); +end: + if (priv->context) { + g_object_unref(priv->context); + priv->context = NULL; + priv->va_context = VA_INVALID_ID; + } + + priv->state = VAAPI_ENC_INIT; + return ret; +} + +EncoderStatus +gst_vaapi_encoder_render_picture( + GstVaapiEncoder *encoder, + GstVaapiSurface *surface, + VABufferID *bufs, + guint num +) +{ + GstVaapiDisplay *display; + VASurfaceID surface_id; + VAContextID context_id; + VADisplay va_display; + VAStatus va_status; + gboolean is_locked = FALSE; + EncoderStatus ret = ENCODER_NO_ERROR; + + display = ENCODER_DISPLAY(encoder); + + g_return_val_if_fail(surface, ENCODER_PARAMETER_ERR); + g_return_val_if_fail(ENCODER_CONTEXT(encoder), ENCODER_PARAMETER_ERR); + + surface_id = (VASurfaceID)GST_VAAPI_OBJECT_ID(surface); + context_id = ENCODER_VA_CONTEXT(encoder); + va_display = ENCODER_VA_DISPLAY(encoder); + g_return_val_if_fail(surface_id != VA_INVALID_SURFACE, ENCODER_PARAMETER_ERR); + + /* begin surface*/ + ENCODER_ACQUIRE_DISPLAY_LOCK(display); + va_status = vaBeginPicture(va_display, context_id, surface_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + ENCODER_PARAMETER_ERR, + "vaBeginPicture failed"); + + va_status = vaRenderPicture(va_display, + context_id, + bufs, + num); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + ENCODER_PARAMETER_ERR, + "vaRenderPicture failed"); + + va_status = vaEndPicture(va_display, context_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + ENCODER_PARAMETER_ERR, + "vaRenderPicture failed"); + +end: + ENCODER_RELEASE_DISPLAY_LOCK(display); + return ret; +} + +EncoderStatus +gst_vaapi_encoder_uninitialize(GstVaapiEncoder* encoder) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder); + GstVaapiEncoderPrivate *priv = encoder->priv; + + if (VAAPI_ENC_NULL == priv->state) { + return ENCODER_NO_ERROR; + } + + if (VAAPI_ENC_INIT < priv->state) { + ret = gst_vaapi_encoder_close(encoder); + } + ENCODER_ASSERT(VAAPI_ENC_INIT == priv->state); + if (encoder_class->uninitialize) { + ret = encoder_class->uninitialize(encoder); + ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret, + ret, + "encoder failed."); + } + +end: + if (priv->display) { + g_object_unref(priv->display); + priv->display = NULL; + priv->va_display = NULL; + } + priv->state = VAAPI_ENC_NULL; + return ret; + +} + +char * +vaapi_encoder_dump_bytes(const guint8 *buf, guint32 num) +{ + static char tmp[1024]; + guint32 i = 0; + memset(tmp, 0, sizeof(tmp)); + + char *p = tmp; + for (i = 0; i < num; i++) { + snprintf(p, 1024-(p-tmp), "%02x", (guint8)buf[i]); + p += strlen(p); + } + return tmp; +} + +static void +gst_vaapi_encoder_init(GstVaapiEncoder *encoder) +{ + GstVaapiEncoderPrivate *priv; + + encoder->priv = GST_VAAPI_ENCODER_GET_PRIVATE(encoder); + priv = encoder->priv; + ENCODER_ASSERT(priv); + + priv->display = NULL; + priv->va_display = NULL; + priv->context = NULL; + priv->va_context = VA_INVALID_ID; + priv->state = VAAPI_ENC_NULL; + + encoder->width = 0; + encoder->height = 0; + encoder->frame_rate = 0; + encoder->rate_control = GST_VAAPI_RATECONTROL_NONE; +} + +static void +gst_vaapi_encoder_finalize(GObject *object) +{ + GstVaapiEncoder* encoder = GST_VAAPI_ENCODER(object); + GstVaapiEncoderPrivate *priv = encoder->priv; + if (VAAPI_ENC_NULL != priv->state) { + gst_vaapi_encoder_uninitialize(encoder); + } + + if (priv->context) { + g_object_unref(priv->context); + priv->context = NULL; + priv->va_context = VA_INVALID_ID; + } + + if (priv->display) { + g_object_unref(priv->display); + priv->display = NULL; + priv->va_display = NULL; + } + + G_OBJECT_CLASS (gst_vaapi_encoder_parent_class)->finalize (object); +} + +static void +gst_vaapi_encoder_class_init(GstVaapiEncoderClass *kclass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(kclass); + g_type_class_add_private(kclass, sizeof(GstVaapiEncoderPrivate)); + + + GST_DEBUG_CATEGORY_INIT (gst_vaapi_encoder_debug, + "gst_va_encoder", + 0, + "gst_va_encoder element"); + + object_class->finalize = gst_vaapi_encoder_finalize; +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder.h b/gst-libs/gst/vaapi/gstvaapiencoder.h new file mode 100644 index 0000000..b8fc6d3 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder.h @@ -0,0 +1,288 @@ +/* + * gstvaapiencoder.h - VA-API encoder interface + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_H +#define GST_VAAPI_ENCODER_H + +#include +#include + +#include "gst/gstinfo.h" +#include "gst/gstbuffer.h" + +#include "gst/vaapi/gstvaapidisplay.h" +#include "gst/vaapi/gstvaapicontext.h" + +G_BEGIN_DECLS + +#define ENCODER_NO_ERROR 0 +#define ENCODER_NO_DATA 1 +#define ENCODER_NO_BUSY_BUF 2 +#define ENCODER_NO_IDLE_BUF 3 +#define ENCODER_FRAME_IN_ORDER 4 + +#define ENCODER_MEM_ERR -1 +#define ENCODER_DISPLAY_ERR -2 +#define ENCODER_CONFIG_ERR -3 +#define ENCODER_CONTEXT_ERR -3 +#define ENCODER_STATE_ERR -4 +#define ENCODER_ENC_RES_ERR -5 +#define ENCODER_PICTURE_ERR -6 +#define ENCODER_SURFACE_ERR -7 +#define ENCODER_QUERY_STATUS_ERR -8 +#define ENCODER_DATA_NOT_READY -9 +#define ENCODER_DATA_ERR -10 +#define ENCODER_PROFILE_ERR -11 +#define ENCODER_PARAMETER_ERR -12 +#define ENCODER_FUNC_PTR_ERR -13 + +#ifdef DEBUG + #define ENCODER_LOG_ERROR(str_fmt,...) \ + fprintf(stdout, str_fmt "\n", ## __VA_ARGS__) + #define ENCODER_LOG_WARNING(str_fmt,...) \ + fprintf(stdout, str_fmt "\n", ## __VA_ARGS__) + #define ENCODER_LOG_DEBUG(str_fmt,...) \ + fprintf(stdout, str_fmt "\n", ## __VA_ARGS__) + #define ENCODER_LOG_INFO(str_fmt,...) \ + fprintf(stdout, str_fmt "\n", ## __VA_ARGS__) +#else + #define ENCODER_LOG_ERROR(...) GST_ERROR( __VA_ARGS__) + #define ENCODER_LOG_WARNING(...) GST_WARNING( __VA_ARGS__) + #define ENCODER_LOG_DEBUG(...) GST_DEBUG( __VA_ARGS__) + #define ENCODER_LOG_INFO(...) GST_INFO( __VA_ARGS__) +#endif + +#define VAAPI_UNUSED_ARG(arg) (void)(arg) + +#ifdef DEBUG +#include +#define ENCODER_ASSERT(exp) assert(exp) +#else +#define ENCODER_ASSERT(exp) g_assert(exp) +#endif + +#define ENCODER_CHECK_STATUS(exp, err_num, err_reason, ...) \ + if (!(exp)) { \ + ENCODER_ASSERT(FALSE); \ + ret = err_num; \ + ENCODER_LOG_ERROR(err_reason, ## __VA_ARGS__); \ + goto end; \ + } + +/* must have declared first*/ +#define ENCODER_ACQUIRE_DISPLAY_LOCK(display) \ + if (!is_locked) { \ + GST_VAAPI_DISPLAY_LOCK(display); \ + is_locked = TRUE; \ + } + +#define ENCODER_RELEASE_DISPLAY_LOCK(display) \ + if (is_locked) { \ + GST_VAAPI_DISPLAY_UNLOCK(display); \ + is_locked = FALSE; \ + } + + +typedef enum { + VAAPI_ENC_NULL, + VAAPI_ENC_INIT, + VAAPI_ENC_OPENED, + VAAPI_ENC_ENCODING, +} VAAPI_Encode_State; + +typedef int EncoderStatus; +typedef struct _GstVaapiEncoder GstVaapiEncoder; +typedef struct _GstVaapiEncoderPrivate GstVaapiEncoderPrivate; +typedef struct _GstVaapiEncoderClass GstVaapiEncoderClass; + +#define GST_TYPE_VAAPI_ENCODER \ + (gst_vaapi_encoder_get_type()) + +#define GST_IS_VAAPI_ENCODER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_ENCODER)) + +#define GST_IS_VAAPI_ENCODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_ENCODER)) + +#define GST_VAAPI_ENCODER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GST_TYPE_VAAPI_ENCODER, \ + GstVaapiEncoderClass)) + +#define GST_VAAPI_ENCODER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_VAAPI_ENCODER, \ + GstVaapiEncoder)) + +#define GST_VAAPI_ENCODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GST_TYPE_VAAPI_ENCODER, \ + GstVaapiEncoderClass)) + +#define GST_VAAPI_ENCODER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_TYPE_VAAPI_ENCODER, \ + GstVaapiEncoderPrivate)) + +#define GST_VAAPI_ENCODER_CAST(encoder) \ + ((GstVaapiEncoder *)(encoder)) + +/* Get GstVaapiDisplay* */ +#define ENCODER_DISPLAY(encoder) \ + (((GstVaapiEncoder*)(encoder))->priv->display) + +/* Get VADisplay */ +#define ENCODER_VA_DISPLAY(encoder) \ + (((GstVaapiEncoder*)(encoder))->priv->va_display) + +/* Get GstVaapiContext* */ +#define ENCODER_CONTEXT(encoder) \ + (((GstVaapiEncoder*)(encoder))->priv->context) + +/* Get VAContext */ +#define ENCODER_VA_CONTEXT(encoder) \ + (((GstVaapiEncoder*)(encoder))->priv->va_context) + +#define ENCODER_WIDTH(encoder) (((GstVaapiEncoder*)(encoder))->width) +#define ENCODER_HEIGHT(encoder) (((GstVaapiEncoder*)(encoder))->height) +#define ENCODER_FPS(encoder) (((GstVaapiEncoder*)(encoder))->frame_rate) +#define ENCODER_RATE_CONTROL(encoder) \ + (((GstVaapiEncoder*)(encoder))->rate_control) + +struct _GstVaapiEncoder { + GObject parent; + GstVaapiEncoderPrivate *priv; + + guint32 width; + guint32 height; + guint32 frame_rate; + GstVaapiRateControl rate_control; +}; + +struct _GstVaapiEncoderClass { + GObjectClass parent_class; + + EncoderStatus (*initialize) (GstVaapiEncoder* encoder); /* can be NULL */ + EncoderStatus (*uninitialize) (GstVaapiEncoder* encoder); /* can be NULL */ + + /* context [out] */ + EncoderStatus (*open) (GstVaapiEncoder* encoder, + GstVaapiContext **context); + + EncoderStatus (*close) (GstVaapiEncoder* encoder); + EncoderStatus (*encode) (GstVaapiEncoder* encoder, + GstBuffer *pic); + /* buf [out] */ + EncoderStatus (*get_buf) (GstVaapiEncoder* encoder, + GstBuffer **buf); + EncoderStatus (*flush) (GstVaapiEncoder* encoder); + + /* get_codec_data can be NULL */ + EncoderStatus (*get_codec_data)(GstVaapiEncoder* encoder, GstBuffer **codec_data); +}; + +struct _GstVaapiEncoderPrivate { + GstVaapiDisplay *display; + VADisplay va_display; + GstVaapiContext *context; + VAContextID va_context; + VAAPI_Encode_State state; +}; + +GType +gst_vaapi_encoder_get_type(void); + +/* set/get display */ +gboolean +gst_vaapi_encoder_set_display( + GstVaapiEncoder* encoder, + GstVaapiDisplay *display +); +GstVaapiDisplay * +gst_vaapi_encoder_get_display(GstVaapiEncoder* encoder); + +/* get context */ +GstVaapiContext * +gst_vaapi_encoder_get_context(GstVaapiEncoder* encoder); + +/* get encoding state */ +VAAPI_Encode_State +gst_vaapi_encoder_get_state(GstVaapiEncoder* encoder); + +/* check/open display */ +EncoderStatus +gst_vaapi_encoder_initialize(GstVaapiEncoder* encoder); + +/* check/open context */ +EncoderStatus +gst_vaapi_encoder_open(GstVaapiEncoder* encoder); + +/* encode one frame */ +EncoderStatus +gst_vaapi_encoder_encode( + GstVaapiEncoder* encoder, + GstBuffer *pic +); + +EncoderStatus +gst_vaapi_encoder_get_encoded_buffer( + GstVaapiEncoder* encoder, + GstBuffer **buf +); + +EncoderStatus +gst_vaapi_encoder_get_codec_data( + GstVaapiEncoder* encoder, + GstBuffer **codec_data +); + +/* flush all frames */ +EncoderStatus +gst_vaapi_encoder_flush(GstVaapiEncoder* encoder); + +/* close context */ +EncoderStatus +gst_vaapi_encoder_close(GstVaapiEncoder* encoder); + +EncoderStatus +gst_vaapi_encoder_render_picture( + GstVaapiEncoder *encoder, + GstVaapiSurface *buffer_surface, + VABufferID *bufs, + guint num +); + +/* close display */ +EncoderStatus +gst_vaapi_encoder_uninitialize(GstVaapiEncoder* encoder); + +static inline void +gst_vaapi_encoder_unref (GstVaapiEncoder *encoder) +{ + g_object_unref (encoder); +} + +/* other functions */ +char *vaapi_encoder_dump_bytes(const guint8 *buf, guint32 num); + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODER_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h263.c b/gst-libs/gst/vaapi/gstvaapiencoder_h263.c new file mode 100644 index 0000000..507a2fa --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h263.c @@ -0,0 +1,326 @@ +/* + * gstvaapiencoder_h263.c - H.263 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstvaapiencoder_h263.h" + +#include +#include + +#include "gstvaapiobject.h" +#include "gstvaapiobject_priv.h" +#include "gstvaapicontext.h" +#include "gstvaapisurface.h" +#include "gstvaapivideobuffer.h" +#include "gstvaapidisplay_priv.h" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h263_encoder_debug); +#define GST_CAT_DEFAULT gst_vaapi_h263_encoder_debug + +#define GST_VAAPI_ENCODER_H263_CAST(encoder) ((GstVaapiEncoderH263 *)(encoder)) + +struct _GstVaapiEncoderH263Private { + GstVaapiSurface *ref_surface; /* reference buffer*/ + GstVaapiSurface *recon_surface; /* reconstruct buffer*/ + + VABufferID seq_param_id; + VABufferID pic_param_id; + VABufferID slic_param_id; +}; + +G_DEFINE_TYPE(GstVaapiEncoderH263, gst_vaapi_encoder_h263, GST_TYPE_VAAPI_BASE_ENCODER) + +GstVaapiEncoderH263 * +gst_vaapi_encoder_h263_new(void) +{ + return GST_VAAPI_ENCODER_H263_CAST(g_object_new(GST_TYPE_VAAPI_ENCODER_H263, NULL)); +} + +static gboolean +gst_vaapi_encoder_h263_validate_attributes( + GstVaapiBaseEncoder* base +) +{ + GstVaapiEncoderH263 *encoder = GST_VAAPI_ENCODER_H263_CAST(base); + if (!ENCODER_WIDTH(encoder) || + !ENCODER_HEIGHT(encoder) || + !ENCODER_FPS(encoder)) + { + return FALSE; + } + if (!encoder->intra_period) { + encoder->intra_period = H263_DEFAULT_INTRA_PERIOD; + } + if (-1 == encoder->init_qp) { + encoder->init_qp = H263_DEFAULT_INIT_QP; + } + if (-1 == encoder->min_qp) { + encoder->min_qp = H263_DEFAULT_MIN_QP; + } + + /* default compress ratio 1: (4*8*1.5) */ + if (!encoder->bitrate) { + encoder->bitrate = + ENCODER_WIDTH(encoder)*ENCODER_HEIGHT(encoder)*ENCODER_FPS(encoder)/4/1024; + } + gst_vaapi_base_encoder_set_va_profile(GST_VAAPI_BASE_ENCODER(encoder), + VAProfileH263Baseline); + return TRUE; + +} + + +static void +h263_release_parameters( + GstVaapiEncoderH263 *encoder +) +{ + GstVaapiEncoderH263Private *priv = encoder->priv; + VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder); + VAStatus va_status = VA_STATUS_SUCCESS; + + VAAPI_UNUSED_ARG(va_status); + + if (VA_INVALID_ID != priv->seq_param_id) { + va_status = vaDestroyBuffer(va_dpy, priv->seq_param_id); + priv->seq_param_id = VA_INVALID_ID; + } + if (VA_INVALID_ID != priv->pic_param_id) { + va_status = vaDestroyBuffer(va_dpy, priv->pic_param_id); + priv->pic_param_id = VA_INVALID_ID; + } + if (VA_INVALID_ID != priv->slic_param_id) { + va_status = vaDestroyBuffer(va_dpy, priv->slic_param_id); + priv->slic_param_id = VA_INVALID_ID; + } + +} + +static gboolean +gst_vaapi_encoder_h263_release_resource( + GstVaapiBaseEncoder* base +) +{ + GstVaapiEncoderH263 *encoder = GST_VAAPI_ENCODER_H263_CAST(base); + GstVaapiEncoderH263Private *priv = encoder->priv; + GstVaapiContext *context = ENCODER_CONTEXT(base); + + h263_release_parameters(encoder); + + /*remove ref_surface*/ + if (priv->ref_surface) { + if (context) { + gst_vaapi_context_put_surface(context, priv->ref_surface); + } else { + g_object_unref(priv->ref_surface); + } + priv->ref_surface = NULL; + } + + /*remove recon_surface*/ + if (priv->recon_surface) { + if (context) { + gst_vaapi_context_put_surface(context, priv->recon_surface); + } else { + g_object_unref(priv->recon_surface); + } + priv->recon_surface = NULL; + } + + return TRUE; +} + +static EncoderStatus +gst_vaapi_encoder_h263_rendering( + GstVaapiBaseEncoder *base, + GstVaapiSurface *surface, + guint frame_index, + VABufferID coded_buf, + gboolean *is_key +) + +{ + GstVaapiEncoderH263 *encoder = GST_VAAPI_ENCODER_H263_CAST(base); + GstVaapiEncoderH263Private *priv = encoder->priv; + GstVaapiContext *context = ENCODER_CONTEXT(base); + VADisplay va_dpy = ENCODER_VA_DISPLAY(base); + VAContextID context_id = ENCODER_VA_CONTEXT(base); + VABufferID va_buffers[64]; + guint32 va_buffers_count = 0; + + VAStatus va_status = VA_STATUS_SUCCESS; + EncoderStatus ret = ENCODER_NO_ERROR; + + *is_key = (frame_index % encoder->intra_period == 0); + + /* initialize sequence parameter set, only first time */ + if (VA_INVALID_ID == priv->seq_param_id) { /*only the first time*/ + VAEncSequenceParameterBufferH263 seq_param = {0}; + + seq_param.intra_period = encoder->intra_period; + seq_param.bits_per_second = encoder->bitrate * 1024; + seq_param.frame_rate = ENCODER_FPS(encoder); + seq_param.initial_qp = encoder->init_qp; + seq_param.min_qp = encoder->min_qp; + + va_status = vaCreateBuffer(va_dpy, context_id, + VAEncSequenceParameterBufferType, + sizeof(seq_param), 1, + &seq_param, + &priv->seq_param_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + ENCODER_ENC_RES_ERR, + "h263 alloc seq-buffer failed."); + va_buffers[va_buffers_count++] = priv->seq_param_id; + } + + /* set reference and reconstructed surfaces */ + if (!priv->ref_surface) { + priv->ref_surface = gst_vaapi_context_get_surface(context); + ENCODER_CHECK_STATUS(priv->ref_surface, + ENCODER_SURFACE_ERR, + "h263 reference surface, h263_pop_free_surface failed."); + } + if (!priv->recon_surface) { + priv->recon_surface = gst_vaapi_context_get_surface(context); + ENCODER_CHECK_STATUS(priv->recon_surface, + ENCODER_SURFACE_ERR, + "h263 reconstructed surface, h263_pop_free_surface failed."); + } + + /* initialize picture, every time, every frame */ + VAEncPictureParameterBufferH263 pic_param = {0}; + pic_param.reference_picture = GST_VAAPI_OBJECT_ID(priv->ref_surface); + pic_param.reconstructed_picture = GST_VAAPI_OBJECT_ID(priv->recon_surface); + pic_param.coded_buf = coded_buf; + pic_param.picture_width = ENCODER_WIDTH(encoder); + pic_param.picture_height = ENCODER_HEIGHT(encoder); + pic_param.picture_type = (*is_key) ? VAEncPictureTypeIntra : VAEncPictureTypePredictive; + if (VA_INVALID_ID != priv->pic_param_id) { /* destroy first*/ + va_status = vaDestroyBuffer(va_dpy, priv->pic_param_id); + priv->pic_param_id = VA_INVALID_ID; + } + + va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType, + sizeof(pic_param), 1, &pic_param, &priv->pic_param_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, + ENCODER_ENC_RES_ERR, "h263 creating pic-param buffer failed."); + va_buffers[va_buffers_count++] = priv->pic_param_id; + + /*initialize slice parameters, only ONE slice for h263*/ + VAEncSliceParameterBuffer slice_param = { 0 }; + slice_param.start_row_number = 0; + slice_param.slice_height = (ENCODER_HEIGHT(encoder)+15)/16; /*MB?*/ + slice_param.slice_flags.bits.is_intra = *is_key; + slice_param.slice_flags.bits.disable_deblocking_filter_idc = 0; + if (VA_INVALID_ID != priv->slic_param_id) { + vaDestroyBuffer(va_dpy, priv->slic_param_id); + priv->slic_param_id = VA_INVALID_ID; + } + + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncSliceParameterBufferType, + sizeof(slice_param), + 1, + &slice_param, + &priv->slic_param_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, + ENCODER_ENC_RES_ERR, + "h263 creating slice-parameters buffer failed."); + va_buffers[va_buffers_count++] = priv->slic_param_id; + + ret = gst_vaapi_encoder_render_picture(GST_VAAPI_ENCODER_CAST(encoder), + surface, + va_buffers, + va_buffers_count); + ENCODER_CHECK_STATUS(ret == ENCODER_NO_ERROR, + ENCODER_PICTURE_ERR, + "h263 rendering slice-parameters buffer failed."); + + /*swap ref_surface and recon_surface */ + GstVaapiSurface *swap = priv->ref_surface; + priv->ref_surface = priv->recon_surface; + priv->recon_surface = swap; + +end: + return ret; +} + +static void +gst_vaapi_encoder_h263_init(GstVaapiEncoderH263 *encoder) +{ + GstVaapiEncoderH263Private *priv = GST_VAAPI_ENCODER_H263_GET_PRIVATE(encoder); + encoder->priv = priv; + ENCODER_ASSERT(priv); + + /* init public */ + encoder->bitrate = 0; + encoder->intra_period = H263_DEFAULT_INTRA_PERIOD; + encoder->init_qp = H263_DEFAULT_INIT_QP; + encoder->min_qp = H263_DEFAULT_MIN_QP; + + /* init private */ + priv->ref_surface = NULL; + priv->recon_surface = NULL; + + priv->seq_param_id = VA_INVALID_ID; + priv->pic_param_id = VA_INVALID_ID; + priv->slic_param_id = VA_INVALID_ID; +} + +static void +gst_vaapi_encoder_h263_finalize(GObject *object) +{ + /*free private buffers*/ + GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object); + + if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) { + gst_vaapi_encoder_uninitialize(encoder); + } + G_OBJECT_CLASS(gst_vaapi_encoder_h263_parent_class)->finalize(object); +} + +static void +gst_vaapi_encoder_h263_class_init(GstVaapiEncoderH263Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiBaseEncoderClass * const base_class = GST_VAAPI_BASE_ENCODER_CLASS(klass); + GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass); + g_type_class_add_private(klass, sizeof(GstVaapiEncoderH263Private)); + + GST_DEBUG_CATEGORY_INIT (gst_vaapi_h263_encoder_debug, "gst_va_h263_encoder", 0, + "gst_va_h263_encoder element"); + + object_class->finalize = gst_vaapi_encoder_h263_finalize; + + base_class->validate_attributes = gst_vaapi_encoder_h263_validate_attributes; + base_class->pre_alloc_resource = NULL; + base_class->release_resource = gst_vaapi_encoder_h263_release_resource; + base_class->render_frame = gst_vaapi_encoder_h263_rendering; + base_class->notify_buffer = NULL; + base_class->wrap_buffer = NULL; + + /* + encoder_class->flush = gst_vaapi_encoder_h263_flush; + */ + encoder_class->get_codec_data = NULL; + +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h263.h b/gst-libs/gst/vaapi/gstvaapiencoder_h263.h new file mode 100644 index 0000000..610a135 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h263.h @@ -0,0 +1,100 @@ +/* + * gstvaapiencoder_h263.h - H.263 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_H263_H +#define GST_VAAPI_ENCODER_H263_H + +#include "gst/vaapi/gstvaapisurfacepool.h" +#include "gst/vaapi/gstvaapibaseencoder.h" + +G_BEGIN_DECLS + +#define H263_DEFAULT_INTRA_PERIOD 30 +#define H263_DEFAULT_INIT_QP 15 +#define H263_DEFAULT_MIN_QP 1 + + +typedef struct _GstVaapiEncoderH263 GstVaapiEncoderH263; +typedef struct _GstVaapiEncoderH263Private GstVaapiEncoderH263Private; +typedef struct _GstVaapiEncoderH263Class GstVaapiEncoderH263Class; + + +#define GST_TYPE_VAAPI_ENCODER_H263 \ + (gst_vaapi_encoder_h263_get_type()) + +#define GST_IS_VAAPI_ENCODER_H263(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_ENCODER_H263)) + +#define GST_IS_VAAPI_ENCODER_H263_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_ENCODER_H263)) + +#define GST_VAAPI_ENCODER_H263_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GST_TYPE_VAAPI_ENCODER_H263, \ + GstVaapiEncoderH263Class)) + +#define GST_VAAPI_ENCODER_H263(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_VAAPI_ENCODER_H263, \ + GstVaapiEncoderH263)) + +#define GST_VAAPI_ENCODER_H263_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GST_TYPE_VAAPI_ENCODER_H263, \ + GstVaapiEncoderH263Class)) + +#define GST_VAAPI_ENCODER_H263_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_TYPE_VAAPI_ENCODER_H263, \ + GstVaapiEncoderH263Private)) + +struct _GstVaapiEncoderH263 { + GstVaapiBaseEncoder parent; /*based on gobject*/ + + guint32 bitrate; /*kbps*/ + guint32 intra_period; + guint32 init_qp; /*default 15, 1~31*/ + guint32 min_qp; /*default 1, 1~31*/ + + GstVaapiEncoderH263Private *priv; +}; + +struct _GstVaapiEncoderH263Class { + GstVaapiBaseEncoderClass parent_class; +}; + + +GType +gst_vaapi_encoder_h263_get_type(void); + +GstVaapiEncoderH263 * +gst_vaapi_encoder_h263_new(void); + +static inline void +gst_vaapi_encoder_h263_unref (GstVaapiEncoderH263 * encoder) +{ + g_object_unref (encoder); +} + + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODER_H263_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264.c b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c new file mode 100644 index 0000000..b98ff47 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c @@ -0,0 +1,2209 @@ +/* + * gstvaapiencoder_h264.c - H.264 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstvaapiencoder_h264.h" +#include "config.h" + +#include +#include +#include +#include +#if !HAVE_OLD_H264_ENCODER +#include +#endif +#include +#include + +#include "gst/gstclock.h" +#include "gst/gstvalue.h" + +#include "gstvaapiobject.h" +#include "gstvaapiobject_priv.h" +#include "gstvaapicontext.h" +#include "gstvaapisurface.h" +#include "gstvaapivideobuffer.h" +#include "gstvaapidisplay_priv.h" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h264_encoder_debug); + +#define GST_CAT_DEFAULT gst_vaapi_h264_encoder_debug + +#define GST_VAAPI_ENCODER_H264_CAST(encoder) ((GstVaapiEncoderH264 *)(encoder)) + +#define SHARE_CODED_BUF 0 + +#define DEFAULT_SURFACE_NUMBER 3 +#define DEFAULT_CODEDBUF_NUM 5 +#define DEFAULT_SID_INPUT 0 // suface_ids[0] + +#define REF_RECON_SURFACE_NUM 2 + +#define ENTROPY_MODE_CAVLC 0 +#define ENTROPY_MODE_CABAC 1 + +#define BR_CBR 0 +#define BR_VBR 1 +#define BR_CQP 2 + +#define NAL_REF_IDC_NONE 0 +#define NAL_REF_IDC_LOW 1 +#define NAL_REF_IDC_MEDIUM 2 +#define NAL_REF_IDC_HIGH 3 + + +typedef enum { + NAL_UNKNOWN = 0, + NAL_NON_IDR = 1, + NAL_IDR = 5, /* ref_idc != 0 */ + NAL_SEI = 6, /* ref_idc == 0 */ + NAL_SPS = 7, + NAL_PPS = 8, + NAL_AUD = 9, + NAL_FILLER = 12, +}H264_NAL_TYPE; + + +typedef enum { + SLICE_TYPE_P = 0, + SLICE_TYPE_B = 1, + SLICE_TYPE_I = 2 +} H264_SLICE_TYPE; + +struct _GstVaapiEncoderH264Private { + GstVaapiEncoderH264 *public; + guint32 format; /*NV12, I420,*/ + gboolean avc_flag; /*elementary flag*/ + + /* private data*/ + GQueue *video_buffer_caches; /*not used for baseline*/ + + GstVaapiSurface *ref_surface1; /* reference buffer*/ + GstVaapiSurface *ref_surface2; /* for B frames */ + GstVaapiSurface *recon_surface; /* reconstruct buffer*/ + + VABufferID seq_param_id; + VABufferID pic_param_id; + VABufferID slice_param_id; + VABufferID misc_param_hdr_id; + VABufferID packed_seq_param_id; + VABufferID packed_seq_data_id; + VABufferID packed_pic_param_id; + VABufferID packed_pic_data_id; + gboolean is_seq_param_set; +#if HAVE_OLD_H264_ENCODER + VAEncSliceParameterBuffer *slice_param_buffers; +#else + VAEncSliceParameterBufferH264 *slice_param_buffers; +#endif + guint32 default_slice_height; + guint32 slice_mod_mb_num; + guint32 default_cts_offset; + + GstBuffer *sps_data; + GstBuffer *pps_data; + + GQueue *queued_buffers; /* GstVaapiVideoBuffers with surface*/ + + guint32 gop_count; + guint32 cur_display_num; + guint32 cur_decode_num; + H264_SLICE_TYPE cur_slice_type; + guint64 last_decode_time; + guint32 max_frame_num; + guint32 max_pic_order_cnt; + guint16 idr_num; +}; + +G_DEFINE_TYPE(GstVaapiEncoderH264, gst_vaapi_encoder_h264, GST_TYPE_VAAPI_BASE_ENCODER) + +// 4096-1 +#define H264_BITSTREAM_ALLOC_ALIGN_MASK 0x0FFF + +#define BIT_STREAM_BUFFER(stream) ((stream)->buffer) +#define BIT_STREAM_BIT_SIZE(stream) ((stream)->bit_size) + +struct _H264Bitstream { + guint8 *buffer; + guint32 bit_size; + guint32 max_bit_capability; +}; + +typedef struct _H264Bitstream H264Bitstream; + +static const guint8 h264_bit_mask[9] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}; + +/* h264 bitstream functions */ +static void +h264_bitstream_init(H264Bitstream *bitstream, guint32 bit_capability); + +static gboolean +h264_bitstream_write_uint( + H264Bitstream *bitstream, + guint32 value, + guint32 bit_size +); + +static gboolean +h264_bitstream_align(H264Bitstream *bitstream, guint32 value); + +static gboolean +h264_bitstream_write_ue(H264Bitstream *bitstream, guint32 value); + +static gboolean +h264_bitstream_write_se(H264Bitstream *bitstream, gint32 value); + +static gboolean +h264_bitstream_write_trailing_bits(H264Bitstream *bitstream); + +static gboolean +h264_bitstream_write_byte_array( + H264Bitstream *bitstream, + const guint8 *buf, + guint32 byte_size +); + +static void +h264_bitstream_destroy(H264Bitstream *bitstream, gboolean free_flag); + +static gboolean +h264_bitstream_auto_grow(H264Bitstream *bitstream, guint32 extra_bit_size); + +static gboolean +h264_bitstream_write_sps( + H264Bitstream *bitstream, + VAEncSequenceParameterBufferH264 *seq, + H264_Profile profile +); +static gboolean +h264_bitstream_write_pps( + H264Bitstream *bitstream, + VAEncPictureParameterBufferH264 *pic +); + +static gboolean +h264_bitstream_write_nal_header( + H264Bitstream *bitstream, + guint nal_ref_idc, + guint nal_unit_type +); + +static VAProfile +h264_get_va_profile(guint32 profile) +{ + switch (profile) { + case H264_PROFILE_BASELINE: + return VAProfileH264Baseline; + + case H264_PROFILE_MAIN: + return VAProfileH264Main; + + case H264_PROFILE_HIGH: + return VAProfileH264High; + + default: + break; + } + return (-1); +} + +GstVaapiEncoderH264 * +gst_vaapi_encoder_h264_new(void) +{ + return GST_VAAPI_ENCODER_H264_CAST( + g_object_new(GST_TYPE_VAAPI_ENCODER_H264, NULL)); +} + +static void +gst_vaapi_encoder_h264_init_public_values(GstVaapiEncoderH264* encoder) +{ + encoder->profile = 0; + encoder->level = 0; + encoder->bitrate = 0; + encoder->intra_period = 0; + encoder->init_qp = -1; + encoder->min_qp = -1; + encoder->slice_num = 0; + encoder->b_frame_num = 0; +} + +void +gst_vaapi_encoder_h264_set_avc_flag(GstVaapiEncoderH264* encoder, gboolean avc) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + priv->avc_flag = avc; +} + +gboolean +gst_vaapi_encoder_h264_get_avc_flag(GstVaapiEncoderH264* encoder) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + return priv->avc_flag; +} + +gboolean +gst_vaapi_encoder_h264_validate_attributes(GstVaapiBaseEncoder *base) +{ + GstVaapiEncoderH264 *encoder = GST_VAAPI_ENCODER_H264_CAST(base); + GstVaapiEncoderH264Private *priv = encoder->priv; + if (!ENCODER_WIDTH(encoder) || + !ENCODER_HEIGHT(encoder) || + !ENCODER_FPS(encoder)) { + return FALSE; + } + if (!encoder->profile) { + encoder->profile = H264_DEFAULT_PROFILE; + } + gst_vaapi_base_encoder_set_va_profile(base, h264_get_va_profile(encoder->profile)); + if (!encoder->level) { + if (encoder->profile <= H264_PROFILE_BASELINE) + encoder->level = H264_LEVEL_31; + else + encoder->level = H264_LEVEL_41; + } + if (!encoder->intra_period) { + encoder->intra_period = H264_DEFAULT_INTRA_PERIOD; + } + if (-1 == encoder->init_qp) { + encoder->init_qp = H264_DEFAULT_INIT_QP; + } + if (-1 == encoder->min_qp) { + if (GST_VAAPI_RATECONTROL_CQP == ENCODER_RATE_CONTROL(encoder)) + encoder->min_qp = encoder->init_qp; + else + encoder->min_qp = H264_DEFAULT_MIN_QP; + } + + if (encoder->min_qp > encoder->init_qp) { + encoder->min_qp = encoder->init_qp; + } + + /* default compress ratio 1: (4*8*1.5) */ + if (GST_VAAPI_RATECONTROL_CBR == ENCODER_RATE_CONTROL(encoder) || + GST_VAAPI_RATECONTROL_VBR == ENCODER_RATE_CONTROL(encoder) || + GST_VAAPI_RATECONTROL_VBR_CONSTRAINED == ENCODER_RATE_CONTROL(encoder)) + { + if (!encoder->bitrate) + encoder->bitrate = ENCODER_WIDTH(encoder) * + ENCODER_HEIGHT(encoder) * + ENCODER_FPS(encoder) / 4 / 1024; + } else + encoder->bitrate = 0; + + if (!encoder->slice_num) { + encoder->slice_num = H264_DEFAULT_SLICE_NUM; + } + + /* need calculate slice-num and each slice-height + suppose: ((encoder->height+15)/16) = 13, slice_num = 8 + then: slice_1_height = 2 + slice_2_height = 2 + slice_3_height = 2 + slice_4_height = 2 + slice_5_height = 2 + slice_6_height = 1 + slice_7_height = 1 + slice_8_height = 1 + */ + priv->default_slice_height = (ENCODER_HEIGHT(encoder)+15)/16/encoder->slice_num; + if (0 == priv->default_slice_height) { /* special value */ + priv->default_slice_height = 1; + priv->slice_mod_mb_num = 0; + encoder->slice_num = (ENCODER_HEIGHT(encoder)+15)/16; + } else { + priv->slice_mod_mb_num = ((ENCODER_HEIGHT(encoder)+15)/16)%encoder->slice_num; + } + + if (encoder->b_frame_num) { + priv->default_cts_offset = GST_SECOND/ENCODER_FPS(encoder); + } else { + priv->default_cts_offset = 0; + } + return TRUE; +} + + +static gboolean +h264_encoder_release_parameters(GstVaapiEncoderH264 *encoder) +{ + VAStatus va_status = VA_STATUS_SUCCESS; + GstVaapiEncoderH264Private *priv = encoder->priv; + GstVaapiDisplay *display = ENCODER_DISPLAY(encoder); + GstVaapiContext *context = ENCODER_CONTEXT(encoder); + + ENCODER_ASSERT(display); + ENCODER_ASSERT(context); + VAAPI_UNUSED_ARG(va_status); + VADisplay va_dpy = gst_vaapi_display_get_display(display); + + if (VA_INVALID_ID != priv->seq_param_id) { + va_status = vaDestroyBuffer(va_dpy, priv->seq_param_id); + priv->seq_param_id = VA_INVALID_ID; + } + if (VA_INVALID_ID != priv->pic_param_id) { + va_status = vaDestroyBuffer(va_dpy, priv->pic_param_id); + priv->pic_param_id = VA_INVALID_ID; + } + if (VA_INVALID_ID != priv->slice_param_id) { + va_status = vaDestroyBuffer(va_dpy, priv->slice_param_id); + priv->slice_param_id = VA_INVALID_ID; + } + if (VA_INVALID_ID != priv->misc_param_hdr_id) { + va_status = vaDestroyBuffer(va_dpy, priv->misc_param_hdr_id); + priv->misc_param_hdr_id = VA_INVALID_ID; + } + + if (VA_INVALID_ID != priv->packed_seq_param_id) { + va_status = vaDestroyBuffer(va_dpy, priv->packed_seq_param_id); + priv->packed_seq_param_id = VA_INVALID_ID; + } + if (VA_INVALID_ID != priv->packed_seq_data_id) { + va_status = vaDestroyBuffer(va_dpy, priv->packed_seq_data_id); + priv->packed_seq_data_id = VA_INVALID_ID; + } + if (VA_INVALID_ID != priv->packed_pic_param_id) { + va_status = vaDestroyBuffer(va_dpy, priv->packed_pic_param_id); + priv->packed_pic_param_id = VA_INVALID_ID; + } + if (VA_INVALID_ID != priv->packed_pic_data_id) { + va_status = vaDestroyBuffer(va_dpy, priv->packed_pic_data_id); + priv->packed_pic_data_id = VA_INVALID_ID; + } + + if (priv->slice_param_buffers) { + g_free(priv->slice_param_buffers); + priv->slice_param_buffers = NULL; + } + + if (priv->sps_data) { + gst_buffer_unref(priv->sps_data); + priv->sps_data = NULL; + } + if (priv->pps_data) { + gst_buffer_unref(priv->pps_data); + priv->pps_data = NULL; + } + + return TRUE; +} + +static void +h264_release_queued_buffers(GstVaapiEncoderH264Private *priv) +{ + while (!g_queue_is_empty(priv->queued_buffers)) { + GstBuffer* tmp = g_queue_pop_head(priv->queued_buffers); + if (tmp) + gst_buffer_unref(tmp); + } +} + + +static gboolean +gst_vaapi_encoder_h264_release_resource( + GstVaapiBaseEncoder* base +) +{ + GstVaapiEncoderH264* encoder = GST_VAAPI_ENCODER_H264_CAST(base); + gboolean ret = TRUE; + GstVaapiEncoderH264Private *priv = encoder->priv; + GstVaapiContext *context = ENCODER_CONTEXT(base); + + /* release buffers first */ + h264_encoder_release_parameters(encoder); + h264_release_queued_buffers(priv); + priv->cur_display_num = 0; + priv->cur_decode_num = 0; + priv->cur_slice_type = SLICE_TYPE_I; + priv->gop_count = 0; + priv->last_decode_time = 0LL; + priv->default_cts_offset = 0; + priv->is_seq_param_set = FALSE; + + /*remove ref_surface1*/ + if (priv->ref_surface1) { + if (context) { + gst_vaapi_context_put_surface(context, priv->ref_surface1); + } else { + g_object_unref(priv->ref_surface1); + } + priv->ref_surface1 = NULL; + } + + if (priv->ref_surface2) { + if (context) { + gst_vaapi_context_put_surface(context, priv->ref_surface2); + } else { + g_object_unref(priv->ref_surface2); + } + priv->ref_surface2 = NULL; + } + + /*remove recon_surface*/ + if (priv->recon_surface) { + if (context) { + gst_vaapi_context_put_surface(context, priv->recon_surface); + } else { + g_object_unref(priv->recon_surface); + } + priv->recon_surface = NULL; + } + + return ret; +} + +static gboolean +gst_vaapi_encoder_h264_alloc_slices( + GstVaapiBaseEncoder *base, + GstVaapiContext *context +) +{ + gboolean ret = TRUE; + GstVaapiEncoderH264 *encoder = GST_VAAPI_ENCODER_H264_CAST(base); + GstVaapiEncoderH264Private *priv = encoder->priv; + + priv->slice_param_buffers = +#if HAVE_OLD_H264_ENCODER + (VAEncSliceParameterBuffer*) +#else + (VAEncSliceParameterBufferH264*) +#endif + g_malloc0_n(encoder->slice_num, + sizeof(priv->slice_param_buffers[0])); + + return ret; +} + +static void +gst_vaapi_encoder_h264_frame_failed( + GstVaapiBaseEncoder *base, + GstVaapiVideoBuffer* buffer +) +{ + GstVaapiEncoderH264 *encoder = GST_VAAPI_ENCODER_H264_CAST(base); + GstVaapiEncoderH264Private *priv = encoder->priv; + + h264_release_queued_buffers(priv); + priv->cur_display_num = 0; + priv->cur_decode_num = 0; + priv->cur_slice_type = SLICE_TYPE_I; + priv->gop_count = 0; + priv->last_decode_time = 0LL; +} + +static EncoderStatus +gst_vaapi_encoder_h264_prepare_next_buffer( + GstVaapiBaseEncoder* base, + GstBuffer *display_buf, + gboolean need_flush, + GstBuffer **out_buf +) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiEncoderH264 *encoder = GST_VAAPI_ENCODER_H264_CAST(base); + GstVaapiEncoderH264Private *priv = encoder->priv; + GstBuffer *return_buf = NULL; + //guint64 pts = 0; + + if (NULL == display_buf && g_queue_is_empty(priv->queued_buffers)) { + ret = ENCODER_FRAME_IN_ORDER; + if (priv->gop_count >= encoder->intra_period || need_flush) + priv->gop_count = 0; + goto end; + } + + if (display_buf) { + ++priv->gop_count; + gst_buffer_ref(GST_BUFFER_CAST(display_buf)); + priv->last_decode_time = GST_BUFFER_TIMESTAMP(display_buf); + } + + /* first frame */ + if (priv->gop_count == 1) { + ENCODER_ASSERT(display_buf); + priv->cur_display_num = 0; + priv->cur_decode_num = 0; + priv->cur_slice_type = SLICE_TYPE_I; + ++priv->idr_num; + return_buf = display_buf; + goto end; + } + + if (display_buf) { + if (encoder->b_frame_num && + priv->gop_count < encoder->intra_period && + g_queue_get_length(priv->queued_buffers) < encoder->b_frame_num + ) + { + g_queue_push_tail(priv->queued_buffers, display_buf); + ret = ENCODER_FRAME_IN_ORDER; + goto end; + } + priv->cur_slice_type = SLICE_TYPE_P; + priv->cur_display_num = priv->gop_count-1; + ++priv->cur_decode_num; + return_buf = display_buf; + } else { + if (need_flush) { + return_buf = (GstBuffer*)g_queue_pop_tail(priv->queued_buffers); + priv->cur_slice_type = SLICE_TYPE_P; + priv->cur_display_num = priv->gop_count - 1; + ++priv->cur_decode_num; + } else { + return_buf = (GstBuffer*)g_queue_pop_head(priv->queued_buffers); + priv->cur_slice_type = SLICE_TYPE_B; + priv->cur_display_num = + priv->gop_count - 2 - g_queue_get_length(priv->queued_buffers); + } + } + +end: + *out_buf = return_buf; + + return ret; +} + +static inline void +h264_swap_surface(GstVaapiSurface **s1, GstVaapiSurface **s2) +{ + GstVaapiSurface *tmp; + + g_return_if_fail(s1 && s2); + tmp = *s1; + *s1 = *s2; + *s2 = tmp; +} + +static inline const char * +get_slice_type(H264_SLICE_TYPE type) +{ + switch (type) { + case SLICE_TYPE_I: + return "I"; + case SLICE_TYPE_P: + return "P"; + case SLICE_TYPE_B: + return "B"; + default: + return "Unknown"; + } +} + +#if HAVE_OLD_H264_ENCODER + +static gboolean +set_sequence_parameters( + GstVaapiEncoderH264 *encoder, + VAEncSequenceParameterBufferH264 *seq_param +) +{ + seq_param->seq_parameter_set_id = 0; + seq_param->level_idc = encoder->level; /* 3.0 */ + seq_param->intra_period = encoder->intra_period; + seq_param->intra_idr_period = encoder->intra_period; + seq_param->max_num_ref_frames = 1; /*Only I, P frames*/ + seq_param->picture_width_in_mbs = (ENCODER_WIDTH(encoder)+15)/16; + seq_param->picture_height_in_mbs = (ENCODER_HEIGHT(encoder)+15)/16; + + seq_param->bits_per_second = encoder->bitrate * 1024; + seq_param->frame_rate = ENCODER_FPS(encoder); + seq_param->initial_qp = encoder->init_qp; /*qp_value; 15, 24, 26?*/ + seq_param->min_qp = encoder->min_qp; /*1, 6, 10*/ + seq_param->basic_unit_size = 0; + seq_param->vui_flag = FALSE; + + return TRUE; +} + +static gboolean +set_picture_parameters( + GstVaapiEncoderH264 *encoder, + VAEncPictureParameterBufferH264 *pic_param, + VABufferID coded_buf +) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + + pic_param->reference_picture = GST_VAAPI_OBJECT_ID(priv->ref_surface1); + pic_param->reconstructed_picture = GST_VAAPI_OBJECT_ID(priv->recon_surface); + pic_param->coded_buf = coded_buf; + pic_param->picture_width = ENCODER_WIDTH(encoder); + pic_param->picture_height = ENCODER_HEIGHT(encoder); + pic_param->last_picture = 0; // last pic or not + + return TRUE; +} + +static gboolean +set_slices_parameters( + GstVaapiEncoderH264 *encoder, + VAEncSliceParameterBuffer *slices, + guint slice_num +) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + VAEncSliceParameterBuffer *slice_param; + + int i = 0; + guint32 last_row_num = 0; + guint32 slice_mod_num = priv->slice_mod_mb_num; + + for (i = 0; i < slice_num; ++i) { + slice_param = &slices[i]; + slice_param->start_row_number = last_row_num; /* unit MB*/ + slice_param->slice_height = priv->default_slice_height; /* unit MB */ + if (slice_mod_num) { + ++slice_param->slice_height; + --slice_mod_num; + } + last_row_num += slice_param->slice_height; + slice_param->slice_flags.bits.is_intra = + (priv->cur_slice_type == SLICE_TYPE_I); + slice_param->slice_flags.bits.disable_deblocking_filter_idc = FALSE; + slice_param->slice_flags.bits.uses_long_term_ref = FALSE; + slice_param->slice_flags.bits.is_long_term_ref = FALSE; + } + + ENCODER_ASSERT(last_row_num == (ENCODER_HEIGHT(encoder)+15)/16); + return TRUE; +} + +#else /* extended libva, new parameter structures*/ + +static gboolean +set_sequence_parameters( + GstVaapiEncoderH264 *encoder, + VAEncSequenceParameterBufferH264 *seq_param +) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + guint width_in_mbs, height_in_mbs; + + width_in_mbs = (ENCODER_WIDTH(encoder)+15)/16; + height_in_mbs = (ENCODER_HEIGHT(encoder)+15)/16; + + seq_param->seq_parameter_set_id = 0; + seq_param->level_idc = encoder->level; /* 3.0 */ + seq_param->intra_period = encoder->intra_period; + seq_param->ip_period = 0; // ? + if (encoder->bitrate> 0) + seq_param->bits_per_second = encoder->bitrate * 1024; + else + seq_param->bits_per_second = 0; + + seq_param->max_num_ref_frames = + (encoder->b_frame_num < 2 ? 3 : encoder->b_frame_num+1); // ?, why 4 + seq_param->picture_width_in_mbs = width_in_mbs; + seq_param->picture_height_in_mbs = height_in_mbs; + + /*sequence field values*/ + seq_param->seq_fields.value = 0; + seq_param->seq_fields.bits.chroma_format_idc = 1; + seq_param->seq_fields.bits.frame_mbs_only_flag = 1; + seq_param->seq_fields.bits.mb_adaptive_frame_field_flag = FALSE; + seq_param->seq_fields.bits.seq_scaling_matrix_present_flag = FALSE; + /* direct_8x8_inference_flag default false */ + seq_param->seq_fields.bits.direct_8x8_inference_flag = FALSE; + seq_param->seq_fields.bits.log2_max_frame_num_minus4 = 4; // log2(seq.intra_period)-3 : 0 + /* picture order count */ + seq_param->seq_fields.bits.pic_order_cnt_type = 0; + seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = + seq_param->seq_fields.bits.log2_max_frame_num_minus4 + 2; + seq_param->seq_fields.bits.delta_pic_order_always_zero_flag = TRUE; + + priv->max_frame_num = + 1<<(seq_param->seq_fields.bits.log2_max_frame_num_minus4 + 4); + priv->max_pic_order_cnt = + 1 <<(seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 + 4); + + seq_param->bit_depth_luma_minus8 = 0; + seq_param->bit_depth_chroma_minus8 = 0; + + /* not used if pic_order_cnt_type == 0 */ + seq_param->num_ref_frames_in_pic_order_cnt_cycle = 0; + seq_param->offset_for_non_ref_pic = 0; + seq_param->offset_for_top_to_bottom_field = 0; + memset(seq_param->offset_for_ref_frame, + 0, + sizeof(seq_param->offset_for_ref_frame)); + + if (height_in_mbs*16 - ENCODER_HEIGHT(encoder)) { + seq_param->frame_cropping_flag = 1; + seq_param->frame_crop_left_offset = 0; + seq_param->frame_crop_right_offset = 0; + seq_param->frame_crop_top_offset = 0; + seq_param->frame_crop_bottom_offset = + ((height_in_mbs * 16 - ENCODER_HEIGHT(encoder))/ + (2 * (!seq_param->seq_fields.bits.frame_mbs_only_flag + 1))); + } +#if 0 + if (h264_encoder->init_qp == -1) + seq.rate_control_method = BR_CBR; + else if (h264_encoder->init_qp == -2) + seq.rate_control_method = BR_VBR; + else { + ENCODER_ASSERT(h264_encoder->init_qp >= 0 && h264_encoder->init_qp <= 51); + seq.rate_control_method = BR_CQP; + } +#endif + + /*vui not set*/ + seq_param->vui_parameters_present_flag = (encoder->bitrate> 0 ? TRUE : FALSE); + if (seq_param->vui_parameters_present_flag) { + seq_param->vui_fields.bits.aspect_ratio_info_present_flag = FALSE; + seq_param->vui_fields.bits.bitstream_restriction_flag = FALSE; + seq_param->vui_fields.bits.timing_info_present_flag = (encoder->bitrate> 0 ? TRUE : FALSE); + if (seq_param->vui_fields.bits.timing_info_present_flag) { + seq_param->num_units_in_tick = 100; + seq_param->time_scale = ENCODER_FPS(encoder)*2*100; + } + } + return TRUE; +} + +static gboolean +ensure_packed_sps_data( + GstVaapiEncoderH264 *encoder, + VAEncSequenceParameterBufferH264 *seq_param +) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 }; + VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder); + VAContextID context_id = ENCODER_VA_CONTEXT(encoder); + guint32 length_in_bits; + guint8 *packed_seq_buffer = NULL; + H264Bitstream bitstream; + gboolean ret = TRUE; + VAStatus va_status = VA_STATUS_SUCCESS; + + if (priv->sps_data) + return TRUE; + + h264_bitstream_init(&bitstream, 128*8); + h264_bitstream_write_uint(&bitstream, 0x00000001, 32); /* start code*/ + h264_bitstream_write_nal_header(&bitstream, NAL_REF_IDC_HIGH, NAL_SPS); + h264_bitstream_write_sps(&bitstream, seq_param, encoder->profile); + ENCODER_ASSERT(BIT_STREAM_BIT_SIZE(&bitstream)%8 == 0); + length_in_bits = BIT_STREAM_BIT_SIZE(&bitstream); + packed_seq_buffer = BIT_STREAM_BUFFER(&bitstream); + + /* set codec data sps */ + priv->sps_data = gst_buffer_new_and_alloc((length_in_bits+7)/8); + GST_BUFFER_SIZE(priv->sps_data) = (length_in_bits+7)/8-4; /* start code size == 4*/ + memcpy(GST_BUFFER_DATA(priv->sps_data), + packed_seq_buffer+4, + GST_BUFFER_SIZE(priv->sps_data)); + + packed_header_param_buffer.type = VAEncPackedHeaderSequence; + packed_header_param_buffer.bit_length = length_in_bits; + packed_header_param_buffer.has_emulation_bytes = 0; + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncPackedHeaderParameterBufferType, + sizeof(packed_header_param_buffer), 1, + &packed_header_param_buffer, + &priv->packed_seq_param_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + FALSE, + "EncPackedSeqHeaderParameterBuffer failed"); + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncPackedHeaderDataBufferType, + (length_in_bits + 7) / 8, 1, + packed_seq_buffer, + &priv->packed_seq_data_id); + h264_bitstream_destroy(&bitstream, TRUE); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + FALSE, + "EncPackedSeqHeaderDataBuffer failed"); +end: + return ret; + +} + +static gboolean +set_picture_parameters( + GstVaapiEncoderH264 *encoder, + VAEncPictureParameterBufferH264 *pic_param, + VABufferID coded_buf +) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + + pic_param->pic_parameter_set_id = 0; + pic_param->seq_parameter_set_id = 0; + pic_param->last_picture = 0; /* means last encoding picture */ + pic_param->frame_num = (priv->cur_slice_type == SLICE_TYPE_B ? + (priv->cur_decode_num + 1) : priv->cur_decode_num); + //pic_param.coding_type = 0; + pic_param->pic_init_qp = encoder->init_qp; + pic_param->num_ref_idx_l0_active_minus1 = 0; /* only 1 reference */ + pic_param->num_ref_idx_l1_active_minus1 = 0; /* B frames only have 1 backward and 1 forward reference*/ + pic_param->chroma_qp_index_offset = 0; + pic_param->second_chroma_qp_index_offset = 0; + + /* set picture fields */ + pic_param->pic_fields.value = 0; + pic_param->pic_fields.bits.idr_pic_flag = (priv->cur_slice_type == SLICE_TYPE_I); + pic_param->pic_fields.bits.reference_pic_flag = (priv->cur_slice_type != SLICE_TYPE_B); + pic_param->pic_fields.bits.entropy_coding_mode_flag = ENTROPY_MODE_CABAC; + pic_param->pic_fields.bits.weighted_pred_flag = FALSE; + pic_param->pic_fields.bits.weighted_bipred_idc = 0; + pic_param->pic_fields.bits.constrained_intra_pred_flag = 0; + pic_param->pic_fields.bits.transform_8x8_mode_flag = TRUE; /* enable 8x8 */ + pic_param->pic_fields.bits.deblocking_filter_control_present_flag = TRUE; /* enable debloking */ + pic_param->pic_fields.bits.redundant_pic_cnt_present_flag = FALSE; + /* bottom_field_pic_order_in_frame_present_flag */ + pic_param->pic_fields.bits.pic_order_present_flag = FALSE; + pic_param->pic_fields.bits.pic_scaling_matrix_present_flag = FALSE; + + /* reference list, */ + pic_param->CurrPic.picture_id = GST_VAAPI_OBJECT_ID(priv->recon_surface); + pic_param->CurrPic.TopFieldOrderCnt = priv->cur_display_num * 2; // ??? /**/ + pic_param->ReferenceFrames[0].picture_id = GST_VAAPI_OBJECT_ID(priv->ref_surface1); + pic_param->ReferenceFrames[1].picture_id = GST_VAAPI_OBJECT_ID(priv->ref_surface2); + pic_param->ReferenceFrames[2].picture_id = VA_INVALID_ID; + pic_param->coded_buf = coded_buf; + + ENCODER_LOG_INFO("type:%s, frame_num:%d, display_num:%d", + get_slice_type(priv->cur_slice_type), + pic_param->frame_num, + pic_param->CurrPic.TopFieldOrderCnt); + return TRUE; +} + +static gboolean +ensure_packed_pps_data( + GstVaapiEncoderH264 *encoder, + VAEncPictureParameterBufferH264 *pic_param +) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 }; + H264Bitstream bitstream; + VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder); + VAContextID context_id = ENCODER_VA_CONTEXT(encoder); + guint32 length_in_bits; + guint8 *packed_pic_buffer = NULL; + gboolean ret = TRUE; + VAStatus va_status = VA_STATUS_SUCCESS; + + if (VA_INVALID_ID != priv->packed_pic_data_id) + return TRUE; + + h264_bitstream_init(&bitstream, 128*8); + h264_bitstream_write_uint(&bitstream, 0x00000001, 32); /* start code*/ + h264_bitstream_write_nal_header(&bitstream, NAL_REF_IDC_HIGH, NAL_PPS); + h264_bitstream_write_pps(&bitstream, pic_param); + ENCODER_ASSERT(BIT_STREAM_BIT_SIZE(&bitstream)%8 == 0); + length_in_bits = BIT_STREAM_BIT_SIZE(&bitstream); + packed_pic_buffer = BIT_STREAM_BUFFER(&bitstream); + + /*set codec data pps*/ + priv->pps_data = gst_buffer_new_and_alloc((length_in_bits+7)/8); + GST_BUFFER_SIZE(priv->pps_data) = (length_in_bits+7)/8-4; + memcpy(GST_BUFFER_DATA(priv->pps_data), + packed_pic_buffer+4, + GST_BUFFER_SIZE(priv->pps_data)); + + packed_header_param_buffer.type = VAEncPackedHeaderPicture; + packed_header_param_buffer.bit_length = length_in_bits; + packed_header_param_buffer.has_emulation_bytes = 0; + + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncPackedHeaderParameterBufferType, + sizeof(packed_header_param_buffer), 1, + &packed_header_param_buffer, + &priv->packed_pic_param_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + FALSE, + "EncPackedPicHeaderParameterBuffer failed"); + + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncPackedHeaderDataBufferType, + (length_in_bits + 7) / 8, 1, + packed_pic_buffer, + &priv->packed_pic_data_id); + h264_bitstream_destroy(&bitstream, TRUE); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + FALSE, + "EncPackedPicHeaderDataBuffer failed"); +end: + return ret; +} + +static gboolean +set_slices_parameters( + GstVaapiEncoderH264 *encoder, + VAEncSliceParameterBufferH264 *slices, + guint slice_num +) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + VAEncSliceParameterBufferH264 *slice_param; + + guint width_in_mbs = (ENCODER_WIDTH(encoder)+15)/16; + int i = 0; + guint32 last_row_num = 0; + guint32 slice_mod_num = priv->slice_mod_mb_num; + + for (i = 0; i < slice_num; ++i) { + int i_pic = 0; + slice_param = slices + i; + + slice_param->macroblock_address = last_row_num*width_in_mbs; + slice_param->num_macroblocks = width_in_mbs*priv->default_slice_height; + last_row_num += priv->default_slice_height; + if (slice_mod_num) { + slice_param->num_macroblocks += width_in_mbs; + ++last_row_num; + --slice_mod_num; + } + slice_param->macroblock_info = VA_INVALID_ID; + slice_param->slice_type = priv->cur_slice_type; + slice_param->pic_parameter_set_id = 0; + slice_param->idr_pic_id = priv->idr_num; + slice_param->pic_order_cnt_lsb = + (priv->cur_display_num*2) % priv->max_pic_order_cnt; + + /* not used if pic_order_cnt_type = 0 */ + slice_param->delta_pic_order_cnt_bottom = 0; + memset(slice_param->delta_pic_order_cnt, + 0, + sizeof(slice_param->delta_pic_order_cnt)); + + /*only works for B frames*/ + slice_param->direct_spatial_mv_pred_flag = FALSE; + /* default equal to picture parameters */ + slice_param->num_ref_idx_active_override_flag = FALSE; + slice_param->num_ref_idx_l0_active_minus1 = 0; + slice_param->num_ref_idx_l1_active_minus1 = 0; + + slice_param->RefPicList0[0].picture_id = + GST_VAAPI_OBJECT_ID(priv->ref_surface1); + for (i_pic = 1; + i_pic < sizeof(slice_param->RefPicList0)/sizeof(slice_param->RefPicList0[0]); + i_pic++) { + slice_param->RefPicList0[i_pic].picture_id = VA_INVALID_ID; + } + + if (SLICE_TYPE_B == priv->cur_slice_type) { + slice_param->RefPicList1[0].picture_id = + GST_VAAPI_OBJECT_ID(priv->ref_surface2); + i_pic = 1; + } else + i_pic = 0; + for (; + i_pic < sizeof(slice_param->RefPicList1)/sizeof(slice_param->RefPicList1[0]); + i_pic++) + slice_param->RefPicList1[i_pic].picture_id = VA_INVALID_ID; + + /* not used if pic_param.pic_fields.bits.weighted_pred_flag == FALSE */ + slice_param->luma_log2_weight_denom = 0; + slice_param->chroma_log2_weight_denom = 0; + slice_param->luma_weight_l0_flag = FALSE; + memset(slice_param->luma_weight_l0, 0, sizeof(slice_param->luma_weight_l0)); + memset(slice_param->luma_offset_l0, 0, sizeof(slice_param->luma_offset_l0)); + slice_param->chroma_weight_l0_flag = FALSE; + memset(slice_param->chroma_weight_l0, 0, sizeof(slice_param->chroma_weight_l0)); + memset(slice_param->chroma_offset_l0, 0, sizeof(slice_param->chroma_offset_l0)); + slice_param->luma_weight_l1_flag = FALSE; + memset(slice_param->luma_weight_l1, 0, sizeof(slice_param->luma_weight_l1)); + memset(slice_param->luma_offset_l1, 0, sizeof(slice_param->luma_offset_l1)); + slice_param->chroma_weight_l1_flag = FALSE; + memset(slice_param->chroma_weight_l1, 0, sizeof(slice_param->chroma_weight_l1)); + memset(slice_param->chroma_offset_l1, 0, sizeof(slice_param->chroma_offset_l1)); + + slice_param->cabac_init_idc = 0; + slice_param->slice_qp_delta = encoder->init_qp - encoder->min_qp; + if (slice_param->slice_qp_delta > 4) + slice_param->slice_qp_delta = 4; + slice_param->disable_deblocking_filter_idc = 0; + slice_param->slice_alpha_c0_offset_div2 = 2; + slice_param->slice_beta_offset_div2 = 2; + + } + ENCODER_ASSERT(last_row_num == (ENCODER_HEIGHT(encoder)+15)/16); + return TRUE; +} + +static gboolean +h264_fill_hdr_buffer(GstVaapiEncoderH264 *encoder) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + VAEncMiscParameterBuffer *misc_param; + VAEncMiscParameterHRD *misc_hrd_param; + VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder); + VAContextID context_id = ENCODER_VA_CONTEXT(encoder); + gboolean ret = TRUE; + VAStatus va_status = VA_STATUS_SUCCESS; + + if (VA_INVALID_ID != priv->misc_param_hdr_id) { + vaDestroyBuffer(va_dpy, priv->misc_param_hdr_id); + priv->misc_param_hdr_id = VA_INVALID_ID; + } + + /* hrd parameter */ + va_status = vaCreateBuffer( + va_dpy, + context_id, + VAEncMiscParameterBufferType, + sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterRateControl), + 1, + NULL, + &priv->misc_param_hdr_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + FALSE, + "vaCreateEncMiscParameterBuffer failed"); + + va_status = vaMapBuffer(va_dpy, + priv->misc_param_hdr_id, + (void **)&misc_param); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + FALSE, + "H264 HDR buffer map failed"); + misc_param->type = VAEncMiscParameterTypeHRD; + misc_hrd_param = (VAEncMiscParameterHRD *)misc_param->data; + + if (encoder->bitrate > 0) { + misc_hrd_param->initial_buffer_fullness = encoder->bitrate * 1024 * 4; + misc_hrd_param->buffer_size = encoder->bitrate * 1024 * 8; + } else { + misc_hrd_param->initial_buffer_fullness = 0; + misc_hrd_param->buffer_size = 0; + } + + vaUnmapBuffer(va_dpy, priv->misc_param_hdr_id); + +end: + return ret; +} +#endif + +static gboolean +h264_fill_sequence_buffer(GstVaapiEncoderH264 *encoder) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + VAEncSequenceParameterBufferH264 seq_param = { 0 }; + VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder); + VAContextID context_id = ENCODER_VA_CONTEXT(encoder); + gboolean ret = TRUE; + VAStatus va_status = VA_STATUS_SUCCESS; + + /* only once */ + if (VA_INVALID_ID != priv->seq_param_id) + return TRUE; + + set_sequence_parameters(encoder, &seq_param); + va_status = vaCreateBuffer(va_dpy, context_id, + VAEncSequenceParameterBufferType, + sizeof(seq_param), 1, + &seq_param, &priv->seq_param_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + FALSE, + "alloc seq-buffer failed."); + +#if !HAVE_OLD_H264_ENCODER + ensure_packed_sps_data(encoder, &seq_param); +#endif + +end: + return ret; +} + +static gboolean +h264_fill_picture_buffer( + GstVaapiEncoderH264 *encoder, + VABufferID coded_buf +) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + VAEncPictureParameterBufferH264 pic_param; + VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder); + VAContextID context_id = ENCODER_VA_CONTEXT(encoder); + gboolean ret = TRUE; + VAStatus va_status = VA_STATUS_SUCCESS; + + VAAPI_UNUSED_ARG(va_status); + memset(&pic_param, 0, sizeof(pic_param)); + set_picture_parameters(encoder, &pic_param, coded_buf); + + if (VA_INVALID_ID != priv->pic_param_id) { /* share the same pic_param_id*/ + vaDestroyBuffer(va_dpy, priv->pic_param_id); + priv->pic_param_id = VA_INVALID_ID; + } + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncPictureParameterBufferType, + sizeof(pic_param), 1, + &pic_param, + &priv->pic_param_id); + + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + FALSE, + "creating pic-param buffer failed."); +#if !HAVE_OLD_H264_ENCODER + ensure_packed_pps_data(encoder, &pic_param); +#endif + +end: + return ret; +} + +static gboolean +h264_fill_slice_buffers( + GstVaapiEncoderH264 *encoder +) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder); + VAContextID context_id = ENCODER_VA_CONTEXT(encoder); + gboolean ret = TRUE; + VAStatus va_status = VA_STATUS_SUCCESS; + + memset(priv->slice_param_buffers, + 0, + encoder->slice_num * sizeof(priv->slice_param_buffers[0])); + set_slices_parameters(encoder, + priv->slice_param_buffers, + encoder->slice_num); + + if (VA_INVALID_ID != priv->slice_param_id) { + vaDestroyBuffer(va_dpy, priv->slice_param_id); + priv->slice_param_id = VA_INVALID_ID; + } + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncSliceParameterBufferType, + sizeof(priv->slice_param_buffers[0]), + encoder->slice_num, + priv->slice_param_buffers, + &priv->slice_param_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + FALSE, + "creating slice-parameters buffer failed."); + +end: + return ret; +} + +static EncoderStatus +gst_vaapi_encoder_h264_rendering( + GstVaapiBaseEncoder *base, + GstVaapiSurface *surface, + guint frame_index, + VABufferID coded_buf, + gboolean *is_key +) +{ + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiEncoderH264 *encoder = GST_VAAPI_ENCODER_H264_CAST(base); + GstVaapiEncoderH264Private *priv = encoder->priv; + GstVaapiContext *context = ENCODER_CONTEXT(base); + VABufferID va_buffers[64]; + guint32 va_buffers_count = 0; + gboolean is_params_ok = TRUE; + + ENCODER_ASSERT(context); + + *is_key = (priv->cur_slice_type == SLICE_TYPE_I); + + if (!priv->ref_surface1) { + priv->ref_surface1 = gst_vaapi_context_get_surface(context); + ENCODER_CHECK_STATUS(priv->ref_surface1, + ENCODER_SURFACE_ERR, + "reference surface, h264_pop_free_surface failed."); + } + if (!priv->ref_surface2) { + priv->ref_surface2 = gst_vaapi_context_get_surface(context); + ENCODER_CHECK_STATUS(priv->ref_surface2, + ENCODER_SURFACE_ERR, + "reference surface, h264_pop_free_surface failed."); + } + if (!priv->recon_surface) { + priv->recon_surface = gst_vaapi_context_get_surface(context); + ENCODER_CHECK_STATUS(priv->recon_surface, + ENCODER_SURFACE_ERR, + "reconstructed surface, h264_pop_free_surface failed."); + } + + if (SLICE_TYPE_P == priv->cur_slice_type) { + h264_swap_surface(&priv->ref_surface1, &priv->ref_surface2); + } + + /* fill sequence parameters, need set every time */ + is_params_ok = h264_fill_sequence_buffer(encoder); + ENCODER_CHECK_STATUS(is_params_ok, + ENCODER_PARAMETER_ERR, + "h264_recreate_seq_param failed"); + /* set pic_parameters*/ + is_params_ok = h264_fill_picture_buffer(encoder, coded_buf); + ENCODER_CHECK_STATUS(is_params_ok, + ENCODER_PARAMETER_ERR, + "h264_recreate_pic_param failed"); + +#if !HAVE_OLD_H264_ENCODER + /* set misc_hdr_parameters*/ + is_params_ok = h264_fill_hdr_buffer(encoder); + ENCODER_CHECK_STATUS(is_params_ok, + ENCODER_PARAMETER_ERR, + "h264_fill_hdr__param failed"); +#endif + + /* set slice parameters, support multiple slices */ + is_params_ok = h264_fill_slice_buffers(encoder); + ENCODER_CHECK_STATUS(is_params_ok, + ENCODER_PARAMETER_ERR, + "h264_recreate_slice_param failed"); + + /*render all buffers*/ + if (VA_INVALID_ID != priv->seq_param_id) { + #if HAVE_OLD_H264_ENCODER + if (!priv->is_seq_param_set) { + priv->is_seq_param_set = TRUE; + va_buffers[va_buffers_count++] = priv->seq_param_id; + } + #else + va_buffers[va_buffers_count++] = priv->seq_param_id; + #endif + } + if (VA_INVALID_ID != priv->pic_param_id) { + va_buffers[va_buffers_count++] = priv->pic_param_id; + } + if (VA_INVALID_ID != priv->misc_param_hdr_id) { + va_buffers[va_buffers_count++] = priv->misc_param_hdr_id; + } + if (VA_INVALID_ID != priv->slice_param_id) { + va_buffers[va_buffers_count++] = priv->slice_param_id; + } + if (SLICE_TYPE_I == priv->cur_slice_type) { + if (VA_INVALID_ID != priv->packed_seq_param_id) { + va_buffers[va_buffers_count++] = priv->packed_seq_param_id; + } + if (VA_INVALID_ID != priv->packed_seq_data_id) { + va_buffers[va_buffers_count++] = priv->packed_seq_data_id; + } + if (VA_INVALID_ID != priv->packed_pic_param_id) { + va_buffers[va_buffers_count++] = priv->packed_pic_param_id; + } + if (VA_INVALID_ID != priv->packed_pic_data_id) { + va_buffers[va_buffers_count++] = priv->packed_pic_data_id; + } + } + ret = gst_vaapi_encoder_render_picture(GST_VAAPI_ENCODER_CAST(encoder), + surface, + va_buffers, + va_buffers_count); + ENCODER_CHECK_STATUS(ret == ENCODER_NO_ERROR, + ENCODER_PICTURE_ERR, + "vaRenderH264Picture failed."); + + /*after finished, swap recon and surface2*/ + if (SLICE_TYPE_P == priv->cur_slice_type || + SLICE_TYPE_I == priv->cur_slice_type) { + h264_swap_surface(&priv->recon_surface, &priv->ref_surface2); + } + + end: + return ret; +} + +static const guint8 * +h264_next_nal(const guint8 *buffer, guint32 len, guint32 *nal_size) +{ + const guint8 *cur = buffer; + const guint8 *end = buffer + len; + const guint8 *nal_start = NULL; + guint32 flag = 0xFFFFFFFF; + guint32 nal_start_len = 0; + + ENCODER_ASSERT(len >= 0 && buffer && nal_size); + if (len < 3) { + *nal_size = len; + nal_start = (len ? buffer : NULL); + return nal_start; + } + + /*locate head postion*/ + if (!buffer[0] && !buffer[1]) { + if (buffer[2] == 1) { // 0x000001 + nal_start_len = 3; + } else if (!buffer[2] && len >=4 && buffer[3] == 1) { //0x00000001 + nal_start_len = 4; + } + } + nal_start = buffer + nal_start_len; + cur = nal_start; + + /*find next nal start position*/ + while (cur < end) { + flag = ((flag<<8) | ((*cur++)&0xFF)); + if ((flag&0x00FFFFFF) == 0x00000001) { + if (flag == 0x00000001) + *nal_size = cur - 4 - nal_start; + else + *nal_size = cur - 3 - nal_start; + break; + } + } + if (cur >= end) { + *nal_size = end - nal_start; + if (nal_start >= end) { + nal_start = NULL; + } + } + return nal_start; +} + +static GstBuffer * +gst_vaapi_encoder_h264_wrap_buffer( + GstVaapiBaseEncoder *base, + GstBuffer *buf +) +{ + GstVaapiEncoderH264 *encoder = GST_VAAPI_ENCODER_H264_CAST(base); + GstVaapiEncoderH264Private *priv = encoder->priv; + GstBuffer *ret_buffer; + guint32 nal_size; + const guint8 *nal_start; + guint8 *frame_end; + H264Bitstream bitstream; + + if (!priv->avc_flag) { + gst_buffer_ref(buf); + return buf; + } + + ret_buffer = gst_buffer_new(); + ENCODER_ASSERT(ret_buffer); + h264_bitstream_init(&bitstream, (GST_BUFFER_SIZE(buf)+32)*8); + h264_bitstream_align(&bitstream, 0); + ENCODER_ASSERT(bitstream.bit_size == 0); + + + frame_end = GST_BUFFER_DATA(buf) + GST_BUFFER_SIZE(buf); + nal_start = GST_BUFFER_DATA(buf); + nal_size = 0; + while(NULL != + (nal_start = h264_next_nal(nal_start, frame_end-nal_start, &nal_size)) + ) { + ENCODER_ASSERT(nal_size); + if (!nal_size) { + nal_start += nal_size; + continue; + } + h264_bitstream_write_uint(&bitstream, nal_size, 32); + h264_bitstream_write_byte_array(&bitstream, nal_start, nal_size); + nal_start += nal_size; + } + h264_bitstream_align(&bitstream, 0); + + GST_BUFFER_MALLOCDATA(ret_buffer) = + GST_BUFFER_DATA(ret_buffer) = BIT_STREAM_BUFFER(&bitstream); + GST_BUFFER_SIZE(ret_buffer) = BIT_STREAM_BIT_SIZE(&bitstream)/8; + h264_bitstream_destroy(&bitstream, FALSE); + + return ret_buffer; +} + +static EncoderStatus +read_sps_pps(GstVaapiEncoderH264Private *priv, const guint8 *buf, guint32 size) +{ + const guint8 *end = buf + size; + const guint8 *nal_start = buf; + guint32 nal_size = 0; + guint8 nal_type; + GstBuffer *sps = NULL, *pps = NULL; + + while((!sps || !pps) && + (nal_start = h264_next_nal(nal_start, end-nal_start, &nal_size)) != NULL + ) { + if (!nal_size) { + nal_start += nal_size; + continue; + } + + nal_type = (*nal_start)&0x1F; + switch (nal_type) { + case NAL_SPS: { + sps = gst_buffer_new_and_alloc(nal_size); + memcpy(GST_BUFFER_DATA(sps), nal_start, nal_size); + gst_buffer_replace(&priv->sps_data, sps); + gst_buffer_unref(sps); /*don't set to NULL*/ + break; + } + + case NAL_PPS: { + pps = gst_buffer_new_and_alloc(nal_size); + memcpy(GST_BUFFER_DATA(pps), nal_start, nal_size); + gst_buffer_replace(&priv->pps_data, pps); + gst_buffer_unref(pps); + break; + } + + default: + break; + } + nal_start += nal_size; + } + + if (!sps || !pps) { + return ENCODER_DATA_NOT_READY; + } + + return ENCODER_NO_ERROR; +} + +static void +gst_vaapi_encoder_h264_notify_frame( + GstVaapiBaseEncoder *base, + guint8 *buf, + guint32 size +) +{ + GstVaapiEncoderH264 *encoder = GST_VAAPI_ENCODER_H264_CAST(base); + GstVaapiEncoderH264Private *priv = encoder->priv; + if (!priv->sps_data || !priv->pps_data) { + read_sps_pps(priv, buf, size); + } + if (priv->sps_data && priv->pps_data) { + gst_vaapi_base_encoder_set_frame_notify(base, FALSE); + } +} + +static gboolean +read_sps_attributes( + const guint8 *sps_data, + guint32 sps_size, + guint32 *profile_idc, + guint32 *profile_comp, + guint32 *level_idc +) +{ + ENCODER_ASSERT(profile_idc && profile_comp && level_idc); + ENCODER_ASSERT(sps_size >= 4); + if (sps_size < 4) { + return FALSE; + } + /*skip sps_data[0], nal_type*/ + *profile_idc = sps_data[1]; + *profile_comp = sps_data[2]; + *level_idc = sps_data[3]; + return TRUE; +} + +static EncoderStatus +gst_vaapi_encoder_h264_flush( + GstVaapiEncoder* base +) +{ + GstVaapiEncoderH264* encoder = GST_VAAPI_ENCODER_H264_CAST(base); + EncoderStatus ret = ENCODER_NO_ERROR; + GstVaapiEncoderH264Private *priv = encoder->priv; + + //priv->frame_count = 0; + priv->cur_display_num = 0; + priv->cur_decode_num = 0; + priv->cur_slice_type = SLICE_TYPE_I; + priv->gop_count = g_queue_get_length(priv->queued_buffers); + //gst_vaapi_base_encoder_set_frame_notify((GST_VAAPI_BASE_ENCODER)encoder, TRUE); + + //end: + return ret; +} + +static EncoderStatus +gst_vaapi_encoder_h264_get_avcC_codec_data( + GstVaapiEncoderH264 *encoder, + GstBuffer **buffer +) +{ + GstVaapiEncoderH264Private *priv = encoder->priv; + GstBuffer *avc_codec; + const guint32 configuration_version = 0x01; + const guint32 length_size_minus_one = 0x03; + guint32 profile, profile_comp, level_idc; + + ENCODER_ASSERT(buffer); + if (!priv->sps_data || !priv->pps_data) { + return ENCODER_DATA_NOT_READY; + } + + if (FALSE == read_sps_attributes(GST_BUFFER_DATA(priv->sps_data), + GST_BUFFER_SIZE(priv->sps_data), + &profile, &profile_comp, &level_idc)) + { + ENCODER_ASSERT(0); + return ENCODER_DATA_ERR; + } + + H264Bitstream bitstream; + h264_bitstream_init(&bitstream, + (GST_BUFFER_SIZE(priv->sps_data) + + GST_BUFFER_SIZE(priv->pps_data) + 32)*8); + + /*codec_data*/ + h264_bitstream_write_uint(&bitstream, configuration_version, 8); + h264_bitstream_write_uint(&bitstream, profile, 8); + h264_bitstream_write_uint(&bitstream, profile_comp, 8); + h264_bitstream_write_uint(&bitstream, level_idc, 8); + h264_bitstream_write_uint(&bitstream, h264_bit_mask[6], 6); /*111111*/ + h264_bitstream_write_uint(&bitstream, length_size_minus_one, 2); + h264_bitstream_write_uint(&bitstream, h264_bit_mask[3], 3); /*111*/ + + /*write sps*/ + h264_bitstream_write_uint(&bitstream, 1, 5); /* sps count = 1*/ + ENCODER_ASSERT( BIT_STREAM_BIT_SIZE(&bitstream)%8 == 0); + h264_bitstream_write_uint(&bitstream, GST_BUFFER_SIZE(priv->sps_data), 16); + h264_bitstream_write_byte_array(&bitstream, + GST_BUFFER_DATA(priv->sps_data), + GST_BUFFER_SIZE(priv->sps_data)); + + /*write pps*/ + h264_bitstream_write_uint(&bitstream, 1, 8); /*pps count = 1*/ + h264_bitstream_write_uint(&bitstream, GST_BUFFER_SIZE(priv->pps_data), 16); + h264_bitstream_write_byte_array(&bitstream, + GST_BUFFER_DATA(priv->pps_data), + GST_BUFFER_SIZE(priv->pps_data)); + + avc_codec = gst_buffer_new(); + GST_BUFFER_MALLOCDATA(avc_codec) = + GST_BUFFER_DATA(avc_codec) = + BIT_STREAM_BUFFER(&bitstream); + GST_BUFFER_SIZE(avc_codec) = BIT_STREAM_BIT_SIZE(&bitstream)/8; + h264_bitstream_destroy(&bitstream, FALSE); + *buffer = avc_codec; + + return ENCODER_NO_ERROR; +} + +static EncoderStatus +gst_vaapi_encoder_h264_get_codec_data( + GstVaapiEncoder* base, + GstBuffer **buffer) +{ + GstVaapiEncoderH264 *encoder = GST_VAAPI_ENCODER_H264_CAST(base); + GstVaapiEncoderH264Private *priv = encoder->priv; + + if (priv->avc_flag) + return gst_vaapi_encoder_h264_get_avcC_codec_data(encoder, buffer); + return ENCODER_NO_DATA; +} + +static void +gst_vaapi_encoder_h264_init(GstVaapiEncoderH264 *encoder) +{ + GstVaapiEncoderH264Private *priv = GST_VAAPI_ENCODER_H264_GET_PRIVATE(encoder); + ENCODER_ASSERT(priv); + priv->public = encoder; + encoder->priv = priv; + + /* init public attributes */ + gst_vaapi_encoder_h264_init_public_values(encoder); + gst_vaapi_base_encoder_set_frame_notify(GST_VAAPI_BASE_ENCODER(encoder), TRUE); + + /* init private values*/ + priv->format = GST_MAKE_FOURCC('N','V','1','2'); + priv->avc_flag = FALSE; + + priv->ref_surface1 = NULL; + priv->ref_surface2 = NULL; + priv->recon_surface = NULL; + + priv->seq_param_id = VA_INVALID_ID; + priv->pic_param_id = VA_INVALID_ID; + priv->slice_param_id = VA_INVALID_ID; + priv->misc_param_hdr_id = VA_INVALID_ID; + priv->packed_seq_param_id = VA_INVALID_ID; + priv->packed_seq_data_id = VA_INVALID_ID; + priv->packed_pic_param_id = VA_INVALID_ID; + priv->packed_pic_data_id = VA_INVALID_ID; + priv->is_seq_param_set = FALSE; + priv->slice_param_buffers = NULL; + priv->default_slice_height = 0; + priv->slice_mod_mb_num = 0; + + priv->sps_data = NULL; + priv->pps_data = NULL; + + priv->queued_buffers = g_queue_new(); + priv->gop_count = 0; + priv->cur_display_num = 0; + priv->cur_decode_num = 0; + priv->cur_slice_type = SLICE_TYPE_I; + priv->last_decode_time = 0LL; + priv->default_cts_offset = 0; + + priv->max_frame_num = 0; + priv->max_pic_order_cnt = 0; + priv->idr_num = 0; +} + +static void +gst_vaapi_encoder_h264_finalize(GObject *object) +{ + /*free private buffers*/ + GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object); + GstVaapiEncoderH264Private *priv = GST_VAAPI_ENCODER_H264_GET_PRIVATE(object); + + if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) { + gst_vaapi_encoder_uninitialize(encoder); + } + + if (priv->sps_data) { + gst_buffer_unref(priv->sps_data); + priv->sps_data = NULL; + } + if (priv->pps_data) { + gst_buffer_unref(priv->pps_data); + priv->pps_data = NULL; + } + if (priv->slice_param_buffers) { + g_free(priv->slice_param_buffers); + priv->slice_param_buffers = NULL; + } + + if (priv->queued_buffers) { + ENCODER_ASSERT(g_queue_is_empty(priv->queued_buffers)); + g_queue_free(priv->queued_buffers); + priv->queued_buffers = NULL; + } + + G_OBJECT_CLASS(gst_vaapi_encoder_h264_parent_class)->finalize(object); +} + +static void +gst_vaapi_encoder_h264_class_init(GstVaapiEncoderH264Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass); + GstVaapiBaseEncoderClass * const base_class = GST_VAAPI_BASE_ENCODER_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiEncoderH264Private)); + + GST_DEBUG_CATEGORY_INIT (gst_vaapi_h264_encoder_debug, + "gst_va_h264_encoder", + 0, + "gst_va_h264_encoder element"); + + object_class->finalize = gst_vaapi_encoder_h264_finalize; + + base_class->validate_attributes = gst_vaapi_encoder_h264_validate_attributes; + base_class->pre_alloc_resource = gst_vaapi_encoder_h264_alloc_slices; + base_class->release_resource = gst_vaapi_encoder_h264_release_resource; + base_class->prepare_next_input_buffer = + gst_vaapi_encoder_h264_prepare_next_buffer; + base_class->render_frame = gst_vaapi_encoder_h264_rendering; + base_class->notify_buffer = gst_vaapi_encoder_h264_notify_frame; + base_class->wrap_buffer = gst_vaapi_encoder_h264_wrap_buffer; + base_class->encode_frame_failed = gst_vaapi_encoder_h264_frame_failed; + + encoder_class->flush = gst_vaapi_encoder_h264_flush; + encoder_class->get_codec_data = gst_vaapi_encoder_h264_get_codec_data; +} + +static void +h264_bitstream_init(H264Bitstream *bitstream, guint32 bit_capability) +{ + bitstream->bit_size = 0; + bitstream->buffer = NULL; + bitstream->max_bit_capability = 0; + if (bit_capability) { + h264_bitstream_auto_grow(bitstream, bit_capability); + } +} + +static gboolean +h264_bitstream_write_uint( + H264Bitstream *bitstream, + guint32 value, + guint32 bit_size +) +{ + gboolean ret = TRUE; + guint32 byte_pos, bit_offset; + guint8 *cur_byte; + guint32 fill_bits; + + if(!bit_size) { + return TRUE; + } + + VAAPI_UNUSED_ARG(ret); + ENCODER_CHECK_STATUS(h264_bitstream_auto_grow(bitstream, bit_size), + FALSE, + "h264_bitstream_auto_grow failed."); + byte_pos = (bitstream->bit_size>>3); + bit_offset = (bitstream->bit_size&0x07); + cur_byte = bitstream->buffer + byte_pos; + ENCODER_ASSERT(bit_offset < 8 && + bitstream->bit_size <= bitstream->max_bit_capability); + + while (bit_size) { + fill_bits = ((8-bit_offset) < bit_size ? (8-bit_offset) : bit_size); + bit_size -= fill_bits; + bitstream->bit_size += fill_bits; + + *cur_byte |= + ((value>>bit_size) & h264_bit_mask[fill_bits])<<(8-bit_offset-fill_bits); + ++cur_byte; + bit_offset = 0; + } + ENCODER_ASSERT(cur_byte <= + (bitstream->buffer + bitstream->max_bit_capability/8)); + + end: + return ret; +} + +static gboolean +h264_bitstream_align(H264Bitstream *bitstream, guint32 value) +{ + guint32 bit_offset, bit_left; + + bit_offset = (bitstream->bit_size&0x07); + if (!bit_offset) { + return TRUE; + } + bit_left = 8 - bit_offset; + if (value) value = h264_bit_mask[bit_left]; + return h264_bitstream_write_uint(bitstream, value, bit_left); +} + + +static gboolean +h264_bitstream_write_byte_array( + H264Bitstream *bitstream, + const guint8 *buf, + guint32 byte_size +) +{ + gboolean ret = TRUE; + if (!byte_size) { + return 0; + } + + VAAPI_UNUSED_ARG(ret); + ENCODER_CHECK_STATUS(h264_bitstream_auto_grow(bitstream, byte_size<<3), + FALSE, + "h264_bitstream_auto_grow failed."); + if (0 == (bitstream->bit_size&0x07)) { + memcpy(&bitstream->buffer[bitstream->bit_size>>3], buf, byte_size); + bitstream->bit_size += (byte_size<<3); + } else { + ENCODER_ASSERT(0); + while(byte_size) { + h264_bitstream_write_uint(bitstream, *buf, 8); + --byte_size; + ++buf; + } + } + +end: + return ret; +} + +static gboolean +h264_bitstream_write_ue(H264Bitstream *bitstream, guint32 value) +{ + gboolean ret = TRUE; + guint32 size_in_bits = 0; + guint32 tmp_value = ++value; + while (tmp_value) { + ++size_in_bits; + tmp_value >>= 1; + } + ENCODER_CHECK_STATUS(h264_bitstream_write_uint(bitstream, 0, size_in_bits-1), + FALSE, + "h264_bitstream_write_ue failed."); + ENCODER_CHECK_STATUS(h264_bitstream_write_uint(bitstream, value, size_in_bits), + FALSE, + "h264_bitstream_write_ue failed."); + +end: + return ret; +} + +static gboolean +h264_bitstream_write_se(H264Bitstream *bitstream, gint32 value) +{ + gboolean ret = TRUE; + guint32 new_val; + + if (value <= 0) { + new_val = -(value<<1); + } else { + new_val = (value<<1) - 1; + } + + ENCODER_CHECK_STATUS(h264_bitstream_write_ue(bitstream, new_val), + FALSE, + "h264_bitstream_write_se failed."); + +end: + return ret; +} + +static gboolean +h264_bitstream_write_trailing_bits(H264Bitstream *bitstream) +{ + h264_bitstream_write_uint(bitstream, 1, 1); + h264_bitstream_align(bitstream, 0); + return TRUE; +} + +static void +h264_bitstream_destroy(H264Bitstream *bitstream, gboolean free_flag) +{ + if (bitstream->buffer && free_flag) { + free (bitstream->buffer); + } + bitstream->buffer = NULL; + bitstream->bit_size = 0; + bitstream->max_bit_capability = 0; +} + +static gboolean +h264_bitstream_auto_grow(H264Bitstream *bitstream, guint32 extra_bit_size) +{ + guint32 new_bit_size = extra_bit_size + bitstream->bit_size; + guint32 clear_pos; + + ENCODER_ASSERT(bitstream->bit_size <= bitstream->max_bit_capability); + if (new_bit_size <= bitstream->max_bit_capability) { + return TRUE; + } + + new_bit_size = ((new_bit_size + H264_BITSTREAM_ALLOC_ALIGN_MASK) + &(~H264_BITSTREAM_ALLOC_ALIGN_MASK)); + ENCODER_ASSERT(new_bit_size%(H264_BITSTREAM_ALLOC_ALIGN_MASK+1) == 0); + clear_pos = ((bitstream->bit_size+7)>>3); + bitstream->buffer = realloc(bitstream->buffer, new_bit_size>>3); + memset(bitstream->buffer+clear_pos, 0, (new_bit_size>>3)-clear_pos); + bitstream->max_bit_capability = new_bit_size; + return TRUE; +} + +static gboolean +h264_bitstream_write_nal_header( + H264Bitstream *bitstream, + guint nal_ref_idc, + guint nal_unit_type +) +{ + h264_bitstream_write_uint(bitstream, 0, 1); + h264_bitstream_write_uint(bitstream, nal_ref_idc, 2); + h264_bitstream_write_uint(bitstream, nal_unit_type, 5); + return TRUE; +} + +#if !HAVE_OLD_H264_ENCODER + +static gboolean +h264_bitstream_write_sps( + H264Bitstream *bitstream, + VAEncSequenceParameterBufferH264 *seq, + H264_Profile profile +) +{ + guint32 constraint_set0_flag, constraint_set1_flag; + guint32 constraint_set2_flag, constraint_set3_flag; + guint32 gaps_in_frame_num_value_allowed_flag = 0; // ?? + gboolean nal_hrd_parameters_present_flag; + + guint32 b_qpprime_y_zero_transform_bypass = 0; + guint32 residual_color_transform_flag = 0; + guint32 pic_height_in_map_units = + (seq->seq_fields.bits.frame_mbs_only_flag ? + seq->picture_height_in_mbs : + seq->picture_height_in_mbs/2); + guint32 mb_adaptive_frame_field = !seq->seq_fields.bits.frame_mbs_only_flag; + guint32 i = 0; + + constraint_set0_flag = profile == H264_PROFILE_BASELINE; + constraint_set1_flag = profile <= H264_PROFILE_MAIN; + constraint_set2_flag = 0; + constraint_set3_flag = 0; + + /* profile_idc */ + h264_bitstream_write_uint(bitstream, profile, 8); + /* constraint_set0_flag */ + h264_bitstream_write_uint(bitstream, constraint_set0_flag, 1); + /* constraint_set1_flag */ + h264_bitstream_write_uint(bitstream, constraint_set1_flag, 1); + /* constraint_set2_flag */ + h264_bitstream_write_uint(bitstream, constraint_set2_flag, 1); + /* constraint_set3_flag */ + h264_bitstream_write_uint(bitstream, constraint_set3_flag, 1); + /* reserved_zero_4bits */ + h264_bitstream_write_uint(bitstream, 0, 4); + /* level_idc */ + h264_bitstream_write_uint(bitstream, seq->level_idc, 8); + /* seq_parameter_set_id */ + h264_bitstream_write_ue(bitstream, seq->seq_parameter_set_id); + + if (profile >= H264_PROFILE_HIGH) { + /* for high profile */ + ENCODER_ASSERT(0); + /* chroma_format_idc = 1, 4:2:0*/ + h264_bitstream_write_ue(bitstream, seq->seq_fields.bits.chroma_format_idc); + if (3 == seq->seq_fields.bits.chroma_format_idc) { + h264_bitstream_write_uint(bitstream, residual_color_transform_flag, 1); + } + /* bit_depth_luma_minus8 */ + h264_bitstream_write_ue(bitstream, seq->bit_depth_luma_minus8); + /* bit_depth_chroma_minus8 */ + h264_bitstream_write_ue(bitstream, seq->bit_depth_chroma_minus8); + /* b_qpprime_y_zero_transform_bypass */ + h264_bitstream_write_uint(bitstream, b_qpprime_y_zero_transform_bypass, 1); + ENCODER_ASSERT(seq->seq_fields.bits.seq_scaling_matrix_present_flag == 0); + /*seq_scaling_matrix_present_flag */ + h264_bitstream_write_uint(bitstream, + seq->seq_fields.bits.seq_scaling_matrix_present_flag, + 1); + + #if 0 + if (seq->seq_fields.bits.seq_scaling_matrix_present_flag) { + for (i = 0; i < (seq->seq_fields.bits.chroma_format_idc != 3 ? 8 : 12); i++) { + h264_bitstream_write_uint(bitstream, seq->seq_fields.bits.seq_scaling_list_present_flag, 1); + if (seq->seq_fields.bits.seq_scaling_list_present_flag) { + ENCODER_ASSERT(0); + /* FIXME, need write scaling list if seq_scaling_matrix_present_flag ==1*/ + } + } + } + #endif + } + + /* log2_max_frame_num_minus4 */ + h264_bitstream_write_ue(bitstream, + seq->seq_fields.bits.log2_max_frame_num_minus4); + /* pic_order_cnt_type */ + h264_bitstream_write_ue(bitstream, seq->seq_fields.bits.pic_order_cnt_type); + + if (seq->seq_fields.bits.pic_order_cnt_type == 0) { + /* log2_max_pic_order_cnt_lsb_minus4 */ + h264_bitstream_write_ue(bitstream, + seq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4); + } else if (seq->seq_fields.bits.pic_order_cnt_type == 1) { + ENCODER_ASSERT(0); + h264_bitstream_write_uint(bitstream, + seq->seq_fields.bits.delta_pic_order_always_zero_flag, + 1); + h264_bitstream_write_se(bitstream, seq->offset_for_non_ref_pic); + h264_bitstream_write_se(bitstream, + seq->offset_for_top_to_bottom_field); + h264_bitstream_write_ue(bitstream, + seq->num_ref_frames_in_pic_order_cnt_cycle); + for ( i = 0; i < seq->num_ref_frames_in_pic_order_cnt_cycle; i++) { + h264_bitstream_write_se(bitstream, seq->offset_for_ref_frame[i]); + } + } + + /* num_ref_frames */ + h264_bitstream_write_ue(bitstream, seq->max_num_ref_frames); + /* gaps_in_frame_num_value_allowed_flag */ + h264_bitstream_write_uint(bitstream, + gaps_in_frame_num_value_allowed_flag, + 1); + + /* pic_width_in_mbs_minus1 */ + h264_bitstream_write_ue(bitstream, seq->picture_width_in_mbs - 1); + /* pic_height_in_map_units_minus1 */ + h264_bitstream_write_ue(bitstream, pic_height_in_map_units - 1); + /* frame_mbs_only_flag */ + h264_bitstream_write_uint(bitstream, + seq->seq_fields.bits.frame_mbs_only_flag, + 1); + + if (!seq->seq_fields.bits.frame_mbs_only_flag) { //ONLY mbs + ENCODER_ASSERT(0); + h264_bitstream_write_uint(bitstream, mb_adaptive_frame_field, 1); + } + + /* direct_8x8_inference_flag */ + h264_bitstream_write_uint(bitstream, 0, 1); + /* frame_cropping_flag */ + h264_bitstream_write_uint(bitstream, seq->frame_cropping_flag, 1); + + if (seq->frame_cropping_flag) { + /* frame_crop_left_offset */ + h264_bitstream_write_ue(bitstream, seq->frame_crop_left_offset); + /* frame_crop_right_offset */ + h264_bitstream_write_ue(bitstream, seq->frame_crop_right_offset); + /* frame_crop_top_offset */ + h264_bitstream_write_ue(bitstream, seq->frame_crop_top_offset); + /* frame_crop_bottom_offset */ + h264_bitstream_write_ue(bitstream, seq->frame_crop_bottom_offset); + } + + /* vui_parameters_present_flag */ + h264_bitstream_write_uint(bitstream, seq->vui_parameters_present_flag, 1); + if (seq->vui_parameters_present_flag) { + /* aspect_ratio_info_present_flag */ + h264_bitstream_write_uint(bitstream, + seq->vui_fields.bits.aspect_ratio_info_present_flag, + 1); + if (seq->vui_fields.bits.aspect_ratio_info_present_flag) { + h264_bitstream_write_uint(bitstream, seq->aspect_ratio_idc, 8); + if (seq->aspect_ratio_idc == 0xFF) { + h264_bitstream_write_uint(bitstream, seq->sar_width, 16); + h264_bitstream_write_uint(bitstream, seq->sar_height, 16); + } + } + + /* overscan_info_present_flag */ + h264_bitstream_write_uint(bitstream, 0, 1); + /* video_signal_type_present_flag */ + h264_bitstream_write_uint(bitstream, 0, 1); + /* chroma_loc_info_present_flag */ + h264_bitstream_write_uint(bitstream, 0, 1); + + /* timing_info_present_flag */ + h264_bitstream_write_uint(bitstream, + seq->vui_fields.bits.timing_info_present_flag, + 1); + if (seq->vui_fields.bits.timing_info_present_flag) { + h264_bitstream_write_uint(bitstream, seq->num_units_in_tick, 32); + h264_bitstream_write_uint(bitstream, seq->time_scale, 32); + h264_bitstream_write_uint(bitstream, 1, 1); /* fixed_frame_rate_flag */ + } + + nal_hrd_parameters_present_flag = (seq->bits_per_second > 0 ? TRUE : FALSE); + /* nal_hrd_parameters_present_flag */ + h264_bitstream_write_uint(bitstream, nal_hrd_parameters_present_flag, 1); + if (nal_hrd_parameters_present_flag) { + /* hrd_parameters */ + /* cpb_cnt_minus1 */ + h264_bitstream_write_ue(bitstream, 0); + h264_bitstream_write_uint(bitstream, 4, 4); /* bit_rate_scale */ + h264_bitstream_write_uint(bitstream, 6, 4); /* cpb_size_scale */ + + for (i = 0; i < 1; ++i) { + /* bit_rate_value_minus1[0] */ + h264_bitstream_write_ue(bitstream, seq->bits_per_second/1024- 1); + /* cpb_size_value_minus1[0] */ + h264_bitstream_write_ue(bitstream, seq->bits_per_second/1024*8 - 1); + /* cbr_flag[0] */ + h264_bitstream_write_uint(bitstream, 1, 1); + } + /* initial_cpb_removal_delay_length_minus1 */ + h264_bitstream_write_uint(bitstream, 23, 5); + /* cpb_removal_delay_length_minus1 */ + h264_bitstream_write_uint(bitstream, 23, 5); + /* dpb_output_delay_length_minus1 */ + h264_bitstream_write_uint(bitstream, 23, 5); + /* time_offset_length */ + h264_bitstream_write_uint(bitstream, 23, 5); + } + /* vcl_hrd_parameters_present_flag */ + h264_bitstream_write_uint(bitstream, 0, 1); + if (nal_hrd_parameters_present_flag || 0/*vcl_hrd_parameters_present_flag*/) { + /* low_delay_hrd_flag */ + h264_bitstream_write_uint(bitstream, 0, 1); + } + /* pic_struct_present_flag */ + h264_bitstream_write_uint(bitstream, 0, 1); + /* bitstream_restriction_flag */ + h264_bitstream_write_uint(bitstream, 0, 1); + } + /* rbsp_trailing_bits */ + h264_bitstream_write_trailing_bits(bitstream); + return TRUE; +} + +static gboolean +h264_bitstream_write_pps( + H264Bitstream *bitstream, + VAEncPictureParameterBufferH264 *pic +) +{ + guint32 num_slice_groups_minus1 = 0; + guint32 pic_init_qs_minus26 = 0; + guint32 redundant_pic_cnt_present_flag = 0; + + /* pic_parameter_set_id */ + h264_bitstream_write_ue(bitstream, pic->pic_parameter_set_id); + /* seq_parameter_set_id */ + h264_bitstream_write_ue(bitstream, pic->seq_parameter_set_id); + /* entropy_coding_mode_flag */ + h264_bitstream_write_uint(bitstream, + pic->pic_fields.bits.entropy_coding_mode_flag, + 1); + /* pic_order_present_flag */ + h264_bitstream_write_uint(bitstream, + pic->pic_fields.bits.pic_order_present_flag, + 1); + /*slice_groups-1*/ + h264_bitstream_write_ue(bitstream, num_slice_groups_minus1); + + if (num_slice_groups_minus1 > 0) { + /*FIXME*/ + ENCODER_ASSERT(0); + } + h264_bitstream_write_ue(bitstream, pic->num_ref_idx_l0_active_minus1); + h264_bitstream_write_ue(bitstream, pic->num_ref_idx_l1_active_minus1); + h264_bitstream_write_uint(bitstream, + pic->pic_fields.bits.weighted_pred_flag, + 1); + h264_bitstream_write_uint(bitstream, + pic->pic_fields.bits.weighted_bipred_idc, + 2); + /* pic_init_qp_minus26 */ + h264_bitstream_write_se(bitstream, pic->pic_init_qp-26); + /* pic_init_qs_minus26 */ + h264_bitstream_write_se(bitstream, pic_init_qs_minus26); + /*chroma_qp_index_offset*/ + h264_bitstream_write_se(bitstream, pic->chroma_qp_index_offset); + + h264_bitstream_write_uint(bitstream, + pic->pic_fields.bits.deblocking_filter_control_present_flag, + 1); + h264_bitstream_write_uint(bitstream, + pic->pic_fields.bits.constrained_intra_pred_flag, + 1); + h264_bitstream_write_uint(bitstream, redundant_pic_cnt_present_flag, 1); + + /*more_rbsp_data*/ + h264_bitstream_write_uint(bitstream, + pic->pic_fields.bits.transform_8x8_mode_flag, + 1); + h264_bitstream_write_uint(bitstream, + pic->pic_fields.bits.pic_scaling_matrix_present_flag, + 1); + if (pic->pic_fields.bits.pic_scaling_matrix_present_flag) { + ENCODER_ASSERT(0); + /* FIXME */ + /* + for (i = 0; i < + (6+(-( (chroma_format_idc ! = 3) ? 2 : 6) * -pic->pic_fields.bits.transform_8x8_mode_flag)); + i++) { + h264_bitstream_write_uint(bitstream, pic->pic_fields.bits.pic_scaling_list_present_flag, 1); + } + */ + } + + h264_bitstream_write_se(bitstream, pic->second_chroma_qp_index_offset); + h264_bitstream_write_trailing_bits(bitstream); + return TRUE; +} +#endif diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264.h b/gst-libs/gst/vaapi/gstvaapiencoder_h264.h new file mode 100644 index 0000000..2de9769 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264.h @@ -0,0 +1,143 @@ +/* + * gstvaapiencoder_h264.h - H.264 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_H264_H +#define GST_VAAPI_ENCODER_H264_H + +#include "gst/vaapi/gstvaapisurfacepool.h" +#include "gst/vaapi/gstvaapibaseencoder.h" + +G_BEGIN_DECLS + +typedef struct _GstVaapiEncoderH264 GstVaapiEncoderH264; +typedef struct _GstVaapiEncoderH264Private GstVaapiEncoderH264Private; +typedef struct _GstVaapiEncoderH264Class GstVaapiEncoderH264Class; + +#define GST_TYPE_VAAPI_ENCODER_H264 \ + (gst_vaapi_encoder_h264_get_type()) + +#define GST_IS_VAAPI_ENCODER_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_ENCODER_H264)) + +#define GST_IS_VAAPI_ENCODER_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_ENCODER_H264)) + +#define GST_VAAPI_ENCODER_H264_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GST_TYPE_VAAPI_ENCODER_H264, \ + GstVaapiEncoderH264Class)) + +#define GST_VAAPI_ENCODER_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_VAAPI_ENCODER_H264, \ + GstVaapiEncoderH264)) + +#define GST_VAAPI_ENCODER_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GST_TYPE_VAAPI_ENCODER_H264, \ + GstVaapiEncoderH264Class)) + +#define GST_VAAPI_ENCODER_H264_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_TYPE_VAAPI_ENCODER_H264, \ + GstVaapiEncoderH264Private)) + +typedef enum { + H264_PROFILE_BASELINE = 66, + H264_PROFILE_MAIN = 77, + H264_PROFILE_EXTENDED = 88, + H264_PROFILE_HIGH = 100, + H264_PROFILE_HIGH10 = 110, + H264_PROFILE_HIGH422 = 122, + H264_PROFILE_HIGH444 = 144, + H264_PROFILE_HIGH444_PREDICTIVE = 244, +} H264_Profile; + +typedef enum { + H264_LEVEL_10 = 10, /* QCIF format, < 380160 samples/sec */ + H264_LEVEL_11 = 11, /* CIF format, < 768000 samples/sec */ + H264_LEVEL_12 = 12, /* CIF format, < 1536000 samples/sec */ + H264_LEVEL_13 = 13, /* CIF format, < 3041280 samples/sec */ + H264_LEVEL_20 = 20, /* CIF format, < 3041280 samples/sec */ + H264_LEVEL_21 = 21, /* HHR format, < 5068800 samples/sec */ + H264_LEVEL_22 = 22, /* SD/4CIF format, < 5184000 samples/sec */ + H264_LEVEL_30 = 30, /* SD/4CIF format, < 10368000 samples/sec */ + H264_LEVEL_31 = 31, /* 720pHD format, < 27648000 samples/sec */ + H264_LEVEL_32 = 32, /* SXGA format, < 55296000 samples/sec */ + H264_LEVEL_40 = 40, /* 2Kx1K format, < 62914560 samples/sec */ + H264_LEVEL_41 = 41, /* 2Kx1K format, < 62914560 samples/sec */ + H264_LEVEL_42 = 42, /* 2Kx1K format, < 125829120 samples/sec */ + H264_LEVEL_50 = 50, /* 3672x1536 format, < 150994944 samples/sec */ + H264_LEVEL_51 = 51, /* 4096x2304 format, < 251658240 samples/sec */ +} H264_Level; + +#define H264_DEFAULT_PROFILE H264_PROFILE_BASELINE +#define H264_DEFAULT_LEVEL H264_LEVEL_30 +#define H264_DEFAULT_INIT_QP 26 +#define H264_DEFAULT_MIN_QP 1 +#define H264_DEFAULT_INTRA_PERIOD 30 +#define H264_DEFAULT_FPS 30 +#define H264_DEFAULT_SLICE_NUM 1 + +struct _GstVaapiEncoderH264 { + GstVaapiBaseEncoder parent; /*based on gobject*/ + + GstVaapiEncoderH264Private *priv; + + guint32 profile; + guint32 level; + guint32 bitrate; /*kbps*/ + guint32 intra_period; + guint32 init_qp; /*default 24*/ + guint32 min_qp; /*default 1*/ + guint32 slice_num; + guint32 b_frame_num; +}; + +struct _GstVaapiEncoderH264Class { + GstVaapiBaseEncoderClass parent_class; +}; + + +GType +gst_vaapi_encoder_h264_get_type(void); + +GstVaapiEncoderH264 * +gst_vaapi_encoder_h264_new(void); + +static inline void +gst_vaapi_encoder_h264_unref (GstVaapiEncoderH264 * encoder) +{ + g_object_unref (encoder); +} + +void +gst_vaapi_encoder_h264_set_avc_flag( + GstVaapiEncoderH264* encoder, + gboolean avc +); + +gboolean +gst_vaapi_encoder_h264_get_avc_flag(GstVaapiEncoderH264* encoder); + +G_END_DECLS + +#endif /*GST_VAAPI_ENCODER_H264_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg4.c b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg4.c new file mode 100644 index 0000000..70e08d7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg4.c @@ -0,0 +1,523 @@ +/* + * gstvaapiencoder_mpeg4.c - MPEG-4 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstvaapiencoder_mpeg4.h" + +#include +#include "gst/gstclock.h" + +#include "gstvaapiobject.h" +#include "gstvaapiobject_priv.h" +#include "gstvaapicontext.h" +#include "gstvaapisurface.h" +#include "gstvaapivideobuffer.h" +#include "gstvaapidisplay_priv.h" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_mpeg4_encoder_debug); +#define GST_CAT_DEFAULT gst_vaapi_mpeg4_encoder_debug + +#define GST_VAAPI_ENCODER_MPEG4_CAST(encoder) ((GstVaapiEncoderMpeg4 *)(encoder)) + +#define VISUAL_OBJECT_SEQUENCE_START_CODE 0x000001B0 +#define VISUAL_OBJECT_SEQUENCE_END_CODE 0x000001B1 +#define VISUAL_OBJECT_START_CODE 0x000001B5 +#define VIDEO_OBJECT_PLANE_START_CODE 0x000001B6 +/* Video Object Start Code range */ +#define VIDEO_OBJECT_START_CODE_MIN 0x00000100 +#define VIDEO_OBJECT_START_CODE_MAX 0x0000011F +/* Video Object Layer Start Code range 0x00000120 ~ 0x0000012F*/ +#define VIDEO_OBJECT_LAYER_START_CODE 0x00000120 +#define VIDEO_OBJECT_LAYER_START_CODE_MASK 0xFFFFFFF0 + + +struct _GstVaapiEncoderMpeg4Private { + GstVaapiSurface *ref_surface; /* reference buffer*/ + GstVaapiSurface *recon_surface; /* reconstruct buffer*/ + + VABufferID seq_param_id; + VABufferID pic_param_id; + VABufferID slice_param_id; + + GstBuffer *codec_data; +}; + +G_DEFINE_TYPE(GstVaapiEncoderMpeg4, gst_vaapi_encoder_mpeg4, GST_TYPE_VAAPI_BASE_ENCODER) + +GstVaapiEncoderMpeg4 * +gst_vaapi_encoder_mpeg4_new(void) +{ + return GST_VAAPI_ENCODER_MPEG4_CAST( + g_object_new(GST_TYPE_VAAPI_ENCODER_MPEG4, NULL)); +} + +gboolean +gst_vaapi_encoder_mpeg4_validate_attributes( + GstVaapiBaseEncoder *base +) +{ + GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base); + + if (!ENCODER_WIDTH(encoder) || + !ENCODER_HEIGHT(encoder) || + !ENCODER_FPS(encoder)) { + return FALSE; + } + if (VAProfileMPEG4Simple != encoder->profile && + VAProfileMPEG4AdvancedSimple != encoder->profile) { + return FALSE; + } + gst_vaapi_base_encoder_set_va_profile(base, encoder->profile); + + if (!encoder->intra_period) { + encoder->intra_period = MPEG4_DEFAULT_INTRA_PERIOD; + } + if (-1 == encoder->init_qp) { + encoder->init_qp = MPEG4_DEFAULT_INIT_QP; + } + if (-1 == encoder->min_qp) { + encoder->min_qp = MPEG4_DEFAULT_MIN_QP; + } + + /* default compress ratio 1: (4*8*1.5) */ + if (!encoder->bitrate) { + encoder->bitrate = + ENCODER_WIDTH(encoder)*ENCODER_HEIGHT(encoder)*ENCODER_FPS(encoder)/4/1024; + } + return TRUE; + +} + +static void +mpeg4_release_parameters( + GstVaapiEncoderMpeg4 *encoder +) +{ + GstVaapiEncoderMpeg4Private *priv = encoder->priv; + VADisplay va_dpy = ENCODER_DISPLAY(encoder); + VAStatus va_status = VA_STATUS_SUCCESS; + + VAAPI_UNUSED_ARG(va_status); + + if (VA_INVALID_ID != priv->seq_param_id) { + va_status = vaDestroyBuffer(va_dpy, priv->seq_param_id); + priv->seq_param_id = VA_INVALID_ID; + } + if (VA_INVALID_ID != priv->pic_param_id) { + va_status = vaDestroyBuffer(va_dpy, priv->pic_param_id); + priv->pic_param_id = VA_INVALID_ID; + } + if (VA_INVALID_ID != priv->slice_param_id) { + va_status = vaDestroyBuffer(va_dpy, priv->slice_param_id); + priv->slice_param_id = VA_INVALID_ID; + } +} + +static gboolean +gst_vaapi_encoder_mpeg4_release_resource( + GstVaapiBaseEncoder* base +) +{ + GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base); + GstVaapiEncoderMpeg4Private *priv = encoder->priv; + GstVaapiContext *context = ENCODER_CONTEXT(base); + + mpeg4_release_parameters(encoder); + + /*remove ref_surface*/ + if (priv->ref_surface) { + if (context) { + gst_vaapi_context_put_surface(context, priv->ref_surface); + } else { + g_object_unref(priv->ref_surface); + } + priv->ref_surface = NULL; + } + + /*remove recon_surface*/ + if (priv->recon_surface) { + if (context) { + gst_vaapi_context_put_surface(context, priv->recon_surface); + } else { + g_object_unref(priv->recon_surface); + } + priv->recon_surface = NULL; + } + + if (priv->codec_data) { + gst_buffer_unref(priv->codec_data); + priv->codec_data = NULL; + } + + return TRUE; +} + +static guint32 +mpeg4_get_profile_level_indication(guint32 profile) +{ + switch(profile) { + case VAProfileMPEG4Simple: + return MPEG4_DEFAULT_SIMPLE_PROFILE_AND_LEVEL; + case VAProfileMPEG4AdvancedSimple: + return MPEG4_DEFAULT_ADVANCED_SIMPLE_PROFILE_AND_LEVEL; + default: + return 0; + } + return 0; +} + +static EncoderStatus +gst_vaapi_encoder_mpeg4_rendering( + GstVaapiBaseEncoder *base, + GstVaapiSurface *surface, + guint frame_index, + VABufferID coded_buf, + gboolean *is_key +) +{ + GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base); + GstVaapiEncoderMpeg4Private *priv = encoder->priv; + GstVaapiContext *context = ENCODER_CONTEXT(base); + VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder); + VAContextID context_id = ENCODER_VA_CONTEXT(encoder); + VABufferID va_buffers[64]; + guint32 va_buffers_count = 0; + + VAStatus va_status = VA_STATUS_SUCCESS; + EncoderStatus ret = ENCODER_NO_ERROR; + + *is_key = (frame_index % encoder->intra_period == 0); + + /* initialize sequence parameter set, only first time */ + if (VA_INVALID_ID == priv->seq_param_id) { /*only the first time*/ + VAEncSequenceParameterBufferMPEG4 seq_param = {0}; + + seq_param.profile_and_level_indication = + mpeg4_get_profile_level_indication(encoder->profile); + seq_param.intra_period = encoder->intra_period; + seq_param.video_object_layer_width = ENCODER_WIDTH(encoder); + seq_param.video_object_layer_height = ENCODER_HEIGHT(encoder); + seq_param.vop_time_increment_resolution = ENCODER_FPS(encoder); + seq_param.fixed_vop_rate = MPEG4_DEFAULT_FIXED_VOP_RATE; + if (seq_param.fixed_vop_rate) { + seq_param.fixed_vop_time_increment = 1; + } + seq_param.bits_per_second = encoder->bitrate * 1024; + seq_param.frame_rate = ENCODER_FPS(encoder); + seq_param.initial_qp = encoder->init_qp; + seq_param.min_qp = encoder->min_qp; //mpeg4_encoder->min_qp; + + va_status = vaCreateBuffer(va_dpy, context_id, + VAEncSequenceParameterBufferType, + sizeof(seq_param), 1, + &seq_param, + &priv->seq_param_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + ENCODER_ENC_RES_ERR, + "mpeg4 alloc seq-buffer failed."); + va_buffers[va_buffers_count++] = priv->seq_param_id; + } + + /* set reference and reconstructed surfaces */ + if (!priv->ref_surface) { + priv->ref_surface = gst_vaapi_context_get_surface(context); + ENCODER_CHECK_STATUS(priv->ref_surface, + ENCODER_SURFACE_ERR, + "mpeg4 reference surface, mpeg4_pop_free_surface failed."); + } + if (!priv->recon_surface) { + priv->recon_surface = gst_vaapi_context_get_surface(context); + ENCODER_CHECK_STATUS(priv->recon_surface, + ENCODER_SURFACE_ERR, + "mpeg4 reconstructed surface, mpeg4_pop_free_surface failed."); + } + + /* initialize picture, every time, every frame */ + VAEncPictureParameterBufferMPEG4 pic_param = {0}; + pic_param.reference_picture = GST_VAAPI_OBJECT_ID(priv->ref_surface); + pic_param.reconstructed_picture = GST_VAAPI_OBJECT_ID(priv->recon_surface); + pic_param.coded_buf = coded_buf; + pic_param.picture_width = ENCODER_WIDTH(encoder); + pic_param.picture_height = ENCODER_HEIGHT(encoder); + if (0 == frame_index) { + pic_param.modulo_time_base = 0; + } else { + pic_param.modulo_time_base = + ((frame_index%ENCODER_FPS(encoder)) == 0 ? 1 : 0); + } + pic_param.vop_time_increment = 301%ENCODER_FPS(encoder); + pic_param.picture_type = + (*is_key ? VAEncPictureTypeIntra : VAEncPictureTypePredictive); + + if (VA_INVALID_ID != priv->pic_param_id) { /* destroy first*/ + va_status = vaDestroyBuffer(va_dpy, priv->pic_param_id); + priv->pic_param_id = VA_INVALID_ID; + } + + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncPictureParameterBufferType, + sizeof(pic_param), 1, + &pic_param, + &priv->pic_param_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, + ENCODER_ENC_RES_ERR, + "mpeg4 creating pic-param buffer failed."); + + va_buffers[va_buffers_count++] = priv->pic_param_id; + + /*initialize slice parameters, only ONE slice for mpeg4*/ + VAEncSliceParameterBuffer slice_param = { 0 }; + slice_param.start_row_number = 0; + slice_param.slice_height = (ENCODER_HEIGHT(encoder)+15)/16; /*MB?*/ + slice_param.slice_flags.bits.is_intra = *is_key; + slice_param.slice_flags.bits.disable_deblocking_filter_idc = 0; + if (VA_INVALID_ID != priv->slice_param_id) { + vaDestroyBuffer(va_dpy, priv->slice_param_id); + priv->slice_param_id = VA_INVALID_ID; + } + + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncSliceParameterBufferType, + sizeof(slice_param), + 1, + &slice_param, + &priv->slice_param_id); + ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, + ENCODER_ENC_RES_ERR, + "mpeg4 creating slice-parameters buffer failed."); + + va_buffers[va_buffers_count++] = priv->slice_param_id; + + ret = gst_vaapi_encoder_render_picture(GST_VAAPI_ENCODER_CAST(encoder), + surface, + va_buffers, + va_buffers_count); + ENCODER_CHECK_STATUS(ret == ENCODER_NO_ERROR, + ENCODER_PICTURE_ERR, + "mpeg4 rendering slice-parameters buffer failed."); + + /*swap ref_surface and recon_surface */ + GstVaapiSurface *swap = priv->ref_surface; + priv->ref_surface = priv->recon_surface; + priv->recon_surface = swap; + +end: + return ret; +} + +#if 0 +static GstBuffer * +gst_vaapi_encoder_mpeg4_copy_coded_buffer(GstVaapiBaseEncoder *encoder, + guint8 *frame, guint32 frame_size, VABufferID *coded_buf) + +{ + /*process data*/ + GstBuffer* buffer = gst_buffer_new_and_alloc(frame_size); + memcpy(GST_BUFFER_DATA(buffer), frame, frame_size); + + #if 0 + GstVaapiEncoderMpeg4 *mpeg4_encoder = GST_VAAPI_ENCODER_MPEG4_CAST(encoder); + if (mpeg4_encoder->profile == VAProfileMPEG4AdvancedSimple) { + guint8 *start_code = GST_BUFFER_DATA(buffer)+16; /*fix old issue of ASP in mrst platform*/ + if (start_code[0] == 0x01 && start_code[1] == 0x20 + && start_code[-1] == 0x00 && start_code[-2] == 0x00) + { + start_code[2] = 0x08; + } + } + #endif + + return buffer; +} +#endif + +static gboolean +find_video_object_configuration_info( + const guint8 *in_buffer, + guint32 in_size, + const guint8 **out_buffer, + guint32 *out_size +) +{ + guint32 value = 0x00; + const guint8 *end = in_buffer + in_size; + + while(in_buffer < end) { + value = ((value<<8)|(*in_buffer)); + if (VISUAL_OBJECT_SEQUENCE_START_CODE == value) { + *out_buffer = in_buffer - 3; + ++in_buffer; + break; + } + ++in_buffer; + } + if (in_buffer >= end) + return FALSE; + + while(in_buffer < end) { + value = ((value<<8)|(*in_buffer)); + if (VIDEO_OBJECT_PLANE_START_CODE == value) { + *out_size = (in_buffer - 3 - *out_buffer); + return TRUE; + } + ++in_buffer; + } + return FALSE; +} + +static gboolean +mpeg4_encoder_generate_codec_data( + const guint8 *in_buffer, + guint32 in_size, + GstBuffer **out_buffer +) +{ + const guint8 *codec_buffer = NULL; + guint32 codec_size = 0; + guint8 *visual_obj_seq_end = NULL; + + if (!find_video_object_configuration_info(in_buffer, + in_size, + &codec_buffer, + &codec_size) + ) { + return FALSE; + } + ENCODER_ASSERT(codec_size); + *out_buffer = gst_buffer_new_and_alloc(codec_size+4); + memcpy(GST_BUFFER_DATA(*out_buffer), codec_buffer, codec_size); + visual_obj_seq_end = GST_BUFFER_DATA(*out_buffer) + codec_size; + visual_obj_seq_end[0] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>24); + visual_obj_seq_end[1] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>16); + visual_obj_seq_end[2] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>8); + visual_obj_seq_end[3] = (guint8)VISUAL_OBJECT_SEQUENCE_END_CODE; + return TRUE; +} + +static void +gst_vaapi_encoder_mpeg4_notify_frame( + GstVaapiBaseEncoder *base, + guint8 *buf, + guint32 size +) +{ + GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base); + GstVaapiEncoderMpeg4Private *priv = encoder->priv; + if (!priv->codec_data) { + if (!mpeg4_encoder_generate_codec_data(buf, size, &priv->codec_data)) { + ENCODER_LOG_ERROR("mpeg4 encoder coded data error," + "please check ."); + } + } + if (priv->codec_data) { + gst_vaapi_base_encoder_set_frame_notify(base, FALSE); + } +} + +static EncoderStatus +gst_vaapi_encoder_mpeg4_flush( + GstVaapiEncoder* base +) +{ + GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base); + + mpeg4_release_parameters(encoder); + return ENCODER_NO_ERROR; +} + +static EncoderStatus +gst_vaapi_encoder_mpeg4_get_codec_data( + GstVaapiEncoder *base, + GstBuffer **buffer +) +{ + GstVaapiEncoderMpeg4 *encoder = GST_VAAPI_ENCODER_MPEG4_CAST(base); + GstVaapiEncoderMpeg4Private *priv = encoder->priv; + + if (!priv->codec_data) + return ENCODER_DATA_NOT_READY; + *buffer = gst_buffer_ref(priv->codec_data); + return ENCODER_NO_ERROR; +} + +static void +gst_vaapi_encoder_mpeg4_init(GstVaapiEncoderMpeg4 *encoder) +{ + GstVaapiEncoderMpeg4Private *priv = GST_VAAPI_ENCODER_MPEG4_GET_PRIVATE(encoder); + ENCODER_ASSERT(priv); + encoder->priv = priv; + + /* init public */ + encoder->profile = VAProfileMPEG4Simple; + encoder->bitrate = 0; + encoder->intra_period = MPEG4_DEFAULT_INTRA_PERIOD; + encoder->init_qp = MPEG4_DEFAULT_INIT_QP; + encoder->min_qp = MPEG4_DEFAULT_MIN_QP; + + gst_vaapi_base_encoder_set_frame_notify(GST_VAAPI_BASE_ENCODER(encoder), TRUE); + /* init private */ + priv->ref_surface = NULL; + priv->recon_surface = NULL; + + priv->seq_param_id = VA_INVALID_ID; + priv->pic_param_id = VA_INVALID_ID; + priv->slice_param_id = VA_INVALID_ID; + + priv->codec_data = NULL; +} + +static void +gst_vaapi_encoder_mpeg4_finalize(GObject *object) +{ + /*free private buffers*/ + GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object); + + if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) { + gst_vaapi_encoder_uninitialize(encoder); + } + G_OBJECT_CLASS(gst_vaapi_encoder_mpeg4_parent_class)->finalize(object); +} + +static void +gst_vaapi_encoder_mpeg4_class_init(GstVaapiEncoderMpeg4Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass); + GstVaapiBaseEncoderClass * const base_class = GST_VAAPI_BASE_ENCODER_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiEncoderMpeg4Private)); + + GST_DEBUG_CATEGORY_INIT (gst_vaapi_mpeg4_encoder_debug, "gst_va_mpeg4_encoder", 0, + "gst_va_mpeg4_encoder element"); + + object_class->finalize = gst_vaapi_encoder_mpeg4_finalize; + + base_class->validate_attributes = gst_vaapi_encoder_mpeg4_validate_attributes; + base_class->pre_alloc_resource = NULL; + base_class->release_resource = gst_vaapi_encoder_mpeg4_release_resource; + base_class->render_frame = gst_vaapi_encoder_mpeg4_rendering; + base_class->notify_buffer = gst_vaapi_encoder_mpeg4_notify_frame; + base_class->wrap_buffer = NULL; + + encoder_class->flush = gst_vaapi_encoder_mpeg4_flush; + encoder_class->get_codec_data = gst_vaapi_encoder_mpeg4_get_codec_data; +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_mpeg4.h b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg4.h new file mode 100644 index 0000000..62e7c89 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiencoder_mpeg4.h @@ -0,0 +1,103 @@ +/* + * gstvaapiencoder_mpeg4.h - MPEG-4 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODER_MPEG4_H +#define GST_VAAPI_ENCODER_MPEG4_H + +#include "gst/vaapi/gstvaapisurfacepool.h" +#include "gst/vaapi/gstvaapibaseencoder.h" + +G_BEGIN_DECLS + +#define MPEG4_DEFAULT_INTRA_PERIOD 30 +#define MPEG4_DEFAULT_INIT_QP 15 +#define MPEG4_DEFAULT_MIN_QP 1 +#define MPEG4_DEFAULT_SIMPLE_PROFILE_AND_LEVEL 0x03 +#define MPEG4_DEFAULT_ADVANCED_SIMPLE_PROFILE_AND_LEVEL 0xF3 + +#define MPEG4_DEFAULT_FIXED_VOP_RATE FALSE + + +typedef struct _GstVaapiEncoderMpeg4 GstVaapiEncoderMpeg4; +typedef struct _GstVaapiEncoderMpeg4Private GstVaapiEncoderMpeg4Private; +typedef struct _GstVaapiEncoderMpeg4Class GstVaapiEncoderMpeg4Class; + + +#define GST_TYPE_VAAPI_ENCODER_MPEG4 \ + (gst_vaapi_encoder_mpeg4_get_type()) + +#define GST_IS_VAAPI_ENCODER_MPEG4(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_ENCODER_MPEG4)) + +#define GST_IS_VAAPI_ENCODER_MPEG4_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_ENCODER_MPEG4)) + +#define GST_VAAPI_ENCODER_MPEG4_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GST_TYPE_VAAPI_ENCODER_MPEG4, \ + GstVaapiEncoderMpeg4Class)) + +#define GST_VAAPI_ENCODER_MPEG4(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_VAAPI_ENCODER_MPEG4, \ + GstVaapiEncoderMpeg4)) + +#define GST_VAAPI_ENCODER_MPEG4_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GST_TYPE_VAAPI_ENCODER_MPEG4, \ + GstVaapiEncoderMpeg4Class)) + +#define GST_VAAPI_ENCODER_MPEG4_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_TYPE_VAAPI_ENCODER_MPEG4, \ + GstVaapiEncoderMpeg4Private)) + +struct _GstVaapiEncoderMpeg4 { + GstVaapiBaseEncoder parent; /*based on gobject*/ + VAProfile profile; /* VAProfileMPEG4Simple, VAProfileMPEG4AdvancedSimple */ + guint32 bitrate; + guint32 intra_period; + guint32 init_qp; /*default 15, 1~31*/ + guint32 min_qp; /*default 1, 1~31*/ + + GstVaapiEncoderMpeg4Private *priv; +}; + +struct _GstVaapiEncoderMpeg4Class { + GstVaapiBaseEncoderClass parent_class; +}; + +GType +gst_vaapi_encoder_mpeg4_get_type(void); + +GstVaapiEncoderMpeg4 * +gst_vaapi_encoder_mpeg4_new(void); + +static inline void +gst_vaapi_encoder_mpeg4_unref (GstVaapiEncoderMpeg4 * encoder) +{ + g_object_unref (encoder); +} + + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODER_MPEG4_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiimage.c b/gst-libs/gst/vaapi/gstvaapiimage.c new file mode 100644 index 0000000..d4e9306 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiimage.c @@ -0,0 +1,1698 @@ +/* + * gstvaapiimage.c - VA image abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiimage + * @short_description: VA image abstraction + */ + +#include "sysdeps.h" +#include +#include "gst/gstutils.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapiimage.h" +#include "gstvaapi_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiImage, gst_vaapi_image, GST_VAAPI_TYPE_OBJECT); + +#define GST_VAAPI_IMAGE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_IMAGE, \ + GstVaapiImagePrivate)) + +struct _GstVaapiImagePrivate { + VAImage internal_image; + VAImage image; + guchar *image_data; + GstVaapiImageFormat internal_format; + GstVaapiImageFormat format; + guint width; + guint height; + guint create_image : 1; + guint is_constructed : 1; + guint is_linear : 1; +}; + +enum { + PROP_0, + + PROP_IMAGE, + PROP_FORMAT, + PROP_WIDTH, + PROP_HEIGHT +}; + +#define SWAP_UINT(a, b) do { \ + guint v = a; \ + a = b; \ + b = v; \ + } while (0) + +static gboolean +_gst_vaapi_image_map(GstVaapiImage *image, GstVaapiImageRaw *raw_image); + +static gboolean +_gst_vaapi_image_unmap(GstVaapiImage *image); + +static gboolean +_gst_vaapi_image_set_image(GstVaapiImage *image, const VAImage *va_image); + +/* + * VAImage wrapper + */ + +#define VAAPI_TYPE_IMAGE vaapi_image_get_type() + +static gpointer +vaapi_image_copy(gpointer va_image) +{ + return g_slice_dup(VAImage, va_image); +} + +static void +vaapi_image_free(gpointer va_image) +{ + if (G_LIKELY(va_image)) + g_slice_free(VAImage, va_image); +} + +static GType +vaapi_image_get_type(void) +{ + static GType type = 0; + + if (G_UNLIKELY(type == 0)) + type = g_boxed_type_register_static( + "VAImage", + vaapi_image_copy, + vaapi_image_free + ); + return type; +} + +static gboolean +vaapi_image_is_linear(const VAImage *va_image) +{ + guint i, width, height, width2, height2, data_size; + + for (i = 1; i < va_image->num_planes; i++) + if (va_image->offsets[i] < va_image->offsets[i - 1]) + return FALSE; + + width = va_image->width; + height = va_image->height; + width2 = (width + 1) / 2; + height2 = (height + 1) / 2; + + switch (va_image->format.fourcc) { + case VA_FOURCC('N','V','1','2'): + case VA_FOURCC('Y','V','1','2'): + case VA_FOURCC('I','4','2','0'): + data_size = width * height + 2 * width2 * height2; + break; + case VA_FOURCC('A','Y','U','V'): + case VA_FOURCC('A','R','G','B'): + case VA_FOURCC('R','G','B','A'): + case VA_FOURCC('A','B','G','R'): + case VA_FOURCC('B','G','R','A'): + data_size = 4 * width * height; + break; + default: + g_error("FIXME: incomplete formats"); + break; + } + return va_image->data_size == data_size; +} + +static void +gst_vaapi_image_destroy(GstVaapiImage *image) +{ + GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(image); + VAImageID image_id; + VAStatus status; + + _gst_vaapi_image_unmap(image); + + image_id = GST_VAAPI_OBJECT_ID(image); + GST_DEBUG("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(image_id)); + + if (image_id != VA_INVALID_ID) { + GST_VAAPI_DISPLAY_LOCK(display); + status = vaDestroyImage(GST_VAAPI_DISPLAY_VADISPLAY(display), image_id); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaDestroyImage()")) + g_warning("failed to destroy image %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS(image_id)); + GST_VAAPI_OBJECT_ID(image) = VA_INVALID_ID; + } +} + +static gboolean +_gst_vaapi_image_create(GstVaapiImage *image, GstVaapiImageFormat format) +{ + GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(image); + GstVaapiImagePrivate * const priv = image->priv; + const VAImageFormat *va_format; + VAStatus status; + + if (!gst_vaapi_display_has_image_format(display, format)) + return FALSE; + + va_format = gst_vaapi_image_format_get_va_format(format); + if (!va_format) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaCreateImage( + GST_VAAPI_DISPLAY_VADISPLAY(display), + (VAImageFormat *)va_format, + priv->width, + priv->height, + &priv->internal_image + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (status != VA_STATUS_SUCCESS || + priv->internal_image.format.fourcc != va_format->fourcc) + return FALSE; + + priv->internal_format = format; + return TRUE; +} + +static gboolean +gst_vaapi_image_create(GstVaapiImage *image) +{ + GstVaapiImagePrivate * const priv = image->priv; + GstVaapiImageFormat format = priv->format; + const VAImageFormat *va_format; + VAImageID image_id; + + if (!priv->create_image) + return (priv->image.image_id != VA_INVALID_ID && + priv->image.buf != VA_INVALID_ID); + + if (!_gst_vaapi_image_create(image, format)) { + switch (format) { + case GST_VAAPI_IMAGE_I420: + format = GST_VAAPI_IMAGE_YV12; + break; + case GST_VAAPI_IMAGE_YV12: + format = GST_VAAPI_IMAGE_I420; + break; + default: + format = 0; + break; + } + if (!format || !_gst_vaapi_image_create(image, format)) + return FALSE; + } + priv->image = priv->internal_image; + image_id = priv->image.image_id; + + if (priv->format != priv->internal_format) { + switch (priv->format) { + case GST_VAAPI_IMAGE_YV12: + case GST_VAAPI_IMAGE_I420: + va_format = gst_vaapi_image_format_get_va_format(priv->format); + if (!va_format) + return FALSE; + priv->image.format = *va_format; + SWAP_UINT(priv->image.offsets[1], priv->image.offsets[2]); + SWAP_UINT(priv->image.pitches[1], priv->image.pitches[2]); + break; + default: + break; + } + } + priv->is_linear = vaapi_image_is_linear(&priv->image); + + GST_DEBUG("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(image_id)); + GST_VAAPI_OBJECT_ID(image) = image_id; + return TRUE; +} + +static void +gst_vaapi_image_finalize(GObject *object) +{ + gst_vaapi_image_destroy(GST_VAAPI_IMAGE(object)); + + G_OBJECT_CLASS(gst_vaapi_image_parent_class)->finalize(object); +} + +static void +gst_vaapi_image_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiImage * const image = GST_VAAPI_IMAGE(object); + GstVaapiImagePrivate * const priv = image->priv; + + switch (prop_id) { + case PROP_IMAGE: { + const VAImage * const va_image = g_value_get_boxed(value); + if (va_image) + _gst_vaapi_image_set_image(image, va_image); + break; + } + case PROP_FORMAT: + if (priv->create_image) + priv->format = g_value_get_uint(value); + break; + case PROP_WIDTH: + if (priv->create_image) + priv->width = g_value_get_uint(value); + break; + case PROP_HEIGHT: + if (priv->create_image) + priv->height = g_value_get_uint(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_image_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiImage * const image = GST_VAAPI_IMAGE(object); + + switch (prop_id) { + case PROP_IMAGE: + g_value_set_boxed(value, &image->priv->image); + break; + case PROP_FORMAT: + g_value_set_uint(value, gst_vaapi_image_get_format(image)); + break; + case PROP_WIDTH: + g_value_set_uint(value, gst_vaapi_image_get_width(image)); + break; + case PROP_HEIGHT: + g_value_set_uint(value, gst_vaapi_image_get_height(image)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_image_constructed(GObject *object) +{ + GstVaapiImage * const image = GST_VAAPI_IMAGE(object); + GObjectClass *parent_class; + + image->priv->is_constructed = gst_vaapi_image_create(image); + + parent_class = G_OBJECT_CLASS(gst_vaapi_image_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static void +gst_vaapi_image_class_init(GstVaapiImageClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiImagePrivate)); + + object_class->finalize = gst_vaapi_image_finalize; + object_class->set_property = gst_vaapi_image_set_property; + object_class->get_property = gst_vaapi_image_get_property; + object_class->constructed = gst_vaapi_image_constructed; + + g_object_class_install_property + (object_class, + PROP_IMAGE, + g_param_spec_boxed("image", + "Image", + "The underlying VA image", + VAAPI_TYPE_IMAGE, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, + PROP_WIDTH, + g_param_spec_uint("width", + "width", + "The image width", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, + PROP_HEIGHT, + g_param_spec_uint("height", + "heighr", + "The image height", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + /** + * GstVaapiImage:format: + * + * The #GstVaapiImageFormat of the image + */ + g_object_class_install_property + (object_class, + PROP_FORMAT, + g_param_spec_uint("format", + "Format", + "The underlying image format", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gst_vaapi_image_init(GstVaapiImage *image) +{ + GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image); + + image->priv = priv; + priv->image_data = NULL; + priv->width = 0; + priv->height = 0; + priv->internal_format = 0; + priv->format = 0; + priv->create_image = TRUE; + priv->is_constructed = FALSE; + priv->is_linear = FALSE; + + memset(&priv->internal_image, 0, sizeof(priv->internal_image)); + priv->internal_image.image_id = VA_INVALID_ID; + priv->internal_image.buf = VA_INVALID_ID; + + memset(&priv->image, 0, sizeof(priv->image)); + priv->image.image_id = VA_INVALID_ID; + priv->image.buf = VA_INVALID_ID; +} + +/** + * gst_vaapi_image_new: + * @display: a #GstVaapiDisplay + * @format: a #GstVaapiImageFormat + * @width: the requested image width + * @height: the requested image height + * + * Creates a new #GstVaapiImage with the specified format and + * dimensions. + * + * Return value: the newly allocated #GstVaapiImage object + */ +GstVaapiImage * +gst_vaapi_image_new( + GstVaapiDisplay *display, + GstVaapiImageFormat format, + guint width, + guint height +) +{ + GstVaapiImage *image; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(width > 0, NULL); + g_return_val_if_fail(height > 0, NULL); + + GST_DEBUG("format %" GST_FOURCC_FORMAT ", size %ux%u", + GST_FOURCC_ARGS(format), width, height); + + image = g_object_new( + GST_VAAPI_TYPE_IMAGE, + "display", display, + "id", GST_VAAPI_ID(VA_INVALID_ID), + "format", format, + "width", width, + "height", height, + NULL + ); + if (!image) + return NULL; + + if (!image->priv->is_constructed) { + g_object_unref(image); + return NULL; + } + return image; +} + +/** + * gst_vaapi_image_new_with_image: + * @display: a #GstVaapiDisplay + * @va_image: a VA image + * + * Creates a new #GstVaapiImage from a foreign VA image. The image + * format and dimensions will be extracted from @va_image. This + * function is mainly used by gst_vaapi_surface_derive_image() to bind + * a VA image to a #GstVaapiImage object. + * + * Return value: the newly allocated #GstVaapiImage object + */ +GstVaapiImage * +gst_vaapi_image_new_with_image(GstVaapiDisplay *display, VAImage *va_image) +{ + GstVaapiImage *image; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(va_image, NULL); + g_return_val_if_fail(va_image->image_id != VA_INVALID_ID, NULL); + g_return_val_if_fail(va_image->buf != VA_INVALID_ID, NULL); + + GST_DEBUG("VA image 0x%08x, format %" GST_FOURCC_FORMAT ", size %ux%u", + va_image->image_id, + GST_FOURCC_ARGS(va_image->format.fourcc), + va_image->width, va_image->height); + + image = g_object_new( + GST_VAAPI_TYPE_IMAGE, + "display", display, + "id", GST_VAAPI_ID(va_image->image_id), + "image", va_image, + NULL + ); + if (!image) + return NULL; + + if (!image->priv->is_constructed) { + g_object_unref(image); + return NULL; + } + return image; +} + +/** + * gst_vaapi_image_get_id: + * @image: a #GstVaapiImage + * + * Returns the underlying VAImageID of the @image. + * + * Return value: the underlying VA image id + */ +GstVaapiID +gst_vaapi_image_get_id(GstVaapiImage *image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), VA_INVALID_ID); + g_return_val_if_fail(image->priv->is_constructed, VA_INVALID_ID); + + return GST_VAAPI_OBJECT_ID(image); +} + +/** + * gst_vaapi_image_get_image: + * @image: a #GstVaapiImage + * @va_image: a VA image + * + * Fills @va_image with the VA image used internally. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + + if (va_image) + *va_image = image->priv->image; + + return TRUE; +} + +/* + * _gst_vaapi_image_set_image: + * @image: a #GstVaapiImage + * @va_image: a VA image + * + * Initializes #GstVaapiImage with a foreign VA image. This function + * will try to "linearize" the VA image. i.e. making sure that the VA + * image offsets into the data buffer are in increasing order with the + * number of planes available in the image. + * + * This is an internal function used by gst_vaapi_image_new_with_image(). + * + * Return value: %TRUE on success + */ +gboolean +_gst_vaapi_image_set_image(GstVaapiImage *image, const VAImage *va_image) +{ + GstVaapiImagePrivate * const priv = image->priv; + GstVaapiImageFormat format; + VAImage alt_va_image; + const VAImageFormat *alt_va_format; + + if (!va_image) + return FALSE; + + format = gst_vaapi_image_format(&va_image->format); + if (!format) + return FALSE; + + priv->create_image = FALSE; + priv->internal_image = *va_image; + priv->internal_format = format; + priv->is_linear = vaapi_image_is_linear(va_image); + priv->image = *va_image; + priv->format = format; + priv->width = va_image->width; + priv->height = va_image->height; + + /* Try to linearize image */ + if (!priv->is_linear) { + switch (format) { + case GST_VAAPI_IMAGE_I420: + format = GST_VAAPI_IMAGE_YV12; + break; + case GST_VAAPI_IMAGE_YV12: + format = GST_VAAPI_IMAGE_I420; + break; + default: + format = 0; + break; + } + if (format && + (alt_va_format = gst_vaapi_image_format_get_va_format(format))) { + alt_va_image = *va_image; + alt_va_image.format = *alt_va_format; + SWAP_UINT(alt_va_image.offsets[1], alt_va_image.offsets[2]); + SWAP_UINT(alt_va_image.pitches[1], alt_va_image.pitches[2]); + if (vaapi_image_is_linear(&alt_va_image)) { + priv->image = alt_va_image; + priv->format = format; + priv->is_linear = TRUE; + GST_DEBUG("linearized image to %" GST_FOURCC_FORMAT " format", + GST_FOURCC_ARGS(format)); + } + } + } + return TRUE; +} + +/** + * gst_vaapi_image_get_format: + * @image: a #GstVaapiImage + * + * Returns the #GstVaapiImageFormat the @image was created with. + * + * Return value: the #GstVaapiImageFormat + */ +GstVaapiImageFormat +gst_vaapi_image_get_format(GstVaapiImage *image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0); + g_return_val_if_fail(image->priv->is_constructed, 0); + + return image->priv->format; +} + +/** + * gst_vaapi_image_get_width: + * @image: a #GstVaapiImage + * + * Returns the @image width. + * + * Return value: the image width, in pixels + */ +guint +gst_vaapi_image_get_width(GstVaapiImage *image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0); + g_return_val_if_fail(image->priv->is_constructed, 0); + + return image->priv->width; +} + +/** + * gst_vaapi_image_get_height: + * @image: a #GstVaapiImage + * + * Returns the @image height. + * + * Return value: the image height, in pixels. + */ +guint +gst_vaapi_image_get_height(GstVaapiImage *image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0); + g_return_val_if_fail(image->priv->is_constructed, 0); + + return image->priv->height; +} + +/** + * gst_vaapi_image_get_size: + * @image: a #GstVaapiImage + * @pwidth: return location for the width, or %NULL + * @pheight: return location for the height, or %NULL + * + * Retrieves the dimensions of a #GstVaapiImage. + */ +void +gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight) +{ + g_return_if_fail(GST_VAAPI_IS_IMAGE(image)); + g_return_if_fail(image->priv->is_constructed); + + if (pwidth) + *pwidth = image->priv->width; + + if (pheight) + *pheight = image->priv->height; +} + +/** + * gst_vaapi_image_is_linear: + * @image: a #GstVaapiImage + * + * Checks whether the @image has data planes allocated from a single + * buffer and offsets into that buffer are in increasing order with + * the number of planes. + * + * Return value: %TRUE if image data planes are allocated from a single buffer + */ +gboolean +gst_vaapi_image_is_linear(GstVaapiImage *image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + + return image->priv->is_linear; +} + +/** + * gst_vaapi_image_is_mapped: + * @image: a #GstVaapiImage + * + * Checks whether the @image is currently mapped or not. + * + * Return value: %TRUE if the @image is mapped + */ +static inline gboolean +_gst_vaapi_image_is_mapped(GstVaapiImage *image) +{ + return image->priv->image_data != NULL; +} + +gboolean +gst_vaapi_image_is_mapped(GstVaapiImage *image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + + return _gst_vaapi_image_is_mapped(image); +} + +/** + * gst_vaapi_image_map: + * @image: a #GstVaapiImage + * + * Maps the image data buffer. The actual pixels are returned by the + * gst_vaapi_image_get_plane() function. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_map(GstVaapiImage *image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + + return _gst_vaapi_image_map(image, NULL); +} + +gboolean +_gst_vaapi_image_map(GstVaapiImage *image, GstVaapiImageRaw *raw_image) +{ + GstVaapiImagePrivate * const priv = image->priv; + GstVaapiDisplay *display; + void *image_data; + VAStatus status; + guint i; + + if (_gst_vaapi_image_is_mapped(image)) + return TRUE; + + display = GST_VAAPI_OBJECT_DISPLAY(image); + if (!display) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaMapBuffer( + GST_VAAPI_DISPLAY_VADISPLAY(display), + image->priv->image.buf, + &image_data + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaMapBuffer()")) + return FALSE; + + image->priv->image_data = image_data; + + if (raw_image) { + const VAImage * const va_image = &priv->image; + raw_image->format = priv->format; + raw_image->width = va_image->width; + raw_image->height = va_image->height; + raw_image->num_planes = va_image->num_planes; + for (i = 0; i < raw_image->num_planes; i++) { + raw_image->pixels[i] = image_data + va_image->offsets[i]; + raw_image->stride[i] = va_image->pitches[i]; + } + } + return TRUE; +} + +/** + * gst_vaapi_image_unmap: + * @image: a #GstVaapiImage + * + * Unmaps the image data buffer. Pointers to pixels returned by + * gst_vaapi_image_get_plane() are then no longer valid. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_unmap(GstVaapiImage *image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + + return _gst_vaapi_image_unmap(image); +} + +gboolean +_gst_vaapi_image_unmap(GstVaapiImage *image) +{ + GstVaapiDisplay *display; + VAStatus status; + + if (!_gst_vaapi_image_is_mapped(image)) + return FALSE; + + display = GST_VAAPI_OBJECT_DISPLAY(image); + if (!display) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaUnmapBuffer( + GST_VAAPI_DISPLAY_VADISPLAY(display), + image->priv->image.buf + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaUnmapBuffer()")) + return FALSE; + + image->priv->image_data = NULL; + return TRUE; +} + +/** + * gst_vaapi_image_ensure_mapped_buffer: + * @image: a #GstVaapiImage + * + * initialize mapped image buffer in case of optimizition on + * nothing did between map and unmap operations. + * + * Return value: %TRUE on success + */ + +gboolean +gst_vaapi_image_ensure_mapped_buffer(GstVaapiImage *image) +{ + GstVaapiImagePrivate * const priv = image->priv; + guchar *user_ptr; + guchar tmp; + guint index; + + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + g_return_val_if_fail(priv->is_constructed, FALSE); + + if (!_gst_vaapi_image_is_mapped(image) || !priv->image_data) + return FALSE; + +#undef GST_VAAPI_IMAGE_PAGE_SIZE +#define GST_VAAPI_IMAGE_PAGE_SIZE 4096 + + /* read each page make sure virtual buffer mapped*/ + user_ptr = priv->image_data; + for (index = 0; + index < priv->image.data_size; + index += GST_VAAPI_IMAGE_PAGE_SIZE) { + tmp = *(user_ptr + index); + /*prevent from compiling optimization*/ + if (tmp == 0) + *(user_ptr + index) = 0; + } + + return TRUE; +} + +/** + * gst_vaapi_image_get_plane_count: + * @image: a #GstVaapiImage + * + * Retrieves the number of planes available in the @image. The @image + * must be mapped for this function to work properly. + * + * Return value: the number of planes available in the @image + */ +guint +gst_vaapi_image_get_plane_count(GstVaapiImage *image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0); + + return image->priv->image.num_planes; +} + +/** + * gst_vaapi_image_get_plane: + * @image: a #GstVaapiImage + * @plane: the requested plane number + * + * Retrieves the pixels data to the specified @plane. The @image must + * be mapped for this function to work properly. + * + * Return value: the pixels data of the specified @plane + */ +guchar * +gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL); + g_return_val_if_fail(plane < image->priv->image.num_planes, NULL); + + return image->priv->image_data + image->priv->image.offsets[plane]; +} + +/** + * gst_vaapi_image_get_pitch: + * @image: a #GstVaapiImage + * @plane: the requested plane number + * + * Retrieves the line size (stride) of the specified @plane. The + * @image must be mapped for this function to work properly. + * + * Return value: the line size (stride) of the specified plane + */ +guint +gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0); + g_return_val_if_fail(plane < image->priv->image.num_planes, 0); + + return image->priv->image.pitches[plane]; +} + +/** + * gst_vaapi_image_get_data_size: + * @image: a #GstVaapiImage + * + * Retrieves the underlying image data size. This function could be + * used to determine whether the image has a compatible layout with + * another image structure. + * + * Return value: the whole image data size of the @image + */ +guint +gst_vaapi_image_get_data_size(GstVaapiImage *image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + + return image->priv->image.data_size; +} + +static gboolean +init_image_from_buffer(GstVaapiImageRaw *raw_image, GstBuffer *buffer) +{ + GstStructure *structure; + GstCaps *caps; + GstVaapiImageFormat format; + guint width2, height2, size2; + gint width, height; + guchar *data; + guint32 data_size; + + data = GST_BUFFER_DATA(buffer); + data_size = GST_BUFFER_SIZE(buffer); + caps = GST_BUFFER_CAPS(buffer); + + if (!caps) + return FALSE; + + format = gst_vaapi_image_format_from_caps(caps); + + structure = gst_caps_get_structure(caps, 0); + gst_structure_get_int(structure, "width", &width); + gst_structure_get_int(structure, "height", &height); + + /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */ + raw_image->format = format; + raw_image->width = width; + raw_image->height = height; + width2 = (width + 1) / 2; + height2 = (height + 1) / 2; + size2 = 0; + switch (format) { + case GST_VAAPI_IMAGE_NV12: + raw_image->num_planes = 2; + raw_image->pixels[0] = data; + raw_image->stride[0] = GST_ROUND_UP_4(width); + size2 += height * raw_image->stride[0]; + raw_image->pixels[1] = data + size2; + raw_image->stride[1] = raw_image->stride[0]; + size2 += height2 * raw_image->stride[1]; + break; + case GST_VAAPI_IMAGE_YV12: + case GST_VAAPI_IMAGE_I420: + raw_image->num_planes = 3; + raw_image->pixels[0] = data; + raw_image->stride[0] = GST_ROUND_UP_4(width); + size2 += height * raw_image->stride[0]; + raw_image->pixels[1] = data + size2; + raw_image->stride[1] = GST_ROUND_UP_4(width2); + size2 += height2 * raw_image->stride[1]; + raw_image->pixels[2] = data + size2; + raw_image->stride[2] = raw_image->stride[1]; + size2 += height2 * raw_image->stride[2]; + break; + case GST_VAAPI_IMAGE_ARGB: + case GST_VAAPI_IMAGE_RGBA: + case GST_VAAPI_IMAGE_ABGR: + case GST_VAAPI_IMAGE_BGRA: + raw_image->num_planes = 1; + raw_image->pixels[0] = data; + raw_image->stride[0] = width * 4; + size2 += height * raw_image->stride[0]; + break; + default: + g_error("could not compute row-stride for %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS(format)); + return FALSE; + } + + if (size2 != data_size) { + g_error("data_size mismatch %d / %u", size2, data_size); + if (size2 > data_size) + return FALSE; + } + return TRUE; +} + +/* Copy N lines of an image */ +static inline void +memcpy_pic( + guchar *dst, + guint dst_stride, + const guchar *src, + guint src_stride, + guint len, + guint height +) +{ + guint i; + + for (i = 0; i < height; i++) { + memcpy(dst, src, len); + dst += dst_stride; + src += src_stride; + } +} + +/* Copy NV12 images */ +static void +copy_image_NV12( + GstVaapiImageRaw *dst_image, + GstVaapiImageRaw *src_image, + const GstVaapiRectangle *rect +) +{ + guchar *dst, *src; + guint dst_stride, src_stride; + + /* Y plane */ + dst_stride = dst_image->stride[0]; + dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x; + src_stride = src_image->stride[0]; + src = src_image->pixels[0] + rect->y * src_stride + rect->x; + memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height); + + /* UV plane */ + dst_stride = dst_image->stride[1]; + dst = dst_image->pixels[1] + (rect->y / 2) * dst_stride + (rect->x & -2); + src_stride = src_image->stride[1]; + src = src_image->pixels[1] + (rect->y / 2) * src_stride + (rect->x & -2); + memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height / 2); +} + +/* Copy YV12 images */ +static void +copy_image_YV12( + GstVaapiImageRaw *dst_image, + GstVaapiImageRaw *src_image, + const GstVaapiRectangle *rect +) +{ + guchar *dst, *src; + guint dst_stride, src_stride; + guint i, x, y, w, h; + + /* Y plane */ + dst_stride = dst_image->stride[0]; + dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x; + src_stride = src_image->stride[0]; + src = src_image->pixels[0] + rect->y * src_stride + rect->x; + memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height); + + /* U/V planes */ + x = rect->x / 2; + y = rect->y / 2; + w = rect->width / 2; + h = rect->height / 2; + for (i = 1; i < dst_image->num_planes; i++) { + dst_stride = dst_image->stride[i]; + dst = dst_image->pixels[i] + y * dst_stride + x; + src_stride = src_image->stride[i]; + src = src_image->pixels[i] + y * src_stride + x; + memcpy_pic(dst, dst_stride, src, src_stride, w, h); + } +} + +/* Copy RGBA images */ +static void +copy_image_RGBA( + GstVaapiImageRaw *dst_image, + GstVaapiImageRaw *src_image, + const GstVaapiRectangle *rect +) +{ + guchar *dst, *src; + guint dst_stride, src_stride; + + dst_stride = dst_image->stride[0]; + dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x; + src_stride = src_image->stride[0]; + src = src_image->pixels[0] + rect->y * src_stride + rect->x; + memcpy_pic(dst, dst_stride, src, src_stride, 4 * rect->width, rect->height); +} + +static gboolean +copy_image( + GstVaapiImageRaw *dst_image, + GstVaapiImageRaw *src_image, + const GstVaapiRectangle *rect +) +{ + GstVaapiRectangle default_rect; + + if (dst_image->format != src_image->format || + dst_image->width != src_image->width || + dst_image->height < src_image->height) + return FALSE; + + if (rect) { + if (rect->x >= src_image->width || + rect->x + src_image->width > src_image->width || + rect->y >= src_image->height || + rect->y + src_image->height > src_image->height) + return FALSE; + } + else { + default_rect.x = 0; + default_rect.y = 0; + default_rect.width = src_image->width; + default_rect.height = src_image->height; + rect = &default_rect; + } + + switch (dst_image->format) { + case GST_VAAPI_IMAGE_NV12: + copy_image_NV12(dst_image, src_image, rect); + break; + case GST_VAAPI_IMAGE_YV12: + case GST_VAAPI_IMAGE_I420: + copy_image_YV12(dst_image, src_image, rect); + break; + case GST_VAAPI_IMAGE_ARGB: + case GST_VAAPI_IMAGE_RGBA: + case GST_VAAPI_IMAGE_ABGR: + case GST_VAAPI_IMAGE_BGRA: + copy_image_RGBA(dst_image, src_image, rect); + break; + default: + GST_ERROR("unsupported image format for copy"); + return FALSE; + } + return TRUE; +} + +/** + * gst_vaapi_image_get_buffer: + * @image: a #GstVaapiImage + * @buffer: a #GstBuffer + * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the + * whole image + * + * Transfers pixels data contained in the @image into the #GstBuffer. + * Both image structures shall have the same format. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_get_buffer( + GstVaapiImage *image, + GstBuffer *buffer, + GstVaapiRectangle *rect +) +{ + GstVaapiImagePrivate *priv; + GstVaapiImageRaw dst_image, src_image; + gboolean success; + + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE); + + priv = image->priv; + + if (!init_image_from_buffer(&dst_image, buffer)) + return FALSE; + if (dst_image.format != priv->format) + return FALSE; + if (dst_image.width != priv->width || dst_image.height != priv->height) + return FALSE; + + if (!_gst_vaapi_image_map(image, &src_image)) + return FALSE; + + success = copy_image(&dst_image, &src_image, rect); + + if (!_gst_vaapi_image_unmap(image)) + return FALSE; + + return success; +} + +/** + * gst_vaapi_image_get_raw: + * @image: a #GstVaapiImage + * @dst_image: a #GstVaapiImageRaw + * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the + * whole image + * + * Transfers pixels data contained in the @image into the #GstVaapiImageRaw. + * Both image structures shall have the same format. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_get_raw( + GstVaapiImage *image, + GstVaapiImageRaw *dst_image, + GstVaapiRectangle *rect +) +{ + GstVaapiImageRaw src_image; + gboolean success; + + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + + if (!_gst_vaapi_image_map(image, &src_image)) + return FALSE; + + success = copy_image(dst_image, &src_image, rect); + + if (!_gst_vaapi_image_unmap(image)) + return FALSE; + + return success; +} + +/** + * gst_vaapi_image_update_from_buffer: + * @image: a #GstVaapiImage + * @buffer: a #GstBuffer + * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the + * whole image + * + * Transfers pixels data contained in the #GstBuffer into the + * @image. Both image structures shall have the same format. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_update_from_buffer( + GstVaapiImage *image, + GstBuffer *buffer, + GstVaapiRectangle *rect +) +{ + GstVaapiImagePrivate *priv; + GstVaapiImageRaw dst_image, src_image; + gboolean success; + + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE); + + priv = image->priv; + + if (!init_image_from_buffer(&src_image, buffer)) + return FALSE; + if (src_image.format != priv->format) + return FALSE; + if (src_image.width != priv->width || src_image.height > priv->height) + return FALSE; + + if (!_gst_vaapi_image_map(image, &dst_image)) + return FALSE; + + success = copy_image(&dst_image, &src_image, rect); + + if (!_gst_vaapi_image_unmap(image)) + return FALSE; + + return success; +} + +/** + * gst_vaapi_image_update_from_raw: + * @image: a #GstVaapiImage + * @src_image: a #GstVaapiImageRaw + * @buffer: a #GstBuffer + * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the + * whole image + * + * Transfers pixels data contained in the #GstVaapiImageRaw into the + * @image. Both image structures shall have the same format. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_image_update_from_raw( + GstVaapiImage *image, + GstVaapiImageRaw *src_image, + GstVaapiRectangle *rect +) +{ + GstVaapiImageRaw dst_image; + gboolean success; + + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + g_return_val_if_fail(image->priv->is_constructed, FALSE); + + if (!_gst_vaapi_image_map(image, &dst_image)) + return FALSE; + + success = copy_image(&dst_image, src_image, rect); + + if (!_gst_vaapi_image_unmap(image)) + return FALSE; + + return success; +} + +static void +_yuv411_to_nv12( + const guint8 *y_src, + guint32 y_src_stride, + const guint8 *u_src, + guint32 u_src_stride, + const guint8 *v_src, + guint32 v_src_stride, + guint8 *y_dest, + guint32 y_dest_stride, + guint8 *uv_dest, + guint32 uv_dest_stride, + guint32 width, + guint32 height +) +{ + guint32 row, column; + guint32 uv_height; + + memcpy_pic(y_dest, y_dest_stride, y_src, y_src_stride, width, height); + uv_height = GST_ROUND_UP_2(height)/2; + for (row = 0; row < uv_height; row++) { + for (column = 0; column < width/2; column++) { + uv_dest[column*2] = u_src[column]; + uv_dest[column*2+1] = v_src[column]; + } + u_src += u_src_stride; + v_src += v_src_stride; + uv_dest += uv_dest_stride; + } +} + +static void +_nv12_to_yuv411( + const guint8 *y_src, + guint32 y_src_stride, + const guint8 *uv_src, + guint32 uv_src_stride, + guint8 *y_dest, + guint32 y_dest_stride, + guint8 *u_dest, + guint32 u_dest_stride, + guint8 *v_dest, + guint32 v_dest_stride, + guint32 width, + guint32 height +) +{ + guint32 row, column; + guint32 uv_height; + + memcpy_pic(y_dest, y_dest_stride, y_src, y_src_stride, width, height); + uv_height = GST_ROUND_UP_2(height)/2; + for (row = 0; row < uv_height; row++) { + for (column = 0; column < width/2; column++) { + u_dest[column] = uv_src[column*2]; + v_dest[column] = uv_src[column*2+1]; + } + uv_src += uv_src_stride; + u_dest += u_dest_stride; + v_dest += v_dest_stride; + } +} + +static void +_yuy2_to_yuv411( + const guint8 *yuv_src, + guint32 yuv_src_stride, + guint8 *y_dest, + guint32 y_dest_stride, + guint8 *u_dest, + guint32 u_dest_stride, + guint8 *v_dest, + guint32 v_dest_stride, + gboolean uv_interlaced, + guint32 width, + guint32 height +) +{ + guint32 row, column; + const guint8 *yuv_next_src; + guint8 *y_next_dest; + guint32 interval; + + interval = uv_interlaced ? 2 : 1; + for (row = 0; row < height/2; row++) { + yuv_next_src = yuv_src + yuv_src_stride; + y_next_dest = y_dest + y_dest_stride; + for (column = 0; column < width/2; column++) { + y_dest[column*2] = yuv_src[column*4]; + y_dest[column*2+1] = yuv_src[column*4+2]; + y_next_dest[column*2] = yuv_next_src[column*4]; + y_next_dest[column*2+1] = yuv_next_src[column*4+2]; + u_dest[column*interval] = ((yuv_src[column*4+1] + yuv_next_src[column*4+1])>>1); + v_dest[column*interval] = ((yuv_src[column*4+3] + yuv_next_src[column*4+3])>>1); + } + yuv_src = yuv_next_src + yuv_src_stride; + y_dest = y_next_dest + y_dest_stride; + u_dest += u_dest_stride; + v_dest += v_dest_stride; + } + + /* odd line */ + if (height%2) { + for (column = 0; column < width/2; column++) { + y_dest[column*2] = yuv_src[column*4]; + y_dest[column*2+1] = yuv_src[column*4+2]; + u_dest[column*interval] = yuv_src[column*4+1]; + v_dest[column*interval] = yuv_src[column*4+3]; + } + } + +} + +static gboolean +_image_convert_to_nv12( + const guint8 *src, + guint32 width, + guint32 height, + guint32 src_format, + guint8 *y_dest, + guint32 y_dest_stride, + guint8 *uv_dest, + guint32 uv_dest_stride +) +{ + const guint8 *y_src, *u_src, *v_src, *uv_src; + guint32 ystride, ustride, vstride, uv_stride; + + switch (src_format) { + case GST_MAKE_FOURCC('N','V','1','2'): { + y_src = src; + ystride = GST_ROUND_UP_4(width); + uv_src = src + ystride*GST_ROUND_UP_2(height); + uv_stride = ystride; + memcpy_pic(y_dest, y_dest_stride, y_src, ystride, width, height); + memcpy_pic(uv_dest, uv_dest_stride, uv_src, uv_stride, + width, GST_ROUND_UP_2(height)/2); + break; + } + + case GST_MAKE_FOURCC('I','4','2','0'): { + y_src = src; + ystride = GST_ROUND_UP_4(width); + u_src = src + ystride*GST_ROUND_UP_2(height); + ustride = GST_ROUND_UP_8(ystride)/2; + v_src = u_src + ustride*GST_ROUND_UP_2(height)/2; + vstride = GST_ROUND_UP_8(ystride)/2; + + _yuv411_to_nv12(y_src, ystride, u_src, ustride, v_src, vstride, + y_dest, y_dest_stride, + uv_dest, uv_dest_stride, + width, height); + break; + } + + case GST_MAKE_FOURCC('Y','V','1','2'):{ + y_src = src; + ystride = GST_ROUND_UP_4(width); + v_src = src + ystride*GST_ROUND_UP_2(height); + vstride = GST_ROUND_UP_8(ystride)/2; + u_src = v_src + vstride*GST_ROUND_UP_2(height)/2; + ustride = GST_ROUND_UP_8(ystride)/2; + + _yuv411_to_nv12(y_src, ystride, u_src, ustride, v_src, vstride, + y_dest, y_dest_stride, uv_dest, uv_dest_stride, + width, height); + break; + } + + case GST_MAKE_FOURCC('Y', 'U', 'Y', '2'): { + y_src = src; + ystride = GST_ROUND_UP_2(width)*2; + _yuy2_to_yuv411(y_src, ystride, + y_dest, y_dest_stride, + uv_dest, uv_dest_stride, + uv_dest+1, uv_dest_stride, + TRUE, + width, height); + break; + } + + default: + return FALSE; + } + return TRUE; +} + +static gboolean +_image_convert_to_yuv411( + const guint8 *src, + guint32 width, + guint32 height, + guint32 src_format, + guint8 *y_dest, + guint32 y_dest_stride, + guint8 *u_dest, + guint32 u_dest_stride, + guint8 *v_dest, + guint32 v_dest_stride +) +{ + const guint8 *y_src, *u_src, *v_src, *uv_src; + guint32 ystride, ustride, vstride, uv_stride; + + switch (src_format) { + case GST_MAKE_FOURCC('N','V','1','2'): { + y_src = src; + ystride = GST_ROUND_UP_4(width); + uv_src = src + ystride*GST_ROUND_UP_2(height); + uv_stride = ystride; + _nv12_to_yuv411(y_src, ystride, uv_src, uv_stride, + y_dest, y_dest_stride, + u_dest, u_dest_stride, + v_dest, v_dest_stride, + width, height); + break; + } + + case GST_MAKE_FOURCC('I','4','2','0'): + case GST_MAKE_FOURCC('Y','V','1','2'):{ + y_src = src; + ystride = GST_ROUND_UP_4(width); + if (GST_MAKE_FOURCC('I','4','2','0') == src_format) { + u_src = src + ystride*GST_ROUND_UP_2(height); + ustride = GST_ROUND_UP_8(ystride)/2; + v_src = u_src + ustride*GST_ROUND_UP_2(height)/2; + vstride = GST_ROUND_UP_8(ystride)/2; + } else { + v_src = src + ystride*GST_ROUND_UP_2(height); + vstride = GST_ROUND_UP_8(ystride)/2; + u_src = v_src + vstride*GST_ROUND_UP_2(height)/2; + ustride = GST_ROUND_UP_8(ystride)/2; + } + + memcpy_pic(y_dest, y_dest_stride, y_src, ystride, width, height); + memcpy_pic(u_dest, u_dest_stride, u_src, ustride, width/2, GST_ROUND_UP_2(height)/2); + memcpy_pic(v_dest, v_dest_stride, v_src, vstride, width/2, GST_ROUND_UP_2(height)/2); + break; + } + + case GST_MAKE_FOURCC('Y', 'U', 'Y', '2'): { + y_src = src; + ystride = GST_ROUND_UP_2(width)*2; + _yuy2_to_yuv411(y_src, ystride, + y_dest, y_dest_stride, + u_dest, u_dest_stride, + v_dest, v_dest_stride, + FALSE, + width, height); + break; + } + + default: + return FALSE; + } + return TRUE; +} + + +gboolean +gst_vaapi_convert_buffer_to_image( + GstVaapiImage *image, + GstBuffer *inbuf + ) +{ + GstVaapiImagePrivate *priv; + guint width, height; + GstVaapiImageFormat image_format; + gboolean success = TRUE; + GstCaps *buffer_caps; + GstStructure *structure; + guint32 in_format = 0; + + priv = image->priv; + gst_vaapi_image_get_size(image, &width, &height); + image_format = gst_vaapi_image_get_format(image); + + /* get buffer format */ + buffer_caps = GST_BUFFER_CAPS(inbuf); + if (!buffer_caps) + return FALSE; + structure = gst_caps_get_structure(buffer_caps, 0); + if (!structure) + return FALSE; + if (!gst_structure_get_fourcc(structure, "format", &in_format)) + return FALSE; + + /* currently only support YUV convert */ + if ( (in_format != GST_MAKE_FOURCC('N','V','1','2') + && in_format != GST_MAKE_FOURCC('Y','V','1','2') + && in_format != GST_MAKE_FOURCC('I','4','2','0') + && in_format != GST_MAKE_FOURCC('Y', 'U', 'Y', '2')) + || (image_format != GST_VAAPI_IMAGE_NV12 + && image_format != GST_VAAPI_IMAGE_YV12 + && image_format != GST_VAAPI_IMAGE_I420) + ) + { + return FALSE; + } + + + gst_vaapi_image_map(image); + switch (image_format) { + case GST_VAAPI_IMAGE_NV12: { + g_assert(priv->image.num_planes == 2); + success = _image_convert_to_nv12(GST_BUFFER_DATA(inbuf), + width, height, in_format, + priv->image_data+priv->image.offsets[0], + priv->image.pitches[0], + priv->image_data+priv->image.offsets[1], + priv->image.pitches[1]); + break; + } + + case GST_VAAPI_IMAGE_I420: { + g_assert(priv->image.num_planes == 3); + success = _image_convert_to_yuv411(GST_BUFFER_DATA(inbuf), + width, height, in_format, + priv->image_data+priv->image.offsets[0], + priv->image.pitches[0], + priv->image_data+priv->image.offsets[1], + priv->image.pitches[1], + priv->image_data+priv->image.offsets[2], + priv->image.pitches[2]); + break; + } + case GST_VAAPI_IMAGE_YV12:{ + g_assert(priv->image.num_planes == 3); + success = _image_convert_to_yuv411(GST_BUFFER_DATA(inbuf), + width, height, in_format, + priv->image_data+priv->image.offsets[0], + priv->image.pitches[0], + priv->image_data+priv->image.offsets[2], + priv->image.pitches[2], + priv->image_data+priv->image.offsets[1], + priv->image.pitches[1]); + break; + } + + default: + success = FALSE; + break; + } + gst_vaapi_image_unmap(image); + + return success; +} + diff --git a/gst-libs/gst/vaapi/gstvaapiimage.h b/gst-libs/gst/vaapi/gstvaapiimage.h new file mode 100644 index 0000000..95ea781 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiimage.h @@ -0,0 +1,217 @@ +/* + * gstvaapiimage.h - VA image abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_IMAGE_H +#define GST_VAAPI_IMAGE_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_IMAGE \ + (gst_vaapi_image_get_type()) + +#define GST_VAAPI_IMAGE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_IMAGE, \ + GstVaapiImage)) + +#define GST_VAAPI_IMAGE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_IMAGE, \ + GstVaapiImageClass)) + +#define GST_VAAPI_IS_IMAGE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_IMAGE)) + +#define GST_VAAPI_IS_IMAGE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_IMAGE)) + +#define GST_VAAPI_IMAGE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_IMAGE, \ + GstVaapiImageClass)) + +/** + * GST_VAAPI_IMAGE_FORMAT: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the #GstVaapiImageFormat of @image. + */ +#define GST_VAAPI_IMAGE_FORMAT(image) gst_vaapi_image_get_format(image) + +/** + * GST_VAAPI_IMAGE_WIDTH: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the width of @image. + */ +#define GST_VAAPI_IMAGE_WIDTH(image) gst_vaapi_image_get_width(image) + +/** + * GST_VAAPI_IMAGE_HEIGHT: + * @image: a #GstVaapiImage + * + * Macro that evaluates to the height of @image. + */ +#define GST_VAAPI_IMAGE_HEIGHT(image) gst_vaapi_image_get_height(image) + +typedef struct _GstVaapiImage GstVaapiImage; +typedef struct _GstVaapiImagePrivate GstVaapiImagePrivate; +typedef struct _GstVaapiImageClass GstVaapiImageClass; +typedef struct _GstVaapiImageRaw GstVaapiImageRaw; + +/** + * GstVaapiImage: + * + * A VA image wrapper + */ +struct _GstVaapiImage { + /*< private >*/ + GstVaapiObject parent_instance; + + GstVaapiImagePrivate *priv; +}; + +/** + * GstVaapiImageClass: + * + * A VA image wrapper class + */ +struct _GstVaapiImageClass { + /*< private >*/ + GstVaapiObjectClass parent_class; +}; + +/** + * GstVaapiImageRaw: + * + * A raw image wrapper. The caller is responsible for initializing all + * the fields with sensible values. + */ +struct _GstVaapiImageRaw { + GstVaapiImageFormat format; + guint width; + guint height; + guint num_planes; + guchar *pixels[3]; + guint stride[3]; +}; + +GType +gst_vaapi_image_get_type(void) G_GNUC_CONST; + +GstVaapiImage * +gst_vaapi_image_new( + GstVaapiDisplay *display, + GstVaapiImageFormat format, + guint width, + guint height +); + +GstVaapiImage * +gst_vaapi_image_new_with_image(GstVaapiDisplay *display, VAImage *va_image); + +GstVaapiID +gst_vaapi_image_get_id(GstVaapiImage *image); + +gboolean +gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image); + +GstVaapiImageFormat +gst_vaapi_image_get_format(GstVaapiImage *image); + +guint +gst_vaapi_image_get_width(GstVaapiImage *image); + +guint +gst_vaapi_image_get_height(GstVaapiImage *image); + +void +gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight); + +gboolean +gst_vaapi_image_is_linear(GstVaapiImage *image); + +gboolean +gst_vaapi_image_is_mapped(GstVaapiImage *image); + +gboolean +gst_vaapi_image_map(GstVaapiImage *image); + +gboolean +gst_vaapi_image_unmap(GstVaapiImage *image); + +gboolean +gst_vaapi_image_ensure_mapped_buffer(GstVaapiImage *image); + +guint +gst_vaapi_image_get_plane_count(GstVaapiImage *image); + +guchar * +gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane); + +guint +gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane); + +guint +gst_vaapi_image_get_data_size(GstVaapiImage *image); + +gboolean +gst_vaapi_image_get_buffer( + GstVaapiImage *image, + GstBuffer *buffer, + GstVaapiRectangle *rect +); + +gboolean +gst_vaapi_image_get_raw( + GstVaapiImage *image, + GstVaapiImageRaw *dst_image, + GstVaapiRectangle *rect +); + +gboolean +gst_vaapi_image_update_from_buffer( + GstVaapiImage *image, + GstBuffer *buffer, + GstVaapiRectangle *rect +); + +gboolean +gst_vaapi_image_update_from_raw( + GstVaapiImage *image, + GstVaapiImageRaw *src_image, + GstVaapiRectangle *rect +); + +gboolean +gst_vaapi_convert_buffer_to_image( + GstVaapiImage *image, + GstBuffer *buffer); + +G_END_DECLS + +#endif /* GST_VAAPI_IMAGE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiimageformat.c b/gst-libs/gst/vaapi/gstvaapiimageformat.c new file mode 100644 index 0000000..dd03157 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiimageformat.c @@ -0,0 +1,316 @@ +/* + * gstvaapiimageformat.c - VA image format abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiimageformat + * @short_description: VA image format abstraction + */ + +#include "sysdeps.h" +#include +#include "gstvaapicompat.h" +#include "gstvaapiimageformat.h" + +typedef enum _GstVaapiImageFormatType GstVaapiImageFormatType; +typedef struct _GstVaapiImageFormatMap GstVaapiImageFormatMap; + +enum _GstVaapiImageFormatType { + GST_VAAPI_IMAGE_FORMAT_TYPE_YCBCR = 1, /* YUV */ + GST_VAAPI_IMAGE_FORMAT_TYPE_RGB, /* RGB */ + GST_VAAPI_IMAGE_FORMAT_TYPE_INDEXED /* paletted */ +}; + +struct _GstVaapiImageFormatMap { + GstVaapiImageFormatType type; + GstVaapiImageFormat format; + const char *caps_str; + VAImageFormat va_format; +}; + +#define DEF(TYPE, FORMAT, CAPS_STR) \ + GST_VAAPI_IMAGE_FORMAT_TYPE_##TYPE, \ + GST_VAAPI_IMAGE_##FORMAT, \ + CAPS_STR +#define DEF_YUV(FORMAT, FOURCC, ENDIAN, BPP) \ + { DEF(YCBCR, FORMAT, GST_VIDEO_CAPS_YUV(#FORMAT)), \ + { VA_FOURCC FOURCC, VA_##ENDIAN##_FIRST, BPP, }, } +#define DEF_RGB(FORMAT, FOURCC, ENDIAN, BPP, DEPTH, R,G,B,A) \ + { DEF(RGB, FORMAT, GST_VIDEO_CAPS_##FORMAT), \ + { VA_FOURCC FOURCC, VA_##ENDIAN##_FIRST, BPP, DEPTH, R,G,B,A }, } + +/* Image formats, listed in HW order preference */ +static const GstVaapiImageFormatMap gst_vaapi_image_formats[] = { + DEF_YUV(NV12, ('N','V','1','2'), LSB, 12), + DEF_YUV(YV12, ('Y','V','1','2'), LSB, 12), + DEF_YUV(I420, ('I','4','2','0'), LSB, 12), + DEF_YUV(AYUV, ('A','Y','U','V'), LSB, 32), +#if G_BYTE_ORDER == G_BIG_ENDIAN + DEF_RGB(ARGB, ('A','R','G','B'), MSB, 32, + 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000), + DEF_RGB(ABGR, ('A','B','G','R'), MSB, 32, + 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000), +#elif G_BYTE_ORDER == G_LITTLE_ENDIAN + DEF_RGB(BGRA, ('B','G','R','A'), LSB, 32, + 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000), + DEF_RGB(RGBA, ('R','G','B','A'), LSB, 32, + 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000), +#endif + { 0, } +}; + +#undef DEF_RGB +#undef DEF_YUV +#undef DEF + +static inline gboolean +match_va_format_rgb(const VAImageFormat *fmt1, const VAImageFormat *fmt2) +{ + return (fmt1->byte_order == fmt2->byte_order && + fmt1->red_mask == fmt2->red_mask && + fmt1->green_mask == fmt2->green_mask && + fmt1->blue_mask == fmt2->blue_mask && + fmt1->alpha_mask == fmt2->alpha_mask); +} + +static const GstVaapiImageFormatMap * +get_map(GstVaapiImageFormat format) +{ + const GstVaapiImageFormatMap *m; + + for (m = gst_vaapi_image_formats; m->format; m++) + if (m->format == format) + return m; + return NULL; +} + +/** + * gst_vaapi_image_format_is_rgb: + * @format: a #GstVaapiImageFormat + * + * Checks whether the format is an RGB format. + * + * Return value: %TRUE if @format is RGB format + */ +gboolean +gst_vaapi_image_format_is_rgb(GstVaapiImageFormat format) +{ + const GstVaapiImageFormatMap * const m = get_map(format); + + return m ? (m->type == GST_VAAPI_IMAGE_FORMAT_TYPE_RGB) : FALSE; +} + +/** + * gst_vaapi_image_format_is_yuv: + * @format: a #GstVaapiImageFormat + * + * Checks whether the format is an YUV format. + * + * Return value: %TRUE if @format is YUV format + */ +gboolean +gst_vaapi_image_format_is_yuv(GstVaapiImageFormat format) +{ + const GstVaapiImageFormatMap * const m = get_map(format); + + return m ? (m->type == GST_VAAPI_IMAGE_FORMAT_TYPE_YCBCR) : FALSE; +} + +/** + * gst_vaapi_image_format: + * @va_format: a #VAImageFormat + * + * Converts a VA image format into the corresponding #GstVaapiImageFormat. + * If the image format cannot be represented by #GstVaapiImageFormat, + * then zero is returned. + * + * Return value: the #GstVaapiImageFormat describing the @va_format + */ +GstVaapiImageFormat +gst_vaapi_image_format(const VAImageFormat *va_format) +{ + const GstVaapiImageFormatMap *m; + + for (m = gst_vaapi_image_formats; m->format; m++) + if (m->va_format.fourcc == va_format->fourcc && + (m->type == GST_VAAPI_IMAGE_FORMAT_TYPE_RGB ? + match_va_format_rgb(&m->va_format, va_format) : + TRUE)) + return m->format; + + return 0; +} + +/** + * gst_vaapi_image_format_from_caps: + * @caps: a #GstCaps + * + * Converts @caps into the corresponding #GstVaapiImageFormat. If the + * image format cannot be represented by #GstVaapiImageFormat, then + * zero is returned. + * + * Return value: the #GstVaapiImageFormat describing the @caps + */ +GstVaapiImageFormat +gst_vaapi_image_format_from_caps(GstCaps *caps) +{ + const GstVaapiImageFormatMap *m; + GstStructure *structure; + VAImageFormat *va_format, va_formats[2]; + gint endian, rmask, gmask, bmask, amask = 0; + guint32 fourcc; + + if (!caps) + return 0; + + structure = gst_caps_get_structure(caps, 0); + if (!structure) + return 0; + + /* Check for YUV format */ + if (gst_structure_get_fourcc(structure, "format", &fourcc)) + return gst_vaapi_image_format_from_fourcc(fourcc); + + /* Check for RGB format */ + gst_structure_get_int(structure, "endianness", &endian); + gst_structure_get_int(structure, "red_mask", &rmask); + gst_structure_get_int(structure, "green_mask", &gmask); + gst_structure_get_int(structure, "blue_mask", &bmask); + gst_structure_get_int(structure, "alpha_mask", &amask); + + va_format = &va_formats[0]; + va_format->byte_order = endian == G_BIG_ENDIAN ? VA_MSB_FIRST : VA_LSB_FIRST; + va_format->red_mask = rmask; + va_format->green_mask = gmask; + va_format->blue_mask = bmask; + va_format->alpha_mask = amask; + + va_format = &va_formats[1]; + va_format->byte_order = endian == G_BIG_ENDIAN ? VA_LSB_FIRST : VA_MSB_FIRST; + va_format->red_mask = GUINT32_SWAP_LE_BE(rmask); + va_format->green_mask = GUINT32_SWAP_LE_BE(gmask); + va_format->blue_mask = GUINT32_SWAP_LE_BE(bmask); + va_format->alpha_mask = GUINT32_SWAP_LE_BE(amask); + + for (m = gst_vaapi_image_formats; m->format; m++) + if (match_va_format_rgb(&m->va_format, &va_formats[0]) || + match_va_format_rgb(&m->va_format, &va_formats[1])) + return m->format; + + return 0; +} + +/** + * gst_vaapi_image_format_from_fourcc: + * @fourcc: a FOURCC value + * + * Converts a FOURCC value into the corresponding #GstVaapiImageFormat. + * If the image format cannot be represented by #GstVaapiImageFormat, + * then zero is returned. + * + * Return value: the #GstVaapiImageFormat describing the FOURCC value + */ +GstVaapiImageFormat +gst_vaapi_image_format_from_fourcc(guint32 fourcc) +{ + return (GstVaapiImageFormat)fourcc; +} + +/** + * gst_vaapi_image_format_from_video: + * @format: a #GstVideoFormat + * + * Converts a #GstVideoFormat into the corresponding + * #GstVaapiImageFormat. If the image format cannot be represented by + * #GstVaapiImageFormat, then zero is returned. + * + * Return value: the #GstVaapiImageFormat describing the video format + */ +GstVaapiImageFormat +gst_vaapi_image_format_from_video(GstVideoFormat format) +{ + GstVaapiImageFormat va_format; + + switch (format) { + case GST_VIDEO_FORMAT_NV12: va_format = GST_VAAPI_IMAGE_NV12; break; + case GST_VIDEO_FORMAT_YV12: va_format = GST_VAAPI_IMAGE_YV12; break; + case GST_VIDEO_FORMAT_I420: va_format = GST_VAAPI_IMAGE_I420; break; + case GST_VIDEO_FORMAT_AYUV: va_format = GST_VAAPI_IMAGE_AYUV; break; + case GST_VIDEO_FORMAT_ARGB: va_format = GST_VAAPI_IMAGE_ARGB; break; + case GST_VIDEO_FORMAT_RGBA: va_format = GST_VAAPI_IMAGE_RGBA; break; + case GST_VIDEO_FORMAT_ABGR: va_format = GST_VAAPI_IMAGE_ABGR; break; + case GST_VIDEO_FORMAT_BGRA: va_format = GST_VAAPI_IMAGE_BGRA; break; + default: va_format = (GstVaapiImageFormat)0; break; + } + return va_format; +} + +/** + * gst_vaapi_image_format_get_va_format: + * @format: a #GstVaapiImageFormat + * + * Converts a #GstVaapiImageFormat into the corresponding VA image + * format. If no matching VA image format was found, %NULL is returned + * and this error must be reported to be fixed. + * + * Return value: the VA image format, or %NULL if none was found + */ +const VAImageFormat * +gst_vaapi_image_format_get_va_format(GstVaapiImageFormat format) +{ + const GstVaapiImageFormatMap * const m = get_map(format); + + return m ? &m->va_format : NULL; +} + +/** + * gst_vaapi_image_format_get_caps: + * @format: a #GstVaapiImageFormat + * + * Converts a #GstVaapiImageFormat into the corresponding #GstCaps. If + * no matching caps were found, %NULL is returned. + * + * Return value: the newly allocated #GstCaps, or %NULL if none was found + */ +GstCaps * +gst_vaapi_image_format_get_caps(GstVaapiImageFormat format) +{ + const GstVaapiImageFormatMap * const m = get_map(format); + + return m ? gst_caps_from_string(m->caps_str) : NULL; +} + +/** + * gst_vaapi_image_format_get_score: + * @format: a #GstVaapiImageFormat + * + * Determines how "native" is this @format. The lower is the returned + * score, the best format this is for the underlying hardware. + * + * Return value: the @format score, or %G_MAXUINT if none was found + */ +guint +gst_vaapi_image_format_get_score(GstVaapiImageFormat format) +{ + const GstVaapiImageFormatMap * const m = get_map(format); + + return m ? (m - &gst_vaapi_image_formats[0]) : G_MAXUINT; +} diff --git a/gst-libs/gst/vaapi/gstvaapiimageformat.h b/gst-libs/gst/vaapi/gstvaapiimageformat.h new file mode 100644 index 0000000..56af2a4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiimageformat.h @@ -0,0 +1,94 @@ +/* + * gstvaapiimageformat.h - VA image format abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_IMAGE_FORMAT_H +#define GST_VAAPI_IMAGE_FORMAT_H + +#include +#include + +G_BEGIN_DECLS + +typedef enum _GstVaapiImageFormat GstVaapiImageFormat; + +/** + * GstVaapiImageFormat: + * @GST_VAAPI_IMAGE_NV12: + * planar YUV 4:2:0, 12-bit, 1 plane for Y and 1 plane for UV + * @GST_VAAPI_IMAGE_YV12: + * planar YUV 4:2:0, 12-bit, 3 planes for Y V U + * @GST_VAAPI_IMAGE_I420: + * planar YUV 4:2:0, 12-bit, 3 planes for Y U V + * @GST_VAAPI_IMAGE_AYUV: + * packed YUV 4:4:4, 32-bit, A Y U V, native endian byte-order + * @GST_VAAPI_IMAGE_ARGB: + * packed RGB 8:8:8, 32-bit, A R G B + * @GST_VAAPI_IMAGE_RGBA: + * packed RGB 8:8:8, 32-bit, R G B A + * @GST_VAAPI_IMAGE_ABGR: + * packed RGB 8:8:8, 32-bit, A B G R + * @GST_VAAPI_IMAGE_BGRA: + * packed RGB 8:8:8, 32-bit, B G R A + * + * The set of all image formats for #GstVaapiImage. + */ +enum _GstVaapiImageFormat { + GST_VAAPI_IMAGE_NV12 = GST_MAKE_FOURCC('N','V','1','2'), + GST_VAAPI_IMAGE_YV12 = GST_MAKE_FOURCC('Y','V','1','2'), + GST_VAAPI_IMAGE_I420 = GST_MAKE_FOURCC('I','4','2','0'), + GST_VAAPI_IMAGE_AYUV = GST_MAKE_FOURCC('A','Y','U','V'), + GST_VAAPI_IMAGE_ARGB = GST_MAKE_FOURCC('A','R','G','B'), + GST_VAAPI_IMAGE_RGBA = GST_MAKE_FOURCC('R','G','B','A'), + GST_VAAPI_IMAGE_ABGR = GST_MAKE_FOURCC('A','B','G','R'), + GST_VAAPI_IMAGE_BGRA = GST_MAKE_FOURCC('B','G','R','A'), +}; + +gboolean +gst_vaapi_image_format_is_rgb(GstVaapiImageFormat format); + +gboolean +gst_vaapi_image_format_is_yuv(GstVaapiImageFormat format); + +GstVaapiImageFormat +gst_vaapi_image_format(const VAImageFormat *va_format); + +GstVaapiImageFormat +gst_vaapi_image_format_from_caps(GstCaps *caps); + +GstVaapiImageFormat +gst_vaapi_image_format_from_fourcc(guint32 fourcc); + +GstVaapiImageFormat +gst_vaapi_image_format_from_video(GstVideoFormat format); + +const VAImageFormat * +gst_vaapi_image_format_get_va_format(GstVaapiImageFormat format); + +GstCaps * +gst_vaapi_image_format_get_caps(GstVaapiImageFormat format); + +guint +gst_vaapi_image_format_get_score(GstVaapiImageFormat format); + +G_END_DECLS + +#endif /* GST_GST_VAAPI_IMAGE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiimagepool.c b/gst-libs/gst/vaapi/gstvaapiimagepool.c new file mode 100644 index 0000000..159cb30 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiimagepool.c @@ -0,0 +1,127 @@ +/* + * gstvaapiimagepool.c - Gst VA image pool + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiimagepool + * @short_description: VA image pool + */ + +#include "sysdeps.h" +#include "gstvaapiimagepool.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE( + GstVaapiImagePool, + gst_vaapi_image_pool, + GST_VAAPI_TYPE_VIDEO_POOL); + +#define GST_VAAPI_IMAGE_POOL_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_IMAGE_POOL, \ + GstVaapiImagePoolPrivate)) + +struct _GstVaapiImagePoolPrivate { + GstVaapiImageFormat format; + guint width; + guint height; +}; + +static void +gst_vaapi_image_pool_set_caps(GstVaapiVideoPool *pool, GstCaps *caps) +{ + GstVaapiImagePoolPrivate * const priv = GST_VAAPI_IMAGE_POOL(pool)->priv; + GstStructure *structure; + gint width, height; + + structure = gst_caps_get_structure(caps, 0); + gst_structure_get_int(structure, "width", &width); + gst_structure_get_int(structure, "height", &height); + + priv->format = gst_vaapi_image_format_from_caps(caps); + priv->width = width; + priv->height = height; +} + +gpointer +gst_vaapi_image_pool_alloc_object( + GstVaapiVideoPool *pool, + GstVaapiDisplay *display +) +{ + GstVaapiImagePoolPrivate * const priv = GST_VAAPI_IMAGE_POOL(pool)->priv; + + return gst_vaapi_image_new(display, + priv->format, + priv->width, + priv->height); +} + +static void +gst_vaapi_image_pool_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_image_pool_parent_class)->finalize(object); +} + +static void +gst_vaapi_image_pool_class_init(GstVaapiImagePoolClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiVideoPoolClass * const pool_class = GST_VAAPI_VIDEO_POOL_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiImagePoolPrivate)); + + object_class->finalize = gst_vaapi_image_pool_finalize; + + pool_class->set_caps = gst_vaapi_image_pool_set_caps; + pool_class->alloc_object = gst_vaapi_image_pool_alloc_object; +} + +static void +gst_vaapi_image_pool_init(GstVaapiImagePool *pool) +{ + GstVaapiImagePoolPrivate *priv = GST_VAAPI_IMAGE_POOL_GET_PRIVATE(pool); + + pool->priv = priv; + priv->format = 0; + priv->width = 0; + priv->height = 0; +} + +/** + * gst_vaapi_image_pool_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps + * + * Creates a new #GstVaapiVideoPool of #GstVaapiImage with the + * specified dimensions in @caps. + * + * Return value: the newly allocated #GstVaapiVideoPool + */ +GstVaapiVideoPool * +gst_vaapi_image_pool_new(GstVaapiDisplay *display, GstCaps *caps) +{ + return g_object_new(GST_VAAPI_TYPE_IMAGE_POOL, + "display", display, + "caps", caps, + NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapiimagepool.h b/gst-libs/gst/vaapi/gstvaapiimagepool.h new file mode 100644 index 0000000..2478c47 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiimagepool.h @@ -0,0 +1,88 @@ +/* + * gstvaapiimagepool.h - Gst VA image pool + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_IMAGE_POOL_H +#define GST_VAAPI_IMAGE_POOL_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_IMAGE_POOL \ + (gst_vaapi_image_pool_get_type()) + +#define GST_VAAPI_IMAGE_POOL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_IMAGE_POOL, \ + GstVaapiImagePool)) + +#define GST_VAAPI_IMAGE_POOL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_IMAGE_POOL, \ + GstVaapiImagePoolClass)) + +#define GST_VAAPI_IS_IMAGE_POOL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_IMAGE_POOL)) + +#define GST_VAAPI_IS_IMAGE_POOL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_IMAGE_POOL)) + +#define GST_VAAPI_IMAGE_POOL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_IMAGE_POOL, \ + GstVaapiImagePoolClass)) + +typedef struct _GstVaapiImagePool GstVaapiImagePool; +typedef struct _GstVaapiImagePoolPrivate GstVaapiImagePoolPrivate; +typedef struct _GstVaapiImagePoolClass GstVaapiImagePoolClass; + +/** + * GstVaapiImagePool: + * + * A pool of lazily allocated #GstVaapiImage objects. + */ +struct _GstVaapiImagePool { + /*< private >*/ + GstVaapiVideoPool parent_instance; + + GstVaapiImagePoolPrivate *priv; +}; + +/** + * GstVaapiImagePoolClass: + * + * A pool of lazily allocated #GstVaapiImage objects. + */ +struct _GstVaapiImagePoolClass { + /*< private >*/ + GstVaapiVideoPoolClass parent_class; +}; + +GType +gst_vaapi_image_pool_get_type(void) G_GNUC_CONST; + +GstVaapiVideoPool * +gst_vaapi_image_pool_new(GstVaapiDisplay *display, GstCaps *caps); + +G_END_DECLS + +#endif /* GST_VAAPI_IMAGE_POOL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiobject.c b/gst-libs/gst/vaapi/gstvaapiobject.c new file mode 100644 index 0000000..ad3d139 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiobject.c @@ -0,0 +1,256 @@ +/* + * gstvaapiobject.c - Base VA object + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiobject + * @short_description: Base VA object + */ + +#include "sysdeps.h" +#include "gstvaapiobject.h" +#include "gstvaapi_priv.h" +#include "gstvaapiparamspecs.h" +#include "gstvaapivalue.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiObject, gst_vaapi_object, G_TYPE_OBJECT); + +enum { + PROP_0, + + PROP_DISPLAY, + PROP_ID +}; + +enum { + DESTROY, + + LAST_SIGNAL +}; + +static guint object_signals[LAST_SIGNAL] = { 0, }; + +static void +gst_vaapi_object_dispose(GObject *object) +{ + GstVaapiObjectPrivate * const priv = GST_VAAPI_OBJECT(object)->priv; + + if (!priv->is_destroying) { + priv->is_destroying = TRUE; + g_signal_emit(object, object_signals[DESTROY], 0); + priv->is_destroying = FALSE; + } + + G_OBJECT_CLASS(gst_vaapi_object_parent_class)->dispose(object); +} + +static void +gst_vaapi_object_finalize(GObject *object) +{ + GstVaapiObjectPrivate * const priv = GST_VAAPI_OBJECT(object)->priv; + + priv->id = GST_VAAPI_ID_NONE; + + g_clear_object(&priv->display); + + G_OBJECT_CLASS(gst_vaapi_object_parent_class)->finalize(object); +} + +static void +gst_vaapi_object_set_property( + GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiObject * const object = GST_VAAPI_OBJECT(gobject); + + switch (prop_id) { + case PROP_DISPLAY: + object->priv->display = g_object_ref(g_value_get_object(value)); + break; + case PROP_ID: + object->priv->id = gst_vaapi_value_get_id(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_object_get_property( + GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiObject * const object = GST_VAAPI_OBJECT(gobject); + + switch (prop_id) { + case PROP_DISPLAY: + g_value_set_object(value, gst_vaapi_object_get_display(object)); + break; + case PROP_ID: + gst_vaapi_value_set_id(value, gst_vaapi_object_get_id(object)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_object_class_init(GstVaapiObjectClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiObjectPrivate)); + + object_class->dispose = gst_vaapi_object_dispose; + object_class->finalize = gst_vaapi_object_finalize; + object_class->set_property = gst_vaapi_object_set_property; + object_class->get_property = gst_vaapi_object_get_property; + + /** + * GstVaapiObject:display: + * + * The #GstVaapiDisplay this object is bound to. + */ + g_object_class_install_property + (object_class, + PROP_DISPLAY, + g_param_spec_object("display", + "Display", + "The GstVaapiDisplay this object is bound to", + GST_VAAPI_TYPE_DISPLAY, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + /** + * GstVaapiObject:id: + * + * The #GstVaapiID contained in this object. + */ + g_object_class_install_property + (object_class, + PROP_ID, + gst_vaapi_param_spec_id("id", + "ID", + "The GstVaapiID contained in this object", + GST_VAAPI_ID_NONE, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + /** + * GstVaapiObject::destroy: + * @object: the object which received the signal + * + * The ::destroy signal is emitted when an object is destroyed, + * when the user released the last reference to @object. + */ + object_signals[DESTROY] = g_signal_new( + "destroy", + G_TYPE_FROM_CLASS(object_class), + G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET(GstVaapiObjectClass, destroy), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0 + ); +} + +static void +gst_vaapi_object_init(GstVaapiObject *object) +{ + GstVaapiObjectPrivate *priv = GST_VAAPI_OBJECT_GET_PRIVATE(object); + + object->priv = priv; + priv->display = NULL; + priv->id = GST_VAAPI_ID_NONE; + priv->is_destroying = FALSE; +} + +/** + * gst_vaapi_object_get_display: + * @object: a #GstVaapiObject + * + * Returns the #GstVaapiDisplay this @object is bound to. + * + * Return value: the parent #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_object_get_display(GstVaapiObject *object) +{ + g_return_val_if_fail(GST_VAAPI_IS_OBJECT(object), NULL); + + return object->priv->display; +} + +/** + * gst_vaapi_object_lock_display: + * @object: a #GstVaapiObject + * + * Locks @object parent display. If display is already locked by + * another thread, the current thread will block until display is + * unlocked by the other thread. + */ +void +gst_vaapi_object_lock_display(GstVaapiObject *object) +{ + g_return_if_fail(GST_VAAPI_IS_OBJECT(object)); + + GST_VAAPI_OBJECT_LOCK_DISPLAY(object); +} + +/** + * gst_vaapi_object_unlock_display: + * @object: a #GstVaapiObject + * + * Unlocks @object parent display. If another thread is blocked in a + * gst_vaapi_object_lock_display() call, it will be woken and can lock + * display itself. + */ +void +gst_vaapi_object_unlock_display(GstVaapiObject *object) +{ + g_return_if_fail(GST_VAAPI_IS_OBJECT(object)); + + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(object); +} + +/** + * gst_vaapi_object_get_id: + * @object: a #GstVaapiObject + * + * Returns the #GstVaapiID contained in the @object. + * + * Return value: the #GstVaapiID of the @object + */ +GstVaapiID +gst_vaapi_object_get_id(GstVaapiObject *object) +{ + g_return_val_if_fail(GST_VAAPI_IS_OBJECT(object), GST_VAAPI_ID_NONE); + + return object->priv->id; +} diff --git a/gst-libs/gst/vaapi/gstvaapiobject.h b/gst-libs/gst/vaapi/gstvaapiobject.h new file mode 100644 index 0000000..913cac8 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiobject.h @@ -0,0 +1,101 @@ +/* + * gstvaapiobject.h - Base VA object + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_OBJECT_H +#define GST_VAAPI_OBJECT_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_OBJECT \ + (gst_vaapi_object_get_type()) + +#define GST_VAAPI_OBJECT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_OBJECT, \ + GstVaapiObject)) + +#define GST_VAAPI_OBJECT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_OBJECT, \ + GstVaapiObjectClass)) + +#define GST_VAAPI_IS_OBJECT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_OBJECT)) + +#define GST_VAAPI_IS_OBJECT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_OBJECT)) + +#define GST_VAAPI_OBJECT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_OBJECT, \ + GstVaapiObjectClass)) + +typedef struct _GstVaapiObject GstVaapiObject; +typedef struct _GstVaapiObjectPrivate GstVaapiObjectPrivate; +typedef struct _GstVaapiObjectClass GstVaapiObjectClass; + +/** + * GstVaapiObject: + * + * VA object base. + */ +struct _GstVaapiObject { + /*< private >*/ + GObject parent_instance; + + GstVaapiObjectPrivate *priv; +}; + +/** + * GstVaapiObjectClass: + * @destroy: signal class handler for #GstVaapiObject::destroy + * + * VA object base class. + */ +struct _GstVaapiObjectClass { + /*< private >*/ + GObjectClass parent_class; + + /*< public >*/ + void (*destroy)(GstVaapiObject *oject); +}; + +GType +gst_vaapi_object_get_type(void) G_GNUC_CONST; + +GstVaapiDisplay * +gst_vaapi_object_get_display(GstVaapiObject *object); + +void +gst_vaapi_object_lock_display(GstVaapiObject *object); + +void +gst_vaapi_object_unlock_display(GstVaapiObject *object); + +GstVaapiID +gst_vaapi_object_get_id(GstVaapiObject *object); + +G_END_DECLS + +#endif /* GST_VAAPI_OBJECT_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiobject_priv.h b/gst-libs/gst/vaapi/gstvaapiobject_priv.h new file mode 100644 index 0000000..aa1b110 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiobject_priv.h @@ -0,0 +1,166 @@ +/* + * gstvaapiobject_priv.h - Base VA object (private definitions) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_OBJECT_PRIV_H +#define GST_VAAPI_OBJECT_PRIV_H + +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_OBJECT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_OBJECT, \ + GstVaapiObjectPrivate)) + +#define GST_VAAPI_OBJECT_CAST(object) ((GstVaapiObject *)(object)) + +/** + * GST_VAAPI_OBJECT_DISPLAY: + * @object: a #GstVaapiObject + * + * Macro that evaluates to the #GstVaapiDisplay the @object is bound to. + * This is an internal macro that does not do any run-time type check. + */ +#define GST_VAAPI_OBJECT_DISPLAY(object) \ + GST_VAAPI_OBJECT_CAST(object)->priv->display + +/** + * GST_VAAPI_OBJECT_ID: + * @object: a #GstVaapiObject + * + * Macro that evaluates to the #GstVaapiID contained in @object. + * This is an internal macro that does not do any run-time type checks. + */ +#define GST_VAAPI_OBJECT_ID(object) \ + GST_VAAPI_OBJECT_CAST(object)->priv->id + +/** + * GST_VAAPI_OBJECT_DISPLAY_X11: + * @object: a #GstVaapiObject + * + * Macro that evaluates to the #GstVaapiDisplayX11 the @object is bound to. + * This is an internal macro that does not do any run-time type check + * and requires #include "gstvaapidisplay_x11_priv.h" + */ +#define GST_VAAPI_OBJECT_DISPLAY_X11(object) \ + GST_VAAPI_DISPLAY_X11_CAST(GST_VAAPI_OBJECT_DISPLAY(object)) + +/** + * GST_VAAPI_OBJECT_DISPLAY_GLX: + * @object: a #GstVaapiObject + * + * Macro that evaluates to the #GstVaapiDisplayGLX the @object is bound to. + * This is an internal macro that does not do any run-time type check + * and requires #include "gstvaapidisplay_glx_priv.h". + */ +#define GST_VAAPI_OBJECT_DISPLAY_GLX(object) \ + GST_VAAPI_DISPLAY_GLX_CAST(GST_VAAPI_OBJECT_DISPLAY(object)) + +/** + * GST_VAAPI_OBJECT_DISPLAY_WAYLAND: + * @object: a #GstVaapiObject + * + * Macro that evaluates to the #GstVaapiDisplayWayland the @object is + * bound to. This is an internal macro that does not do any run-time + * type check and requires #include "gstvaapidisplay_wayland_priv.h" + */ +#define GST_VAAPI_OBJECT_DISPLAY_WAYLAND(object) \ + GST_VAAPI_DISPLAY_WAYLAND_CAST(GST_VAAPI_OBJECT_DISPLAY(object)) + +/** + * GST_VAAPI_OBJECT_VADISPLAY: + * @object: a #GstVaapiObject + * + * Macro that evaluates to the #VADisplay of @display. + * This is an internal macro that does not do any run-time type check + * and requires #include "gstvaapidisplay_priv.h". + */ +#define GST_VAAPI_OBJECT_VADISPLAY(object) \ + GST_VAAPI_DISPLAY_VADISPLAY(GST_VAAPI_OBJECT_DISPLAY(object)) + +/** + * GST_VAAPI_OBJECT_XDISPLAY: + * @object: a #GstVaapiObject + * + * Macro that evaluates to the underlying X11 #Display of @display. + * This is an internal macro that does not do any run-time type check + * and requires #include "gstvaapidisplay_x11_priv.h". + */ +#define GST_VAAPI_OBJECT_XDISPLAY(object) \ + GST_VAAPI_DISPLAY_XDISPLAY(GST_VAAPI_OBJECT_DISPLAY(object)) + +/** + * GST_VAAPI_OBJECT_XSCREEN: + * @object: a #GstVaapiObject + * + * Macro that evaluates to the underlying X11 screen of @display. + * This is an internal macro that does not do any run-time type check + * and requires #include "gstvaapidisplay_x11_priv.h". + */ +#define GST_VAAPI_OBJECT_XSCREEN(object) \ + GST_VAAPI_DISPLAY_XSCREEN(GST_VAAPI_OBJECT_DISPLAY(object)) + +/** + * GST_VAAPI_OBJECT_WL_DISPLAY: + * @object: a #GstVaapiObject + * + * Macro that evaluates to the underlying #wl_display of @display. + * This is an internal macro that does not do any run-time type check + * and requires #include "gstvaapidisplay_wayland_priv.h". + */ +#define GST_VAAPI_OBJECT_WL_DISPLAY(object) \ + GST_VAAPI_DISPLAY_WL_DISPLAY(GST_VAAPI_OBJECT_DISPLAY(object)) + +/** + * GST_VAAPI_OBJECT_LOCK_DISPLAY: + * @object: a #GstVaapiObject + * + * Macro that locks the #GstVaapiDisplay contained in the @object. + * This is an internal macro that does not do any run-time type check. + */ +#define GST_VAAPI_OBJECT_LOCK_DISPLAY(object) \ + GST_VAAPI_DISPLAY_LOCK(GST_VAAPI_OBJECT_DISPLAY(object)) + +/** + * GST_VAAPI_OBJECT_UNLOCK_DISPLAY: + * @object: a #GstVaapiObject + * + * Macro that unlocks the #GstVaapiDisplay contained in the @object. + * This is an internal macro that does not do any run-time type check. + */ +#define GST_VAAPI_OBJECT_UNLOCK_DISPLAY(object) \ + GST_VAAPI_DISPLAY_UNLOCK(GST_VAAPI_OBJECT_DISPLAY(object)) + +/** + * GstVaapiObjectPrivate: + * + * VA object base. + */ +struct _GstVaapiObjectPrivate { + GstVaapiDisplay *display; + GstVaapiID id; + guint is_destroying : 1; +}; + +G_END_DECLS + +#endif /* GST_VAAPI_OBJECT_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiparamspecs.c b/gst-libs/gst/vaapi/gstvaapiparamspecs.c new file mode 100644 index 0000000..8905af4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiparamspecs.c @@ -0,0 +1,140 @@ +/* + * gstvaapiparamspecs.c - GParamSpecs for some of our types + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiparamspecs + * @short_description: GParamSpecs for some of our types + */ + +#include "sysdeps.h" +#include "gstvaapiparamspecs.h" +#include "gstvaapivalue.h" + +/* --- GstVaapiParamSpecID --- */ + +static void +gst_vaapi_param_id_init(GParamSpec *pspec) +{ + GST_VAAPI_PARAM_SPEC_ID(pspec)->default_value = GST_VAAPI_ID_NONE; +} + +static void +gst_vaapi_param_id_set_default(GParamSpec *pspec, GValue *value) +{ + gst_vaapi_value_set_id(value, GST_VAAPI_PARAM_SPEC_ID(pspec)->default_value); +} + +static gboolean +gst_vaapi_param_id_validate(GParamSpec *pspec, GValue *value) +{ + /* Return FALSE if everything is OK, otherwise TRUE */ + return FALSE; +} + +static gint +gst_vaapi_param_id_compare( + GParamSpec *pspec, + const GValue *value1, + const GValue *value2 +) +{ + const GstVaapiID v1 = gst_vaapi_value_get_id(value1); + const GstVaapiID v2 = gst_vaapi_value_get_id(value2); + + return (v1 < v2 ? -1 : (v1 > v2 ? 1 : 0)); +} + +GType +gst_vaapi_param_spec_id_get_type(void) +{ + static GType type; + + if (G_UNLIKELY(type == 0)) { + static GParamSpecTypeInfo pspec_info = { + sizeof(GstVaapiParamSpecID), /* instance_size */ + 0, /* n_preallocs */ + gst_vaapi_param_id_init, /* instance_init */ + G_TYPE_INVALID, /* value_type */ + NULL, /* finalize */ + gst_vaapi_param_id_set_default, /* value_set_default */ + gst_vaapi_param_id_validate, /* value_validate */ + gst_vaapi_param_id_compare, /* values_cmp */ + }; + pspec_info.value_type = GST_VAAPI_TYPE_ID; + type = g_param_type_register_static("GstVaapiParamSpecID", &pspec_info); + } + return type; +} + +/** + * gst_vaapi_param_spec_id: + * @name: canonical name of the property specified + * @nick: nick name for the property specified + * @blurb: description of the property specified + * @default_value: default value + * @flags: flags for the property specified + * + * This function creates an ID GParamSpec for use by #GstVaapiObject + * objects. This function is typically used in connection with + * g_object_class_install_property() in a GObjects's instance_init + * function. + * + * Return value: a newly created parameter specification + */ +GParamSpec * +gst_vaapi_param_spec_id( + const gchar *name, + const gchar *nick, + const gchar *blurb, + GstVaapiID default_value, + GParamFlags flags +) +{ + GstVaapiParamSpecID *ispec; + GParamSpec *pspec; + GValue value = { 0, }; + + ispec = g_param_spec_internal( + GST_VAAPI_TYPE_PARAM_ID, + name, + nick, + blurb, + flags + ); + if (!ispec) + return NULL; + + ispec->default_value = default_value; + pspec = G_PARAM_SPEC(ispec); + + /* Validate default value */ + g_value_init(&value, GST_VAAPI_TYPE_ID); + gst_vaapi_value_set_id(&value, default_value); + if (gst_vaapi_param_id_validate(pspec, &value)) { + g_param_spec_ref(pspec); + g_param_spec_sink(pspec); + g_param_spec_unref(pspec); + pspec = NULL; + } + g_value_unset(&value); + + return pspec; +} diff --git a/gst-libs/gst/vaapi/gstvaapiparamspecs.h b/gst-libs/gst/vaapi/gstvaapiparamspecs.h new file mode 100644 index 0000000..5b20149 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiparamspecs.h @@ -0,0 +1,71 @@ +/* + * gstvaapiparamspecs.h - GParamSpecs for some of our types + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_PARAM_SPECS_H +#define GST_VAAPI_PARAM_SPECS_H + +#include +#include + +G_BEGIN_DECLS + +/** + * GstVaapiParamSpecID: + * @parent_instance: super class + * @default_value: default value + * + * A GParamSpec derived structure that contains the meta data for + * #GstVaapiID properties. + */ +typedef struct _GstVaapiParamSpecID GstVaapiParamSpecID; +struct _GstVaapiParamSpecID { + GParamSpec parent_instance; + + GstVaapiID default_value; +}; + +#define GST_VAAPI_TYPE_PARAM_ID \ + (gst_vaapi_param_spec_id_get_type()) + +#define GST_VAAPI_IS_PARAM_SPEC_ID(pspec) \ + (G_TYPE_CHECK_INSTANCE_TYPE((pspec), \ + GST_VAAPI_TYPE_PARAM_ID)) + +#define GST_VAAPI_PARAM_SPEC_ID(pspec) \ + (G_TYPE_CHECK_INSTANCE_CAST((pspec), \ + GST_VAAPI_TYPE_PARAM_ID, \ + GstVaapiParamSpecID)) + +GType +gst_vaapi_param_spec_id_get_type(void) G_GNUC_CONST; + +GParamSpec * +gst_vaapi_param_spec_id( + const gchar *name, + const gchar *nick, + const gchar *blurb, + GstVaapiID default_value, + GParamFlags flags +); + +G_END_DECLS + +#endif /* GST_VAAPI_PARAM_SPECS_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiprofile.c b/gst-libs/gst/vaapi/gstvaapiprofile.c new file mode 100644 index 0000000..7536c44 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiprofile.c @@ -0,0 +1,392 @@ +/* + * gstvaapiprofile.c - VA profile abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiprofile + * @short_description: VA profile abstraction + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapicompat.h" +#include "gstvaapiprofile.h" +#include "gstvaapiworkarounds.h" + +typedef struct _GstVaapiProfileMap GstVaapiProfileMap; +typedef struct _GstVaapiEntrypointMap GstVaapiEntrypointMap; + +struct _GstVaapiProfileMap { + GstVaapiProfile profile; + VAProfile va_profile; + const char *caps_str; + const gchar *profile_str; +}; + +struct _GstVaapiEntrypointMap { + GstVaapiEntrypoint entrypoint; + VAEntrypoint va_entrypoint; +}; + +/* Profiles */ +static const GstVaapiProfileMap gst_vaapi_profiles[] = { + { GST_VAAPI_PROFILE_MPEG2_SIMPLE, VAProfileMPEG2Simple, + "video/mpeg, mpegversion=2", "simple" + }, + { GST_VAAPI_PROFILE_MPEG2_MAIN, VAProfileMPEG2Main, + "video/mpeg, mpegversion=2", "main" + }, + { GST_VAAPI_PROFILE_MPEG4_SIMPLE, VAProfileMPEG4Simple, + "video/mpeg, mpegversion=4", "simple" + }, + { GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple, + "video/mpeg, mpegversion=4", "advanced-simple" + }, + { GST_VAAPI_PROFILE_MPEG4_MAIN, VAProfileMPEG4Main, + "video/mpeg, mpegversion=4", "main" + }, + { GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple, + "video/x-divx, divxversion=5", "advanced-simple" + }, + { GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple, + "video/x-xvid", "advanced-simple" + }, +#if VA_CHECK_VERSION(0,30,0) + { GST_VAAPI_PROFILE_H263_BASELINE, VAProfileH263Baseline, + "video/x-h263, variant=itu, h263version=h263", "baseline" + }, +#endif + { GST_VAAPI_PROFILE_H264_BASELINE, VAProfileH264Baseline, + "video/x-h264", "baseline" + }, + { GST_VAAPI_PROFILE_H264_MAIN, VAProfileH264Main, + "video/x-h264", "main" + }, + { GST_VAAPI_PROFILE_H264_HIGH, VAProfileH264High, + "video/x-h264", "high" + }, + { GST_VAAPI_PROFILE_VC1_SIMPLE, VAProfileVC1Simple, + "video/x-wmv, wmvversion=3", "simple" + }, + { GST_VAAPI_PROFILE_VC1_MAIN, VAProfileVC1Main, + "video/x-wmv, wmvversion=3", "main" + }, + { GST_VAAPI_PROFILE_VC1_ADVANCED, VAProfileVC1Advanced, + "video/x-wmv, wmvversion=3, format=(fourcc)WVC1", "advanced" + }, +#if VA_CHECK_VERSION(0,32,0) + { GST_VAAPI_PROFILE_JPEG_BASELINE, VAProfileJPEGBaseline, + "image/jpeg", "baseline" + }, +#endif + { 0, } +}; + +/* Entry-points */ +static const GstVaapiEntrypointMap gst_vaapi_entrypoints[] = { + { GST_VAAPI_ENTRYPOINT_VLD, VAEntrypointVLD }, + { GST_VAAPI_ENTRYPOINT_IDCT, VAEntrypointIDCT }, + { GST_VAAPI_ENTRYPOINT_MOCO, VAEntrypointMoComp }, +#if VA_CHECK_VERSION(0,30,0) + { GST_VAAPI_ENTRYPOINT_SLICE_ENCODE, VAEntrypointEncSlice }, +#endif + { 0, } +}; + +static const GstVaapiProfileMap * +get_profiles_map(GstVaapiProfile profile) +{ + const GstVaapiProfileMap *m; + + for (m = gst_vaapi_profiles; m->profile; m++) + if (m->profile == profile) + return m; + return NULL; +} + +static const GstVaapiEntrypointMap * +get_entrypoints_map(GstVaapiEntrypoint entrypoint) +{ + const GstVaapiEntrypointMap *m; + + for (m = gst_vaapi_entrypoints; m->entrypoint; m++) + if (m->entrypoint == entrypoint) + return m; + return NULL; +} + +/** + * gst_vaapi_profile: + * @profile: a #VAProfile + * + * Converts a VA profile into the corresponding #GstVaapiProfile. If + * the profile cannot be represented by #GstVaapiProfile, then zero is + * returned. + * + * Return value: the #GstVaapiProfile describing the @profile + */ +GstVaapiProfile +gst_vaapi_profile(VAProfile profile) +{ + const GstVaapiProfileMap *m; + + for (m = gst_vaapi_profiles; m->profile; m++) + if (m->va_profile == profile) + return m->profile; + return 0; +} + +/** + * gst_vaapi_profile_from_codec_data: + * @codec: a #GstVaapiCodec + * @buffer: a #GstBuffer holding code data + * + * Tries to parse VA profile from @buffer data and @codec information. + * + * Return value: the #GstVaapiProfile described in @buffer + */ +static GstVaapiProfile +gst_vaapi_profile_from_codec_data_h264(GstBuffer *buffer) +{ + /* MPEG-4 Part 15: Advanced Video Coding (AVC) file format */ + guchar * const buf = GST_BUFFER_DATA(buffer); + + if (buf[0] != 1) /* configurationVersion = 1 */ + return 0; + + switch (buf[1]) { /* AVCProfileIndication */ + case 66: return GST_VAAPI_PROFILE_H264_BASELINE; + case 77: return GST_VAAPI_PROFILE_H264_MAIN; + case 100: return GST_VAAPI_PROFILE_H264_HIGH; + } + return 0; +} + +static GstVaapiProfile +gst_vaapi_profile_from_codec_data(GstVaapiCodec codec, GstBuffer *buffer) +{ + GstVaapiProfile profile; + + if (!codec || !buffer) + return 0; + + switch (codec) { + case GST_VAAPI_CODEC_H264: + profile = gst_vaapi_profile_from_codec_data_h264(buffer); + break; + default: + profile = 0; + break; + } + return profile; +} + +/** + * gst_vaapi_profile_from_caps: + * @caps: a #GstCaps + * + * Converts @caps into the corresponding #GstVaapiProfile. If the + * profile cannot be represented by #GstVaapiProfile, then zero is + * returned. + * + * Return value: the #GstVaapiProfile describing the @caps + */ +GstVaapiProfile +gst_vaapi_profile_from_caps(GstCaps *caps) +{ + const GstVaapiProfileMap *m; + GstCaps *caps_test; + GstStructure *structure; + const gchar *profile_str; + GstVaapiProfile profile, best_profile; + GstBuffer *codec_data = NULL; + const gchar *name; + gsize namelen; + + if (!caps) + return 0; + + structure = gst_caps_get_structure(caps, 0); + if (!structure) + return 0; + + name = gst_structure_get_name(structure); + namelen = strlen(name); + + profile_str = gst_structure_get_string(structure, "profile"); + if (!profile_str) { + const GValue *v_codec_data; + v_codec_data = gst_structure_get_value(structure, "codec_data"); + if (v_codec_data) + codec_data = gst_value_get_buffer(v_codec_data); + } + + profile = 0; + best_profile = 0; + for (m = gst_vaapi_profiles; !profile && m->profile; m++) { + if (strncmp(name, m->caps_str, namelen) != 0) + continue; + caps_test = gst_caps_from_string(m->caps_str);; + if (gst_caps_is_always_compatible(caps, caps_test)) { + best_profile = m->profile; + if (profile_str && m->profile_str && + strcmp(profile_str, m->profile_str) == 0) + profile = best_profile; + } + if (!profile) { + profile = gst_vaapi_profile_from_codec_data( + gst_vaapi_profile_get_codec(m->profile), + codec_data + ); + if (!profile && + WORKAROUND_QTDEMUX_NO_H263_PROFILES && + strncmp(name, "video/x-h263", namelen) == 0) { + /* HACK: qtdemux does not report profiles for h263 */ + profile = m->profile; + } + } + gst_caps_unref(caps_test); + } + return profile ? profile : best_profile; +} + +/** + * gst_vaapi_profile_get_va_profile: + * @profile: a #GstVaapiProfile + * + * Converts a #GstVaapiProfile into the corresponding VA profile. If + * no matching VA profile was found, -1 is returned and this error + * must be reported to be fixed. + * + * Return value: the VA profile, or -1 if none was found + */ +VAProfile +gst_vaapi_profile_get_va_profile(GstVaapiProfile profile) +{ + const GstVaapiProfileMap * const m = get_profiles_map(profile); + + return m ? m->va_profile : (VAProfile)-1; +} + +/** + * gst_vaapi_profile_get_caps: + * @profile: a #GstVaapiProfile + * + * Converts a #GstVaapiProfile into the corresponding #GstCaps. If no + * matching caps were found, %NULL is returned. + * + * Return value: the newly allocated #GstCaps, or %NULL if none was found + */ +GstCaps * +gst_vaapi_profile_get_caps(GstVaapiProfile profile) +{ + const GstVaapiProfileMap *m; + GstCaps *out_caps, *caps; + + out_caps = gst_caps_new_empty(); + if (!out_caps) + return NULL; + + for (m = gst_vaapi_profiles; m->profile; m++) { + if (m->profile != profile) + continue; + caps = gst_caps_from_string(m->caps_str); + if (!caps) + continue; + gst_caps_set_simple( + caps, + "profile", G_TYPE_STRING, m->profile_str, + NULL + ); + gst_caps_merge(out_caps, caps); + } + return out_caps; +} + +/** + * gst_vaapi_profile_get_codec: + * @profile: a #GstVaapiProfile + * + * Extracts the #GstVaapiCodec from @profile. + * + * Return value: the #GstVaapiCodec from @profile + */ +GstVaapiCodec +gst_vaapi_profile_get_codec(GstVaapiProfile profile) +{ + GstVaapiCodec codec; + + switch (profile) { + case GST_VAAPI_PROFILE_VC1_SIMPLE: + case GST_VAAPI_PROFILE_VC1_MAIN: + codec = GST_VAAPI_CODEC_WMV3; + break; + case GST_VAAPI_PROFILE_VC1_ADVANCED: + codec = GST_VAAPI_CODEC_VC1; + break; + case GST_VAAPI_PROFILE_JPEG_BASELINE: + codec = GST_VAAPI_CODEC_JPEG; + break; + default: + codec = (guint32)profile & GST_MAKE_FOURCC(0xff,0xff,0xff,0); + break; + } + return codec; +} + +/** + * gst_vaapi_entrypoint: + * @entrypoint: a #VAEntrypoint + * + * Converts a VA entry-point into the corresponding #GstVaapiEntrypoint. + * If the entry-point cannot be represented by #GstVaapiEntrypoint, + * then zero is returned. + * + * Return value: the #GstVaapiEntrypoint describing the @entrypoint + */ +GstVaapiEntrypoint +gst_vaapi_entrypoint(VAEntrypoint entrypoint) +{ + const GstVaapiEntrypointMap *m; + + for (m = gst_vaapi_entrypoints; m->entrypoint; m++) + if (m->va_entrypoint == entrypoint) + return m->entrypoint; + return 0; +} + +/** + * gst_vaapi_entrypoint_get_va_entrypoint: + * @entrypoint: a #GstVaapiEntrypoint + * + * Converts a #GstVaapiEntrypoint into the corresponding VA + * entry-point. If no matching VA entry-point was found, -1 is + * returned and this error must be reported to be fixed. + * + * Return value: the VA entry-point, or -1 if none was found + */ +VAEntrypoint +gst_vaapi_entrypoint_get_va_entrypoint(GstVaapiEntrypoint entrypoint) +{ + const GstVaapiEntrypointMap * const m = get_entrypoints_map(entrypoint); + + return m ? m->va_entrypoint : (VAEntrypoint)-1; +} diff --git a/gst-libs/gst/vaapi/gstvaapiprofile.h b/gst-libs/gst/vaapi/gstvaapiprofile.h new file mode 100644 index 0000000..986c9a2 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiprofile.h @@ -0,0 +1,160 @@ +/* + * gstvaapiprofile.h - VA profile abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_PROFILE_H +#define GST_VAAPI_PROFILE_H + +#include + +G_BEGIN_DECLS + +typedef enum _GstVaapiCodec GstVaapiCodec; +typedef enum _GstVaapiProfile GstVaapiProfile; +typedef enum _GstVaapiEntrypoint GstVaapiEntrypoint; + +/** + * GstVaapiCodec: + * @GST_VAAPI_CODEC_MPEG1: MPEG-1 (ISO/IEC 11172) + * @GST_VAAPI_CODEC_MPEG2: MPEG-2 (ISO/IEC 13818-2) + * @GST_VAAPI_CODEC_MPEG4: MPEG-4 Part 2 (ISO/IEC 14496-2) + * @GST_VAAPI_CODEC_H263: H.263 + * @GST_VAAPI_CODEC_H264: H.264 aka MPEG-4 Part 10 (ISO/IEC 14496-10) + * @GST_VAAPI_CODEC_WMV3: Windows Media Video 9. VC-1 Simple or Main profile (SMPTE 421M) + * @GST_VAAPI_CODEC_VC1: VC-1 Advanced profile (SMPTE 421M) + * + * The set of all codecs for #GstVaapiCodec. + */ +enum _GstVaapiCodec { + GST_VAAPI_CODEC_MPEG1 = GST_MAKE_FOURCC('M','P','1',0), + GST_VAAPI_CODEC_MPEG2 = GST_MAKE_FOURCC('M','P','2',0), + GST_VAAPI_CODEC_MPEG4 = GST_MAKE_FOURCC('M','P','4',0), + GST_VAAPI_CODEC_H263 = GST_MAKE_FOURCC('2','6','3',0), + GST_VAAPI_CODEC_H264 = GST_MAKE_FOURCC('2','6','4',0), + GST_VAAPI_CODEC_WMV3 = GST_MAKE_FOURCC('W','M','V',0), + GST_VAAPI_CODEC_VC1 = GST_MAKE_FOURCC('V','C','1',0), + GST_VAAPI_CODEC_JPEG = GST_MAKE_FOURCC('J','P','G',0), +}; + +/** + * GST_VAAPI_MAKE_PROFILE: + * @codec: the #GstVaapiCodec without the GST_VAAPI_CODEC_ prefix + * @sub_id: a non-zero sub-codec id + * + * Macro that evaluates to the profile composed from @codec and + * @sub_id. + */ +#define GST_VAAPI_MAKE_PROFILE(codec, sub_id) \ + (GST_VAAPI_CODEC_##codec | GST_MAKE_FOURCC(0,0,0,sub_id)) + +/** + * GstVaapiProfile: + * @GST_VAAPI_PROFILE_UNKNOWN: + * Unknown profile, used for initializers + * @GST_VAAPI_PROFILE_MPEG1: + * MPEG-1 + * @GST_VAAPI_PROFILE_MPEG2_SIMPLE: + * MPEG-2 simple profile + * @GST_VAAPI_PROFILE_MPEG2_MAIN: + * MPEG-2 main profile + * @GST_VAAPI_PROFILE_MPEG2_HIGH: + * MPEG-2 high profile + * @GST_VAAPI_PROFILE_MPEG4_SIMPLE: + * MPEG-4 Part-2 simple profile + * @GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE: + * MPEG-4 Part-2 advanced simple profile + * @GST_VAAPI_PROFILE_MPEG4_MAIN: + * MPEG-4 Part-2 main profile + * @GST_VAAPI_PROFILE_H263_BASELINE: + * H.263 baseline profile + * @GST_VAAPI_PROFILE_H264_BASELINE: + * H.264 (MPEG-4 Part-10) baseline profile + * @GST_VAAPI_PROFILE_H264_MAIN: + * H.264 (MPEG-4 Part-10) main profile + * @GST_VAAPI_PROFILE_H264_HIGH: + * H.264 (MPEG-4 Part-10) high profile + * @GST_VAAPI_PROFILE_VC1_SIMPLE: + * VC-1 simple profile + * @GST_VAAPI_PROFILE_VC1_MAIN: + * VC-1 main profile + * @GST_VAAPI_PROFILE_VC1_ADVANCED: + * VC-1 advanced profile + * + * The set of all profiles for #GstVaapiProfile. + */ +enum _GstVaapiProfile { + GST_VAAPI_PROFILE_UNKNOWN = 0, + GST_VAAPI_PROFILE_MPEG1 = GST_VAAPI_MAKE_PROFILE(MPEG1,1), + GST_VAAPI_PROFILE_MPEG2_SIMPLE = GST_VAAPI_MAKE_PROFILE(MPEG2,1), + GST_VAAPI_PROFILE_MPEG2_MAIN = GST_VAAPI_MAKE_PROFILE(MPEG2,2), + GST_VAAPI_PROFILE_MPEG2_HIGH = GST_VAAPI_MAKE_PROFILE(MPEG2,3), + GST_VAAPI_PROFILE_MPEG4_SIMPLE = GST_VAAPI_MAKE_PROFILE(MPEG4,1), + GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE = GST_VAAPI_MAKE_PROFILE(MPEG4,2), + GST_VAAPI_PROFILE_MPEG4_MAIN = GST_VAAPI_MAKE_PROFILE(MPEG4,3), + GST_VAAPI_PROFILE_H263_BASELINE = GST_VAAPI_MAKE_PROFILE(H263,1), + GST_VAAPI_PROFILE_H264_BASELINE = GST_VAAPI_MAKE_PROFILE(H264,1), + GST_VAAPI_PROFILE_H264_MAIN = GST_VAAPI_MAKE_PROFILE(H264,2), + GST_VAAPI_PROFILE_H264_HIGH = GST_VAAPI_MAKE_PROFILE(H264,3), + GST_VAAPI_PROFILE_VC1_SIMPLE = GST_VAAPI_MAKE_PROFILE(VC1,1), + GST_VAAPI_PROFILE_VC1_MAIN = GST_VAAPI_MAKE_PROFILE(VC1,2), + GST_VAAPI_PROFILE_VC1_ADVANCED = GST_VAAPI_MAKE_PROFILE(VC1,3), + GST_VAAPI_PROFILE_JPEG_BASELINE = GST_VAAPI_MAKE_PROFILE(JPEG,1), +}; + +/** + * GstVaapiEntrypoint: + * @GST_VAAPI_ENTRYPOINT_VLD: Variable Length Decoding + * @GST_VAAPI_ENTRYPOINT_IDCT: Inverse Decrete Cosine Transform + * @GST_VAAPI_ENTRYPOINT_MOCO: Motion Compensation + * @GST_VAAPI_ENTRYPOINT_SLICE_ENCODE: Encode Slice + * + * The set of all entrypoints for #GstVaapiEntrypoint + */ +enum _GstVaapiEntrypoint { + GST_VAAPI_ENTRYPOINT_VLD = 1, + GST_VAAPI_ENTRYPOINT_IDCT, + GST_VAAPI_ENTRYPOINT_MOCO, + GST_VAAPI_ENTRYPOINT_SLICE_ENCODE +}; + +GstVaapiProfile +gst_vaapi_profile(VAProfile profile); + +GstVaapiProfile +gst_vaapi_profile_from_caps(GstCaps *caps); + +VAProfile +gst_vaapi_profile_get_va_profile(GstVaapiProfile profile); + +GstCaps * +gst_vaapi_profile_get_caps(GstVaapiProfile profile); + +GstVaapiCodec +gst_vaapi_profile_get_codec(GstVaapiProfile profile); + +GstVaapiEntrypoint +gst_vaapi_entrypoint(VAEntrypoint entrypoint); + +VAEntrypoint +gst_vaapi_entrypoint_get_va_entrypoint(GstVaapiEntrypoint entrypoint); + +G_END_DECLS + +#endif /* GST_GST_VAAPI_IMAGE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisubpicture.c b/gst-libs/gst/vaapi/gstvaapisubpicture.c new file mode 100644 index 0000000..cfd7fd3 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisubpicture.c @@ -0,0 +1,334 @@ +/* + * gstvaapisubpicture.c - VA subpicture abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapisubpicture + * @short_description: VA subpicture abstraction + */ + +#include "sysdeps.h" +#include +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapisubpicture.h" +#include "gstvaapi_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiSubpicture, gst_vaapi_subpicture, GST_VAAPI_TYPE_OBJECT); + +#define GST_VAAPI_SUBPICTURE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_SUBPICTURE, \ + GstVaapiSubpicturePrivate)) + +struct _GstVaapiSubpicturePrivate { + GstVaapiImage *image; +}; + +enum { + PROP_0, + + PROP_IMAGE +}; + +static void +gst_vaapi_subpicture_destroy(GstVaapiSubpicture *subpicture) +{ + GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(subpicture); + GstVaapiSubpicturePrivate * const priv = subpicture->priv; + VASubpictureID subpicture_id; + VAStatus status; + + subpicture_id = GST_VAAPI_OBJECT_ID(subpicture); + GST_DEBUG("subpicture %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS(subpicture_id)); + + if (subpicture_id != VA_INVALID_ID) { + if (display) { + GST_VAAPI_DISPLAY_LOCK(display); + status = vaDestroySubpicture( + GST_VAAPI_DISPLAY_VADISPLAY(display), + subpicture_id + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaDestroySubpicture()")) + g_warning("failed to destroy subpicture %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS(subpicture_id)); + } + GST_VAAPI_OBJECT_ID(subpicture) = VA_INVALID_ID; + } + + g_clear_object(&priv->image); +} + +static gboolean +gst_vaapi_subpicture_create(GstVaapiSubpicture *subpicture) +{ + GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(subpicture); + GstVaapiSubpicturePrivate * const priv = subpicture->priv; + VASubpictureID subpicture_id; + VAStatus status; + + if (!priv->image) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaCreateSubpicture( + GST_VAAPI_DISPLAY_VADISPLAY(display), + GST_VAAPI_OBJECT_ID(priv->image), + &subpicture_id + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaCreateSubpicture()")) + return FALSE; + + GST_DEBUG("subpicture %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS(subpicture_id)); + GST_VAAPI_OBJECT_ID(subpicture) = subpicture_id; + return TRUE; +} + +static void +gst_vaapi_subpicture_finalize(GObject *object) +{ + gst_vaapi_subpicture_destroy(GST_VAAPI_SUBPICTURE(object)); + + G_OBJECT_CLASS(gst_vaapi_subpicture_parent_class)->finalize(object); +} + +static void +gst_vaapi_subpicture_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiSubpicture * const subpicture = GST_VAAPI_SUBPICTURE(object); + + switch (prop_id) { + case PROP_IMAGE: + gst_vaapi_subpicture_set_image(subpicture, g_value_get_object(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_subpicture_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiSubpicture * const subpicture = GST_VAAPI_SUBPICTURE(object); + + switch (prop_id) { + case PROP_IMAGE: + g_value_set_object(value, gst_vaapi_subpicture_get_image(subpicture)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_subpicture_class_init(GstVaapiSubpictureClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiSubpicturePrivate)); + + object_class->finalize = gst_vaapi_subpicture_finalize; + object_class->set_property = gst_vaapi_subpicture_set_property; + object_class->get_property = gst_vaapi_subpicture_get_property; + + /** + * GstVaapiSubpicture:image: + * + * The #GstVaapiImage this subpicture is bound to. + */ + g_object_class_install_property + (object_class, + PROP_IMAGE, + g_param_spec_object("image", + "Image", + "The GstVaapiImage this subpicture is bound to", + GST_VAAPI_TYPE_IMAGE, + G_PARAM_READWRITE)); +} + +static void +gst_vaapi_subpicture_init(GstVaapiSubpicture *subpicture) +{ + GstVaapiSubpicturePrivate *priv = GST_VAAPI_SUBPICTURE_GET_PRIVATE(subpicture); + + subpicture->priv = priv; + priv->image = NULL; +} + +/** + * gst_vaapi_subpicture_new: + * @image: a #GstVaapiImage + * + * Creates a new #GstVaapiSubpicture with @image as source pixels. The + * newly created object holds a reference on @image. + * + * Return value: the newly allocated #GstVaapiSubpicture object + */ +GstVaapiSubpicture * +gst_vaapi_subpicture_new(GstVaapiImage *image) +{ + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL); + + GST_DEBUG("create from image %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(image))); + + return g_object_new(GST_VAAPI_TYPE_SUBPICTURE, + "display", GST_VAAPI_OBJECT_DISPLAY(image), + "id", GST_VAAPI_ID(VA_INVALID_ID), + "image", image, + NULL); +} + +/** + * gst_vaapi_subpicture_new_from_overlay_rectangle: + * @display: a #GstVaapiDisplay + * @rect: a #GstVideoOverlayRectangle + * + * Helper function that creates a new #GstVaapiSubpicture from a + * #GstVideoOverlayRectangle. A new #GstVaapiImage is also created + * along the way and attached to the resulting subpicture. The + * subpicture holds a unique reference to the underlying image. + * + * Return value: the newly allocated #GstVaapiSubpicture object + */ +GstVaapiSubpicture * +gst_vaapi_subpicture_new_from_overlay_rectangle( + GstVaapiDisplay *display, + GstVideoOverlayRectangle *rect +) +{ + GstVaapiSubpicture *subpicture; + GstVaapiImageFormat format; + GstVaapiImage *image; + GstVaapiImageRaw raw_image; + GstBuffer *buffer; + guint width, height, stride; + + g_return_val_if_fail(GST_IS_VIDEO_OVERLAY_RECTANGLE(rect), NULL); + + buffer = gst_video_overlay_rectangle_get_pixels_unscaled_argb( + rect, + &width, &height, &stride, + GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE + ); + if (!buffer) + return NULL; + + /* XXX: use gst_vaapi_image_format_from_video() */ +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + format = GST_VAAPI_IMAGE_BGRA; +#else + format = GST_VAAPI_IMAGE_ARGB; +#endif + image = gst_vaapi_image_new(display, format, width, height); + if (!image) + return NULL; + + raw_image.format = format; + raw_image.width = width; + raw_image.height = height; + raw_image.num_planes = 1; + raw_image.pixels[0] = GST_BUFFER_DATA(buffer); + raw_image.stride[0] = stride; + if (!gst_vaapi_image_update_from_raw(image, &raw_image, NULL)) { + GST_WARNING("could not update VA image with subtitle data"); + g_object_unref(image); + return NULL; + } + + subpicture = gst_vaapi_subpicture_new(image); + g_object_unref(image); + return subpicture; +} + +/** + * gst_vaapi_subpicture_get_id: + * @subpicture: a #GstVaapiSubpicture + * + * Returns the underlying VASubpictureID of the @subpicture. + * + * Return value: the underlying VA subpicture id + */ +GstVaapiID +gst_vaapi_subpicture_get_id(GstVaapiSubpicture *subpicture) +{ + g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), VA_INVALID_ID); + + return GST_VAAPI_OBJECT_ID(subpicture); +} + +/** + * gst_vaapi_subpicture_get_image: + * @subpicture: a #GstVaapiSubpicture + * + * Returns the #GstVaapiImage this @subpicture is bound to. + * + * Return value: the #GstVaapiImage this @subpicture is bound to + */ +GstVaapiImage * +gst_vaapi_subpicture_get_image(GstVaapiSubpicture *subpicture) +{ + g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), NULL); + + return subpicture->priv->image; +} + +/** + * gst_vaapi_subpicture_set_image: + * @subpicture: a #GstVaapiSubpicture + * @image: a #GstVaapiImage + * + * Binds a new #GstVaapiImage to the @subpicture. The reference to the + * previous image is released and a new one is acquired on @image. + */ +void +gst_vaapi_subpicture_set_image( + GstVaapiSubpicture *subpicture, + GstVaapiImage *image +) +{ + g_return_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture)); + g_return_if_fail(GST_VAAPI_IS_IMAGE(image)); + + gst_vaapi_subpicture_destroy(subpicture); + + subpicture->priv->image = g_object_ref(image); + gst_vaapi_subpicture_create(subpicture); +} diff --git a/gst-libs/gst/vaapi/gstvaapisubpicture.h b/gst-libs/gst/vaapi/gstvaapisubpicture.h new file mode 100644 index 0000000..e7a6dbf --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisubpicture.h @@ -0,0 +1,109 @@ +/* + * gstvaapisubpicture.h - VA subpicture abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SUBPICTURE_H +#define GST_VAAPI_SUBPICTURE_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_SUBPICTURE \ + (gst_vaapi_subpicture_get_type()) + +#define GST_VAAPI_SUBPICTURE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_SUBPICTURE, \ + GstVaapiSubpicture)) + +#define GST_VAAPI_SUBPICTURE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_SUBPICTURE, \ + GstVaapiSubpictureClass)) + +#define GST_VAAPI_IS_SUBPICTURE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_SUBPICTURE)) + +#define GST_VAAPI_IS_SUBPICTURE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_SUBPICTURE)) + +#define GST_VAAPI_SUBPICTURE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_SUBPICTURE, \ + GstVaapiSubpictureClass)) + +typedef struct _GstVaapiSubpicture GstVaapiSubpicture; +typedef struct _GstVaapiSubpicturePrivate GstVaapiSubpicturePrivate; +typedef struct _GstVaapiSubpictureClass GstVaapiSubpictureClass; + +/** + * GstVaapiSubpicture: + * + * A VA subpicture wrapper + */ +struct _GstVaapiSubpicture { + /*< private >*/ + GstVaapiObject parent_instance; + + GstVaapiSubpicturePrivate *priv; +}; + +/** + * GstVaapiSubpictureClass: + * + * A VA subpicture wrapper class + */ +struct _GstVaapiSubpictureClass { + /*< private >*/ + GstVaapiObjectClass parent_class; +}; + +GType +gst_vaapi_subpicture_get_type(void) G_GNUC_CONST; + +GstVaapiSubpicture * +gst_vaapi_subpicture_new(GstVaapiImage *image); + +GstVaapiSubpicture * +gst_vaapi_subpicture_new_from_overlay_rectangle( + GstVaapiDisplay *display, + GstVideoOverlayRectangle *rect +); + +GstVaapiID +gst_vaapi_subpicture_get_id(GstVaapiSubpicture *subpicture); + +GstVaapiImage * +gst_vaapi_subpicture_get_image(GstVaapiSubpicture *subpicture); + +void +gst_vaapi_subpicture_set_image( + GstVaapiSubpicture *subpicture, + GstVaapiImage *image +); + +G_END_DECLS + +#endif /* GST_VAAPI_SUBPICTURE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurface.c b/gst-libs/gst/vaapi/gstvaapisurface.c new file mode 100644 index 0000000..18b9559 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface.c @@ -0,0 +1,942 @@ +/* + * gstvaapisurface.c - VA surface abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapisurface + * @short_description: VA surface abstraction + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapisurface.h" +#include "gstvaapisurface_priv.h" +#include "gstvaapicontext.h" +#include "gstvaapiimage.h" +#include "gstvaapi_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiSurface, gst_vaapi_surface, GST_VAAPI_TYPE_OBJECT); + +#define GST_VAAPI_SURFACE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_SURFACE, \ + GstVaapiSurfacePrivate)) + +struct _GstVaapiSurfacePrivate { + guint width; + guint height; + GstVaapiChromaType chroma_type; + GPtrArray *subpictures; + GstVaapiContext *parent_context; +}; + +enum { + PROP_0, + + PROP_WIDTH, + PROP_HEIGHT, + PROP_CHROMA_TYPE, + PROP_PARENT_CONTEXT +}; + +static gboolean +_gst_vaapi_surface_associate_subpicture( + GstVaapiSurface *surface, + GstVaapiSubpicture *subpicture, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect +); + +static gboolean +_gst_vaapi_surface_deassociate_subpicture( + GstVaapiSurface *surface, + GstVaapiSubpicture *subpicture +); + +static void +destroy_subpicture_cb(gpointer subpicture, gpointer surface) +{ + _gst_vaapi_surface_deassociate_subpicture(surface, subpicture); + g_object_unref(subpicture); +} + +static void +gst_vaapi_surface_destroy_subpictures(GstVaapiSurface *surface) +{ + GstVaapiSurfacePrivate * const priv = surface->priv; + + if (priv->subpictures) { + g_ptr_array_foreach(priv->subpictures, destroy_subpicture_cb, surface); + g_ptr_array_free(priv->subpictures, TRUE); + priv->subpictures = NULL; + } +} + +static void +gst_vaapi_surface_destroy(GstVaapiSurface *surface) +{ + GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(surface); + VASurfaceID surface_id; + VAStatus status; + + surface_id = GST_VAAPI_OBJECT_ID(surface); + GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id)); + + gst_vaapi_surface_destroy_subpictures(surface); + gst_vaapi_surface_set_parent_context(surface, NULL); + + if (surface_id != VA_INVALID_SURFACE) { + GST_VAAPI_DISPLAY_LOCK(display); + status = vaDestroySurfaces( + GST_VAAPI_DISPLAY_VADISPLAY(display), + &surface_id, 1 + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaDestroySurfaces()")) + g_warning("failed to destroy surface %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS(surface_id)); + GST_VAAPI_OBJECT_ID(surface) = VA_INVALID_SURFACE; + } +} + +static gboolean +gst_vaapi_surface_create(GstVaapiSurface *surface) +{ + GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(surface); + GstVaapiSurfacePrivate * const priv = surface->priv; + VASurfaceID surface_id; + VAStatus status; + guint format; + + switch (priv->chroma_type) { + case GST_VAAPI_CHROMA_TYPE_YUV420: + format = VA_RT_FORMAT_YUV420; + break; + case GST_VAAPI_CHROMA_TYPE_YUV422: + format = VA_RT_FORMAT_YUV422; + break; + case GST_VAAPI_CHROMA_TYPE_YUV444: + format = VA_RT_FORMAT_YUV444; + break; + default: + GST_DEBUG("unsupported chroma-type %u\n", priv->chroma_type); + return FALSE; + } + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaCreateSurfaces( + GST_VAAPI_DISPLAY_VADISPLAY(display), + priv->width, + priv->height, + format, + 1, &surface_id + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaCreateSurfaces()")) + return FALSE; + + GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id)); + GST_VAAPI_OBJECT_ID(surface) = surface_id; + return TRUE; +} + +static void +gst_vaapi_surface_finalize(GObject *object) +{ + gst_vaapi_surface_destroy(GST_VAAPI_SURFACE(object)); + + G_OBJECT_CLASS(gst_vaapi_surface_parent_class)->finalize(object); +} + +static void +gst_vaapi_surface_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiSurface * const surface = GST_VAAPI_SURFACE(object); + GstVaapiSurfacePrivate * const priv = surface->priv; + + switch (prop_id) { + case PROP_WIDTH: + priv->width = g_value_get_uint(value); + break; + case PROP_HEIGHT: + priv->height = g_value_get_uint(value); + break; + case PROP_CHROMA_TYPE: + priv->chroma_type = g_value_get_uint(value); + break; + case PROP_PARENT_CONTEXT: + gst_vaapi_surface_set_parent_context(surface, g_value_get_object(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_surface_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiSurface * const surface = GST_VAAPI_SURFACE(object); + + switch (prop_id) { + case PROP_WIDTH: + g_value_set_uint(value, gst_vaapi_surface_get_width(surface)); + break; + case PROP_HEIGHT: + g_value_set_uint(value, gst_vaapi_surface_get_height(surface)); + break; + case PROP_CHROMA_TYPE: + g_value_set_uint(value, gst_vaapi_surface_get_chroma_type(surface)); + break; + case PROP_PARENT_CONTEXT: + g_value_set_object(value, gst_vaapi_surface_get_parent_context(surface)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_surface_constructed(GObject *object) +{ + GstVaapiSurface * const surface = GST_VAAPI_SURFACE(object); + GstVaapiSurfaceClass * const klass = GST_VAAPI_SURFACE_GET_CLASS(object); + GObjectClass *parent_class; + + if (klass->create) + klass->create(surface); + + parent_class = G_OBJECT_CLASS(gst_vaapi_surface_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static void +gst_vaapi_surface_class_init(GstVaapiSurfaceClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiSurfacePrivate)); + + object_class->finalize = gst_vaapi_surface_finalize; + object_class->set_property = gst_vaapi_surface_set_property; + object_class->get_property = gst_vaapi_surface_get_property; + object_class->constructed = gst_vaapi_surface_constructed; + + klass->create = gst_vaapi_surface_create; + + g_object_class_install_property + (object_class, + PROP_WIDTH, + g_param_spec_uint("width", + "Width", + "The width of the surface", + 0, G_MAXINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, + PROP_HEIGHT, + g_param_spec_uint("height", + "Height", + "The height of the surface", + 0, G_MAXINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, + PROP_CHROMA_TYPE, + g_param_spec_uint("chroma-type", + "Chroma type", + "The chroma type of the surface", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, + PROP_PARENT_CONTEXT, + g_param_spec_object("parent-context", + "Parent Context", + "The parent context, if any", + GST_VAAPI_TYPE_CONTEXT, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gst_vaapi_surface_init(GstVaapiSurface *surface) +{ + GstVaapiSurfacePrivate *priv = GST_VAAPI_SURFACE_GET_PRIVATE(surface); + + surface->priv = priv; + priv->width = 0; + priv->height = 0; + priv->chroma_type = 0; + priv->subpictures = NULL; + priv->parent_context = NULL; +} + +/** + * gst_vaapi_surface_new: + * @display: a #GstVaapiDisplay + * @chroma_type: the surface chroma format + * @width: the requested surface width + * @height: the requested surface height + * + * Creates a new #GstVaapiSurface with the specified chroma format and + * dimensions. + * + * Return value: the newly allocated #GstVaapiSurface object + */ +GstVaapiSurface * +gst_vaapi_surface_new( + GstVaapiDisplay *display, + GstVaapiChromaType chroma_type, + guint width, + guint height +) +{ + GST_DEBUG("size %ux%u, chroma type 0x%x", width, height, chroma_type); + + return g_object_new(GST_VAAPI_TYPE_SURFACE, + "display", display, + "id", GST_VAAPI_ID(VA_INVALID_ID), + "width", width, + "height", height, + "chroma-type", chroma_type, + NULL); +} + +/** + * gst_vaapi_surface_get_id: + * @surface: a #GstVaapiSurface + * + * Returns the underlying VASurfaceID of the @surface. + * + * Return value: the underlying VA surface id + */ +GstVaapiID +gst_vaapi_surface_get_id(GstVaapiSurface *surface) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), VA_INVALID_SURFACE); + + return GST_VAAPI_OBJECT_ID(surface); +} + +/** + * gst_vaapi_surface_get_chroma_type: + * @surface: a #GstVaapiSurface + * + * Returns the #GstVaapiChromaType the @surface was created with. + * + * Return value: the #GstVaapiChromaType + */ +GstVaapiChromaType +gst_vaapi_surface_get_chroma_type(GstVaapiSurface *surface) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0); + + return surface->priv->chroma_type; +} + +/** + * gst_vaapi_surface_get_width: + * @surface: a #GstVaapiSurface + * + * Returns the @surface width. + * + * Return value: the surface width, in pixels + */ +guint +gst_vaapi_surface_get_width(GstVaapiSurface *surface) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0); + + return surface->priv->width; +} + +/** + * gst_vaapi_surface_get_height: + * @surface: a #GstVaapiSurface + * + * Returns the @surface height. + * + * Return value: the surface height, in pixels. + */ +guint +gst_vaapi_surface_get_height(GstVaapiSurface *surface) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0); + + return surface->priv->height; +} + +/** + * gst_vaapi_surface_get_size: + * @surface: a #GstVaapiSurface + * @pwidth: return location for the width, or %NULL + * @pheight: return location for the height, or %NULL + * + * Retrieves the dimensions of a #GstVaapiSurface. + */ +void +gst_vaapi_surface_get_size( + GstVaapiSurface *surface, + guint *pwidth, + guint *pheight +) +{ + g_return_if_fail(GST_VAAPI_IS_SURFACE(surface)); + + if (pwidth) + *pwidth = gst_vaapi_surface_get_width(surface); + + if (pheight) + *pheight = gst_vaapi_surface_get_height(surface); +} + +/** + * gst_vaapi_surface_set_parent_context: + * @surface: a #GstVaapiSurface + * @context: a #GstVaapiContext + * + * Sets new parent context, or clears any parent context if @context + * is %NULL. This function owns an extra reference to the context, + * which will be released when the surface is destroyed. + */ +void +gst_vaapi_surface_set_parent_context( + GstVaapiSurface *surface, + GstVaapiContext *context +) +{ + GstVaapiSurfacePrivate *priv; + + g_return_if_fail(GST_VAAPI_IS_SURFACE(surface)); + + priv = surface->priv; + + g_clear_object(&priv->parent_context); + + if (context) + priv->parent_context = g_object_ref(context); +} + +/** + * gst_vaapi_surface_get_parent_context: + * @surface: a #GstVaapiSurface + * + * Retrieves the parent #GstVaapiContext, or %NULL if there is + * none. The surface shall still own a reference to the context. + * i.e. the caller shall not unreference the returned context object. + * + * Return value: the parent context, if any. + */ +GstVaapiContext * +gst_vaapi_surface_get_parent_context(GstVaapiSurface *surface) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL); + + return surface->priv->parent_context; +} + +/** + * gst_vaapi_surface_derive_image: + * @surface: a #GstVaapiSurface + * + * Derives a #GstVaapiImage from the @surface. This image buffer can + * then be mapped/unmapped for direct CPU access. This operation is + * only possible if the underlying implementation supports direct + * rendering capabilities and internal surface formats that can be + * represented with a #GstVaapiImage. + * + * When the operation is not possible, the function returns %NULL and + * the user should then fallback to using gst_vaapi_surface_get_image() + * or gst_vaapi_surface_put_image() to accomplish the same task in an + * indirect manner (additional copy). + * + * An image created with gst_vaapi_surface_derive_image() should be + * unreferenced when it's no longer needed. The image and image buffer + * data structures will be destroyed. However, the surface contents + * will remain unchanged until destroyed through the last call to + * g_object_unref(). + * + * Return value: the newly allocated #GstVaapiImage object, or %NULL + * on failure + */ +GstVaapiImage * +gst_vaapi_surface_derive_image(GstVaapiSurface *surface) +{ + GstVaapiDisplay *display; + VAImage va_image; + VAStatus status; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL); + + display = GST_VAAPI_OBJECT_DISPLAY(surface); + va_image.image_id = VA_INVALID_ID; + va_image.buf = VA_INVALID_ID; + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaDeriveImage( + GST_VAAPI_DISPLAY_VADISPLAY(display), + GST_VAAPI_OBJECT_ID(surface), + &va_image + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaDeriveImage()")) + return NULL; + if (va_image.image_id == VA_INVALID_ID || va_image.buf == VA_INVALID_ID) + return NULL; + + return gst_vaapi_image_new_with_image(display, &va_image); +} + +/** + * gst_vaapi_surface_get_image + * @surface: a #GstVaapiSurface + * @image: a #GstVaapiImage + * + * Retrieves surface data into a #GstVaapiImage. The @image must have + * a format supported by the @surface. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_get_image(GstVaapiSurface *surface, GstVaapiImage *image) +{ + GstVaapiDisplay *display; + VAImageID image_id; + VAStatus status; + guint width, height; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE); + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + + display = GST_VAAPI_OBJECT_DISPLAY(surface); + if (!display) + return FALSE; + + gst_vaapi_image_get_size(image, &width, &height); + if (width != surface->priv->width || height != surface->priv->height) + return FALSE; + + image_id = GST_VAAPI_OBJECT_ID(image); + if (image_id == VA_INVALID_ID) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaGetImage( + GST_VAAPI_DISPLAY_VADISPLAY(display), + GST_VAAPI_OBJECT_ID(surface), + 0, 0, width, height, + image_id + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaGetImage()")) + return FALSE; + + return TRUE; +} + +/** + * gst_vaapi_surface_put_image: + * @surface: a #GstVaapiSurface + * @image: a #GstVaapiImage + * + * Copies data from a #GstVaapiImage into a @surface. The @image must + * have a format supported by the @surface. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_put_image(GstVaapiSurface *surface, GstVaapiImage *image) +{ + GstVaapiDisplay *display; + VAImageID image_id; + VAStatus status; + guint width, height; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE); + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); + + display = GST_VAAPI_OBJECT_DISPLAY(surface); + if (!display) + return FALSE; + + gst_vaapi_image_get_size(image, &width, &height); + if (width != surface->priv->width || height != surface->priv->height) + return FALSE; + + image_id = GST_VAAPI_OBJECT_ID(image); + if (image_id == VA_INVALID_ID) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaPutImage( + GST_VAAPI_DISPLAY_VADISPLAY(display), + GST_VAAPI_OBJECT_ID(surface), + image_id, + 0, 0, width, height, + 0, 0, width, height + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaPutImage()")) + return FALSE; + + return TRUE; +} + +/** + * gst_vaapi_surface_associate_subpicture: + * @surface: a #GstVaapiSurface + * @subpicture: a #GstVaapiSubpicture + * @src_rect: the sub-rectangle of the source subpicture + * image to extract and process. If %NULL, the entire image will be used. + * @dst_rect: the sub-rectangle of the destination + * surface into which the image is rendered. If %NULL, the entire + * surface will be used. + * + * Associates the @subpicture with the @surface. The @src_rect + * coordinates and size are relative to the source image bound to + * @subpicture. The @dst_rect coordinates and size are relative to the + * target @surface. Note that the @surface holds an additional + * reference to the @subpicture. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_associate_subpicture( + GstVaapiSurface *surface, + GstVaapiSubpicture *subpicture, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect +) +{ + gboolean success; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE); + g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE); + + if (!surface->priv->subpictures) { + surface->priv->subpictures = g_ptr_array_new(); + if (!surface->priv->subpictures) + return FALSE; + } + + if (g_ptr_array_remove_fast(surface->priv->subpictures, subpicture)) { + success = _gst_vaapi_surface_deassociate_subpicture(surface, subpicture); + g_object_unref(subpicture); + if (!success) + return FALSE; + } + + success = _gst_vaapi_surface_associate_subpicture( + surface, + subpicture, + src_rect, + dst_rect + ); + if (!success) + return FALSE; + + g_ptr_array_add(surface->priv->subpictures, g_object_ref(subpicture)); + return TRUE; +} + +gboolean +_gst_vaapi_surface_associate_subpicture( + GstVaapiSurface *surface, + GstVaapiSubpicture *subpicture, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect +) +{ + GstVaapiDisplay *display; + GstVaapiRectangle src_rect_default, dst_rect_default; + GstVaapiImage *image; + VASurfaceID surface_id; + VAStatus status; + + display = GST_VAAPI_OBJECT_DISPLAY(surface); + if (!display) + return FALSE; + + surface_id = GST_VAAPI_OBJECT_ID(surface); + if (surface_id == VA_INVALID_SURFACE) + return FALSE; + + if (!src_rect) { + image = gst_vaapi_subpicture_get_image(subpicture); + if (!image) + return FALSE; + src_rect = &src_rect_default; + src_rect_default.x = 0; + src_rect_default.y = 0; + gst_vaapi_image_get_size( + image, + &src_rect_default.width, + &src_rect_default.height + ); + } + + if (!dst_rect) { + dst_rect = &dst_rect_default; + dst_rect_default.x = 0; + dst_rect_default.y = 0; + dst_rect_default.width = surface->priv->width; + dst_rect_default.height = surface->priv->height; + } + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaAssociateSubpicture( + GST_VAAPI_DISPLAY_VADISPLAY(display), + GST_VAAPI_OBJECT_ID(subpicture), + &surface_id, 1, + src_rect->x, src_rect->y, src_rect->width, src_rect->height, + dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height, + 0 + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaAssociateSubpicture()")) + return FALSE; + + return TRUE; +} + +/** + * gst_vaapi_surface_deassociate_subpicture: + * @surface: a #GstVaapiSurface + * @subpicture: a #GstVaapiSubpicture + * + * Deassociates @subpicture from @surface. Other associations are kept. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_deassociate_subpicture( + GstVaapiSurface *surface, + GstVaapiSubpicture *subpicture +) +{ + gboolean success; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE); + g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE); + + if (!surface->priv->subpictures) + return TRUE; + + /* First, check subpicture was really associated with this surface */ + if (!g_ptr_array_remove_fast(surface->priv->subpictures, subpicture)) { + GST_DEBUG("subpicture %" GST_VAAPI_ID_FORMAT " was not bound to " + "surface %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(subpicture)), + GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface))); + return TRUE; + } + + success = _gst_vaapi_surface_deassociate_subpicture(surface, subpicture); + g_object_unref(subpicture); + return success; +} + +gboolean +_gst_vaapi_surface_deassociate_subpicture( + GstVaapiSurface *surface, + GstVaapiSubpicture *subpicture +) +{ + GstVaapiDisplay *display; + VASurfaceID surface_id; + VAStatus status; + + display = GST_VAAPI_OBJECT_DISPLAY(surface); + if (!display) + return FALSE; + + surface_id = GST_VAAPI_OBJECT_ID(surface); + if (surface_id == VA_INVALID_SURFACE) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaDeassociateSubpicture( + GST_VAAPI_DISPLAY_VADISPLAY(display), + GST_VAAPI_OBJECT_ID(subpicture), + &surface_id, 1 + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaDeassociateSubpicture()")) + return FALSE; + + return TRUE; +} + +/** + * gst_vaapi_surface_sync: + * @surface: a #GstVaapiSurface + * + * Blocks until all pending operations on the @surface have been + * completed. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_sync(GstVaapiSurface *surface) +{ + GstVaapiDisplay *display; + VAStatus status; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE); + + display = GST_VAAPI_OBJECT_DISPLAY(surface); + if (!display) + return FALSE; + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaSyncSurface( + GST_VAAPI_DISPLAY_VADISPLAY(display), + GST_VAAPI_OBJECT_ID(surface) + ); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaSyncSurface()")) + return FALSE; + + return TRUE; +} + +/** + * gst_vaapi_surface_query_status: + * @surface: a #GstVaapiSurface + * @pstatus: return location for the #GstVaapiSurfaceStatus + * + * Finds out any pending operations on the @surface. The + * #GstVaapiSurfaceStatus flags are returned into @pstatus. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_query_status( + GstVaapiSurface *surface, + GstVaapiSurfaceStatus *pstatus +) +{ + VASurfaceStatus surface_status; + VAStatus status; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE); + + GST_VAAPI_OBJECT_LOCK_DISPLAY(surface); + status = vaQuerySurfaceStatus( + GST_VAAPI_OBJECT_VADISPLAY(surface), + GST_VAAPI_OBJECT_ID(surface), + &surface_status + ); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(surface); + if (!vaapi_check_status(status, "vaQuerySurfaceStatus()")) + return FALSE; + + if (pstatus) + *pstatus = to_GstVaapiSurfaceStatus(surface_status); + return TRUE; +} + +/** + * gst_vaapi_surface_set_subpictures_from_composition: + * @surface: a #GstVaapiSurface + * @compostion: a #GstVideoOverlayCompositon + * @propagate_context: a flag specifying whether to apply composition + * to the parent context, if any + * + * Helper to update the subpictures from #GstVideoOverlayCompositon. Sending + * a NULL composition will clear all the current subpictures. Note that this + * method will clear existing subpictures. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_surface_set_subpictures_from_composition( + GstVaapiSurface *surface, + GstVideoOverlayComposition *composition, + gboolean propagate_context +) +{ + GstVaapiDisplay *display; + guint n, nb_rectangles; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE); + + if (propagate_context) { + GstVaapiContext * const context = surface->priv->parent_context; + if (context) + return gst_vaapi_context_apply_composition(context, composition); + } + + display = GST_VAAPI_OBJECT_DISPLAY(surface); + if (!display) + return FALSE; + + /* Clear current subpictures */ + gst_vaapi_surface_destroy_subpictures(surface); + + if (!composition) + return TRUE; + + nb_rectangles = gst_video_overlay_composition_n_rectangles (composition); + + /* Overlay all the rectangles cantained in the overlay composition */ + for (n = 0; n < nb_rectangles; ++n) { + GstVideoOverlayRectangle *rect; + GstVaapiRectangle sub_rect; + GstVaapiSubpicture *subpicture; + + rect = gst_video_overlay_composition_get_rectangle (composition, n); + subpicture = gst_vaapi_subpicture_new_from_overlay_rectangle (display, + rect); + + gst_video_overlay_rectangle_get_render_rectangle (rect, + (gint *)&sub_rect.x, (gint *)&sub_rect.y, + &sub_rect.width, &sub_rect.height); + + if (!gst_vaapi_surface_associate_subpicture (surface, subpicture, + NULL, &sub_rect)) { + GST_WARNING ("could not render overlay rectangle %p", rect); + g_object_unref (subpicture); + return FALSE; + } + g_object_unref (subpicture); + } + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapisurface.h b/gst-libs/gst/vaapi/gstvaapisurface.h new file mode 100644 index 0000000..f6c269d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface.h @@ -0,0 +1,252 @@ +/* + * gstvaapisurface.h - VA surface abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_H +#define GST_VAAPI_SURFACE_H + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +typedef enum _GstVaapiChromaType GstVaapiChromaType; +typedef enum _GstVaapiSurfaceStatus GstVaapiSurfaceStatus; +typedef enum _GstVaapiSurfaceRenderFlags GstVaapiSurfaceRenderFlags; + +/** + * GST_VAAPI_SURFACE_CAPS_NAME: + * + * Generic caps type for VA surfaces. + */ +#define GST_VAAPI_SURFACE_CAPS_NAME GST_VIDEO_CAPS_SURFACE + +/** + * GST_VAAPI_SURFACE_CAPS: + * + * Generic caps for VA surfaces. + */ +#define GST_VAAPI_SURFACE_CAPS \ + GST_VAAPI_SURFACE_CAPS_NAME ", " \ + "type = vaapi, " \ + "opengl = (boolean) { true, false }, " \ + "width = (int) [ 1, MAX ], " \ + "height = (int) [ 1, MAX ], " \ + "framerate = (fraction) [ 0, MAX ]" + +#define GST_VAAPI_BUFFER_SHARING_CAPS_NAME "video/x-vaapi-sharing" + +#define GST_VAAPI_BUFFER_SHARING_CAPS \ + GST_VAAPI_BUFFER_SHARING_CAPS_NAME ", " \ + "type = vaapi, " \ + "width = (int) [ 1, MAX ], " \ + "height = (int) [ 1, MAX ], " \ + "framerate = (fraction) [ 0, MAX ]" + +/** + * GstVaapiChromaType: + * @GST_VAAPI_CHROMA_TYPE_YUV420: 4:2:0 chroma format + * @GST_VAAPI_CHROMA_TYPE_YUV422: 4:2:2 chroma format + * @GST_VAAPI_CHROMA_TYPE_YUV444: 4:4:4 chroma format + * + * The set of all chroma types for #GstVaapiSurface. + */ +enum _GstVaapiChromaType { + GST_VAAPI_CHROMA_TYPE_YUV420 = 1, + GST_VAAPI_CHROMA_TYPE_YUV422, + GST_VAAPI_CHROMA_TYPE_YUV444 +}; + +/** + * GstVaapiSurfaceStatus: + * @GST_VAAPI_SURFACE_STATUS_IDLE: + * the surface is not being rendered or displayed + * @GST_VAAPI_SURFACE_STATUS_RENDERING: + * the surface is used for rendering (decoding to the surface in progress) + * @GST_VAAPI_SURFACE_STATUS_DISPLAYING: + * the surface is being displayed to screen + * @GST_VAAPI_SURFACE_STATUS_SKIPPED: + * indicates a skipped frame during encode + * + * The set of all surface status for #GstVaapiSurface. + */ +enum _GstVaapiSurfaceStatus { + GST_VAAPI_SURFACE_STATUS_IDLE = 1 << 0, + GST_VAAPI_SURFACE_STATUS_RENDERING = 1 << 1, + GST_VAAPI_SURFACE_STATUS_DISPLAYING = 1 << 2, + GST_VAAPI_SURFACE_STATUS_SKIPPED = 1 << 3 +}; + +/** + * GstVaapiSurfaceRenderFlags + * @GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD: + * selects the top field of the surface + * @GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD: + * selects the bottom field of the surface + * @GST_VAAPI_PICTURE_STRUCTURE_FRAME: + * selects the entire surface + * @GST_VAAPI_COLOR_STANDARD_ITUR_BT_601: + * uses ITU-R BT.601 standard for color space conversion + * @GST_VAAPI_COLOR_STANDARD_ITUR_BT_709: + * uses ITU-R BT.709 standard for color space conversion + * + * The set of all render flags for gst_vaapi_window_put_surface(). + */ +enum _GstVaapiSurfaceRenderFlags { + GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD = 1 << 0, + GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD = 1 << 1, + GST_VAAPI_PICTURE_STRUCTURE_FRAME = + ( + GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD | + GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD + ), + GST_VAAPI_COLOR_STANDARD_ITUR_BT_601 = 1 << 2, + GST_VAAPI_COLOR_STANDARD_ITUR_BT_709 = 1 << 3, +}; + +#define GST_VAAPI_TYPE_SURFACE \ + (gst_vaapi_surface_get_type()) + +#define GST_VAAPI_SURFACE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_SURFACE, \ + GstVaapiSurface)) + +#define GST_VAAPI_SURFACE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_SURFACE, \ + GstVaapiSurfaceClass)) + +#define GST_VAAPI_IS_SURFACE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_SURFACE)) + +#define GST_VAAPI_IS_SURFACE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_SURFACE)) + +#define GST_VAAPI_SURFACE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_SURFACE, \ + GstVaapiSurfaceClass)) + +typedef struct _GstVaapiSurface GstVaapiSurface; +typedef struct _GstVaapiSurfacePrivate GstVaapiSurfacePrivate; +typedef struct _GstVaapiSurfaceClass GstVaapiSurfaceClass; + +/** + * GstVaapiSurface: + * + * A VA surface wrapper. + */ +struct _GstVaapiSurface { + /*< private >*/ + GstVaapiObject parent_instance; + + GstVaapiSurfacePrivate *priv; +}; + +/** + * GstVaapiSurfaceClass: + * + * A VA surface wrapper class. + */ +struct _GstVaapiSurfaceClass { + /*< private >*/ + GstVaapiObjectClass parent_class; + + gboolean (*create)(GstVaapiSurface *surface); +}; + +GType +gst_vaapi_surface_get_type(void) G_GNUC_CONST; + +GstVaapiSurface * +gst_vaapi_surface_new( + GstVaapiDisplay *display, + GstVaapiChromaType chroma_type, + guint width, + guint height +); + +GstVaapiID +gst_vaapi_surface_get_id(GstVaapiSurface *surface); + +GstVaapiChromaType +gst_vaapi_surface_get_chroma_type(GstVaapiSurface *surface); + +guint +gst_vaapi_surface_get_width(GstVaapiSurface *surface); + +guint +gst_vaapi_surface_get_height(GstVaapiSurface *surface); + +void +gst_vaapi_surface_get_size( + GstVaapiSurface *surface, + guint *pwidth, + guint *pheight +); + +GstVaapiImage * +gst_vaapi_surface_derive_image(GstVaapiSurface *surface); + +gboolean +gst_vaapi_surface_get_image(GstVaapiSurface *surface, GstVaapiImage *image); + +gboolean +gst_vaapi_surface_put_image(GstVaapiSurface *surface, GstVaapiImage *image); + +gboolean +gst_vaapi_surface_associate_subpicture( + GstVaapiSurface *surface, + GstVaapiSubpicture *subpicture, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect +); + +gboolean +gst_vaapi_surface_deassociate_subpicture( + GstVaapiSurface *surface, + GstVaapiSubpicture *subpicture +); + +gboolean +gst_vaapi_surface_sync(GstVaapiSurface *surface); + +gboolean +gst_vaapi_surface_query_status( + GstVaapiSurface *surface, + GstVaapiSurfaceStatus *pstatus +); + +gboolean +gst_vaapi_surface_set_subpictures_from_composition( + GstVaapiSurface *surface, + GstVideoOverlayComposition *composition, + gboolean propagate_context +); + +G_END_DECLS + +#endif /* GST_VAAPI_SURFACE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurface_priv.h b/gst-libs/gst/vaapi/gstvaapisurface_priv.h new file mode 100644 index 0000000..0817b29 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface_priv.h @@ -0,0 +1,39 @@ +/* + * gstvaapisurface_priv.h - VA surface abstraction (private data) + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_PRIV_H +#define GST_VAAPI_SURFACE_PRIV_H + +#include +#include + +G_GNUC_INTERNAL +void +gst_vaapi_surface_set_parent_context( + GstVaapiSurface *surface, + GstVaapiContext *context +); + +G_GNUC_INTERNAL +GstVaapiContext * +gst_vaapi_surface_get_parent_context(GstVaapiSurface *surface); + +#endif /* GST_VAAPI_SURFACE_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurface_userptr.c b/gst-libs/gst/vaapi/gstvaapisurface_userptr.c new file mode 100644 index 0000000..787a80d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface_userptr.c @@ -0,0 +1,303 @@ +/* + * gstvaapisurface_userptr.c - VA surface abstraction for userptr + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapisurface_userptr + * @short_description: VA surface abstraction for userptr + */ +#include "sysdeps.h" +#include "gstvaapisurface_userptr.h" +#include "gstvaapiutils.h" +#include "gstvaapiobject_priv.h" +#include "gstvaapidisplay_priv.h" + +#include +#include + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiSurfaceUserPtr, gst_vaapi_surface_userptr, GST_VAAPI_TYPE_SURFACE); + +#define GST_VAAPI_SURFACE_USERPTR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_SURFACE_USERPTR, \ + GstVaapiSurfaceUserPtrPrivate)) + +struct _GstVaapiSurfaceUserPtrPrivate { + GstVaapiImageFormat format; +}; + +enum { + PROP_0, + + PROP_FORMAT +}; + +typedef struct _GstVaapiSurfaceUserPtrInfo { + guint fourcc; + guint datasize; + guint y_stride; + guint u_stride; + guint v_stride; + guint y_offset; + guint u_offset; + guint v_offset; +} GstVaapiSurfaceUserPtrInfo; + +static gboolean +_get_surface_userptr_info( + GstVaapiImageFormat format, + guint width, + guint height, + GstVaapiSurfaceUserPtrInfo *info +) +{ + const VAImageFormat *va_format; + guint stride1, stride2; + guint height2; + + g_return_val_if_fail(info, FALSE); + + va_format = gst_vaapi_image_format_get_va_format(format); + if (!va_format) + return FALSE; + info->fourcc = va_format->fourcc; + + stride1 = GST_ROUND_UP_4(width); + stride2 = GST_ROUND_UP_4((width + 1) / 2); + height2 = (height + 1) / 2; + + info->datasize = (stride1 * height) + (stride2 * height2)*2; + info->y_stride = stride1; + info->y_offset = 0; + + switch (format) { + case GST_VAAPI_IMAGE_NV12: + info->u_stride = stride1; + info->v_stride = stride1; + info->u_offset = stride1 * height; + info->v_offset = stride1 * height; + break; + + case GST_VAAPI_IMAGE_YV12: + info->u_stride = stride2; + info->v_stride = stride2; + info->u_offset = stride1 * height + stride2 * height2; + info->v_offset = stride1 * height; + break; + + case GST_VAAPI_IMAGE_I420: + info->u_stride = stride2; + info->v_stride = stride2; + info->u_offset = stride1 * height; + info->v_offset = stride1 * height + stride2 * height2; + break; + + default: + return FALSE; + } + return TRUE; +} + +static gboolean +gst_vaapi_surface_userptr_create(GstVaapiSurface *base) +{ + GstVaapiSurfaceUserPtr * const surface = GST_VAAPI_SURFACE_USERPTR(base); + GstVaapiSurfaceUserPtrPrivate * const priv = surface->priv; + GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(surface); + GstVaapiSurfaceUserPtrInfo info; + VASurfaceID surface_id; + VAStatus status; + guint surface_format; + GstVaapiChromaType chroma_type; + guint width, height; + + chroma_type = gst_vaapi_surface_get_chroma_type(base); + gst_vaapi_surface_get_size(base, &width, &height); + + if (!_get_surface_userptr_info(priv->format, width, height, &info)) { + GST_ERROR("surface userptr format error."); + return FALSE; + } + + switch (chroma_type) { + case GST_VAAPI_CHROMA_TYPE_YUV420: + surface_format = VA_RT_FORMAT_YUV420; + break; + case GST_VAAPI_CHROMA_TYPE_YUV422: + surface_format = VA_RT_FORMAT_YUV422; + break; + case GST_VAAPI_CHROMA_TYPE_YUV444: + surface_format = VA_RT_FORMAT_YUV444; + break; + default: + GST_DEBUG("unsupported chroma-type %u\n", chroma_type); + return FALSE; + } + + GST_VAAPI_DISPLAY_LOCK(display); + status = vaCreateSurfacesForUserPtr( + GST_VAAPI_DISPLAY_VADISPLAY(display), + width, + height, + surface_format, + 1, &surface_id, + info.datasize, + info.fourcc, + info.y_stride, + info.u_stride, + info.v_stride, + info.y_offset, + info.u_offset, + info.v_offset); + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!vaapi_check_status(status, "vaCreateSurfaces()")) + return FALSE; + + GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id)); + GST_VAAPI_OBJECT_ID(surface) = surface_id; + return TRUE; +} + +static void +gst_vaapi_surface_userptr_finalize(GObject *object) +{ + + G_OBJECT_CLASS(gst_vaapi_surface_userptr_parent_class)->finalize(object); +} + +static void +gst_vaapi_surface_userptr_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiSurfaceUserPtr * const surface = GST_VAAPI_SURFACE_USERPTR(object); + GstVaapiSurfaceUserPtrPrivate * const priv = surface->priv; + + switch (prop_id) { + case PROP_FORMAT: + priv->format = g_value_get_uint(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_surface_userptr_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiSurfaceUserPtr * const surface = GST_VAAPI_SURFACE_USERPTR(object); + + switch (prop_id) { + case PROP_FORMAT: + g_value_set_uint(value, gst_vaapi_surface_userptr_get_format(surface)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_surface_userptr_class_init(GstVaapiSurfaceUserPtrClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiSurfaceClass * const surface_class = GST_VAAPI_SURFACE_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiSurfaceUserPtrPrivate)); + + object_class->finalize = gst_vaapi_surface_userptr_finalize; + object_class->set_property = gst_vaapi_surface_userptr_set_property; + object_class->get_property = gst_vaapi_surface_userptr_get_property; + + surface_class->create = gst_vaapi_surface_userptr_create; + + g_object_class_install_property + (object_class, + PROP_FORMAT, + g_param_spec_uint("format", + "format", + "The buffer format of surface userptr", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gst_vaapi_surface_userptr_init(GstVaapiSurfaceUserPtr *surface) +{ + GstVaapiSurfaceUserPtrPrivate *priv = GST_VAAPI_SURFACE_USERPTR_GET_PRIVATE(surface); + + surface->priv = priv; + priv->format = 0; +} + +/** + * gst_vaapi_surface_new: + * @display: a #GstVaapiDisplay + * @chroma_type: the surface chroma format + * @format: the fourcc format of the buffer + * @width: the requested surface width + * @height: the requested surface height + * + * Creates a new #GstVaapiSurface with the specified chroma format and + * dimensions. + * + * Return value: the newly allocated #GstVaapiSurface object + */ +GstVaapiSurfaceUserPtr * +gst_vaapi_surface_userptr_new( + GstVaapiDisplay *display, + GstVaapiChromaType chroma_type, + GstVaapiImageFormat format, + guint width, + guint height +) +{ + GST_DEBUG("size %ux%u, chroma type 0x%x", width, height, chroma_type); + + return g_object_new(GST_VAAPI_TYPE_SURFACE_USERPTR, + "display", display, + "id", GST_VAAPI_ID(VA_INVALID_ID), + "width", width, + "height", height, + "chroma-type", chroma_type, + "format", format, + NULL); +} + + +GstVaapiImageFormat +gst_vaapi_surface_userptr_get_format(GstVaapiSurfaceUserPtr *surface) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE_USERPTR(surface), 0); + + return surface->priv->format; +} diff --git a/gst-libs/gst/vaapi/gstvaapisurface_userptr.h b/gst-libs/gst/vaapi/gstvaapisurface_userptr.h new file mode 100644 index 0000000..564ea5f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurface_userptr.h @@ -0,0 +1,98 @@ +/* + * gstvaapisurface_userptr.h - VA surface abstraction for userptr + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_USERPTR_H +#define GST_VAAPI_SURFACE_USERPTR_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_SURFACE_USERPTR \ + (gst_vaapi_surface_userptr_get_type()) + +#define GST_VAAPI_SURFACE_USERPTR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_SURFACE_USERPTR, \ + GstVaapiSurfaceUserPtr)) + +#define GST_VAAPI_SURFACE_USERPTR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_SURFACE_USERPTR, \ + GstVaapiSurfaceUserPtrClass)) + +#define GST_VAAPI_IS_SURFACE_USERPTR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_SURFACE_USERPTR)) + +#define GST_VAAPI_IS_SURFACE_USERPTR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_SURFACE_USERPTR)) + +#define GST_VAAPI_SURFACE_USERPTR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_SURFACE_USERPTR, \ + GstVaapiSurfaceUserPtrClass)) + +typedef struct _GstVaapiSurfaceUserPtr GstVaapiSurfaceUserPtr; +typedef struct _GstVaapiSurfaceUserPtrPrivate GstVaapiSurfaceUserPtrPrivate; +typedef struct _GstVaapiSurfaceUserPtrClass GstVaapiSurfaceUserPtrClass; + +/** + * GstVaapiSurfaceUserPtr: + * + * A VA surface userptr wrapper. + */ +struct _GstVaapiSurfaceUserPtr { + /*< private >*/ + GstVaapiSurface parent_instance; + + GstVaapiSurfaceUserPtrPrivate *priv; +}; + +/** + * GstVaapiSurfaceUserPtrClass: + * + * A VA surface userptr wrapper class. + */ +struct _GstVaapiSurfaceUserPtrClass { + /*< private >*/ + GstVaapiSurfaceClass parent_class; +}; + +GType +gst_vaapi_surface_userptr_get_type(void) G_GNUC_CONST; + +GstVaapiSurfaceUserPtr * +gst_vaapi_surface_userptr_new( + GstVaapiDisplay *display, + GstVaapiChromaType chroma_type, + GstVaapiImageFormat format, + guint width, + guint height +); + +GstVaapiImageFormat +gst_vaapi_surface_userptr_get_format(GstVaapiSurfaceUserPtr *surface); + +G_END_DECLS + +#endif /* GST_VAAPI_SURFACE_USERPTR_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurfacepool.c b/gst-libs/gst/vaapi/gstvaapisurfacepool.c new file mode 100644 index 0000000..5bd9196 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurfacepool.c @@ -0,0 +1,142 @@ +/* + * gstvaapisurfacepool.c - Gst VA surface pool + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapisurfacepool + * @short_description: VA surface pool + */ + +#include "sysdeps.h" +#include "gstvaapisurfacepool.h" +#include "gstvaapisurface_userptr.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE( + GstVaapiSurfacePool, + gst_vaapi_surface_pool, + GST_VAAPI_TYPE_VIDEO_POOL); + +#define GST_VAAPI_SURFACE_POOL_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_SURFACE_POOL, \ + GstVaapiSurfacePoolPrivate)) + +struct _GstVaapiSurfacePoolPrivate { + GstVaapiChromaType chroma_type; + guint width; + guint height; + gboolean is_shared_buffer; +}; + +static void +gst_vaapi_surface_pool_set_caps(GstVaapiVideoPool *pool, GstCaps *caps) +{ + GstVaapiSurfacePoolPrivate *priv = GST_VAAPI_SURFACE_POOL(pool)->priv; + GstStructure *structure; + gint width, height; + + structure = gst_caps_get_structure(caps, 0); + gst_structure_get_int(structure, "width", &width); + gst_structure_get_int(structure, "height", &height); + + if (gst_structure_has_name(structure, GST_VAAPI_BUFFER_SHARING_CAPS_NAME)) + priv->is_shared_buffer = TRUE; + else + priv->is_shared_buffer = FALSE; + + priv->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + priv->width = width; + priv->height = height; +} + +gpointer +gst_vaapi_surface_pool_alloc_object( + GstVaapiVideoPool *pool, + GstVaapiDisplay *display +) +{ + GstVaapiSurfacePoolPrivate *priv = GST_VAAPI_SURFACE_POOL(pool)->priv; + + if (priv->is_shared_buffer) + return gst_vaapi_surface_userptr_new(display, + priv->chroma_type, + GST_VAAPI_IMAGE_NV12, + priv->width, + priv->height); + else + return gst_vaapi_surface_new(display, + priv->chroma_type, + priv->width, + priv->height); +} + +static void +gst_vaapi_surface_pool_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_surface_pool_parent_class)->finalize(object); +} + +static void +gst_vaapi_surface_pool_class_init(GstVaapiSurfacePoolClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiVideoPoolClass * const pool_class = GST_VAAPI_VIDEO_POOL_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiSurfacePoolPrivate)); + + object_class->finalize = gst_vaapi_surface_pool_finalize; + + pool_class->set_caps = gst_vaapi_surface_pool_set_caps; + pool_class->alloc_object = gst_vaapi_surface_pool_alloc_object; +} + +static void +gst_vaapi_surface_pool_init(GstVaapiSurfacePool *pool) +{ + GstVaapiSurfacePoolPrivate *priv = GST_VAAPI_SURFACE_POOL_GET_PRIVATE(pool); + + pool->priv = priv; + priv->chroma_type = 0; + priv->width = 0; + priv->height = 0; + priv->is_shared_buffer = FALSE; +} + +/** + * gst_vaapi_surface_pool_new: + * @display: a #GstVaapiDisplay + * @caps: a #GstCaps + * + * Creates a new #GstVaapiVideoPool of #GstVaapiSurface with the + * specified dimensions in @caps. + * + * Return value: the newly allocated #GstVaapiVideoPool + */ +GstVaapiVideoPool * +gst_vaapi_surface_pool_new(GstVaapiDisplay *display, GstCaps *caps) +{ + return g_object_new(GST_VAAPI_TYPE_SURFACE_POOL, + "display", display, + "caps", caps, + NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapisurfacepool.h b/gst-libs/gst/vaapi/gstvaapisurfacepool.h new file mode 100644 index 0000000..2bb661c --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurfacepool.h @@ -0,0 +1,88 @@ +/* + * gstvaapisurfacepool.h - Gst VA surface pool + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_POOL_H +#define GST_VAAPI_SURFACE_POOL_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_SURFACE_POOL \ + (gst_vaapi_surface_pool_get_type()) + +#define GST_VAAPI_SURFACE_POOL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_SURFACE_POOL, \ + GstVaapiSurfacePool)) + +#define GST_VAAPI_SURFACE_POOL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_SURFACE_POOL, \ + GstVaapiSurfacePoolClass)) + +#define GST_VAAPI_IS_SURFACE_POOL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_SURFACE_POOL)) + +#define GST_VAAPI_IS_SURFACE_POOL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_SURFACE_POOL)) + +#define GST_VAAPI_SURFACE_POOL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_SURFACE_POOL, \ + GstVaapiSurfacePoolClass)) + +typedef struct _GstVaapiSurfacePool GstVaapiSurfacePool; +typedef struct _GstVaapiSurfacePoolPrivate GstVaapiSurfacePoolPrivate; +typedef struct _GstVaapiSurfacePoolClass GstVaapiSurfacePoolClass; + +/** + * GstVaapiSurfacePool: + * + * A pool of lazily allocated #GstVaapiSurface objects. + */ +struct _GstVaapiSurfacePool { + /*< private >*/ + GstVaapiVideoPool parent_instance; + + GstVaapiSurfacePoolPrivate *priv; +}; + +/** + * GstVaapiSurfacePoolClass: + * + * A pool of lazily allocated #GstVaapiSurface objects. + */ +struct _GstVaapiSurfacePoolClass { + /*< private >*/ + GstVaapiVideoPoolClass parent_class; +}; + +GType +gst_vaapi_surface_pool_get_type(void) G_GNUC_CONST; + +GstVaapiVideoPool * +gst_vaapi_surface_pool_new(GstVaapiDisplay *display, GstCaps *caps); + +G_END_DECLS + +#endif /* GST_VAAPI_SURFACE_POOL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurfaceproxy.c b/gst-libs/gst/vaapi/gstvaapisurfaceproxy.c new file mode 100644 index 0000000..aa4103e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurfaceproxy.c @@ -0,0 +1,431 @@ +/* + * gstvaapisurfaceproxy.c - VA surface proxy + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapisurfaceproxy + * @short_description: VA surface proxy + */ + +#include "sysdeps.h" +#include "gstvaapisurfaceproxy.h" +#include "gstvaapiobject_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiSurfaceProxy, gst_vaapi_surface_proxy, G_TYPE_OBJECT); + +#define GST_VAAPI_SURFACE_PROXY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_SURFACE_PROXY, \ + GstVaapiSurfaceProxyPrivate)) + +struct _GstVaapiSurfaceProxyPrivate { + GstVaapiContext *context; + GstVaapiSurface *surface; + GstClockTime timestamp; + guint is_interlaced : 1; + guint tff : 1; +}; + +enum { + PROP_0, + + PROP_CONTEXT, + PROP_SURFACE, + PROP_TIMESTAMP, + PROP_INTERLACED, + PROP_TFF +}; + +static void +gst_vaapi_surface_proxy_finalize(GObject *object) +{ + GstVaapiSurfaceProxy * const proxy = GST_VAAPI_SURFACE_PROXY(object); + + gst_vaapi_surface_proxy_set_surface(proxy, NULL); + gst_vaapi_surface_proxy_set_context(proxy, NULL); + + G_OBJECT_CLASS(gst_vaapi_surface_proxy_parent_class)->finalize(object); +} + +static void +gst_vaapi_surface_proxy_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiSurfaceProxy * const proxy = GST_VAAPI_SURFACE_PROXY(object); + + switch (prop_id) { + case PROP_CONTEXT: + gst_vaapi_surface_proxy_set_context(proxy, g_value_get_pointer(value)); + break; + case PROP_SURFACE: + gst_vaapi_surface_proxy_set_surface(proxy, g_value_get_pointer(value)); + break; + case PROP_TIMESTAMP: + gst_vaapi_surface_proxy_set_timestamp(proxy, g_value_get_uint64(value)); + break; + case PROP_INTERLACED: + gst_vaapi_surface_proxy_set_interlaced(proxy, g_value_get_boolean(value)); + break; + case PROP_TFF: + gst_vaapi_surface_proxy_set_tff(proxy, g_value_get_boolean(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_surface_proxy_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiSurfaceProxy * const proxy = GST_VAAPI_SURFACE_PROXY(object); + + switch (prop_id) { + case PROP_CONTEXT: + g_value_set_pointer(value, gst_vaapi_surface_proxy_get_context(proxy)); + break; + case PROP_SURFACE: + g_value_set_pointer(value, gst_vaapi_surface_proxy_get_surface(proxy)); + break; + case PROP_TIMESTAMP: + g_value_set_uint64(value, gst_vaapi_surface_proxy_get_timestamp(proxy)); + break; + case PROP_INTERLACED: + g_value_set_boolean(value, gst_vaapi_surface_proxy_get_interlaced(proxy)); + break; + case PROP_TFF: + g_value_set_boolean(value, gst_vaapi_surface_proxy_get_tff(proxy)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_surface_proxy_class_init(GstVaapiSurfaceProxyClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiSurfaceProxyPrivate)); + + object_class->finalize = gst_vaapi_surface_proxy_finalize; + object_class->set_property = gst_vaapi_surface_proxy_set_property; + object_class->get_property = gst_vaapi_surface_proxy_get_property; + + g_object_class_install_property + (object_class, + PROP_CONTEXT, + g_param_spec_pointer("context", + "Context", + "The context stored in the proxy", + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, + PROP_SURFACE, + g_param_spec_pointer("surface", + "Surface", + "The surface stored in the proxy", + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, + PROP_TIMESTAMP, + g_param_spec_uint64("timestamp", + "Timestamp", + "The presentation time of the surface", + 0, G_MAXUINT64, GST_CLOCK_TIME_NONE, + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, + PROP_INTERLACED, + g_param_spec_boolean("interlaced", + "Interlaced", + "Flag indicating whether surface is interlaced", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, + PROP_TFF, + g_param_spec_boolean("tff", + "Top-Field-First", + "Flag indicating for interlaced surfaces whether Top Field is First", + FALSE, + G_PARAM_READWRITE)); +} + +static void +gst_vaapi_surface_proxy_init(GstVaapiSurfaceProxy *proxy) +{ + GstVaapiSurfaceProxyPrivate *priv; + + priv = GST_VAAPI_SURFACE_PROXY_GET_PRIVATE(proxy); + proxy->priv = priv; + priv->context = NULL; + priv->surface = NULL; + priv->timestamp = GST_CLOCK_TIME_NONE; + priv->is_interlaced = FALSE; + priv->tff = FALSE; +} + +/** + * gst_vaapi_surface_proxy_new: + * @context: a #GstVaapiContext + * @surface: a #GstVaapiSurface + * + * Creates a new #GstVaapiSurfaceProxy with the specified context and + * surface. + * + * Return value: the newly allocated #GstVaapiSurfaceProxy object + */ +GstVaapiSurfaceProxy * +gst_vaapi_surface_proxy_new(GstVaapiContext *context, GstVaapiSurface *surface) +{ + g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), NULL); + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL); + + return g_object_new(GST_VAAPI_TYPE_SURFACE_PROXY, + "context", context, + "surface", surface, + NULL); +} + +/** + * gst_vaapi_surface_proxy_get_context: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the #GstVaapiContext stored in the @proxy. + * + * Return value: the #GstVaapiContext + */ +GstVaapiContext * +gst_vaapi_surface_proxy_get_context(GstVaapiSurfaceProxy *proxy) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), NULL); + + return proxy->priv->context; +} + +/** + * gst_vaapi_surface_proxy_set_context: + * @proxy: a #GstVaapiSurfaceProxy + * @context: the new #GstVaapiContext to be stored in @proxy + * + * Stores a new @context into the @proxy. The proxy releases the + * previous reference, if any, and then holds a reference to the new + * @context. + */ +void +gst_vaapi_surface_proxy_set_context( + GstVaapiSurfaceProxy *proxy, + GstVaapiContext *context +) +{ + GstVaapiSurfaceProxyPrivate *priv; + + g_return_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy)); + + priv = proxy->priv; + + g_clear_object(&priv->context); + + if (context) + priv->context = g_object_ref(context); +} + +/** + * gst_vaapi_surface_proxy_get_surface: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the #GstVaapiSurface stored in the @proxy. + * + * Return value: the #GstVaapiSurface + */ +GstVaapiSurface * +gst_vaapi_surface_proxy_get_surface(GstVaapiSurfaceProxy *proxy) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), NULL); + + return proxy->priv->surface; +} + +/** + * gst_vaapi_surface_proxy_get_surface_id: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the VA surface ID stored in the @proxy. + * + * Return value: the #GstVaapiID + */ +GstVaapiID +gst_vaapi_surface_proxy_get_surface_id(GstVaapiSurfaceProxy *proxy) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), GST_VAAPI_ID_NONE); + g_return_val_if_fail(proxy->priv->surface != NULL, GST_VAAPI_ID_NONE); + + return GST_VAAPI_OBJECT_ID(proxy->priv->surface); +} + +/** + * gst_vaapi_surface_proxy_set_surface: + * @proxy: a #GstVaapiSurfaceProxy + * @surface: the new #GstVaapiSurface to be stored in @proxy + * + * Stores a new @surface into the @proxy. The proxy releases the + * previous reference, if any, and then holds a reference to the new + * @surface. + */ +void +gst_vaapi_surface_proxy_set_surface( + GstVaapiSurfaceProxy *proxy, + GstVaapiSurface *surface +) +{ + GstVaapiSurfaceProxyPrivate *priv; + + g_return_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy)); + + priv = proxy->priv; + + if (priv->surface) { + if (priv->context) + gst_vaapi_context_put_surface(priv->context, priv->surface); + g_object_unref(priv->surface); + priv->surface = NULL; + } + + if (surface) + priv->surface = g_object_ref(surface); +} + +/** + * gst_vaapi_surface_proxy_get_timestamp: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the presentation timestamp of the #GstVaapiSurface held by @proxy. + * + * Return value: the presentation timestamp of the surface, or + * %GST_CLOCK_TIME_NONE is none was set + */ +GstClockTime +gst_vaapi_surface_proxy_get_timestamp(GstVaapiSurfaceProxy *proxy) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), GST_CLOCK_TIME_NONE); + + return proxy->priv->timestamp; +} + +/** + * gst_vaapi_surface_proxy_set_timestamp: + * @proxy: a #GstVaapiSurfaceProxy + * @timestamp: the new presentation timestamp as a #GstClockTime + * + * Sets the presentation timestamp of the @proxy surface to @timestamp. + */ +void +gst_vaapi_surface_proxy_set_timestamp( + GstVaapiSurfaceProxy *proxy, + GstClockTime timestamp +) +{ + g_return_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy)); + + proxy->priv->timestamp = timestamp; +} + +/** + * gst_vaapi_surface_proxy_get_interlaced: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns whether the @proxy holds an interlaced #GstVaapiSurface or not. + * + * Return value: %TRUE if the underlying surface is interlaced, %FALSE + * otherwise. + */ +gboolean +gst_vaapi_surface_proxy_get_interlaced(GstVaapiSurfaceProxy *proxy) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), FALSE); + + return proxy->priv->is_interlaced; +} + +/** + * gst_vaapi_surface_proxy_set_interlaced: + * @proxy: a #GstVaapiSurfaceProxy + * @b: a boolean value + * + * Sets whether the underlying #GstVaapiSurface for @proxy is interlaced + * or not. + */ +void +gst_vaapi_surface_proxy_set_interlaced(GstVaapiSurfaceProxy *proxy, gboolean b) +{ + g_return_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy)); + + proxy->priv->is_interlaced = b; +} + +/** + * gst_vaapi_surface_proxy_get_tff: + * @proxy: a #GstVaapiSurfaceProxy + * + * Returns the TFF flag of the #GstVaapiSurface held by @proxy. + * + * Return value: the TFF flag of the surface + */ +gboolean +gst_vaapi_surface_proxy_get_tff(GstVaapiSurfaceProxy *proxy) +{ + g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), FALSE); + + return proxy->priv->is_interlaced && proxy->priv->tff; +} + +/** + * gst_vaapi_surface_proxy_set_tff: + * @proxy: a #GstVaapiSurfaceProxy + * @tff: the new value of the TFF flag + * + * Sets the TFF flag of the @proxy surface to @tff. + */ +void +gst_vaapi_surface_proxy_set_tff(GstVaapiSurfaceProxy *proxy, gboolean tff) +{ + g_return_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy)); + + proxy->priv->tff = tff; +} diff --git a/gst-libs/gst/vaapi/gstvaapisurfaceproxy.h b/gst-libs/gst/vaapi/gstvaapisurfaceproxy.h new file mode 100644 index 0000000..35e38f7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapisurfaceproxy.h @@ -0,0 +1,169 @@ +/* + * gstvaapisurfaceproxy.h - VA surface proxy + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_SURFACE_PROXY_H +#define GST_VAAPI_SURFACE_PROXY_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_SURFACE_PROXY \ + (gst_vaapi_surface_proxy_get_type()) + +#define GST_VAAPI_SURFACE_PROXY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_SURFACE_PROXY, \ + GstVaapiSurfaceProxy)) + +#define GST_VAAPI_SURFACE_PROXY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_SURFACE_PROXY, \ + GstVaapiSurfaceProxyClass)) + +#define GST_VAAPI_IS_SURFACE_PROXY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_SURFACE_PROXY)) + +#define GST_VAAPI_IS_SURFACE_PROXY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_SURFACE_PROXY)) + +#define GST_VAAPI_SURFACE_PROXY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_SURFACE_PROXY, \ + GstVaapiSurfaceProxyClass)) + +/** + * GST_VAAPI_SURFACE_PROXY_SURFACE: + * @surface: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the #GstVaapiSurface of @surface. + */ +#define GST_VAAPI_SURFACE_PROXY_SURFACE(surface) \ + gst_vaapi_surface_proxy_get_surface(surface) + +/** + * GST_VAAPI_SURFACE_PROXY_TIMESTAMP: + * @surface: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the @surface timestamp, or + * %GST_CLOCK_TIME_NONE if none was set. + */ +#define GST_VAAPI_SURFACE_PROXY_TIMESTAMP(surface) \ + gst_vaapi_surface_proxy_get_timestamp(surface) + +/** + * GST_VAAPI_SURFACE_PROXY_INTERLACED: + * @surface: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to %TRUE if the @surface is interlaced. + */ +#define GST_VAAPI_SURFACE_PROXY_INTERLACED(surface) \ + gst_vaapi_surface_proxy_get_interlaced(surface) + +/** + * GST_VAAPI_SURFACE_PROXY_TFF: + * @surface: a #GstVaapiSurfaceProxy + * + * Macro that evaluates to the tff flag of the @surface + */ +#define GST_VAAPI_SURFACE_PROXY_TFF(surface) \ + gst_vaapi_surface_proxy_get_tff(surface) + +typedef struct _GstVaapiSurfaceProxy GstVaapiSurfaceProxy; +typedef struct _GstVaapiSurfaceProxyPrivate GstVaapiSurfaceProxyPrivate; +typedef struct _GstVaapiSurfaceProxyClass GstVaapiSurfaceProxyClass; + +/** + * GstVaapiSurfaceProxy: + * + * A wrapper around a VA surface and context. + */ +struct _GstVaapiSurfaceProxy { + /*< private >*/ + GObject parent_instance; + + GstVaapiSurfaceProxyPrivate *priv; +}; + +/** + * GstVaapiSurfaceProxyClass: + * + * A wrapper around a VA surface and context. + */ +struct _GstVaapiSurfaceProxyClass { + /*< private >*/ + GObjectClass parent_class; +}; + +GType +gst_vaapi_surface_proxy_get_type(void) G_GNUC_CONST; + +GstVaapiSurfaceProxy * +gst_vaapi_surface_proxy_new(GstVaapiContext *context, GstVaapiSurface *surface); + +GstVaapiContext * +gst_vaapi_surface_proxy_get_context(GstVaapiSurfaceProxy *proxy); + +void +gst_vaapi_surface_proxy_set_context( + GstVaapiSurfaceProxy *proxy, + GstVaapiContext *context +); + +GstVaapiSurface * +gst_vaapi_surface_proxy_get_surface(GstVaapiSurfaceProxy *proxy); + +GstVaapiID +gst_vaapi_surface_proxy_get_surface_id(GstVaapiSurfaceProxy *proxy); + +void +gst_vaapi_surface_proxy_set_surface( + GstVaapiSurfaceProxy *proxy, + GstVaapiSurface *surface +); + +GstClockTime +gst_vaapi_surface_proxy_get_timestamp(GstVaapiSurfaceProxy *proxy); + +void +gst_vaapi_surface_proxy_set_timestamp( + GstVaapiSurfaceProxy *proxy, + GstClockTime timestamp +); + +gboolean +gst_vaapi_surface_proxy_get_interlaced(GstVaapiSurfaceProxy *proxy); + +void +gst_vaapi_surface_proxy_set_interlaced(GstVaapiSurfaceProxy *proxy, gboolean b); + +gboolean +gst_vaapi_surface_proxy_get_tff(GstVaapiSurfaceProxy *proxy); + +void +gst_vaapi_surface_proxy_set_tff(GstVaapiSurfaceProxy *proxy, gboolean tff); + +G_END_DECLS + +#endif /* GST_VAAPI_SURFACE_PROXY_H */ diff --git a/gst-libs/gst/vaapi/gstvaapitexture.c b/gst-libs/gst/vaapi/gstvaapitexture.c new file mode 100644 index 0000000..97025f2 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitexture.c @@ -0,0 +1,683 @@ +/* + * gstvaapitexture.c - VA texture abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapitexture + * @short_description: VA/GLX texture abstraction + */ + +#include "sysdeps.h" +#include "gstvaapitexture.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapiutils_glx.h" +#include "gstvaapidisplay_glx.h" +#include "gstvaapi_priv.h" +#include "gstvaapidisplay_x11_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiTexture, gst_vaapi_texture, GST_VAAPI_TYPE_OBJECT); + +#define GST_VAAPI_TEXTURE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_TEXTURE, \ + GstVaapiTexturePrivate)) + +struct _GstVaapiTexturePrivate { + GLenum target; + GLenum format; + guint width; + guint height; + GLContextState *gl_context; + void *gl_surface; + GLPixmapObject *pixo; + GLFramebufferObject *fbo; + guint foreign_texture : 1; + guint is_constructed : 1; +}; + +enum { + PROP_0, + + PROP_TARGET, + PROP_FORMAT, + PROP_WIDTH, + PROP_HEIGHT +}; + +static void +_gst_vaapi_texture_destroy_objects(GstVaapiTexture *texture) +{ + GstVaapiTexturePrivate * const priv = texture->priv; + +#if USE_VAAPI_GLX + GST_VAAPI_OBJECT_LOCK_DISPLAY(texture); + if (priv->gl_surface) { + vaDestroySurfaceGLX( + GST_VAAPI_OBJECT_VADISPLAY(texture), + priv->gl_surface + ); + priv->gl_surface = NULL; + } + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture); +#else + GLContextState old_cs; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(texture); + if (priv->gl_context) + gl_set_current_context(priv->gl_context, &old_cs); + + if (priv->fbo) { + gl_destroy_framebuffer_object(priv->fbo); + priv->fbo = NULL; + } + + if (priv->pixo) { + gl_destroy_pixmap_object(priv->pixo); + priv->pixo = NULL; + } + + if (priv->gl_context) { + gl_set_current_context(&old_cs, NULL); + gl_destroy_context(priv->gl_context); + priv->gl_context = NULL; + } + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture); +#endif +} + +static void +gst_vaapi_texture_destroy(GstVaapiTexture *texture) +{ + GstVaapiTexturePrivate * const priv = texture->priv; + const GLuint texture_id = GST_VAAPI_OBJECT_ID(texture); + + _gst_vaapi_texture_destroy_objects(texture); + + if (texture_id) { + if (!priv->foreign_texture) + glDeleteTextures(1, &texture_id); + GST_VAAPI_OBJECT_ID(texture) = 0; + } +} + +static gboolean +_gst_vaapi_texture_create_objects(GstVaapiTexture *texture, GLuint texture_id) +{ + GstVaapiTexturePrivate * const priv = texture->priv; + gboolean success = FALSE; + +#if USE_VAAPI_GLX + VAStatus status; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(texture); + status = vaCreateSurfaceGLX( + GST_VAAPI_OBJECT_VADISPLAY(texture), + priv->target, + texture_id, + &priv->gl_surface + ); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture); + success = vaapi_check_status(status, "vaCreateSurfaceGLX()"); +#else + GLContextState old_cs; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(texture); + gl_get_current_context(&old_cs); + priv->gl_context = gl_create_context( + GST_VAAPI_OBJECT_XDISPLAY(texture), + GST_VAAPI_OBJECT_XSCREEN(texture), + &old_cs + ); + if (!priv->gl_context || !gl_set_current_context(priv->gl_context, NULL)) + goto end; + + priv->pixo = gl_create_pixmap_object( + GST_VAAPI_OBJECT_XDISPLAY(texture), + priv->width, + priv->height + ); + if (!priv->pixo) + goto end; + + priv->fbo = gl_create_framebuffer_object( + priv->target, + texture_id, + priv->width, + priv->height + ); + if (priv->fbo) + success = TRUE; +end: + gl_set_current_context(&old_cs, NULL); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture); +#endif + return success; +} + +static gboolean +gst_vaapi_texture_create(GstVaapiTexture *texture) +{ + GstVaapiTexturePrivate * const priv = texture->priv; + GLuint texture_id; + + if (priv->foreign_texture) + texture_id = GST_VAAPI_OBJECT_ID(texture); + else { + GST_VAAPI_OBJECT_LOCK_DISPLAY(texture); + texture_id = gl_create_texture( + priv->target, + priv->format, + priv->width, + priv->height + ); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture); + if (!texture_id) + return FALSE; + GST_VAAPI_OBJECT_ID(texture) = texture_id; + } + + return _gst_vaapi_texture_create_objects(texture, texture_id); +} + +static void +gst_vaapi_texture_finalize(GObject *object) +{ + gst_vaapi_texture_destroy(GST_VAAPI_TEXTURE(object)); + + G_OBJECT_CLASS(gst_vaapi_texture_parent_class)->finalize(object); +} + +static void +gst_vaapi_texture_constructed(GObject *object) +{ + GstVaapiTexture * const texture = GST_VAAPI_TEXTURE(object); + GObjectClass *parent_class; + + texture->priv->foreign_texture = GST_VAAPI_OBJECT_ID(texture) != 0; + texture->priv->is_constructed = gst_vaapi_texture_create(texture); + + parent_class = G_OBJECT_CLASS(gst_vaapi_texture_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static void +gst_vaapi_texture_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiTexture * const texture = GST_VAAPI_TEXTURE(object); + + switch (prop_id) { + case PROP_TARGET: + texture->priv->target = g_value_get_uint(value); + break; + case PROP_FORMAT: + texture->priv->format = g_value_get_uint(value); + break; + case PROP_WIDTH: + texture->priv->width = g_value_get_uint(value); + break; + case PROP_HEIGHT: + texture->priv->height = g_value_get_uint(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_texture_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiTexture * const texture = GST_VAAPI_TEXTURE(object); + + switch (prop_id) { + case PROP_TARGET: + g_value_set_uint(value, gst_vaapi_texture_get_target(texture)); + break; + case PROP_FORMAT: + g_value_set_uint(value, gst_vaapi_texture_get_format(texture)); + break; + case PROP_WIDTH: + g_value_set_uint(value, gst_vaapi_texture_get_width(texture)); + break; + case PROP_HEIGHT: + g_value_set_uint(value, gst_vaapi_texture_get_height(texture)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_texture_class_init(GstVaapiTextureClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiTexturePrivate)); + + object_class->finalize = gst_vaapi_texture_finalize; + object_class->set_property = gst_vaapi_texture_set_property; + object_class->get_property = gst_vaapi_texture_get_property; + object_class->constructed = gst_vaapi_texture_constructed; + + g_object_class_install_property + (object_class, + PROP_TARGET, + g_param_spec_uint("target", + "Target", + "The texture target", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, + PROP_FORMAT, + g_param_spec_uint("format", + "Format", + "The texture format", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, + PROP_WIDTH, + g_param_spec_uint("width", + "width", + "The texture width", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, + PROP_HEIGHT, + g_param_spec_uint("height", + "height", + "The texture height", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gst_vaapi_texture_init(GstVaapiTexture *texture) +{ + GstVaapiTexturePrivate *priv = GST_VAAPI_TEXTURE_GET_PRIVATE(texture); + + texture->priv = priv; + priv->target = GL_NONE; + priv->format = GL_NONE; + priv->width = 0; + priv->height = 0; + priv->gl_context = NULL; + priv->gl_surface = NULL; + priv->pixo = NULL; + priv->fbo = NULL; + priv->foreign_texture = FALSE; + priv->is_constructed = FALSE; +} + +/** + * gst_vaapi_texture_new: + * @display: a #GstVaapiDisplay + * @target: the target to which the texture is bound + * @format: the format of the pixel data + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Creates a texture with the specified dimensions, @target and + * @format. Note that only GL_TEXTURE_2D @target and GL_RGBA or + * GL_BGRA formats are supported at this time. + * + * The application shall maintain the live GL context itself. That is, + * gst_vaapi_window_glx_make_current() must be called beforehand, or + * any other function like glXMakeCurrent() if the context is managed + * outside of this library. + * + * Return value: the newly created #GstVaapiTexture object + */ +GstVaapiTexture * +gst_vaapi_texture_new( + GstVaapiDisplay *display, + GLenum target, + GLenum format, + guint width, + guint height +) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + + return g_object_new(GST_VAAPI_TYPE_TEXTURE, + "display", display, + "id", GST_VAAPI_ID(0), + "target", target, + "format", format, + "width", width, + "height", height, + NULL); +} + +/** + * gst_vaapi_texture_new_with_texture: + * @display: a #GstVaapiDisplay + * @texture: the foreign GL texture name to use + * @target: the target to which the texture is bound + * @format: the format of the pixel data + * + * Creates a texture from an existing GL texture, with the specified + * @target and @format. Note that only GL_TEXTURE_2D @target and + * GL_RGBA or GL_BGRA formats are supported at this time. The + * dimensions will be retrieved from the @texture. + * + * The application shall maintain the live GL context itself. That is, + * gst_vaapi_window_glx_make_current() must be called beforehand, or + * any other function like glXMakeCurrent() if the context is managed + * outside of this library. + * + * Return value: the newly created #GstVaapiTexture object + */ +GstVaapiTexture * +gst_vaapi_texture_new_with_texture( + GstVaapiDisplay *display, + GLuint texture, + GLenum target, + GLenum format +) +{ + guint width, height, border_width; + GLTextureState ts; + gboolean success; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + + /* Check texture dimensions */ + GST_VAAPI_DISPLAY_LOCK(display); + success = gl_bind_texture(&ts, target, texture); + if (success) { + if (!gl_get_texture_param(target, GL_TEXTURE_WIDTH, &width) || + !gl_get_texture_param(target, GL_TEXTURE_HEIGHT, &height) || + !gl_get_texture_param(target, GL_TEXTURE_BORDER, &border_width)) + success = FALSE; + gl_unbind_texture(&ts); + } + GST_VAAPI_DISPLAY_UNLOCK(display); + if (!success) + return NULL; + + width -= 2 * border_width; + height -= 2 * border_width; + if (width == 0 || height == 0) + return NULL; + + return g_object_new(GST_VAAPI_TYPE_TEXTURE, + "display", display, + "id", GST_VAAPI_ID(texture), + "target", target, + "format", format, + "width", width, + "height", height, + NULL); +} + +/** + * gst_vaapi_texture_get_id: + * @texture: a #GstVaapiTexture + * + * Returns the underlying texture id of the @texture. + * + * Return value: the underlying texture id of the @texture + */ +GLuint +gst_vaapi_texture_get_id(GstVaapiTexture *texture) +{ + g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), 0); + + return GST_VAAPI_OBJECT_ID(texture); +} + +/** + * gst_vaapi_texture_get_target: + * @texture: a #GstVaapiTexture + * + * Returns the @texture target type + * + * Return value: the texture target + */ +GLenum +gst_vaapi_texture_get_target(GstVaapiTexture *texture) +{ + g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), GL_NONE); + g_return_val_if_fail(texture->priv->is_constructed, GL_NONE); + + return texture->priv->target; +} + +/** + * gst_vaapi_texture_get_format + * @texture: a #GstVaapiTexture + * + * Returns the @texture format + * + * Return value: the texture format + */ +GLenum +gst_vaapi_texture_get_format(GstVaapiTexture *texture) +{ + g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), GL_NONE); + g_return_val_if_fail(texture->priv->is_constructed, GL_NONE); + + return texture->priv->format; +} + +/** + * gst_vaapi_texture_get_width: + * @texture: a #GstVaapiTexture + * + * Returns the @texture width. + * + * Return value: the texture width, in pixels + */ +guint +gst_vaapi_texture_get_width(GstVaapiTexture *texture) +{ + g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), 0); + g_return_val_if_fail(texture->priv->is_constructed, 0); + + return texture->priv->width; +} + +/** + * gst_vaapi_texture_get_height: + * @texture: a #GstVaapiTexture + * + * Returns the @texture height. + * + * Return value: the texture height, in pixels. + */ +guint +gst_vaapi_texture_get_height(GstVaapiTexture *texture) +{ + g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), 0); + g_return_val_if_fail(texture->priv->is_constructed, 0); + + return texture->priv->height; +} + +/** + * gst_vaapi_texture_get_size: + * @texture: a #GstVaapiTexture + * @pwidth: return location for the width, or %NULL + * @pheight: return location for the height, or %NULL + * + * Retrieves the dimensions of a #GstVaapiTexture. + */ +void +gst_vaapi_texture_get_size( + GstVaapiTexture *texture, + guint *pwidth, + guint *pheight +) +{ + g_return_if_fail(GST_VAAPI_IS_TEXTURE(texture)); + g_return_if_fail(texture->priv->is_constructed); + + if (pwidth) + *pwidth = texture->priv->width; + + if (pheight) + *pheight = texture->priv->height; +} + +/** + * gst_vaapi_texture_put_surface: + * @texture: a #GstVaapiTexture + * @surface: a #GstVaapiSurface + * @flags: postprocessing flags. See #GstVaapiTextureRenderFlags + * + * Renders the @surface into the àtexture. The @flags specify how + * de-interlacing (if needed), color space conversion, scaling and + * other postprocessing transformations are performed. + * + * Return value: %TRUE on success + */ +static gboolean +_gst_vaapi_texture_put_surface( + GstVaapiTexture *texture, + GstVaapiSurface *surface, + guint flags +) +{ + GstVaapiTexturePrivate * const priv = texture->priv; + VAStatus status; + +#if USE_VAAPI_GLX + GST_VAAPI_OBJECT_LOCK_DISPLAY(texture); + status = vaCopySurfaceGLX( + GST_VAAPI_OBJECT_VADISPLAY(texture), + priv->gl_surface, + GST_VAAPI_OBJECT_ID(surface), + from_GstVaapiSurfaceRenderFlags(flags) + ); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture); + if (!vaapi_check_status(status, "vaCopySurfaceGLX()")) + return FALSE; +#else + guint surface_width, surface_height; + GLContextState old_cs; + gboolean success = FALSE; + + gst_vaapi_surface_get_size(surface, &surface_width, &surface_height); + + GST_VAAPI_OBJECT_LOCK_DISPLAY(texture); + status = vaPutSurface( + GST_VAAPI_OBJECT_VADISPLAY(texture), + GST_VAAPI_OBJECT_ID(surface), + priv->pixo->pixmap, + 0, 0, surface_width, surface_height, + 0, 0, priv->width, priv->height, + NULL, 0, + from_GstVaapiSurfaceRenderFlags(flags) + ); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture); + if (!vaapi_check_status(status, "vaPutSurface() [TFP]")) + return FALSE; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(texture); + if (priv->gl_context) { + success = gl_set_current_context(priv->gl_context, &old_cs); + if (!success) + goto end; + } + + success = gl_bind_framebuffer_object(priv->fbo); + if (!success) { + GST_DEBUG("could not bind FBO"); + goto out_reset_context; + } + + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture); + success = gst_vaapi_surface_sync(surface); + GST_VAAPI_OBJECT_LOCK_DISPLAY(texture); + if (!success) { + GST_DEBUG("could not render surface to pixmap"); + goto out_unbind_fbo; + } + + success = gl_bind_pixmap_object(priv->pixo); + if (!success) { + GST_DEBUG("could not bind GLX pixmap"); + goto out_unbind_fbo; + } + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + { + glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0 ); + glTexCoord2f(0.0f, 1.0f); glVertex2i(0, priv->height); + glTexCoord2f(1.0f, 1.0f); glVertex2i(priv->width, priv->height); + glTexCoord2f(1.0f, 0.0f); glVertex2i(priv->width, 0 ); + } + glEnd(); + + success = gl_unbind_pixmap_object(priv->pixo); + if (!success) { + GST_DEBUG("could not release GLX pixmap"); + goto out_unbind_fbo; + } + +out_unbind_fbo: + if (!gl_unbind_framebuffer_object(priv->fbo)) + success = FALSE; +out_reset_context: + if (priv->gl_context && !gl_set_current_context(&old_cs, NULL)) + success = FALSE; +end: + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture); + return success; +#endif + return TRUE; +} + +gboolean +gst_vaapi_texture_put_surface( + GstVaapiTexture *texture, + GstVaapiSurface *surface, + guint flags +) +{ + g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), FALSE); + g_return_val_if_fail(texture->priv->is_constructed, FALSE); + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE); + + return _gst_vaapi_texture_put_surface(texture, surface, flags); +} diff --git a/gst-libs/gst/vaapi/gstvaapitexture.h b/gst-libs/gst/vaapi/gstvaapitexture.h new file mode 100644 index 0000000..4f8f3ce --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitexture.h @@ -0,0 +1,134 @@ +/* + * gstvaapitexture.h - VA texture abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_TEXTURE_H +#define GST_VAAPI_TEXTURE_H + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_TEXTURE \ + (gst_vaapi_texture_get_type()) + +#define GST_VAAPI_TEXTURE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_TEXTURE, \ + GstVaapiTexture)) + +#define GST_VAAPI_TEXTURE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_TEXTURE, \ + GstVaapiTextureClass)) + +#define GST_VAAPI_IS_TEXTURE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_TEXTURE)) + +#define GST_VAAPI_IS_TEXTURE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_TEXTURE)) + +#define GST_VAAPI_TEXTURE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_TEXTURE, \ + GstVaapiTextureClass)) + +typedef struct _GstVaapiTexture GstVaapiTexture; +typedef struct _GstVaapiTexturePrivate GstVaapiTexturePrivate; +typedef struct _GstVaapiTextureClass GstVaapiTextureClass; + +/** + * GstVaapiTexture: + * + * Base class for system-dependent textures. + */ +struct _GstVaapiTexture { + /*< private >*/ + GstVaapiObject parent_instance; + + GstVaapiTexturePrivate *priv; +}; + +/** + * GstVaapiTextureClass: + * + * Base class for system-dependent textures. + */ +struct _GstVaapiTextureClass { + /*< private >*/ + GstVaapiObjectClass parent_class; +}; + +GType +gst_vaapi_texture_get_type(void) G_GNUC_CONST; + +GstVaapiTexture * +gst_vaapi_texture_new( + GstVaapiDisplay *display, + GLenum target, + GLenum format, + guint width, + guint height +); + +GstVaapiTexture * +gst_vaapi_texture_new_with_texture( + GstVaapiDisplay *display, + GLuint texture, + GLenum target, + GLenum format +); + +GLuint +gst_vaapi_texture_get_id(GstVaapiTexture *texture); + +GLenum +gst_vaapi_texture_get_target(GstVaapiTexture *texture); + +GLenum +gst_vaapi_texture_get_format(GstVaapiTexture *texture); + +guint +gst_vaapi_texture_get_width(GstVaapiTexture *texture); + +guint +gst_vaapi_texture_get_height(GstVaapiTexture *texture); + +void +gst_vaapi_texture_get_size( + GstVaapiTexture *texture, + guint *pwidth, + guint *pheight +); + +gboolean +gst_vaapi_texture_put_surface( + GstVaapiTexture *texture, + GstVaapiSurface *surface, + guint flags +); + +G_END_DECLS + +#endif /* GST_VAAPI_TEXTURE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapitypes.h b/gst-libs/gst/vaapi/gstvaapitypes.h new file mode 100644 index 0000000..08c0bd1 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapitypes.h @@ -0,0 +1,175 @@ +/* + * gstvaapitypes.h - Basic types + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_TYPES_H +#define GST_VAAPI_TYPES_H + +#include + +G_BEGIN_DECLS + +/** + * GstVaapiID: + * + * An integer large enough to hold a generic VA id or a pointer + * wherever necessary. + */ +#if defined(GLIB_SIZEOF_VOID_P) +# define GST_VAAPI_TYPE_ID_SIZE GLIB_SIZEOF_VOID_P +#elif G_MAXULONG == 0xffffffff +# define GST_VAAPI_TYPE_ID_SIZE 4 +#elif G_MAXULONG == 0xffffffffffffffffull +# define GST_VAAPI_TYPE_ID_SIZE 8 +#else +# error "could not determine size of GstVaapiID" +#endif +#if GST_VAAPI_TYPE_ID_SIZE == 4 +typedef guint32 GstVaapiID; +#elif GST_VAAPI_TYPE_ID_SIZE == 8 +typedef guint64 GstVaapiID; +#else +# error "unsupported value for GST_VAAPI_TYPE_ID_SIZE" +#endif + +/** + * GST_VAAPI_ID: + * @id: an arbitrary integer value + * + * Macro that creates a #GstVaapiID from @id. + */ +#define GST_VAAPI_ID(id) ((GstVaapiID)(id)) + +/** + * GST_VAAPI_ID_NONE: + * + * Macro that evaluates to the default #GstVaapiID value. + */ +#define GST_VAAPI_ID_NONE GST_VAAPI_ID(0) + +/** + * GST_VAAPI_ID_FORMAT: + * + * Can be used together with #GST_VAAPI_ID_ARGS to properly output an + * integer value in a printf()-style text message. + * + * + * printf("id: %" GST_VAAPI_ID_FORMAT "\n", GST_VAAPI_ID_ARGS(id)); + * + * + */ +#define GST_VAAPI_ID_FORMAT "p" + +/** + * GST_VAAPI_ID_ARGS: + * @id: a #GstVaapiID + * + * Can be used together with #GST_VAAPI_ID_FORMAT to properly output + * an integer value in a printf()-style text message. + */ +#define GST_VAAPI_ID_ARGS(id) GUINT_TO_POINTER(id) + +/** + * GstVaapiPoint: + * @x: X coordinate + * @y: Y coordinate + * + * A location within a surface. + */ +typedef struct _GstVaapiPoint GstVaapiPoint; +struct _GstVaapiPoint { + guint32 x; + guint32 y; +}; + +/** + * GstVaapiRectangle: + * @x: X coordinate + * @y: Y coordinate + * @width: region width + * @height: region height + * + * A rectangle region within a surface. + */ +typedef struct _GstVaapiRectangle GstVaapiRectangle; +struct _GstVaapiRectangle { + guint32 x; + guint32 y; + guint32 width; + guint32 height; +}; + +/** + * GstVaapiRenderMode: + * @GST_VAAPI_RENDER_MODE_OVERLAY: in this mode, the VA display + * backend renders surfaces with an overlay engine. This means that + * the surface that is currently displayed shall not be re-used + * right away for decoding. i.e. it needs to be retained further, + * until the next surface is to be displayed. + * @GST_VAAPI_RENDER_MODE_TEXTURE: in this modem the VA display + * backend renders surfaces with a textured blit (GPU/3D engine). + * This means that the surface is copied to some intermediate + * backing store, or back buffer of a frame buffer, and is free to + * be re-used right away for decoding. + */ +typedef enum _GstVaapiRenderMode GstVaapiRenderMode; +enum _GstVaapiRenderMode { + GST_VAAPI_RENDER_MODE_OVERLAY = 1, + GST_VAAPI_RENDER_MODE_TEXTURE +}; + +/** + * GstVaapiRotation: + * @GST_VAAPI_ROTATION_0: the VA display is not rotated. + * @GST_VAAPI_ROTATION_90: the VA display is rotated by 90°, clockwise. + * @GST_VAAPI_ROTATION_180: the VA display is rotated by 180°, clockwise. + * @GST_VAAPI_ROTATION_270: the VA display is rotated by 270°, clockwise. + */ +typedef enum _GstVaapiRotation GstVaapiRotation; +enum _GstVaapiRotation { + GST_VAAPI_ROTATION_0 = 0, + GST_VAAPI_ROTATION_90 = 90, + GST_VAAPI_ROTATION_180 = 180, + GST_VAAPI_ROTATION_270 = 270, +}; + +/** + * GstVaapiRateControl: + * @GST_VAAPI_RATECONTROL_NONE: None rate control + * @GST_VAAPI_RATECONTROL_CBR: Constant rate control + * @GST_VAAPI_RATECONTROL_VBR: Variable bitrate control + * @GST_VAAPI_RATECONTROL_VCM: Video conference mode + * @GST_VAAPI_RATECONTROL_CQP: Variable bitrate control + * @GST_VAAPI_RATECONTROL_VBR_CONSTRAINED: Variable bitrate control with peak rate higher than average bitrate + * + * The set of all rate-controls for #GstVaapiRateControl, only worked on encoders + */ +typedef enum { + GST_VAAPI_RATECONTROL_NONE = 0, + GST_VAAPI_RATECONTROL_CBR, + GST_VAAPI_RATECONTROL_VBR, + GST_VAAPI_RATECONTROL_VCM, + GST_VAAPI_RATECONTROL_CQP, + GST_VAAPI_RATECONTROL_VBR_CONSTRAINED, +} GstVaapiRateControl; + +G_END_DECLS + +#endif /* GST_VAAPI_TYPES_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils.c b/gst-libs/gst/vaapi/gstvaapiutils.c new file mode 100644 index 0000000..55cefe7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils.c @@ -0,0 +1,354 @@ +/* + * gstvaapiutils.c - VA-API utilities + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapicompat.h" +#include "gstvaapiutils.h" +#include "gstvaapisurface.h" +#include +#include + +#define DEBUG 1 +#include "gstvaapidebug.h" + +#define CONCAT(a, b) CONCAT_(a, b) +#define CONCAT_(a, b) a##b +#define STRINGIFY(x) STRINGIFY_(x) +#define STRINGIFY_(x) #x +#define STRCASEP(p, x) STRCASE(CONCAT(p, x)) +#define STRCASE(x) case x: return STRINGIFY(x) + +/* Check VA status for success or print out an error */ +gboolean +vaapi_check_status(VAStatus status, const char *msg) +{ + if (status != VA_STATUS_SUCCESS) { + GST_DEBUG("%s: %s", msg, vaErrorStr(status)); + return FALSE; + } + return TRUE; +} + +/* Maps VA buffer */ +void * +vaapi_map_buffer(VADisplay dpy, VABufferID buf_id) +{ + VAStatus status; + void *data = NULL; + + status = vaMapBuffer(dpy, buf_id, &data); + if (!vaapi_check_status(status, "vaMapBuffer()")) + return NULL; + return data; +} + +/* Unmaps VA buffer */ +void +vaapi_unmap_buffer(VADisplay dpy, VABufferID buf_id, void **pbuf) +{ + VAStatus status; + + if (pbuf) + *pbuf = NULL; + + status = vaUnmapBuffer(dpy, buf_id); + if (!vaapi_check_status(status, "vaUnmapBuffer()")) + return; +} + +/* Creates and maps VA buffer */ +gboolean +vaapi_create_buffer( + VADisplay dpy, + VAContextID ctx, + int type, + unsigned int size, + gconstpointer buf, + VABufferID *buf_id_ptr, + gpointer *mapped_data +) +{ + VABufferID buf_id; + VAStatus status; + gpointer data = (gpointer)buf; + + status = vaCreateBuffer(dpy, ctx, type, size, 1, data, &buf_id); + if (!vaapi_check_status(status, "vaCreateBuffer()")) + return FALSE; + + if (mapped_data) { + data = vaapi_map_buffer(dpy, buf_id); + if (!data) + goto error; + *mapped_data = data; + } + + *buf_id_ptr = buf_id; + return TRUE; + +error: + vaapi_destroy_buffer(dpy, &buf_id); + return FALSE; +} + +/* Destroy VA buffer */ +void +vaapi_destroy_buffer(VADisplay dpy, VABufferID *buf_id_ptr) +{ + if (!buf_id_ptr || *buf_id_ptr == VA_INVALID_ID) + return; + + vaDestroyBuffer(dpy, *buf_id_ptr); + *buf_id_ptr = VA_INVALID_ID; +} + +/* Return a string representation of a VAProfile */ +const char *string_of_VAProfile(VAProfile profile) +{ + switch (profile) { +#define MAP(profile) \ + STRCASEP(VAProfile, profile) + MAP(MPEG2Simple); + MAP(MPEG2Main); + MAP(MPEG4Simple); + MAP(MPEG4AdvancedSimple); + MAP(MPEG4Main); +#if VA_CHECK_VERSION(0,32,0) + MAP(JPEGBaseline); + MAP(H263Baseline); + MAP(H264ConstrainedBaseline); +#endif + MAP(H264Baseline); + MAP(H264Main); + MAP(H264High); + MAP(VC1Simple); + MAP(VC1Main); + MAP(VC1Advanced); +#undef MAP + default: break; + } + return ""; +} + +/* Return a string representation of a VAEntrypoint */ +const char *string_of_VAEntrypoint(VAEntrypoint entrypoint) +{ + switch (entrypoint) { +#define MAP(entrypoint) \ + STRCASEP(VAEntrypoint, entrypoint) + MAP(VLD); + MAP(IZZ); + MAP(IDCT); + MAP(MoComp); + MAP(Deblocking); +#undef MAP + default: break; + } + return ""; +} + +/* Return a string representation of a VADisplayAttributeType */ +const char * +string_of_VADisplayAttributeType(VADisplayAttribType attribute_type) +{ + switch (attribute_type) { +#define MAP(attribute_type) \ + STRCASEP(VADisplayAttrib, attribute_type) + MAP(Brightness); + MAP(Contrast); + MAP(Hue); + MAP(Saturation); + MAP(BackgroundColor); +#if !VA_CHECK_VERSION(0,34,0) + MAP(DirectSurface); +#endif + MAP(Rotation); + MAP(OutofLoopDeblock); +#if VA_CHECK_VERSION(0,31,1) && !VA_CHECK_VERSION(0,34,0) + MAP(BLEBlackMode); + MAP(BLEWhiteMode); + MAP(BlueStretch); + MAP(SkinColorCorrection); +#endif + MAP(CSCMatrix); + MAP(BlendColor); + MAP(OverlayAutoPaintColorKey); + MAP(OverlayColorKey); + MAP(RenderMode); + MAP(RenderDevice); + MAP(RenderRect); +#undef MAP + default: break; + } + return ""; +} + +/** + * from_GstVaapiSurfaceRenderFlags: + * @flags: the #GstVaapiSurfaceRenderFlags + * + * Converts #GstVaapiSurfaceRenderFlags to flags suitable for + * vaPutSurface(). + */ +guint +from_GstVaapiSurfaceRenderFlags(guint flags) +{ + guint va_fields = 0, va_csc = 0; + + if (flags & GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) + va_fields |= VA_TOP_FIELD; + if (flags & GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) + va_fields |= VA_BOTTOM_FIELD; + if ((va_fields ^ (VA_TOP_FIELD|VA_BOTTOM_FIELD)) == 0) + va_fields = VA_FRAME_PICTURE; + +#ifdef VA_SRC_BT601 + if (flags & GST_VAAPI_COLOR_STANDARD_ITUR_BT_601) + va_csc = VA_SRC_BT601; +#endif +#ifdef VA_SRC_BT709 + if (flags & GST_VAAPI_COLOR_STANDARD_ITUR_BT_709) + va_csc = VA_SRC_BT709; +#endif + + return va_fields|va_csc; +} + +/** + * to_GstVaapiSurfaceStatus: + * @flags: the #GstVaapiSurfaceStatus flags to translate + * + * Converts vaQuerySurfaceStatus() @flags to #GstVaapiSurfaceStatus + * flags. + * + * Return value: the #GstVaapiSurfaceStatus flags + */ +guint +to_GstVaapiSurfaceStatus(guint va_flags) +{ + guint flags; + const guint va_flags_mask = (VASurfaceReady| + VASurfaceRendering| + VASurfaceDisplaying); + + /* Check for core status */ + switch (va_flags & va_flags_mask) { + case VASurfaceReady: + flags = GST_VAAPI_SURFACE_STATUS_IDLE; + break; + case VASurfaceRendering: + flags = GST_VAAPI_SURFACE_STATUS_RENDERING; + break; + case VASurfaceDisplaying: + flags = GST_VAAPI_SURFACE_STATUS_DISPLAYING; + break; + default: + flags = 0; + break; + } + + /* Check for encoder status */ +#if VA_CHECK_VERSION(0,30,0) + if (va_flags & VASurfaceSkipped) + flags |= GST_VAAPI_SURFACE_STATUS_SKIPPED; +#endif + return flags; +} + +/* Translate GstVaapiRotation value to VA-API rotation value */ +guint +from_GstVaapiRotation(guint value) +{ + switch (value) { + case GST_VAAPI_ROTATION_0: return VA_ROTATION_NONE; + case GST_VAAPI_ROTATION_90: return VA_ROTATION_90; + case GST_VAAPI_ROTATION_180: return VA_ROTATION_180; + case GST_VAAPI_ROTATION_270: return VA_ROTATION_270; + } + GST_ERROR("unsupported GstVaapiRotation value %d", value); + return VA_ROTATION_NONE; +} + +/* Translate VA-API rotation value to GstVaapiRotation value */ +guint +to_GstVaapiRotation(guint value) +{ + switch (value) { + case VA_ROTATION_NONE: return GST_VAAPI_ROTATION_0; + case VA_ROTATION_90: return GST_VAAPI_ROTATION_90; + case VA_ROTATION_180: return GST_VAAPI_ROTATION_180; + case VA_ROTATION_270: return GST_VAAPI_ROTATION_270; + } + GST_ERROR("unsupported VA-API rotation value %d", value); + return GST_VAAPI_ROTATION_0; +} + +guint +from_GstVaapiRateControl(guint value) +{ + switch (value) { + case GST_VAAPI_RATECONTROL_NONE: return VA_RC_NONE; + case GST_VAAPI_RATECONTROL_CBR: return VA_RC_CBR; + case GST_VAAPI_RATECONTROL_VBR: return VA_RC_VBR; + case GST_VAAPI_RATECONTROL_VCM: return VA_RC_VCM; +#if VA_CHECK_VERSION(0,34,0) + case GST_VAAPI_RATECONTROL_CQP: return VA_RC_CQP; + case GST_VAAPI_RATECONTROL_VBR_CONSTRAINED: return VA_RC_VBR_CONSTRAINED; +#endif + } + GST_ERROR("unsupported GstVaapiRateControl value %d", value); + return VA_RC_NONE; +} + +guint +to_GstVaapiRateControl(guint value) +{ + switch (value) { + case VA_RC_NONE: return GST_VAAPI_RATECONTROL_NONE; + case VA_RC_CBR: return GST_VAAPI_RATECONTROL_CBR; + case VA_RC_VBR: return GST_VAAPI_RATECONTROL_VBR; + case VA_RC_VCM: return GST_VAAPI_RATECONTROL_VCM; +#if VA_CHECK_VERSION(0,34,0) + case VA_RC_CQP: return GST_VAAPI_RATECONTROL_CQP; + case VA_RC_VBR_CONSTRAINED: return GST_VAAPI_RATECONTROL_VBR_CONSTRAINED; +#endif + } + GST_ERROR("unsupported VA-API Rate Control value %d", value); + return GST_VAAPI_RATECONTROL_NONE; +} + +const char * +string_of_VARateControl(guint rate_control) +{ + switch (rate_control) { + case VA_RC_NONE: return "VA_RC_NONE"; + case VA_RC_CBR: return "VA_RC_CBR"; + case VA_RC_VBR: return "VA_RC_VBR"; + case VA_RC_VCM: return "VA_RC_VCM"; +#if VA_CHECK_VERSION(0,34,0) + case VA_RC_CQP: return "VA_RC_CQP"; + case VA_RC_VBR_CONSTRAINED: return "VA_RC_VBR_CONSTRAINED"; +#endif + default: break; + } + return ""; +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils.h b/gst-libs/gst/vaapi/gstvaapiutils.h new file mode 100644 index 0000000..1a3fbf2 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils.h @@ -0,0 +1,104 @@ +/* + * gstvaapiutils.h - VA-API utilities + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_H +#define GST_VAAPI_UTILS_H + +#include "config.h" +#include +#include + +/** Check VA status for success or print out an error */ +G_GNUC_INTERNAL +gboolean +vaapi_check_status(VAStatus status, const char *msg); + +/** Maps VA buffer */ +G_GNUC_INTERNAL +void * +vaapi_map_buffer(VADisplay dpy, VABufferID buf_id); + +/** Unmaps VA buffer */ +G_GNUC_INTERNAL +void +vaapi_unmap_buffer(VADisplay dpy, VABufferID buf_id, void **pbuf); + +/** Creates and maps VA buffer */ +G_GNUC_INTERNAL +gboolean +vaapi_create_buffer( + VADisplay dpy, + VAContextID ctx, + int type, + unsigned int size, + gconstpointer data, + VABufferID *buf_id, + gpointer *mapped_data +); + +/** Destroy VA buffer */ +G_GNUC_INTERNAL +void +vaapi_destroy_buffer(VADisplay dpy, VABufferID *buf_id); + +/** Return a string representation of a VAProfile */ +G_GNUC_INTERNAL +const char *string_of_VAProfile(VAProfile profile); + +/** Return a string representation of a VAEntrypoint */ +G_GNUC_INTERNAL +const char *string_of_VAEntrypoint(VAEntrypoint entrypoint); + +/* Return a string representation of a VADisplayAttributeType */ +G_GNUC_INTERNAL +const char * +string_of_VADisplayAttributeType(VADisplayAttribType attribute_type); + +G_GNUC_INTERNAL +guint +from_GstVaapiSurfaceRenderFlags(guint flags); + +G_GNUC_INTERNAL +guint +to_GstVaapiSurfaceStatus(guint va_flags); + +G_GNUC_INTERNAL +guint +from_GstVaapiRotation(guint value); + +G_GNUC_INTERNAL +guint +to_GstVaapiRotation(guint value); + +G_GNUC_INTERNAL +guint +from_GstVaapiRateControl(guint value); + +G_GNUC_INTERNAL +guint +to_GstVaapiRateControl(guint value); + +G_GNUC_INTERNAL +const char * +string_of_VARateControl(guint rate_control); + +#endif /* GST_VAAPI_UTILS_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_glx.c b/gst-libs/gst/vaapi/gstvaapiutils_glx.c new file mode 100644 index 0000000..3821181 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_glx.c @@ -0,0 +1,1192 @@ +/* + * gstvaapiutils_glx.c - GLX utilties + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE 1 /* RTLD_DEFAULT */ +#include "sysdeps.h" +#include +#include +#include +#include "gstvaapiutils_glx.h" +#include "gstvaapiutils_x11.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/** Lookup for substring NAME in string EXT using SEP as separators */ +static gboolean +find_string(const char *name, const char *ext, const char *sep) +{ + const char *end; + int name_len, n; + + if (!name || !ext) + return FALSE; + + end = ext + strlen(ext); + name_len = strlen(name); + while (ext < end) { + n = strcspn(ext, sep); + if (n == name_len && strncmp(name, ext, n) == 0) + return TRUE; + ext += (n + 1); + } + return FALSE; +} + +/** + * gl_get_error_string: + * @error: an OpenGL error enumeration + * + * Retrieves the string representation the OpenGL @error. + * + * Return error: the static string representing the OpenGL @error + */ +const char * +gl_get_error_string(GLenum error) +{ + switch (error) { +#define MAP(id, str) \ + case id: return str " (" #id ")" + MAP(GL_NO_ERROR, "no error"); + MAP(GL_INVALID_ENUM, "invalid enumerant"); + MAP(GL_INVALID_VALUE, "invalid value"); + MAP(GL_INVALID_OPERATION, "invalid operation"); + MAP(GL_STACK_OVERFLOW, "stack overflow"); + MAP(GL_STACK_UNDERFLOW, "stack underflow"); + MAP(GL_OUT_OF_MEMORY, "out of memory"); +#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT + MAP(GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "invalid framebuffer operation"); +#endif +#undef MAP + default: break; + }; + return ""; +} + +/** + * gl_purge_errors: + * + * Purges all OpenGL errors. This function is generally useful to + * clear up the pending errors prior to calling gl_check_error(). + */ +void +gl_purge_errors(void) +{ + while (glGetError() != GL_NO_ERROR) + ; /* nothing */ +} + +/** + * gl_check_error: + * + * Checks whether there is any OpenGL error pending. + * + * Return value: %TRUE if an error was encountered + */ +gboolean +gl_check_error(void) +{ + GLenum error; + gboolean has_errors = FALSE; + + while ((error = glGetError()) != GL_NO_ERROR) { + GST_DEBUG("glError: %s caught", gl_get_error_string(error)); + has_errors = TRUE; + } + return has_errors; +} + +/** + * gl_get_param: + * @param: the parameter name + * @pval: return location for the value + * + * This function is a wrapper around glGetIntegerv() that does extra + * error checking. + * + * Return value: %TRUE on success + */ +gboolean +gl_get_param(GLenum param, guint *pval) +{ + GLint val; + + gl_purge_errors(); + glGetIntegerv(param, &val); + if (gl_check_error()) + return FALSE; + + if (pval) + *pval = val; + return TRUE; +} + +/** + * gl_get_texture_param: + * @target: the target to which the texture is bound + * @param: the parameter name + * @pval: return location for the value + * + * This function is a wrapper around glGetTexLevelParameteriv() that + * does extra error checking. + * + * Return value: %TRUE on success + */ +gboolean +gl_get_texture_param(GLenum target, GLenum param, guint *pval) +{ + GLint val; + + gl_purge_errors(); + glGetTexLevelParameteriv(target, 0, param, &val); + if (gl_check_error()) + return FALSE; + + if (pval) + *pval = val; + return TRUE; +} + +/** + * gl_get_texture_binding: + * @target: a texture target + * + * Determines the texture binding type for the specified target. + * + * Return value: texture binding type for @target + */ +static GLenum +gl_get_texture_binding(GLenum target) +{ + GLenum binding; + + switch (target) { + case GL_TEXTURE_1D: + binding = GL_TEXTURE_BINDING_1D; + break; + case GL_TEXTURE_2D: + binding = GL_TEXTURE_BINDING_2D; + break; + case GL_TEXTURE_3D: + binding = GL_TEXTURE_BINDING_3D; + break; + case GL_TEXTURE_RECTANGLE_ARB: + binding = GL_TEXTURE_BINDING_RECTANGLE_ARB; + break; + default: + binding = 0; + break; + } + return binding; +} + +/** + * gl_set_bgcolor: + * @color: the requested RGB color + * + * Sets background color to the RGB @color. This basically is a + * wrapper around glClearColor(). + */ +void +gl_set_bgcolor(guint32 color) +{ + glClearColor( + ((color >> 16) & 0xff) / 255.0f, + ((color >> 8) & 0xff) / 255.0f, + ( color & 0xff) / 255.0f, + 1.0f + ); +} + +/** + * gl_perspective: + * @fovy: the field of view angle, in degrees, in the y direction + * @aspect: the aspect ratio that determines the field of view in the + * x direction. The aspect ratio is the ratio of x (width) to y + * (height) + * @zNear: the distance from the viewer to the near clipping plane + * (always positive) + * @zFar: the distance from the viewer to the far clipping plane + * (always positive) + * + * Specified a viewing frustum into the world coordinate system. This + * basically is the Mesa implementation of gluPerspective(). + */ +static void +gl_perspective(GLdouble fovy, GLdouble aspect, GLdouble near_val, GLdouble far_val) +{ + GLdouble left, right, top, bottom; + + /* Source (Q 9.085): + */ + top = tan(fovy * M_PI / 360.0) * near_val; + bottom = -top; + left = aspect * bottom; + right = aspect * top; + glFrustum(left, right, bottom, top, near_val, far_val); +} + +/** + * gl_resize: + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Resizes the OpenGL viewport to the specified dimensions, using an + * orthogonal projection. (0,0) represents the top-left corner of the + * window. + */ +void +gl_resize(guint width, guint height) +{ +#define FOVY 60.0f +#define ASPECT 1.0f +#define Z_NEAR 0.1f +#define Z_FAR 100.0f +#define Z_CAMERA 0.869f + + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gl_perspective(FOVY, ASPECT, Z_NEAR, Z_FAR); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glTranslatef(-0.5f, -0.5f, -Z_CAMERA); + glScalef(1.0f/width, -1.0f/height, 1.0f/width); + glTranslatef(0.0f, -1.0f*height, 0.0f); +} + +/** + * gl_create_context: + * @dpy: an X11 #Display + * @screen: the associated screen of @dpy + * @parent: the parent #GLContextState, or %NULL if none is to be used + * + * Creates a GLX context sharing textures and displays lists with + * @parent, if not %NULL. + * + * Return value: the newly created GLX context + */ +GLContextState * +gl_create_context(Display *dpy, int screen, GLContextState *parent) +{ + GLContextState *cs; + GLXFBConfig *fbconfigs = NULL; + int fbconfig_id, val, n, n_fbconfigs; + Status status; + + static GLint fbconfig_attrs[] = { + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DOUBLEBUFFER, True, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + None + }; + + cs = malloc(sizeof(*cs)); + if (!cs) + goto error; + + if (parent) { + cs->display = parent->display; + cs->window = parent->window; + screen = DefaultScreen(parent->display); + } + else { + cs->display = dpy; + cs->window = None; + } + cs->visual = NULL; + cs->context = NULL; + cs->swapped_buffers = FALSE; + + if (parent && parent->context) { + status = glXQueryContext( + parent->display, + parent->context, + GLX_FBCONFIG_ID, &fbconfig_id + ); + if (status != Success) + goto error; + + if (fbconfig_id == GLX_DONT_CARE) + goto choose_fbconfig; + + fbconfigs = glXGetFBConfigs(parent->display, screen, &n_fbconfigs); + if (!fbconfigs) + goto error; + + /* Find out a GLXFBConfig compatible with the parent context */ + for (n = 0; n < n_fbconfigs; n++) { + status = glXGetFBConfigAttrib( + parent->display, + fbconfigs[n], + GLX_FBCONFIG_ID, &val + ); + if (status == Success && val == fbconfig_id) + break; + } + if (n == n_fbconfigs) + goto error; + } + else { + choose_fbconfig: + fbconfigs = glXChooseFBConfig( + cs->display, + screen, + fbconfig_attrs, &n_fbconfigs + ); + if (!fbconfigs) + goto error; + + /* Select the first one */ + n = 0; + } + + cs->visual = glXGetVisualFromFBConfig(cs->display, fbconfigs[n]); + cs->context = glXCreateNewContext( + cs->display, + fbconfigs[n], + GLX_RGBA_TYPE, + parent ? parent->context : NULL, + True + ); + if (cs->context) + goto end; + +error: + gl_destroy_context(cs); + cs = NULL; +end: + if (fbconfigs) + XFree(fbconfigs); + return cs; +} + +/** + * gl_destroy_context: + * @cs: a #GLContextState + * + * Destroys the GLX context @cs + */ +void +gl_destroy_context(GLContextState *cs) +{ + if (!cs) + return; + + if (cs->visual) { + XFree(cs->visual); + cs->visual = NULL; + } + + if (cs->display && cs->context) { + if (glXGetCurrentContext() == cs->context) { + /* XXX: if buffers were never swapped, the application + will crash later with the NVIDIA driver */ + if (!cs->swapped_buffers) + gl_swap_buffers(cs); + glXMakeCurrent(cs->display, None, NULL); + } + glXDestroyContext(cs->display, cs->context); + cs->display = NULL; + cs->context = NULL; + } + free(cs); +} + +/** + * gl_get_current_context: + * @cs: return location to the current #GLContextState + * + * Retrieves the current GLX context, display and drawable packed into + * the #GLContextState struct. + */ +void +gl_get_current_context(GLContextState *cs) +{ + cs->display = glXGetCurrentDisplay(); + cs->window = glXGetCurrentDrawable(); + cs->context = glXGetCurrentContext(); +} + +/** + * gl_set_current_context: + * @new_cs: the requested new #GLContextState + * @old_cs: return location to the context that was previously current + * + * Makes the @new_cs GLX context the current GLX rendering context of + * the calling thread, replacing the previously current context if + * there was one. + * + * If @old_cs is non %NULL, the previously current GLX context and + * window are recorded. + * + * Return value: %TRUE on success + */ +gboolean +gl_set_current_context(GLContextState *new_cs, GLContextState *old_cs) +{ + /* If display is NULL, this could be that new_cs was retrieved from + gl_get_current_context() with none set previously. If that case, + the other fields are also NULL and we don't return an error */ + if (!new_cs->display) + return !new_cs->window && !new_cs->context; + + if (old_cs) { + if (old_cs == new_cs) + return TRUE; + gl_get_current_context(old_cs); + if (old_cs->display == new_cs->display && + old_cs->window == new_cs->window && + old_cs->context == new_cs->context) + return TRUE; + } + return glXMakeCurrent(new_cs->display, new_cs->window, new_cs->context); +} + +/** + * gl_swap_buffers: + * @cs: a #GLContextState + * + * Promotes the contents of the back buffer of the @win window to + * become the contents of the front buffer. This simply is wrapper + * around glXSwapBuffers(). + */ +void +gl_swap_buffers(GLContextState *cs) +{ + glXSwapBuffers(cs->display, cs->window); + cs->swapped_buffers = TRUE; +} + +/** + * gl_bind_texture: + * @ts: a #GLTextureState + * @target: the target to which the texture is bound + * @texture: the name of a texture + * + * Binds @texture to the specified @target, while recording the + * previous state in @ts. + * + * Return value: %TRUE on success + */ +gboolean +gl_bind_texture(GLTextureState *ts, GLenum target, GLuint texture) +{ + GLenum binding; + + ts->target = target; + + if (glIsEnabled(target)) { + binding = gl_get_texture_binding(target); + if (!binding) + return FALSE; + if (!gl_get_param(binding, &ts->old_texture)) + return FALSE; + ts->was_enabled = TRUE; + ts->was_bound = texture == ts->old_texture; + if (ts->was_bound) + return TRUE; + } + else { + glEnable(target); + ts->old_texture = 0; + ts->was_enabled = FALSE; + ts->was_bound = FALSE; + } + + gl_purge_errors(); + glBindTexture(target, texture); + if (gl_check_error()) + return FALSE; + return TRUE; +} + +/** + * gl_unbind_texture: + * @ts: a #GLTextureState + * + * Rebinds the texture that was previously bound and recorded in @ts. + */ +void +gl_unbind_texture(GLTextureState *ts) +{ + if (!ts->was_bound && ts->old_texture) + glBindTexture(ts->target, ts->old_texture); + if (!ts->was_enabled) + glDisable(ts->target); +} + +/** + * gl_create_texture: + * @target: the target to which the texture is bound + * @format: the format of the pixel data + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Creates a texture with the specified dimensions and @format. The + * internal format will be automatically derived from @format. + * + * Return value: the newly created texture name + */ +GLuint +gl_create_texture(GLenum target, GLenum format, guint width, guint height) +{ + GLenum internal_format; + GLuint texture; + GLTextureState ts; + guint bytes_per_component; + + internal_format = format; + switch (format) { + case GL_LUMINANCE: + bytes_per_component = 1; + break; + case GL_LUMINANCE_ALPHA: + bytes_per_component = 2; + break; + case GL_RGBA: + case GL_BGRA: + internal_format = GL_RGBA; + bytes_per_component = 4; + break; + default: + bytes_per_component = 0; + break; + } + g_assert(bytes_per_component > 0); + + glGenTextures(1, &texture); + if (!gl_bind_texture(&ts, target, texture)) + return 0; + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glPixelStorei(GL_UNPACK_ALIGNMENT, bytes_per_component); + glTexImage2D( + target, + 0, + internal_format, + width, height, + 0, + format, + GL_UNSIGNED_BYTE, + NULL + ); + gl_unbind_texture(&ts); + return texture; +} + +/** + * get_proc_address: + * @name: the name of the OpenGL extension function to lookup + * + * Returns the specified OpenGL extension function + * + * Return value: the OpenGL extension matching @name, or %NULL if none + * was found + */ +typedef void (*GLFuncPtr)(void); +typedef GLFuncPtr (*GLXGetProcAddressProc)(const char *); + +static GLFuncPtr +get_proc_address_default(const char *name) +{ + return NULL; +} + +static GLXGetProcAddressProc +get_proc_address_func(void) +{ + GLXGetProcAddressProc get_proc_func; + + dlerror(); + get_proc_func = (GLXGetProcAddressProc) + dlsym(RTLD_DEFAULT, "glXGetProcAddress"); + if (!dlerror()) + return get_proc_func; + + get_proc_func = (GLXGetProcAddressProc) + dlsym(RTLD_DEFAULT, "glXGetProcAddressARB"); + if (!dlerror()) + return get_proc_func; + + return get_proc_address_default; +} + +static inline GLFuncPtr +get_proc_address(const char *name) +{ + static GLXGetProcAddressProc get_proc_func = NULL; + if (!get_proc_func) + get_proc_func = get_proc_address_func(); + return get_proc_func(name); +} + +/** + * gl_init_vtable: + * + * Initializes the global #GLVTable. + * + * Return value: the #GLVTable filled in with OpenGL extensions, or + * %NULL on error. + */ +static GLVTable gl_vtable_static; + +static GLVTable * +gl_init_vtable(void) +{ + GLVTable * const gl_vtable = &gl_vtable_static; + const gchar *gl_extensions = (const gchar *)glGetString(GL_EXTENSIONS); + gboolean has_extension; + + /* GLX_EXT_texture_from_pixmap */ + gl_vtable->glx_create_pixmap = (PFNGLXCREATEPIXMAPPROC) + get_proc_address("glXCreatePixmap"); + if (!gl_vtable->glx_create_pixmap) + return NULL; + gl_vtable->glx_destroy_pixmap = (PFNGLXDESTROYPIXMAPPROC) + get_proc_address("glXDestroyPixmap"); + if (!gl_vtable->glx_destroy_pixmap) + return NULL; + gl_vtable->glx_bind_tex_image = (PFNGLXBINDTEXIMAGEEXTPROC) + get_proc_address("glXBindTexImageEXT"); + if (!gl_vtable->glx_bind_tex_image) + return NULL; + gl_vtable->glx_release_tex_image = (PFNGLXRELEASETEXIMAGEEXTPROC) + get_proc_address("glXReleaseTexImageEXT"); + if (!gl_vtable->glx_release_tex_image) + return NULL; + + /* GL_ARB_framebuffer_object */ + has_extension = ( + find_string("GL_ARB_framebuffer_object", gl_extensions, " ") || + find_string("GL_EXT_framebuffer_object", gl_extensions, " ") + ); + if (has_extension) { + gl_vtable->gl_gen_framebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC) + get_proc_address("glGenFramebuffersEXT"); + if (!gl_vtable->gl_gen_framebuffers) + return NULL; + gl_vtable->gl_delete_framebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC) + get_proc_address("glDeleteFramebuffersEXT"); + if (!gl_vtable->gl_delete_framebuffers) + return NULL; + gl_vtable->gl_bind_framebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC) + get_proc_address("glBindFramebufferEXT"); + if (!gl_vtable->gl_bind_framebuffer) + return NULL; + gl_vtable->gl_gen_renderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC) + get_proc_address("glGenRenderbuffersEXT"); + if (!gl_vtable->gl_gen_renderbuffers) + return NULL; + gl_vtable->gl_delete_renderbuffers = (PFNGLDELETERENDERBUFFERSEXTPROC) + get_proc_address("glDeleteRenderbuffersEXT"); + if (!gl_vtable->gl_delete_renderbuffers) + return NULL; + gl_vtable->gl_bind_renderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC) + get_proc_address("glBindRenderbufferEXT"); + if (!gl_vtable->gl_bind_renderbuffer) + return NULL; + gl_vtable->gl_renderbuffer_storage = (PFNGLRENDERBUFFERSTORAGEEXTPROC) + get_proc_address("glRenderbufferStorageEXT"); + if (!gl_vtable->gl_renderbuffer_storage) + return NULL; + gl_vtable->gl_framebuffer_renderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) + get_proc_address("glFramebufferRenderbufferEXT"); + if (!gl_vtable->gl_framebuffer_renderbuffer) + return NULL; + gl_vtable->gl_framebuffer_texture_2d = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) + get_proc_address("glFramebufferTexture2DEXT"); + if (!gl_vtable->gl_framebuffer_texture_2d) + return NULL; + gl_vtable->gl_check_framebuffer_status = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) + get_proc_address("glCheckFramebufferStatusEXT"); + if (!gl_vtable->gl_check_framebuffer_status) + return NULL; + gl_vtable->has_framebuffer_object = TRUE; + } + + /* GL_ARB_fragment_program */ + has_extension = ( + find_string("GL_ARB_fragment_program", gl_extensions, " ") + ); + if (has_extension) { + gl_vtable->gl_gen_programs = (PFNGLGENPROGRAMSARBPROC) + get_proc_address("glGenProgramsARB"); + if (!gl_vtable->gl_gen_programs) + return NULL; + gl_vtable->gl_delete_programs = (PFNGLDELETEPROGRAMSARBPROC) + get_proc_address("glDeleteProgramsARB"); + if (!gl_vtable->gl_delete_programs) + return NULL; + gl_vtable->gl_bind_program = (PFNGLBINDPROGRAMARBPROC) + get_proc_address("glBindProgramARB"); + if (!gl_vtable->gl_bind_program) + return NULL; + gl_vtable->gl_program_string = (PFNGLPROGRAMSTRINGARBPROC) + get_proc_address("glProgramStringARB"); + if (!gl_vtable->gl_program_string) + return NULL; + gl_vtable->gl_get_program_iv = (PFNGLGETPROGRAMIVARBPROC) + get_proc_address("glGetProgramivARB"); + if (!gl_vtable->gl_get_program_iv) + return NULL; + gl_vtable->gl_program_local_parameter_4fv = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) + get_proc_address("glProgramLocalParameter4fvARB"); + if (!gl_vtable->gl_program_local_parameter_4fv) + return NULL; + gl_vtable->has_fragment_program = TRUE; + } + + /* GL_ARB_multitexture */ + has_extension = ( + find_string("GL_ARB_multitexture", gl_extensions, " ") + ); + if (has_extension) { + gl_vtable->gl_active_texture = (PFNGLACTIVETEXTUREPROC) + get_proc_address("glActiveTextureARB"); + if (!gl_vtable->gl_active_texture) + return NULL; + gl_vtable->gl_multi_tex_coord_2f = (PFNGLMULTITEXCOORD2FPROC) + get_proc_address("glMultiTexCoord2fARB"); + if (!gl_vtable->gl_multi_tex_coord_2f) + return NULL; + gl_vtable->has_multitexture = TRUE; + } + return gl_vtable; +} + +/** + * gl_get_vtable: + * + * Retrieves a VTable for OpenGL extensions. + * + * Return value: VTable for OpenGL extensions + */ +GLVTable * +gl_get_vtable(void) +{ + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + static gboolean gl_vtable_init = TRUE; + static GLVTable *gl_vtable = NULL; + + g_static_mutex_lock(&mutex); + if (gl_vtable_init) { + gl_vtable_init = FALSE; + gl_vtable = gl_init_vtable(); + } + g_static_mutex_unlock(&mutex); + return gl_vtable; +} + +/** + * gl_create_pixmap_object: + * @dpy: an X11 #Display + * @width: the request width, in pixels + * @height: the request height, in pixels + * + * Creates a #GLPixmapObject of the specified dimensions. This + * requires the GLX_EXT_texture_from_pixmap extension. + * + * Return value: the newly created #GLPixmapObject object + */ +GLPixmapObject * +gl_create_pixmap_object(Display *dpy, guint width, guint height) +{ + GLVTable * const gl_vtable = gl_get_vtable(); + GLPixmapObject *pixo; + GLXFBConfig *fbconfig; + int screen; + Window rootwin; + XWindowAttributes wattr; + int *attr; + int n_fbconfig_attrs; + + int fbconfig_attrs[32] = { + GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, + GLX_DOUBLEBUFFER, GL_FALSE, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_X_RENDERABLE, GL_TRUE, + GLX_Y_INVERTED_EXT, GL_TRUE, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GL_NONE, + }; + + int pixmap_attrs[10] = { + GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, + GLX_MIPMAP_TEXTURE_EXT, GL_FALSE, + GL_NONE, + }; + + if (!gl_vtable) + return NULL; + + screen = DefaultScreen(dpy); + rootwin = RootWindow(dpy, screen); + + /* XXX: this won't work for different displays */ + if (!gl_vtable->has_texture_from_pixmap) { + const char *glx_extensions = glXQueryExtensionsString(dpy, screen); + if (!glx_extensions) + return NULL; + if (!find_string("GLX_EXT_texture_from_pixmap", glx_extensions, " ")) + return NULL; + gl_vtable->has_texture_from_pixmap = TRUE; + } + + pixo = calloc(1, sizeof(*pixo)); + if (!pixo) + return NULL; + + pixo->dpy = dpy; + pixo->width = width; + pixo->height = height; + pixo->pixmap = None; + pixo->glx_pixmap = None; + pixo->is_bound = FALSE; + + XGetWindowAttributes(dpy, rootwin, &wattr); + pixo->pixmap = XCreatePixmap(dpy, rootwin, width, height, wattr.depth); + if (!pixo->pixmap) + goto error; + + /* Initialize FBConfig attributes */ + for (attr = fbconfig_attrs; *attr != GL_NONE; attr += 2) + ; + *attr++ = GLX_DEPTH_SIZE; *attr++ = wattr.depth; + if (wattr.depth == 32) { + *attr++ = GLX_ALPHA_SIZE; *attr++ = 8; + *attr++ = GLX_BIND_TO_TEXTURE_RGBA_EXT; *attr++ = GL_TRUE; + } + else { + *attr++ = GLX_BIND_TO_TEXTURE_RGB_EXT; *attr++ = GL_TRUE; + } + *attr++ = GL_NONE; + + fbconfig = glXChooseFBConfig( + dpy, + screen, + fbconfig_attrs, &n_fbconfig_attrs + ); + if (!fbconfig) + goto error; + + /* Initialize GLX Pixmap attributes */ + for (attr = pixmap_attrs; *attr != GL_NONE; attr += 2) + ; + *attr++ = GLX_TEXTURE_FORMAT_EXT; + if (wattr.depth == 32) + *attr++ = GLX_TEXTURE_FORMAT_RGBA_EXT; + else + *attr++ = GLX_TEXTURE_FORMAT_RGB_EXT; + *attr++ = GL_NONE; + + x11_trap_errors(); + pixo->glx_pixmap = gl_vtable->glx_create_pixmap( + dpy, + fbconfig[0], + pixo->pixmap, + pixmap_attrs + ); + free(fbconfig); + if (x11_untrap_errors() != 0) + goto error; + + pixo->target = GL_TEXTURE_2D; + glGenTextures(1, &pixo->texture); + if (!gl_bind_texture(&pixo->old_texture, pixo->target, pixo->texture)) + goto error; + glTexParameteri(pixo->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(pixo->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl_unbind_texture(&pixo->old_texture); + return pixo; + +error: + gl_destroy_pixmap_object(pixo); + return NULL; +} + +/** + * gl_destroy_pixmap_object: + * @pixo: a #GLPixmapObject + * + * Destroys the #GLPixmapObject object. + */ +void +gl_destroy_pixmap_object(GLPixmapObject *pixo) +{ + GLVTable * const gl_vtable = gl_get_vtable(); + + if (!pixo) + return; + + gl_unbind_pixmap_object(pixo); + + if (pixo->texture) { + glDeleteTextures(1, &pixo->texture); + pixo->texture = 0; + } + + if (pixo->glx_pixmap) { + gl_vtable->glx_destroy_pixmap(pixo->dpy, pixo->glx_pixmap); + pixo->glx_pixmap = None; + } + + if (pixo->pixmap) { + XFreePixmap(pixo->dpy, pixo->pixmap); + pixo->pixmap = None; + } + free(pixo); +} + +/** + * gl_bind_pixmap_object: + * @pixo: a #GLPixmapObject + * + * Defines a two-dimensional texture image. The texture image is taken + * from the @pixo pixmap and need not be copied. The texture target, + * format and size are derived from attributes of the @pixo pixmap. + * + * Return value: %TRUE on success + */ +gboolean +gl_bind_pixmap_object(GLPixmapObject *pixo) +{ + GLVTable * const gl_vtable = gl_get_vtable(); + + if (pixo->is_bound) + return TRUE; + + if (!gl_bind_texture(&pixo->old_texture, pixo->target, pixo->texture)) + return FALSE; + + x11_trap_errors(); + gl_vtable->glx_bind_tex_image( + pixo->dpy, + pixo->glx_pixmap, + GLX_FRONT_LEFT_EXT, + NULL + ); + XSync(pixo->dpy, False); + if (x11_untrap_errors() != 0) { + GST_DEBUG("failed to bind pixmap"); + return FALSE; + } + + pixo->is_bound = TRUE; + return TRUE; +} + +/** + * gl_unbind_pixmap_object: + * @pixo: a #GLPixmapObject + * + * Releases a color buffers that is being used as a texture. + * + * Return value: %TRUE on success + */ +gboolean +gl_unbind_pixmap_object(GLPixmapObject *pixo) +{ + GLVTable * const gl_vtable = gl_get_vtable(); + + if (!pixo->is_bound) + return TRUE; + + x11_trap_errors(); + gl_vtable->glx_release_tex_image( + pixo->dpy, + pixo->glx_pixmap, + GLX_FRONT_LEFT_EXT + ); + XSync(pixo->dpy, False); + if (x11_untrap_errors() != 0) { + GST_DEBUG("failed to release pixmap"); + return FALSE; + } + + gl_unbind_texture(&pixo->old_texture); + + pixo->is_bound = FALSE; + return TRUE; +} + +/** + * gl_create_framebuffer_object: + * @target: the target to which the texture is bound + * @texture: the GL texture to hold the framebuffer + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Creates an FBO with the specified texture and size. + * + * Return value: the newly created #GLFramebufferObject, or %NULL if + * an error occurred + */ +GLFramebufferObject * +gl_create_framebuffer_object( + GLenum target, + GLuint texture, + guint width, + guint height +) +{ + GLVTable * const gl_vtable = gl_get_vtable(); + GLFramebufferObject *fbo; + GLenum status; + + if (!gl_vtable || !gl_vtable->has_framebuffer_object) + return NULL; + + /* XXX: we only support GL_TEXTURE_2D at this time */ + if (target != GL_TEXTURE_2D) + return NULL; + + fbo = calloc(1, sizeof(*fbo)); + if (!fbo) + return NULL; + + fbo->width = width; + fbo->height = height; + fbo->fbo = 0; + fbo->old_fbo = 0; + fbo->is_bound = FALSE; + + gl_get_param(GL_FRAMEBUFFER_BINDING, &fbo->old_fbo); + gl_vtable->gl_gen_framebuffers(1, &fbo->fbo); + gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo->fbo); + gl_vtable->gl_framebuffer_texture_2d( + GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + target, texture, + 0 + ); + + status = gl_vtable->gl_check_framebuffer_status(GL_DRAW_FRAMEBUFFER_EXT); + gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo->old_fbo); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + goto error; + return fbo; + +error: + gl_destroy_framebuffer_object(fbo); + return NULL; +} + +/** + * gl_destroy_framebuffer_object: + * @fbo: a #GLFramebufferObject + * + * Destroys the @fbo object. + */ +void +gl_destroy_framebuffer_object(GLFramebufferObject *fbo) +{ + GLVTable * const gl_vtable = gl_get_vtable(); + + if (!fbo) + return; + + gl_unbind_framebuffer_object(fbo); + + if (fbo->fbo) { + gl_vtable->gl_delete_framebuffers(1, &fbo->fbo); + fbo->fbo = 0; + } + free(fbo); +} + +/** + * gl_bind_framebuffer_object: + * @fbo: a #GLFramebufferObject + * + * Binds @fbo object. + * + * Return value: %TRUE on success + */ +gboolean +gl_bind_framebuffer_object(GLFramebufferObject *fbo) +{ + GLVTable * const gl_vtable = gl_get_vtable(); + const guint width = fbo->width; + const guint height = fbo->height; + + const guint attribs = (GL_VIEWPORT_BIT| + GL_CURRENT_BIT| + GL_ENABLE_BIT| + GL_TEXTURE_BIT| + GL_COLOR_BUFFER_BIT); + + if (fbo->is_bound) + return TRUE; + + gl_get_param(GL_FRAMEBUFFER_BINDING, &fbo->old_fbo); + gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo->fbo); + glPushAttrib(attribs); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glViewport(0, 0, width, height); + glTranslatef(-1.0f, -1.0f, 0.0f); + glScalef(2.0f / width, 2.0f / height, 1.0f); + + fbo->is_bound = TRUE; + return TRUE; +} + +/** + * gl_unbind_framebuffer_object: + * @fbo: a #GLFramebufferObject + * + * Releases @fbo object. + * + * Return value: %TRUE on success + */ +gboolean +gl_unbind_framebuffer_object(GLFramebufferObject *fbo) +{ + GLVTable * const gl_vtable = gl_get_vtable(); + + if (!fbo->is_bound) + return TRUE; + + glPopAttrib(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo->old_fbo); + + fbo->is_bound = FALSE; + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_glx.h b/gst-libs/gst/vaapi/gstvaapiutils_glx.h new file mode 100644 index 0000000..c9a4983 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_glx.h @@ -0,0 +1,218 @@ +/* + * gstvaapiutils_glx.h - GLX utilties + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_GLX_H +#define GST_VAAPI_UTILS_GLX_H + +#include "config.h" +#include +#include +#include +#include +#include + +#if GLX_GLXEXT_VERSION < 18 +typedef void (*PFNGLXBINDTEXIMAGEEXTPROC)(Display *, GLXDrawable, int, const int *); +typedef void (*PFNGLXRELEASETEXIMAGEEXTPROC)(Display *, GLXDrawable, int); +#endif + +#if GLX_GLXEXT_VERSION < 27 +/* XXX: this is not exactly that version but this is the only means to + make sure we have the correct with those signatures */ +typedef GLXPixmap (*PFNGLXCREATEPIXMAPPROC)(Display *, GLXFBConfig, Pixmap, const int *); +typedef void (*PFNGLXDESTROYPIXMAPPROC)(Display *, GLXPixmap); +#endif + +#ifndef GL_FRAMEBUFFER_BINDING +#define GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_EXT +#endif + +G_GNUC_INTERNAL +const char * +gl_get_error_string(GLenum error); + +G_GNUC_INTERNAL +void +gl_purge_errors(void); + +G_GNUC_INTERNAL +gboolean +gl_check_error(void); + +G_GNUC_INTERNAL +gboolean +gl_get_param(GLenum param, guint *pval); + +G_GNUC_INTERNAL +gboolean +gl_get_texture_param(GLenum target, GLenum param, guint *pval); + +G_GNUC_INTERNAL +void +gl_set_bgcolor(guint32 color); + +G_GNUC_INTERNAL +void +gl_resize(guint width, guint height); + +typedef struct _GLContextState GLContextState; +struct _GLContextState { + Display *display; + Window window; + XVisualInfo *visual; + GLXContext context; + guint swapped_buffers : 1; +}; + +G_GNUC_INTERNAL +GLContextState * +gl_create_context(Display *dpy, int screen, GLContextState *parent); + +G_GNUC_INTERNAL +void +gl_destroy_context(GLContextState *cs); + +G_GNUC_INTERNAL +void +gl_get_current_context(GLContextState *cs); + +G_GNUC_INTERNAL +gboolean +gl_set_current_context(GLContextState *new_cs, GLContextState *old_cs); + +G_GNUC_INTERNAL +void +gl_swap_buffers(GLContextState *cs); + +typedef struct _GLTextureState GLTextureState; +struct _GLTextureState { + GLenum target; + GLuint old_texture; + guint was_enabled : 1; + guint was_bound : 1; +}; + +G_GNUC_INTERNAL +gboolean +gl_bind_texture(GLTextureState *ts, GLenum target, GLuint texture); + +G_GNUC_INTERNAL +void +gl_unbind_texture(GLTextureState *ts); + +G_GNUC_INTERNAL +GLuint +gl_create_texture(GLenum target, GLenum format, guint width, guint height); + +typedef struct _GLVTable GLVTable; +struct _GLVTable { + PFNGLXCREATEPIXMAPPROC glx_create_pixmap; + PFNGLXDESTROYPIXMAPPROC glx_destroy_pixmap; + PFNGLXBINDTEXIMAGEEXTPROC glx_bind_tex_image; + PFNGLXRELEASETEXIMAGEEXTPROC glx_release_tex_image; + PFNGLGENFRAMEBUFFERSEXTPROC gl_gen_framebuffers; + PFNGLDELETEFRAMEBUFFERSEXTPROC gl_delete_framebuffers; + PFNGLBINDFRAMEBUFFEREXTPROC gl_bind_framebuffer; + PFNGLGENRENDERBUFFERSEXTPROC gl_gen_renderbuffers; + PFNGLDELETERENDERBUFFERSEXTPROC gl_delete_renderbuffers; + PFNGLBINDRENDERBUFFEREXTPROC gl_bind_renderbuffer; + PFNGLRENDERBUFFERSTORAGEEXTPROC gl_renderbuffer_storage; + PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC gl_framebuffer_renderbuffer; + PFNGLFRAMEBUFFERTEXTURE2DEXTPROC gl_framebuffer_texture_2d; + PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC gl_check_framebuffer_status; + PFNGLGENPROGRAMSARBPROC gl_gen_programs; + PFNGLDELETEPROGRAMSARBPROC gl_delete_programs; + PFNGLBINDPROGRAMARBPROC gl_bind_program; + PFNGLPROGRAMSTRINGARBPROC gl_program_string; + PFNGLGETPROGRAMIVARBPROC gl_get_program_iv; + PFNGLPROGRAMLOCALPARAMETER4FVARBPROC gl_program_local_parameter_4fv; + PFNGLACTIVETEXTUREPROC gl_active_texture; + PFNGLMULTITEXCOORD2FPROC gl_multi_tex_coord_2f; + guint has_texture_from_pixmap : 1; + guint has_framebuffer_object : 1; + guint has_fragment_program : 1; + guint has_multitexture : 1; +}; + +G_GNUC_INTERNAL +GLVTable * +gl_get_vtable(void); + +typedef struct _GLPixmapObject GLPixmapObject; +struct _GLPixmapObject { + Display *dpy; + GLenum target; + GLuint texture; + GLTextureState old_texture; + guint width; + guint height; + Pixmap pixmap; + GLXPixmap glx_pixmap; + guint is_bound : 1; +}; + +G_GNUC_INTERNAL +GLPixmapObject * +gl_create_pixmap_object(Display *dpy, guint width, guint height); + +G_GNUC_INTERNAL +void +gl_destroy_pixmap_object(GLPixmapObject *pixo); + +G_GNUC_INTERNAL +gboolean +gl_bind_pixmap_object(GLPixmapObject *pixo); + +G_GNUC_INTERNAL +gboolean +gl_unbind_pixmap_object(GLPixmapObject *pixo); + +typedef struct _GLFramebufferObject GLFramebufferObject; +struct _GLFramebufferObject { + guint width; + guint height; + GLuint fbo; + GLuint old_fbo; + guint is_bound : 1; +}; + +G_GNUC_INTERNAL +GLFramebufferObject * +gl_create_framebuffer_object( + GLenum target, + GLuint texture, + guint width, + guint height +); + +G_GNUC_INTERNAL +void +gl_destroy_framebuffer_object(GLFramebufferObject *fbo); + +G_GNUC_INTERNAL +gboolean +gl_bind_framebuffer_object(GLFramebufferObject *fbo); + +G_GNUC_INTERNAL +gboolean +gl_unbind_framebuffer_object(GLFramebufferObject *fbo); + +#endif /* GST_VAAPI_UTILS_GLX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_x11.c b/gst-libs/gst/vaapi/gstvaapiutils_x11.c new file mode 100644 index 0000000..abc58b8 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_x11.c @@ -0,0 +1,154 @@ +/* + * gstvaapiutils_x11.c - X11 utilties + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapiutils_x11.h" + +// X error trap +static int x11_error_code = 0; +static int (*old_error_handler)(Display *, XErrorEvent *); + +static int error_handler(Display *dpy, XErrorEvent *error) +{ + x11_error_code = error->error_code; + return 0; +} + +void x11_trap_errors(void) +{ + x11_error_code = 0; + old_error_handler = XSetErrorHandler(error_handler); +} + +int x11_untrap_errors(void) +{ + XSetErrorHandler(old_error_handler); + return x11_error_code; +} + +// X window management +static const int x11_event_mask = (KeyPressMask | + KeyReleaseMask | + ButtonPressMask | + ButtonReleaseMask | + PointerMotionMask | + EnterWindowMask | + ExposureMask | + StructureNotifyMask); + +/** + * x11_create_window: + * @dpy: an X11 #Display + * @w: the requested width, in pixels + * @h: the requested height, in pixels + * @vis: the request visual + * @cmap: the request colormap + * + * Creates a border-less window with the specified dimensions. If @vis + * is %NULL, the default visual for @display will be used. If @cmap is + * %None, no specific colormap will be bound to the window. Also note + * the default background color is black. + * + * Return value: the newly created X #Window. + */ +Window +x11_create_window(Display *dpy, guint w, guint h, Visual *vis, Colormap cmap) +{ + Window rootwin, win; + int screen, depth; + XSetWindowAttributes xswa; + unsigned long xswa_mask; + XWindowAttributes wattr; + unsigned long black_pixel; + + screen = DefaultScreen(dpy); + rootwin = RootWindow(dpy, screen); + black_pixel = BlackPixel(dpy, screen); + + if (!vis) + vis = DefaultVisual(dpy, screen); + + XGetWindowAttributes(dpy, rootwin, &wattr); + depth = wattr.depth; + if (depth != 15 && depth != 16 && depth != 24 && depth != 32) + depth = 24; + + xswa_mask = CWBorderPixel | CWBackPixel; + xswa.border_pixel = black_pixel; + xswa.background_pixel = black_pixel; + + if (cmap) { + xswa_mask |= CWColormap; + xswa.colormap = cmap; + } + + win = XCreateWindow( + dpy, + rootwin, + 0, 0, w, h, + 0, + depth, + InputOutput, + vis, + xswa_mask, &xswa + ); + if (!win) + return None; + + XSelectInput(dpy, win, x11_event_mask); + return win; +} + +gboolean +x11_get_geometry( + Display *dpy, + Drawable drawable, + gint *px, + gint *py, + guint *pwidth, + guint *pheight +) +{ + Window rootwin; + int x, y; + guint width, height, border_width, depth; + + x11_trap_errors(); + XGetGeometry( + dpy, + drawable, + &rootwin, + &x, &y, &width, &height, + &border_width, + &depth + ); + if (x11_untrap_errors()) + return FALSE; + + if (px) *px = x; + if (py) *py = y; + if (pwidth) *pwidth = width; + if (pheight) *pheight = height; + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_x11.h b/gst-libs/gst/vaapi/gstvaapiutils_x11.h new file mode 100644 index 0000000..090b403 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_x11.h @@ -0,0 +1,52 @@ +/* + * gstvaapiutils_x11.h - X11 utilties + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_UTILS_X11_H +#define GST_VAAPI_UTILS_X11_H + +#include "config.h" +#include +#include + +G_GNUC_INTERNAL +void +x11_trap_errors(void); + +G_GNUC_INTERNAL +int +x11_untrap_errors(void); + +G_GNUC_INTERNAL +Window +x11_create_window(Display *dpy, guint w, guint h, Visual *vis, Colormap cmap); + +G_GNUC_INTERNAL +gboolean +x11_get_geometry( + Display *dpy, + Drawable drawable, + gint *px, + gint *py, + guint *pwidth, + guint *pheight +); + +#endif /* GST_VAAPI_UTILS_X11_H */ diff --git a/gst-libs/gst/vaapi/gstvaapivalue.c b/gst-libs/gst/vaapi/gstvaapivalue.c new file mode 100644 index 0000000..9bd97c3 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivalue.c @@ -0,0 +1,241 @@ +/* + * gstvaapivalue.c - GValue implementations specific to VA-API + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapivalue + * @short_description: GValue implementations specific to VA-API + */ + +#include "sysdeps.h" +#include +#include "gstvaapivalue.h" + +static GTypeInfo gst_vaapi_type_info = { + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL, + NULL, +}; + +static GTypeFundamentalInfo gst_vaapi_type_finfo = { + 0 +}; + +#define GST_VAAPI_TYPE_DEFINE(type, name) \ +GType gst_vaapi_ ## type ## _get_type(void) \ +{ \ + static GType gst_vaapi_ ## type ## _type = 0; \ + \ + if (G_UNLIKELY(gst_vaapi_ ## type ## _type == 0)) { \ + gst_vaapi_type_info.value_table = \ + &gst_vaapi_ ## type ## _value_table; \ + gst_vaapi_ ## type ## _type = g_type_register_fundamental( \ + g_type_fundamental_next(), \ + name, \ + &gst_vaapi_type_info, \ + &gst_vaapi_type_finfo, \ + 0 \ + ); \ + } \ + return gst_vaapi_ ## type ## _type; \ +} + +/* --- GstVaapiID --- */ + +#if GST_VAAPI_TYPE_ID_SIZE == 4 +# define GST_VAAPI_VALUE_ID_(cvalue) ((cvalue).v_int) +# define GST_VAAPI_VALUE_ID_CFORMAT "i" +#elif GST_VAAPI_TYPE_ID_SIZE == 8 +# define GST_VAAPI_VALUE_ID_(cvalue) ((cvalue).v_int64) +# define GST_VAAPI_VALUE_ID_CFORMAT "q" +#else +# error "unsupported GstVaapiID size" +#endif +#define GST_VAAPI_VALUE_ID(value) GST_VAAPI_VALUE_ID_((value)->data[0]) + +static void +gst_vaapi_value_id_init(GValue *value) +{ + GST_VAAPI_VALUE_ID(value) = 0; +} + +static void +gst_vaapi_value_id_copy(const GValue *src_value, GValue *dst_value) +{ + GST_VAAPI_VALUE_ID(dst_value) = GST_VAAPI_VALUE_ID(src_value); +} + +static gchar * +gst_vaapi_value_id_collect( + GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags +) +{ + GST_VAAPI_VALUE_ID(value) = GST_VAAPI_VALUE_ID_(collect_values[0]); + + return NULL; +} + +static gchar * +gst_vaapi_value_id_lcopy( + const GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags +) +{ + GstVaapiID *id_p = collect_values[0].v_pointer; + + if (!id_p) + return g_strdup_printf("value location for `%s' passed as NULL", + G_VALUE_TYPE_NAME(value)); + + *id_p = GST_VAAPI_VALUE_ID(value); + return NULL; +} + +static const GTypeValueTable gst_vaapi_id_value_table = { + gst_vaapi_value_id_init, + NULL, + gst_vaapi_value_id_copy, + NULL, + GST_VAAPI_VALUE_ID_CFORMAT, + gst_vaapi_value_id_collect, + "p", + gst_vaapi_value_id_lcopy +}; + +GST_VAAPI_TYPE_DEFINE(id, "GstVaapiID"); + +/** + * gst_vaapi_value_get_id: + * @value: a GValue initialized to #GstVaapiID + * + * Gets the integer contained in @value. + * + * Return value: the integer contained in @value + */ +GstVaapiID +gst_vaapi_value_get_id(const GValue *value) +{ + g_return_val_if_fail(GST_VAAPI_VALUE_HOLDS_ID(value), 0); + + return GST_VAAPI_VALUE_ID(value); +} + +/** + * gst_vaapi_value_set_id: + * @value: a GValue initialized to #GstVaapiID + * @id: a #GstVaapiID + * + * Sets the integer contained in @id to @value. + */ +void +gst_vaapi_value_set_id(GValue *value, GstVaapiID id) +{ + g_return_if_fail(GST_VAAPI_VALUE_HOLDS_ID(value)); + + GST_VAAPI_VALUE_ID(value) = id; +} + +/* --- GstVaapiRenderMode --- */ + +GType +gst_vaapi_render_mode_get_type(void) +{ + static GType render_mode_type = 0; + + static const GEnumValue render_modes[] = { + { GST_VAAPI_RENDER_MODE_OVERLAY, + "Overlay render mode", "overlay" }, + { GST_VAAPI_RENDER_MODE_TEXTURE, + "Textured-blit render mode", "texture" }, + { 0, NULL, NULL } + }; + + if (!render_mode_type) { + render_mode_type = + g_enum_register_static("GstVaapiRenderMode", render_modes); + } + return render_mode_type; +} + +/* --- GstVaapiRotation --- */ + +GType +gst_vaapi_rotation_get_type(void) +{ + static GType g_type = 0; + + static const GEnumValue rotation_values[] = { + { GST_VAAPI_ROTATION_0, + "Unrotated mode", "0" }, + { GST_VAAPI_ROTATION_90, + "Rotated by 90°, clockwise", "90" }, + { GST_VAAPI_ROTATION_180, + "Rotated by 180°, clockwise", "180" }, + { GST_VAAPI_ROTATION_270, + "Rotated by 270°, clockwise", "270" }, + { 0, NULL, NULL }, + }; + + if (!g_type) + g_type = g_enum_register_static("GstVaapiRotation", rotation_values); + return g_type; +} + +/* --- GstVaapiRateControl --- */ + +GType +gst_vaapi_rate_control_get_type(void) +{ + static GType g_type = 0; + + static const GEnumValue rate_control_values[] = { + { GST_VAAPI_RATECONTROL_NONE, + "None rate control mode", "none" }, + { GST_VAAPI_RATECONTROL_CBR, + "Constant bitrate control mode", "cbr" }, + { GST_VAAPI_RATECONTROL_VBR, + "Variable bitrate control mode", "vbr" }, + { GST_VAAPI_RATECONTROL_VCM, + "Video conference mode", "vcm" }, + { GST_VAAPI_RATECONTROL_CQP, + "Constant QP mode", "cqp" }, + { GST_VAAPI_RATECONTROL_VBR_CONSTRAINED, + "Variable bitrate control with peak rate higher than average bitrate", + "vbr_constrain" }, + { 0, NULL, NULL }, + }; + + if (!g_type) + g_type = g_enum_register_static("GstVaapiRateControl", rate_control_values); + return g_type; + +} diff --git a/gst-libs/gst/vaapi/gstvaapivalue.h b/gst-libs/gst/vaapi/gstvaapivalue.h new file mode 100644 index 0000000..cb45ad0 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivalue.h @@ -0,0 +1,95 @@ +/* + * gstvaapivalue.h - GValue implementations specific to VA-API + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VALUE_H +#define GST_VAAPI_VALUE_H + +#include +#include + +G_BEGIN_DECLS + +/** + * GST_VAAPI_TYPE_ID: + * + * A #GValue type that represents a VA identifier. + * + * Return value: the #GType of GstVaapiID + */ +#define GST_VAAPI_TYPE_ID gst_vaapi_id_get_type() + +/** + * GST_VAAPI_VALUE_HOLDS_ID: + * @x: the #GValue to check + * + * Checks if the given #GValue contains a #GstVaapiID value. + */ +#define GST_VAAPI_VALUE_HOLDS_ID(x) (G_VALUE_HOLDS((x), GST_VAAPI_TYPE_ID)) + +/** + * GST_VAAPI_TYPE_RENDER_MODE: + * + * A #GstVaapiRenderMode type that represents the VA display backend + * rendering mode: overlay (2D engine) or textured-blit (3D engine). + * + * Return value: the #GType of GstVaapiRenderMode + */ +#define GST_VAAPI_TYPE_RENDER_MODE gst_vaapi_render_mode_get_type() + +/** + * GST_VAAPI_TYPE_ROTATION: + * + * A type that represents the VA display rotation. + * + * Return value: the #GType of GstVaapiRotation + */ +#define GST_VAAPI_TYPE_ROTATION gst_vaapi_rotation_get_type() + +/** + * GST_VAAPI_TYPE_RATE_CONTROL: + * + * A type that represents the VA rate control. + * + * Return value: the #GType of GstVaapiRateControl + */ +#define GST_VAAPI_TYPE_RATE_CONTROL gst_vaapi_rate_control_get_type() + +GType +gst_vaapi_id_get_type(void) G_GNUC_CONST; + +GstVaapiID +gst_vaapi_value_get_id(const GValue *value); + +void +gst_vaapi_value_set_id(GValue *value, GstVaapiID id); + +GType +gst_vaapi_render_mode_get_type(void) G_GNUC_CONST; + +GType +gst_vaapi_rotation_get_type(void) G_GNUC_CONST; + +GType +gst_vaapi_rate_control_get_type(void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* GST_VAAPI_VALUE_H */ diff --git a/gst-libs/gst/vaapi/gstvaapivideobuffer.c b/gst-libs/gst/vaapi/gstvaapivideobuffer.c new file mode 100644 index 0000000..488d473 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideobuffer.c @@ -0,0 +1,665 @@ +/* + * gstvaapivideobuffer.c - Gst VA video buffer + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapivideobuffer + * @short_description: VA video buffer for GStreamer + */ + +#include "sysdeps.h" +#include "gstvaapivideobuffer.h" +#include "gstvaapivideobuffer_priv.h" +#include "gstvaapiimagepool.h" +#include "gstvaapisurfacepool.h" +#include "gstvaapiobject_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiVideoBuffer, gst_vaapi_video_buffer, GST_TYPE_SURFACE_BUFFER); + +#define GST_VAAPI_VIDEO_BUFFER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_VIDEO_BUFFER, \ + GstVaapiVideoBufferPrivate)) + +struct _GstVaapiVideoBufferPrivate { + GstVaapiDisplay *display; + GstVaapiVideoPool *image_pool; + GstVaapiImage *image; + GstVaapiVideoPool *surface_pool; + GstVaapiSurface *surface; + GstVaapiSurfaceProxy *proxy; + GstBuffer *buffer; + guint render_flags; +}; + +static void +set_display(GstVaapiVideoBuffer *buffer, GstVaapiDisplay *display) +{ + GstVaapiVideoBufferPrivate * const priv = buffer->priv; + + g_clear_object(&priv->display); + + if (display) + priv->display = g_object_ref(display); +} + +static inline void +set_image(GstVaapiVideoBuffer *buffer, GstVaapiImage *image) +{ + buffer->priv->image = g_object_ref(image); + set_display(buffer, GST_VAAPI_OBJECT_DISPLAY(image)); +} + +static inline void +set_surface(GstVaapiVideoBuffer *buffer, GstVaapiSurface *surface) +{ + buffer->priv->surface = g_object_ref(surface); + set_display(buffer, GST_VAAPI_OBJECT_DISPLAY(surface)); +} + +static void +gst_vaapi_video_buffer_destroy_image(GstVaapiVideoBuffer *buffer) +{ + GstVaapiVideoBufferPrivate * const priv = buffer->priv; + + if (priv->image) { + if (priv->image_pool) + gst_vaapi_video_pool_put_object(priv->image_pool, priv->image); + g_object_unref(priv->image); + priv->image = NULL; + } + + g_clear_object(&priv->image_pool); +} + +static void +gst_vaapi_video_buffer_destroy_surface(GstVaapiVideoBuffer *buffer) +{ + GstVaapiVideoBufferPrivate * const priv = buffer->priv; + + g_clear_object(&priv->proxy); + + if (priv->surface) { + if (priv->surface_pool) + gst_vaapi_video_pool_put_object(priv->surface_pool, priv->surface); + g_object_unref(priv->surface); + priv->surface = NULL; + } + + g_clear_object(&priv->surface_pool); + + if (priv->buffer) { + gst_buffer_unref(priv->buffer); + priv->buffer = NULL; + } +} + +static void +gst_vaapi_video_buffer_finalize(GstMiniObject *object) +{ + GstVaapiVideoBuffer * const buffer = GST_VAAPI_VIDEO_BUFFER(object); + GstMiniObjectClass *parent_class; + + gst_vaapi_video_buffer_destroy_image(buffer); + gst_vaapi_video_buffer_destroy_surface(buffer); + + set_display(buffer, NULL); + + parent_class = GST_MINI_OBJECT_CLASS(gst_vaapi_video_buffer_parent_class); + if (parent_class->finalize) + parent_class->finalize(object); +} + +static void +gst_vaapi_video_buffer_class_init(GstVaapiVideoBufferClass *klass) +{ + GstMiniObjectClass * const object_class = GST_MINI_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiVideoBufferPrivate)); + + object_class->finalize = gst_vaapi_video_buffer_finalize; +} + +static void +gst_vaapi_video_buffer_init(GstVaapiVideoBuffer *buffer) +{ + GstVaapiVideoBufferPrivate *priv; + + priv = GST_VAAPI_VIDEO_BUFFER_GET_PRIVATE(buffer); + buffer->priv = priv; + priv->display = NULL; + priv->image_pool = NULL; + priv->image = NULL; + priv->surface_pool = NULL; + priv->surface = NULL; + priv->proxy = NULL; + priv->buffer = NULL; + priv->render_flags = 0; +} + +static inline gboolean +gst_vaapi_video_buffer_is_a(GstBuffer *buffer, GType type) +{ + return G_TYPE_CHECK_INSTANCE_TYPE(buffer, type); +} + +static inline gpointer +_gst_vaapi_video_buffer_typed_new(GType type) +{ + g_return_val_if_fail(g_type_is_a(type, GST_VAAPI_TYPE_VIDEO_BUFFER), NULL); + + return gst_mini_object_new(type); +} + +/** + * gst_vaapi_video_buffer_typed_new: + * @display: a #GstVaapiDisplay + * + * Creates an empty #GstBuffer. The caller is responsible for completing + * the initialization of the buffer with the gst_vaapi_video_buffer_set_*() + * functions. + * + * This function shall only be called from within gstreamer-vaapi + * plugin elements. + * + * Return value: the newly allocated #GstBuffer, or %NULL or error + */ +GstBuffer * +gst_vaapi_video_buffer_typed_new(GType type, GstVaapiDisplay *display) +{ + GstBuffer *buffer; + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + + buffer = _gst_vaapi_video_buffer_typed_new(type); + if (!buffer) + return NULL; + + set_display(GST_VAAPI_VIDEO_BUFFER(buffer), display); + return buffer; +} + +/** + * gst_vaapi_video_buffer_typed_new_from_pool: + * @pool: a #GstVaapiVideoPool + * + * Creates a #GstBuffer with a video object allocated from a @pool. + * Only #GstVaapiSurfacePool and #GstVaapiImagePool pools are supported. + * + * The buffer is destroyed through the last call to gst_buffer_unref() + * and the video objects are pushed back to their respective pools. + * + * Return value: the newly allocated #GstBuffer, or %NULL on error + */ +GstBuffer * +gst_vaapi_video_buffer_typed_new_from_pool(GType type, GstVaapiVideoPool *pool) +{ + GstVaapiVideoBuffer *buffer; + gboolean is_image_pool, is_surface_pool; + + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), NULL); + + is_image_pool = GST_VAAPI_IS_IMAGE_POOL(pool); + is_surface_pool = GST_VAAPI_IS_SURFACE_POOL(pool); + + if (!is_image_pool && !is_surface_pool) + return NULL; + + buffer = _gst_vaapi_video_buffer_typed_new(type); + if (buffer && + ((is_image_pool && + gst_vaapi_video_buffer_set_image_from_pool(buffer, pool)) || + (is_surface_pool && + gst_vaapi_video_buffer_set_surface_from_pool(buffer, pool)))) { + set_display(buffer, gst_vaapi_video_pool_get_display(pool)); + return GST_BUFFER(buffer); + } + + gst_mini_object_unref(GST_MINI_OBJECT(buffer)); + return NULL; +} + +/** + * gst_vaapi_video_buffer_typed_new_from_buffer: + * @buffer: a #GstBuffer + * + * Creates a #GstBuffer with video objects bound to @buffer video + * objects, if any. + * + * This function shall only be called from within gstreamer-vaapi + * plugin elements. + * + * Return value: the newly allocated #GstBuffer, or %NULL on error + */ +GstBuffer * +gst_vaapi_video_buffer_typed_new_from_buffer(GType type, GstBuffer *buffer) +{ + GstVaapiVideoBuffer *inbuf, *outbuf; + + if (!gst_vaapi_video_buffer_is_a(buffer, type)) { + if (!buffer->parent || + !gst_vaapi_video_buffer_is_a(buffer->parent, type)) + return NULL; + buffer = buffer->parent; + } + inbuf = GST_VAAPI_VIDEO_BUFFER(buffer); + + outbuf = _gst_vaapi_video_buffer_typed_new(type); + if (!outbuf) + return NULL; + + if (inbuf->priv->image) + gst_vaapi_video_buffer_set_image(outbuf, inbuf->priv->image); + if (inbuf->priv->surface) + gst_vaapi_video_buffer_set_surface(outbuf, inbuf->priv->surface); + if (inbuf->priv->proxy) + gst_vaapi_video_buffer_set_surface_proxy(outbuf, inbuf->priv->proxy); + + outbuf->priv->buffer = gst_buffer_ref(buffer); + return GST_BUFFER(outbuf); +} + +/** + * gst_vaapi_video_buffer_typed_new_with_image: + * @image: a #GstVaapiImage + * + * Creates a #GstBuffer with the specified @image. The resulting + * buffer holds an additional reference to the @image. + * + * This function shall only be called from within gstreamer-vaapi + * plugin elements. + * + * Return value: the newly allocated #GstBuffer, or %NULL on error + */ +GstBuffer * +gst_vaapi_video_buffer_typed_new_with_image(GType type, GstVaapiImage *image) +{ + GstVaapiVideoBuffer *buffer; + + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL); + + buffer = _gst_vaapi_video_buffer_typed_new(type); + if (buffer) + gst_vaapi_video_buffer_set_image(buffer, image); + return GST_BUFFER(buffer); +} + +/** + * gst_vaapi_video_buffer_typed_new_with_surface: + * @surface: a #GstVaapiSurface + * + * Creates a #GstBuffer with the specified @surface. The resulting + * buffer holds an additional reference to the @surface. + * + * This function shall only be called from within gstreamer-vaapi + * plugin elements. + * + * Return value: the newly allocated #GstBuffer, or %NULL on error + */ +GstBuffer * +gst_vaapi_video_buffer_typed_new_with_surface( + GType type, + GstVaapiSurface *surface +) +{ + GstVaapiVideoBuffer *buffer; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL); + + buffer = _gst_vaapi_video_buffer_typed_new(type); + if (buffer) + gst_vaapi_video_buffer_set_surface(buffer, surface); + return GST_BUFFER(buffer); +} + +/** + * gst_vaapi_video_buffer_typed_new_with_surface_proxy: + * @proxy: a #GstVaapiSurfaceProxy + * + * Creates a #GstBuffer with the specified surface @proxy. The + * resulting buffer holds an additional reference to the @proxy. + * + * This function shall only be called from within gstreamer-vaapi + * plugin elements. + * + * Return value: the newly allocated #GstBuffer, or %NULL on error + */ +GstBuffer * +gst_vaapi_video_buffer_typed_new_with_surface_proxy( + GType type, + GstVaapiSurfaceProxy *proxy +) +{ + GstVaapiVideoBuffer *buffer; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), NULL); + + buffer = _gst_vaapi_video_buffer_typed_new(type); + if (buffer) + gst_vaapi_video_buffer_set_surface_proxy(buffer, proxy); + return GST_BUFFER(buffer); +} + +/** + * gst_vaapi_video_buffer_get_display: + * @buffer: a #GstVaapiVideoBuffer + * + * Retrieves the #GstVaapiDisplay the @buffer is bound to. The @buffer + * owns the returned #GstVaapiDisplay object so the caller is + * responsible for calling g_object_ref() when needed. + * + * Return value: the #GstVaapiDisplay the @buffer is bound to + */ +GstVaapiDisplay * +gst_vaapi_video_buffer_get_display(GstVaapiVideoBuffer *buffer) +{ + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), NULL); + + return buffer->priv->display; +} + +/** + * gst_vaapi_video_buffer_get_image: + * @buffer: a #GstVaapiVideoBuffer + * + * Retrieves the #GstVaapiImage bound to the @buffer. The @buffer owns + * the #GstVaapiImage so the caller is responsible for calling + * g_object_ref() when needed. + * + * Return value: the #GstVaapiImage bound to the @buffer, or %NULL if + * there is none + */ +GstVaapiImage * +gst_vaapi_video_buffer_get_image(GstVaapiVideoBuffer *buffer) +{ + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), NULL); + + return buffer->priv->image; +} + +/** + * gst_vaapi_video_buffer_set_image: + * @buffer: a #GstVaapiVideoBuffer + * @image: a #GstVaapiImage + * + * Binds @image to the @buffer. If the @buffer contains another image + * previously allocated from a pool, it's pushed back to its parent + * pool and the pool is also released. + */ +void +gst_vaapi_video_buffer_set_image( + GstVaapiVideoBuffer *buffer, + GstVaapiImage *image +) +{ + g_return_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer)); + g_return_if_fail(GST_VAAPI_IS_IMAGE(image)); + + gst_vaapi_video_buffer_destroy_image(buffer); + + if (image) + set_image(buffer, image); +} + +/** + * gst_vaapi_video_buffer_set_image_from_pool + * @buffer: a #GstVaapiVideoBuffer + * @pool: a #GstVaapiVideoPool + * + * Binds a newly allocated video object from the @pool. The @pool + * shall be of type #GstVaapiImagePool. Previously allocated objects + * are released and returned to their parent pools, if any. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_video_buffer_set_image_from_pool( + GstVaapiVideoBuffer *buffer, + GstVaapiVideoPool *pool +) +{ + GstVaapiImage *image; + + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), FALSE); + g_return_val_if_fail(GST_VAAPI_IS_IMAGE_POOL(pool), FALSE); + + gst_vaapi_video_buffer_destroy_image(buffer); + + if (pool) { + image = gst_vaapi_video_pool_get_object(pool); + if (!image) + return FALSE; + set_image(buffer, image); + buffer->priv->image_pool = g_object_ref(pool); + } + return TRUE; +} + +/** + * gst_vaapi_video_buffer_get_surface: + * @buffer: a #GstVaapiVideoBuffer + * + * Retrieves the #GstVaapiSurface bound to the @buffer. The @buffer + * owns the #GstVaapiSurface so the caller is responsible for calling + * g_object_ref() when needed. + * + * Return value: the #GstVaapiSurface bound to the @buffer, or %NULL if + * there is none + */ +GstVaapiSurface * +gst_vaapi_video_buffer_get_surface(GstVaapiVideoBuffer *buffer) +{ + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), NULL); + + return buffer->priv->surface; +} + +/** + * gst_vaapi_video_buffer_set_surface: + * @buffer: a #GstVaapiVideoBuffer + * @surface: a #GstVaapiSurface + * + * Binds @surface to the @buffer. If the @buffer contains another + * surface previously allocated from a pool, it's pushed back to its + * parent pool and the pool is also released. + */ +void +gst_vaapi_video_buffer_set_surface( + GstVaapiVideoBuffer *buffer, + GstVaapiSurface *surface +) +{ + g_return_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer)); + g_return_if_fail(GST_VAAPI_IS_SURFACE(surface)); + + gst_vaapi_video_buffer_destroy_surface(buffer); + + if (surface) + set_surface(buffer, surface); +} + +/** + * gst_vaapi_video_buffer_set_surface_from_pool + * @buffer: a #GstVaapiVideoBuffer + * @pool: a #GstVaapiVideoPool + * + * Binds a newly allocated video object from the @pool. The @pool + * shall be of type #GstVaapiSurfacePool. Previously allocated objects + * are released and returned to their parent pools, if any. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_video_buffer_set_surface_from_pool( + GstVaapiVideoBuffer *buffer, + GstVaapiVideoPool *pool +) +{ + GstVaapiSurface *surface; + + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), FALSE); + g_return_val_if_fail(GST_VAAPI_IS_SURFACE_POOL(pool), FALSE); + + gst_vaapi_video_buffer_destroy_surface(buffer); + + if (pool) { + surface = gst_vaapi_video_pool_get_object(pool); + if (!surface) + return FALSE; + set_surface(buffer, surface); + buffer->priv->surface_pool = g_object_ref(pool); + } + return TRUE; +} + +/** + * gst_vaapi_video_buffer_get_surface_proxy: + * @buffer: a #GstVaapiVideoBuffer + * + * Retrieves the #GstVaapiSurfaceProxy bound to the @buffer. The @buffer + * owns the #GstVaapiSurfaceProxy so the caller is responsible for calling + * g_object_ref() when needed. + * + * Return value: the #GstVaapiSurfaceProxy bound to the @buffer, or + * %NULL if there is none + */ +GstVaapiSurfaceProxy * +gst_vaapi_video_buffer_get_surface_proxy(GstVaapiVideoBuffer *buffer) +{ + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), NULL); + + return buffer->priv->proxy; +} + +/** + * gst_vaapi_video_buffer_set_surface_proxy: + * @buffer: a #GstVaapiVideoBuffer + * @proxy: a #GstVaapiSurfaceProxy + * + * Binds surface @proxy to the @buffer. If the @buffer contains another + * surface previously allocated from a pool, it's pushed back to its + * parent pool and the pool is also released. + */ +void +gst_vaapi_video_buffer_set_surface_proxy( + GstVaapiVideoBuffer *buffer, + GstVaapiSurfaceProxy *proxy +) +{ + GstVaapiSurface *surface; + + g_return_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer)); + g_return_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy)); + + gst_vaapi_video_buffer_destroy_surface(buffer); + + if (proxy) { + surface = GST_VAAPI_SURFACE_PROXY_SURFACE(proxy); + if (!surface) + return; + set_surface(buffer, surface); + buffer->priv->proxy = g_object_ref(proxy); + } +} + +/** + * gst_vaapi_video_buffer_get_render_flags: + * @buffer: a #GstVaapiVideoBuffer + * + * Retrieves the surface render flags bound to the @buffer. + * + * Return value: a combination for #GstVaapiSurfaceRenderFlags + */ +guint +gst_vaapi_video_buffer_get_render_flags(GstVaapiVideoBuffer *buffer) +{ + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), 0); + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(buffer->priv->surface), 0); + + return buffer->priv->render_flags; +} + +/** + * gst_vaapi_video_buffer_set_render_flags: + * @buffer: a #GstVaapiVideoBuffer + * @flags: a set of surface render flags + * + * Sets #GstVaapiSurfaceRenderFlags to the @buffer. + */ +void +gst_vaapi_video_buffer_set_render_flags(GstVaapiVideoBuffer *buffer, guint flags) +{ + g_return_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer)); + g_return_if_fail(GST_VAAPI_IS_SURFACE(buffer->priv->surface)); + + buffer->priv->render_flags = flags; +} + +/** + * gst_vaapi_video_buffer_ensure_pointer: + * @buffer: a #GstVaapiVideoBuffer + * + * Maps image data buffer to #GstBuffer of @buffer. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_video_buffer_ensure_pointer(GstVaapiVideoBuffer *buffer) +{ + GstVaapiVideoBufferPrivate * const priv = buffer->priv; + GstVaapiImage *image = NULL; + gboolean is_image_derived = FALSE; + gboolean ret = FALSE; + + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), FALSE); + g_return_val_if_fail (priv->image || priv->surface, FALSE); + + if (!priv->image) { + image = gst_vaapi_surface_derive_image(priv->surface); + g_return_val_if_fail(image, FALSE); + is_image_derived = TRUE; + } else { + image = priv->image; + is_image_derived = FALSE; + } + + if (!gst_vaapi_image_map(image)) + goto end; + + if(!gst_vaapi_image_ensure_mapped_buffer(image)) + goto end; + + GST_BUFFER_DATA(buffer) = gst_vaapi_image_get_plane(image, 0); + GST_BUFFER_SIZE(buffer) = gst_vaapi_image_get_data_size(image); + + if (!gst_vaapi_image_unmap(image)) + goto end; + + ret = TRUE; + +end: + if (image && is_image_derived) + g_object_unref(image); + return ret; +} diff --git a/gst-libs/gst/vaapi/gstvaapivideobuffer.h b/gst-libs/gst/vaapi/gstvaapivideobuffer.h new file mode 100644 index 0000000..0161240 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideobuffer.h @@ -0,0 +1,141 @@ +/* + * gstvaapivideobuffer.h - Gstreamer/VA video buffer + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_BUFFER_H +#define GST_VAAPI_VIDEO_BUFFER_H + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_VIDEO_BUFFER \ + (gst_vaapi_video_buffer_get_type()) + +#define GST_VAAPI_VIDEO_BUFFER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_VIDEO_BUFFER, \ + GstVaapiVideoBuffer)) + +#define GST_VAAPI_VIDEO_BUFFER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_VIDEO_BUFFER, \ + GstVaapiVideoBufferClass)) + +#define GST_VAAPI_IS_VIDEO_BUFFER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_VIDEO_BUFFER)) + +#define GST_VAAPI_IS_VIDEO_BUFFER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_VIDEO_BUFFER)) + +#define GST_VAAPI_VIDEO_BUFFER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_VIDEO_BUFFER, \ + GstVaapiVideoBufferClass)) + +typedef struct _GstVaapiVideoBuffer GstVaapiVideoBuffer; +typedef struct _GstVaapiVideoBufferPrivate GstVaapiVideoBufferPrivate; +typedef struct _GstVaapiVideoBufferClass GstVaapiVideoBufferClass; + +/** + * GstVaapiVideoBuffer: + * + * A #GstBuffer holding video objects (#GstVaapiSurface and #GstVaapiImage). + */ +struct _GstVaapiVideoBuffer { + /*< private >*/ + GstSurfaceBuffer parent_instance; + + GstVaapiVideoBufferPrivate *priv; +}; + +/** + * GstVaapiVideoBufferClass: + * + * A #GstBuffer holding video objects + */ +struct _GstVaapiVideoBufferClass { + /*< private >*/ + GstSurfaceBufferClass parent_class; +}; + +GType +gst_vaapi_video_buffer_get_type(void) G_GNUC_CONST; + +GstVaapiDisplay * +gst_vaapi_video_buffer_get_display(GstVaapiVideoBuffer *buffer); + +GstVaapiImage * +gst_vaapi_video_buffer_get_image(GstVaapiVideoBuffer *buffer); + +void +gst_vaapi_video_buffer_set_image( + GstVaapiVideoBuffer *buffer, + GstVaapiImage *image +); + +gboolean +gst_vaapi_video_buffer_set_image_from_pool( + GstVaapiVideoBuffer *buffer, + GstVaapiVideoPool *pool +); + +GstVaapiSurface * +gst_vaapi_video_buffer_get_surface(GstVaapiVideoBuffer *buffer); + +void +gst_vaapi_video_buffer_set_surface( + GstVaapiVideoBuffer *buffer, + GstVaapiSurface *surface +); + +gboolean +gst_vaapi_video_buffer_set_surface_from_pool( + GstVaapiVideoBuffer *buffer, + GstVaapiVideoPool *pool +); + +GstVaapiSurfaceProxy * +gst_vaapi_video_buffer_get_surface_proxy(GstVaapiVideoBuffer *buffer); + +void +gst_vaapi_video_buffer_set_surface_proxy( + GstVaapiVideoBuffer *buffer, + GstVaapiSurfaceProxy *proxy +); + +guint +gst_vaapi_video_buffer_get_render_flags(GstVaapiVideoBuffer *buffer); + +void +gst_vaapi_video_buffer_set_render_flags(GstVaapiVideoBuffer *buffer, guint flags); + +gboolean +gst_vaapi_video_buffer_ensure_pointer(GstVaapiVideoBuffer *buffer); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_BUFFER_H */ diff --git a/gst-libs/gst/vaapi/gstvaapivideobuffer_glx.c b/gst-libs/gst/vaapi/gstvaapivideobuffer_glx.c new file mode 100644 index 0000000..c531f79 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideobuffer_glx.c @@ -0,0 +1,55 @@ +/* + * gstvaapivideobuffer_glx.c - Gst VA video buffer + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Collabora Ltd. + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapivideobufferglx + * @short_description: VA video buffer for GStreamer with GLX support + */ + +#include "sysdeps.h" +#include "gstvaapivideobuffer_glx.h" +#include "gstvaapivideoconverter_glx.h" +#include "gstvaapivideopool.h" +#include "gstvaapivideobuffer_priv.h" +#include "gstvaapidisplay_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiVideoBufferGLX, + gst_vaapi_video_buffer_glx, + GST_VAAPI_TYPE_VIDEO_BUFFER); + +static void +gst_vaapi_video_buffer_glx_class_init(GstVaapiVideoBufferGLXClass *klass) +{ + GstSurfaceBufferClass * const surface_class = + GST_SURFACE_BUFFER_CLASS(klass); + + surface_class->create_converter = gst_vaapi_video_converter_glx_new; +} + +static void +gst_vaapi_video_buffer_glx_init(GstVaapiVideoBufferGLX *buffer) +{ +} diff --git a/gst-libs/gst/vaapi/gstvaapivideobuffer_glx.h b/gst-libs/gst/vaapi/gstvaapivideobuffer_glx.h new file mode 100644 index 0000000..0dbe065 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideobuffer_glx.h @@ -0,0 +1,85 @@ +/* + * gstvaapivideobuffer_glx.h - Gstreamer/VA video buffer + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Collabora Ltd. + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_BUFFER_GLX_H +#define GST_VAAPI_VIDEO_BUFFER_GLX_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_VIDEO_BUFFER_GLX \ + (gst_vaapi_video_buffer_glx_get_type()) + +#define GST_VAAPI_VIDEO_BUFFER_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_VIDEO_BUFFER_GLX, \ + GstVaapiVideoBufferGLX)) + +#define GST_VAAPI_VIDEO_BUFFER_GLX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_VIDEO_BUFFER_GLX, \ + GstVaapiVideoBufferGLXClass)) + +#define GST_VAAPI_IS_VIDEO_BUFFER_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_VIDEO_BUFFER_GLX)) + +#define GST_VAAPI_IS_VIDEO_BUFFER_GLX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_VIDEO_BUFFER_GLX)) + +#define GST_VAAPI_VIDEO_BUFFER_GLX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_VIDEO_BUFFER_GLX, \ + GstVaapiVideoBufferGLXClass)) + +typedef struct _GstVaapiVideoBufferGLX GstVaapiVideoBufferGLX; +typedef struct _GstVaapiVideoBufferGLXClass GstVaapiVideoBufferGLXClass; + +/** + * GstVaapiVideoBufferGLX: + * + * A #GstBuffer holding video objects (#GstVaapiSurface and #GstVaapiImage). + */ +struct _GstVaapiVideoBufferGLX { + /*< private >*/ + GstVaapiVideoBuffer parent_instance; +}; + +/** + * GstVaapiVideoBufferGLXClass: + * + * A #GstBuffer holding video objects + */ +struct _GstVaapiVideoBufferGLXClass { + /*< private >*/ + GstVaapiVideoBufferClass parent_class; +}; + +GType gst_vaapi_video_buffer_glx_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_BUFFER_GLX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapivideobuffer_priv.h b/gst-libs/gst/vaapi/gstvaapivideobuffer_priv.h new file mode 100644 index 0000000..a08edbd --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideobuffer_priv.h @@ -0,0 +1,59 @@ +/* + * gstvaapivideobuffer_priv.h - Gstreamer/VA video buffer (private interface) + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Collabora Ltd. + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_BUFFER_PRIV_H +#define GST_VAAPI_VIDEO_BUFFER_PRIV_H + +#include + +G_BEGIN_DECLS + +/* Private API for gstreamer-vaapi plugin elements only */ + +GstBuffer * +gst_vaapi_video_buffer_typed_new(GType type, GstVaapiDisplay *display); + +GstBuffer * +gst_vaapi_video_buffer_typed_new_from_pool(GType type, GstVaapiVideoPool *pool); + +GstBuffer * +gst_vaapi_video_buffer_typed_new_from_buffer(GType type, GstBuffer *buffer); + +GstBuffer * +gst_vaapi_video_buffer_typed_new_with_image(GType type, GstVaapiImage *image); + +GstBuffer * +gst_vaapi_video_buffer_typed_new_with_surface( + GType type, + GstVaapiSurface *surface +); + +GstBuffer * +gst_vaapi_video_buffer_typed_new_with_surface_proxy( + GType type, + GstVaapiSurfaceProxy *proxy +); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_BUFFER_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c b/gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c new file mode 100644 index 0000000..0ea968f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideoconverter_glx.c @@ -0,0 +1,143 @@ +/* + * gstvaapivideoconverter_glx.c - Gst VA video converter + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Collabora Ltd. + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include +#include "gstvaapivideoconverter_glx.h" +#include "gstvaapivideobuffer.h" +#include "gstvaapitexture.h" + +static void gst_vaapi_video_converter_glx_iface_init (GstSurfaceConverterInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GstVaapiVideoConverterGLX, gst_vaapi_video_converter_glx, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GST_TYPE_SURFACE_CONVERTER, + gst_vaapi_video_converter_glx_iface_init)); + +struct _GstVaapiVideoConverterGLXPrivate { + GstVaapiTexture *texture; +}; + +static void +gst_vaapi_video_converter_glx_dispose(GObject *object) +{ + GstVaapiVideoConverterGLXPrivate *priv = + GST_VAAPI_VIDEO_CONVERTER_GLX (object)->priv; + + g_clear_object(&priv->texture); + + G_OBJECT_CLASS (gst_vaapi_video_converter_glx_parent_class)->dispose (object); +} + +static void +gst_vaapi_video_converter_glx_class_init(GstVaapiVideoConverterGLXClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GstVaapiVideoConverterGLXPrivate)); + object_class->dispose = gst_vaapi_video_converter_glx_dispose; +} + +static void +gst_vaapi_video_converter_glx_init(GstVaapiVideoConverterGLX *buffer) +{ + buffer->priv = G_TYPE_INSTANCE_GET_PRIVATE(buffer, + GST_VAAPI_TYPE_VIDEO_CONVERTER, + GstVaapiVideoConverterGLXPrivate); +} + +static void +gst_vaapi_video_converter_glx_iface_init (GstSurfaceConverterInterface *iface) { + iface->upload = gst_vaapi_video_converter_glx_upload; +} + +/** + * gst_vaapi_video_converter_glx_new: + * @surface: the #GstSurfaceBuffer + * @type: type of the target buffer (must be "opengl") + * @dest: target of the conversion (must be GL texture id) + * + * Creates an empty #GstBuffer. The caller is responsible for + * completing the initialization of the buffer with the + * gst_vaapi_video_converter_glx_set_*() functions. + * + * Return value: the newly allocated #GstBuffer, or %NULL on error + */ +GstSurfaceConverter * +gst_vaapi_video_converter_glx_new(GstSurfaceBuffer *surface, const gchar *type, + GValue *dest) +{ + GstVaapiVideoBuffer *buffer = GST_VAAPI_VIDEO_BUFFER (surface); + GstVaapiDisplay *display = gst_vaapi_video_buffer_get_display (buffer); + GstVaapiTexture *texture; + GstVaapiVideoConverterGLX *converter = NULL; + + /* We only support Open GL texture conversion */ + if (strcmp(type, "opengl") || !G_VALUE_HOLDS_UINT (dest)) + return NULL; + + /* FIXME Should we assume target and format ? */ + texture = gst_vaapi_texture_new_with_texture (display, + g_value_get_uint (dest), + GL_TEXTURE_2D, + GL_BGRA); + + if (texture) { + converter = g_object_new (GST_VAAPI_TYPE_VIDEO_CONVERTER, NULL); + converter->priv->texture = texture; + } + + return GST_SURFACE_CONVERTER (converter); +} + +gboolean +gst_vaapi_video_converter_glx_upload (GstSurfaceConverter *converter, + GstSurfaceBuffer *buffer) +{ + GstVaapiVideoConverterGLXPrivate *priv = + GST_VAAPI_VIDEO_CONVERTER_GLX (converter)->priv; + GstVaapiVideoBuffer * const vbuffer = GST_VAAPI_VIDEO_BUFFER (buffer); + GstVaapiSurface *surface = gst_vaapi_video_buffer_get_surface (vbuffer); + GstVaapiDisplay *new_dpy, *old_dpy; + GstVideoOverlayComposition * const composition = + gst_video_buffer_get_overlay_composition (GST_BUFFER (buffer)); + + new_dpy = gst_vaapi_object_get_display (GST_VAAPI_OBJECT (surface)); + old_dpy = gst_vaapi_object_get_display (GST_VAAPI_OBJECT (priv->texture)); + + if (old_dpy != new_dpy) { + guint texture = gst_vaapi_texture_get_id (priv->texture); + g_object_unref (priv->texture); + priv->texture = gst_vaapi_texture_new_with_texture (new_dpy, + texture, + GL_TEXTURE_2D, + GL_BGRA); + } + + if (!gst_vaapi_surface_set_subpictures_from_composition (surface, + composition, TRUE)) + GST_WARNING ("could not update subtitles"); + + return gst_vaapi_texture_put_surface (priv->texture, surface, + gst_vaapi_video_buffer_get_render_flags (vbuffer)); +} diff --git a/gst-libs/gst/vaapi/gstvaapivideoconverter_glx.h b/gst-libs/gst/vaapi/gstvaapivideoconverter_glx.h new file mode 100644 index 0000000..0215444 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideoconverter_glx.h @@ -0,0 +1,75 @@ +/* + * gstvaapivideoconverter_glx.h - Gstreamer/VA video converter + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Collabora Ltd. + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_CONVERTER_GLX_H +#define GST_VAAPI_VIDEO_CONVERTER_GLX_H + +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_VIDEO_CONVERTER (gst_vaapi_video_converter_glx_get_type ()) +#define GST_VAAPI_VIDEO_CONVERTER_GLX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_VAAPI_TYPE_VIDEO_CONVERTER, GstVaapiVideoConverterGLX)) +#define GST_VAAPI_VIDEO_CONVERTER_GLX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_VAAPI_TYPE_VIDEO_CONVERTER, GstVaapiVideoConverterGLXClass)) +#define GST_VAAPI_IS_VIDEO_CONVERTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_VAAPI_TYPE_VIDEO_CONVERTER)) +#define GST_VAAPI_IS_VIDEO_CONVERTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_VAAPI_TYPE_VIDEO_CONVERTER)) +#define GST_VAAPI_VIDEO_CONVERTER_GLX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_VAAPI_TYPE_VIDEO_CONVERTER, GstVaapiVideoConverterGLXClass)) + +typedef struct _GstVaapiVideoConverterGLX GstVaapiVideoConverterGLX; +typedef struct _GstVaapiVideoConverterGLXPrivate GstVaapiVideoConverterGLXPrivate; +typedef struct _GstVaapiVideoConverterGLXClass GstVaapiVideoConverterGLXClass; + +/** + * GstVaapiVideoConverterGLX: + * + * Converter to transform VA buffers into GL textures. + */ +struct _GstVaapiVideoConverterGLX { + /*< private >*/ + GObject parent_instance; + + GstVaapiVideoConverterGLXPrivate *priv; +}; + +/** + * GstVaapiVideoConverterGLXClass: + * + * Converter to transform VA buffers into GL textures. + */ +struct _GstVaapiVideoConverterGLXClass { + /*< private >*/ + GObjectClass parent_class; +}; + +GType gst_vaapi_video_converter_glx_get_type (void) G_GNUC_CONST; + +GstSurfaceConverter *gst_vaapi_video_converter_glx_new (GstSurfaceBuffer *buffer, + const gchar *type, + GValue *dest); + +gboolean gst_vaapi_video_converter_glx_upload (GstSurfaceConverter *self, + GstSurfaceBuffer *buffer); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_CONVERTER_GLX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapivideopool.c b/gst-libs/gst/vaapi/gstvaapivideopool.c new file mode 100644 index 0000000..f05ba00 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideopool.c @@ -0,0 +1,516 @@ +/* + * gstvaapivideopool.c - Video object pool abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapivideopool + * @short_description: Video object pool abstraction + */ + +#include "sysdeps.h" +#include "gstvaapivideopool.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiVideoPool, gst_vaapi_video_pool, G_TYPE_OBJECT); + +#define GST_VAAPI_VIDEO_POOL_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_VIDEO_POOL, \ + GstVaapiVideoPoolPrivate)) + +#define VAAPI_VIDEO_POOL_LOCK(mutex) g_static_rec_mutex_lock(mutex) +#define VAAPI_VIDEO_POOL_UNLOCK(mutex) g_static_rec_mutex_unlock(mutex) + + +struct _GstVaapiVideoPoolPrivate { + GstVaapiDisplay *display; + GQueue free_objects; + GList *used_objects; + GstCaps *caps; + guint used_count; + guint capacity; + + GStaticRecMutex mutex; +}; + +enum { + PROP_0, + + PROP_DISPLAY, + PROP_CAPS, + PROP_CAPACITY +}; + +static void +gst_vaapi_video_pool_set_caps(GstVaapiVideoPool *pool, GstCaps *caps); + +static inline gpointer +gst_vaapi_video_pool_alloc_object(GstVaapiVideoPool *pool) +{ + GstVaapiVideoPoolClass * const klass = GST_VAAPI_VIDEO_POOL_GET_CLASS(pool); + + return klass->alloc_object(pool, pool->priv->display); +} + +static void +gst_vaapi_video_pool_clear(GstVaapiVideoPool *pool) +{ + GstVaapiVideoPoolPrivate * const priv = pool->priv; + gpointer object; + GList *list, *next; + + for (list = priv->used_objects; list; list = next) { + next = list->next; + g_object_unref(list->data); + g_list_free_1(list); + } + priv->used_objects = NULL; + + while ((object = g_queue_pop_head(&priv->free_objects))) + g_object_unref(object); +} + +static void +gst_vaapi_video_pool_destroy(GstVaapiVideoPool *pool) +{ + GstVaapiVideoPoolPrivate * const priv = pool->priv; + + gst_vaapi_video_pool_clear(pool); + + if (priv->caps) { + gst_caps_unref(priv->caps); + priv->caps = NULL; + } + + g_clear_object(&priv->display); +} + +static void +gst_vaapi_video_pool_finalize(GObject *object) +{ + gst_vaapi_video_pool_destroy(GST_VAAPI_VIDEO_POOL(object)); + + G_OBJECT_CLASS(gst_vaapi_video_pool_parent_class)->finalize(object); +} + +static void +gst_vaapi_video_pool_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiVideoPool * const pool = GST_VAAPI_VIDEO_POOL(object); + + switch (prop_id) { + case PROP_DISPLAY: + pool->priv->display = g_object_ref(g_value_get_object(value)); + break; + case PROP_CAPS: + gst_vaapi_video_pool_set_caps(pool, g_value_get_pointer(value)); + break; + case PROP_CAPACITY: + gst_vaapi_video_pool_set_capacity(pool, g_value_get_uint(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_video_pool_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiVideoPool * const pool = GST_VAAPI_VIDEO_POOL(object); + + switch (prop_id) { + case PROP_DISPLAY: + g_value_set_object(value, gst_vaapi_video_pool_get_display(pool)); + break; + case PROP_CAPS: + g_value_set_pointer(value, gst_vaapi_video_pool_get_caps(pool)); + break; + case PROP_CAPACITY: + g_value_set_uint(value, gst_vaapi_video_pool_get_capacity(pool)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_video_pool_class_init(GstVaapiVideoPoolClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiVideoPoolPrivate)); + + object_class->finalize = gst_vaapi_video_pool_finalize; + object_class->set_property = gst_vaapi_video_pool_set_property; + object_class->get_property = gst_vaapi_video_pool_get_property; + + /** + * GstVaapiVideoPool:display: + * + * The #GstVaapiDisplay this pool is bound to. + */ + g_object_class_install_property + (object_class, + PROP_DISPLAY, + g_param_spec_object("display", + "Display", + "The GstVaapiDisplay this pool is bound to", + GST_VAAPI_TYPE_DISPLAY, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + /** + * GstVaapiVidePool:caps: + * + * The video object capabilities represented as a #GstCaps. This + * shall hold at least the "width" and "height" properties. + */ + g_object_class_install_property + (object_class, + PROP_CAPS, + g_param_spec_pointer("caps", + "caps", + "The video object capabilities", + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + /** + * GstVaapiVidePool:capacity: + * + * The maximum number of objects in the pool. Or zero, the pool + * will allocate as many objects as possible. + */ + g_object_class_install_property + (object_class, + PROP_CAPACITY, + g_param_spec_uint("capacity", + "capacity", + "The maximum number of objects in the pool", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE)); +} + +static void +gst_vaapi_video_pool_init(GstVaapiVideoPool *pool) +{ + GstVaapiVideoPoolPrivate *priv = GST_VAAPI_VIDEO_POOL_GET_PRIVATE(pool); + + pool->priv = priv; + priv->display = NULL; + priv->used_objects = NULL; + priv->caps = NULL; + priv->used_count = 0; + priv->capacity = 0; + + g_queue_init(&priv->free_objects); + g_static_rec_mutex_init(&priv->mutex); +} + +/** + * gst_vaapi_video_pool_get_display: + * @pool: a #GstVaapiVideoPool + * + * Retrieves the #GstVaapiDisplay the @pool is bound to. The @pool + * owns the returned object and it shall not be unref'ed. + * + * Return value: the #GstVaapiDisplay the @pool is bound to + */ +GstVaapiDisplay * +gst_vaapi_video_pool_get_display(GstVaapiVideoPool *pool) +{ + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), NULL); + + return pool->priv->display; +} + +/** + * gst_vaapi_video_pool_get_caps: + * @pool: a #GstVaapiVideoPool + * + * Retrieves the #GstCaps the @pool was created with. The @pool owns + * the returned object and it shall not be unref'ed. + * + * Return value: the #GstCaps the @pool was created with + */ +GstCaps * +gst_vaapi_video_pool_get_caps(GstVaapiVideoPool *pool) +{ + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), NULL); + + return pool->priv->caps; +} + +/* + * gst_vaapi_video_pool_set_caps: + * @pool: a #GstVaapiVideoPool + * @caps: a #GstCaps + * + * Binds new @caps to the @pool and notify the sub-classes. + */ +void +gst_vaapi_video_pool_set_caps(GstVaapiVideoPool *pool, GstCaps *caps) +{ + GstVaapiVideoPoolClass * const klass = GST_VAAPI_VIDEO_POOL_GET_CLASS(pool); + + pool->priv->caps = gst_caps_ref(caps); + + if (klass->set_caps) + klass->set_caps(pool, caps); +} + +/** + * gst_vaapi_video_pool_get_object: + * @pool: a #GstVaapiVideoPool + * + * Retrieves a new object from the @pool, or allocates a new one if + * none was found. The @pool holds a reference on the returned object + * and thus shall be released through gst_vaapi_video_pool_put_object() + * when it's no longer needed. + * + * Return value: a possibly newly allocated object, or %NULL on error + */ +gpointer +gst_vaapi_video_pool_get_object(GstVaapiVideoPool *pool) +{ + GstVaapiVideoPoolPrivate *priv; + gpointer object = NULL; + + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), NULL); + + priv = pool->priv; + + VAAPI_VIDEO_POOL_LOCK(&priv->mutex); + if (priv->capacity && priv->used_count >= priv->capacity) + goto end; + + object = g_queue_pop_head(&priv->free_objects); + if (!object) { + VAAPI_VIDEO_POOL_UNLOCK(&priv->mutex); + object = gst_vaapi_video_pool_alloc_object(pool); + VAAPI_VIDEO_POOL_LOCK(&priv->mutex); + if (!object) + goto end; + } + + ++priv->used_count; + priv->used_objects = g_list_prepend(priv->used_objects, object); + g_object_ref(object); + + end: + VAAPI_VIDEO_POOL_UNLOCK(&priv->mutex); + return object; +} + +/** + * gst_vaapi_video_pool_put_object: + * @pool: a #GstVaapiVideoPool + * @object: the object to add back to the pool + * + * Pushes the @object back into the pool. The @object shall be + * obtained from the @pool through gst_vaapi_video_pool_get_object(). + * Calling this function with an arbitrary object yields undefined + * behaviour. + */ +void +gst_vaapi_video_pool_put_object(GstVaapiVideoPool *pool, gpointer object) +{ + GstVaapiVideoPoolPrivate *priv; + GList *elem; + + g_return_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool)); + g_return_if_fail(G_IS_OBJECT(object)); + + priv = pool->priv; + + VAAPI_VIDEO_POOL_LOCK(&priv->mutex); + elem = g_list_find(priv->used_objects, object); + if (!elem) + goto end; + + g_object_unref(object); + --priv->used_count; + priv->used_objects = g_list_delete_link(priv->used_objects, elem); + g_queue_push_tail(&priv->free_objects, object); + + end: + VAAPI_VIDEO_POOL_UNLOCK(&priv->mutex); +} + +/** + * gst_vaapi_video_pool_add_object: + * @pool: a #GstVaapiVideoPool + * @object: the object to add to the pool + * + * Adds the @object to the pool. The pool then holds a reference on + * the @object. This operation does not change the capacity of the + * pool. + * + * Return value: %TRUE on success. + */ +gboolean +gst_vaapi_video_pool_add_object(GstVaapiVideoPool *pool, gpointer object) +{ + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), FALSE); + g_return_val_if_fail(G_IS_OBJECT(object), FALSE); + + VAAPI_VIDEO_POOL_LOCK(&pool->priv->mutex); + g_queue_push_tail(&pool->priv->free_objects, g_object_ref(object)); + VAAPI_VIDEO_POOL_UNLOCK(&pool->priv->mutex); + + return TRUE; +} + +/** + * gst_vaapi_video_pool_add_objects: + * @pool: a #GstVaapiVideoPool + * @objects: a #GPtrArray of objects + * + * Adds the @objects to the pool. The pool then holds a reference on + * the @objects. This operation does not change the capacity of the + * pool and is just a wrapper around gst_vaapi_video_pool_add_object(). + * + * Return value: %TRUE on success. + */ +gboolean +gst_vaapi_video_pool_add_objects(GstVaapiVideoPool *pool, GPtrArray *objects) +{ + guint i; + + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), FALSE); + + for (i = 0; i < objects->len; i++) { + gpointer const object = g_ptr_array_index(objects, i); + if (!gst_vaapi_video_pool_add_object(pool, object)) + return FALSE; + } + return TRUE; +} + +/** + * gst_vaapi_video_pool_get_size: + * @pool: a #GstVaapiVideoPool + * + * Returns the number of free objects available in the pool. + * + * Return value: number of free objects in the pool + */ +guint +gst_vaapi_video_pool_get_size(GstVaapiVideoPool *pool) +{ + guint size; + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), 0); + + + VAAPI_VIDEO_POOL_LOCK(&pool->priv->mutex); + size = g_queue_get_length(&pool->priv->free_objects); + VAAPI_VIDEO_POOL_UNLOCK(&pool->priv->mutex); + return size; +} + +/** + * gst_vaapi_video_pool_reserve: + * @pool: a #GstVaapiVideoPool + * @n: the number of objects to pre-allocate + * + * Pre-allocates up to @n objects in the pool. If @n is less than or + * equal to the number of free and used objects in the pool, this call + * has no effect. Otherwise, it is a request for allocation of + * additional objects. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_video_pool_reserve(GstVaapiVideoPool *pool, guint n) +{ + guint i, num_allocated; + gboolean ret = TRUE; + + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), 0); + + VAAPI_VIDEO_POOL_LOCK(&pool->priv->mutex); + + num_allocated = gst_vaapi_video_pool_get_size(pool) + pool->priv->used_count; + if (n < num_allocated) + goto end; + + if ((n -= num_allocated) > pool->priv->capacity) + n = pool->priv->capacity; + + for (i = num_allocated; i < n; i++) { + gpointer const object = gst_vaapi_video_pool_alloc_object(pool); + if (!object) { + ret = FALSE; + goto end; + } + g_queue_push_tail(&pool->priv->free_objects, object); + } + ret = TRUE; + end: + VAAPI_VIDEO_POOL_UNLOCK(&pool->priv->mutex); + return ret; +} + +/** + * gst_vaapi_video_pool_get_capacity: + * @pool: a #GstVaapiVideoPool + * + * Returns the maximum number of objects in the pool. i.e. the maximum + * number of objects that can be returned by gst_vaapi_video_pool_get_object(). + * + * Return value: the capacity of the pool + */ +guint +gst_vaapi_video_pool_get_capacity(GstVaapiVideoPool *pool) +{ + guint capacity; + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), 0); + VAAPI_VIDEO_POOL_LOCK(&pool->priv->mutex); + capacity = pool->priv->capacity; + VAAPI_VIDEO_POOL_UNLOCK(&pool->priv->mutex); + return capacity; +} + +/** + * gst_vaapi_video_pool_set_capacity: + * @pool: a #GstVaapiVideoPool + * @capacity: the maximal capacity of the pool + * + * Sets the maximum number of objects that can be allocated in the pool. + */ +void +gst_vaapi_video_pool_set_capacity(GstVaapiVideoPool *pool, guint capacity) +{ + g_return_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool)); + VAAPI_VIDEO_POOL_LOCK(&pool->priv->mutex); + pool->priv->capacity = capacity; + VAAPI_VIDEO_POOL_UNLOCK(&pool->priv->mutex); +} diff --git a/gst-libs/gst/vaapi/gstvaapivideopool.h b/gst-libs/gst/vaapi/gstvaapivideopool.h new file mode 100644 index 0000000..f2fdb5e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapivideopool.h @@ -0,0 +1,123 @@ +/* + * gstvaapivideopool.h - Video object pool abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_VIDEO_POOL_H +#define GST_VAAPI_VIDEO_POOL_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_VIDEO_POOL \ + (gst_vaapi_video_pool_get_type()) + +#define GST_VAAPI_VIDEO_POOL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_VIDEO_POOL, \ + GstVaapiVideoPool)) + +#define GST_VAAPI_VIDEO_POOL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_VIDEO_POOL, \ + GstVaapiVideoPoolClass)) + +#define GST_VAAPI_IS_VIDEO_POOL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_VIDEO_POOL)) + +#define GST_VAAPI_IS_VIDEO_POOL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_VIDEO_POOL)) + +#define GST_VAAPI_VIDEO_POOL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_VIDEO_POOL, \ + GstVaapiVideoPoolClass)) + +typedef struct _GstVaapiVideoPool GstVaapiVideoPool; +typedef struct _GstVaapiVideoPoolPrivate GstVaapiVideoPoolPrivate; +typedef struct _GstVaapiVideoPoolClass GstVaapiVideoPoolClass; + +/** + * GstVaapiVideoPool: + * + * A pool of lazily allocated video objects. e.g. surfaces, images. + */ +struct _GstVaapiVideoPool { + /*< private >*/ + GObject parent_instance; + + GstVaapiVideoPoolPrivate *priv; +}; + +/** + * GstVaapiVideoPoolClass: + * @set_caps: virtual function for notifying the subclass of the + * negotiated caps + * @alloc_object: virtual function for allocating a video pool object + * + * A pool base class used to hold video objects. e.g. surfaces, images. + */ +struct _GstVaapiVideoPoolClass { + /*< private >*/ + GObjectClass parent_class; + + /*< public >*/ + void (*set_caps) (GstVaapiVideoPool *pool, GstCaps *caps); + gpointer (*alloc_object)(GstVaapiVideoPool *pool, GstVaapiDisplay *display); +}; + +GType +gst_vaapi_video_pool_get_type(void) G_GNUC_CONST; + +GstVaapiDisplay * +gst_vaapi_video_pool_get_display(GstVaapiVideoPool *pool); + +GstCaps * +gst_vaapi_video_pool_get_caps(GstVaapiVideoPool *pool); + +gpointer +gst_vaapi_video_pool_get_object(GstVaapiVideoPool *pool); + +void +gst_vaapi_video_pool_put_object(GstVaapiVideoPool *pool, gpointer object); + +gboolean +gst_vaapi_video_pool_add_object(GstVaapiVideoPool *pool, gpointer object); + +gboolean +gst_vaapi_video_pool_add_objects(GstVaapiVideoPool *pool, GPtrArray *objects); + +guint +gst_vaapi_video_pool_get_size(GstVaapiVideoPool *pool); + +gboolean +gst_vaapi_video_pool_reserve(GstVaapiVideoPool *pool, guint n); + +guint +gst_vaapi_video_pool_get_capacity(GstVaapiVideoPool *pool); + +void +gst_vaapi_video_pool_set_capacity(GstVaapiVideoPool *pool, guint capacity); + +G_END_DECLS + +#endif /* GST_VAAPI_VIDEO_POOL_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow.c b/gst-libs/gst/vaapi/gstvaapiwindow.c new file mode 100644 index 0000000..56ef8ed --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow.c @@ -0,0 +1,512 @@ +/* + * gstvaapiwindow.c - VA window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiwindow + * @short_description: VA window abstraction + */ + +#include "sysdeps.h" +#include "gstvaapiwindow.h" +#include "gstvaapi_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiWindow, gst_vaapi_window, GST_VAAPI_TYPE_OBJECT); + +#define GST_VAAPI_WINDOW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_WINDOW, \ + GstVaapiWindowPrivate)) + +struct _GstVaapiWindowPrivate { + guint width; + guint height; + guint display_width; + guint display_height; + gboolean is_constructed : 1; + guint is_fullscreen : 1; + guint check_geometry : 1; +}; + +enum { + PROP_0, + + PROP_WIDTH, + PROP_HEIGHT, + PROP_FULLSCREEN +}; + +static void +gst_vaapi_window_ensure_size(GstVaapiWindow *window) +{ + GstVaapiWindowPrivate * const priv = window->priv; + GstVaapiWindowClass * const klass = GST_VAAPI_WINDOW_GET_CLASS(window); + + if (!priv->check_geometry) + return; + + if (klass->get_geometry) + klass->get_geometry(window, NULL, NULL, &priv->width, &priv->height); + + priv->check_geometry = FALSE; + priv->is_fullscreen = (priv->width == priv->display_width && + priv->height == priv->display_height); +} + +static void +gst_vaapi_window_destroy(GstVaapiWindow *window) +{ + GST_VAAPI_WINDOW_GET_CLASS(window)->destroy(window); +} + +static gboolean +gst_vaapi_window_create(GstVaapiWindow *window) +{ + GstVaapiWindowPrivate * const priv = window->priv; + guint width, height; + + width = priv->width; + height = priv->height; + + gst_vaapi_display_get_size( + GST_VAAPI_OBJECT_DISPLAY(window), + &priv->display_width, + &priv->display_height + ); + + if (!GST_VAAPI_WINDOW_GET_CLASS(window)->create(window, &width, &height)) + return FALSE; + + if (width != priv->width || height != priv->height) { + GST_DEBUG("backend resized window to %ux%u", width, height); + priv->width = width; + priv->height = height; + } + return TRUE; +} + +static void +gst_vaapi_window_finalize(GObject *object) +{ + gst_vaapi_window_destroy(GST_VAAPI_WINDOW(object)); + + G_OBJECT_CLASS(gst_vaapi_window_parent_class)->finalize(object); +} + +static void +gst_vaapi_window_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiWindow * const window = GST_VAAPI_WINDOW(object); + + switch (prop_id) { + case PROP_WIDTH: + gst_vaapi_window_set_width(window, g_value_get_uint(value)); + break; + case PROP_HEIGHT: + gst_vaapi_window_set_height(window, g_value_get_uint(value)); + break; + case PROP_FULLSCREEN: + gst_vaapi_window_set_fullscreen(window, g_value_get_boolean(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_window_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiWindow * const window = GST_VAAPI_WINDOW(object); + + switch (prop_id) { + case PROP_WIDTH: + g_value_set_uint(value, gst_vaapi_window_get_width(window)); + break; + case PROP_HEIGHT: + g_value_set_uint(value, gst_vaapi_window_get_height(window)); + break; + case PROP_FULLSCREEN: + g_value_set_boolean(value, window->priv->is_fullscreen); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_window_constructed(GObject *object) +{ + GstVaapiWindow * const window = GST_VAAPI_WINDOW(object); + GObjectClass *parent_class; + + window->priv->is_constructed = gst_vaapi_window_create(window); + + parent_class = G_OBJECT_CLASS(gst_vaapi_window_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static void +gst_vaapi_window_class_init(GstVaapiWindowClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiWindowPrivate)); + + object_class->finalize = gst_vaapi_window_finalize; + object_class->set_property = gst_vaapi_window_set_property; + object_class->get_property = gst_vaapi_window_get_property; + object_class->constructed = gst_vaapi_window_constructed; + + g_object_class_install_property + (object_class, + PROP_WIDTH, + g_param_spec_uint("width", + "Width", + "The window width", + 1, G_MAXUINT32, 1, + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, + PROP_HEIGHT, + g_param_spec_uint("height", + "height", + "The window height", + 1, G_MAXUINT32, 1, + G_PARAM_READWRITE)); + + g_object_class_install_property + (object_class, + PROP_FULLSCREEN, + g_param_spec_boolean("fullscreen", + "Fullscreen", + "The fullscreen state of the window", + FALSE, + G_PARAM_READWRITE)); +} + +static void +gst_vaapi_window_init(GstVaapiWindow *window) +{ + GstVaapiWindowPrivate *priv = GST_VAAPI_WINDOW_GET_PRIVATE(window); + + window->priv = priv; + priv->width = 1; + priv->height = 1; + priv->is_constructed = FALSE; + priv->is_fullscreen = FALSE; + priv->check_geometry = FALSE; +} + +/** + * gst_vaapi_window_get_display: + * @window: a #GstVaapiWindow + * + * Returns the #GstVaapiDisplay this @window is bound to. + * + * Return value: the parent #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_window_get_display(GstVaapiWindow *window) +{ + g_return_val_if_fail(GST_VAAPI_IS_WINDOW(window), NULL); + + return GST_VAAPI_OBJECT_DISPLAY(window); +} + +/** + * gst_vaapi_window_show: + * @window: a #GstVaapiWindow + * + * Flags a window to be displayed. Any window that is not shown will + * not appear on the screen. + */ +void +gst_vaapi_window_show(GstVaapiWindow *window) +{ + g_return_if_fail(GST_VAAPI_IS_WINDOW(window)); + g_return_if_fail(window->priv->is_constructed); + + GST_VAAPI_WINDOW_GET_CLASS(window)->show(window); + window->priv->check_geometry = TRUE; +} + +/** + * gst_vaapi_window_hide: + * @window: a #GstVaapiWindow + * + * Reverses the effects of gst_vaapi_window_show(), causing the window + * to be hidden (invisible to the user). + */ +void +gst_vaapi_window_hide(GstVaapiWindow *window) +{ + g_return_if_fail(GST_VAAPI_IS_WINDOW(window)); + g_return_if_fail(window->priv->is_constructed); + + GST_VAAPI_WINDOW_GET_CLASS(window)->hide(window); +} + +/** + * gst_vaapi_window_get_fullscreen: + * @window: a #GstVaapiWindow + * + * Retrieves whether the @window is fullscreen or not + * + * Return value: %TRUE if the window is fullscreen + */ +gboolean +gst_vaapi_window_get_fullscreen(GstVaapiWindow *window) +{ + g_return_val_if_fail(GST_VAAPI_IS_WINDOW(window), FALSE); + + gst_vaapi_window_ensure_size(window); + + return window->priv->is_fullscreen; +} + +/** + * gst_vaapi_window_set_fullscreen: + * @window: a #GstVaapiWindow + * @fullscreen: %TRUE to request window to get fullscreen + * + * Requests to place the @window in fullscreen or unfullscreen states. + */ +void +gst_vaapi_window_set_fullscreen(GstVaapiWindow *window, gboolean fullscreen) +{ + GstVaapiWindowClass *klass; + + g_return_if_fail(GST_VAAPI_IS_WINDOW(window)); + + klass = GST_VAAPI_WINDOW_GET_CLASS(window); + + if (window->priv->is_fullscreen != fullscreen && + klass->set_fullscreen && klass->set_fullscreen(window, fullscreen)) { + window->priv->is_fullscreen = fullscreen; + window->priv->check_geometry = TRUE; + } +} + +/** + * gst_vaapi_window_get_width: + * @window: a #GstVaapiWindow + * + * Retrieves the width of a #GstVaapiWindow. + * + * Return value: the width of the @window, in pixels + */ +guint +gst_vaapi_window_get_width(GstVaapiWindow *window) +{ + g_return_val_if_fail(GST_VAAPI_IS_WINDOW(window), 0); + g_return_val_if_fail(window->priv->is_constructed, 0); + + gst_vaapi_window_ensure_size(window); + + return window->priv->width; +} + +/** + * gst_vaapi_window_get_height: + * @window: a #GstVaapiWindow + * + * Retrieves the height of a #GstVaapiWindow + * + * Return value: the height of the @window, in pixels + */ +guint +gst_vaapi_window_get_height(GstVaapiWindow *window) +{ + g_return_val_if_fail(GST_VAAPI_IS_WINDOW(window), 0); + g_return_val_if_fail(window->priv->is_constructed, 0); + + gst_vaapi_window_ensure_size(window); + + return window->priv->height; +} + +/** + * gst_vaapi_window_get_size: + * @window: a #GstVaapiWindow + * @pwidth: return location for the width, or %NULL + * @pheight: return location for the height, or %NULL + * + * Retrieves the dimensions of a #GstVaapiWindow. + */ +void +gst_vaapi_window_get_size(GstVaapiWindow *window, guint *pwidth, guint *pheight) +{ + g_return_if_fail(GST_VAAPI_IS_WINDOW(window)); + g_return_if_fail(window->priv->is_constructed); + + gst_vaapi_window_ensure_size(window); + + if (pwidth) + *pwidth = window->priv->width; + + if (pheight) + *pheight = window->priv->height; +} + +/** + * gst_vaapi_window_set_width: + * @window: a #GstVaapiWindow + * @width: requested new width for the window, in pixels + * + * Resizes the @window to match the specified @width. + */ +void +gst_vaapi_window_set_width(GstVaapiWindow *window, guint width) +{ + g_return_if_fail(GST_VAAPI_IS_WINDOW(window)); + + gst_vaapi_window_set_size(window, width, window->priv->height); +} + +/** + * gst_vaapi_window_set_height: + * @window: a #GstVaapiWindow + * @height: requested new height for the window, in pixels + * + * Resizes the @window to match the specified @height. + */ +void +gst_vaapi_window_set_height(GstVaapiWindow *window, guint height) +{ + g_return_if_fail(GST_VAAPI_IS_WINDOW(window)); + + gst_vaapi_window_set_size(window, window->priv->width, height); +} + +/** + * gst_vaapi_window_set_size: + * @window: a #GstVaapiWindow + * @width: requested new width for the window, in pixels + * @height: requested new height for the window, in pixels + * + * Resizes the @window to match the specified @width and @height. + */ +void +gst_vaapi_window_set_size(GstVaapiWindow *window, guint width, guint height) +{ + g_return_if_fail(GST_VAAPI_IS_WINDOW(window)); + + if (width == window->priv->width && height == window->priv->height) + return; + + window->priv->width = width; + window->priv->height = height; + + if (window->priv->is_constructed) + GST_VAAPI_WINDOW_GET_CLASS(window)->resize(window, width, height); +} + +static inline void +get_surface_rect(GstVaapiSurface *surface, GstVaapiRectangle *rect) +{ + guint width, height; + + gst_vaapi_surface_get_size(surface, &width, &height); + rect->x = 0; + rect->y = 0; + rect->width = width; + rect->height = height; +} + +static inline void +get_window_rect(GstVaapiWindow *window, GstVaapiRectangle *rect) +{ + guint width, height; + + gst_vaapi_window_get_size(window, &width, &height); + rect->x = 0; + rect->y = 0; + rect->width = width; + rect->height = height; +} + +/** + * gst_vaapi_window_put_surface: + * @window: a #GstVaapiWindow + * @surface: a #GstVaapiSurface + * @src_rect: the sub-rectangle of the source surface to + * extract and process. If %NULL, the entire surface will be used. + * @dst_rect: the sub-rectangle of the destination + * window into which the surface is rendered. If %NULL, the entire + * window will be used. + * @flags: postprocessing flags. See #GstVaapiSurfaceRenderFlags + * + * Renders the @surface region specified by @src_rect into the @window + * region specified by @dst_rect. The @flags specify how de-interlacing + * (if needed), color space conversion, scaling and other postprocessing + * transformations are performed. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_window_put_surface( + GstVaapiWindow *window, + GstVaapiSurface *surface, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect, + guint flags +) +{ + GstVaapiWindowClass *klass; + GstVaapiRectangle src_rect_default, dst_rect_default; + + g_return_val_if_fail(GST_VAAPI_IS_WINDOW(window), FALSE); + g_return_val_if_fail(window->priv->is_constructed, FALSE); + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE); + + klass = GST_VAAPI_WINDOW_GET_CLASS(window); + if (!klass->render) + return FALSE; + + if (!src_rect) { + src_rect = &src_rect_default; + get_surface_rect(surface, &src_rect_default); + } + + if (!dst_rect) { + dst_rect = &dst_rect_default; + get_window_rect(window, &dst_rect_default); + } + + return klass->render(window, surface, src_rect, dst_rect, flags); +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow.h b/gst-libs/gst/vaapi/gstvaapiwindow.h new file mode 100644 index 0000000..5fdaf81 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow.h @@ -0,0 +1,153 @@ +/* + * gstvaapiwindow.h - VA window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_H +#define GST_VAAPI_WINDOW_H + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_WINDOW \ + (gst_vaapi_window_get_type()) + +#define GST_VAAPI_WINDOW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_WINDOW, \ + GstVaapiWindow)) + +#define GST_VAAPI_WINDOW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_WINDOW, \ + GstVaapiWindowClass)) + +#define GST_VAAPI_IS_WINDOW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_WINDOW)) + +#define GST_VAAPI_IS_WINDOW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_WINDOW)) + +#define GST_VAAPI_WINDOW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_WINDOW, \ + GstVaapiWindowClass)) + +typedef struct _GstVaapiWindow GstVaapiWindow; +typedef struct _GstVaapiWindowPrivate GstVaapiWindowPrivate; +typedef struct _GstVaapiWindowClass GstVaapiWindowClass; + +/** + * GstVaapiWindow: + * + * Base class for system-dependent windows. + */ +struct _GstVaapiWindow { + /*< private >*/ + GstVaapiObject parent_instance; + + GstVaapiWindowPrivate *priv; +}; + +/** + * GstVaapiWindowClass: + * @create: virtual function to create a window with width and height + * @destroy: virtual function to destroy a window + * @show: virtual function to show (map) a window + * @hide: virtual function to hide (unmap) a window + * @set_fullscreen: virtual function to change window fullscreen state + * @resize: virtual function to resize a window + * @render: virtual function to render a #GstVaapiSurface into a window + * + * Base class for system-dependent windows. + */ +struct _GstVaapiWindowClass { + /*< private >*/ + GstVaapiObjectClass parent_class; + + /*< public >*/ + gboolean (*create) (GstVaapiWindow *window, guint *width, guint *height); + void (*destroy)(GstVaapiWindow *window); + gboolean (*show) (GstVaapiWindow *window); + gboolean (*hide) (GstVaapiWindow *window); + gboolean (*get_geometry) (GstVaapiWindow *window, + gint *px, gint *py, + guint *pwidth, guint *pheight); + gboolean (*set_fullscreen)(GstVaapiWindow *window, gboolean fullscreen); + gboolean (*resize) (GstVaapiWindow *window, guint width, guint height); + gboolean (*render) (GstVaapiWindow *window, + GstVaapiSurface *surface, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect, + guint flags); +}; + +GType +gst_vaapi_window_get_type(void) G_GNUC_CONST; + +GstVaapiDisplay * +gst_vaapi_window_get_display(GstVaapiWindow *window); + +void +gst_vaapi_window_show(GstVaapiWindow *window); + +void +gst_vaapi_window_hide(GstVaapiWindow *window); + +gboolean +gst_vaapi_window_get_fullscreen(GstVaapiWindow *window); + +void +gst_vaapi_window_set_fullscreen(GstVaapiWindow *window, gboolean fullscreen); + +guint +gst_vaapi_window_get_width(GstVaapiWindow *window); + +guint +gst_vaapi_window_get_height(GstVaapiWindow *window); + +void +gst_vaapi_window_get_size(GstVaapiWindow *window, guint *pwidth, guint *pheight); + +void +gst_vaapi_window_set_width(GstVaapiWindow *window, guint width); + +void +gst_vaapi_window_set_height(GstVaapiWindow *window, guint height); + +void +gst_vaapi_window_set_size(GstVaapiWindow *window, guint width, guint height); + +gboolean +gst_vaapi_window_put_surface( + GstVaapiWindow *window, + GstVaapiSurface *surface, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect, + guint flags +); + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_drm.c b/gst-libs/gst/vaapi/gstvaapiwindow_drm.c new file mode 100644 index 0000000..6303480 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_drm.c @@ -0,0 +1,161 @@ +/* + * gstvaapiwindow_drm.c - VA/DRM window abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiwindow_drm + * @short_description: VA/DRM dummy window abstraction + */ + +#include "sysdeps.h" +#include "gstvaapiwindow_drm.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiWindowDRM, + gst_vaapi_window_drm, + GST_VAAPI_TYPE_WINDOW); + +static gboolean +gst_vaapi_window_drm_show(GstVaapiWindow *window) +{ + return TRUE; +} + +static gboolean +gst_vaapi_window_drm_hide(GstVaapiWindow *window) +{ + return TRUE; +} + +static gboolean +gst_vaapi_window_drm_create( + GstVaapiWindow *window, + guint *width, + guint *height +) +{ + return TRUE; +} + +static void +gst_vaapi_window_drm_destroy(GstVaapiWindow * window) +{ +} + +static gboolean +gst_vaapi_window_drm_resize( + GstVaapiWindow * window, + guint width, + guint height +) +{ + return TRUE; +} + +static gboolean +gst_vaapi_window_drm_render( + GstVaapiWindow *window, + GstVaapiSurface *surface, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect, + guint flags +) +{ + return TRUE; +} + +static void +gst_vaapi_window_drm_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_window_drm_parent_class)->finalize(object); +} + +static void +gst_vaapi_window_drm_constructed(GObject *object) +{ + GObjectClass *parent_class; + + parent_class = G_OBJECT_CLASS(gst_vaapi_window_drm_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static void +gst_vaapi_window_drm_class_init(GstVaapiWindowDRMClass * klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiWindowClass * const window_class = GST_VAAPI_WINDOW_CLASS(klass); + + object_class->finalize = gst_vaapi_window_drm_finalize; + object_class->constructed = gst_vaapi_window_drm_constructed; + + window_class->create = gst_vaapi_window_drm_create; + window_class->destroy = gst_vaapi_window_drm_destroy; + window_class->show = gst_vaapi_window_drm_show; + window_class->hide = gst_vaapi_window_drm_hide; + window_class->render = gst_vaapi_window_drm_render; + window_class->resize = gst_vaapi_window_drm_resize; +} + +static void +gst_vaapi_window_drm_init(GstVaapiWindowDRM * window) +{ +} + +/** + * gst_vaapi_window_drm_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels (unused) + * @height: the requested windo height, in pixels (unused) + * + * Creates a dummy window. The window will be attached to the @display. + * All rendering functions will return success since VA/DRM is a + * renderless API. + * + * Note: this dummy window object is only necessary to fulfill cases + * where the client application wants to automatically determine the + * best display to use for the current system. As such, it provides + * utility functions with the same API (function arguments) to help + * implement uniform function tables. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_drm_new( + GstVaapiDisplay *display, + guint width, + guint height +) +{ + GST_DEBUG("new window, size %ux%u", width, height); + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(width > 0, NULL); + g_return_val_if_fail(height > 0, NULL); + + return g_object_new(GST_VAAPI_TYPE_WINDOW_DRM, + "display", display, + "id", GST_VAAPI_ID(0), + "width", width, + "height", height, + NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_drm.h b/gst-libs/gst/vaapi/gstvaapiwindow_drm.h new file mode 100644 index 0000000..47e053a --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_drm.h @@ -0,0 +1,85 @@ +/* + * gstvaapiwindow_drm.h - VA/DRM window abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_DRM_H +#define GST_VAAPI_WINDOW_DRM_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_WINDOW_DRM \ + (gst_vaapi_window_drm_get_type()) + +#define GST_VAAPI_WINDOW_DRM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_WINDOW_DRM, \ + GstVaapiWindowDRM)) + +#define GST_VAAPI_WINDOW_DRM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_WINDOW_DRM, \ + GstVaapiWindowDRMClass)) + +#define GST_VAAPI_IS_WINDOW_DRM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_WINDOW_DRM)) + +#define GST_VAAPI_IS_WINDOW_DRM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_WINDOW_DRM)) + +#define GST_VAAPI_WINDOW_DRM_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_WINDOW_DRM, \ + GstVaapiWindowDRMClass)) + +typedef struct _GstVaapiWindowDRM GstVaapiWindowDRM; +typedef struct _GstVaapiWindowDRMClass GstVaapiWindowDRMClass; + +/** + * GstVaapiWindowDRM: + * + * A dummy DRM window abstraction. + */ +struct _GstVaapiWindowDRM { + /*< private >*/ + GstVaapiWindow parent_instance; +}; + +/** + * GstVaapiWindowDRMClass: + * + * A DRM window class. + */ +struct _GstVaapiWindowDRMClass { + /*< private >*/ + GstVaapiWindowClass parent_class; +}; + +GType +gst_vaapi_window_drm_get_type(void) G_GNUC_CONST; + +GstVaapiWindow * +gst_vaapi_window_drm_new(GstVaapiDisplay *display, guint width, guint height); + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_DRM_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_glx.c b/gst-libs/gst/vaapi/gstvaapiwindow_glx.c new file mode 100644 index 0000000..45c040d --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_glx.c @@ -0,0 +1,604 @@ +/* + * gstvaapiwindow_glx.c - VA/GLX window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiwindow_glx + * @short_description: VA/GLX window abstraction + */ + +#include "sysdeps.h" +#include "gstvaapiwindow_glx.h" +#include "gstvaapidisplay_x11.h" +#include "gstvaapidisplay_x11_priv.h" +#include "gstvaapiutils_x11.h" +#include "gstvaapiutils_glx.h" +#include "gstvaapi_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiWindowGLX, + gst_vaapi_window_glx, + GST_VAAPI_TYPE_WINDOW_X11); + +#define GST_VAAPI_WINDOW_GLX_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_WINDOW_GLX, \ + GstVaapiWindowGLXPrivate)) + +struct _GstVaapiWindowGLXPrivate { + Colormap cmap; + GLContextState *gl_context; + guint is_constructed : 1; + guint foreign_window : 1; +}; + +enum { + PROP_0, + + PROP_GLX_CONTEXT +}; + +/* Fill rectangle coords with capped bounds */ +static inline void +fill_rect( + GstVaapiRectangle *dst_rect, + const GstVaapiRectangle *src_rect, + guint width, + guint height +) +{ + if (src_rect) { + dst_rect->x = src_rect->x > 0 ? src_rect->x : 0; + dst_rect->y = src_rect->y > 0 ? src_rect->y : 0; + if (src_rect->x + src_rect->width < width) + dst_rect->width = src_rect->width; + else + dst_rect->width = width - dst_rect->x; + if (src_rect->y + src_rect->height < height) + dst_rect->height = src_rect->height; + else + dst_rect->height = height - dst_rect->y; + } + else { + dst_rect->x = 0; + dst_rect->y = 0; + dst_rect->width = width; + dst_rect->height = height; + } +} + +static void +_gst_vaapi_window_glx_destroy_context(GstVaapiWindowGLX *window) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + if (priv->gl_context) { + gl_destroy_context(priv->gl_context); + priv->gl_context = NULL; + } + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); +} + +static gboolean +_gst_vaapi_window_glx_create_context( + GstVaapiWindowGLX *window, + GLXContext foreign_context +) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + GLContextState parent_cs; + + parent_cs.display = dpy; + parent_cs.window = None; + parent_cs.context = foreign_context; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + priv->gl_context = gl_create_context( + dpy, + GST_VAAPI_OBJECT_XSCREEN(window), + &parent_cs + ); + if (!priv->gl_context) { + GST_DEBUG("could not create GLX context"); + goto end; + } + + if (!glXIsDirect(dpy, priv->gl_context->context)) { + GST_DEBUG("could not create a direct-rendering GLX context"); + goto out_destroy_context; + } + goto end; + +out_destroy_context: + gl_destroy_context(priv->gl_context); + priv->gl_context = NULL; +end: + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + return priv->gl_context != NULL; +} + +static gboolean +_gst_vaapi_window_glx_ensure_context( + GstVaapiWindowGLX *window, + GLXContext foreign_context +) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + + if (priv->gl_context) { + if (!foreign_context || foreign_context == priv->gl_context->context) + return TRUE; + _gst_vaapi_window_glx_destroy_context(window); + } + return _gst_vaapi_window_glx_create_context(window, foreign_context); +} + +static gboolean +gst_vaapi_window_glx_ensure_context( + GstVaapiWindowGLX *window, + GLXContext foreign_context +) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + GLContextState old_cs; + guint width, height; + + if (!_gst_vaapi_window_glx_ensure_context(window, foreign_context)) + return FALSE; + + priv->gl_context->window = GST_VAAPI_OBJECT_ID(window); + if (!gl_set_current_context(priv->gl_context, &old_cs)) { + GST_DEBUG("could not make newly created GLX context current"); + return FALSE; + } + + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + glDisable(GL_CULL_FACE); + glDrawBuffer(GL_BACK); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + gst_vaapi_window_get_size(GST_VAAPI_WINDOW(window), &width, &height); + gl_resize(width, height); + + gl_set_bgcolor(0); + glClear(GL_COLOR_BUFFER_BIT); + gl_set_current_context(&old_cs, NULL); + return TRUE; +} + +static Visual * +gst_vaapi_window_glx_get_visual(GstVaapiWindow *window) +{ + GstVaapiWindowGLX * const glx_window = GST_VAAPI_WINDOW_GLX(window); + + if (!_gst_vaapi_window_glx_ensure_context(glx_window, NULL)) + return NULL; + return glx_window->priv->gl_context->visual->visual; +} + +static void +gst_vaapi_window_glx_destroy_colormap(GstVaapiWindowGLX *window) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + + if (priv->cmap) { + if (!priv->foreign_window) { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + XFreeColormap(dpy, priv->cmap); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + } + priv->cmap = None; + } +} + +static Colormap +gst_vaapi_window_glx_create_colormap(GstVaapiWindowGLX *window) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + int screen; + XWindowAttributes wattr; + gboolean success = FALSE; + + if (!priv->cmap) { + if (!priv->foreign_window) { + if (!_gst_vaapi_window_glx_ensure_context(window, NULL)) + return None; + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + x11_trap_errors(); + /* XXX: add a GstVaapiDisplayX11:x11-screen property? */ + screen = GST_VAAPI_OBJECT_XSCREEN(window); + priv->cmap = XCreateColormap( + dpy, + RootWindow(dpy, screen), + priv->gl_context->visual->visual, + AllocNone + ); + success = x11_untrap_errors() == 0; + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + } + else { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + x11_trap_errors(); + XGetWindowAttributes(dpy, GST_VAAPI_OBJECT_ID(window), &wattr); + priv->cmap = wattr.colormap; + success = x11_untrap_errors() == 0; + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + } + if (!success) + return None; + } + return priv->cmap; +} + +static Colormap +gst_vaapi_window_glx_get_colormap(GstVaapiWindow *window) +{ + return gst_vaapi_window_glx_create_colormap(GST_VAAPI_WINDOW_GLX(window)); +} + +static gboolean +gst_vaapi_window_glx_resize(GstVaapiWindow *window, guint width, guint height) +{ + GstVaapiWindowGLXPrivate * const priv = GST_VAAPI_WINDOW_GLX(window)->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + GLContextState old_cs; + + if (!GST_VAAPI_WINDOW_CLASS(gst_vaapi_window_glx_parent_class)-> + resize(window, width, height)) + return FALSE; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + XSync(dpy, False); /* make sure resize completed */ + if (gl_set_current_context(priv->gl_context, &old_cs)) { + gl_resize(width, height); + gl_set_current_context(&old_cs, NULL); + } + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + return TRUE; +} + +static void +gst_vaapi_window_glx_finalize(GObject *object) +{ + GstVaapiWindowGLX * const window = GST_VAAPI_WINDOW_GLX(object); + + _gst_vaapi_window_glx_destroy_context(window); + gst_vaapi_window_glx_destroy_colormap(window); + + G_OBJECT_CLASS(gst_vaapi_window_glx_parent_class)->finalize(object); +} + +static void +gst_vaapi_window_glx_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiWindowGLX * const window = GST_VAAPI_WINDOW_GLX(object); + + switch (prop_id) { + case PROP_GLX_CONTEXT: + gst_vaapi_window_glx_set_context(window, g_value_get_pointer(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_window_glx_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiWindowGLX * const window = GST_VAAPI_WINDOW_GLX(object); + + switch (prop_id) { + case PROP_GLX_CONTEXT: + g_value_set_pointer(value, gst_vaapi_window_glx_get_context(window)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_window_glx_constructed(GObject *object) +{ + GstVaapiWindowGLXPrivate * const priv = GST_VAAPI_WINDOW_GLX(object)->priv; + GObjectClass *parent_class; + + parent_class = G_OBJECT_CLASS(gst_vaapi_window_glx_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); + + priv->foreign_window = + gst_vaapi_window_x11_is_foreign_xid(GST_VAAPI_WINDOW_X11(object)); + + priv->is_constructed = + gst_vaapi_window_glx_ensure_context(GST_VAAPI_WINDOW_GLX(object), NULL); +} + +static void +gst_vaapi_window_glx_class_init(GstVaapiWindowGLXClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiWindowClass * const win_class = GST_VAAPI_WINDOW_CLASS(klass); + GstVaapiWindowX11Class * const xwin_class = GST_VAAPI_WINDOW_X11_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiWindowGLXPrivate)); + + object_class->finalize = gst_vaapi_window_glx_finalize; + object_class->set_property = gst_vaapi_window_glx_set_property; + object_class->get_property = gst_vaapi_window_glx_get_property; + object_class->constructed = gst_vaapi_window_glx_constructed; + + win_class->resize = gst_vaapi_window_glx_resize; + xwin_class->get_visual = gst_vaapi_window_glx_get_visual; + xwin_class->get_colormap = gst_vaapi_window_glx_get_colormap; + + /** + * GstVaapiDisplayGLX:glx-context: + * + * The GLX context that was created by gst_vaapi_window_glx_new() + * or that was bound from gst_vaapi_window_glx_set_context(). + */ + g_object_class_install_property + (object_class, + PROP_GLX_CONTEXT, + g_param_spec_pointer("glx-context", + "GLX context", + "GLX context", + G_PARAM_READWRITE)); +} + +static void +gst_vaapi_window_glx_init(GstVaapiWindowGLX *window) +{ + GstVaapiWindowGLXPrivate *priv = GST_VAAPI_WINDOW_GLX_GET_PRIVATE(window); + + window->priv = priv; + priv->cmap = None; + priv->gl_context = NULL; + priv->is_constructed = FALSE; + priv->foreign_window = FALSE; +} + +/** + * gst_vaapi_window_glx_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels + * @height: the requested windo height, in pixels + * + * Creates a window with the specified @width and @height. The window + * will be attached to the @display and remains invisible to the user + * until gst_vaapi_window_show() is called. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_glx_new(GstVaapiDisplay *display, guint width, guint height) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(width > 0, NULL); + g_return_val_if_fail(height > 0, NULL); + + return g_object_new(GST_VAAPI_TYPE_WINDOW_GLX, + "display", display, + "id", GST_VAAPI_ID(None), + "width", width, + "height", height, + NULL); +} + +/** + * gst_vaapi_window_glx_new_with_xid: + * @display: a #GstVaapiDisplay + * @xid: an X11 #Window id + * + * Creates a #GstVaapiWindow using the X11 #Window @xid. The caller + * still owns the window and must call XDestroyWindow() when all + * #GstVaapiWindow references are released. Doing so too early can + * yield undefined behaviour. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_glx_new_with_xid(GstVaapiDisplay *display, Window xid) +{ + GST_DEBUG("new window from xid 0x%08x", xid); + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(xid != None, NULL); + + return g_object_new(GST_VAAPI_TYPE_WINDOW_GLX, + "display", display, + "id", GST_VAAPI_ID(xid), + NULL); +} + +/** + * gst_vaapi_window_glx_get_context: + * @window: a #GstVaapiWindowGLX + * + * Returns the #GLXContext bound to the @window. + * + * Return value: the #GLXContext bound to the @window + */ +GLXContext +gst_vaapi_window_glx_get_context(GstVaapiWindowGLX *window) +{ + g_return_val_if_fail(GST_VAAPI_IS_WINDOW_GLX(window), NULL); + g_return_val_if_fail(window->priv->is_constructed, FALSE); + + return window->priv->gl_context->context; +} + +/** + * gst_vaapi_window_glx_set_context: + * @window: a #GstVaapiWindowGLX + * @ctx: a GLX context + * + * Binds GLX context @ctx to @window. If @ctx is non %NULL, the caller + * is responsible to making sure it has compatible visual with that of + * the underlying X window. If @ctx is %NULL, a new context is created + * and the @window owns it. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_window_glx_set_context(GstVaapiWindowGLX *window, GLXContext ctx) +{ + g_return_val_if_fail(GST_VAAPI_IS_WINDOW_GLX(window), FALSE); + g_return_val_if_fail(window->priv->is_constructed, FALSE); + + return gst_vaapi_window_glx_ensure_context(window, ctx); +} + +/** + * gst_vaapi_window_glx_make_current: + * @window: a #GstVaapiWindowGLX + * + * Makes the @window GLX context the current GLX rendering context of + * the calling thread, replacing the previously current context if + * there was one. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_window_glx_make_current(GstVaapiWindowGLX *window) +{ + gboolean success; + + g_return_val_if_fail(GST_VAAPI_IS_WINDOW_GLX(window), FALSE); + g_return_val_if_fail(window->priv->is_constructed, FALSE); + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + success = gl_set_current_context(window->priv->gl_context, NULL); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + return success; +} + +/** + * gst_vaapi_window_glx_swap_buffers: + * @window: a #GstVaapiWindowGLX + * + * Promotes the contents of the back buffer of @window to become the + * contents of the front buffer of @window. This simply is wrapper + * around glXSwapBuffers(). + */ +void +gst_vaapi_window_glx_swap_buffers(GstVaapiWindowGLX *window) +{ + g_return_if_fail(GST_VAAPI_IS_WINDOW_GLX(window)); + g_return_if_fail(window->priv->is_constructed); + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + gl_swap_buffers(window->priv->gl_context); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); +} + +/** + * gst_vaapi_window_glx_put_texture: + * @window: a #GstVaapiWindowGLX + * @texture: a #GstVaapiTexture + * @src_rect: the sub-rectangle of the source texture to + * extract and process. If %NULL, the entire texture will be used. + * @dst_rect: the sub-rectangle of the destination + * window into which the texture is rendered. If %NULL, the entire + * window will be used. + * + * Renders the @texture region specified by @src_rect into the @window + * region specified by @dst_rect. + * + * NOTE: only GL_TEXTURE_2D textures are supported at this time. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_window_glx_put_texture( + GstVaapiWindowGLX *window, + GstVaapiTexture *texture, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect +) +{ + GstVaapiRectangle tmp_src_rect, tmp_dst_rect; + GLTextureState ts; + GLenum tex_target; + GLuint tex_id; + guint tex_width, tex_height; + guint win_width, win_height; + + g_return_val_if_fail(GST_VAAPI_IS_WINDOW_GLX(window), FALSE); + g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), FALSE); + + gst_vaapi_texture_get_size(texture, &tex_width, &tex_height); + fill_rect(&tmp_src_rect, src_rect, tex_width, tex_height); + src_rect = &tmp_src_rect; + + gst_vaapi_window_get_size(GST_VAAPI_WINDOW(window), &win_width, &win_height); + fill_rect(&tmp_dst_rect, dst_rect, win_width, win_height); + dst_rect = &tmp_dst_rect; + + /* XXX: only GL_TEXTURE_2D textures are supported at this time */ + tex_target = gst_vaapi_texture_get_target(texture); + if (tex_target != GL_TEXTURE_2D) + return FALSE; + + tex_id = gst_vaapi_texture_get_id(texture); + if (!gl_bind_texture(&ts, tex_target, tex_id)) + return FALSE; + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glPushMatrix(); + glTranslatef((GLfloat)dst_rect->x, (GLfloat)dst_rect->y, 0.0f); + glBegin(GL_QUADS); + { + const float tx1 = (float)src_rect->x / tex_width; + const float tx2 = (float)(src_rect->x + src_rect->width) / tex_width; + const float ty1 = (float)src_rect->y / tex_height; + const float ty2 = (float)(src_rect->y + src_rect->height) / tex_height; + const guint w = dst_rect->width; + const guint h = dst_rect->height; + glTexCoord2f(tx1, ty1); glVertex2i(0, 0); + glTexCoord2f(tx1, ty2); glVertex2i(0, h); + glTexCoord2f(tx2, ty2); glVertex2i(w, h); + glTexCoord2f(tx2, ty1); glVertex2i(w, 0); + } + glEnd(); + glPopMatrix(); + gl_unbind_texture(&ts); + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_glx.h b/gst-libs/gst/vaapi/gstvaapiwindow_glx.h new file mode 100644 index 0000000..5547355 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_glx.h @@ -0,0 +1,113 @@ +/* + * gstvaapiwindow_glx.h - VA/GLX window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_GLX_H +#define GST_VAAPI_WINDOW_GLX_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_WINDOW_GLX \ + (gst_vaapi_window_glx_get_type()) + +#define GST_VAAPI_WINDOW_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_WINDOW_GLX, \ + GstVaapiWindowGLX)) + +#define GST_VAAPI_WINDOW_GLX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_WINDOW_GLX, \ + GstVaapiWindowGLXClass)) + +#define GST_VAAPI_IS_WINDOW_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_WINDOW_GLX)) + +#define GST_VAAPI_IS_WINDOW_GLX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_WINDOW_GLX)) + +#define GST_VAAPI_WINDOW_GLX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_WINDOW_GLX, \ + GstVaapiWindowGLXClass)) + +typedef struct _GstVaapiWindowGLX GstVaapiWindowGLX; +typedef struct _GstVaapiWindowGLXPrivate GstVaapiWindowGLXPrivate; +typedef struct _GstVaapiWindowGLXClass GstVaapiWindowGLXClass; + +/** + * GstVaapiWindowGLX: + * + * An X11 #Window suitable for GLX rendering. + */ +struct _GstVaapiWindowGLX { + /*< private >*/ + GstVaapiWindowX11 parent_instance; + + GstVaapiWindowGLXPrivate *priv; +}; + +/** + * GstVaapiWindowGLXClass: + * + * An X11 #Window suitable for GLX rendering. + */ +struct _GstVaapiWindowGLXClass { + /*< private >*/ + GstVaapiWindowX11Class parent_class; +}; + +GType +gst_vaapi_window_glx_get_type(void) G_GNUC_CONST; + +GstVaapiWindow * +gst_vaapi_window_glx_new(GstVaapiDisplay *display, guint width, guint height); + +GstVaapiWindow * +gst_vaapi_window_glx_new_with_xid(GstVaapiDisplay *display, Window xid); + +GLXContext +gst_vaapi_window_glx_get_context(GstVaapiWindowGLX *window); + +gboolean +gst_vaapi_window_glx_set_context(GstVaapiWindowGLX *window, GLXContext ctx); + +gboolean +gst_vaapi_window_glx_make_current(GstVaapiWindowGLX *window); + +void +gst_vaapi_window_glx_swap_buffers(GstVaapiWindowGLX *window); + +gboolean +gst_vaapi_window_glx_put_texture( + GstVaapiWindowGLX *window, + GstVaapiTexture *texture, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect +); + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_GLX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c b/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c new file mode 100644 index 0000000..5925fe4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c @@ -0,0 +1,340 @@ +/* + * gstvaapiwindow_wayland.c - VA/Wayland window abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiwindow_wayland + * @short_description: VA/Wayland window abstraction + */ + +#include "sysdeps.h" +#include +#include "gstvaapicompat.h" +#include "gstvaapiwindow_wayland.h" +#include "gstvaapidisplay_wayland.h" +#include "gstvaapidisplay_wayland_priv.h" +#include "gstvaapiutils.h" +#include "gstvaapi_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiWindowWayland, + gst_vaapi_window_wayland, + GST_VAAPI_TYPE_WINDOW); + +#define GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_WINDOW_WAYLAND, \ + GstVaapiWindowWaylandPrivate)) + +struct _GstVaapiWindowWaylandPrivate { + struct wl_shell_surface *shell_surface; + struct wl_surface *surface; + struct wl_buffer *buffer; + guint redraw_pending : 1; +}; + +static gboolean +gst_vaapi_window_wayland_show(GstVaapiWindow *window) +{ + GST_WARNING("unimplemented GstVaapiWindowWayland::show()"); + + return TRUE; +} + +static gboolean +gst_vaapi_window_wayland_hide(GstVaapiWindow *window) +{ + GST_WARNING("unimplemented GstVaapiWindowWayland::hide()"); + + return TRUE; +} + +static void +handle_ping(void *data, struct wl_shell_surface *shell_surface, + uint32_t serial) +{ + wl_shell_surface_pong(shell_surface, serial); +} + +static void +handle_configure(void *data, struct wl_shell_surface *shell_surface, + uint32_t edges, int32_t width, int32_t height) +{ +} + +static void +handle_popup_done(void *data, struct wl_shell_surface *shell_surface) +{ +} + +static const struct wl_shell_surface_listener shell_surface_listener = { + handle_ping, + handle_configure, + handle_popup_done +}; + +static gboolean +gst_vaapi_window_wayland_create( + GstVaapiWindow *window, + guint *width, + guint *height +) +{ + GstVaapiWindowWaylandPrivate * const priv = + GST_VAAPI_WINDOW_WAYLAND(window)->priv; + GstVaapiDisplayWaylandPrivate * const priv_display = + GST_VAAPI_OBJECT_DISPLAY_WAYLAND(window)->priv; + + GST_DEBUG("create window, size %ux%u", *width, *height); + + g_return_val_if_fail(priv_display->compositor != NULL, FALSE); + g_return_val_if_fail(priv_display->shell != NULL, FALSE); + + priv->surface = wl_compositor_create_surface(priv_display->compositor); + if (!priv->surface) + return FALSE; + + priv->shell_surface = + wl_shell_get_shell_surface(priv_display->shell, priv->surface); + if (!priv->shell_surface) + return FALSE; + + wl_shell_surface_add_listener(priv->shell_surface, + &shell_surface_listener, priv); + wl_shell_surface_set_toplevel(priv->shell_surface); + wl_shell_surface_set_fullscreen( + priv->shell_surface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE, + 0, + NULL + ); + + priv->redraw_pending = FALSE; + return TRUE; +} + +static void +gst_vaapi_window_wayland_destroy(GstVaapiWindow * window) +{ + GstVaapiWindowWaylandPrivate * const priv = + GST_VAAPI_WINDOW_WAYLAND(window)->priv; + + if (priv->shell_surface) { + wl_shell_surface_destroy(priv->shell_surface); + priv->shell_surface = NULL; + } + + if (priv->surface) { + wl_surface_destroy(priv->surface); + priv->surface = NULL; + } + + if (priv->buffer) { + wl_buffer_destroy(priv->buffer); + priv->buffer = NULL; + } +} + +static gboolean +gst_vaapi_window_wayland_resize( + GstVaapiWindow * window, + guint width, + guint height +) +{ + GST_DEBUG("resize window, new size %ux%u", width, height); + return TRUE; +} + +static void +frame_redraw_callback(void *data, struct wl_callback *callback, uint32_t time) +{ + GstVaapiWindowWaylandPrivate * const priv = data; + + priv->redraw_pending = FALSE; + wl_buffer_destroy(priv->buffer); + priv->buffer = NULL; + wl_callback_destroy(callback); +} + +static const struct wl_callback_listener frame_callback_listener = { + frame_redraw_callback +}; + +static gboolean +gst_vaapi_window_wayland_render( + GstVaapiWindow *window, + GstVaapiSurface *surface, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect, + guint flags +) +{ + GstVaapiWindowWaylandPrivate * const priv = + GST_VAAPI_WINDOW_WAYLAND(window)->priv; + GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(window); + struct wl_display * const wl_display = GST_VAAPI_OBJECT_WL_DISPLAY(window); + struct wl_buffer *buffer; + struct wl_callback *callback; + guint width, height, va_flags; + VASurfaceID surface_id; + VAStatus status; + + /* XXX: use VPP to support unusual source and destination rectangles */ + gst_vaapi_surface_get_size(surface, &width, &height); + if (src_rect->x != 0 || + src_rect->y != 0 || + src_rect->width != width || + src_rect->height != height) { + GST_ERROR("unsupported source rectangle for rendering"); + return FALSE; + } + + if (0 && (dst_rect->width != width || dst_rect->height != height)) { + GST_ERROR("unsupported target rectangle for rendering"); + return FALSE; + } + + surface_id = GST_VAAPI_OBJECT_ID(surface); + if (surface_id == VA_INVALID_ID) + return FALSE; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + + /* Wait for the previous frame to complete redraw */ + if (priv->redraw_pending) + wl_display_iterate(wl_display, WL_DISPLAY_READABLE); + + /* XXX: use VA/VPP for other filters */ + va_flags = from_GstVaapiSurfaceRenderFlags(flags); + status = vaGetSurfaceBufferWl( + GST_VAAPI_DISPLAY_VADISPLAY(display), + surface_id, + va_flags & (VA_TOP_FIELD|VA_BOTTOM_FIELD), + &buffer + ); + if (status == VA_STATUS_ERROR_FLAG_NOT_SUPPORTED) { + /* XXX: de-interlacing flags not supported, try with VPP? */ + status = vaGetSurfaceBufferWl( + GST_VAAPI_DISPLAY_VADISPLAY(display), + surface_id, + VA_FRAME_PICTURE, + &buffer + ); + } + if (!vaapi_check_status(status, "vaGetSurfaceBufferWl()")) + return FALSE; + + /* XXX: attach to the specified target rectangle */ + wl_surface_attach(priv->surface, buffer, 0, 0); + wl_surface_damage(priv->surface, 0, 0, width, height); + + wl_display_iterate(wl_display, WL_DISPLAY_WRITABLE); + priv->redraw_pending = TRUE; + priv->buffer = buffer; + + callback = wl_surface_frame(priv->surface); + wl_callback_add_listener(callback, &frame_callback_listener, priv); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + return TRUE; +} + +static void +gst_vaapi_window_wayland_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_window_wayland_parent_class)->finalize(object); +} + +static void +gst_vaapi_window_wayland_constructed(GObject *object) +{ + GObjectClass *parent_class; + + parent_class = G_OBJECT_CLASS(gst_vaapi_window_wayland_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static void +gst_vaapi_window_wayland_class_init(GstVaapiWindowWaylandClass * klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiWindowClass * const window_class = GST_VAAPI_WINDOW_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiWindowWaylandPrivate)); + + object_class->finalize = gst_vaapi_window_wayland_finalize; + object_class->constructed = gst_vaapi_window_wayland_constructed; + + window_class->create = gst_vaapi_window_wayland_create; + window_class->destroy = gst_vaapi_window_wayland_destroy; + window_class->show = gst_vaapi_window_wayland_show; + window_class->hide = gst_vaapi_window_wayland_hide; + window_class->render = gst_vaapi_window_wayland_render; + window_class->resize = gst_vaapi_window_wayland_resize; +} + +static void +gst_vaapi_window_wayland_init(GstVaapiWindowWayland * window) +{ + GstVaapiWindowWaylandPrivate *priv = + GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE(window); + + window->priv = priv; + priv->shell_surface = NULL; + priv->surface = NULL; + priv->buffer = NULL; + priv->redraw_pending = FALSE; +} + +/** + * gst_vaapi_window_wayland_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels + * @height: the requested windo height, in pixels + * + * Creates a window with the specified @width and @height. The window + * will be attached to the @display and remains invisible to the user + * until gst_vaapi_window_show() is called. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_wayland_new( + GstVaapiDisplay *display, + guint width, + guint height +) +{ + GST_DEBUG("new window, size %ux%u", width, height); + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(width > 0, NULL); + g_return_val_if_fail(height > 0, NULL); + + return g_object_new(GST_VAAPI_TYPE_WINDOW_WAYLAND, + "display", display, + "id", GST_VAAPI_ID(0), + "width", width, + "height", height, + NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_wayland.h b/gst-libs/gst/vaapi/gstvaapiwindow_wayland.h new file mode 100644 index 0000000..d711fb7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_wayland.h @@ -0,0 +1,89 @@ +/* + * gstvaapiwindow_wayland.h - VA/Wayland window abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_WAYLAND_H +#define GST_VAAPI_WINDOW_WAYLAND_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_WINDOW_WAYLAND \ + (gst_vaapi_window_wayland_get_type()) + +#define GST_VAAPI_WINDOW_WAYLAND(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_WINDOW_WAYLAND, \ + GstVaapiWindowWayland)) + +#define GST_VAAPI_WINDOW_WAYLAND_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_WINDOW_WAYLAND, \ + GstVaapiWindowWaylandClass)) + +#define GST_VAAPI_IS_WINDOW_WAYLAND(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_WINDOW_WAYLAND)) + +#define GST_VAAPI_IS_WINDOW_WAYLAND_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_WINDOW_WAYLAND)) + +#define GST_VAAPI_WINDOW_WAYLAND_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_WINDOW_WAYLAND, \ + GstVaapiWindowWaylandClass)) + +typedef struct _GstVaapiWindowWayland GstVaapiWindowWayland; +typedef struct _GstVaapiWindowWaylandPrivate GstVaapiWindowWaylandPrivate; +typedef struct _GstVaapiWindowWaylandClass GstVaapiWindowWaylandClass; + +/** + * GstVaapiWindowWayland: + * + * A Wayland window abstraction. + */ +struct _GstVaapiWindowWayland { + /*< private >*/ + GstVaapiWindow parent_instance; + + GstVaapiWindowWaylandPrivate *priv; +}; + +/** + * GstVaapiWindowWaylandClass: + * + * An Wayland #Window wrapper class. + */ +struct _GstVaapiWindowWaylandClass { + /*< private >*/ + GstVaapiWindowClass parent_class; +}; + +GType +gst_vaapi_window_wayland_get_type(void) G_GNUC_CONST; + +GstVaapiWindow * +gst_vaapi_window_wayland_new(GstVaapiDisplay *display, guint width, guint height); + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_WAYLAND_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_x11.c b/gst-libs/gst/vaapi/gstvaapiwindow_x11.c new file mode 100644 index 0000000..a936813 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_x11.c @@ -0,0 +1,625 @@ +/* + * gstvaapiwindow_x11.c - VA/X11 window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiwindow_x11 + * @short_description: VA/X11 window abstraction + */ + +#include "sysdeps.h" +#include +#include +#include "gstvaapicompat.h" +#include "gstvaapiwindow_x11.h" +#include "gstvaapidisplay_x11.h" +#include "gstvaapidisplay_x11_priv.h" +#include "gstvaapiutils.h" +#include "gstvaapiutils_x11.h" +#include "gstvaapi_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiWindowX11, gst_vaapi_window_x11, GST_VAAPI_TYPE_WINDOW); + +#define GST_VAAPI_WINDOW_X11_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_WINDOW_X11, \ + GstVaapiWindowX11Private)) + +struct _GstVaapiWindowX11Private { + Atom atom_NET_WM_STATE; + Atom atom_NET_WM_STATE_FULLSCREEN; + guint create_window : 1; + guint is_mapped : 1; + guint fullscreen_on_map : 1; + guint is_pixmap : 1; +}; +/* + * is_pixmap will be used by _create(), but _new_with_xid() doesn't have + * a chance to set the flag, so add this flag here. + * TODO, we'd better add is_pixmap flag to base class: GstVaapiWindow +*/ + +static gboolean _is_pixmap = FALSE; + +#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ +#define _NET_WM_STATE_ADD 1 /* add/set property */ +#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ + +static void +send_wmspec_change_state(GstVaapiWindowX11 *window, Atom state, gboolean add) +{ + GstVaapiWindowX11Private * const priv = window->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + XClientMessageEvent xclient; + + memset(&xclient, 0, sizeof(xclient)); + + xclient.type = ClientMessage; + xclient.window = GST_VAAPI_OBJECT_ID(window); + xclient.message_type = priv->atom_NET_WM_STATE; + xclient.format = 32; + + xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + xclient.data.l[1] = state; + xclient.data.l[2] = 0; + xclient.data.l[3] = 0; + xclient.data.l[4] = 0; + + XSendEvent( + dpy, + DefaultRootWindow(dpy), + False, + SubstructureRedirectMask|SubstructureNotifyMask, + (XEvent *)&xclient + ); +} + +static void +wait_event(GstVaapiWindow *window, int type) +{ + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + const Window xid = GST_VAAPI_OBJECT_ID(window); + XEvent e; + Bool got_event; + + for (;;) { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + got_event = XCheckTypedWindowEvent(dpy, xid, type, &e); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + if (got_event) + break; + g_usleep(10); + } +} + +static gboolean +timed_wait_event(GstVaapiWindow *window, int type, guint64 end_time, XEvent *e) +{ + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + const Window xid = GST_VAAPI_OBJECT_ID(window); + XEvent tmp_event; + GTimeVal now; + guint64 now_time; + Bool got_event; + + if (!e) + e = &tmp_event; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + got_event = XCheckTypedWindowEvent(dpy, xid, type, e); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + if (got_event) + return TRUE; + + do { + g_usleep(10); + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + got_event = XCheckTypedWindowEvent(dpy, xid, type, e); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + if (got_event) + return TRUE; + g_get_current_time(&now); + now_time = (guint64)now.tv_sec * 1000000 + now.tv_usec; + } while (now_time < end_time); + return FALSE; +} + +static gboolean +gst_vaapi_window_x11_show(GstVaapiWindow *window) +{ + GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + const Window xid = GST_VAAPI_OBJECT_ID(window); + XWindowAttributes wattr; + gboolean has_errors; + + if (priv->is_mapped) + return TRUE; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + x11_trap_errors(); + if (!priv->create_window) { + XGetWindowAttributes(dpy, xid, &wattr); + if (!(wattr.your_event_mask & StructureNotifyMask)) + XSelectInput(dpy, xid, StructureNotifyMask); + } + XMapWindow(dpy, xid); + has_errors = x11_untrap_errors() != 0; + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + + if (!has_errors) { + wait_event(window, MapNotify); + if (!priv->create_window && + !(wattr.your_event_mask & StructureNotifyMask)) { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + x11_trap_errors(); + XSelectInput(dpy, xid, wattr.your_event_mask); + has_errors = x11_untrap_errors() != 0; + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + } + priv->is_mapped = TRUE; + + if (priv->fullscreen_on_map) + gst_vaapi_window_set_fullscreen(window, TRUE); + } + return !has_errors; +} + +static gboolean +gst_vaapi_window_x11_hide(GstVaapiWindow *window) +{ + GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + const Window xid = GST_VAAPI_OBJECT_ID(window); + XWindowAttributes wattr; + gboolean has_errors; + + if (!priv->is_mapped) + return TRUE; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + x11_trap_errors(); + if (!priv->create_window) { + XGetWindowAttributes(dpy, xid, &wattr); + if (!(wattr.your_event_mask & StructureNotifyMask)) + XSelectInput(dpy, xid, StructureNotifyMask); + } + XUnmapWindow(dpy, xid); + has_errors = x11_untrap_errors() != 0; + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + + if (!has_errors) { + wait_event(window, UnmapNotify); + if (!priv->create_window && + !(wattr.your_event_mask & StructureNotifyMask)) { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + x11_trap_errors(); + XSelectInput(dpy, xid, wattr.your_event_mask); + has_errors = x11_untrap_errors() != 0; + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + } + priv->is_mapped = FALSE; + } + return !has_errors; +} + +static gboolean +gst_vaapi_window_x11_create(GstVaapiWindow *window, guint *width, guint *height) +{ + GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + Window xid = GST_VAAPI_OBJECT_ID(window); + Visual *vis = NULL; + Colormap cmap = None; + GstVaapiWindowX11Class *klass; + XWindowAttributes wattr; + Atom atoms[2]; + gboolean ok; + + static const char *atom_names[2] = { + "_NET_WM_STATE", + "_NET_WM_STATE_FULLSCREEN", + }; + + if (!priv->create_window && xid) { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + if (_is_pixmap) { + priv->is_mapped = TRUE; + } + else { + XGetWindowAttributes(dpy, xid, &wattr); + priv->is_mapped = wattr.map_state == IsViewable; + } + ok = x11_get_geometry(dpy, xid, NULL, NULL, width, height); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + return ok; + } + + klass = GST_VAAPI_WINDOW_X11_GET_CLASS(window); + if (klass) { + if (klass->get_visual) + vis = klass->get_visual(window); + if (klass->get_colormap) + cmap = klass->get_colormap(window); + } + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + XInternAtoms( + dpy, + (char **)atom_names, G_N_ELEMENTS(atom_names), + False, + atoms + ); + priv->atom_NET_WM_STATE = atoms[0]; + priv->atom_NET_WM_STATE_FULLSCREEN = atoms[1]; + + xid = x11_create_window(dpy, *width, *height, vis, cmap); + if (xid) + XRaiseWindow(dpy, xid); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + + GST_DEBUG("xid %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(xid)); + GST_VAAPI_OBJECT_ID(window) = xid; + return xid != None; +} + +static void +gst_vaapi_window_x11_destroy(GstVaapiWindow *window) +{ + GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + const Window xid = GST_VAAPI_OBJECT_ID(window); + + if (xid) { + if (priv->create_window) { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + XDestroyWindow(dpy, xid); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + } + GST_VAAPI_OBJECT_ID(window) = None; + } +} + +static gboolean +gst_vaapi_window_x11_get_geometry( + GstVaapiWindow *window, + gint *px, + gint *py, + guint *pwidth, + guint *pheight) +{ + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + const Window xid = GST_VAAPI_OBJECT_ID(window); + + return x11_get_geometry(dpy, xid, px, py, pwidth, pheight); +} + +static gboolean +gst_vaapi_window_x11_set_fullscreen(GstVaapiWindow *window, gboolean fullscreen) +{ + GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + const Window xid = GST_VAAPI_OBJECT_ID(window); + XEvent e; + guint width, height; + gboolean has_errors; + GTimeVal now; + guint64 end_time; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + x11_trap_errors(); + if (fullscreen) { + if (!priv->is_mapped) { + priv->fullscreen_on_map = TRUE; + + XChangeProperty( + dpy, + xid, + priv->atom_NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, + (unsigned char *)&priv->atom_NET_WM_STATE_FULLSCREEN, 1 + ); + } + else { + send_wmspec_change_state( + GST_VAAPI_WINDOW_X11(window), + priv->atom_NET_WM_STATE_FULLSCREEN, + TRUE + ); + } + } + else { + if (!priv->is_mapped) { + priv->fullscreen_on_map = FALSE; + + XDeleteProperty( + dpy, + xid, + priv->atom_NET_WM_STATE + ); + } + else { + send_wmspec_change_state( + GST_VAAPI_WINDOW_X11(window), + priv->atom_NET_WM_STATE_FULLSCREEN, + FALSE + ); + } + } + XSync(dpy, False); + has_errors = x11_untrap_errors() != 0; + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + if (has_errors) + return FALSE; + + /* Try to wait for the completion of the fullscreen mode switch */ + if (priv->create_window && priv->is_mapped) { + const guint DELAY = 100000; /* 100 ms */ + g_get_current_time(&now); + end_time = DELAY + ((guint64)now.tv_sec * 1000000 + now.tv_usec); + while (timed_wait_event(window, ConfigureNotify, end_time, &e)) { + if (fullscreen) { + gst_vaapi_display_get_size( + GST_VAAPI_OBJECT_DISPLAY(window), + &width, + &height + ); + if (e.xconfigure.width == width && e.xconfigure.height == height) + return TRUE; + } + else { + gst_vaapi_window_get_size(window, &width, &height); + if (e.xconfigure.width != width || e.xconfigure.height != height) + return TRUE; + } + } + } + return FALSE; +} + +static gboolean +gst_vaapi_window_x11_resize(GstVaapiWindow *window, guint width, guint height) +{ + gboolean has_errors; + + if (!GST_VAAPI_OBJECT_ID(window)) + return FALSE; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + x11_trap_errors(); + XResizeWindow( + GST_VAAPI_OBJECT_XDISPLAY(window), + GST_VAAPI_OBJECT_ID(window), + width, + height + ); + has_errors = x11_untrap_errors() != 0; + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + return !has_errors; +} + +static gboolean +gst_vaapi_window_x11_render( + GstVaapiWindow *window, + GstVaapiSurface *surface, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect, + guint flags +) +{ + VASurfaceID surface_id; + VAStatus status; + + surface_id = GST_VAAPI_OBJECT_ID(surface); + if (surface_id == VA_INVALID_ID) + return FALSE; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + status = vaPutSurface( + GST_VAAPI_OBJECT_VADISPLAY(window), + surface_id, + GST_VAAPI_OBJECT_ID(window), + src_rect->x, + src_rect->y, + src_rect->width, + src_rect->height, + dst_rect->x, + dst_rect->y, + dst_rect->width, + dst_rect->height, + NULL, 0, + from_GstVaapiSurfaceRenderFlags(flags) + ); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + if (!vaapi_check_status(status, "vaPutSurface()")) + return FALSE; + + return TRUE; +} + +static void +gst_vaapi_window_x11_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_window_x11_parent_class)->finalize(object); +} + +static void +gst_vaapi_window_x11_constructed(GObject *object) +{ + GstVaapiWindowX11 * const window = GST_VAAPI_WINDOW_X11(object); + GObjectClass *parent_class; + + window->priv->create_window = GST_VAAPI_OBJECT_ID(object) == None; + + parent_class = G_OBJECT_CLASS(gst_vaapi_window_x11_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static void +gst_vaapi_window_x11_class_init(GstVaapiWindowX11Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiWindowClass * const window_class = GST_VAAPI_WINDOW_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiWindowX11Private)); + + object_class->finalize = gst_vaapi_window_x11_finalize; + object_class->constructed = gst_vaapi_window_x11_constructed; + + window_class->create = gst_vaapi_window_x11_create; + window_class->destroy = gst_vaapi_window_x11_destroy; + window_class->show = gst_vaapi_window_x11_show; + window_class->hide = gst_vaapi_window_x11_hide; + window_class->get_geometry = gst_vaapi_window_x11_get_geometry; + window_class->set_fullscreen = gst_vaapi_window_x11_set_fullscreen; + window_class->resize = gst_vaapi_window_x11_resize; + window_class->render = gst_vaapi_window_x11_render; +} + +static void +gst_vaapi_window_x11_init(GstVaapiWindowX11 *window) +{ + GstVaapiWindowX11Private *priv = GST_VAAPI_WINDOW_X11_GET_PRIVATE(window); + + window->priv = priv; + priv->create_window = TRUE; + priv->is_mapped = FALSE; + priv->fullscreen_on_map = FALSE; + priv->is_pixmap = FALSE; +} + +/** + * gst_vaapi_window_x11_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels + * @height: the requested windo height, in pixels + * + * Creates a window with the specified @width and @height. The window + * will be attached to the @display and remains invisible to the user + * until gst_vaapi_window_show() is called. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_x11_new(GstVaapiDisplay *display, guint width, guint height) +{ + GST_DEBUG("new window, size %ux%u", width, height); + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(width > 0, NULL); + g_return_val_if_fail(height > 0, NULL); + + return g_object_new(GST_VAAPI_TYPE_WINDOW_X11, + "display", display, + "id", GST_VAAPI_ID(None), + "width", width, + "height", height, + NULL); +} + +/** + * gst_vaapi_window_x11_new_with_xid: + * @display: a #GstVaapiDisplay + * @xid: an X11 #Window id + * + * Creates a #GstVaapiWindow using the X11 #Window @xid. The caller + * still owns the window and must call XDestroyWindow() when all + * #GstVaapiWindow references are released. Doing so too early can + * yield undefined behaviour. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_x11_new_with_xid(GstVaapiDisplay *display, Window xid, gboolean is_pixmap) +{ + GstVaapiWindow * window = NULL; + GST_DEBUG("new window from xid 0x%08x", xid); + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(xid != None, NULL); + + _is_pixmap = is_pixmap; + window = g_object_new(GST_VAAPI_TYPE_WINDOW_X11, + "display", display, + "id", GST_VAAPI_ID(xid), + NULL); + + if (window) { + GstVaapiWindowX11Private *priv = GST_VAAPI_WINDOW_X11_GET_PRIVATE(window); + priv->is_pixmap = is_pixmap; + } + + return window; +} + +/** + * gst_vaapi_window_x11_get_xid: + * @window: a #GstVaapiWindowX11 + * + * Returns the underlying X11 #Window that was created by + * gst_vaapi_window_x11_new() or that was bound with + * gst_vaapi_window_x11_new_with_xid(). + * + * Return value: the underlying X11 #Window bound to @window. + */ +Window +gst_vaapi_window_x11_get_xid(GstVaapiWindowX11 *window) +{ + g_return_val_if_fail(GST_VAAPI_IS_WINDOW_X11(window), None); + + return GST_VAAPI_OBJECT_ID(window); +} + +/** + * gst_vaapi_window_x11_is_foreign_xid: + * @window: a #GstVaapiWindowX11 + * + * Checks whether the @window XID was created by gst_vaapi_window_x11_new() or bound with gst_vaapi_window_x11_new_with_xid(). + * + * Return value: %TRUE if the underlying X window is owned by the + * caller (foreign window) + */ +gboolean +gst_vaapi_window_x11_is_foreign_xid(GstVaapiWindowX11 *window) +{ + g_return_val_if_fail(GST_VAAPI_IS_WINDOW_X11(window), FALSE); + + return !window->priv->create_window; +} + +/** + * gst_vaapi_window_x11_is_pixmap: + * @window: a #GstVaapiWindowX11 + * + * Checks whether the @window XID is Pixmap or Window + * + * Return value: %TRUE if the underlying X Drawble is Pixmap + */ +gboolean +gst_vaapi_window_x11_is_pixmap(GstVaapiWindowX11 *window) +{ + g_return_val_if_fail(GST_VAAPI_IS_WINDOW_X11(window), FALSE); + + return window->priv->is_pixmap; +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_x11.h b/gst-libs/gst/vaapi/gstvaapiwindow_x11.h new file mode 100644 index 0000000..b5ea9ff --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_x11.h @@ -0,0 +1,114 @@ +/* + * gstvaapiwindow_x11.h - VA/X11 window abstraction + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_X11_H +#define GST_VAAPI_WINDOW_X11_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_WINDOW_X11 \ + (gst_vaapi_window_x11_get_type()) + +#define GST_VAAPI_WINDOW_X11(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_WINDOW_X11, \ + GstVaapiWindowX11)) + +#define GST_VAAPI_WINDOW_X11_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_WINDOW_X11, \ + GstVaapiWindowX11Class)) + +#define GST_VAAPI_IS_WINDOW_X11(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_WINDOW_X11)) + +#define GST_VAAPI_IS_WINDOW_X11_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_WINDOW_X11)) + +#define GST_VAAPI_WINDOW_X11_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_WINDOW_X11, \ + GstVaapiWindowX11Class)) + +/** + * GST_VAAPI_WINDOW_XWINDOW: + * @window: a #GstVaapiWindow + * + * Macro that evaluates to the underlying X11 #Window of @window + */ +#define GST_VAAPI_WINDOW_XWINDOW(window) \ + gst_vaapi_window_x11_get_xid(GST_VAAPI_WINDOW_X11(window)) + +typedef struct _GstVaapiWindowX11 GstVaapiWindowX11; +typedef struct _GstVaapiWindowX11Private GstVaapiWindowX11Private; +typedef struct _GstVaapiWindowX11Class GstVaapiWindowX11Class; + +/** + * GstVaapiWindowX11: + * + * An X11 #Window wrapper. + */ +struct _GstVaapiWindowX11 { + /*< private >*/ + GstVaapiWindow parent_instance; + + GstVaapiWindowX11Private *priv; +}; + +/** + * GstVaapiWindowX11Class: + * @get_visual: virtual function to get the desired visual used to + * create the window + * @get_colormap: virtual function to get the desired colormap used to + * create the window + * + * An X11 #Window wrapper class. + */ +struct _GstVaapiWindowX11Class { + /*< private >*/ + GstVaapiWindowClass parent_class; + + Visual * (*get_visual) (GstVaapiWindow *window); + Colormap (*get_colormap) (GstVaapiWindow *window); +}; + +GType +gst_vaapi_window_x11_get_type(void) G_GNUC_CONST; + +GstVaapiWindow * +gst_vaapi_window_x11_new(GstVaapiDisplay *display, guint width, guint height); + +GstVaapiWindow * +gst_vaapi_window_x11_new_with_xid(GstVaapiDisplay *display, Window xid, gboolean is_pixmap); + +Window +gst_vaapi_window_x11_get_xid(GstVaapiWindowX11 *window); + +gboolean +gst_vaapi_window_x11_is_foreign_xid(GstVaapiWindowX11 *window); + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_X11_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiworkarounds.h b/gst-libs/gst/vaapi/gstvaapiworkarounds.h new file mode 100644 index 0000000..a7276f4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiworkarounds.h @@ -0,0 +1,41 @@ +/* + * gstvaapiworkaround.h - GStreamer/VA workarounds + * + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WORKAROUNDS_H +#define GST_VAAPI_WORKAROUNDS_H + +G_BEGIN_DECLS + +/* + * Workaround to expose H.263 Baseline decode profile for drivers that + * support MPEG-4:2 Simple profile decoding. + */ +#define WORKAROUND_H263_BASELINE_DECODE_PROFILE (1) + +/* + * Workaround for qtdemux that does not report profiles for + * video/x-h263. Assume H.263 Baseline profile in this case. + */ +#define WORKAROUND_QTDEMUX_NO_H263_PROFILES (1) + +G_END_DECLS + +#endif /* GST_VAAPI_WORKAROUNDS_H */ diff --git a/gst-libs/gst/vaapi/sysdeps.h b/gst-libs/gst/vaapi/sysdeps.h new file mode 100644 index 0000000..c8be890 --- /dev/null +++ b/gst-libs/gst/vaapi/sysdeps.h @@ -0,0 +1,31 @@ +/* + * sysdeps.h - System-dependent definitions + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef SYSDEPS_H +#define SYSDEPS_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "glibcompat.h" + +#endif /* SYSDEPS_H */ diff --git a/gst/Makefile.am b/gst/Makefile.am new file mode 100644 index 0000000..37d365d --- /dev/null +++ b/gst/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = vaapi + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/gst/vaapi/Makefile.am b/gst/vaapi/Makefile.am new file mode 100644 index 0000000..ebe46bb --- /dev/null +++ b/gst/vaapi/Makefile.am @@ -0,0 +1,91 @@ +plugin_LTLIBRARIES = libgstvaapi.la + +libgstvaapi_CFLAGS = \ + $(LIBVA_CFLAGS) \ + -DGST_USE_UNSTABLE_API \ + -I$(top_srcdir)/gst-libs \ + -I$(top_builddir)/gst-libs \ + $(NULL) + +libgstvaapi_LIBS = + +if USE_DRM +libgstvaapi_LIBS += \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-drm-$(GST_MAJORMINOR).la +endif + +if USE_X11 +libgstvaapi_LIBS += \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-x11-$(GST_MAJORMINOR).la +endif + +if USE_GLX +libgstvaapi_LIBS += \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-glx-$(GST_MAJORMINOR).la +endif + +if USE_WAYLAND +libgstvaapi_LIBS += \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-wayland-$(GST_MAJORMINOR).la +endif + +libgstvaapi_la_SOURCES = \ + gstvaapi.c \ + gstvaapidecode.c \ + gstvaapidownload.c \ + gstvaapipluginbuffer.c \ + gstvaapipluginutil.c \ + gstvaapipostproc.c \ + gstvaapisink.c \ + gstvaapiupload.c \ + $(NULL) + +noinst_HEADERS = \ + gstvaapidecode.h \ + gstvaapidownload.h \ + gstvaapipluginbuffer.h \ + gstvaapipluginutil.h \ + gstvaapipostproc.h \ + gstvaapisink.h \ + gstvaapiupload.h \ + $(NULL) + +if USE_ENCODERS +libgstvaapi_la_SOURCES += \ + gstvaapiencode.c \ + gstvaapiencode_h264.c \ + gstvaapiencode_h263.c \ + gstvaapiencode_mpeg4.c \ + $(NULL) + +noinst_HEADERS += \ + gstvaapiencode.h \ + gstvaapiencode_h264.h \ + gstvaapiencode_h263.h \ + gstvaapiencode_mpeg4.h \ + $(NULL) +endif + +libgstvaapi_la_CFLAGS = \ + $(libgstvaapi_CFLAGS) \ + $(GST_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_VIDEO_CFLAGS) \ + $(GST_INTERFACES_CFLAGS) \ + $(GST_BASEVIDEO_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) + +libgstvaapi_la_LIBADD = \ + $(libgstvaapi_LIBS) \ + $(GST_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_VIDEO_LIBS) \ + $(GST_INTERFACES_LIBS) \ + $(GST_BASEVIDEO_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) + +libgstvaapi_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstvaapi_la_LIBTOOLFLAGS = --tag=disable-static + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/gst/vaapi/gstvaapi.c b/gst/vaapi/gstvaapi.c new file mode 100644 index 0000000..4bd442b --- /dev/null +++ b/gst/vaapi/gstvaapi.c @@ -0,0 +1,90 @@ +/* + * gstvaapi.c - VA-API element registration + * + * Copyright (C) 2011-2012 Intel Corporation + * Copyright (C) 2011 Collabora Ltd. + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "gstvaapidownload.h" +#include "gstvaapiupload.h" +#include "gstvaapidecode.h" +#include "gstvaapipostproc.h" +#include "gstvaapisink.h" + +#if USE_ENCODERS +#include "gstvaapiencode.h" +#include "gstvaapiencode_h264.h" +#include "gstvaapiencode_h263.h" +#include "gstvaapiencode_mpeg4.h" + +/* encoder plugin register*/ +static gboolean +vaapi_encoder_plugins_init (GstPlugin * plugin) +{ + gboolean ret = TRUE; + + ret &= gst_element_register (plugin, "vaapiencodeh264", GST_RANK_PRIMARY, + GST_TYPE_VAAPI_ENCODE_H264); + ret &= gst_element_register (plugin, "vaapiencodeh263", GST_RANK_PRIMARY, + GST_TYPE_VAAPI_ENCODE_H263); + ret &= gst_element_register (plugin, "vaapiencodempeg4", GST_RANK_PRIMARY, + GST_TYPE_VAAPI_ENCODE_MPEG4); + return ret; +} +#endif + +static gboolean +plugin_init (GstPlugin *plugin) +{ + gst_element_register(plugin, "vaapidownload", + GST_RANK_SECONDARY, + GST_TYPE_VAAPIDOWNLOAD); + gst_element_register(plugin, "vaapiupload", + GST_RANK_PRIMARY, + GST_TYPE_VAAPIUPLOAD); + gst_element_register(plugin, "vaapidecode", + GST_RANK_PRIMARY, + GST_TYPE_VAAPIDECODE); + gst_element_register(plugin, "vaapipostproc", + GST_RANK_PRIMARY, + GST_TYPE_VAAPIPOSTPROC); + gst_element_register(plugin, "vaapisink", + GST_RANK_PRIMARY, + GST_TYPE_VAAPISINK); +#if USE_ENCODERS + return vaapi_encoder_plugins_init(plugin); +#endif + return TRUE; +} + +GST_PLUGIN_DEFINE( + GST_VERSION_MAJOR, GST_VERSION_MINOR, + "vaapi", + "VA-API based elements", + plugin_init, + PACKAGE_VERSION, + "LGPL", + PACKAGE, + PACKAGE_BUGREPORT); diff --git a/gst/vaapi/gstvaapidecode.c b/gst/vaapi/gstvaapidecode.c new file mode 100644 index 0000000..3647d4c --- /dev/null +++ b/gst/vaapi/gstvaapidecode.c @@ -0,0 +1,790 @@ +/* + * gstvaapidecode.c - VA-API video decoder + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +/** + * SECTION:gstvaapidecode + * @short_description: A VA-API based video decoder + * + * vaapidecode decodes from raw bitstreams to surfaces suitable for + * the vaapisink element. + */ + +#include "config.h" + +#include +#include +#include + +#include "gstvaapidecode.h" +#include "gstvaapipluginutil.h" +#include "gstvaapipluginbuffer.h" + +#include +#include +#include +#include +#include + +#define GST_PLUGIN_NAME "vaapidecode" +#define GST_PLUGIN_DESC "A VA-API based video decoder" + +GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidecode); +#define GST_CAT_DEFAULT gst_debug_vaapidecode + +/* ElementFactory information */ +static const GstElementDetails gst_vaapidecode_details = + GST_ELEMENT_DETAILS( + "VA-API decoder", + "Codec/Decoder/Video", + GST_PLUGIN_DESC, + "Gwenole Beauchesne "); + +/* Default templates */ +#define GST_CAPS_CODEC(CODEC) CODEC "; " + +static const char gst_vaapidecode_sink_caps_str[] = + GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false") + GST_CAPS_CODEC("video/mpeg, mpegversion=4") + GST_CAPS_CODEC("video/x-divx") + GST_CAPS_CODEC("video/x-xvid") + GST_CAPS_CODEC("video/x-h263") + GST_CAPS_CODEC("video/x-h264") + GST_CAPS_CODEC("video/x-wmv") + GST_CAPS_CODEC("image/jpeg") + ; + +static const char gst_vaapidecode_src_caps_str[] = + GST_VAAPI_SURFACE_CAPS; + +static GstStaticPadTemplate gst_vaapidecode_sink_factory = + GST_STATIC_PAD_TEMPLATE( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapidecode_sink_caps_str)); + +static GstStaticPadTemplate gst_vaapidecode_src_factory = + GST_STATIC_PAD_TEMPLATE( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapidecode_src_caps_str)); + +static void +gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface); + +static void +gst_video_context_interface_init(GstVideoContextInterface *iface); + +#define GstVideoContextClass GstVideoContextInterface +G_DEFINE_TYPE_WITH_CODE( + GstVaapiDecode, + gst_vaapidecode, + GST_TYPE_ELEMENT, + G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE, + gst_vaapidecode_implements_iface_init); + G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT, + gst_video_context_interface_init)); + +static gboolean +gst_vaapidecode_update_src_caps(GstVaapiDecode *decode, GstCaps *caps); + +static void +gst_vaapi_decoder_notify_caps(GObject *obj, GParamSpec *pspec, void *user_data) +{ + GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data); + GstCaps *caps; + + g_assert(decode->decoder == GST_VAAPI_DECODER(obj)); + + caps = gst_vaapi_decoder_get_caps(decode->decoder); + gst_vaapidecode_update_src_caps(decode, caps); +} + +static inline gboolean +gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps) +{ + if (decode->sinkpad_caps) + gst_caps_unref(decode->sinkpad_caps); + decode->sinkpad_caps = gst_caps_ref(caps); + return TRUE; +} + +static gboolean +gst_vaapidecode_update_src_caps(GstVaapiDecode *decode, GstCaps *caps) +{ + GstCaps *other_caps; + GstStructure *structure; + const GValue *v_width, *v_height, *v_framerate, *v_par, *v_interlaced; + gboolean success; + + if (!decode->srcpad_caps) { + decode->srcpad_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME); + if (!decode->srcpad_caps) + return FALSE; + } + + structure = gst_caps_get_structure(caps, 0); + v_width = gst_structure_get_value(structure, "width"); + v_height = gst_structure_get_value(structure, "height"); + v_framerate = gst_structure_get_value(structure, "framerate"); + v_par = gst_structure_get_value(structure, "pixel-aspect-ratio"); + v_interlaced = gst_structure_get_value(structure, "interlaced"); + + structure = gst_caps_get_structure(decode->srcpad_caps, 0); + if (v_width && v_height) { + gst_structure_set_value(structure, "width", v_width); + gst_structure_set_value(structure, "height", v_height); + } + if (v_framerate) + gst_structure_set_value(structure, "framerate", v_framerate); + if (v_par) + gst_structure_set_value(structure, "pixel-aspect-ratio", v_par); + if (v_interlaced) + gst_structure_set_value(structure, "interlaced", v_interlaced); + + gst_structure_set(structure, "type", G_TYPE_STRING, "vaapi", NULL); + gst_structure_set(structure, "opengl", G_TYPE_BOOLEAN, USE_GLX, NULL); + + other_caps = gst_caps_copy(decode->srcpad_caps); + success = gst_pad_set_caps(decode->srcpad, other_caps); + gst_caps_unref(other_caps); + return success; +} + +static void +gst_vaapidecode_release(GstVaapiDecode *decode, GObject *dead_object) +{ + g_mutex_lock(decode->decoder_mutex); + g_cond_signal(decode->decoder_ready); + g_mutex_unlock(decode->decoder_mutex); +} + +static gboolean +gst_vaapidecode_is_valid_time(GstVaapiDecode *decode, gint64 time) +{ + if (decode->segment.format != GST_FORMAT_TIME) + return TRUE; + if (decode->segment.stop != -1 && time != -1 && time > decode->segment.stop) + return FALSE; + if (decode->segment.start != -1 && time != -1 && time < decode->segment.start) + return FALSE; + + return TRUE; +} + +static GstFlowReturn +gst_vaapidecode_step(GstVaapiDecode *decode) +{ + GstVaapiSurfaceProxy *proxy; + GstVaapiDecoderStatus status; + GstBuffer *buffer; + GstClockTime timestamp; + GstFlowReturn ret; + guint tries; + + for (;;) { + tries = 0; + again: + proxy = gst_vaapi_decoder_get_surface(decode->decoder, &status); + if (!proxy) { + if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) { + /* Wait for a VA surface to be displayed and free'd */ + if (++tries > 100) + goto error_decode_timeout; + GTimeVal timeout; + g_get_current_time(&timeout); + g_time_val_add(&timeout, 10000); /* 10 ms each step */ + g_mutex_lock(decode->decoder_mutex); + g_cond_timed_wait( + decode->decoder_ready, + decode->decoder_mutex, + &timeout + ); + g_mutex_unlock(decode->decoder_mutex); + goto again; + } + if (status != GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA) + goto error_decode; + /* More data is needed */ + break; + } + + timestamp = GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy); + if (GST_CLOCK_TIME_IS_VALID(timestamp) && + !gst_vaapidecode_is_valid_time(decode, (gint64)timestamp)) { + g_object_unref(proxy); + continue; + } + + g_object_weak_ref( + G_OBJECT(proxy), + (GWeakNotify)gst_vaapidecode_release, + decode + ); + + buffer = gst_vaapi_video_buffer_new(decode->display); + if (!buffer) + goto error_create_buffer; + + GST_BUFFER_TIMESTAMP(buffer) = timestamp; + gst_buffer_set_caps(buffer, GST_PAD_CAPS(decode->srcpad)); + + if (GST_VAAPI_SURFACE_PROXY_TFF(proxy)) + GST_BUFFER_FLAG_SET(buffer, GST_VIDEO_BUFFER_TFF); + + gst_vaapi_video_buffer_set_surface_proxy( + GST_VAAPI_VIDEO_BUFFER(buffer), + proxy + ); + + ret = gst_pad_push(decode->srcpad, buffer); + if (ret != GST_FLOW_OK) + goto error_commit_buffer; + + g_object_unref(proxy); + } + return GST_FLOW_OK; + + /* ERRORS */ +error_decode_timeout: + { + GST_DEBUG("decode timeout. Decoder required a VA surface but none " + "got available within one second"); + return GST_FLOW_UNEXPECTED; + } +error_decode: + { + GST_DEBUG("decode error %d", status); + switch (status) { + case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC: + case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE: + case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT: + ret = GST_FLOW_NOT_SUPPORTED; + break; + default: + ret = GST_FLOW_UNEXPECTED; + break; + } + return ret; + } +error_create_buffer: + { + const GstVaapiID surface_id = + gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy)); + + GST_DEBUG("video sink failed to create video buffer for proxy'ed " + "surface %" GST_VAAPI_ID_FORMAT " (error %d)", + GST_VAAPI_ID_ARGS(surface_id), ret); + g_object_unref(proxy); + return GST_FLOW_UNEXPECTED; + } +error_commit_buffer: + { + GST_DEBUG("video sink rejected the video buffer (error %d)", ret); + g_object_unref(proxy); + return GST_FLOW_UNEXPECTED; + } +} + +static inline gboolean +gst_vaapidecode_ensure_display(GstVaapiDecode *decode) +{ + return gst_vaapi_ensure_display(decode, GST_VAAPI_DISPLAY_TYPE_ANY, + &decode->display); +} + +static gboolean +gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps) +{ + GstVaapiDisplay *dpy; + GstStructure *structure; + int version; + + if (!gst_vaapidecode_ensure_display(decode)) + return FALSE; + dpy = decode->display; + + decode->decoder_mutex = g_mutex_new(); + if (!decode->decoder_mutex) + return FALSE; + + decode->decoder_ready = g_cond_new(); + if (!decode->decoder_ready) + return FALSE; + + structure = gst_caps_get_structure(caps, 0); + if (!structure) + return FALSE; + + if (gst_structure_has_name(structure, "video/x-h264")) + decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps); + else if (gst_structure_has_name(structure, "video/mpeg")) { + if (!gst_structure_get_int(structure, "mpegversion", &version)) + return FALSE; + if (version == 2) + decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps); + else if (version == 4) + decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps); + } + else if (gst_structure_has_name(structure, "video/x-wmv")) + decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps); + else if (gst_structure_has_name(structure, "video/x-h263") || + gst_structure_has_name(structure, "video/x-divx") || + gst_structure_has_name(structure, "video/x-xvid")) + decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps); +#if USE_JPEG_DECODER + else if (gst_structure_has_name(structure, "image/jpeg")) + decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps); +#endif + if (!decode->decoder) + return FALSE; + + g_signal_connect( + G_OBJECT(decode->decoder), + "notify::caps", + G_CALLBACK(gst_vaapi_decoder_notify_caps), + decode + ); + + decode->decoder_caps = gst_caps_ref(caps); + return TRUE; +} + +static void +gst_vaapidecode_destroy(GstVaapiDecode *decode) +{ + if (decode->decoder) { + gst_vaapi_decoder_put_buffer(decode->decoder, NULL); + g_object_unref(decode->decoder); + decode->decoder = NULL; + } + + if (decode->decoder_caps) { + gst_caps_unref(decode->decoder_caps); + decode->decoder_caps = NULL; + } + + if (decode->decoder_ready) { + gst_vaapidecode_release(decode, NULL); + g_cond_free(decode->decoder_ready); + decode->decoder_ready = NULL; + } + + if (decode->decoder_mutex) { + g_mutex_free(decode->decoder_mutex); + decode->decoder_mutex = NULL; + } +} + +static gboolean +gst_vaapidecode_reset(GstVaapiDecode *decode, GstCaps *caps) +{ + if (decode->decoder && + decode->decoder_caps && + gst_caps_is_always_compatible(caps, decode->decoder_caps)) + return TRUE; + + gst_vaapidecode_destroy(decode); + return gst_vaapidecode_create(decode, caps); +} + +static void +gst_vaapidecode_configure_segment( + GstVaapiDecode *decode, + GstEvent *event +) +{ + gboolean update; + gdouble rate, applied_rate; + GstFormat format; + gint64 start, stop, time; + + gst_event_parse_new_segment_full(event, &update, &rate, &applied_rate, + &format, &start, &stop, &time); + if (format == GST_FORMAT_TIME) { + gst_segment_set_newsegment_full(&decode->segment, update, rate, applied_rate, + format, start, stop, time); + GST_DEBUG("configured new segment, update %d, rate %lf, applied rate %lf, " + "format GST_FORMAT_TIME, " + "start %" GST_TIME_FORMAT ", stop %" GST_TIME_FORMAT ", " + "time %" GST_TIME_FORMAT, + update, rate, applied_rate, + GST_TIME_ARGS(start), GST_TIME_ARGS(stop), + GST_TIME_ARGS(time)); + } +} + +/* GstImplementsInterface interface */ + +static gboolean +gst_vaapidecode_implements_interface_supported( + GstImplementsInterface *iface, + GType type +) +{ + return (type == GST_TYPE_VIDEO_CONTEXT); +} + +static void +gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface) +{ + iface->supported = gst_vaapidecode_implements_interface_supported; +} + +/* GstVideoContext interface */ + +static void +gst_vaapidecode_set_video_context(GstVideoContext *context, const gchar *type, + const GValue *value) +{ + GstVaapiDecode *decode = GST_VAAPIDECODE (context); + gst_vaapi_set_display (type, value, &decode->display); +} + +static void +gst_video_context_interface_init(GstVideoContextInterface *iface) +{ + iface->set_context = gst_vaapidecode_set_video_context; +} + +static void +gst_vaapidecode_finalize(GObject *object) +{ + GstVaapiDecode * const decode = GST_VAAPIDECODE(object); + + gst_vaapidecode_destroy(decode); + + if (decode->sinkpad_caps) { + gst_caps_unref(decode->sinkpad_caps); + decode->sinkpad_caps = NULL; + } + + if (decode->srcpad_caps) { + gst_caps_unref(decode->srcpad_caps); + decode->srcpad_caps = NULL; + } + + g_clear_object(&decode->display); + + if (decode->allowed_caps) { + gst_caps_unref(decode->allowed_caps); + decode->allowed_caps = NULL; + } + + if (decode->delayed_new_seg) { + gst_event_unref(decode->delayed_new_seg); + decode->delayed_new_seg = NULL; + } + + G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object); +} + +static GstStateChangeReturn +gst_vaapidecode_change_state(GstElement *element, GstStateChange transition) +{ + GstVaapiDecode * const decode = GST_VAAPIDECODE(element); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + decode->is_ready = TRUE; + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS(gst_vaapidecode_parent_class)->change_state(element, transition); + if (ret != GST_STATE_CHANGE_SUCCESS) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + gst_vaapidecode_destroy(decode); + g_clear_object(&decode->display); + decode->is_ready = FALSE; + break; + default: + break; + } + return GST_STATE_CHANGE_SUCCESS; +} + +static void +gst_vaapidecode_class_init(GstVaapiDecodeClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + GstPadTemplate *pad_template; + + GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode, + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); + + object_class->finalize = gst_vaapidecode_finalize; + + element_class->change_state = gst_vaapidecode_change_state; + + gst_element_class_set_details_simple( + element_class, + gst_vaapidecode_details.longname, + gst_vaapidecode_details.klass, + gst_vaapidecode_details.description, + gst_vaapidecode_details.author + ); + + /* sink pad */ + pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory); + gst_element_class_add_pad_template(element_class, pad_template); + gst_object_unref(pad_template); + + /* src pad */ + pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory); + gst_element_class_add_pad_template(element_class, pad_template); + gst_object_unref(pad_template); +} + +static gboolean +gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode) +{ + GstCaps *decode_caps; + guint i, n_decode_caps; + + if (decode->allowed_caps) + return TRUE; + + if (!gst_vaapidecode_ensure_display(decode)) + goto error_no_display; + + decode_caps = gst_vaapi_display_get_decode_caps(decode->display); + if (!decode_caps) + goto error_no_decode_caps; + n_decode_caps = gst_caps_get_size(decode_caps); + + decode->allowed_caps = gst_caps_new_empty(); + if (!decode->allowed_caps) + goto error_no_memory; + + for (i = 0; i < n_decode_caps; i++) { + GstStructure *structure; + structure = gst_caps_get_structure(decode_caps, i); + if (!structure) + continue; + structure = gst_structure_copy(structure); + if (!structure) + continue; + gst_structure_remove_field(structure, "profile"); + gst_structure_set( + structure, + "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, + NULL + ); + gst_caps_merge_structure(decode->allowed_caps, structure); + } + + gst_caps_unref(decode_caps); + return TRUE; + + /* ERRORS */ +error_no_display: + { + GST_DEBUG("failed to retrieve VA display"); + return FALSE; + } +error_no_decode_caps: + { + GST_DEBUG("failed to retrieve VA decode caps"); + return FALSE; + } +error_no_memory: + { + GST_DEBUG("failed to allocate allowed-caps set"); + gst_caps_unref(decode_caps); + return FALSE; + } +} + +static GstCaps * +gst_vaapidecode_get_caps(GstPad *pad) +{ + GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad)); + + if (!decode->is_ready) + return gst_static_pad_template_get_caps(&gst_vaapidecode_sink_factory); + + if (!gst_vaapidecode_ensure_allowed_caps(decode)) + return gst_caps_new_empty(); + + return gst_caps_ref(decode->allowed_caps); +} + +static gboolean +gst_vaapidecode_set_caps(GstPad *pad, GstCaps *caps) +{ + GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad)); + + g_return_val_if_fail(pad == decode->sinkpad, FALSE); + + if (!gst_vaapidecode_update_sink_caps(decode, caps)) + return FALSE; + if (!gst_vaapidecode_update_src_caps(decode, caps)) + return FALSE; + if (!gst_vaapidecode_reset(decode, decode->sinkpad_caps)) + return FALSE; + + /* Propagate NEWSEGMENT event downstream, now that pads are linked */ + if (decode->delayed_new_seg) { + if (gst_pad_push_event(decode->srcpad, decode->delayed_new_seg)) + gst_event_unref(decode->delayed_new_seg); + decode->delayed_new_seg = NULL; + } + return TRUE; +} + +static GstFlowReturn +gst_vaapidecode_chain(GstPad *pad, GstBuffer *buf) +{ + GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad)); + + if (!gst_vaapi_decoder_put_buffer(decode->decoder, buf)) + goto error_push_buffer; + + gst_buffer_unref(buf); + return gst_vaapidecode_step(decode); + + /* ERRORS */ +error_push_buffer: + { + GST_DEBUG("failed to push input buffer to decoder"); + gst_buffer_unref(buf); + return GST_FLOW_UNEXPECTED; + } +} + +static gboolean +gst_vaapidecode_sink_event(GstPad *pad, GstEvent *event) +{ + GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad)); + + GST_DEBUG("handle sink event '%s'", GST_EVENT_TYPE_NAME(event)); + + /* Propagate event downstream */ + switch (GST_EVENT_TYPE(event)) { + case GST_EVENT_FLUSH_STOP: + gst_segment_init(&decode->segment, GST_FORMAT_UNDEFINED); + if (decode->decoder) + gst_vaapi_decoder_clear_buffer(decode->decoder); + break; + case GST_EVENT_NEWSEGMENT: + if (decode->delayed_new_seg) { + gst_event_unref(decode->delayed_new_seg); + decode->delayed_new_seg = NULL; + } + if (!GST_PAD_PEER(decode->srcpad)) { + decode->delayed_new_seg = gst_event_ref(event); + return TRUE; + } + gst_vaapidecode_configure_segment(decode, event); + break; + default: + break; + } + return gst_pad_push_event(decode->srcpad, event); +} + +static gboolean +gst_vaapidecode_src_event(GstPad *pad, GstEvent *event) +{ + GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad)); + + GST_DEBUG("handle src event '%s'", GST_EVENT_TYPE_NAME(event)); + + /* Propagate event upstream */ + return gst_pad_push_event(decode->sinkpad, event); +} + +static gboolean +gst_vaapidecode_query (GstPad *pad, GstQuery *query) { + GstVaapiDecode *decode = GST_VAAPIDECODE (gst_pad_get_parent_element (pad)); + gboolean res; + + GST_DEBUG ("sharing display %p", decode->display); + + if (gst_vaapi_reply_to_query (query, decode->display)) + res = TRUE; + else + res = gst_pad_query_default (pad, query); + + g_object_unref (decode); + return res; +} + +static void +gst_vaapidecode_init(GstVaapiDecode *decode) +{ + GstVaapiDecodeClass *klass = GST_VAAPIDECODE_GET_CLASS(decode); + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + + decode->display = NULL; + decode->decoder = NULL; + decode->decoder_mutex = NULL; + decode->decoder_ready = NULL; + decode->decoder_caps = NULL; + decode->allowed_caps = NULL; + decode->delayed_new_seg = NULL; + decode->is_ready = FALSE; + gst_segment_init(&decode->segment, GST_FORMAT_UNDEFINED); + + /* Pad through which data comes in to the element */ + decode->sinkpad = gst_pad_new_from_template( + gst_element_class_get_pad_template(element_class, "sink"), + "sink" + ); + decode->sinkpad_caps = NULL; + + gst_pad_set_getcaps_function(decode->sinkpad, gst_vaapidecode_get_caps); + gst_pad_set_setcaps_function(decode->sinkpad, gst_vaapidecode_set_caps); + gst_pad_set_chain_function(decode->sinkpad, gst_vaapidecode_chain); + gst_pad_set_event_function(decode->sinkpad, gst_vaapidecode_sink_event); + gst_pad_set_query_function(decode->sinkpad, gst_vaapidecode_query); + gst_element_add_pad(GST_ELEMENT(decode), decode->sinkpad); + + /* Pad through which data goes out of the element */ + decode->srcpad = gst_pad_new_from_template( + gst_element_class_get_pad_template(element_class, "src"), + "src" + ); + decode->srcpad_caps = NULL; + + gst_pad_use_fixed_caps(decode->srcpad); + gst_pad_set_event_function(decode->srcpad, gst_vaapidecode_src_event); + gst_pad_set_query_function(decode->srcpad, gst_vaapidecode_query); + gst_element_add_pad(GST_ELEMENT(decode), decode->srcpad); +} diff --git a/gst/vaapi/gstvaapidecode.h b/gst/vaapi/gstvaapidecode.h new file mode 100644 index 0000000..6d22507 --- /dev/null +++ b/gst/vaapi/gstvaapidecode.h @@ -0,0 +1,89 @@ +/* + * gstvaapidecode.h - VA-API video decoder + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPIDECODE_H +#define GST_VAAPIDECODE_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIDECODE \ + (gst_vaapidecode_get_type()) + +#define GST_VAAPIDECODE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_TYPE_VAAPIDECODE, \ + GstVaapiDecode)) + +#define GST_VAAPIDECODE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_TYPE_VAAPIDECODE, \ + GstVaapiDecodeClass)) + +#define GST_IS_VAAPIDECODE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VAAPIDECODE)) + +#define GST_IS_VAAPIDECODE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VAAPIDECODE)) + +#define GST_VAAPIDECODE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_TYPE_VAAPIDECODE, \ + GstVaapiDecodeClass)) + +typedef struct _GstVaapiDecode GstVaapiDecode; +typedef struct _GstVaapiDecodeClass GstVaapiDecodeClass; + +struct _GstVaapiDecode { + /*< private >*/ + GstElement parent_instance; + + GstPad *sinkpad; + GstCaps *sinkpad_caps; + GstPad *srcpad; + GstCaps *srcpad_caps; + GstVaapiDisplay *display; + GstVaapiDecoder *decoder; + GMutex *decoder_mutex; + GCond *decoder_ready; + GstCaps *decoder_caps; + GstCaps *allowed_caps; + GstEvent *delayed_new_seg; + GstSegment segment; + unsigned int is_ready : 1; +}; + +struct _GstVaapiDecodeClass { + /*< private >*/ + GstElementClass parent_class; +}; + +GType +gst_vaapidecode_get_type(void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* GST_VAAPIDECODE_H */ diff --git a/gst/vaapi/gstvaapidownload.c b/gst/vaapi/gstvaapidownload.c new file mode 100644 index 0000000..56ae902 --- /dev/null +++ b/gst/vaapi/gstvaapidownload.c @@ -0,0 +1,620 @@ +/* + * gstvaapidownload.c - VA-API video downloader + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidownload + * @short_description: A VA to video flow filter + * + * vaapidownload converts from VA surfaces to raw YUV pixels. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "gstvaapidownload.h" +#include "gstvaapipluginutil.h" +#include "gstvaapipluginbuffer.h" + +#define GST_PLUGIN_NAME "vaapidownload" +#define GST_PLUGIN_DESC "A VA to video flow filter" + +GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidownload); +#define GST_CAT_DEFAULT gst_debug_vaapidownload + +/* ElementFactory information */ +static const GstElementDetails gst_vaapidownload_details = + GST_ELEMENT_DETAILS( + "VA-API colorspace converter", + "Filter/Converter/Video", + GST_PLUGIN_DESC, + "Gwenole Beauchesne "); + +/* Default templates */ +static const char gst_vaapidownload_yuv_caps_str[] = + "video/x-raw-yuv, " + "width = (int) [ 1, MAX ], " + "height = (int) [ 1, MAX ]; "; + +static const char gst_vaapidownload_vaapi_caps_str[] = + GST_VAAPI_SURFACE_CAPS; + +static GstStaticPadTemplate gst_vaapidownload_sink_factory = + GST_STATIC_PAD_TEMPLATE( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapidownload_vaapi_caps_str)); + +static GstStaticPadTemplate gst_vaapidownload_src_factory = + GST_STATIC_PAD_TEMPLATE( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapidownload_yuv_caps_str)); + +typedef struct _TransformSizeCache TransformSizeCache; +struct _TransformSizeCache { + GstCaps *caps; + guint size; +}; + +struct _GstVaapiDownload { + /*< private >*/ + GstBaseTransform parent_instance; + + GstVaapiDisplay *display; + GstCaps *allowed_caps; + TransformSizeCache transform_size_cache[2]; + GstVaapiVideoPool *images; + GstVaapiImageFormat image_format; + guint image_width; + guint image_height; + unsigned int images_reset : 1; +}; + +struct _GstVaapiDownloadClass { + /*< private >*/ + GstBaseTransformClass parent_class; +}; + +static void +gst_vaapidownload_implements_iface_init(GstImplementsInterfaceClass *iface); + +static void +gst_video_context_interface_init(GstVideoContextInterface *iface); + +#define GstVideoContextClass GstVideoContextInterface +G_DEFINE_TYPE_WITH_CODE( + GstVaapiDownload, + gst_vaapidownload, + GST_TYPE_BASE_TRANSFORM, + G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE, + gst_vaapidownload_implements_iface_init); + G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT, + gst_video_context_interface_init)); + +static gboolean +gst_vaapidownload_start(GstBaseTransform *trans); + +static gboolean +gst_vaapidownload_stop(GstBaseTransform *trans); + +static void +gst_vaapidownload_before_transform(GstBaseTransform *trans, GstBuffer *buffer); + +static GstFlowReturn +gst_vaapidownload_transform( + GstBaseTransform *trans, + GstBuffer *inbuf, + GstBuffer *outbuf +); + +static GstCaps * +gst_vaapidownload_transform_caps( + GstBaseTransform *trans, + GstPadDirection direction, + GstCaps *caps +); + +static gboolean +gst_vaapidownload_transform_size( + GstBaseTransform *trans, + GstPadDirection direction, + GstCaps *caps, + guint size, + GstCaps *othercaps, + guint *othersize +); + +static gboolean +gst_vaapidownload_set_caps( + GstBaseTransform *trans, + GstCaps *incaps, + GstCaps *outcaps +); + +static gboolean +gst_vaapidownload_query( + GstPad *pad, + GstQuery *query +); + +/* GstImplementsInterface interface */ + +static gboolean +gst_vaapidownload_implements_interface_supported( + GstImplementsInterface *iface, + GType type +) +{ + return (type == GST_TYPE_VIDEO_CONTEXT); +} + +static void +gst_vaapidownload_implements_iface_init(GstImplementsInterfaceClass *iface) +{ + iface->supported = gst_vaapidownload_implements_interface_supported; +} + +/* GstVideoContext interface */ + +static void +gst_vaapidownload_set_video_context(GstVideoContext *context, const gchar *type, + const GValue *value) +{ + GstVaapiDownload *download = GST_VAAPIDOWNLOAD (context); + gst_vaapi_set_display (type, value, &download->display); +} + +static void +gst_video_context_interface_init(GstVideoContextInterface *iface) +{ + iface->set_context = gst_vaapidownload_set_video_context; +} + +static void +gst_vaapidownload_destroy(GstVaapiDownload *download) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS(download->transform_size_cache); i++) { + TransformSizeCache * const tsc = &download->transform_size_cache[i]; + if (tsc->caps) { + gst_caps_unref(tsc->caps); + tsc->caps = NULL; + tsc->size = 0; + } + } + + if (download->allowed_caps) { + gst_caps_unref(download->allowed_caps); + download->allowed_caps = NULL; + } + + g_clear_object(&download->images); + g_clear_object(&download->display); +} + +static void +gst_vaapidownload_finalize(GObject *object) +{ + gst_vaapidownload_destroy(GST_VAAPIDOWNLOAD(object)); + + G_OBJECT_CLASS(gst_vaapidownload_parent_class)->finalize(object); +} + +static void +gst_vaapidownload_class_init(GstVaapiDownloadClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstBaseTransformClass * const trans_class = GST_BASE_TRANSFORM_CLASS(klass); + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + GstPadTemplate *pad_template; + + GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidownload, + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); + + object_class->finalize = gst_vaapidownload_finalize; + trans_class->start = gst_vaapidownload_start; + trans_class->stop = gst_vaapidownload_stop; + trans_class->before_transform = gst_vaapidownload_before_transform; + trans_class->transform = gst_vaapidownload_transform; + trans_class->transform_caps = gst_vaapidownload_transform_caps; + trans_class->transform_size = gst_vaapidownload_transform_size; + trans_class->set_caps = gst_vaapidownload_set_caps; + + gst_element_class_set_details_simple( + element_class, + gst_vaapidownload_details.longname, + gst_vaapidownload_details.klass, + gst_vaapidownload_details.description, + gst_vaapidownload_details.author + ); + + /* sink pad */ + pad_template = gst_static_pad_template_get(&gst_vaapidownload_sink_factory); + gst_element_class_add_pad_template(element_class, pad_template); + gst_object_unref(pad_template); + + /* src pad */ + pad_template = gst_static_pad_template_get(&gst_vaapidownload_src_factory); + gst_element_class_add_pad_template(element_class, pad_template); + gst_object_unref(pad_template); +} + +static void +gst_vaapidownload_init(GstVaapiDownload *download) +{ + GstPad *sinkpad, *srcpad; + + download->display = NULL; + download->allowed_caps = NULL; + download->images = NULL; + download->images_reset = FALSE; + download->image_format = (GstVaapiImageFormat)0; + download->image_width = 0; + download->image_height = 0; + + /* Override buffer allocator on sink pad */ + sinkpad = gst_element_get_static_pad(GST_ELEMENT(download), "sink"); + gst_pad_set_query_function(sinkpad, gst_vaapidownload_query); + gst_object_unref(sinkpad); + + /* Override query on src pad */ + srcpad = gst_element_get_static_pad(GST_ELEMENT(download), "src"); + gst_pad_set_query_function(srcpad, gst_vaapidownload_query); + gst_object_unref(srcpad); +} + +static inline gboolean +gst_vaapidownload_ensure_display(GstVaapiDownload *download) +{ + return gst_vaapi_ensure_display(download, GST_VAAPI_DISPLAY_TYPE_ANY, + &download->display); +} + +static gboolean +gst_vaapidownload_start(GstBaseTransform *trans) +{ + GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans); + + if (!gst_vaapidownload_ensure_display(download)) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapidownload_stop(GstBaseTransform *trans) +{ + GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans); + + g_clear_object(&download->display); + + return TRUE; +} + +static GstVaapiImageFormat +get_surface_format(GstVaapiSurface *surface) +{ + GstVaapiImage *image; + GstVaapiImageFormat format = GST_VAAPI_IMAGE_NV12; + + /* XXX: NV12 is assumed by default */ + image = gst_vaapi_surface_derive_image(surface); + if (image) { + format = gst_vaapi_image_get_format(image); + g_object_unref(image); + } + return format; +} + +static gboolean +gst_vaapidownload_update_src_caps(GstVaapiDownload *download, GstBuffer *buffer) +{ + GstVaapiVideoBuffer *vbuffer; + GstVaapiSurface *surface; + GstVaapiImageFormat format; + GstPad *srcpad; + GstCaps *in_caps, *out_caps; + + vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer); + surface = gst_vaapi_video_buffer_get_surface(vbuffer); + if (!surface) { + GST_WARNING("failed to retrieve VA surface from buffer"); + return FALSE; + } + + format = get_surface_format(surface); + if (format == download->image_format) + return TRUE; + + in_caps = GST_BUFFER_CAPS(buffer); + if (!in_caps) { + GST_WARNING("failed to retrieve caps from buffer"); + return FALSE; + } + + out_caps = gst_vaapi_image_format_get_caps(format); + if (!out_caps) { + GST_WARNING("failed to create caps from format %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS(format)); + return FALSE; + } + + if (!gst_vaapi_append_surface_caps(out_caps, in_caps)) { + gst_caps_unref(out_caps); + return FALSE; + } + + /* Try to renegotiate downstream caps */ + srcpad = gst_element_get_static_pad(GST_ELEMENT(download), "src"); + gst_pad_set_caps(srcpad, out_caps); + gst_object_unref(srcpad); + + gst_vaapidownload_set_caps(GST_BASE_TRANSFORM(download), in_caps, out_caps); + gst_caps_replace(&download->allowed_caps, out_caps); + gst_caps_unref(out_caps); + return TRUE; +} + +static void +gst_vaapidownload_before_transform(GstBaseTransform *trans, GstBuffer *buffer) +{ + GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans); + + gst_vaapidownload_update_src_caps(download, buffer); +} + +static GstFlowReturn +gst_vaapidownload_transform( + GstBaseTransform *trans, + GstBuffer *inbuf, + GstBuffer *outbuf +) +{ + GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans); + GstVaapiVideoBuffer *vbuffer; + GstVaapiSurface *surface; + GstVaapiImage *image = NULL; + gboolean success; + + vbuffer = GST_VAAPI_VIDEO_BUFFER(inbuf); + surface = gst_vaapi_video_buffer_get_surface(vbuffer); + if (!surface) + return GST_FLOW_UNEXPECTED; + + image = gst_vaapi_video_pool_get_object(download->images); + if (!image) + return GST_FLOW_UNEXPECTED; + if (!gst_vaapi_surface_get_image(surface, image)) + goto error_get_image; + + success = gst_vaapi_image_get_buffer(image, outbuf, NULL); + gst_vaapi_video_pool_put_object(download->images, image); + if (!success) + goto error_get_buffer; + return GST_FLOW_OK; + +error_get_image: + { + GST_WARNING("failed to download %" GST_FOURCC_FORMAT " image " + "from surface 0x%08x", + GST_FOURCC_ARGS(gst_vaapi_image_get_format(image)), + gst_vaapi_surface_get_id(surface)); + gst_vaapi_video_pool_put_object(download->images, image); + return GST_FLOW_UNEXPECTED; + } + +error_get_buffer: + { + GST_WARNING("failed to transfer image to output video buffer"); + return GST_FLOW_UNEXPECTED; + } +} + +static GstCaps * +gst_vaapidownload_transform_caps( + GstBaseTransform *trans, + GstPadDirection direction, + GstCaps *caps +) +{ + GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans); + GstPad *srcpad; + GstCaps *allowed_caps, *inter_caps, *out_caps = NULL; + GstStructure *structure; + + g_return_val_if_fail(GST_IS_CAPS(caps), NULL); + + structure = gst_caps_get_structure(caps, 0); + + if (direction == GST_PAD_SINK) { + if (!gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME)) + return NULL; + if (!gst_vaapidownload_ensure_display(download)) + return NULL; + out_caps = gst_caps_from_string(gst_vaapidownload_yuv_caps_str); + + /* Build up allowed caps */ + /* XXX: we don't know the decoded surface format yet so we + expose whatever VA images we support */ + if (download->allowed_caps) + allowed_caps = gst_caps_ref(download->allowed_caps); + else { + allowed_caps = gst_vaapi_display_get_image_caps(download->display); + if (!allowed_caps) + return NULL; + } + inter_caps = gst_caps_intersect(out_caps, allowed_caps); + gst_caps_unref(allowed_caps); + gst_caps_unref(out_caps); + out_caps = inter_caps; + + /* Intersect with allowed caps from the peer, if any */ + srcpad = gst_element_get_static_pad(GST_ELEMENT(download), "src"); + allowed_caps = gst_pad_peer_get_caps(srcpad); + if (allowed_caps) { + inter_caps = gst_caps_intersect(out_caps, allowed_caps); + gst_caps_unref(allowed_caps); + gst_caps_unref(out_caps); + out_caps = inter_caps; + } + } + else { + if (!gst_structure_has_name(structure, "video/x-raw-yuv")) + return NULL; + out_caps = gst_caps_from_string(gst_vaapidownload_vaapi_caps_str); + + structure = gst_caps_get_structure(out_caps, 0); + gst_structure_set( + structure, + "type", G_TYPE_STRING, "vaapi", + "opengl", G_TYPE_BOOLEAN, USE_GLX, + NULL + ); + } + + if (!gst_vaapi_append_surface_caps(out_caps, caps)) { + gst_caps_unref(out_caps); + return NULL; + } + return out_caps; +} + +static gboolean +gst_vaapidownload_ensure_image_pool(GstVaapiDownload *download, GstCaps *caps) +{ + GstStructure * const structure = gst_caps_get_structure(caps, 0); + GstVaapiImageFormat format; + gint width, height; + + format = gst_vaapi_image_format_from_caps(caps); + gst_structure_get_int(structure, "width", &width); + gst_structure_get_int(structure, "height", &height); + + if (format != download->image_format || + width != download->image_width || + height != download->image_height) { + download->image_format = format; + download->image_width = width; + download->image_height = height; + g_clear_object(&download->images); + download->images = gst_vaapi_image_pool_new(download->display, caps); + if (!download->images) + return FALSE; + download->images_reset = TRUE; + } + return TRUE; +} + +static inline gboolean +gst_vaapidownload_negotiate_buffers( + GstVaapiDownload *download, + GstCaps *incaps, + GstCaps *outcaps +) +{ + if (!gst_vaapidownload_ensure_image_pool(download, outcaps)) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapidownload_set_caps( + GstBaseTransform *trans, + GstCaps *incaps, + GstCaps *outcaps +) +{ + GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans); + + if (!gst_vaapidownload_negotiate_buffers(download, incaps, outcaps)) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapidownload_transform_size( + GstBaseTransform *trans, + GstPadDirection direction, + GstCaps *caps, + guint size, + GstCaps *othercaps, + guint *othersize +) +{ + GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans); + GstStructure * const structure = gst_caps_get_structure(othercaps, 0); + GstVideoFormat format; + gint width, height; + guint i; + + /* Lookup in cache */ + for (i = 0; i < G_N_ELEMENTS(download->transform_size_cache); i++) { + TransformSizeCache * const tsc = &download->transform_size_cache[i]; + if (tsc->caps && tsc->caps == othercaps) { + *othersize = tsc->size; + return TRUE; + } + } + + /* Compute requested buffer size */ + if (gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME)) + *othersize = 0; + else { + if (!gst_video_format_parse_caps(othercaps, &format, &width, &height)) + return FALSE; + *othersize = gst_video_format_get_size(format, width, height); + } + + /* Update cache */ + for (i = 0; i < G_N_ELEMENTS(download->transform_size_cache); i++) { + TransformSizeCache * const tsc = &download->transform_size_cache[i]; + if (!tsc->caps) { + gst_caps_replace(&tsc->caps, othercaps); + tsc->size = *othersize; + } + } + return TRUE; +} + +static gboolean +gst_vaapidownload_query(GstPad *pad, GstQuery *query) +{ + GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(gst_pad_get_parent_element(pad)); + gboolean res; + + GST_DEBUG("sharing display %p", download->display); + + if (gst_vaapi_reply_to_query(query, download->display)) + res = TRUE; + else + res = gst_pad_query_default(pad, query); + + g_object_unref(download); + return res; + +} diff --git a/gst/vaapi/gstvaapidownload.h b/gst/vaapi/gstvaapidownload.h new file mode 100644 index 0000000..7a594c4 --- /dev/null +++ b/gst/vaapi/gstvaapidownload.h @@ -0,0 +1,67 @@ +/* + * gstvaapidownload.h - VA-API video downloader + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#ifndef GST_VAAPIDOWNLOAD_H +#define GST_VAAPIDOWNLOAD_H + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIDOWNLOAD \ + (gst_vaapidownload_get_type()) + +#define GST_VAAPIDOWNLOAD(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_TYPE_VAAPIDOWNLOAD, \ + GstVaapiDownload)) + +#define GST_VAAPIDOWNLOAD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_TYPE_VAAPIDOWNLOAD, \ + GstVaapiDownloadClass)) + +#define GST_IS_VAAPIDOWNLOAD(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VAAPIDOWNLOAD)) + +#define GST_IS_VAAPIDOWNLOAD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VAAPIDOWNLOAD)) + +#define GST_VAAPIDOWNLOAD_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_TYPE_VAAPIDOWNLOAD, \ + GstVaapiDownloadClass)) + +typedef struct _GstVaapiDownload GstVaapiDownload; +typedef struct _GstVaapiDownloadClass GstVaapiDownloadClass; + +GType +gst_vaapidownload_get_type(void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* GST_VAAPIDOWNLOAD_H */ diff --git a/gst/vaapi/gstvaapiencode.c b/gst/vaapi/gstvaapiencode.c new file mode 100644 index 0000000..a524dc9 --- /dev/null +++ b/gst/vaapi/gstvaapiencode.c @@ -0,0 +1,728 @@ +/* + * gstvaapiencode.c - VA-API video encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "gstvaapiencode.h" + +#include +#include +#include +#include "gst/vaapi/gstvaapibaseencoder.h" + +#include "gstvaapiencode_h264.h" +#include "gstvaapiencode_h263.h" +#include "gstvaapiencode_mpeg4.h" +#include "gstvaapipluginutil.h" +#include "gstvaapipluginbuffer.h" + +/* gst_debug + GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encode_debug) + #define GST_CAT_DEFAULT gst_vaapi_encode_debug + //class_init + GST_DEBUG_CATEGORY_INIT (gst_vaapi_encode_debug, "vaapiencode", 0, + "vaapiencode element"); +*/ +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encode_debug); +#define GST_CAT_DEFAULT gst_vaapi_encode_debug + +#define GST_VAAPI_ENCODE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + GST_TYPE_VAAPI_ENCODE, \ + GstVaapiEncodePrivate)) + +typedef struct _GstVaapiEncodePrivate GstVaapiEncodePrivate; + +#define GstVideoContextClass GstVideoContextInterface + +#define GST_VAAPI_ENCODE_MUTEX_LOCK(encode) \ + G_STMT_START{ g_mutex_lock((encode)->mutex); }G_STMT_END + +#define GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode) \ + G_STMT_START{ g_mutex_unlock((encode)->mutex); }G_STMT_END + +#define GST_VAAPI_ENCODE_IDLE_BUF_WAIT(encode) \ + G_STMT_START { \ + g_cond_wait((encode)->idle_buf_added, (encode)->mutex); \ + } G_STMT_END + +#define GST_VAAPI_ENCODE_IDLE_BUF_SIGNAL(encode) \ + G_STMT_START { \ + g_cond_signal((encode)->idle_buf_added); \ + } G_STMT_END + +#define GST_VAAPI_ENCODE_BUSY_BUF_WAIT(encode) \ + G_STMT_START { \ + g_cond_wait((encode)->busy_buf_added, (encode)->mutex); \ + } G_STMT_END + +#define GST_VAAPI_ENCODE_BUSY_BUF_SIGNAL(encode) \ + G_STMT_START { \ + g_cond_signal((encode)->busy_buf_added); \ + } G_STMT_END + +GST_BOILERPLATE_WITH_INTERFACE( + GstVaapiEncode, + gst_vaapi_encode, + GstElement, + GST_TYPE_ELEMENT, + GstVideoContext, + GST_TYPE_VIDEO_CONTEXT, + gst_video_context) + + +enum { + PROP_0, +}; + +static char* +_encode_dump_caps(GstCaps *cpas) +{ + guint i = 0, j = 0; + GstStructure const *structure; + GValue const *value; + static char caps_string[4096*5]; + char *tmp; + + char *cur = caps_string; + memset(caps_string, 0, sizeof(caps_string)); + for (i = 0; i < gst_caps_get_size(cpas); i++) { + structure = gst_caps_get_structure(cpas, i); + const char* caps_name = gst_structure_get_name (structure); + sprintf(cur, "cap_%02d:%s\n", i, caps_name); + cur += strlen(cur); + + for (j = 0; j < gst_structure_n_fields(structure); j++) { + const char* name = gst_structure_nth_field_name(structure, j); + value = gst_structure_get_value(structure, name); + tmp = gst_value_serialize(value); + sprintf(cur, "\t%s:%s(%s)\n", name, tmp, G_VALUE_TYPE_NAME(value)); + cur += strlen(cur); + g_free(tmp); + } + } + + return caps_string; +} + +/* context(display) interface */ +static void +gst_vaapi_encode_set_video_context( + GstVideoContext *context, + const gchar *type, + const GValue *value +) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE (context); + GstVaapiDisplay *display = NULL; + + gst_vaapi_set_display (type, value, &display); + gst_vaapi_encoder_set_display(encode->encoder, display); +} + +static gboolean +gst_video_context_supported (GstVaapiEncode *decode, GType iface_type) +{ + return (iface_type == GST_TYPE_VIDEO_CONTEXT); +} + +static void +gst_video_context_interface_init(GstVideoContextInterface *iface) +{ + iface->set_context = gst_vaapi_encode_set_video_context; +} + +static gboolean +gst_vaapi_encode_query (GstPad *pad, GstQuery *query) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE (gst_pad_get_parent_element (pad)); + gboolean res; + + if (encode->encoder && + gst_vaapi_reply_to_query(query, ENCODER_DISPLAY(encode->encoder))) + res = TRUE; + else + res = gst_pad_query_default (pad, query); + + g_object_unref (encode); + return res; +} + +static inline gboolean +gst_vaapi_encode_ensure_display(GstVaapiEncode *encode) +{ + return gst_vaapi_ensure_display(encode, + GST_VAAPI_DISPLAY_TYPE_ANY, + &ENCODER_DISPLAY(encode->encoder)); +} + +static void +gst_vaapi_encode_buffer_loop(GstVaapiEncode *encode) +{ + GstBuffer *buf = NULL; + EncoderStatus encoder_ret = ENCODER_NO_ERROR; + gboolean is_running; + + GST_VAAPI_ENCODE_MUTEX_LOCK(encode); + is_running = encode->is_running; + GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode); + if (!is_running) + return; + + encoder_ret = + gst_vaapi_encoder_get_encoded_buffer( + encode->encoder, + &buf); + if (encoder_ret < ENCODER_NO_ERROR) { + ENCODER_LOG_ERROR("get encoded buffer failed"); + return; + } + GST_VAAPI_ENCODE_IDLE_BUF_SIGNAL(encode); + + if (!buf) + return; + + GST_VAAPI_ENCODE_MUTEX_LOCK(encode); + if (encode->first_src_frame) { /* Set src pad caps and codec data */ + GstBuffer *codec_data = NULL; + if ((ENCODER_NO_ERROR == + gst_vaapi_encoder_get_codec_data(encode->encoder, &codec_data)) && + codec_data) { + gst_caps_set_simple(encode->srcpad_caps, + "codec_data",GST_TYPE_BUFFER, codec_data, + NULL); + } + gst_pad_set_caps (encode->srcpad, encode->srcpad_caps); + GST_BUFFER_CAPS(buf) = gst_caps_ref(encode->srcpad_caps); + ENCODER_LOG_INFO("gst_vaapi_encode_chain 1st push-buffer caps,\n%s", + _encode_dump_caps(encode->srcpad_caps)); + encode->first_src_frame = FALSE; + } + GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode); + ENCODER_LOG_DEBUG( + "output:%" GST_TIME_FORMAT ", 0x%s", + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)), + vaapi_encoder_dump_bytes(GST_BUFFER_DATA(buf), + (GST_BUFFER_SIZE(buf) > 16 ? + 16: GST_BUFFER_SIZE(buf))) + ); + gst_pad_push(encode->srcpad, buf); +} + +static gboolean +_encoder_status_callback( + GstVaapiBaseEncoder* encoder, + EncoderStatus status, + void* user_data +) +{ + GstVaapiEncode *encode = (GstVaapiEncode *)user_data; + gboolean ret = FALSE; + + GST_VAAPI_ENCODE_MUTEX_LOCK(encode); + + if (!encode->is_running) { + ret = FALSE; + goto end; + } + + switch (status) { + case ENCODER_NO_IDLE_BUF: + GST_VAAPI_ENCODE_IDLE_BUF_WAIT(encode); + ret = TRUE; + break; + + case ENCODER_NO_BUSY_BUF: + GST_VAAPI_ENCODE_BUSY_BUF_WAIT(encode); + ret = TRUE; + break; + + default: + ret = FALSE; + goto end; + } + + if (!encode->is_running) + ret = FALSE; + +end: + GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode); + + return ret; +} + +static gboolean +gst_vaapi_encode_set_caps(GstPad *sink_pad, GstCaps *caps) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad)); + GstVaapiEncodeClass *encode_class = GST_VAAPI_ENCODE_GET_CLASS(encode); + GstStructure *structure = NULL, *src_struct = NULL; + gint width = 0, height = 0; + gint fps_n = 0, fps_d = 0; + const GValue *fps_value = NULL, *format_value; + guint32 format = 0; + gboolean ret = TRUE; + EncoderStatus encoder_ret = ENCODER_NO_ERROR; + + GST_VAAPI_ENCODE_MUTEX_LOCK(encode); + + encode->sinkpad_caps = caps; + gst_caps_ref(caps); + ENCODER_LOG_INFO("gst_vaapi_encode_set_caps,\n%s", + _encode_dump_caps(caps)); + + structure = gst_caps_get_structure (caps, 0); + + if (gst_structure_has_name(structure, GST_VAAPI_BUFFER_SHARING_CAPS_NAME)) + encode->is_buffer_sharing = TRUE; + else + encode->is_buffer_sharing = FALSE; + + if (gst_structure_get_int (structure, "width", &width)) { + encode->encoder->width = width; + } + if (gst_structure_get_int (structure, "height", &height)) { + encode->encoder->height = height; + } + fps_value = gst_structure_get_value (structure, "framerate"); + if (fps_value) { + fps_n = gst_value_get_fraction_numerator (fps_value); + fps_d = gst_value_get_fraction_denominator (fps_value); + encode->encoder->frame_rate = fps_n/fps_d; + } + format_value = gst_structure_get_value (structure, "format"); + if (format_value && GST_IS_VAAPI_ENCODE_H264(encode)) { + ENCODER_CHECK_STATUS((format_value && + GST_TYPE_FOURCC == G_VALUE_TYPE(format_value)), + FALSE, + "1st buffer caps' format type is not fourcc."); + format = gst_value_get_fourcc (format_value); + if (format) { + gst_vaapi_base_encoder_set_input_format( + GST_VAAPI_BASE_ENCODER(encode->encoder), + format); + } + } + + /*set src pad caps*/ + if (encode->srcpad_caps) { + gst_caps_unref(encode->srcpad_caps); + } + encode->srcpad_caps = + gst_caps_copy(gst_pad_get_pad_template_caps(encode->srcpad)); + src_struct = gst_caps_get_structure(encode->srcpad_caps, 0); + gst_structure_set(src_struct, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + "framerate", GST_TYPE_FRACTION, fps_n, fps_d, + NULL); + if (encode_class->set_encoder_src_caps) { + encode_class->set_encoder_src_caps(encode, encode->srcpad_caps); + } + + /*set display and initialize encoder*/ + ENCODER_CHECK_STATUS(gst_vaapi_encode_ensure_display(encode), + FALSE, + "encoder ensure display failed on setting caps."); + + gst_vaapi_base_encoder_set_notify_status( + GST_VAAPI_BASE_ENCODER(encode->encoder), + _encoder_status_callback, + encode); + gst_vaapi_base_encoder_set_buffer_sharing( + GST_VAAPI_BASE_ENCODER(encode->encoder), + encode->is_buffer_sharing); + + encoder_ret = gst_vaapi_encoder_initialize(encode->encoder); + ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret, + FALSE, + "gst_vaapi_encoder_initialize failed."); + + encoder_ret = gst_vaapi_encoder_open(encode->encoder); + ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == encoder_ret, + FALSE, + "gst_vaapi_encoder_open failed."); + + encode->is_running = TRUE; + +end: + GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode); + if (ret) { + ret = gst_pad_start_task(encode->srcpad, + (GstTaskFunction)gst_vaapi_encode_buffer_loop, + encode); + if (!ret) + ENCODER_LOG_INFO("gstvaapiencode start task failed."); + } + return ret; +} + +static GstCaps * +gst_vaapi_encode_get_caps(GstPad *sink_pad) +{ + GstCaps *caps = NULL; + GstVaapiEncode * const encode = + GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad)); + + GST_VAAPI_ENCODE_MUTEX_LOCK(encode); + + if (encode->sinkpad_caps) { + gst_caps_ref(encode->sinkpad_caps); + ENCODER_LOG_INFO("get caps,\n%s", + _encode_dump_caps(encode->sinkpad_caps)); + caps = encode->sinkpad_caps; + } else + caps = gst_caps_copy(gst_pad_get_pad_template_caps(sink_pad)); + + GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode); + return caps; +} + +static GstStateChangeReturn +gst_vaapi_encode_change_state( + GstElement *element, + GstStateChange transition +) +{ + GstVaapiEncode * const encode = GST_VAAPI_ENCODE(element); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: { + GST_VAAPI_ENCODE_MUTEX_LOCK (encode); + encode->is_running = FALSE; + encode->is_buffer_sharing = FALSE; + GST_VAAPI_ENCODE_BUSY_BUF_SIGNAL(encode); + GST_VAAPI_ENCODE_IDLE_BUF_SIGNAL(encode); + GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode); + gst_pad_stop_task(encode->srcpad); + break; + } + default: + break; + } + + ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition); + if (ret != GST_STATE_CHANGE_SUCCESS) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_vaapi_encoder_close(encode->encoder); + GST_VAAPI_ENCODE_MUTEX_LOCK(encode); + if (encode->video_pool) { + g_object_unref(encode->video_pool); + encode->video_pool = NULL; + } + GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode); + break; + default: + break; + } + + return GST_STATE_CHANGE_SUCCESS; +} + +static GstFlowReturn +gst_vaapi_encode_chain(GstPad *sink_pad, GstBuffer *buf) +{ + GstFlowReturn ret = GST_FLOW_OK; + GstVaapiEncode *encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(sink_pad)); + EncoderStatus encoder_ret = ENCODER_NO_ERROR; + gboolean is_buffer_sharing; + + ENCODER_ASSERT(encode && encode->encoder); + + GST_VAAPI_ENCODE_MUTEX_LOCK(encode); + is_buffer_sharing = encode->is_buffer_sharing; + GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode); + + if (!is_buffer_sharing && !GST_VAAPI_IS_VIDEO_BUFFER(buf)) { + ENCODER_LOG_ERROR("gst_vaapi_encode_chain parameter doesn't have video buffer."); + ret = ENCODER_NO_ERROR; + goto end; + } + + /*encoding frames*/ + encoder_ret = gst_vaapi_encoder_encode(encode->encoder, buf); + GST_VAAPI_ENCODE_BUSY_BUF_SIGNAL(encode); + ENCODER_CHECK_STATUS (ENCODER_NO_ERROR <= encoder_ret, + GST_FLOW_ERROR, + "gst_vaapi_encoder_encode failed."); + +end: + gst_buffer_unref(buf); + return ret; +} + +static gboolean +gst_vaapi_encode_ensure_video_pool( + GstVaapiEncode *encode, + GstCaps *caps) +{ + GstStructure *structure; + gint width = 0, height = 0; + + g_return_val_if_fail(caps, FALSE); + + structure = gst_caps_get_structure(caps, 0); + g_return_val_if_fail(structure, FALSE); + + if (encode->video_pool) + return TRUE; + + if (!gst_structure_get_int(structure, "width", &width) || + !gst_structure_get_int(structure, "height", &height)) + return FALSE; + + encode->video_pool = + gst_vaapi_surface_pool_new(ENCODER_DISPLAY(encode->encoder), caps); + if (!encode->video_pool) + return FALSE; + + return TRUE; +} + +static GstFlowReturn +gst_vaapi_encode_buffer_alloc( + GstPad * pad, + guint64 offset, + guint size, + GstCaps * caps, + GstBuffer ** buf +) +{ + GstVaapiEncode * const encode = GST_VAAPI_ENCODE(GST_OBJECT_PARENT(pad)); + GstStructure *structure = NULL; + GstBuffer *video_buffer = NULL; + GstFlowReturn ret = GST_FLOW_ERROR; + + if (!caps) + return GST_FLOW_ERROR; + + structure = gst_caps_get_structure(caps, 0); + if (!structure || + (!gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME) && + !gst_structure_has_name(structure, GST_VAAPI_BUFFER_SHARING_CAPS_NAME))) + return GST_FLOW_ERROR; + + ENCODER_CHECK_STATUS( + gst_vaapi_encode_ensure_display(encode), + GST_FLOW_ERROR, + "gst_vaapi_encode_buffer_alloc can't ensure display"); + + GST_VAAPI_ENCODE_MUTEX_LOCK(encode); + if (!gst_vaapi_encode_ensure_video_pool(encode, caps)) + goto unlock; + + video_buffer = gst_vaapi_video_buffer_new_from_pool(encode->video_pool); + +unlock: + GST_VAAPI_ENCODE_MUTEX_UNLOCK(encode); + + ENCODER_CHECK_STATUS(video_buffer, + GST_FLOW_ERROR, + "gst_vaapi_encode_buffer_alloc failed."); + + if (gst_structure_has_name(structure, GST_VAAPI_BUFFER_SHARING_CAPS_NAME)) { + ENCODER_CHECK_STATUS( + gst_vaapi_video_buffer_ensure_pointer(GST_VAAPI_VIDEO_BUFFER(video_buffer)), + GST_FLOW_ERROR, + "gst_vaapi_video_buffer_ensure_pointer failed."); + } + + if (caps) { + gst_buffer_set_caps(video_buffer, caps); + } + *buf = video_buffer; + ret = GST_FLOW_OK; + +end: + return ret; +} + +static void +gst_vaapi_encode_finalize(GObject *object) +{ + GstVaapiEncode * const encode = GST_VAAPI_ENCODE(object); + + if (encode->sinkpad_caps) { + gst_caps_unref(encode->sinkpad_caps); + encode->sinkpad_caps = NULL; + } + encode->sinkpad = NULL; + + if (encode->srcpad_caps) { + gst_caps_unref(encode->srcpad_caps); + encode->srcpad_caps = NULL; + } + encode->srcpad = NULL; + + if (encode->video_pool) + g_object_unref(encode->video_pool); + + if (encode->encoder) { + gst_vaapi_encoder_close(encode->encoder); + gst_vaapi_encoder_uninitialize(encode->encoder); + gst_vaapi_encoder_unref(encode->encoder); + encode->encoder = NULL; + } + + g_mutex_free(encode->mutex); + g_cond_free(encode->idle_buf_added); + g_cond_free(encode->busy_buf_added); + + G_OBJECT_CLASS(parent_class)->finalize(object); +} + +static void +gst_vaapi_encode_init( + GstVaapiEncode *encode, + GstVaapiEncodeClass *klass +) +{ + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + + encode->sinkpad_caps = NULL; + encode->srcpad_caps = NULL; + encode->first_src_frame = TRUE; + encode->is_running = FALSE; + encode->is_buffer_sharing = FALSE; + + encode->encoder = NULL; + encode->video_pool = NULL; + + encode->mutex = g_mutex_new(); + encode->idle_buf_added = g_cond_new(); + encode->busy_buf_added = g_cond_new(); + + /*sink pad */ + encode->sinkpad = gst_pad_new_from_template( + gst_element_class_get_pad_template(element_class, "sink"), + "sink" + ); + gst_pad_set_getcaps_function(encode->sinkpad, gst_vaapi_encode_get_caps); + gst_pad_set_setcaps_function(encode->sinkpad, gst_vaapi_encode_set_caps); + gst_pad_set_chain_function(encode->sinkpad, gst_vaapi_encode_chain); + gst_pad_set_bufferalloc_function(encode->sinkpad, + gst_vaapi_encode_buffer_alloc); + /*gst_pad_set_event_function(encode->sinkpad, gst_vaapi_encode_sink_event); */ + /*gst_pad_use_fixed_caps(encode->sinkpad);*/ + gst_pad_set_query_function(encode->sinkpad, gst_vaapi_encode_query); + gst_element_add_pad(GST_ELEMENT(encode), encode->sinkpad); + + /* src pad */ + encode->srcpad = gst_pad_new_from_template( + gst_element_class_get_pad_template(element_class, "src"), + "src" + ); + encode->srcpad_caps = NULL; + + gst_pad_use_fixed_caps(encode->srcpad); + /*gst_pad_set_event_function(encode->srcpad, gst_vaapi_encode_src_event);*/ + gst_pad_set_query_function(encode->srcpad, gst_vaapi_encode_query); + gst_element_add_pad(GST_ELEMENT(encode), encode->srcpad); +} + +static void +gst_vaapi_encode_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE(object); + ENCODER_ASSERT(encode->encoder); + + switch (prop_id) { + } +} + +static void +gst_vaapi_encode_get_property ( + GObject * object, + guint prop_id, + GValue * value, + GParamSpec * pspec +) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE(object); + ENCODER_ASSERT(encode->encoder); + + switch (prop_id) { + } +} + +static void +gst_vaapi_encode_base_init(gpointer klass) +{ + #if 0 + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + + gst_element_class_set_details(element_class, &gst_vaapi_encode_details); + + /* sink pad */ + gst_element_class_add_pad_template( + element_class, + gst_static_pad_template_get(&gst_vaapi_encode_sink_factory) + ); + + /* src pad */ + gst_element_class_add_pad_template( + element_class, + gst_static_pad_template_get(&gst_vaapi_encode_src_factory) + ); + #endif +} + +static void +gst_vaapi_encode_class_init(GstVaapiEncodeClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + + object_class->finalize = gst_vaapi_encode_finalize; + object_class->set_property = gst_vaapi_encode_set_property; + object_class->get_property = gst_vaapi_encode_get_property; + + GST_DEBUG_CATEGORY_INIT (gst_vaapi_encode_debug, + "vaapiencode", + 0, + "vaapiencode element"); + + element_class->change_state = gst_vaapi_encode_change_state; + + klass->set_encoder_src_caps = NULL; + + /* Registering debug symbols for function pointers */ + GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_change_state); + GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_get_caps); + GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_set_caps); + GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_chain); + GST_DEBUG_REGISTER_FUNCPTR (gst_vaapi_encode_buffer_alloc); +} diff --git a/gst/vaapi/gstvaapiencode.h b/gst/vaapi/gstvaapiencode.h new file mode 100644 index 0000000..7127ad3 --- /dev/null +++ b/gst/vaapi/gstvaapiencode.h @@ -0,0 +1,95 @@ +/* + * gstvaapiencode.h - VA-API video encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODE_H +#define GST_VAAPI_ENCODE_H + +#include +#include "gst/vaapi/gstvaapiencoder.h" + +G_BEGIN_DECLS + +/* Default templates */ +#define GST_CAPS_CODEC(CODEC) \ + CODEC ", " \ + "width = (int) [ 1, MAX ], " \ + "height = (int) [ 1, MAX ]; " + +#define GST_TYPE_VAAPI_ENCODE \ + (gst_vaapi_encode_get_type()) + +#define GST_IS_VAAPI_ENCODE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_ENCODE)) + +#define GST_IS_VAAPI_ENCODE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_ENCODE)) + +#define GST_VAAPI_ENCODE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GST_TYPE_VAAPI_ENCODE, \ + GstVaapiEncodeClass)) + +#define GST_VAAPI_ENCODE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_VAAPI_ENCODE, \ + GstVaapiEncode)) + +#define GST_VAAPI_ENCODE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GST_TYPE_VAAPI_ENCODE, \ + GstVaapiEncodeClass)) + +typedef struct _GstVaapiEncode GstVaapiEncode; +typedef struct _GstVaapiEncodeClass GstVaapiEncodeClass; + +struct _GstVaapiEncode { + GstElement parent_instance; + + GstPad *sinkpad; + GstCaps *sinkpad_caps; + + GstPad *srcpad; + GstCaps *srcpad_caps; + + GstVaapiEncoder *encoder; + gboolean first_src_frame; + + GstVaapiVideoPool *video_pool; + + /*encode chain lock*/ + GMutex *mutex; + GCond *idle_buf_added; + GCond *busy_buf_added; + gboolean is_running; + gboolean is_buffer_sharing; +}; + +struct _GstVaapiEncodeClass { + GstElementClass parent_class; + gboolean (*set_encoder_src_caps)(GstVaapiEncode* encode, GstCaps *caps); +}; + +GType gst_vaapi_encode_get_type(void); + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODE_H */ + diff --git a/gst/vaapi/gstvaapiencode_h263.c b/gst/vaapi/gstvaapiencode_h263.c new file mode 100644 index 0000000..eeb5a00 --- /dev/null +++ b/gst/vaapi/gstvaapiencode_h263.c @@ -0,0 +1,245 @@ +/* + * gstvaapiencode_h263.c - VA-API H.263 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstvaapiencode_h263.h" +#include "gst/vaapi/gstvaapiencoder_h263.h" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h263_encode_debug); +#define GST_CAT_DEFAULT gst_vaapi_h263_encode_debug + +#define GST_VAAPI_ENCODE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + GST_TYPE_VAAPI_ENCODE, \ + GstVaapiEncodePrivate)) + +static const char gst_vaapi_encode_h263_sink_caps_str[] = + GST_VAAPI_SURFACE_CAPS "; " + GST_VAAPI_BUFFER_SHARING_CAPS; + +static const GstElementDetails gst_vaapi_encode_h263_details = + GST_ELEMENT_DETAILS( + "VA-API h263 encoder", + "Codec/Encoder/Video", + "A VA-API based h263 encoder", + "Feng Yuan "); + + +static const char gst_vaapi_encode_h263_src_caps_str[] = + GST_CAPS_CODEC("video/x-h263"); + +static GstStaticPadTemplate gst_vaapi_encode_h263_sink_factory = + GST_STATIC_PAD_TEMPLATE( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapi_encode_h263_sink_caps_str)); + +static GstStaticPadTemplate gst_vaapi_encode_h263_src_factory = + GST_STATIC_PAD_TEMPLATE( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapi_encode_h263_src_caps_str)); + +/* h263 encode */ +GST_BOILERPLATE( + GstVaapiEncodeH263, + gst_vaapi_encode_h263, + GstVaapiEncode, + GST_TYPE_VAAPI_ENCODE) + +enum { + H263_PROP_0, + H263_PROP_BITRATE, + H263_PROP_INTRA_PERIOD, + H263_PROP_INIT_QP, + H263_PROP_MIN_QP, +}; + +static void +gst_vaapi_encode_h263_init( + GstVaapiEncodeH263 *h263_encode, + GstVaapiEncodeH263Class *klass +) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE(h263_encode); + encode->encoder = GST_VAAPI_ENCODER(gst_vaapi_encoder_h263_new()); + ENCODER_ASSERT(encode->encoder); +} + +static void +gst_vaapi_encode_h263_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiEncode *base = GST_VAAPI_ENCODE(object); + GstVaapiEncoderH263 *encoder = GST_VAAPI_ENCODER_H263(base->encoder); + + ENCODER_ASSERT(encoder); + + switch (prop_id) { + case H263_PROP_BITRATE: { + encoder->bitrate = g_value_get_uint(value); + } + break; + + case H263_PROP_INTRA_PERIOD: { + encoder->intra_period = g_value_get_uint(value); + } + break; + + case H263_PROP_INIT_QP: { + encoder->init_qp = g_value_get_uint(value); + } + break; + + case H263_PROP_MIN_QP: { + encoder->min_qp = g_value_get_uint(value); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_encode_h263_get_property ( + GObject * object, + guint prop_id, + GValue * value, + GParamSpec * pspec +) +{ + GstVaapiEncode *base = GST_VAAPI_ENCODE(object); + GstVaapiEncoderH263 *encoder = GST_VAAPI_ENCODER_H263(base->encoder); + ENCODER_ASSERT(encoder); + + switch (prop_id) { + case H263_PROP_BITRATE: + g_value_set_uint (value, encoder->bitrate); + break; + + case H263_PROP_INTRA_PERIOD: + g_value_set_uint (value, encoder->intra_period); + break; + + case H263_PROP_INIT_QP: + g_value_set_uint (value, encoder->init_qp); + break; + + case H263_PROP_MIN_QP: + g_value_set_uint (value, encoder->min_qp); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_encode_h263_base_init(gpointer klass) +{ + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + + gst_element_class_set_details(element_class, &gst_vaapi_encode_h263_details); + + /* sink pad */ + gst_element_class_add_pad_template( + element_class, + gst_static_pad_template_get(&gst_vaapi_encode_h263_sink_factory) + ); + + /* src pad */ + gst_element_class_add_pad_template( + element_class, + gst_static_pad_template_get(&gst_vaapi_encode_h263_src_factory) + ); +} + +static void +gst_vaapi_encode_h263_class_init(GstVaapiEncodeH263Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + GST_DEBUG_CATEGORY_INIT (gst_vaapi_h263_encode_debug, + "vaapih263encode", + 0, + "vaapih263encode element"); + + /* object_class->finalize = gst_vaapi_encode_h263_finalize; */ + object_class->set_property = gst_vaapi_encode_h263_set_property; + object_class->get_property = gst_vaapi_encode_h263_get_property; + + g_object_class_install_property ( + object_class, + H263_PROP_BITRATE, + g_param_spec_uint ( + "bitrate", + "H263 encoding bitrate(kpbs)", + "H263 encoding bitrate(kbps), (0, auto-calculate)", + 0, + 100*1024, + 0, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + H263_PROP_INTRA_PERIOD, + g_param_spec_uint ( + "intra-period", + "H263 encoding intra-period", + "H263 encoding intra-period", + 1, + 300, + H263_DEFAULT_INTRA_PERIOD, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + H263_PROP_INIT_QP, + g_param_spec_uint ( + "init-qp", + "H263 init-qp", + "H263 init-qp", + 1, + 51, + H263_DEFAULT_INIT_QP, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + H263_PROP_MIN_QP, + g_param_spec_uint ( + "min-qp", + "H263 min-qp", + "H263 min-qp", + 1, + 51, + H263_DEFAULT_MIN_QP, + G_PARAM_READWRITE)); + +} diff --git a/gst/vaapi/gstvaapiencode_h263.h b/gst/vaapi/gstvaapiencode_h263.h new file mode 100644 index 0000000..5d4657f --- /dev/null +++ b/gst/vaapi/gstvaapiencode_h263.h @@ -0,0 +1,69 @@ +/* + * gstvaapiencode_h263.h - VA-API H.263 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODE_H263_H +#define GST_VAAPI_ENCODE_H263_H + +#include +#include "gstvaapiencode.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_ENCODE_H263 \ + (gst_vaapi_encode_h263_get_type()) + +#define GST_IS_VAAPI_ENCODE_H263(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_ENCODE_H263)) + +#define GST_IS_VAAPI_ENCODE_H263_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_ENCODE_H263)) + +#define GST_VAAPI_ENCODE_H263_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GST_TYPE_VAAPI_ENCODE_H263, \ + GstVaapiEncodeH263Class)) + +#define GST_VAAPI_ENCODE_H263(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_VAAPI_ENCODE_H263, \ + GstVaapiEncodeH263)) + +#define GST_VAAPI_ENCODE_H263_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GST_TYPE_VAAPI_ENCODE_H263, \ + GstVaapiEncodeH263Class)) + +typedef struct _GstVaapiEncodeH263 GstVaapiEncodeH263; +typedef struct _GstVaapiEncodeH263Class GstVaapiEncodeH263Class; + +struct _GstVaapiEncodeH263 { + GstVaapiEncode parent; +}; + +struct _GstVaapiEncodeH263Class { + GstVaapiEncodeClass parent_class; +}; + +GType gst_vaapi_encode_h263_get_type(void); + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODE_H263_H */ diff --git a/gst/vaapi/gstvaapiencode_h264.c b/gst/vaapi/gstvaapiencode_h264.c new file mode 100644 index 0000000..0bb7475 --- /dev/null +++ b/gst/vaapi/gstvaapiencode_h264.c @@ -0,0 +1,457 @@ +/* + * gstvaapiencode_h264.c - VA-API H.264 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstvaapiencode_h264.h" +#include "gst/vaapi/gstvaapiencoder_h264.h" +#include "gst/vaapi/gstvaapivalue.h" + +#include + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h264_encode_debug); +#define GST_CAT_DEFAULT gst_vaapi_h264_encode_debug + +static const char gst_vaapi_encode_h264_sink_caps_str[] = + GST_VAAPI_SURFACE_CAPS "; " + GST_VAAPI_BUFFER_SHARING_CAPS; + +static const GstElementDetails gst_vaapi_encode_h264_details = + GST_ELEMENT_DETAILS( + "VA-API h264 encoder", + "Codec/Encoder/Video", + "A VA-API based h264 encoder", + "Feng Yuan"); + + +static const char gst_vaapi_encode_h264_src_caps_str[] = + GST_CAPS_CODEC("video/x-h264"); + +static GstStaticPadTemplate gst_vaapi_encode_h264_sink_factory = + GST_STATIC_PAD_TEMPLATE( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapi_encode_h264_sink_caps_str)); + +static GstStaticPadTemplate gst_vaapi_encode_h264_src_factory = + GST_STATIC_PAD_TEMPLATE( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapi_encode_h264_src_caps_str)); + +/* h264 encode */ +GST_BOILERPLATE( + GstVaapiEncodeH264, + gst_vaapi_encode_h264, + GstVaapiEncode, + GST_TYPE_VAAPI_ENCODE) + +enum { + H264_PROP_0, + H264_PROP_PROFILE, + H264_PROP_LEVEL, + H264_PROP_RATE_CONTROL, + H264_PROP_BITRATE, + H264_PROP_INTRA_PERIOD, + H264_PROP_INIT_QP, + H264_PROP_MIN_QP, + H264_PROP_SLICE_NUM, + H264_PROP_B_FRAME_NUM, +}; + +static void +gst_vaapi_encode_h264_init( + GstVaapiEncodeH264 *h264_encode, + GstVaapiEncodeH264Class *klass +) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE(h264_encode); + encode->encoder = GST_VAAPI_ENCODER(gst_vaapi_encoder_h264_new()); + ENCODER_ASSERT(encode->encoder); +} + +static void +gst_vaapi_encode_h264_finalize(GObject *object) +{ + //GstVaapiEncodeH264 * const h264_encode = GST_VAAPI_ENCODE_H264(object); + G_OBJECT_CLASS(parent_class)->finalize(object); +} + + +static inline gboolean +h264_check_valid_profile(guint profile) +{ + static const guint limit_profiles[] = { + H264_PROFILE_BASELINE, + H264_PROFILE_MAIN, + H264_PROFILE_HIGH + }; + guint n_profiles = sizeof(limit_profiles)/sizeof(limit_profiles[0]); + guint i; + for (i = 0; i < n_profiles; ++i) { + if (limit_profiles[i] == profile) + return TRUE; + } + return FALSE; +} + +static inline gboolean +h264_check_valid_level(guint level) +{ + static const guint limit_levels[] = { + H264_LEVEL_10, + H264_LEVEL_11, + H264_LEVEL_12, + H264_LEVEL_13, + H264_LEVEL_20, + H264_LEVEL_21, + H264_LEVEL_22, + H264_LEVEL_30, + H264_LEVEL_31, + H264_LEVEL_32, + H264_LEVEL_40, + H264_LEVEL_41, + H264_LEVEL_42, + H264_LEVEL_50, + H264_LEVEL_51 + }; + guint n_levels = sizeof(limit_levels)/sizeof(limit_levels[0]); + guint i; + for (i = 0; i < n_levels; ++i) { + if (limit_levels[i] == level) + return TRUE; + } + return FALSE; + +} + + +static void +gst_vaapi_encode_h264_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE(object); + GstVaapiEncoderH264 *h264encoder = GST_VAAPI_ENCODER_H264(encode->encoder); + + ENCODER_ASSERT(h264encoder); + + switch (prop_id) { + case H264_PROP_PROFILE: { + guint profile = g_value_get_uint(value); + if (h264_check_valid_profile(profile)) { + h264encoder->profile = profile; + } else { + ENCODER_LOG_ERROR("h264encode set property failed."); + } + } + break; + + case H264_PROP_LEVEL: { + guint level = g_value_get_uint(value); + if (h264_check_valid_level(level)) { + h264encoder->level= level; + } else { + ENCODER_LOG_ERROR("h264encode set property failed."); + } + } + break; + + case H264_PROP_RATE_CONTROL: { + ENCODER_RATE_CONTROL(h264encoder) = g_value_get_enum(value); + } + break; + + case H264_PROP_BITRATE: { + h264encoder->bitrate = g_value_get_uint(value); + } + break; + + case H264_PROP_INTRA_PERIOD: { + h264encoder->intra_period = g_value_get_uint(value); + } + break; + + case H264_PROP_INIT_QP: { + h264encoder->init_qp = g_value_get_uint(value); + } + break; + + case H264_PROP_MIN_QP: { + h264encoder->min_qp = g_value_get_uint(value); + } + break; + + case H264_PROP_SLICE_NUM: { + h264encoder->slice_num= g_value_get_uint(value); + } + break; + + case H264_PROP_B_FRAME_NUM: { + h264encoder->b_frame_num= g_value_get_uint(value); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_encode_h264_get_property ( + GObject * object, + guint prop_id, + GValue * value, + GParamSpec * pspec +) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE(object); + GstVaapiEncoderH264 *h264encoder = GST_VAAPI_ENCODER_H264(encode->encoder); + ENCODER_ASSERT(h264encoder); + + switch (prop_id) { + case H264_PROP_PROFILE: + g_value_set_uint (value, h264encoder->profile); + break; + + case H264_PROP_LEVEL: + g_value_set_uint (value, h264encoder->level); + break; + + case H264_PROP_RATE_CONTROL: + g_value_set_enum(value, ENCODER_RATE_CONTROL(h264encoder)); + break; + + case H264_PROP_BITRATE: + g_value_set_uint (value, h264encoder->bitrate); + break; + + case H264_PROP_INTRA_PERIOD: + g_value_set_uint (value, h264encoder->intra_period); + break; + + case H264_PROP_INIT_QP: + g_value_set_uint (value, h264encoder->init_qp); + break; + + case H264_PROP_MIN_QP: + g_value_set_uint (value, h264encoder->min_qp); + break; + + case H264_PROP_SLICE_NUM: + g_value_set_uint (value, h264encoder->slice_num); + break; + + case H264_PROP_B_FRAME_NUM: + g_value_set_uint (value, h264encoder->b_frame_num); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_vaapi_encode_h264_set_src_caps( + GstVaapiEncode* encode, + GstCaps *caps +) +{ + GstVaapiEncoderH264 *h264encoder = GST_VAAPI_ENCODER_H264(encode->encoder); + GstCaps *peer_caps, *allowed_caps; + GstStructure *s; + const gchar *stream_format; + + g_return_val_if_fail(caps,FALSE); + peer_caps = gst_pad_peer_get_caps_reffed(encode->srcpad); + if (peer_caps) { + allowed_caps = gst_caps_intersect(peer_caps, caps); + if (allowed_caps) { + allowed_caps = gst_caps_make_writable(allowed_caps); + gst_pad_fixate_caps(encode->srcpad, caps); + s = gst_caps_get_structure (allowed_caps, 0); + stream_format = gst_structure_get_string (s, "stream-format"); + if (stream_format) { + if (!strcmp (stream_format, "avc")) { + gst_vaapi_encoder_h264_set_avc_flag(h264encoder, TRUE); + } else if (!strcmp (stream_format, "byte-stream")) { + gst_vaapi_encoder_h264_set_avc_flag(h264encoder, FALSE); + } + } + gst_caps_unref(allowed_caps); + } + gst_caps_unref(peer_caps); + } + gst_caps_set_simple(caps, "stream-format", + G_TYPE_STRING, + (gst_vaapi_encoder_h264_get_avc_flag(h264encoder) ? "avc" : "byte-stream"), + "alignment", G_TYPE_STRING, "au", + NULL); + return TRUE; +} + +static void +gst_vaapi_encode_h264_base_init(gpointer klass) +{ + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + + gst_element_class_set_details(element_class, &gst_vaapi_encode_h264_details); + + /* sink pad */ + gst_element_class_add_pad_template( + element_class, + gst_static_pad_template_get(&gst_vaapi_encode_h264_sink_factory) + ); + + /* src pad */ + gst_element_class_add_pad_template( + element_class, + gst_static_pad_template_get(&gst_vaapi_encode_h264_src_factory) + ); +} + +static void +gst_vaapi_encode_h264_class_init(GstVaapiEncodeH264Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiEncodeClass *const encode_class = GST_VAAPI_ENCODE_CLASS(klass); + GST_DEBUG_CATEGORY_INIT (gst_vaapi_h264_encode_debug, + "vaapih264encode", + 0, + "vaapih264encode element"); + + object_class->finalize = gst_vaapi_encode_h264_finalize; + object_class->set_property = gst_vaapi_encode_h264_set_property; + object_class->get_property = gst_vaapi_encode_h264_get_property; + + encode_class->set_encoder_src_caps = gst_vaapi_encode_h264_set_src_caps; + + g_object_class_install_property ( + object_class, + H264_PROP_PROFILE, + g_param_spec_uint ( + "profile", + "H264 Profile", + "Profile supports: 66(Baseline), 77(Main), 100(High)", + H264_PROFILE_BASELINE, + H264_PROFILE_HIGH10, + H264_DEFAULT_PROFILE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + H264_PROP_LEVEL, + g_param_spec_uint ( + "level", + "H264 level idc", + "Level idc supports: 10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41", + H264_LEVEL_10, + H264_LEVEL_41, + H264_DEFAULT_LEVEL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + H264_PROP_RATE_CONTROL, + g_param_spec_enum ("rate-control", + "rate-control", + "Rate control mode", + GST_VAAPI_TYPE_RATE_CONTROL, + GST_VAAPI_RATECONTROL_NONE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + H264_PROP_BITRATE, + g_param_spec_uint ( + "bitrate", + "H264 encoding bitrate(kbps)", + "H264 encoding bitrate(kbps), (0, auto-calculate)", + 0, + 100*1024, + 0, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + H264_PROP_INTRA_PERIOD, + g_param_spec_uint ( + "intra-period", + "H264 encoding intra-period", + "H264 encoding intra-period", + 1, + 300, + H264_DEFAULT_INTRA_PERIOD, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + H264_PROP_INIT_QP, + g_param_spec_uint ( + "init-qp", + "H264 init-qp", + "H264 init-qp", + 1, + 51, + H264_DEFAULT_INIT_QP, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + H264_PROP_MIN_QP, + g_param_spec_uint ( + "min-qp", + "H264 min-qp", + "H264 min-qp", + 1, + 51, + H264_DEFAULT_MIN_QP, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + H264_PROP_SLICE_NUM, + g_param_spec_uint ( + "slice-num", + "H264 slice num", + "H264 slice num", + 1, + 200, + 1, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + H264_PROP_B_FRAME_NUM, + g_param_spec_uint ( + "b-frame-num", + "B frams num", + "B frams num", + 0, + 10, + 0, + G_PARAM_READWRITE)); +} diff --git a/gst/vaapi/gstvaapiencode_h264.h b/gst/vaapi/gstvaapiencode_h264.h new file mode 100644 index 0000000..ba4b383 --- /dev/null +++ b/gst/vaapi/gstvaapiencode_h264.h @@ -0,0 +1,70 @@ +/* + * gstvaapiencode_h264.h - VA-API H.264 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODE_H264_H +#define GST_VAAPI_ENCODE_H264_H + +#include +#include "gstvaapiencode.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_ENCODE_H264 \ + (gst_vaapi_encode_h264_get_type()) + +#define GST_IS_VAAPI_ENCODE_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_ENCODE_H264)) + +#define GST_IS_VAAPI_ENCODE_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_ENCODE_H264)) + +#define GST_VAAPI_ENCODE_H264_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GST_TYPE_VAAPI_ENCODE_H264, \ + GstVaapiEncodeH264Class)) + +#define GST_VAAPI_ENCODE_H264(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_VAAPI_ENCODE_H264, \ + GstVaapiEncodeH264)) + +#define GST_VAAPI_ENCODE_H264_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GST_TYPE_VAAPI_ENCODE_H264, \ + GstVaapiEncodeH264Class)) + + +typedef struct _GstVaapiEncodeH264 GstVaapiEncodeH264; +typedef struct _GstVaapiEncodeH264Class GstVaapiEncodeH264Class; + +struct _GstVaapiEncodeH264 { + GstVaapiEncode parent; +}; + +struct _GstVaapiEncodeH264Class { + GstVaapiEncodeClass parent_class; +}; + +GType gst_vaapi_encode_h264_get_type(void); + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODE_H264_H */ diff --git a/gst/vaapi/gstvaapiencode_mpeg4.c b/gst/vaapi/gstvaapiencode_mpeg4.c new file mode 100644 index 0000000..74cb7f7 --- /dev/null +++ b/gst/vaapi/gstvaapiencode_mpeg4.c @@ -0,0 +1,270 @@ +/* + * gstvaapiencode_mpeg4.c - VA-API MPEG-4 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gstvaapiencode_mpeg4.h" +#include "gst/vaapi/gstvaapiencoder_mpeg4.h" + +GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encode_mpeg4_debug); +#define GST_CAT_DEFAULT gst_vaapi_encode_mpeg4_debug + + +static const char gst_vaapi_encode_mpeg4_sink_caps_str[] = + GST_VAAPI_SURFACE_CAPS "; " + GST_VAAPI_BUFFER_SHARING_CAPS; + +static const GstElementDetails gst_vaapi_encode_mpeg4_details = + GST_ELEMENT_DETAILS( + "VA-API mpeg4 encoder", + "Codec/Encoder/Video", + "A VA-API based mpeg4 encoder", + "Feng Yuan"); + + +static const char gst_vaapi_encode_mpeg4_src_caps_str[] = + GST_CAPS_CODEC("video/mpeg, mpegversion=4"); + +static GstStaticPadTemplate gst_vaapi_encode_mpeg4_sink_factory = + GST_STATIC_PAD_TEMPLATE( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapi_encode_mpeg4_sink_caps_str)); + +static GstStaticPadTemplate gst_vaapi_encode_mpeg4_src_factory = + GST_STATIC_PAD_TEMPLATE( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapi_encode_mpeg4_src_caps_str)); + + +/* mpeg4 encode */ +GST_BOILERPLATE( + GstVaapiEncodeMpeg4, + gst_vaapi_encode_mpeg4, + GstVaapiEncode, + GST_TYPE_VAAPI_ENCODE) + +enum { + MPEG4_PROP_0, + MPEG4_PROP_PROFILE, + MPEG4_PROP_BITRATE, + MPEG4_PROP_INTRA_PERIOD, + MPEG4_PROP_INIT_QP, + MPEG4_PROP_MIN_QP, +}; + +static void +gst_vaapi_encode_mpeg4_init( + GstVaapiEncodeMpeg4 *mpeg4_encode, + GstVaapiEncodeMpeg4Class *klass) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE(mpeg4_encode); + encode->encoder = GST_VAAPI_ENCODER(gst_vaapi_encoder_mpeg4_new()); + ENCODER_ASSERT(encode->encoder); +} + +static void +gst_vaapi_encode_mpeg4_finalize(GObject *object) +{ + //GstVaapiEncodeMpeg4 * const mpeg4_encode = GST_VAAPI_ENCODE_MPEG4(object); + G_OBJECT_CLASS(parent_class)->finalize(object); +} + +static void +gst_vaapi_encode_mpeg4_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE(object); + GstVaapiEncoderMpeg4 *mpeg4encoder = GST_VAAPI_ENCODER_MPEG4(encode->encoder); + + ENCODER_ASSERT(mpeg4encoder); + + switch (prop_id) { + case MPEG4_PROP_PROFILE: { + mpeg4encoder->profile = g_value_get_uint(value); + } + break; + + case MPEG4_PROP_BITRATE: { + mpeg4encoder->bitrate = g_value_get_uint(value); + } + break; + + case MPEG4_PROP_INTRA_PERIOD: { + mpeg4encoder->intra_period = g_value_get_uint(value); + } + break; + + case MPEG4_PROP_INIT_QP: { + mpeg4encoder->init_qp = g_value_get_uint(value); + } + break; + + case MPEG4_PROP_MIN_QP: { + mpeg4encoder->min_qp = g_value_get_uint(value); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_encode_mpeg4_get_property( + GObject * object, + guint prop_id, + GValue * value, + GParamSpec * pspec +) +{ + GstVaapiEncode *encode = GST_VAAPI_ENCODE(object); + GstVaapiEncoderMpeg4 *mpeg4encoder = GST_VAAPI_ENCODER_MPEG4(encode->encoder); + ENCODER_ASSERT(mpeg4encoder); + + switch (prop_id) { + case MPEG4_PROP_PROFILE: + g_value_set_uint (value, mpeg4encoder->profile); + break; + + case MPEG4_PROP_BITRATE: + g_value_set_uint (value, mpeg4encoder->bitrate); + break; + + case MPEG4_PROP_INTRA_PERIOD: + g_value_set_uint (value, mpeg4encoder->intra_period); + break; + + case MPEG4_PROP_INIT_QP: + g_value_set_uint (value, mpeg4encoder->init_qp); + break; + + case MPEG4_PROP_MIN_QP: + g_value_set_uint (value, mpeg4encoder->min_qp); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_encode_mpeg4_base_init(gpointer klass) +{ + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + + gst_element_class_set_details(element_class, &gst_vaapi_encode_mpeg4_details); + + /* sink pad */ + gst_element_class_add_pad_template( + element_class, + gst_static_pad_template_get(&gst_vaapi_encode_mpeg4_sink_factory) + ); + + /* src pad */ + gst_element_class_add_pad_template( + element_class, + gst_static_pad_template_get(&gst_vaapi_encode_mpeg4_src_factory) + ); +} + +static void +gst_vaapi_encode_mpeg4_class_init(GstVaapiEncodeMpeg4Class *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + + GST_DEBUG_CATEGORY_INIT (gst_vaapi_encode_mpeg4_debug, + "vaapimpeg4encode", + 0, + "vaapimpeg4encode element"); + + object_class->finalize = gst_vaapi_encode_mpeg4_finalize; + object_class->set_property = gst_vaapi_encode_mpeg4_set_property; + object_class->get_property = gst_vaapi_encode_mpeg4_get_property; + + + g_object_class_install_property ( + object_class, + MPEG4_PROP_PROFILE, + g_param_spec_uint ( + "profile", + "MPEG4 Profile", + "Profile supports: 2(Baseline), 3(ASP)", + 2, + 3, + 2, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + MPEG4_PROP_BITRATE, + g_param_spec_uint ( + "bitrate", + "MPEG4 encoding bitrate(kpbs)", + "MPEG4 encoding bitrate(kpbs), (0, auto-calculate)", + 0, + 100*1024, + 0, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + MPEG4_PROP_INTRA_PERIOD, + g_param_spec_uint ( + "intra-period", + "MPEG4 encoding intra-period", + "MPEG4 encoding intra-period", + 1, + 300, + MPEG4_DEFAULT_INTRA_PERIOD, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + MPEG4_PROP_INIT_QP, + g_param_spec_uint ( + "init-qp", + "MPEG4 init-qp", + "MPEG4 init-qp", + 1, + 51, + MPEG4_DEFAULT_INIT_QP, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + MPEG4_PROP_MIN_QP, + g_param_spec_uint ( + "min-qp", + "MPEG4 min-qp", + "MPEG4 min-qp", + 1, + 51, + MPEG4_DEFAULT_MIN_QP, + G_PARAM_READWRITE)); +} diff --git a/gst/vaapi/gstvaapiencode_mpeg4.h b/gst/vaapi/gstvaapiencode_mpeg4.h new file mode 100644 index 0000000..e13a406 --- /dev/null +++ b/gst/vaapi/gstvaapiencode_mpeg4.h @@ -0,0 +1,70 @@ +/* + * gstvaapiencode_mpeg4.h - VA-API MPEG-4 encoder + * + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_ENCODE_MPEG4_H +#define GST_VAAPI_ENCODE_MPEG4_H + +#include +#include "gstvaapiencode.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPI_ENCODE_MPEG4 \ + (gst_vaapi_encode_mpeg4_get_type()) + +#define GST_IS_VAAPI_ENCODE_MPEG4(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_ENCODE_MPEG4)) + +#define GST_IS_VAAPI_ENCODE_MPEG4_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_ENCODE_MPEG4)) + +#define GST_VAAPI_ENCODE_MPEG4_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GST_TYPE_VAAPI_ENCODE_MPEG4, \ + GstVaapiEncodeMpeg4Class)) + +#define GST_VAAPI_ENCODE_MPEG4(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GST_TYPE_VAAPI_ENCODE_MPEG4, \ + GstVaapiEncodeMpeg4)) + +#define GST_VAAPI_ENCODE_MPEG4_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GST_TYPE_VAAPI_ENCODE_MPEG4, \ + GstVaapiEncodeMpeg4Class)) + + +typedef struct _GstVaapiEncodeMpeg4 GstVaapiEncodeMpeg4; +typedef struct _GstVaapiEncodeMpeg4Class GstVaapiEncodeMpeg4Class; + +struct _GstVaapiEncodeMpeg4 { + GstVaapiEncode parent; +}; + +struct _GstVaapiEncodeMpeg4Class { + GstVaapiEncodeClass parent_class; +}; + +GType gst_vaapi_encode_mpeg4_get_type(void); + +G_END_DECLS + +#endif /* GST_VAAPI_ENCODE_MPEG4_H */ diff --git a/gst/vaapi/gstvaapipluginbuffer.c b/gst/vaapi/gstvaapipluginbuffer.c new file mode 100644 index 0000000..33cb917 --- /dev/null +++ b/gst/vaapi/gstvaapipluginbuffer.c @@ -0,0 +1,137 @@ +/* + * gstvaapipluginbuffer.c - Private GStreamer/VA video buffers + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#if USE_GLX +# include +#endif +#include "gstvaapipluginbuffer.h" + +static GType +get_type(GstVaapiDisplay *display) +{ + GType type; + + switch (gst_vaapi_display_get_display_type(display)) { +#if USE_GLX + case GST_VAAPI_DISPLAY_TYPE_GLX: + type = GST_VAAPI_TYPE_VIDEO_BUFFER_GLX; + break; +#endif + default: + type = GST_VAAPI_TYPE_VIDEO_BUFFER; + break; + } + return type; +} + +GstBuffer * +gst_vaapi_video_buffer_new(GstVaapiDisplay *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + + return gst_vaapi_video_buffer_typed_new(get_type(display), display); +} + +GstBuffer * +gst_vaapi_video_buffer_new_from_pool(GstVaapiVideoPool *pool) +{ + GstVaapiDisplay *display; + + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), NULL); + + display = gst_vaapi_video_pool_get_display(pool); + if (!display) + return NULL; + return gst_vaapi_video_buffer_typed_new_from_pool(get_type(display), pool); +} + +GstBuffer * +gst_vaapi_video_buffer_new_from_buffer(GstBuffer *buffer) +{ + GstVaapiVideoBuffer *vbuffer; + GstVaapiDisplay *display; + + g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), NULL); + + vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer); + display = gst_vaapi_video_buffer_get_display(vbuffer); + if (!display) + return NULL; + + return gst_vaapi_video_buffer_typed_new_from_buffer( + get_type(display), buffer); +} + +GstBuffer * +gst_vaapi_video_buffer_new_with_image(GstVaapiImage *image) +{ + GstVaapiDisplay *display; + + g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL); + + display = gst_vaapi_object_get_display(GST_VAAPI_OBJECT(image)); + if (!display) + return NULL; + + return gst_vaapi_video_buffer_typed_new_with_image( + get_type(display), image); +} + +GstBuffer * +gst_vaapi_video_buffer_new_with_surface(GstVaapiSurface *surface) +{ + GstVaapiDisplay *display; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL); + + display = gst_vaapi_object_get_display(GST_VAAPI_OBJECT(surface)); + if (!display) + return NULL; + + return gst_vaapi_video_buffer_typed_new_with_surface( + get_type(display), surface); +} + +GstBuffer * +gst_vaapi_video_buffer_new_with_surface_proxy(GstVaapiSurfaceProxy *proxy) +{ + GstVaapiDisplay *display; + GstVaapiSurface *surface; + + g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), NULL); + + surface = gst_vaapi_surface_proxy_get_surface(proxy); + if (!surface) + return NULL; + + display = gst_vaapi_object_get_display(GST_VAAPI_OBJECT(surface)); + if (!display) + return NULL; + + return gst_vaapi_video_buffer_typed_new_with_surface_proxy( + get_type(display), proxy); +} diff --git a/gst/vaapi/gstvaapipluginbuffer.h b/gst/vaapi/gstvaapipluginbuffer.h new file mode 100644 index 0000000..d6798d5 --- /dev/null +++ b/gst/vaapi/gstvaapipluginbuffer.h @@ -0,0 +1,49 @@ +/* + * gstvaapipluginbuffer.h - Private GStreamer/VA video buffers + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_PLUGIN_BUFFER_H +#define GST_VAAPI_PLUGIN_BUFFER_H + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new(GstVaapiDisplay *display); + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new_from_pool(GstVaapiVideoPool *pool); + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new_from_buffer(GstBuffer *buffer); + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new_with_image(GstVaapiImage *image); + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new_with_surface(GstVaapiSurface *surface); + +G_GNUC_INTERNAL +GstBuffer * +gst_vaapi_video_buffer_new_with_surface_proxy(GstVaapiSurfaceProxy *proxy); + +#endif /* GST_VAAPI_PLUGIN_BUFFER_H */ diff --git a/gst/vaapi/gstvaapipluginutil.c b/gst/vaapi/gstvaapipluginutil.c new file mode 100644 index 0000000..0a56893 --- /dev/null +++ b/gst/vaapi/gstvaapipluginutil.c @@ -0,0 +1,333 @@ +/* + * gstvaapipluginutil.h - VA-API plugin helpers + * + * Copyright (C) 2011-2012 Intel Corporation + * Copyright (C) 2011 Collabora + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#if USE_DRM +# include +#endif +#if USE_X11 +# include +#endif +#if USE_GLX +# include +#endif +#if USE_WAYLAND +# include +#endif +#include "gstvaapipluginutil.h" + +/* Preferred first */ +static const char *display_types[] = { + "gst-vaapi-display", + "vaapi-display", +#if USE_WAYLAND + "wl-display", + "wl-display-name", +#endif +#if USE_X11 + "x11-display", + "x11-display-name", +#endif +#if USE_DRM + "drm-device", + "drm-device-path", +#endif + NULL +}; + +typedef struct { + const gchar *type_str; + GstVaapiDisplayType type; + GstVaapiDisplay * (*create_display)(const gchar *); +} DisplayMap; + +static const DisplayMap g_display_map[] = { +#if USE_WAYLAND + { "wayland", + GST_VAAPI_DISPLAY_TYPE_WAYLAND, + gst_vaapi_display_wayland_new }, +#endif +#if USE_X11 + { "x11", + GST_VAAPI_DISPLAY_TYPE_X11, + gst_vaapi_display_x11_new }, +#endif +#if USE_GLX + { "glx", + GST_VAAPI_DISPLAY_TYPE_GLX, + gst_vaapi_display_glx_new }, +#endif +#if USE_DRM + { "drm", + GST_VAAPI_DISPLAY_TYPE_DRM, + gst_vaapi_display_drm_new }, +#endif + { NULL, } +}; + +gboolean +gst_vaapi_ensure_display( + gpointer element, + GstVaapiDisplayType display_type, + GstVaapiDisplay **display_ptr +) +{ + GstVaapiDisplay *display; + GstVideoContext *context; + const DisplayMap *m; + + g_return_val_if_fail(GST_IS_VIDEO_CONTEXT(element), FALSE); + g_return_val_if_fail(display_ptr != NULL, FALSE); + + /* Already exist ? */ + display = *display_ptr; + if (display) + return TRUE; + + context = GST_VIDEO_CONTEXT(element); + g_return_val_if_fail(context != NULL, FALSE); + + gst_video_context_prepare(context, display_types); + + /* Neighbour found and it updated the display */ + if (*display_ptr) + return TRUE; + + /* If no neighboor, or application not interested, use system default */ + for (m = g_display_map; m->type_str != NULL; m++) { + if (display_type != GST_VAAPI_DISPLAY_TYPE_ANY && + display_type != m->type) + continue; + + display = m->create_display(NULL); + if (display) { + /* FIXME: allocator should return NULL if an error occurred */ + if (gst_vaapi_display_get_display(display)) { + display_type = m->type; + break; + } + g_object_unref(display); + display = NULL; + } + + if (display_type != GST_VAAPI_DISPLAY_TYPE_ANY) + break; + } + + if (display_ptr) + *display_ptr = display; + return display != NULL; +} + +void +gst_vaapi_set_display( + const gchar *type, + const GValue *value, + GstVaapiDisplay **display +) +{ + GstVaapiDisplay *dpy = NULL; + + if (!strcmp(type, "vaapi-display")) { + g_return_if_fail(G_VALUE_HOLDS_POINTER(value)); + dpy = gst_vaapi_display_new_with_display(g_value_get_pointer(value)); + } + else if (!strcmp(type, "gst-vaapi-display")) { + g_return_if_fail(G_VALUE_HOLDS_OBJECT(value)); + dpy = g_value_dup_object(value); + } +#if USE_DRM + else if (!strcmp(type, "drm-device")) { + gint device; + g_return_if_fail(G_VALUE_HOLDS_INT(value)); + device = g_value_get_int(value); + dpy = gst_vaapi_display_drm_new_with_device(device); + } + else if (!strcmp(type, "drm-device-path")) { + const gchar *device_path; + g_return_if_fail(G_VALUE_HOLDS_STRING(value)); + device_path = g_value_get_string(value); + dpy = gst_vaapi_display_drm_new(device_path); + } +#endif +#if USE_X11 + else if (!strcmp(type, "x11-display-name")) { + g_return_if_fail(G_VALUE_HOLDS_STRING(value)); +#if USE_GLX + dpy = gst_vaapi_display_glx_new(g_value_get_string(value)); +#endif + if (!dpy) + dpy = gst_vaapi_display_x11_new(g_value_get_string(value)); + } + else if (!strcmp(type, "x11-display")) { + g_return_if_fail(G_VALUE_HOLDS_POINTER(value)); +#if USE_GLX + dpy = gst_vaapi_display_glx_new_with_display(g_value_get_pointer(value)); +#endif + if (!dpy) + dpy = gst_vaapi_display_x11_new_with_display(g_value_get_pointer(value)); + } +#endif +#if USE_WAYLAND + else if (!strcmp(type, "wl-display")) { + struct wl_display *wl_display; + g_return_if_fail(G_VALUE_HOLDS_POINTER(value)); + wl_display = g_value_get_pointer(value); + dpy = gst_vaapi_display_wayland_new_with_display(wl_display); + } + else if (!strcmp(type, "wl-display-name")) { + const gchar *display_name; + g_return_if_fail(G_VALUE_HOLDS_STRING(value)); + display_name = g_value_get_string(value); + dpy = gst_vaapi_display_wayland_new(display_name); + } +#endif + + if (dpy) { + if (*display) + g_object_unref(*display); + *display = dpy; + } +} + +gboolean +gst_vaapi_reply_to_query(GstQuery *query, GstVaapiDisplay *display) +{ + GstVaapiDisplayType display_type; + const gchar **types; + const gchar *type; + gint i; + gboolean res = FALSE; + + if (!display) + return FALSE; + + types = gst_video_context_query_get_supported_types(query); + + if (!types) + return FALSE; + + display_type = gst_vaapi_display_get_display_type(display); + for (i = 0; types[i] && !res; i++) { + type = types[i]; + + res = TRUE; + if (!strcmp(type, "gst-vaapi-display")) { + gst_video_context_query_set_object(query, type, G_OBJECT(display)); + } + else if (!strcmp(type, "vaapi-display")) { + VADisplay vadpy = gst_vaapi_display_get_display(display); + gst_video_context_query_set_pointer(query, type, vadpy); + } + else { + switch (display_type) { +#if USE_DRM + case GST_VAAPI_DISPLAY_TYPE_DRM: { + GstVaapiDisplayDRM * const drm_dpy = + GST_VAAPI_DISPLAY_DRM(display); + if (!strcmp(type, "drm-device-path")) + gst_video_context_query_set_string(query, type, + gst_vaapi_display_drm_get_device_path(drm_dpy)); +#if 0 + /* XXX: gst_video_context_query_set_int() does not exist yet */ + else if (!strcmp(type, "drm-device")) + gst_video_context_query_set_int(query, type, + gst_vaapi_display_drm_get_device(drm_dpy)); +#endif + else + res = FALSE; + break; + } +#endif +#if USE_X11 +#if USE_GLX + case GST_VAAPI_DISPLAY_TYPE_GLX: +#endif + case GST_VAAPI_DISPLAY_TYPE_X11: { + GstVaapiDisplayX11 * const xvadpy = + GST_VAAPI_DISPLAY_X11(display); + Display * const x11dpy = + gst_vaapi_display_x11_get_display(xvadpy); + if (!strcmp(type, "x11-display")) + gst_video_context_query_set_pointer(query, type, x11dpy); + else if (!strcmp(type, "x11-display-name")) + gst_video_context_query_set_string(query, type, + DisplayString(x11dpy)); + else + res = FALSE; + break; + } +#endif +#if USE_WAYLAND + case GST_VAAPI_DISPLAY_TYPE_WAYLAND: { + GstVaapiDisplayWayland * const wlvadpy = + GST_VAAPI_DISPLAY_WAYLAND(display); + struct wl_display * const wldpy = + gst_vaapi_display_wayland_get_display(wlvadpy); + if (!strcmp(type, "wl-display")) + gst_video_context_query_set_pointer(query, type, wldpy); + else + res = FALSE; + break; + } +#endif + default: + res = FALSE; + break; + } + } + } + return res; +} + +gboolean +gst_vaapi_append_surface_caps(GstCaps *out_caps, GstCaps *in_caps) +{ + GstStructure *structure; + const GValue *v_width, *v_height, *v_framerate, *v_par; + guint i, n_structures; + + structure = gst_caps_get_structure(in_caps, 0); + v_width = gst_structure_get_value(structure, "width"); + v_height = gst_structure_get_value(structure, "height"); + v_framerate = gst_structure_get_value(structure, "framerate"); + v_par = gst_structure_get_value(structure, "pixel-aspect-ratio"); + if (!v_width || !v_height) + return FALSE; + + n_structures = gst_caps_get_size(out_caps); + for (i = 0; i < n_structures; i++) { + structure = gst_caps_get_structure(out_caps, i); + gst_structure_set_value(structure, "width", v_width); + gst_structure_set_value(structure, "height", v_height); + if (v_framerate) + gst_structure_set_value(structure, "framerate", v_framerate); + if (v_par) + gst_structure_set_value(structure, "pixel-aspect-ratio", v_par); + } + return TRUE; +} diff --git a/gst/vaapi/gstvaapipluginutil.h b/gst/vaapi/gstvaapipluginutil.h new file mode 100644 index 0000000..78f274f --- /dev/null +++ b/gst/vaapi/gstvaapipluginutil.h @@ -0,0 +1,59 @@ +/* + * gstvaapipluginutil.h - VA-API plugins private helper + * + * Copyright (C) 2011-2012 Intel Corporation + * Copyright (C) 2011 Collabora + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_PLUGIN_UTIL_H +#define GST_VAAPI_PLUGIN_UTIL_H + +#include + +G_GNUC_INTERNAL +gboolean +gst_vaapi_ensure_display( + gpointer element, + GstVaapiDisplayType display_type, + GstVaapiDisplay **display +); + +G_GNUC_INTERNAL +void +gst_vaapi_set_display( + const gchar *type, + const GValue *value, + GstVaapiDisplay **display +); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_reply_to_query(GstQuery *query, GstVaapiDisplay *display); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_append_surface_caps (GstCaps *out_caps, GstCaps *in_caps); + +#ifndef G_PRIMITIVE_SWAP +#define G_PRIMITIVE_SWAP(type, a, b) do { \ + const type t = a; a = b; b = t; \ + } while (0) +#endif + +#endif /* GST_VAAPI_PLUGIN_UTIL_H */ diff --git a/gst/vaapi/gstvaapipostproc.c b/gst/vaapi/gstvaapipostproc.c new file mode 100644 index 0000000..6f6a818 --- /dev/null +++ b/gst/vaapi/gstvaapipostproc.c @@ -0,0 +1,746 @@ +/* + * gstvaapipostproc.c - VA-API video postprocessing + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapipostproc + * @short_description: A video postprocessing filter + * + * vaapipostproc consists in various postprocessing algorithms to be + * applied to VA surfaces. So far, only basic bob deinterlacing is + * implemented. + */ + +#include "config.h" +#include +#include +#include + +#include "gstvaapipostproc.h" +#include "gstvaapipluginutil.h" +#include "gstvaapipluginbuffer.h" + +#define GST_PLUGIN_NAME "vaapipostproc" +#define GST_PLUGIN_DESC "A video postprocessing filter" + +GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapipostproc); +#define GST_CAT_DEFAULT gst_debug_vaapipostproc + +/* ElementFactory information */ +static const GstElementDetails gst_vaapipostproc_details = + GST_ELEMENT_DETAILS( + "VA-API video postprocessing", + "Filter/Converter/Video", + GST_PLUGIN_DESC, + "Gwenole Beauchesne "); + +/* Default templates */ +static const char gst_vaapipostproc_sink_caps_str[] = + GST_VAAPI_SURFACE_CAPS ", " + "interlaced = (boolean) { true, false }"; + +static const char gst_vaapipostproc_src_caps_str[] = + GST_VAAPI_SURFACE_CAPS ", " + "interlaced = (boolean) false"; + +static GstStaticPadTemplate gst_vaapipostproc_sink_factory = + GST_STATIC_PAD_TEMPLATE( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapipostproc_sink_caps_str)); + +static GstStaticPadTemplate gst_vaapipostproc_src_factory = + GST_STATIC_PAD_TEMPLATE( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapipostproc_src_caps_str)); + +static void +gst_vaapipostproc_implements_iface_init(GstImplementsInterfaceClass *iface); + +static void +gst_video_context_interface_init(GstVideoContextInterface *iface); + +#define GstVideoContextClass GstVideoContextInterface +G_DEFINE_TYPE_WITH_CODE( + GstVaapiPostproc, + gst_vaapipostproc, + GST_TYPE_ELEMENT, + G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE, + gst_vaapipostproc_implements_iface_init); + G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT, + gst_video_context_interface_init)); + +enum { + PROP_0, + + PROP_DEINTERLACE_MODE, + PROP_DEINTERLACE_METHOD, +}; + +#define DEFAULT_DEINTERLACE_MODE GST_VAAPI_DEINTERLACE_MODE_AUTO +#define DEFAULT_DEINTERLACE_METHOD GST_VAAPI_DEINTERLACE_METHOD_BOB + +#define GST_TYPE_VAAPI_DEINTERLACE_MODES \ + gst_vaapi_deinterlace_modes_get_type() + +static GType +gst_vaapi_deinterlace_modes_get_type(void) +{ + static GType deinterlace_modes_type = 0; + + static const GEnumValue modes_types[] = { + { GST_VAAPI_DEINTERLACE_MODE_AUTO, + "Auto detection", "auto" }, + { GST_VAAPI_DEINTERLACE_MODE_INTERLACED, + "Force deinterlacing", "interlaced" }, + { GST_VAAPI_DEINTERLACE_MODE_DISABLED, + "Never deinterlace", "disabled" }, + { 0, NULL, NULL }, + }; + + if (!deinterlace_modes_type) { + deinterlace_modes_type = + g_enum_register_static("GstVaapiDeinterlaceModes", modes_types); + } + return deinterlace_modes_type; +} + +#define GST_TYPE_VAAPI_DEINTERLACE_METHODS \ + gst_vaapi_deinterlace_methods_get_type() + +static GType +gst_vaapi_deinterlace_methods_get_type(void) +{ + static GType deinterlace_methods_type = 0; + + static const GEnumValue methods_types[] = { + { GST_VAAPI_DEINTERLACE_METHOD_BOB, + "Bob deinterlacing", "bob" }, +#if 0 + /* VA/VPP */ + { GST_VAAPI_DEINTERLACE_METHOD_WEAVE, + "Weave deinterlacing", "weave" }, + { GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE, + "Motion adaptive deinterlacing", "motion-adaptive" }, + { GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED, + "Motion compensated deinterlacing", "motion-compensated" }, +#endif + { 0, NULL, NULL }, + }; + + if (!deinterlace_methods_type) { + deinterlace_methods_type = + g_enum_register_static("GstVaapiDeinterlaceMethods", methods_types); + } + return deinterlace_methods_type; +} + +static inline GstVaapiPostproc * +get_vaapipostproc_from_pad(GstPad *pad) +{ + return GST_VAAPIPOSTPROC(gst_pad_get_parent_element(pad)); +} + +/* GstImplementsInterface interface */ + +static gboolean +gst_vaapipostproc_implements_interface_supported( + GstImplementsInterface *iface, + GType type +) +{ + return (type == GST_TYPE_VIDEO_CONTEXT); +} + +static void +gst_vaapipostproc_implements_iface_init(GstImplementsInterfaceClass *iface) +{ + iface->supported = gst_vaapipostproc_implements_interface_supported; +} + +/* GstVideoContext interface */ + +static void +gst_vaapipostproc_set_video_context( + GstVideoContext *context, + const gchar *type, + const GValue *value +) +{ + GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(context); + + gst_vaapi_set_display(type, value, &postproc->display); +} + +static void +gst_video_context_interface_init(GstVideoContextInterface *iface) +{ + iface->set_context = gst_vaapipostproc_set_video_context; +} + +static inline gboolean +gst_vaapipostproc_ensure_display(GstVaapiPostproc *postproc) +{ + return gst_vaapi_ensure_display(postproc, GST_VAAPI_DISPLAY_TYPE_ANY, + &postproc->display); +} + +static gboolean +gst_vaapipostproc_create(GstVaapiPostproc *postproc, GstCaps *caps) +{ + if (!gst_vaapipostproc_ensure_display(postproc)) + return FALSE; + + gst_caps_replace(&postproc->postproc_caps, caps); + return TRUE; +} + +static void +gst_vaapipostproc_destroy(GstVaapiPostproc *postproc) +{ + gst_caps_replace(&postproc->postproc_caps, NULL); + + g_clear_object(&postproc->display); +} + +static gboolean +gst_vaapipostproc_reset(GstVaapiPostproc *postproc, GstCaps *caps) +{ + if (postproc->postproc_caps && + gst_caps_is_always_compatible(caps, postproc->postproc_caps)) + return TRUE; + + gst_vaapipostproc_destroy(postproc); + return gst_vaapipostproc_create(postproc, caps); +} + +static gboolean +gst_vaapipostproc_start(GstVaapiPostproc *postproc) +{ + if (!gst_vaapipostproc_ensure_display(postproc)) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapipostproc_stop(GstVaapiPostproc *postproc) +{ + if (postproc->display) { + g_object_unref(postproc->display); + postproc->display = NULL; + } + return TRUE; +} + +static GstFlowReturn +gst_vaapipostproc_process(GstVaapiPostproc *postproc, GstBuffer *buf) +{ + GstVaapiVideoBuffer *vbuf = GST_VAAPI_VIDEO_BUFFER(buf); + GstVaapiSurfaceProxy *proxy; + GstClockTime timestamp; + GstFlowReturn ret; + GstBuffer *outbuf = NULL; + guint outbuf_flags, flags; + gboolean interlaced, tff; + + flags = gst_vaapi_video_buffer_get_render_flags(vbuf); + + /* Deinterlacing disabled, push frame */ + if (!postproc->deinterlace) { + gst_vaapi_video_buffer_set_render_flags(vbuf, flags); + ret = gst_pad_push(postproc->srcpad, buf); + if (ret != GST_FLOW_OK) + goto error_push_buffer; + return GST_FLOW_OK; + } + + timestamp = GST_BUFFER_TIMESTAMP(buf); + proxy = gst_vaapi_video_buffer_get_surface_proxy(vbuf); + interlaced = gst_vaapi_surface_proxy_get_interlaced(proxy); + tff = gst_vaapi_surface_proxy_get_tff(proxy); + + flags &= ~(GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD| + GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD); + + /* First field */ + outbuf = gst_vaapi_video_buffer_new_with_surface_proxy(proxy); + if (!outbuf) + goto error_create_buffer; + + vbuf = GST_VAAPI_VIDEO_BUFFER(outbuf); + outbuf_flags = flags; + outbuf_flags |= interlaced ? ( + tff ? + GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD : + GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) : + GST_VAAPI_PICTURE_STRUCTURE_FRAME; + gst_vaapi_video_buffer_set_render_flags(vbuf, outbuf_flags); + + GST_BUFFER_TIMESTAMP(outbuf) = timestamp; + GST_BUFFER_DURATION(outbuf) = postproc->field_duration; + gst_buffer_set_caps(outbuf, postproc->srcpad_caps); + ret = gst_pad_push(postproc->srcpad, outbuf); + if (ret != GST_FLOW_OK) + goto error_push_buffer; + + /* Second field */ + outbuf = gst_vaapi_video_buffer_new_with_surface_proxy(proxy); + if (!outbuf) + goto error_create_buffer; + + vbuf = GST_VAAPI_VIDEO_BUFFER(outbuf); + outbuf_flags = flags; + outbuf_flags |= interlaced ? ( + tff ? + GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD : + GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) : + GST_VAAPI_PICTURE_STRUCTURE_FRAME; + gst_vaapi_video_buffer_set_render_flags(vbuf, outbuf_flags); + + GST_BUFFER_TIMESTAMP(outbuf) = timestamp + postproc->field_duration; + GST_BUFFER_DURATION(outbuf) = postproc->field_duration; + gst_buffer_set_caps(outbuf, postproc->srcpad_caps); + ret = gst_pad_push(postproc->srcpad, outbuf); + if (ret != GST_FLOW_OK) + goto error_push_buffer; + + gst_buffer_unref(buf); + return GST_FLOW_OK; + + /* ERRORS */ +error_create_buffer: + { + GST_ERROR("failed to create output buffer"); + gst_buffer_unref(buf); + return GST_FLOW_UNEXPECTED; + } +error_push_buffer: + { + if (ret != GST_FLOW_WRONG_STATE) + GST_ERROR("failed to push output buffer to video sink"); + gst_buffer_unref(buf); + return GST_FLOW_UNEXPECTED; + } +} + +static gboolean +gst_vaapipostproc_update_sink_caps(GstVaapiPostproc *postproc, GstCaps *caps) +{ + gint fps_n, fps_d; + gboolean interlaced; + + if (!gst_video_parse_caps_framerate(caps, &fps_n, &fps_d)) + return FALSE; + postproc->fps_n = fps_n; + postproc->fps_d = fps_d; + + switch (postproc->deinterlace_mode) { + case GST_VAAPI_DEINTERLACE_MODE_AUTO: + if (!gst_video_format_parse_caps_interlaced(caps, &interlaced)) + return FALSE; + postproc->deinterlace = interlaced; + break; + case GST_VAAPI_DEINTERLACE_MODE_INTERLACED: + postproc->deinterlace = TRUE; + break; + case GST_VAAPI_DEINTERLACE_MODE_DISABLED: + postproc->deinterlace = FALSE; + break; + } + + postproc->field_duration = gst_util_uint64_scale( + GST_SECOND, + postproc->fps_d, + (1 + postproc->deinterlace) * postproc->fps_n + ); + + gst_caps_replace(&postproc->sinkpad_caps, caps); + return TRUE; +} + +static gboolean +gst_vaapipostproc_update_src_caps(GstVaapiPostproc *postproc, GstCaps *caps) +{ + GstCaps *src_caps; + GstStructure *structure; + const GValue *v_width, *v_height, *v_par; + gint fps_n, fps_d; + + if (postproc->srcpad_caps) + src_caps = gst_caps_make_writable(postproc->srcpad_caps); + else + src_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME); + if (!src_caps) + return FALSE; + postproc->srcpad_caps = src_caps; + + structure = gst_caps_get_structure(caps, 0); + v_width = gst_structure_get_value(structure, "width"); + v_height = gst_structure_get_value(structure, "height"); + v_par = gst_structure_get_value(structure, "pixel-aspect-ratio"); + + structure = gst_caps_get_structure(src_caps, 0); + if (v_width && v_height) { + gst_structure_set_value(structure, "width", v_width); + gst_structure_set_value(structure, "height", v_height); + } + if (v_par) + gst_structure_set_value(structure, "pixel-aspect-ratio", v_par); + + gst_structure_set(structure, "type", G_TYPE_STRING, "vaapi", NULL); + gst_structure_set(structure, "opengl", G_TYPE_BOOLEAN, USE_GLX, NULL); + + if (!postproc->deinterlace) + gst_structure_remove_field(structure, "interlaced"); + else { + /* Set double framerate in interlaced mode */ + if (!gst_util_fraction_multiply(postproc->fps_n, postproc->fps_d, + 2, 1, + &fps_n, &fps_d)) + return FALSE; + + gst_structure_set( + structure, + "interlaced", G_TYPE_BOOLEAN, FALSE, + "framerate", GST_TYPE_FRACTION, fps_n, fps_d, + NULL + ); + } + return gst_pad_set_caps(postproc->srcpad, src_caps); +} + +static gboolean +gst_vaapipostproc_ensure_allowed_caps(GstVaapiPostproc *postproc) +{ + if (postproc->allowed_caps) + return TRUE; + + postproc->allowed_caps = + gst_caps_from_string(gst_vaapipostproc_sink_caps_str); + if (!postproc->allowed_caps) + return FALSE; + + /* XXX: append VA/VPP filters */ + return TRUE; +} + +static GstCaps * +gst_vaapipostproc_get_caps(GstPad *pad) +{ + GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad); + GstCaps *out_caps; + + if (gst_vaapipostproc_ensure_allowed_caps(postproc)) + out_caps = gst_caps_ref(postproc->allowed_caps); + else + out_caps = gst_caps_new_empty(); + + gst_object_unref(postproc); + return out_caps; +} + +static gboolean +gst_vaapipostproc_set_caps(GstPad *pad, GstCaps *caps) +{ + GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad); + gboolean success = FALSE; + + g_return_val_if_fail(pad == postproc->sinkpad, FALSE); + + do { + if (!gst_vaapipostproc_update_sink_caps(postproc, caps)) + break; + if (!gst_vaapipostproc_update_src_caps(postproc, caps)) + break; + if (!gst_vaapipostproc_reset(postproc, postproc->sinkpad_caps)) + break; + success = TRUE; + } while (0); + gst_object_unref(postproc); + return success; +} + +static GstFlowReturn +gst_vaapipostproc_chain(GstPad *pad, GstBuffer *buf) +{ + GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad); + GstFlowReturn ret; + + ret = gst_vaapipostproc_process(postproc, buf); + gst_object_unref(postproc); + return ret; +} + +static gboolean +gst_vaapipostproc_sink_event(GstPad *pad, GstEvent *event) +{ + GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad); + gboolean success; + + GST_DEBUG("handle sink event '%s'", GST_EVENT_TYPE_NAME(event)); + + /* Propagate event downstream */ + success = gst_pad_push_event(postproc->srcpad, event); + gst_object_unref(postproc); + return success; +} + +static gboolean +gst_vaapipostproc_src_event(GstPad *pad, GstEvent *event) +{ + GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad); + gboolean success; + + GST_DEBUG("handle src event '%s'", GST_EVENT_TYPE_NAME(event)); + + /* Propagate event upstream */ + success = gst_pad_push_event(postproc->sinkpad, event); + gst_object_unref(postproc); + return success; +} + +static gboolean +gst_vaapipostproc_query(GstPad *pad, GstQuery *query) +{ + GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad); + gboolean success; + + GST_DEBUG("sharing display %p", postproc->display); + + if (gst_vaapi_reply_to_query(query, postproc->display)) + success = TRUE; + else + success = gst_pad_query_default(pad, query); + + gst_object_unref(postproc); + return success; +} + +static void +gst_vaapipostproc_finalize(GObject *object) +{ + GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object); + + gst_vaapipostproc_destroy(postproc); + + gst_caps_replace(&postproc->sinkpad_caps, NULL); + gst_caps_replace(&postproc->srcpad_caps, NULL); + gst_caps_replace(&postproc->allowed_caps, NULL); + + G_OBJECT_CLASS(gst_vaapipostproc_parent_class)->finalize(object); +} + +static void +gst_vaapipostproc_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object); + + switch (prop_id) { + case PROP_DEINTERLACE_MODE: + postproc->deinterlace_mode = g_value_get_enum(value); + break; + case PROP_DEINTERLACE_METHOD: + postproc->deinterlace_method = g_value_get_enum(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapipostproc_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object); + + switch (prop_id) { + case PROP_DEINTERLACE_MODE: + g_value_set_enum(value, postproc->deinterlace_mode); + break; + case PROP_DEINTERLACE_METHOD: + g_value_set_enum(value, postproc->deinterlace_method); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static GstStateChangeReturn +gst_vaapipostproc_change_state(GstElement *element, GstStateChange transition) +{ + GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(element); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!gst_vaapipostproc_start(postproc)) + return GST_STATE_CHANGE_FAILURE; + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS(gst_vaapipostproc_parent_class)->change_state(element, transition); + if (ret != GST_STATE_CHANGE_SUCCESS) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + if (!gst_vaapipostproc_stop(postproc)) + return GST_STATE_CHANGE_FAILURE; + break; + default: + break; + } + return GST_STATE_CHANGE_SUCCESS; +} + +static void +gst_vaapipostproc_class_init(GstVaapiPostprocClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + GstPadTemplate *pad_template; + + GST_DEBUG_CATEGORY_INIT(gst_debug_vaapipostproc, + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); + + object_class->finalize = gst_vaapipostproc_finalize; + object_class->set_property = gst_vaapipostproc_set_property; + object_class->get_property = gst_vaapipostproc_get_property; + + element_class->change_state = gst_vaapipostproc_change_state; + + gst_element_class_set_details_simple( + element_class, + gst_vaapipostproc_details.longname, + gst_vaapipostproc_details.klass, + gst_vaapipostproc_details.description, + gst_vaapipostproc_details.author + ); + + /* sink pad */ + pad_template = gst_static_pad_template_get(&gst_vaapipostproc_sink_factory); + gst_element_class_add_pad_template(element_class, pad_template); + gst_object_unref(pad_template); + + /* src pad */ + pad_template = gst_static_pad_template_get(&gst_vaapipostproc_src_factory); + gst_element_class_add_pad_template(element_class, pad_template); + gst_object_unref(pad_template); + + /** + * GstVaapiPostproc:deinterlace-mode: + * + * This selects whether the deinterlacing should always be applied or if + * they should only be applied on content that has the "interlaced" flag + * on the caps. + */ + g_object_class_install_property + (object_class, + PROP_DEINTERLACE_MODE, + g_param_spec_enum("deinterlace", + "Deinterlace", + "Deinterlace mode to use", + GST_TYPE_VAAPI_DEINTERLACE_MODES, + DEFAULT_DEINTERLACE_MODE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstVaapiPostproc:deinterlace-method: + * + * This selects the deinterlacing method to apply. + */ + g_object_class_install_property + (object_class, + PROP_DEINTERLACE_METHOD, + g_param_spec_enum("deinterlace-method", + "Deinterlace method", + "Deinterlace method to use", + GST_TYPE_VAAPI_DEINTERLACE_METHODS, + DEFAULT_DEINTERLACE_METHOD, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_vaapipostproc_init(GstVaapiPostproc *postproc) +{ + GstVaapiPostprocClass *klass = GST_VAAPIPOSTPROC_GET_CLASS(postproc); + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + + postproc->allowed_caps = NULL; + postproc->postproc_caps = NULL; + postproc->display = NULL; + postproc->surface_width = 0; + postproc->surface_height = 0; + postproc->deinterlace = FALSE; + postproc->deinterlace_mode = DEFAULT_DEINTERLACE_MODE; + postproc->deinterlace_method = DEFAULT_DEINTERLACE_METHOD; + postproc->field_duration = GST_CLOCK_TIME_NONE; + postproc->fps_n = 0; + postproc->fps_d = 0; + + /* Pad through which data comes in to the element */ + postproc->sinkpad = gst_pad_new_from_template( + gst_element_class_get_pad_template(element_class, "sink"), + "sink" + ); + postproc->sinkpad_caps = NULL; + + gst_pad_set_getcaps_function(postproc->sinkpad, gst_vaapipostproc_get_caps); + gst_pad_set_setcaps_function(postproc->sinkpad, gst_vaapipostproc_set_caps); + gst_pad_set_chain_function(postproc->sinkpad, gst_vaapipostproc_chain); + gst_pad_set_event_function(postproc->sinkpad, gst_vaapipostproc_sink_event); + gst_pad_set_query_function(postproc->sinkpad, gst_vaapipostproc_query); + gst_element_add_pad(GST_ELEMENT(postproc), postproc->sinkpad); + + /* Pad through which data goes out of the element */ + postproc->srcpad = gst_pad_new_from_template( + gst_element_class_get_pad_template(element_class, "src"), + "src" + ); + postproc->srcpad_caps = NULL; + + gst_pad_set_event_function(postproc->srcpad, gst_vaapipostproc_src_event); + gst_pad_set_query_function(postproc->srcpad, gst_vaapipostproc_query); + gst_element_add_pad(GST_ELEMENT(postproc), postproc->srcpad); +} diff --git a/gst/vaapi/gstvaapipostproc.h b/gst/vaapi/gstvaapipostproc.h new file mode 100644 index 0000000..6ec56d1 --- /dev/null +++ b/gst/vaapi/gstvaapipostproc.h @@ -0,0 +1,123 @@ +/* + * gstvaapipostproc.h - VA-API video post processing + * + * Copyright (C) 2012 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#ifndef GST_VAAPIPOSTPROC_H +#define GST_VAAPIPOSTPROC_H + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIPOSTPROC \ + (gst_vaapipostproc_get_type()) + +#define GST_VAAPIPOSTPROC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_TYPE_VAAPIPOSTPROC, \ + GstVaapiPostproc)) + +#define GST_VAAPIPOSTPROC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_TYPE_VAAPIPOSTPROC, \ + GstVaapiPostprocClass)) + +#define GST_IS_VAAPIPOSTPROC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VAAPIPOSTPROC)) + +#define GST_IS_VAAPIPOSTPROC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VAAPIPOSTPROC)) + +#define GST_VAAPIPOSTPROC_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_TYPE_VAAPIPOSTPROC, \ + GstVaapiPostprocClass)) + +typedef struct _GstVaapiPostproc GstVaapiPostproc; +typedef struct _GstVaapiPostprocClass GstVaapiPostprocClass; + +typedef enum _GstVaapiDeinterlaceMode GstVaapiDeinterlaceMode; +typedef enum _GstVaapiDeinterlaceMethod GstVaapiDeinterlaceMethod; + +/** + * GstVaapiDeinterlaceMode: + * @GST_VAAPI_DEINTERLACE_MODE_AUTO: Auto detect needs for deinterlacing. + * @GST_VAAPI_DEINTERLACE_MODE_INTERLACED: Force deinterlacing. + * @GST_VAAPI_DEINTERLACE_MODE_DISABLED: Never perform deinterlacing. + */ +enum _GstVaapiDeinterlaceMode { + GST_VAAPI_DEINTERLACE_MODE_AUTO = 0, + GST_VAAPI_DEINTERLACE_MODE_INTERLACED, + GST_VAAPI_DEINTERLACE_MODE_DISABLED, +}; + +/** + * GstVaapiDeinterlaceMethod: + * @GST_VAAPI_DEINTERLACE_METHOD_BOB: Basic bob deinterlacing algorithm. + * @GST_VAAPI_DEINTERLACE_METHOD_WEAVE: Weave deinterlacing algorithm. + * @GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE: Motion adaptive deinterlacing algorithm. + * @GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED: Motion compensated deinterlacing algorithm. + */ +enum _GstVaapiDeinterlaceMethod { + GST_VAAPI_DEINTERLACE_METHOD_BOB = 1, + GST_VAAPI_DEINTERLACE_METHOD_WEAVE, + GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE, + GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED, +}; + +struct _GstVaapiPostproc { + /*< private >*/ + GstElement parent_instance; + + GstPad *sinkpad; + GstCaps *sinkpad_caps; + GstPad *srcpad; + GstCaps *srcpad_caps; + GstCaps *allowed_caps; + GstCaps *postproc_caps; + + GstVaapiDisplay *display; + guint surface_width; + guint surface_height; + + /* Deinterlacing */ + gboolean deinterlace; + GstVaapiDeinterlaceMode deinterlace_mode; + GstVaapiDeinterlaceMethod deinterlace_method; + GstClockTime field_duration; + gint fps_n; + gint fps_d; +}; + +struct _GstVaapiPostprocClass { + /*< private >*/ + GstElementClass parent_class; +}; + +GType +gst_vaapipostproc_get_type(void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* GST_VAAPIPOSTPROC_H */ diff --git a/gst/vaapi/gstvaapisink.c b/gst/vaapi/gstvaapisink.c new file mode 100644 index 0000000..c3c55a4 --- /dev/null +++ b/gst/vaapi/gstvaapisink.c @@ -0,0 +1,1310 @@ +/* + * gstvaapisink.c - VA-API video sink + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapisink + * @short_description: A VA-API based videosink + * + * vaapisink renders video frames to a drawable (X #Window) on a local + * display using the Video Acceleration (VA) API. The element will + * create its own internal window and render into it. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include + +#if USE_DRM +# include +#endif +#if USE_X11 +# include +# include +#endif +#if USE_GLX +# include +# include +#endif +#if USE_WAYLAND +# include +# include +#endif + +/* Supported interfaces */ +#include + +#include "gstvaapisink.h" +#include "gstvaapipluginutil.h" + +#define GST_PLUGIN_NAME "vaapisink" +#define GST_PLUGIN_DESC "A VA-API based videosink" + +GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapisink); +#define GST_CAT_DEFAULT gst_debug_vaapisink + +/* ElementFactory information */ +static const GstElementDetails gst_vaapisink_details = + GST_ELEMENT_DETAILS( + "VA-API sink", + "Sink/Video", + GST_PLUGIN_DESC, + "Gwenole Beauchesne "); + +static const char gst_vaapisink_sink_caps_str[] = + GST_VAAPI_SURFACE_CAPS "; " + GST_VAAPI_BUFFER_SHARING_CAPS; + +/* Default template */ +static GstStaticPadTemplate gst_vaapisink_sink_factory = + GST_STATIC_PAD_TEMPLATE( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapisink_sink_caps_str)); + +static void +gst_vaapisink_implements_iface_init(GstImplementsInterfaceClass *iface); + +static void +gst_vaapisink_video_context_iface_init(GstVideoContextInterface *iface); + +static void +gst_vaapisink_xoverlay_iface_init(GstXOverlayClass *iface); + +G_DEFINE_TYPE_WITH_CODE( + GstVaapiSink, + gst_vaapisink, + GST_TYPE_VIDEO_SINK, + G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE, + gst_vaapisink_implements_iface_init); + G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT, + gst_vaapisink_video_context_iface_init); + G_IMPLEMENT_INTERFACE(GST_TYPE_X_OVERLAY, + gst_vaapisink_xoverlay_iface_init)); + +enum { + PROP_0, + + PROP_DISPLAY_TYPE, + PROP_FULLSCREEN, + PROP_SYNCHRONOUS, + PROP_USE_REFLECTION, + PROP_ROTATION, + PROP_IS_PIXMAP, +}; + +#define DEFAULT_DISPLAY_TYPE GST_VAAPI_DISPLAY_TYPE_ANY +#define DEFAULT_ROTATION GST_VAAPI_ROTATION_0 + +/* GstImplementsInterface interface */ +/** + * gst_vaapisink_prepare_xid: + * @overlay: a #GstXOverlay which does not yet have an XWindow or XPixmap. + * + * This will post a "prepare-xid" element message with video size and display size on the bus + * to give applications an opportunity to call + * gst_x_overlay_set_xwindow_id() before a plugin creates its own + * window or pixmap. + * + * This function should only be used by video overlay plugin developers. + */ +static void +gst_vaapisink_prepare_xid (GstXOverlay * overlay) +{ + GstStructure *s; + GstMessage *msg; + + g_return_if_fail (overlay != NULL); + g_return_if_fail (GST_IS_X_OVERLAY (overlay)); + + GstVaapiSink *sink; + sink = GST_VAAPISINK (GST_OBJECT (overlay)); + + GST_DEBUG ("post \"prepare-xid\" element message with video-width(%d), video-height(%d), display-width(%d), display-height(%d)", + sink->video_width, sink->video_height, sink->window_width, sink->window_height); + + GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xid"); + s = gst_structure_new ("prepare-xid", + "video-width", G_TYPE_INT, sink->video_width, + "video-height", G_TYPE_INT, sink->video_height, + "display-width", G_TYPE_INT, sink->window_width, + "display-height", G_TYPE_INT, sink->window_height, + NULL); + msg = gst_message_new_element (GST_OBJECT (overlay), s); + gst_element_post_message (GST_ELEMENT (overlay), msg); +} + +static gboolean +gst_vaapisink_implements_interface_supported( + GstImplementsInterface *iface, + GType type +) +{ + return (type == GST_TYPE_VIDEO_CONTEXT || + type == GST_TYPE_X_OVERLAY); +} + +static void +gst_vaapisink_implements_iface_init(GstImplementsInterfaceClass *iface) +{ + iface->supported = gst_vaapisink_implements_interface_supported; +} + +/* GstVideoContext interface */ + +static void +gst_vaapisink_set_video_context(GstVideoContext *context, const gchar *type, + const GValue *value) +{ + GstVaapiSink *sink = GST_VAAPISINK (context); + gst_vaapi_set_display (type, value, &sink->display); +} + +static void +gst_vaapisink_video_context_iface_init(GstVideoContextInterface *iface) +{ + iface->set_context = gst_vaapisink_set_video_context; +} + +/* GstXOverlay interface */ + +#if USE_X11 +static gboolean +gst_vaapisink_ensure_window_xid(GstVaapiSink *sink, guintptr window_id); +#endif + +static gboolean +gst_vaapisink_ensure_display_rect(GstVaapiSink *sink, guint width, guint height); + +static GstFlowReturn +gst_vaapisink_show_frame(GstBaseSink *base_sink, GstBuffer *buffer); + +static void +gst_vaapisink_xoverlay_set_window_handle(GstXOverlay *overlay, guintptr window) +{ + GstVaapiSink * const sink = GST_VAAPISINK(overlay); + + /* Disable GLX rendering when vaapisink is using a foreign X + window. It's pretty much useless */ + if (sink->display_type == GST_VAAPI_DISPLAY_TYPE_GLX) + sink->display_type = GST_VAAPI_DISPLAY_TYPE_X11; + + sink->foreign_window = TRUE; + + switch (sink->display_type) { +#if USE_X11 + case GST_VAAPI_DISPLAY_TYPE_X11: + gst_vaapisink_ensure_window_xid(sink, window); + break; +#endif + default: + break; + } +} + +static void +gst_vaapisink_xoverlay_set_render_rectangle( + GstXOverlay *overlay, + gint x, + gint y, + gint width, + gint height +) +{ + GstVaapiSink * const sink = GST_VAAPISINK(overlay); + GstVaapiRectangle * const render_rect = &sink->render_rect; + + render_rect->x = x; + render_rect->y = y; + render_rect->width = width; + render_rect->height = height; + + GST_DEBUG("render rect (%d,%d):%ux%u", + render_rect->x, render_rect->y, + render_rect->width, render_rect->height); + + gst_vaapisink_ensure_display_rect( + sink, + sink->render_rect.width, + sink->render_rect.height); +} + +static void +gst_vaapisink_xoverlay_expose(GstXOverlay *overlay) +{ + GstBaseSink * const base_sink = GST_BASE_SINK(overlay); + GstBuffer *buffer; + + buffer = gst_base_sink_get_last_buffer(base_sink); + if (buffer) { + gst_vaapisink_show_frame(base_sink, buffer); + gst_buffer_unref(buffer); + } +} + +static void +gst_vaapisink_xoverlay_iface_init(GstXOverlayClass *iface) +{ + iface->set_window_handle = gst_vaapisink_xoverlay_set_window_handle; + iface->set_render_rectangle = gst_vaapisink_xoverlay_set_render_rectangle; + iface->expose = gst_vaapisink_xoverlay_expose; +} + +static void +gst_vaapisink_destroy(GstVaapiSink *sink) +{ + gst_buffer_replace(&sink->video_buffer, NULL); + g_clear_object(&sink->texture); + g_clear_object(&sink->display); + + gst_caps_replace(&sink->caps, NULL); + + if (sink->video_pool) { + g_object_unref(sink->video_pool); + sink->video_pool = NULL; + } +} + +#if USE_X11 +/* Checks whether a ConfigureNotify event is in the queue */ +typedef struct _ConfigureNotifyEventPendingArgs ConfigureNotifyEventPendingArgs; +struct _ConfigureNotifyEventPendingArgs { + Window window; + guint width; + guint height; + gboolean match; +}; + +static Bool +configure_notify_event_pending_cb(Display *dpy, XEvent *xev, XPointer arg) +{ + ConfigureNotifyEventPendingArgs * const args = + (ConfigureNotifyEventPendingArgs *)arg; + + if (xev->type == ConfigureNotify && + xev->xconfigure.window == args->window && + xev->xconfigure.width == args->width && + xev->xconfigure.height == args->height) + args->match = TRUE; + + /* XXX: this is a hack to traverse the whole queue because we + can't use XPeekIfEvent() since it could block */ + return False; +} + +static gboolean +configure_notify_event_pending( + GstVaapiSink *sink, + Window window, + guint width, + guint height +) +{ + ConfigureNotifyEventPendingArgs args; + XEvent xev; + + args.window = window; + args.width = width; + args.height = height; + args.match = FALSE; + + /* XXX: don't use XPeekIfEvent() because it might block */ + XCheckIfEvent( + gst_vaapi_display_x11_get_display(GST_VAAPI_DISPLAY_X11(sink->display)), + &xev, + configure_notify_event_pending_cb, (XPointer)&args + ); + return args.match; +} +#endif + +static const gchar * +get_display_type_name(GstVaapiDisplayType display_type) +{ + gpointer const klass = g_type_class_peek(GST_VAAPI_TYPE_DISPLAY_TYPE); + GEnumValue * const e = g_enum_get_value(klass, display_type); + + if (e) + return e->value_name; + return ""; +} + +static inline gboolean +gst_vaapisink_ensure_display(GstVaapiSink *sink) +{ + GstVaapiDisplayType display_type; + GstVaapiRenderMode render_mode; + GstVaapiDisplay *old_display = sink->display; + + if (!gst_vaapi_ensure_display(sink, sink->display_type, &sink->display)) + return FALSE; + + display_type = gst_vaapi_display_get_display_type(sink->display); + if (display_type != sink->display_type || old_display != sink->display) { + GST_INFO("created %s %p", get_display_type_name(display_type), + sink->display); + sink->display_type = display_type; + + sink->use_overlay = + gst_vaapi_display_get_render_mode(sink->display, &render_mode) && + render_mode == GST_VAAPI_RENDER_MODE_OVERLAY; + GST_DEBUG("use %s rendering mode", sink->use_overlay ? "overlay" : "texture"); + + sink->use_rotation = gst_vaapi_display_has_property( + sink->display, GST_VAAPI_DISPLAY_PROP_ROTATION); + } + return TRUE; +} + +static gboolean +gst_vaapisink_ensure_display_rect(GstVaapiSink *sink, guint width, guint height) +{ + GstVaapiRectangle * const display_rect = &sink->display_rect; + guint num, den, display_par_n, display_par_d; + gboolean success; + + /* Return success if caps are not set yet */ + if (!sink->caps) + return TRUE; + + GST_DEBUG("ensure render rect within %ux%u bounds", width, height); + + gst_vaapi_display_get_pixel_aspect_ratio( + sink->display, + &display_par_n, &display_par_d + ); + GST_DEBUG("display pixel-aspect-ratio %d/%d", + display_par_n, display_par_d); + + success = gst_video_calculate_display_ratio( + &num, &den, + sink->video_width, sink->video_height, + sink->video_par_n, sink->video_par_d, + display_par_n, display_par_d + ); + if (!success) + return FALSE; + GST_DEBUG("video size %dx%d, calculated ratio %d/%d", + sink->video_width, sink->video_height, num, den); + + display_rect->width = gst_util_uint64_scale_int(height, num, den); + if (display_rect->width <= width) { + GST_DEBUG("keeping window height"); + display_rect->height = height; + } + else { + GST_DEBUG("keeping window width"); + display_rect->width = width; + display_rect->height = + gst_util_uint64_scale_int(width, den, num); + } + GST_DEBUG("scaling video to %ux%u", display_rect->width, display_rect->height); + + g_assert(display_rect->width <= width); + g_assert(display_rect->height <= height); + + display_rect->x = (width - display_rect->width) / 2; + display_rect->y = (height - display_rect->height) / 2; + + display_rect->x += sink->render_rect.x; + display_rect->y += sink->render_rect.y; + + GST_DEBUG("render rect (%d,%d):%ux%u", + display_rect->x, display_rect->y, + display_rect->width, display_rect->height); + return TRUE; +} + +static void +gst_vaapisink_ensure_window_size(GstVaapiSink *sink, guint *pwidth, guint *pheight) +{ + GstVideoRectangle src_rect, dst_rect, out_rect; + guint num, den, display_width, display_height, display_par_n, display_par_d; + gboolean success, scale; + + if (sink->foreign_window) { + *pwidth = sink->window_width; + *pheight = sink->window_height; + return; + } + + gst_vaapi_display_get_size(sink->display, &display_width, &display_height); + if (sink->fullscreen) { + *pwidth = display_width; + *pheight = display_height; + return; + } + + gst_vaapi_display_get_pixel_aspect_ratio( + sink->display, + &display_par_n, &display_par_d + ); + + success = gst_video_calculate_display_ratio( + &num, &den, + sink->video_width, sink->video_height, + sink->video_par_n, sink->video_par_d, + display_par_n, display_par_d + ); + if (!success) { + num = sink->video_par_n; + den = sink->video_par_d; + } + + src_rect.x = 0; + src_rect.y = 0; + src_rect.w = gst_util_uint64_scale_int(sink->video_height, num, den); + src_rect.h = sink->video_height; + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.w = display_width; + dst_rect.h = display_height; + scale = (src_rect.w > dst_rect.w || src_rect.h > dst_rect.h); + gst_video_sink_center_rect(src_rect, dst_rect, &out_rect, scale); + *pwidth = out_rect.w; + *pheight = out_rect.h; +} + +static inline gboolean +gst_vaapisink_ensure_window(GstVaapiSink *sink, guint width, guint height) +{ + GstVaapiDisplay * const display = sink->display; + + if (!sink->window) { + sink->render_rect.x = 0; + sink->render_rect.y = 0; + sink->render_rect.width = width; + sink->render_rect.height = height; + + switch (sink->display_type) { +#if USE_GLX + case GST_VAAPI_DISPLAY_TYPE_GLX: + sink->window = gst_vaapi_window_glx_new(display, width, height); + goto notify_xoverlay_interface; +#endif +#if USE_X11 + case GST_VAAPI_DISPLAY_TYPE_X11: + sink->window = gst_vaapi_window_x11_new(display, width, height); + notify_xoverlay_interface: + if (!sink->window) + break; + gst_x_overlay_got_window_handle( + GST_X_OVERLAY(sink), + gst_vaapi_window_x11_get_xid(GST_VAAPI_WINDOW_X11(sink->window)) + ); + break; +#endif +#if USE_WAYLAND + case GST_VAAPI_DISPLAY_TYPE_WAYLAND: + sink->window = gst_vaapi_window_wayland_new(display, width, height); + break; +#endif + default: + GST_ERROR("unsupported display type %d", sink->display_type); + return FALSE; + } + } + return sink->window != NULL; +} + +#if USE_X11 +static gboolean +gst_vaapisink_ensure_window_xid(GstVaapiSink *sink, guintptr window_id) +{ + Window rootwin; + unsigned int width, height, border_width, depth; + int x, y, i; + XID xid = window_id; + + if (!gst_vaapisink_ensure_display(sink)) + return FALSE; + + gst_vaapi_display_lock(sink->display); + XGetGeometry( + gst_vaapi_display_x11_get_display(GST_VAAPI_DISPLAY_X11(sink->display)), + xid, + &rootwin, + &x, &y, &width, &height, &border_width, &depth + ); + gst_vaapi_display_unlock(sink->display); + + sink->render_rect.x = 0; + sink->render_rect.y = 0; + sink->render_rect.width = width; + sink->render_rect.height = height; + + if ((width != sink->window_width || height != sink->window_height) && + !configure_notify_event_pending(sink, xid, width, height)) { + if (!gst_vaapisink_ensure_display_rect(sink, width, height)) + return FALSE; + sink->window_width = width; + sink->window_height = height; + } + + if (sink->is_pixmap) { + for (i = 0; i < MAX_PIXMAP_COUNT; i++) { + if (sink->pixmap_pool[i]) + if (sink->pixmap_pool[i] && + gst_vaapi_window_x11_get_xid(GST_VAAPI_WINDOW_X11(sink->pixmap_pool[i])) == xid) { + sink->window = sink->pixmap_pool[i]; + return TRUE; + } + } + } + else { + if (sink->window && + gst_vaapi_window_x11_get_xid(GST_VAAPI_WINDOW_X11(sink->window)) == xid) + return TRUE; + g_clear_object(&sink->window); + } + + switch (sink->display_type) { +#if USE_GLX + case GST_VAAPI_DISPLAY_TYPE_GLX: + sink->window = gst_vaapi_window_glx_new_with_xid(sink->display, xid); + break; +#endif + case GST_VAAPI_DISPLAY_TYPE_X11: + sink->window = gst_vaapi_window_x11_new_with_xid(sink->display, xid, sink->is_pixmap); + break; + default: + GST_ERROR("unsupported display type %d", sink->display_type); + return FALSE; + } + + gboolean save_pixmap_to_pool = FALSE; + for (i = 0; i < MAX_PIXMAP_COUNT; i++) { + if (!sink->pixmap_pool[i]) { + sink->pixmap_pool[i] = sink->window; + save_pixmap_to_pool = TRUE; + break; + } + } + + if (!save_pixmap_to_pool) { + g_clear_object(&sink->pixmap_pool[MAX_PIXMAP_COUNT-1]); + sink->pixmap_pool[MAX_PIXMAP_COUNT-1] = sink->window; + GST_WARNING("exceed MAX_PIXMAP_COUNT: %d", MAX_PIXMAP_COUNT); + } + + return sink->window != NULL; +} +#endif + +static gboolean +gst_vaapisink_ensure_rotation(GstVaapiSink *sink, gboolean recalc_display_rect) +{ + gboolean success = FALSE; + + g_return_val_if_fail(sink->display, FALSE); + + if (sink->rotation == sink->rotation_req) + return TRUE; + + if (!sink->use_rotation) { + GST_WARNING("VA display does not support rotation"); + goto end; + } + + gst_vaapi_display_lock(sink->display); + success = gst_vaapi_display_set_rotation(sink->display, sink->rotation_req); + gst_vaapi_display_unlock(sink->display); + if (!success) { + GST_ERROR("failed to change VA display rotation mode"); + goto end; + } + + if (((sink->rotation + sink->rotation_req) % 180) == 90) { + /* Orientation changed */ + G_PRIMITIVE_SWAP(guint, sink->video_width, sink->video_height); + G_PRIMITIVE_SWAP(gint, sink->video_par_n, sink->video_par_d); + } + + if (recalc_display_rect ) + gst_vaapisink_ensure_display_rect(sink, sink->render_rect.width, + sink->render_rect.height); + success = TRUE; + +end: + sink->rotation = sink->rotation_req; + return success; +} + +static gboolean +gst_vaapisink_start(GstBaseSink *base_sink) +{ + GstVaapiSink * const sink = GST_VAAPISINK(base_sink); + + return gst_vaapisink_ensure_display(sink); +} + +static gboolean +gst_vaapisink_stop(GstBaseSink *base_sink) +{ + int i = 0; + GstVaapiSink * const sink = GST_VAAPISINK(base_sink); + + gst_buffer_replace(&sink->video_buffer, NULL); + if (sink->is_pixmap) { + for (i=0; ipixmap_pool[i]) { + g_clear_object(&sink->pixmap_pool[i]); + } + } + } + else + g_clear_object(&sink->window); + sink->window = NULL; + + g_clear_object(&sink->display); + + if (sink->video_pool) { + g_object_unref(sink->video_pool); + sink->video_pool = NULL; + } + sink->buffer_sharing = FALSE; + + return TRUE; +} + +static gboolean +gst_vaapisink_set_caps(GstBaseSink *base_sink, GstCaps *caps) +{ + GstVaapiSink * const sink = GST_VAAPISINK(base_sink); + GstStructure * const structure = gst_caps_get_structure(caps, 0); + guint win_width, win_height; + gint video_width, video_height, video_par_n = 1, video_par_d = 1; + +#if USE_DRM + if (sink->display_type == GST_VAAPI_DISPLAY_TYPE_DRM) + return TRUE; +#endif + + if (!structure) + return FALSE; + if (gst_structure_has_name(structure, GST_VAAPI_BUFFER_SHARING_CAPS_NAME)) + sink->buffer_sharing = TRUE; + else + sink->buffer_sharing = FALSE; + if (!gst_structure_get_int(structure, "width", &video_width)) + return FALSE; + if (!gst_structure_get_int(structure, "height", &video_height)) + return FALSE; + sink->video_width = video_width; + sink->video_height = video_height; + + gst_video_parse_caps_pixel_aspect_ratio(caps, &video_par_n, &video_par_d); + sink->video_par_n = video_par_n; + sink->video_par_d = video_par_d; + GST_DEBUG("video pixel-aspect-ratio %d/%d", video_par_n, video_par_d); + + gst_caps_replace(&sink->caps, caps); + + if (!gst_vaapisink_ensure_display(sink)) + return FALSE; + + gst_vaapisink_ensure_rotation(sink, FALSE); + + gst_vaapisink_ensure_window_size(sink, &win_width, &win_height); + if (sink->window) { + if (!sink->foreign_window || sink->fullscreen) + gst_vaapi_window_set_size(sink->window, win_width, win_height); + } + else { + gst_vaapi_display_lock(sink->display); + gst_x_overlay_prepare_xwindow_id(GST_X_OVERLAY(sink)); + if (!sink->window) + gst_vaapisink_prepare_xid(GST_X_OVERLAY(sink)); // tizen customized interface/message for webkit-efl + gst_vaapi_display_unlock(sink->display); + if (sink->window) + return TRUE; + if (!gst_vaapisink_ensure_window(sink, win_width, win_height)) + return FALSE; + gst_vaapi_window_set_fullscreen(sink->window, sink->fullscreen); + gst_vaapi_window_show(sink->window); + gst_vaapi_window_get_size(sink->window, &win_width, &win_height); + } + sink->window_width = win_width; + sink->window_height = win_height; + if (!sink->render_rect.width || !sink->render_rect.height) { + sink->render_rect.width = win_width; + sink->render_rect.height = win_height; + } + GST_DEBUG("window size %ux%u", win_width, win_height); + + return gst_vaapisink_ensure_display_rect(sink, + sink->render_rect.width, + sink->render_rect.height); +} + +#if USE_GLX +static void +render_background(GstVaapiSink *sink) +{ + /* Original code from Mirco Muller (MacSlow): + */ + GLfloat fStartX = 0.0f; + GLfloat fStartY = 0.0f; + GLfloat fWidth = (GLfloat)sink->window_width; + GLfloat fHeight = (GLfloat)sink->window_height; + + glClear(GL_COLOR_BUFFER_BIT); + glBegin(GL_QUADS); + { + /* top third, darker grey to white */ + glColor3f(0.85f, 0.85f, 0.85f); + glVertex3f(fStartX, fStartY, 0.0f); + glColor3f(0.85f, 0.85f, 0.85f); + glVertex3f(fStartX + fWidth, fStartY, 0.0f); + glColor3f(1.0f, 1.0f, 1.0f); + glVertex3f(fStartX + fWidth, fStartY + fHeight / 3.0f, 0.0f); + glColor3f(1.0f, 1.0f, 1.0f); + glVertex3f(fStartX, fStartY + fHeight / 3.0f, 0.0f); + + /* middle third, just plain white */ + glColor3f(1.0f, 1.0f, 1.0f); + glVertex3f(fStartX, fStartY + fHeight / 3.0f, 0.0f); + glVertex3f(fStartX + fWidth, fStartY + fHeight / 3.0f, 0.0f); + glVertex3f(fStartX + fWidth, fStartY + 2.0f * fHeight / 3.0f, 0.0f); + glVertex3f(fStartX, fStartY + 2.0f * fHeight / 3.0f, 0.0f); + + /* bottom third, white to lighter grey */ + glColor3f(1.0f, 1.0f, 1.0f); + glVertex3f(fStartX, fStartY + 2.0f * fHeight / 3.0f, 0.0f); + glColor3f(1.0f, 1.0f, 1.0f); + glVertex3f(fStartX + fWidth, fStartY + 2.0f * fHeight / 3.0f, 0.0f); + glColor3f(0.62f, 0.66f, 0.69f); + glVertex3f(fStartX + fWidth, fStartY + fHeight, 0.0f); + glColor3f(0.62f, 0.66f, 0.69f); + glVertex3f(fStartX, fStartY + fHeight, 0.0f); + } + glEnd(); +} + +static void +render_frame(GstVaapiSink *sink) +{ + const guint x1 = sink->display_rect.x; + const guint x2 = sink->display_rect.x + sink->display_rect.width; + const guint y1 = sink->display_rect.y; + const guint y2 = sink->display_rect.y + sink->display_rect.height; + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + { + glTexCoord2f(0.0f, 0.0f); glVertex2i(x1, y1); + glTexCoord2f(0.0f, 1.0f); glVertex2i(x1, y2); + glTexCoord2f(1.0f, 1.0f); glVertex2i(x2, y2); + glTexCoord2f(1.0f, 0.0f); glVertex2i(x2, y1); + } + glEnd(); +} + +static void +render_reflection(GstVaapiSink *sink) +{ + const guint x1 = sink->display_rect.x; + const guint x2 = sink->display_rect.x + sink->display_rect.width; + const guint y1 = sink->display_rect.y; + const guint rh = sink->display_rect.height / 5; + GLfloat ry = 1.0f - (GLfloat)rh / (GLfloat)sink->display_rect.height; + + glBegin(GL_QUADS); + { + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glTexCoord2f(0.0f, 1.0f); glVertex2i(x1, y1); + glTexCoord2f(1.0f, 1.0f); glVertex2i(x2, y1); + + glColor4f(1.0f, 1.0f, 1.0f, 0.0f); + glTexCoord2f(1.0f, ry); glVertex2i(x2, y1 + rh); + glTexCoord2f(0.0f, ry); glVertex2i(x1, y1 + rh); + } + glEnd(); +} + +static gboolean +gst_vaapisink_show_frame_glx( + GstVaapiSink *sink, + GstVaapiSurface *surface, + guint flags +) +{ + GstVaapiWindowGLX * const window = GST_VAAPI_WINDOW_GLX(sink->window); + GLenum target; + GLuint texture; + + gst_vaapi_window_glx_make_current(window); + if (!sink->texture) { + sink->texture = gst_vaapi_texture_new( + sink->display, + GL_TEXTURE_2D, + GL_BGRA, + sink->video_width, + sink->video_height + ); + if (!sink->texture) + goto error_create_texture; + } + if (!gst_vaapi_texture_put_surface(sink->texture, surface, flags)) + goto error_transfer_surface; + + target = gst_vaapi_texture_get_target(sink->texture); + texture = gst_vaapi_texture_get_id(sink->texture); + if (target != GL_TEXTURE_2D || !texture) + return FALSE; + + if (sink->use_reflection) + render_background(sink); + + glEnable(target); + glBindTexture(target, texture); + { + if (sink->use_reflection) { + glPushMatrix(); + glRotatef(20.0f, 0.0f, 1.0f, 0.0f); + glTranslatef(50.0f, 0.0f, 0.0f); + } + render_frame(sink); + if (sink->use_reflection) { + glPushMatrix(); + glTranslatef(0.0, (GLfloat)sink->display_rect.height + 5.0f, 0.0f); + render_reflection(sink); + glPopMatrix(); + glPopMatrix(); + } + } + glBindTexture(target, 0); + glDisable(target); + gst_vaapi_window_glx_swap_buffers(window); + return TRUE; + + /* ERRORS */ +error_create_texture: + { + GST_DEBUG("could not create VA/GLX texture"); + return FALSE; + } +error_transfer_surface: + { + GST_DEBUG("could not transfer VA surface to texture"); + return FALSE; + } +} +#endif + +static inline gboolean +gst_vaapisink_put_surface( + GstVaapiSink *sink, + GstVaapiSurface *surface, + guint flags +) +{ + if (!gst_vaapi_window_put_surface(sink->window, surface, + NULL, &sink->display_rect, flags)) { + GST_DEBUG("could not render VA surface"); + return FALSE; + } + return TRUE; +} + +static GstFlowReturn +gst_vaapisink_show_frame(GstBaseSink *base_sink, GstBuffer *buffer) +{ + GstVaapiSink * const sink = GST_VAAPISINK(base_sink); + GstVaapiVideoBuffer * vbuffer; + GstVaapiSurface *surface; + guint flags; + gboolean success; + GstVideoOverlayComposition * const composition = + gst_video_buffer_get_overlay_composition(buffer); + + if (sink->buffer_sharing) + vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer->data); + else + vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer); + + if (sink->display != gst_vaapi_video_buffer_get_display (vbuffer)) { + g_clear_object(&sink->display); + sink->display = g_object_ref (gst_vaapi_video_buffer_get_display (vbuffer)); + } + + if (!sink->window) + return GST_FLOW_UNEXPECTED; + + gst_vaapisink_ensure_rotation(sink, TRUE); + + surface = gst_vaapi_video_buffer_get_surface(vbuffer); + if (!surface) + return GST_FLOW_UNEXPECTED; + + GST_DEBUG("render surface %" GST_VAAPI_ID_FORMAT, + GST_VAAPI_ID_ARGS(gst_vaapi_surface_get_id(surface))); + + flags = gst_vaapi_video_buffer_get_render_flags(vbuffer); + + if (!gst_vaapi_surface_set_subpictures_from_composition(surface, + composition, TRUE)) + GST_WARNING("could not update subtitles"); + + switch (sink->display_type) { +#if USE_GLX + case GST_VAAPI_DISPLAY_TYPE_GLX: + success = gst_vaapisink_show_frame_glx(sink, surface, flags); + break; +#endif +#if USE_DRM + case GST_VAAPI_DISPLAY_TYPE_DRM: + success = TRUE; + break; +#endif +#if USE_X11 + case GST_VAAPI_DISPLAY_TYPE_X11: + success = gst_vaapisink_put_surface(sink, surface, flags); + break; +#endif +#if USE_WAYLAND + case GST_VAAPI_DISPLAY_TYPE_WAYLAND: + success = gst_vaapisink_put_surface(sink, surface, flags); + break; +#endif + default: + GST_ERROR("unsupported display type %d", sink->display_type); + success = FALSE; + break; + } + if (!success) + return GST_FLOW_UNEXPECTED; + + /* Retain VA surface until the next one is displayed */ + if (sink->use_overlay) + gst_buffer_replace(&sink->video_buffer, buffer); + + FPS_CALCULATION(vaapisink); + return GST_FLOW_OK; +} + +static gboolean +gst_vaapisink_query(GstBaseSink *base_sink, GstQuery *query) +{ + GstVaapiSink *sink = GST_VAAPISINK(base_sink); + GST_DEBUG ("sharing display %p", sink->display); + return gst_vaapi_reply_to_query (query, sink->display); +} + +static gboolean +gst_vaapisink_ensure_video_pool( + GstVaapiSink *sink, + GstCaps *caps) +{ + GstStructure *structure; + gint width = 0, height = 0; + + g_return_val_if_fail(caps, FALSE); + + structure = gst_caps_get_structure(caps, 0); + g_return_val_if_fail(structure, FALSE); + + if (sink->video_pool) + return TRUE; + + if (!gst_structure_get_int(structure, "width", &width) || + !gst_structure_get_int(structure, "height", &height)) + return FALSE; + + sink->video_pool = gst_vaapi_surface_pool_new(sink->display, caps); + if (!sink->video_pool) { + return FALSE; + } + + return TRUE; +} + +static GstFlowReturn +gst_vaapisink_pad_buffer_alloc( + GstPad * pad, + guint64 offset, + guint size, + GstCaps * caps, + GstBuffer ** buf) +{ + GstVaapiSink * const sink = GST_VAAPISINK(GST_OBJECT_PARENT(pad)); + GstStructure *structure = NULL; + GstBuffer *video_buffer = NULL; + + if (!caps) + goto error; + + structure = gst_caps_get_structure(caps, 0); + if (!structure || + (!gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME) && + !gst_structure_has_name(structure, GST_VAAPI_BUFFER_SHARING_CAPS_NAME))) + goto error; + + if (!gst_vaapisink_ensure_display(sink)) + goto error; + + if (!gst_vaapisink_ensure_video_pool(sink, caps)) + goto error; + + video_buffer = gst_vaapi_video_buffer_new_from_pool(sink->video_pool); + + if (gst_structure_has_name(structure, GST_VAAPI_BUFFER_SHARING_CAPS_NAME) && + !gst_vaapi_video_buffer_ensure_pointer(GST_VAAPI_VIDEO_BUFFER(video_buffer))) + goto error; + + *buf = video_buffer; + return GST_FLOW_OK; + +error: + GST_ERROR("vaapisink allocate buffer failed."); + return GST_FLOW_ERROR; +} + +static void +gst_vaapisink_finalize(GObject *object) +{ + gst_vaapisink_destroy(GST_VAAPISINK(object)); + + G_OBJECT_CLASS(gst_vaapisink_parent_class)->finalize(object); +} + +static void +gst_vaapisink_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiSink * const sink = GST_VAAPISINK(object); + + switch (prop_id) { + case PROP_DISPLAY_TYPE: + sink->display_type = g_value_get_enum(value); + break; + case PROP_FULLSCREEN: + sink->fullscreen = g_value_get_boolean(value); + break; + case PROP_SYNCHRONOUS: + sink->synchronous = g_value_get_boolean(value); + break; + case PROP_USE_REFLECTION: + sink->use_reflection = g_value_get_boolean(value); + break; + case PROP_ROTATION: + sink->rotation_req = g_value_get_enum(value); + break; + case PROP_IS_PIXMAP: + sink->is_pixmap = g_value_get_boolean(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapisink_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiSink * const sink = GST_VAAPISINK(object); + + switch (prop_id) { + case PROP_DISPLAY_TYPE: + g_value_set_enum(value, sink->display_type); + break; + case PROP_FULLSCREEN: + g_value_set_boolean(value, sink->fullscreen); + break; + case PROP_SYNCHRONOUS: + g_value_set_boolean(value, sink->synchronous); + break; + case PROP_USE_REFLECTION: + g_value_set_boolean(value, sink->use_reflection); + break; + case PROP_ROTATION: + g_value_set_enum(value, sink->rotation); + break; + case PROP_IS_PIXMAP: + g_value_set_boolean(value, sink->is_pixmap); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapisink_class_init(GstVaapiSinkClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + GstBaseSinkClass * const basesink_class = GST_BASE_SINK_CLASS(klass); + GstPadTemplate *pad_template; + + GST_DEBUG_CATEGORY_INIT(gst_debug_vaapisink, + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); + + object_class->finalize = gst_vaapisink_finalize; + object_class->set_property = gst_vaapisink_set_property; + object_class->get_property = gst_vaapisink_get_property; + + basesink_class->start = gst_vaapisink_start; + basesink_class->stop = gst_vaapisink_stop; + basesink_class->set_caps = gst_vaapisink_set_caps; + basesink_class->preroll = gst_vaapisink_show_frame; + basesink_class->render = gst_vaapisink_show_frame; + basesink_class->query = gst_vaapisink_query; + + gst_element_class_set_details_simple( + element_class, + gst_vaapisink_details.longname, + gst_vaapisink_details.klass, + gst_vaapisink_details.description, + gst_vaapisink_details.author + ); + + pad_template = gst_static_pad_template_get(&gst_vaapisink_sink_factory); + gst_element_class_add_pad_template(element_class, pad_template); + gst_object_unref(pad_template); + + g_object_class_install_property + (object_class, + PROP_DISPLAY_TYPE, + g_param_spec_enum("display", + "display type", + "display type to use", + GST_VAAPI_TYPE_DISPLAY_TYPE, + GST_VAAPI_DISPLAY_TYPE_ANY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + +#if USE_GLX + g_object_class_install_property + (object_class, + PROP_USE_REFLECTION, + g_param_spec_boolean("use-reflection", + "Reflection effect", + "Enables OpenGL reflection effect", + FALSE, + G_PARAM_READWRITE)); +#endif + + g_object_class_install_property + (object_class, + PROP_FULLSCREEN, + g_param_spec_boolean("fullscreen", + "Fullscreen", + "Requests window in fullscreen state", + FALSE, + G_PARAM_READWRITE)); + + /** + * GstVaapiSink:synchronous: + * + * When enabled, runs the X display in synchronous mode. Note that + * this is used only for debugging. + */ + g_object_class_install_property + (object_class, + PROP_SYNCHRONOUS, + g_param_spec_boolean("synchronous", + "Synchronous mode", + "Toggles X display synchronous mode", + FALSE, + G_PARAM_READWRITE)); + + /** + * GstVaapiSink:rotation: + * + * The VA display rotation mode, expressed as a #GstVaapiRotation. + */ + g_object_class_install_property + (object_class, + PROP_ROTATION, + g_param_spec_enum(GST_VAAPI_DISPLAY_PROP_ROTATION, + "rotation", + "The display rotation mode", + GST_VAAPI_TYPE_ROTATION, + DEFAULT_ROTATION, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, + PROP_IS_PIXMAP, + g_param_spec_boolean("is-pixmap", + "IsPixmap", + "the X drawable is Pixmap or not", + FALSE, + G_PARAM_READWRITE)); + +} + +static void +gst_vaapisink_init(GstVaapiSink *sink) +{ + int i = 0; + GstPad *sinkpad = GST_BASE_SINK_PAD(sink); + + gst_pad_set_bufferalloc_function(sinkpad, + gst_vaapisink_pad_buffer_alloc); + + sink->caps = NULL; + sink->display = NULL; + sink->window = NULL; + sink->window_width = 0; + sink->window_height = 0; + sink->texture = NULL; + sink->video_buffer = NULL; + sink->video_width = 0; + sink->video_height = 0; + sink->video_par_n = 1; + sink->video_par_d = 1; + sink->foreign_window = FALSE; + sink->fullscreen = FALSE; + sink->synchronous = FALSE; + sink->display_type = DEFAULT_DISPLAY_TYPE; + sink->rotation = DEFAULT_ROTATION; + sink->rotation_req = DEFAULT_ROTATION; + sink->use_reflection = FALSE; + sink->use_overlay = FALSE; + sink->use_rotation = FALSE; + sink->render_rect.x = 0; + sink->render_rect.y = 0; + sink->render_rect.width = 0; + sink->render_rect.height = 0; + sink->video_pool = NULL; + sink->buffer_sharing = FALSE; + sink->is_pixmap = FALSE; + + for (i=0; ipixmap_pool[i] = NULL; + } +} diff --git a/gst/vaapi/gstvaapisink.h b/gst/vaapi/gstvaapisink.h new file mode 100644 index 0000000..acf6dd6 --- /dev/null +++ b/gst/vaapi/gstvaapisink.h @@ -0,0 +1,110 @@ +/* + * gstvaapisink.h - VA-API video sink + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#ifndef GST_VAAPISINK_H +#define GST_VAAPISINK_H + +#include +#include +#include +#if USE_GLX +#include +#endif +#include "gstvaapipluginutil.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPISINK \ + (gst_vaapisink_get_type()) + +#define GST_VAAPISINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_TYPE_VAAPISINK, \ + GstVaapiSink)) + +#define GST_VAAPISINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_TYPE_VAAPISINK, \ + GstVaapiSinkClass)) + +#define GST_IS_VAAPISINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VAAPISINK)) + +#define GST_IS_VAAPISINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VAAPISINK)) + +#define GST_VAAPISINK_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_TYPE_VAAPISINK, \ + GstVaapiSinkClass)) + +typedef struct _GstVaapiSink GstVaapiSink; +typedef struct _GstVaapiSinkClass GstVaapiSinkClass; +#if !USE_GLX +typedef struct _GstVaapiTexture GstVaapiTexture; +#endif + +#define MAX_PIXMAP_COUNT 20 + +struct _GstVaapiSink { + /*< private >*/ + GstVideoSink parent_instance; + + GstCaps *caps; + GstVaapiDisplay *display; + GstVaapiDisplayType display_type; + GstVaapiWindow *window; + guint window_width; + guint window_height; + GstVaapiTexture *texture; + GstBuffer *video_buffer; + guint video_width; + guint video_height; + gint video_par_n; + gint video_par_d; + GstVaapiRectangle display_rect; /* centralized video display position */ + GstVaapiRectangle render_rect; /* user defined rendering position */ + GstVaapiRotation rotation; + GstVaapiRotation rotation_req; + GstVaapiVideoPool *video_pool; + guint foreign_window : 1; + guint fullscreen : 1; + guint synchronous : 1; + guint use_reflection : 1; + guint use_overlay : 1; + guint use_rotation : 1; + guint buffer_sharing : 1; + guint is_pixmap : 1; + GstVaapiWindow *pixmap_pool[MAX_PIXMAP_COUNT]; +}; + +struct _GstVaapiSinkClass { + /*< private >*/ + GstVideoSinkClass parent_class; +}; + +GType +gst_vaapisink_get_type(void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* GST_VAAPISINK_H */ diff --git a/gst/vaapi/gstvaapiupload.c b/gst/vaapi/gstvaapiupload.c new file mode 100644 index 0000000..ce31088 --- /dev/null +++ b/gst/vaapi/gstvaapiupload.c @@ -0,0 +1,945 @@ +/* + * gstvaapiupload.c - VA-API video uploader + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiupload + * @short_description: A video to VA flow filter + * + * vaapiupload uploads from raw YUV pixels to VA surfaces suitable + * for the vaapisink element, for example. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "gstvaapiupload.h" +#include "gstvaapipluginutil.h" +#include "gstvaapipluginbuffer.h" + +#define GST_PLUGIN_NAME "vaapiupload" +#define GST_PLUGIN_DESC "A video to VA flow filter" + +GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapiupload); +#define GST_CAT_DEFAULT gst_debug_vaapiupload + +/* ElementFactory information */ +static const GstElementDetails gst_vaapiupload_details = + GST_ELEMENT_DETAILS( + "VA-API colorspace uploader", + "Filter/Converter/Video", + GST_PLUGIN_DESC, + "Gwenole Beauchesne "); + +/* Default templates */ +static const char gst_vaapiupload_yuv_caps_str[] = + "video/x-raw-yuv, " + "width = (int) [ 1, MAX ], " + "height = (int) [ 1, MAX ]; "; + +static const char gst_vaapiupload_vaapi_caps_str[] = + GST_VAAPI_SURFACE_CAPS; + +static GstStaticPadTemplate gst_vaapiupload_sink_factory = + GST_STATIC_PAD_TEMPLATE( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapiupload_yuv_caps_str)); + +static GstStaticPadTemplate gst_vaapiupload_src_factory = + GST_STATIC_PAD_TEMPLATE( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(gst_vaapiupload_vaapi_caps_str)); + +static void +gst_vaapiupload_implements_iface_init(GstImplementsInterfaceClass *iface); + +static void +gst_video_context_interface_init(GstVideoContextInterface *iface); + +#define GstVideoContextClass GstVideoContextInterface +G_DEFINE_TYPE_WITH_CODE( + GstVaapiUpload, + gst_vaapiupload, + GST_TYPE_BASE_TRANSFORM, + G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE, + gst_vaapiupload_implements_iface_init); + G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT, + gst_video_context_interface_init)); + +/* + * Direct rendering levels (direct-rendering) + * 0: upstream allocated YUV pixels + * 1: vaapiupload allocated YUV pixels (mapped from VA image) + * 2: vaapiupload allocated YUV pixels (mapped from VA surface) + */ +#define DIRECT_RENDERING_DEFAULT 2 + +enum { + PROP_0, + + PROP_DIRECT_RENDERING, +}; + +static gboolean +gst_vaapiupload_start(GstBaseTransform *trans); + +static gboolean +gst_vaapiupload_stop(GstBaseTransform *trans); + +static GstFlowReturn +gst_vaapiupload_transform( + GstBaseTransform *trans, + GstBuffer *inbuf, + GstBuffer *outbuf +); + +static GstCaps * +gst_vaapiupload_transform_caps( + GstBaseTransform *trans, + GstPadDirection direction, + GstCaps *caps +); + +static gboolean +gst_vaapiupload_set_caps( + GstBaseTransform *trans, + GstCaps *incaps, + GstCaps *outcaps +); + +static gboolean +gst_vaapiupload_get_unit_size( + GstBaseTransform *trans, + GstCaps *caps, + guint *size +); + +static GstFlowReturn +gst_vaapiupload_sinkpad_buffer_alloc( + GstPad *pad, + guint64 offset, + guint size, + GstCaps *caps, + GstBuffer **pbuf +); + +static GstFlowReturn +gst_vaapiupload_prepare_output_buffer( + GstBaseTransform *trans, + GstBuffer *inbuf, + gint size, + GstCaps *caps, + GstBuffer **poutbuf +); + +static gboolean +gst_vaapiupload_query( + GstPad *pad, + GstQuery *query +); + +/* GstImplementsInterface interface */ + +static gboolean +gst_vaapiupload_implements_interface_supported( + GstImplementsInterface *iface, + GType type +) +{ + return (type == GST_TYPE_VIDEO_CONTEXT); +} + +static void +gst_vaapiupload_implements_iface_init(GstImplementsInterfaceClass *iface) +{ + iface->supported = gst_vaapiupload_implements_interface_supported; +} + +/* GstVideoContext interface */ + +static void +gst_vaapiupload_set_video_context(GstVideoContext *context, const gchar *type, + const GValue *value) +{ + GstVaapiUpload *upload = GST_VAAPIUPLOAD (context); + gst_vaapi_set_display (type, value, &upload->display); +} + +static void +gst_video_context_interface_init(GstVideoContextInterface *iface) +{ + iface->set_context = gst_vaapiupload_set_video_context; +} + +static void +gst_vaapiupload_destroy(GstVaapiUpload *upload) +{ + g_clear_object(&upload->images); + g_clear_object(&upload->surfaces); + g_clear_object(&upload->display); +} + +static void +gst_vaapiupload_finalize(GObject *object) +{ + gst_vaapiupload_destroy(GST_VAAPIUPLOAD(object)); + + G_OBJECT_CLASS(gst_vaapiupload_parent_class)->finalize(object); +} + + +static void +gst_vaapiupload_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiUpload * const upload = GST_VAAPIUPLOAD(object); + + switch (prop_id) { + case PROP_DIRECT_RENDERING: + GST_OBJECT_LOCK(upload); + upload->direct_rendering = g_value_get_uint(value); + GST_OBJECT_UNLOCK(upload); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapiupload_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiUpload * const upload = GST_VAAPIUPLOAD(object); + + switch (prop_id) { + case PROP_DIRECT_RENDERING: + g_value_set_uint(value, upload->direct_rendering); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapiupload_class_init(GstVaapiUploadClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstElementClass * const element_class = GST_ELEMENT_CLASS(klass); + GstBaseTransformClass * const trans_class = GST_BASE_TRANSFORM_CLASS(klass); + GstPadTemplate *pad_template; + + GST_DEBUG_CATEGORY_INIT(gst_debug_vaapiupload, + GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC); + + object_class->finalize = gst_vaapiupload_finalize; + object_class->set_property = gst_vaapiupload_set_property; + object_class->get_property = gst_vaapiupload_get_property; + + trans_class->start = gst_vaapiupload_start; + trans_class->stop = gst_vaapiupload_stop; + trans_class->transform = gst_vaapiupload_transform; + trans_class->transform_caps = gst_vaapiupload_transform_caps; + trans_class->set_caps = gst_vaapiupload_set_caps; + trans_class->get_unit_size = gst_vaapiupload_get_unit_size; + trans_class->prepare_output_buffer = gst_vaapiupload_prepare_output_buffer; + + gst_element_class_set_details_simple( + element_class, + gst_vaapiupload_details.longname, + gst_vaapiupload_details.klass, + gst_vaapiupload_details.description, + gst_vaapiupload_details.author + ); + + /* sink pad */ + pad_template = gst_static_pad_template_get(&gst_vaapiupload_sink_factory); + gst_element_class_add_pad_template(element_class, pad_template); + gst_object_unref(pad_template); + + /* src pad */ + pad_template = gst_static_pad_template_get(&gst_vaapiupload_src_factory); + gst_element_class_add_pad_template(element_class, pad_template); + gst_object_unref(pad_template); + + /** + * GstVaapiUpload:direct-rendering: + * + * Selects the direct rendering level. + * + * + * Disables direct rendering. + * + * + * Enables direct rendering to the output buffer. i.e. this + * tries to use a single buffer for both sink and src pads. + * + * + * Enables direct rendering to the underlying surface. i.e. with + * drivers supporting vaDeriveImage(), the output surface pixels + * will be modified directly. + * + * + */ + g_object_class_install_property + (object_class, + PROP_DIRECT_RENDERING, + g_param_spec_uint("direct-rendering", + "Direct rendering", + "Direct rendering level", + 0, 2, + DIRECT_RENDERING_DEFAULT, + G_PARAM_READWRITE)); +} + +static void +gst_vaapiupload_init(GstVaapiUpload *upload) +{ + GstPad *sinkpad, *srcpad; + + upload->display = NULL; + upload->images = NULL; + upload->images_reset = FALSE; + upload->image_width = 0; + upload->image_height = 0; + upload->surfaces = NULL; + upload->surfaces_reset = FALSE; + upload->surface_width = 0; + upload->surface_height = 0; + upload->direct_rendering_caps = 0; + upload->direct_rendering = G_MAXUINT32; + upload->need_manual_upload = FALSE; + + /* Override buffer allocator on sink pad */ + sinkpad = gst_element_get_static_pad(GST_ELEMENT(upload), "sink"); + gst_pad_set_bufferalloc_function( + sinkpad, + gst_vaapiupload_sinkpad_buffer_alloc + ); + gst_pad_set_query_function(sinkpad, gst_vaapiupload_query); + g_object_unref(sinkpad); + + /* Override query on src pad */ + srcpad = gst_element_get_static_pad(GST_ELEMENT(upload), "src"); + gst_pad_set_query_function(srcpad, gst_vaapiupload_query); + g_object_unref(srcpad); +} + +static inline gboolean +gst_vaapiupload_ensure_display(GstVaapiUpload *upload) +{ + return gst_vaapi_ensure_display(upload, GST_VAAPI_DISPLAY_TYPE_ANY, + &upload->display); +} + +static gboolean +gst_vaapiupload_start(GstBaseTransform *trans) +{ + GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans); + + if (!gst_vaapiupload_ensure_display(upload)) + return FALSE; + return TRUE; +} + +static gboolean +gst_vaapiupload_stop(GstBaseTransform *trans) +{ + GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans); + + g_clear_object(&upload->display); + + return TRUE; +} + +static GstFlowReturn +gst_vaapiupload_transform( + GstBaseTransform *trans, + GstBuffer *inbuf, + GstBuffer *outbuf +) +{ + GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans); + GstVaapiVideoBuffer *vbuffer; + GstVaapiSurface *surface; + GstVaapiImage *image; + gboolean success; + + vbuffer = GST_VAAPI_VIDEO_BUFFER(outbuf); + surface = gst_vaapi_video_buffer_get_surface(vbuffer); + if (!surface) + return GST_FLOW_UNEXPECTED; + + if (upload->direct_rendering) { + if (!GST_VAAPI_IS_VIDEO_BUFFER(inbuf)) { + GST_DEBUG("GstVaapiVideoBuffer was expected"); + return GST_FLOW_UNEXPECTED; + } + + vbuffer = GST_VAAPI_VIDEO_BUFFER(inbuf); + image = gst_vaapi_video_buffer_get_image(vbuffer); + if (!image) + return GST_FLOW_UNEXPECTED; + if (!gst_vaapi_image_unmap(image)) + return GST_FLOW_UNEXPECTED; + + if (upload->direct_rendering < 2) { + if (!gst_vaapi_surface_put_image(surface, image)) + goto error_put_image; + } + goto flow_ok; + } + + /* PVR need directly copy image to surface */ + image = gst_vaapi_surface_derive_image(surface); + //image = gst_vaapi_video_pool_get_object(upload->images); + if (!image) + goto error_put_image; + + if (!upload->need_manual_upload) { + success = gst_vaapi_image_update_from_buffer(image, inbuf, NULL); + } else { /* manually copy data to image*/ + success = gst_vaapi_convert_buffer_to_image(image, inbuf); + } + if (!success) + goto error_put_image; + + //success = gst_vaapi_surface_put_image(surface, image); + //gst_vaapi_video_pool_put_object(upload->images, image); + //if (!success) + // goto error_put_image; + g_object_unref(image); + +flow_ok: + FPS_CALCULATION(vaapiupload); + return GST_FLOW_OK; + +error_put_image: + { + GST_WARNING("failed to upload %" GST_FOURCC_FORMAT " image " + "to surface 0x%08x", + GST_FOURCC_ARGS(gst_vaapi_image_get_format(image)), + gst_vaapi_surface_get_id(surface)); + if (!upload->direct_rendering && image) + g_object_unref(image); + return GST_FLOW_OK; + } +} + +static GstCaps * +gst_vaapi_get_other_support_caps(GstVaapiUpload *upload) +{ + GstCaps *caps; + caps = gst_caps_from_string(GST_VIDEO_CAPS_YUV("YUY2")); + return caps; +} + +static GstCaps * +gst_vaapiupload_transform_caps( + GstBaseTransform *trans, + GstPadDirection direction, + GstCaps *caps +) +{ + GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans); + GstCaps *out_caps = NULL; + GstStructure *structure; + + g_return_val_if_fail(GST_IS_CAPS(caps), NULL); + + structure = gst_caps_get_structure(caps, 0); + + if (direction == GST_PAD_SINK) { + if (!gst_structure_has_name(structure, "video/x-raw-yuv")) + return NULL; + out_caps = gst_caps_from_string(gst_vaapiupload_vaapi_caps_str); + + structure = gst_caps_get_structure(out_caps, 0); + gst_structure_set( + structure, + "type", G_TYPE_STRING, "vaapi", + "opengl", G_TYPE_BOOLEAN, USE_GLX, + NULL + ); + } + else { + if (!gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME)) + return NULL; + out_caps = gst_caps_from_string(gst_vaapiupload_yuv_caps_str); + if (upload->display) { + GstCaps *allowed_caps, *inter_caps, *other_caps; + allowed_caps = gst_vaapi_display_get_image_caps(upload->display); + if (!allowed_caps) + return NULL; + /* can direct copy other YUV to va surface */ + other_caps = gst_vaapi_get_other_support_caps(upload); + gst_caps_merge(allowed_caps, other_caps); + + inter_caps = gst_caps_intersect(out_caps, allowed_caps); + gst_caps_unref(allowed_caps); + gst_caps_unref(out_caps); + out_caps = inter_caps; + } + } + + if (!gst_vaapi_append_surface_caps(out_caps, caps)) { + gst_caps_unref(out_caps); + return NULL; + } + return out_caps; +} + +static gboolean +gst_vaapiupload_ensure_image_pool(GstVaapiUpload *upload, GstCaps *caps) +{ + GstStructure * const structure = gst_caps_get_structure(caps, 0); + gint width, height; + + gst_structure_get_int(structure, "width", &width); + gst_structure_get_int(structure, "height", &height); + + if (width != upload->image_width || height != upload->image_height) { + upload->image_width = width; + upload->image_height = height; + g_clear_object(&upload->images); + upload->images = gst_vaapi_image_pool_new(upload->display, caps); + if (!upload->images) + return FALSE; + upload->images_reset = TRUE; + } + return TRUE; +} + +static gboolean +gst_vaapiupload_ensure_surface_pool(GstVaapiUpload *upload, GstCaps *caps) +{ + GstStructure * const structure = gst_caps_get_structure(caps, 0); + gint width, height; + + gst_structure_get_int(structure, "width", &width); + gst_structure_get_int(structure, "height", &height); + + if (width != upload->surface_width || height != upload->surface_height) { + upload->surface_width = width; + upload->surface_height = height; + g_clear_object(&upload->surfaces); + upload->surfaces = gst_vaapi_surface_pool_new(upload->display, caps); + if (!upload->surfaces) + return FALSE; + upload->surfaces_reset = TRUE; + } + return TRUE; +} + +static void +gst_vaapiupload_ensure_direct_rendering_caps( + GstVaapiUpload *upload, + GstCaps *caps +) +{ + GstVaapiSurface *surface; + GstVaapiImage *image; + GstVaapiImageFormat vaformat; + GstVideoFormat vformat; + GstStructure *structure; + gint width, height; + + if (!upload->images_reset && !upload->surfaces_reset) + return; + + upload->images_reset = FALSE; + upload->surfaces_reset = FALSE; + upload->direct_rendering_caps = 0; + + structure = gst_caps_get_structure(caps, 0); + if (!structure) + return; + gst_structure_get_int(structure, "width", &width); + gst_structure_get_int(structure, "height", &height); + + /* Translate from Gst video format to VA image format */ + if (!gst_video_format_parse_caps(caps, &vformat, NULL, NULL)) + return; + if (!gst_video_format_is_yuv(vformat)) + return; + vaformat = gst_vaapi_image_format_from_video(vformat); + if (!vaformat) + return; + + /* Check if we can alias sink & output buffers (same data_size) */ + image = gst_vaapi_video_pool_get_object(upload->images); + if (image) { + if (upload->direct_rendering_caps == 0 && + (gst_vaapi_image_get_format(image) == vaformat && + gst_vaapi_image_is_linear(image) && + (gst_vaapi_image_get_data_size(image) == + gst_video_format_get_size(vformat, width, height)))) + upload->direct_rendering_caps = 1; + gst_vaapi_video_pool_put_object(upload->images, image); + } + + /* Check if we can access to the surface pixels directly */ + surface = gst_vaapi_video_pool_get_object(upload->surfaces); + if (surface) { + image = gst_vaapi_surface_derive_image(surface); + if (image) { + if (gst_vaapi_image_map(image)) { + if (upload->direct_rendering_caps == 1 && + (gst_vaapi_image_get_format(image) == vaformat && + gst_vaapi_image_is_linear(image) && + (gst_vaapi_image_get_data_size(image) == + gst_video_format_get_size(vformat, width, height)))) + upload->direct_rendering_caps = 2; + gst_vaapi_image_unmap(image); + } + g_object_unref(image); + } + gst_vaapi_video_pool_put_object(upload->surfaces, surface); + } +} + +typedef enum YUV_TYPE { + YUV_UNKOWN = 0, + YUV_411 = 1, + YUV_422 = 2, + YUV_444 = 4 +} YUV_TYPE; + +static YUV_TYPE +_image_format_to_yuv_type(guint32 fourcc) +{ + switch (fourcc) { + case GST_MAKE_FOURCC('N','V','1','2'): + case GST_MAKE_FOURCC('Y','V','1','2'): + case GST_MAKE_FOURCC('I','4','2','0'): + case GST_MAKE_FOURCC('N','V','2','1'): + return YUV_411; + + case GST_MAKE_FOURCC('Y','U','Y','2'): + case GST_MAKE_FOURCC('Y','V','Y','U'): + return YUV_422; + + case GST_MAKE_FOURCC('A','Y','U','V'): + return YUV_UNKOWN; + + default: + return YUV_UNKOWN; + } +} + +static GstCaps * +_get_nearest_caps(GstCaps *caps_list, GstCaps *src_caps) +{ + GstCaps *ret = NULL; + GstStructure *cur_struct, *tmp_struct; + guint32 cur_format, dest_format, tmp_format; + YUV_TYPE cur_type, tmp_type; + const GValue*tmp_val; + guint n_caps; + guint i; + guint min_diff, tmp_diff; + + cur_struct = gst_caps_get_structure(src_caps, 0); + tmp_val = gst_structure_get_value (cur_struct, "format"); + if (!tmp_val) + return NULL; + + cur_format = gst_value_get_fourcc(tmp_val); + if((cur_type = _image_format_to_yuv_type(cur_format)) == YUV_UNKOWN) + return NULL; + + n_caps = gst_caps_get_size(caps_list); + min_diff = 100; + dest_format = 0; + for (i = 0; i < n_caps; ++i) { + tmp_struct = gst_caps_get_structure(caps_list, i); + tmp_val = gst_structure_get_value (tmp_struct, "format"); + if (!tmp_val) + continue; + tmp_format = gst_value_get_fourcc(tmp_val); + if ((tmp_type = _image_format_to_yuv_type(tmp_format)) == YUV_UNKOWN) + continue; + tmp_diff = abs(tmp_type - cur_type); + if (tmp_diff < min_diff) { + min_diff = tmp_diff; + dest_format = tmp_format; + } + } + + if (dest_format == 0) + return NULL; + + ret = gst_caps_copy(src_caps); + tmp_struct = gst_caps_get_structure(ret, 0); + gst_structure_set(tmp_struct, "format", GST_TYPE_FOURCC, dest_format, NULL); + return ret; +} + +static gboolean +gst_vaapiupload_negotiate_buffers( + GstVaapiUpload *upload, + GstCaps *incaps, + GstCaps *outcaps +) +{ + guint dr; + gboolean ret = TRUE; + GstCaps *image_allowed_caps = NULL; + GstCaps *image_caps = NULL; + + image_allowed_caps = gst_vaapi_display_get_image_caps(upload->display); + if (gst_caps_can_intersect(incaps, image_allowed_caps)) { + image_caps = gst_caps_ref(incaps); + upload->need_manual_upload = FALSE; + } else { + image_caps = _get_nearest_caps(image_allowed_caps, incaps); + upload->need_manual_upload = TRUE; + } + + if (!gst_vaapiupload_ensure_image_pool(upload, image_caps)) + goto failed; + + if (!gst_vaapiupload_ensure_surface_pool(upload, outcaps)) + goto failed; + + gst_vaapi_video_pool_set_capacity(upload->surfaces, 6); + gst_vaapi_video_pool_reserve(upload->surfaces, 4); + + if (upload->direct_rendering && !upload->need_manual_upload) + gst_vaapiupload_ensure_direct_rendering_caps(upload, incaps); + dr = MIN(upload->direct_rendering, upload->direct_rendering_caps); + if (upload->direct_rendering != dr) { + upload->direct_rendering = dr; + GST_DEBUG("direct-rendering level: %d", dr); + } + ret = TRUE; + goto end; + + failed: + ret = FALSE; + + end: + gst_caps_unref(image_caps); + gst_caps_unref(image_allowed_caps); + return ret; +} + +static gboolean +gst_vaapiupload_set_caps( + GstBaseTransform *trans, + GstCaps *incaps, + GstCaps *outcaps +) +{ + GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans); + + if (!gst_vaapiupload_negotiate_buffers(upload, incaps, outcaps)) + return FALSE; + + GST_INFO("set caps\nIN caps:\n%" GST_PTR_FORMAT "\nOUT caps:\n%" GST_PTR_FORMAT, + incaps, outcaps); + return TRUE; +} + +static gboolean +gst_vaapiupload_get_unit_size( + GstBaseTransform *trans, + GstCaps *caps, + guint *size +) +{ + GstStructure * const structure = gst_caps_get_structure(caps, 0); + GstVideoFormat format; + gint width, height; + + if (gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME)) + *size = 0; + else { + if (!gst_video_format_parse_caps(caps, &format, &width, &height)) + return FALSE; + *size = gst_video_format_get_size(format, width, height); + } + return TRUE; +} + +static GstFlowReturn +gst_vaapiupload_buffer_alloc( + GstBaseTransform *trans, + guint size, + GstCaps *caps, + GstBuffer **pbuf +) +{ + GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans); + GstBuffer *buffer = NULL; + GstVaapiImage *image = NULL; + GstVaapiSurface *surface = NULL; + GstVaapiVideoBuffer *vbuffer; + + /* already checked */ + if (!upload->direct_rendering) + return GST_FLOW_OK; + + /* Check if we can use direct-rendering */ + if (!gst_vaapiupload_negotiate_buffers(upload, caps, caps)) + goto error; + if (!upload->direct_rendering) + return GST_FLOW_OK; + + switch (upload->direct_rendering) { + case 2: + buffer = gst_vaapi_video_buffer_new_from_pool(upload->surfaces); + if (!buffer) + goto error; + vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer); + + surface = gst_vaapi_video_buffer_get_surface(vbuffer); + image = gst_vaapi_surface_derive_image(surface); + if (image && gst_vaapi_image_get_data_size(image) == size) { + gst_vaapi_video_buffer_set_image(vbuffer, image); + g_object_unref(image); /* video buffer owns an extra reference */ + break; + } + + /* We can't use the derive-image optimization. Disable it. */ + upload->direct_rendering = 1; + gst_buffer_unref(buffer); + buffer = NULL; + + case 1: + buffer = gst_vaapi_video_buffer_new_from_pool(upload->images); + if (!buffer) + goto error; + vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer); + + image = gst_vaapi_video_buffer_get_image(vbuffer); + break; + } + g_assert(image); + + if (!gst_vaapi_image_map(image)) + goto error; + + GST_BUFFER_DATA(buffer) = gst_vaapi_image_get_plane(image, 0); + GST_BUFFER_SIZE(buffer) = gst_vaapi_image_get_data_size(image); + + gst_buffer_set_caps(buffer, caps); + *pbuf = buffer; + return GST_FLOW_OK; + +error: + /* We can't use the inout-buffers optimization. Disable it. */ + GST_DEBUG("disable in/out buffer optimization"); + if (buffer) + gst_buffer_unref(buffer); + upload->direct_rendering = 0; + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_vaapiupload_sinkpad_buffer_alloc( + GstPad *pad, + guint64 offset, + guint size, + GstCaps *caps, + GstBuffer **pbuf +) +{ + GstBaseTransform *trans; + GstFlowReturn ret; + + trans = GST_BASE_TRANSFORM(gst_pad_get_parent_element(pad)); + if (!trans) + return GST_FLOW_UNEXPECTED; + + ret = gst_vaapiupload_buffer_alloc(trans, size, caps, pbuf); + g_object_unref(trans); + return ret; +} + +static GstFlowReturn +gst_vaapiupload_prepare_output_buffer( + GstBaseTransform *trans, + GstBuffer *inbuf, + gint size, + GstCaps *caps, + GstBuffer **poutbuf +) +{ + GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans); + GstBuffer *buffer = NULL; + + if (upload->direct_rendering == 2) { + if (GST_VAAPI_IS_VIDEO_BUFFER(inbuf)) { + buffer = gst_vaapi_video_buffer_new_from_buffer(inbuf); + GST_BUFFER_SIZE(buffer) = size; + } + else { + GST_DEBUG("upstream element destroyed our in/out buffer"); + upload->direct_rendering = 1; + } + } + + if (!buffer) { + buffer = gst_vaapi_video_buffer_new_from_pool(upload->surfaces); + if (!buffer) + return GST_FLOW_UNEXPECTED; + gst_buffer_set_caps(buffer, caps); + } + + *poutbuf = buffer; + return GST_FLOW_OK; +} + +static gboolean +gst_vaapiupload_query(GstPad *pad, GstQuery *query) +{ + GstVaapiUpload *upload = GST_VAAPIUPLOAD (gst_pad_get_parent_element (pad)); + gboolean res; + + GST_DEBUG ("sharing display %p", upload->display); + + if (gst_vaapi_reply_to_query (query, upload->display)) + res = TRUE; + else + res = gst_pad_query_default (pad, query); + + g_object_unref (upload); + return res; +} diff --git a/gst/vaapi/gstvaapiupload.h b/gst/vaapi/gstvaapiupload.h new file mode 100644 index 0000000..c9627d2 --- /dev/null +++ b/gst/vaapi/gstvaapiupload.h @@ -0,0 +1,93 @@ +/* + * gstvaapiupload.h - VA-API video uploader + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#ifndef GST_VAAPIUPLOAD_H +#define GST_VAAPIUPLOAD_H + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VAAPIUPLOAD \ + (gst_vaapiupload_get_type()) + +#define GST_VAAPIUPLOAD(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_TYPE_VAAPIUPLOAD, \ + GstVaapiUpload)) + +#define GST_VAAPIUPLOAD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_TYPE_VAAPIUPLOAD, \ + GstVaapiUploadClass)) + +#define GST_IS_VAAPIUPLOAD(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VAAPIUPLOAD)) + +#define GST_IS_VAAPIUPLOAD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VAAPIUPLOAD)) + +#define GST_VAAPIUPLOAD_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_TYPE_VAAPIUPLOAD, \ + GstVaapiUploadClass)) + +typedef struct _GstVaapiUpload GstVaapiUpload; +typedef struct _GstVaapiUploadClass GstVaapiUploadClass; + +/* Max output surfaces */ +#define GST_VAAPIUPLOAD_MAX_SURFACES 2 + +struct _GstVaapiUpload { + /*< private >*/ + GstBaseTransform parent_instance; + + GstVaapiDisplay *display; + GstVaapiVideoPool *images; + guint image_width; + guint image_height; + GstVaapiVideoPool *surfaces; + guint surface_width; + guint surface_height; + guint direct_rendering_caps; + guint direct_rendering; + unsigned int images_reset : 1; + unsigned int surfaces_reset : 1; + unsigned int need_manual_upload : 1; +}; + +struct _GstVaapiUploadClass { + /*< private >*/ + GstBaseTransformClass parent_class; +}; + +GType +gst_vaapiupload_get_type(void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* GST_VAAPIUPLOAD_H */ diff --git a/packaging/gstreamer-vaapi.changes b/packaging/gstreamer-vaapi.changes new file mode 100644 index 0000000..107bc3a --- /dev/null +++ b/packaging/gstreamer-vaapi.changes @@ -0,0 +1,32 @@ +* Mon Sep 24 2012 Yan Yin accepted/2.0_beta/20120917.204432@eadd4f0 +- decoder_h264: reduce max_dec_frame_buffering from 16 to 8 +- vaapidecode: dynamically add surface to vaapicontext. + +* Mon Sep 17 2012 Yan Yin accepted/2.0_beta/20120912.025253@838e26e +- vaapisink: ensure render rect for foreign window +- vaapisink: centralizing display_rect even in user defined render_rect +- vaapsink: fix display properties check after display_type set + +* Tue Sep 11 2012 Yan Yin submit/2.0_beta/20120907.063807@d0aadd7 +- fix summary for devel pacakge + +* Wed Sep 05 2012 Yan Yin submit/2.0_beta/20120831.083100@c9d3506 +- fix build failure of libdrm. + +* Tue Aug 07 2012 Yan Yin build/2012-08-01.041209@c9c8547 +- fix wrong version number to 0.4.0.pre1 + +* Wed Aug 01 2012 Yan Yin build/2012-08-01.041020@bc1613b +- rebase to 0.3.8pre + +* Thu Jun 28 2012 Yan Yin 0.2.6@0372cfd +- add manifest file + +* Tue Jun 26 2012 Yan Yin 0.2.6@f766365 +- add packaging files + +* Mon Jun 25 2012 Yan Yin 0.2.6@3706b26 +- fix build failure when compiling without GLX + +* Fri May 04 2012 Markus Lehtonen 0.2.6@1860d12 +- tizen build: disable docs diff --git a/packaging/gstreamer-vaapi.manifest b/packaging/gstreamer-vaapi.manifest new file mode 100644 index 0000000..017d22d --- /dev/null +++ b/packaging/gstreamer-vaapi.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/gstreamer-vaapi.spec b/packaging/gstreamer-vaapi.spec new file mode 100644 index 0000000..2c6acd5 --- /dev/null +++ b/packaging/gstreamer-vaapi.spec @@ -0,0 +1,70 @@ +Name: gstreamer-vaapi +Version: 0.4.0.pre1 +Release: 0 +Summary: VA-API based plugins for GStreamer and helper libraries +Group: Multimedia/Gstreamer +License: LGPLv2+ and GPLv2+ +URL: http://gitorious.org/vaapi/gstreamer-vaapi +Source0: %{name}-%{version}.tar.bz2 +Source1001: packaging/gstreamer-vaapi.manifest +BuildRequires: pkgconfig(x11) +BuildRequires: pkgconfig(libva) +BuildRequires: pkgconfig(gstreamer-0.10) +BuildRequires: pkgconfig(gstreamer-basevideo-0.10) +BuildRequires: pkgconfig(gstreamer-plugins-base-0.10) +BuildRequires: pvr-bin-mdfld-devel +BuildRequires: pkgconfig(libdrm) +BuildRequires: which +ExclusiveArch: %{ix86} + +%description +Gstreamer-vaapi is a collection of VA-API based plugins for GStreamer +and helper libraries. vaapidecode is used to decode MPEG-2, MPEG-4, +H.264, VC-1, WMV3 videos to video/x-vaapi-surface surfaces, depending +on the underlying HW capabilities. vaapiconvert is used to convert from +video/x-raw-yuv pixels to video/x-vaapi-surface surfaces. vaapisink is +used to display video/x-vaapi-surface surfaces to the screen. + +%package devel +Summary: Development files for gstreamer-vaapi +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +Requires: pkgconfig + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + +%prep +%setup -q -n %{name}-%{version} + +%build +cp %{SOURCE1001} . + +./autogen.sh --prefix=/usr --enable-encoders +make %{?_smp_mflags} + +%install +rm -rf %{buildroot} +make install DESTDIR=%{buildroot} +find %{buildroot} -regex ".*\.la$" | xargs rm -f -- +find %{buildroot} -regex ".*\.a$" | xargs rm -f -- + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%manifest gstreamer-vaapi.manifest +%defattr(-,root,root,-) +%doc AUTHORS COPYING.LIB NEWS README +%{_libdir}/*.so.* +%{_libdir}/gstreamer-0.10/*.so + +%files devel +%manifest gstreamer-vaapi.manifest +%defattr(-,root,root,-) +%doc README COPYING.LIB +%{_includedir}/gstreamer-0.10/gst/vaapi +%{_libdir}/*.so +%{_libdir}/pkgconfig/%{name}*.pc diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am new file mode 100644 index 0000000..04537d1 --- /dev/null +++ b/pkgconfig/Makefile.am @@ -0,0 +1,33 @@ +pcfiles_in = gstreamer-vaapi.pc.in +if USE_DRM +pcfiles_in += gstreamer-vaapi-drm.pc.in +endif +if USE_X11 +pcfiles_in += gstreamer-vaapi-x11.pc.in +endif +if USE_GLX +pcfiles_in += gstreamer-vaapi-glx.pc.in +endif +if USE_WAYLAND +pcfiles_in += gstreamer-vaapi-wayland.pc.in +endif + +pcfiles = $(pcfiles_in:%.pc.in=%-@GST_MAJORMINOR@.pc) + +all_pcfiles_in = gstreamer-vaapi.pc.in +all_pcfiles_in += gstreamer-vaapi-drm.pc.in +all_pcfiles_in += gstreamer-vaapi-x11.pc.in +all_pcfiles_in += gstreamer-vaapi-glx.pc.in +all_pcfiles_in += gstreamer-vaapi-wayland.pc.in + +all_pcfiles = $(all_pcfiles_in:%.pc.in=%-@GST_MAJORMINOR@.pc) + +pkgconfigdir = @pkgconfigdir@ +pkgconfig_DATA = $(pcfiles) + +EXTRA_DIST = $(all_pcfiles_in) + +DISTCLEANFILES = $(all_pcfiles) + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/pkgconfig/gstreamer-vaapi-drm.pc.in b/pkgconfig/gstreamer-vaapi-drm.pc.in new file mode 100644 index 0000000..3ebfadf --- /dev/null +++ b/pkgconfig/gstreamer-vaapi-drm.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gstreamer-@GST_MAJORMINOR@ +pluginsdir=@libdir@/gstreamer-@GST_MAJORMINOR@ + +Name: GStreamer VA-API (DRM) Plugins Libraries +Description: Streaming media framework, VA-API (DRM) plugins libraries +Requires: gstreamer-vaapi-@GST_MAJORMINOR@ libva-drm +Version: @VERSION@ +Libs: -L${libdir} -lgstvaapi-drm-@GST_MAJORMINOR@ +Cflags: -I${includedir} diff --git a/pkgconfig/gstreamer-vaapi-glx.pc.in b/pkgconfig/gstreamer-vaapi-glx.pc.in new file mode 100644 index 0000000..73b4c1b --- /dev/null +++ b/pkgconfig/gstreamer-vaapi-glx.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gstreamer-@GST_MAJORMINOR@ +pluginsdir=@libdir@/gstreamer-@GST_MAJORMINOR@ + +Name: GStreamer VA-API (glx) Plugins Libraries +Description: Streaming media framework, VA-API (glx) plugins libraries +Requires: gstreamer-vaapi-@GST_MAJORMINOR@ @LIBVA_GLX_PKGNAME@ +Version: @VERSION@ +Libs: -L${libdir} -lgstvaapi-glx-@GST_MAJORMINOR@ @LIBVA_EXTRA_LIBS@ +Cflags: -I${includedir} @LIBVA_EXTRA_CFLAGS@ diff --git a/pkgconfig/gstreamer-vaapi-wayland.pc.in b/pkgconfig/gstreamer-vaapi-wayland.pc.in new file mode 100644 index 0000000..07f1da0 --- /dev/null +++ b/pkgconfig/gstreamer-vaapi-wayland.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gstreamer-@GST_MAJORMINOR@ +pluginsdir=@libdir@/gstreamer-@GST_MAJORMINOR@ + +Name: GStreamer VA-API (Wayland) Plugins Libraries +Description: Streaming media framework, VA-API (Wayland) plugins libraries +Requires: gstreamer-vaapi-@GST_MAJORMINOR@ libva-wayland +Version: @VERSION@ +Libs: -L${libdir} -lgstvaapi-wayland-@GST_MAJORMINOR@ +Cflags: -I${includedir} diff --git a/pkgconfig/gstreamer-vaapi-x11.pc.in b/pkgconfig/gstreamer-vaapi-x11.pc.in new file mode 100644 index 0000000..1f258de --- /dev/null +++ b/pkgconfig/gstreamer-vaapi-x11.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gstreamer-@GST_MAJORMINOR@ +pluginsdir=@libdir@/gstreamer-@GST_MAJORMINOR@ + +Name: GStreamer VA-API (x11) Plugins Libraries +Description: Streaming media framework, VA-API (x11) plugins libraries +Requires: gstreamer-vaapi-@GST_MAJORMINOR@ @LIBVA_X11_PKGNAME@ +Version: @VERSION@ +Libs: -L${libdir} -lgstvaapi-x11-@GST_MAJORMINOR@ @LIBVA_EXTRA_LIBS@ +Cflags: -I${includedir} @LIBVA_EXTRA_CFLAGS@ diff --git a/pkgconfig/gstreamer-vaapi.pc.in b/pkgconfig/gstreamer-vaapi.pc.in new file mode 100644 index 0000000..281dee0 --- /dev/null +++ b/pkgconfig/gstreamer-vaapi.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gstreamer-@GST_MAJORMINOR@ +pluginsdir=@libdir@/gstreamer-@GST_MAJORMINOR@ + +Name: GStreamer VA-API Plugins Libraries +Description: Streaming media framework, VA-API plugins libraries +Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@ @LIBVA_PKGNAME@ +Version: @VERSION@ +Libs: -L${libdir} -lgstvaapi-@GST_MAJORMINOR@ @LIBVA_EXTRA_LIBS@ +Cflags: -I${includedir} @LIBVA_EXTRA_CFLAGS@ diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..4c8edbb --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,99 @@ +noinst_PROGRAMS = \ + test-decode \ + test-display \ + test-surfaces \ + test-windows \ + test-subpicture \ + $(NULL) + +if USE_GLX +noinst_PROGRAMS += \ + test-textures \ + $(NULL) +endif + +TEST_CFLAGS = \ + -DGST_USE_UNSTABLE_API \ + -I$(top_srcdir)/gst-libs \ + $(LIBVA_CFLAGS) \ + $(GST_CFLAGS) \ + $(NULL) + +TEST_LIBS = \ + $(LIBVA_LIBS) \ + $(GST_LIBS) \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-@GST_MAJORMINOR@.la + +if USE_DRM +TEST_CFLAGS += $(LIBVA_DRM_CFLAGS) +TEST_LIBS += \ + $(LIBVA_DRM_LIBS) \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-drm-@GST_MAJORMINOR@.la +endif + +if USE_X11 +TEST_CFLAGS += $(X11_CFLAGS) +TEST_LIBS += \ + $(LIBVA_X11_LIBS) \ + $(X11_LIBS) \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-x11-@GST_MAJORMINOR@.la +endif + +if USE_GLX +TEST_CFLAGS += $(X11_CFLAGS) $(GL_CFLAGS) +TEST_LIBS += \ + $(LIBVA_GLX_LIBS) \ + $(X11_LIBS) \ + $(GL_LIBS) \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-glx-@GST_MAJORMINOR@.la +endif + +if USE_WAYLAND +TEST_CFLAGS += $(WAYLAND_CFLAGS) +TEST_LIBS += \ + $(LIBVA_WAYLAND_LIBS) \ + $(WAYLAND_LIBS) \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-wayland-@GST_MAJORMINOR@.la +endif + +test_codecs_source_c = test-mpeg2.c test-h264.c test-vc1.c test-jpeg.c +test_codecs_source_h = $(test_codecs_source_c:%.c=%.h) test-decode.h + +test_utils_source_c = image.c output.c $(test_codecs_source_c) +test_utils_source_h = image.h output.h $(test_codecs_source_h) + +noinst_LTLIBRARIES = libutils.la +libutils_la_SOURCES = $(test_utils_source_c) +libutils_la_CFLAGS = $(TEST_CFLAGS) + +test_decode_SOURCES = test-decode.c $(test_codecs_source_c) +test_decode_CFLAGS = $(TEST_CFLAGS) +test_decode_LDADD = libutils.la $(TEST_LIBS) + +test_display_SOURCES = test-display.c +test_display_CFLAGS = $(TEST_CFLAGS) +test_display_LDADD = libutils.la $(TEST_LIBS) + +test_surfaces_SOURCES = test-surfaces.c +test_surfaces_CFLAGS = $(TEST_CFLAGS) +test_surfaces_LDADD = libutils.la $(TEST_LIBS) + +test_subpicture_SOURCES = test-subpicture.c test-subpicture-data.c +test_subpicture_CFLAGS = $(TEST_CFLAGS) +test_subpicture_LDADD = libutils.la $(TEST_LIBS) + +test_windows_SOURCES = test-windows.c +test_windows_CFLAGS = $(TEST_CFLAGS) +test_windows_LDADD = libutils.la $(TEST_LIBS) + +test_textures_SOURCES = test-textures.c +test_textures_CFLAGS = $(TEST_CFLAGS) +test_textures_LDADD = libutils.la $(TEST_LIBS) + +EXTRA_DIST = \ + test-subpicture-data.h \ + $(test_utils_source_h) \ + $(NULL) + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/tests/image.c b/tests/image.c new file mode 100644 index 0000000..39a8ac5 --- /dev/null +++ b/tests/image.c @@ -0,0 +1,360 @@ +/* + * image.c - Image utilities for the tests + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#include "image.h" + +GstVaapiImage * +image_generate( + GstVaapiDisplay *display, + GstVaapiImageFormat format, + guint width, + guint height +) +{ + const guint w = width; + const guint h = height; + GstVaapiImage *image; + + image = gst_vaapi_image_new(display, format, w, h); + if (!image) + return NULL; + + if (image_draw_rectangle(image, 0, 0, w/2, h/2, 0xffff0000) && + image_draw_rectangle(image, w/2, 0, w/2, h/2, 0xff00ff00) && + image_draw_rectangle(image, 0, h/2, w/2, h/2, 0xff0000ff) && + image_draw_rectangle(image, w/2, h/2, w/2, h/2, 0xff000000)) + return image; + + g_object_unref(image); + return NULL; +} + +typedef void (*DrawRectFunc)( + guchar *pixels[3], + guint stride[3], + gint x, + gint y, + guint width, + guint height, + guint32 color +); + +static void draw_rect_ARGB( + guchar *pixels[3], + guint stride[3], + gint x, + gint y, + guint width, + guint height, + guint32 color +) +{ + guint i, j; + + color = GUINT32_TO_BE(color); + + for (j = 0; j < height; j++) { + guint32 *p = (guint32 *)(pixels[0] + (y + j) * stride[0] + x * 4); + for (i = 0; i < width; i++) + p[i] = color; + } +} + +static void draw_rect_BGRA( + guchar *pixels[3], + guint stride[3], + gint x, + gint y, + guint width, + guint height, + guint32 color +) +{ + // Converts ARGB color to BGRA + color = GUINT32_SWAP_LE_BE(color); + + draw_rect_ARGB(pixels, stride, x, y, width, height, color); +} + +static void draw_rect_RGBA( + guchar *pixels[3], + guint stride[3], + gint x, + gint y, + guint width, + guint height, + guint32 color +) +{ + // Converts ARGB color to RGBA + color = ((color >> 24) & 0xff) | ((color & 0xffffff) << 8); + + draw_rect_ARGB(pixels, stride, x, y, width, height, color); +} + +static void draw_rect_ABGR( + guchar *pixels[3], + guint stride[3], + gint x, + gint y, + guint width, + guint height, + guint32 color +) +{ + // Converts ARGB color to ABGR + color = ((color & 0xff00ff00) | + ((color >> 16) & 0xff) | + ((color & 0xff) << 16)); + + draw_rect_ARGB(pixels, stride, x, y, width, height, color); +} + +static void draw_rect_NV12( // Y, UV planes + guchar *pixels[3], + guint stride[3], + gint x, + gint y, + guint width, + guint height, + guint32 color +) +{ + const guchar Y = color >> 16; + const guchar Cb = color >> 8; + const guchar Cr = color; + guchar *dst; + guint i, j; + + dst = pixels[0] + y * stride[0] + x; + for (j = 0; j < height; j++, dst += stride[0]) + for (i = 0; i < width; i++) + dst[i] = Y; + + x /= 2; + y /= 2; + width /= 2; + height /= 2; + + dst = pixels[1] + y * stride[1] + x * 2; + for (j = 0; j < height; j++, dst += stride[1]) + for (i = 0; i < width; i++) { + dst[2*i + 0] = Cb; + dst[2*i + 1] = Cr; + } +} + +static void draw_rect_YV12( // Y, V, U planes + guchar *pixels[3], + guint stride[3], + gint x, + gint y, + guint width, + guint height, + guint32 color +) +{ + const guchar Y = color >> 16; + const guchar Cb = color >> 8; + const guchar Cr = color; + guchar *pY, *pU, *pV; + guint i, j; + + pY = pixels[0] + y * stride[0] + x; + for (j = 0; j < height; j++, pY += stride[0]) + for (i = 0; i < width; i++) + pY[i] = Y; + + x /= 2; + y /= 2; + width /= 2; + height /= 2; + + pU = pixels[1] + y * stride[1] + x; + pV = pixels[2] + y * stride[2] + x; + for (j = 0; j < height; j++, pU += stride[1], pV += stride[2]) + for (i = 0; i < width; i++) { + pU[i] = Cb; + pV[i] = Cr; + } +} + +static void draw_rect_I420( // Y, U, V planes + guchar *pixels[3], + guint stride[3], + gint x, + gint y, + guint width, + guint height, + guint32 color +) +{ + guchar *new_pixels[3] = { pixels[0], pixels[2], pixels[1] }; + guint new_stride[3] = { stride[0], stride[2], stride[1] }; + + draw_rect_YV12(new_pixels, new_stride, x, y, width, height, color); +} + +static void draw_rect_AYUV( + guchar *pixels[3], + guint stride[3], + gint x, + gint y, + guint width, + guint height, + guint32 color +) +{ + guint i, j; + + color = color | 0xff000000; + + for (j = 0; j < height; j++) { + guint32 *p = (guint32 *)(pixels[0] + (y + j) * stride[0] + x * 4); + for (i = 0; i < width; i++) + p[i] = color; + } +} + +static inline guint32 argb2yuv(guint32 color) +{ + const gint32 r = (color >> 16) & 0xff; + const gint32 g = (color >> 8) & 0xff; + const gint32 b = (color ) & 0xff; + + const guint32 y = (( 263 * r + 516 * g + 100 * b) >> 10) + 16; + const guint32 u = ((-152 * r - 298 * g + 450 * b) >> 10) + 128; + const guint32 v = (( 450 * r - 376 * g - 73 * b) >> 10) + 128; + + return (y << 16) | (u << 8) | v; +} + +gboolean +image_draw_rectangle( + GstVaapiImage *image, + gint x, + gint y, + guint width, + guint height, + guint32 color +) +{ + const GstVaapiImageFormat image_format = gst_vaapi_image_get_format(image); + const guint image_width = gst_vaapi_image_get_width(image); + const guint image_height = gst_vaapi_image_get_height(image); + GstVaapiDisplay *display; + guchar *pixels[3]; + guint stride[3]; + DrawRectFunc draw_rect = NULL; + guint i; + + static const struct { + GstVaapiImageFormat format; + DrawRectFunc draw_rect; + } + map[] = { +#define _(FORMAT) { GST_VAAPI_IMAGE_##FORMAT, draw_rect_##FORMAT } + _(ARGB), + _(BGRA), + _(RGBA), + _(ABGR), + _(NV12), + _(YV12), + _(I420), + _(AYUV), +#undef _ + { 0, } + }; + + for (i = 0; !draw_rect && map[i].format; i++) + if (map[i].format == image_format) + draw_rect = map[i].draw_rect; + if (!draw_rect) + return FALSE; + + display = gst_vaapi_object_get_display(GST_VAAPI_OBJECT(image)); + if (!display) + return FALSE; + + if (!gst_vaapi_image_map(image)) + return FALSE; + + for (i = 0; i < gst_vaapi_image_get_plane_count(image); i++) { + pixels[i] = gst_vaapi_image_get_plane(image, i); + stride[i] = gst_vaapi_image_get_pitch(image, i); + } + + if (gst_vaapi_image_format_is_yuv(image_format)) + color = argb2yuv(color); + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + if (width > image_width - x) + width = image_width - x; + if (height > image_height - y) + height = image_height - y; + + gst_vaapi_display_lock(display); + draw_rect(pixels, stride, x, y, width, height, color); + gst_vaapi_display_unlock(display); + return gst_vaapi_image_unmap(image); +} + +gboolean +image_upload(GstVaapiImage *image, GstVaapiSurface *surface) +{ + GstVaapiDisplay *display; + GstVaapiImageFormat format; + GstVaapiSubpicture *subpicture; + + display = gst_vaapi_object_get_display(GST_VAAPI_OBJECT(surface)); + if (!display) + return FALSE; + + format = gst_vaapi_image_get_format(image); + if (!format) + return FALSE; + + if (gst_vaapi_surface_put_image(surface, image)) + return TRUE; + + g_print("could not upload %" GST_FOURCC_FORMAT" image to surface\n", + GST_FOURCC_ARGS(format)); + + if (!gst_vaapi_display_has_subpicture_format(display, format)) + return FALSE; + + g_print("trying as a subpicture\n"); + + subpicture = gst_vaapi_subpicture_new(image); + if (!subpicture) + g_error("could not create VA subpicture"); + + if (!gst_vaapi_surface_associate_subpicture(surface, subpicture, + NULL, NULL)) + g_error("could not associate subpicture to surface"); + + /* The surface holds a reference to the subpicture. This is safe */ + g_object_unref(subpicture); + return TRUE; +} diff --git a/tests/image.h b/tests/image.h new file mode 100644 index 0000000..f958065 --- /dev/null +++ b/tests/image.h @@ -0,0 +1,49 @@ +/* + * image.h - Image utilities for the tests + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#ifndef IMAGE_H +#define IMAGE_H + +#include +#include + +GstVaapiImage * +image_generate( + GstVaapiDisplay *display, + GstVaapiImageFormat format, + guint width, + guint height +); + +gboolean +image_draw_rectangle( + GstVaapiImage *image, + gint x, + gint y, + guint width, + guint height, + guint32 color +); + +gboolean +image_upload(GstVaapiImage *image, GstVaapiSurface *surface); + +#endif /* IMAGE_H */ diff --git a/tests/output.c b/tests/output.c new file mode 100644 index 0000000..438c04c --- /dev/null +++ b/tests/output.c @@ -0,0 +1,187 @@ +/* + * output.c - Video output helpers + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include +#include +#if USE_DRM +# include +# include +#endif +#if USE_X11 +# include +# include +#endif +#if USE_GLX +# include +# include +#endif +#if USE_WAYLAND +# include +# include +#endif +#include "output.h" + +static const VideoOutputInfo *g_video_output; +static const VideoOutputInfo g_video_outputs[] = { + /* Video outputs are sorted in test order for automatic characterisation */ +#if USE_WAYLAND + { "wayland", + gst_vaapi_display_wayland_new, + gst_vaapi_window_wayland_new + }, +#endif +#if USE_X11 + { "x11", + gst_vaapi_display_x11_new, + gst_vaapi_window_x11_new + }, +#endif +#if USE_GLX + { "glx", + gst_vaapi_display_glx_new, + gst_vaapi_window_glx_new + }, +#endif +#if USE_DRM + { "drm", + gst_vaapi_display_drm_new, + gst_vaapi_window_drm_new + }, +#endif + { NULL, } +}; + +static gchar *g_output_name; +static gboolean g_list_outputs = FALSE; + +static GOptionEntry g_options[] = { + { "list-outputs", 0, + 0, + G_OPTION_ARG_NONE, &g_list_outputs, + "list video outputs", NULL }, + { "output", 'o', + 0, + G_OPTION_ARG_STRING, &g_output_name, + "video output name", NULL }, + { NULL, } +}; + +static void +list_outputs(void) +{ + const VideoOutputInfo *o; + + g_print("Video outputs:"); + for (o = g_video_outputs; o->name != NULL; o++) + g_print(" %s", o->name); + g_print("\n"); +} + +gboolean +video_output_init(int *argc, char *argv[], GOptionEntry *options) +{ + GOptionContext *ctx; + gboolean success; + +#if !GLIB_CHECK_VERSION(2,31,0) + if (!g_thread_supported()) + g_thread_init(NULL); +#endif + + ctx = g_option_context_new("- test options"); + if (!ctx) + return FALSE; + + g_option_context_add_group(ctx, gst_init_get_option_group()); + g_option_context_add_main_entries(ctx, g_options, NULL); + if (options) + g_option_context_add_main_entries(ctx, options, NULL); + success = g_option_context_parse(ctx, argc, &argv, NULL); + g_option_context_free(ctx); + + if (g_list_outputs) { + list_outputs(); + exit(0); + } + return success; +} + +void +video_output_exit(void) +{ + g_free(g_output_name); + gst_deinit(); +} + +const VideoOutputInfo * +video_output_lookup(const gchar *output_name) +{ + const VideoOutputInfo *o; + + if (!output_name) + return NULL; + + for (o = g_video_outputs; o->name != NULL; o++) { + if (g_ascii_strcasecmp(o->name, output_name) == 0) + return o; + } + return NULL; +} + +GstVaapiDisplay * +video_output_create_display(const gchar *display_name) +{ + const VideoOutputInfo *o = g_video_output; + GstVaapiDisplay *display = NULL; + + if (!o) { + if (g_output_name) + o = video_output_lookup(g_output_name); + else { + for (o = g_video_outputs; o->name != NULL; o++) { + display = o->create_display(display_name); + if (display) { + if (gst_vaapi_display_get_display(display)) + break; + g_object_unref(display); + display = NULL; + } + } + } + if (!o || !o->name) + return NULL; + g_print("Using %s video output\n", o->name); + g_video_output = o; + } + + if (!display) + display = o->create_display(display_name); + return display; +} + +GstVaapiWindow * +video_output_create_window(GstVaapiDisplay *display, guint width, guint height) +{ + if (!g_video_output) + return NULL; + return g_video_output->create_window(display, width, height); +} diff --git a/tests/output.h b/tests/output.h new file mode 100644 index 0000000..3377915 --- /dev/null +++ b/tests/output.h @@ -0,0 +1,55 @@ +/* + * output.h - Video output helpers + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef OUTPUT_H +#define OUTPUT_H + +#include +#include +#include + +typedef GstVaapiDisplay *(*CreateDisplayFunc)(const gchar *display_name); +typedef GstVaapiWindow *(*CreateWindowFunc)(GstVaapiDisplay *display, + guint width, guint height); + +typedef struct _VideoOutputInfo VideoOutputInfo; +struct _VideoOutputInfo { + const gchar *name; + CreateDisplayFunc create_display; + CreateWindowFunc create_window; +}; + +gboolean +video_output_init(int *argc, char *argv[], GOptionEntry *options); + +void +video_output_exit(void); + +const VideoOutputInfo * +video_output_lookup(const gchar *output_name); + +GstVaapiDisplay * +video_output_create_display(const gchar *display_name); + +GstVaapiWindow * +video_output_create_window(GstVaapiDisplay *display, guint width, guint height); + +#endif /* OUTPUT_H */ diff --git a/tests/test-decode.c b/tests/test-decode.c new file mode 100644 index 0000000..a425f82 --- /dev/null +++ b/tests/test-decode.c @@ -0,0 +1,199 @@ +/* + * test-decode.c - Test GstVaapiDecoder + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Copyright (C) 2011-2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include "test-jpeg.h" +#include "test-mpeg2.h" +#include "test-h264.h" +#include "test-vc1.h" +#include "output.h" + +/* Set to 1 to check display cache works (shared VA display) */ +#define CHECK_DISPLAY_CACHE 1 + +typedef void (*GetVideoInfoFunc)(VideoDecodeInfo *info); + +typedef struct _CodecDefs CodecDefs; +struct _CodecDefs { + const gchar *codec_str; + GetVideoInfoFunc get_video_info; +}; + +static const CodecDefs g_codec_defs[] = { +#define INIT_FUNCS(CODEC) { #CODEC, CODEC##_get_video_info } + INIT_FUNCS(jpeg), + INIT_FUNCS(mpeg2), + INIT_FUNCS(h264), + INIT_FUNCS(vc1), +#undef INIT_FUNCS + { NULL, } +}; + +static const CodecDefs * +get_codec_defs(const gchar *codec_str) +{ + const CodecDefs *c; + for (c = g_codec_defs; c->codec_str; c++) + if (strcmp(codec_str, c->codec_str) == 0) + return c; + return NULL; +} + +static inline void pause(void) +{ + g_print("Press any key to continue...\n"); + getchar(); +} + +static gchar *g_codec_str; + +static GOptionEntry g_options[] = { + { "codec", 'c', + 0, + G_OPTION_ARG_STRING, &g_codec_str, + "codec to test", NULL }, + { NULL, } +}; + +int +main(int argc, char *argv[]) +{ + GstVaapiDisplay *display, *display2; + GstVaapiWindow *window; + GstVaapiDecoder *decoder; + GstCaps *decoder_caps; + GstStructure *structure; + GstVaapiDecoderStatus status; + const CodecDefs *codec; + GstBuffer *buffer; + GstVaapiSurfaceProxy *proxy; + VideoDecodeInfo info; + + static const guint win_width = 640; + static const guint win_height = 480; + + if (!video_output_init(&argc, argv, g_options)) + g_error("failed to initialize video output subsystem"); + + if (!g_codec_str) + g_codec_str = g_strdup("h264"); + + g_print("Test %s decode\n", g_codec_str); + codec = get_codec_defs(g_codec_str); + if (!codec) + g_error("no %s codec data found", g_codec_str); + + display = video_output_create_display(NULL); + if (!display) + g_error("could not create VA display"); + + if (CHECK_DISPLAY_CACHE) + display2 = video_output_create_display(NULL); + else + display2 = g_object_ref(display); + if (!display2) + g_error("could not create second VA display"); + + window = video_output_create_window(display, win_width, win_height); + if (!window) + g_error("could not create window"); + + codec->get_video_info(&info); + decoder_caps = gst_vaapi_profile_get_caps(info.profile); + if (!decoder_caps) + g_error("could not create decoder caps"); + + structure = gst_caps_get_structure(decoder_caps, 0); + if (info.width > 0 && info.height > 0) + gst_structure_set( + structure, + "width", G_TYPE_INT, info.width, + "height", G_TYPE_INT, info.height, + NULL + ); + + switch (gst_vaapi_profile_get_codec(info.profile)) { + case GST_VAAPI_CODEC_H264: + decoder = gst_vaapi_decoder_h264_new(display, decoder_caps); + break; +#if USE_JPEG_DECODER + case GST_VAAPI_CODEC_JPEG: + decoder = gst_vaapi_decoder_jpeg_new(display, decoder_caps); + break; +#endif + case GST_VAAPI_CODEC_MPEG2: + decoder = gst_vaapi_decoder_mpeg2_new(display, decoder_caps); + break; + case GST_VAAPI_CODEC_VC1: + decoder = gst_vaapi_decoder_vc1_new(display, decoder_caps); + break; + default: + decoder = NULL; + break; + } + if (!decoder) + g_error("could not create decoder"); + gst_caps_unref(decoder_caps); + + buffer = gst_buffer_new(); + if (!buffer) + g_error("could not create encoded data buffer"); + gst_buffer_set_data(buffer, (guchar *)info.data, info.data_size); + + if (!gst_vaapi_decoder_put_buffer(decoder, buffer)) + g_error("could not send video data to the decoder"); + gst_buffer_unref(buffer); + + if (!gst_vaapi_decoder_put_buffer(decoder, NULL)) + g_error("could not send EOS to the decoder"); + + proxy = gst_vaapi_decoder_get_surface(decoder, &status); + if (!proxy) + g_error("could not get decoded surface (decoder status %d)", status); + + gst_vaapi_window_show(window); + + if (!gst_vaapi_window_put_surface(window, + GST_VAAPI_SURFACE_PROXY_SURFACE(proxy), + NULL, + NULL, + GST_VAAPI_PICTURE_STRUCTURE_FRAME)) + g_error("could not render surface"); + + pause(); + + g_object_unref(proxy); + g_object_unref(decoder); + g_object_unref(window); + g_object_unref(display); + g_object_unref(display2); + g_free(g_codec_str); + video_output_exit(); + return 0; +} diff --git a/tests/test-decode.h b/tests/test-decode.h new file mode 100644 index 0000000..147f51c --- /dev/null +++ b/tests/test-decode.h @@ -0,0 +1,37 @@ +/* + * test-decode.h - Test GstVaapiDecoder + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef TEST_DECODE_H +#define TEST_DECODE_H + +#include +#include + +typedef struct _VideoDecodeInfo VideoDecodeInfo; +struct _VideoDecodeInfo { + GstVaapiProfile profile; + guint width; + guint height; + const guchar *data; + guint data_size; +}; + +#endif /* TEST_DECODE_H */ diff --git a/tests/test-display.c b/tests/test-display.c new file mode 100644 index 0000000..fa381cd --- /dev/null +++ b/tests/test-display.c @@ -0,0 +1,499 @@ +/* + * test-display.c - Test GstVaapiDisplayX11 + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#include "config.h" +#include +#if USE_DRM +# include +# include +# include +# include +# ifndef DRM_DEVICE_PATH +# define DRM_DEVICE_PATH "/dev/dri/card0" +# endif +#endif +#if USE_X11 +# include +#endif +#if USE_GLX +# include +#endif +#if USE_WAYLAND +# include +#endif + +#ifdef HAVE_VA_VA_GLX_H +# include +#endif + +static void +print_value(const GValue *value, const gchar *name) +{ + gchar *value_string; + + value_string = g_strdup_value_contents(value); + if (!value_string) + return; + g_print(" %s: %s\n", name, value_string); + g_free(value_string); +} + +static void +print_profile_caps(GstCaps *caps, const gchar *name) +{ + guint i, n_caps = gst_caps_get_size(caps); + gint version; + const gchar *profile; + gboolean has_version; + + g_print("%u %s caps\n", n_caps, name); + + for (i = 0; i < gst_caps_get_size(caps); i++) { + GstStructure * const structure = gst_caps_get_structure(caps, i); + if (!structure) + g_error("could not get caps structure %d", i); + + has_version = ( + gst_structure_get_int(structure, "version", &version) || + gst_structure_get_int(structure, "mpegversion", &version) + ); + + g_print(" %s", gst_structure_get_name(structure)); + if (has_version) + g_print("%d", version); + + profile = gst_structure_get_string(structure, "profile"); + if (!profile) + g_error("could not get structure profile"); + g_print(": %s profile\n", profile); + } +} + +static void +print_format_caps(GstCaps *caps, const gchar *name) +{ + guint i, n_caps = gst_caps_get_size(caps); + + g_print("%u %s caps\n", n_caps, name); + + for (i = 0; i < gst_caps_get_size(caps); i++) { + GstStructure * const structure = gst_caps_get_structure(caps, i); + if (!structure) + g_error("could not get caps structure %d", i); + + g_print(" %s:", gst_structure_get_name(structure)); + + if (gst_structure_has_name(structure, "video/x-raw-yuv")) { + guint32 fourcc; + + gst_structure_get_fourcc(structure, "format", &fourcc); + + g_print(" fourcc '%c%c%c%c'", + fourcc & 0xff, + (fourcc >> 8) & 0xff, + (fourcc >> 16) & 0xff, + (fourcc >> 24) & 0xff); + } + else { + gint bpp, endian, rmask, gmask, bmask, amask; + gboolean has_alpha; + + gst_structure_get_int(structure, "bpp", &bpp); + gst_structure_get_int(structure, "endianness", &endian); + gst_structure_get_int(structure, "red_mask", &rmask); + gst_structure_get_int(structure, "blue_mask", &bmask); + gst_structure_get_int(structure, "green_mask", &gmask); + has_alpha = gst_structure_get_int(structure, "alpha_mask", &amask); + + g_print(" %d bits per pixel, %s endian,", + bpp, endian == G_BIG_ENDIAN ? "big" : "little"); + g_print(" %s masks", has_alpha ? "rgba" : "rgb"); + g_print(" 0x%08x 0x%08x 0x%08x", rmask, gmask, bmask); + if (has_alpha) + g_print(" 0x%08x", amask); + } + g_print("\n"); + } +} + +typedef struct _GstVaapiDisplayProperty GstVaapiDisplayProperty; +struct _GstVaapiDisplayProperty { + const gchar *name; + GValue value; +}; + +static void +gst_vaapi_display_property_free(GstVaapiDisplayProperty *prop) +{ + if (!prop) + return; + g_value_unset(&prop->value); + g_slice_free(GstVaapiDisplayProperty, prop); +} + +static GstVaapiDisplayProperty * +gst_vaapi_display_property_new(const gchar *name) +{ + GstVaapiDisplayProperty *prop; + + prop = g_slice_new0(GstVaapiDisplayProperty); + if (!prop) + return NULL; + prop->name = name; + return prop; +} + +static void +free_property_cb(gpointer data, gpointer user_data) +{ + gst_vaapi_display_property_free(data); +} + +static inline GParamSpec * +get_display_property(GstVaapiDisplay *display, const gchar *name) +{ + GObjectClass *klass; + + klass = G_OBJECT_CLASS(GST_VAAPI_DISPLAY_GET_CLASS(display)); + if (!klass) + return NULL; + return g_object_class_find_property(klass, name); +} + +static void +dump_properties(GstVaapiDisplay *display) +{ + GstVaapiDisplayProperty *prop; + GPtrArray *properties; + guint i; + + static const gchar *g_properties[] = { + GST_VAAPI_DISPLAY_PROP_RENDER_MODE, + GST_VAAPI_DISPLAY_PROP_ROTATION, + GST_VAAPI_DISPLAY_PROP_HUE, + GST_VAAPI_DISPLAY_PROP_SATURATION, + GST_VAAPI_DISPLAY_PROP_BRIGHTNESS, + GST_VAAPI_DISPLAY_PROP_CONTRAST, + NULL + }; + + properties = g_ptr_array_new(); + if (!properties) + return; + + for (i = 0; g_properties[i] != NULL; i++) { + GParamSpec *pspec = get_display_property(display, g_properties[i]); + + if (!pspec) { + GST_ERROR("failed to find GstVaapiDisplay property '%s'", + g_properties[i]); + goto end; + } + + if (!gst_vaapi_display_has_property(display, pspec->name)) + continue; + + prop = gst_vaapi_display_property_new(pspec->name); + if (!prop) { + GST_ERROR("failed to allocate GstVaapiDisplayProperty"); + goto end; + } + + g_value_init(&prop->value, pspec->value_type); + g_object_get_property(G_OBJECT(display), pspec->name, &prop->value); + g_ptr_array_add(properties, prop); + } + + g_print("%u properties\n", properties->len); + for (i = 0; i < properties->len; i++) { + prop = g_ptr_array_index(properties, i); + print_value(&prop->value, prop->name); + } + +end: + if (properties) { + g_ptr_array_foreach(properties, free_property_cb, NULL); + g_ptr_array_free(properties, TRUE); + } +} + +static void +dump_info(GstVaapiDisplay *display) +{ + GstCaps *caps; + + caps = gst_vaapi_display_get_decode_caps(display); + if (!caps) + g_error("could not get VA decode caps"); + + print_profile_caps(caps, "decoders"); + gst_caps_unref(caps); + + caps = gst_vaapi_display_get_encode_caps(display); + if (!caps) + g_error("could not get VA encode caps"); + + print_profile_caps(caps, "encoders"); + gst_caps_unref(caps); + + caps = gst_vaapi_display_get_image_caps(display); + if (!caps) + g_error("could not get VA image caps"); + + print_format_caps(caps, "image"); + gst_caps_unref(caps); + + caps = gst_vaapi_display_get_subpicture_caps(display); + if (!caps) + g_error("could not get VA subpicture caps"); + + print_format_caps(caps, "subpicture"); + gst_caps_unref(caps); + + dump_properties(display); +} + +int +main(int argc, char *argv[]) +{ + GstVaapiDisplay *display; + guint width, height, par_n, par_d; + + gst_init(&argc, &argv); + +#if USE_DRM + g_print("#\n"); + g_print("# Create display with gst_vaapi_display_drm_new()\n"); + g_print("#\n"); + { + display = gst_vaapi_display_drm_new(NULL); + if (!display) + g_error("could not create Gst/VA display"); + + dump_info(display); + g_object_unref(display); + } + g_print("\n"); + + g_print("#\n"); + g_print("# Create display with gst_vaapi_display_drm_new_with_device()\n"); + g_print("#\n"); + { + int drm_device; + + drm_device = open(DRM_DEVICE_PATH, O_RDWR|O_CLOEXEC); + if (drm_device < 0) + g_error("could not open DRM device"); + + display = gst_vaapi_display_drm_new_with_device(drm_device); + if (!display) + g_error("could not create Gst/VA display"); + + dump_info(display); + g_object_unref(display); + close(drm_device); + } + g_print("\n"); + + g_print("#\n"); + g_print("# Create display with gst_vaapi_display_new_with_display() [vaGetDisplayDRM()]\n"); + g_print("#\n"); + { + int drm_device; + VADisplay va_display; + + drm_device = open(DRM_DEVICE_PATH, O_RDWR|O_CLOEXEC); + if (drm_device < 0) + g_error("could not open DRM device"); + + va_display = vaGetDisplayDRM(drm_device); + if (!va_display) + g_error("could not create VA display"); + + display = gst_vaapi_display_new_with_display(va_display); + if (!display) + g_error("could not create Gst/VA display"); + + dump_info(display); + g_object_unref(display); + close(drm_device); + } + g_print("\n"); +#endif + +#if USE_X11 + g_print("#\n"); + g_print("# Create display with gst_vaapi_display_x11_new()\n"); + g_print("#\n"); + { + display = gst_vaapi_display_x11_new(NULL); + if (!display) + g_error("could not create Gst/VA display"); + + gst_vaapi_display_get_size(display, &width, &height); + g_print("Display size: %ux%u\n", width, height); + + gst_vaapi_display_get_pixel_aspect_ratio(display, &par_n, &par_d); + g_print("Pixel aspect ratio: %u/%u\n", par_n, par_d); + + dump_info(display); + g_object_unref(display); + } + g_print("\n"); + + g_print("#\n"); + g_print("# Create display with gst_vaapi_display_x11_new_with_display()\n"); + g_print("#\n"); + { + Display *x11_display; + + x11_display = XOpenDisplay(NULL); + if (!x11_display) + g_error("could not create X11 display"); + + display = gst_vaapi_display_x11_new_with_display(x11_display); + if (!display) + g_error("could not create Gst/VA display"); + + dump_info(display); + g_object_unref(display); + XCloseDisplay(x11_display); + } + g_print("\n"); + + g_print("#\n"); + g_print("# Create display with gst_vaapi_display_new_with_display() [vaGetDisplay()]\n"); + g_print("#\n"); + { + Display *x11_display; + VADisplay va_display; + + x11_display = XOpenDisplay(NULL); + if (!x11_display) + g_error("could not create X11 display"); + + va_display = vaGetDisplay(x11_display); + if (!va_display) + g_error("could not create VA display"); + + display = gst_vaapi_display_new_with_display(va_display); + if (!display) + g_error("could not create Gst/VA display"); + + dump_info(display); + g_object_unref(display); + XCloseDisplay(x11_display); + } + g_print("\n"); +#endif + +#if USE_GLX + g_print("#\n"); + g_print("# Create display with gst_vaapi_display_glx_new()\n"); + g_print("#\n"); + { + display = gst_vaapi_display_glx_new(NULL); + if (!display) + g_error("could not create Gst/VA display"); + + gst_vaapi_display_get_size(display, &width, &height); + g_print("Display size: %ux%u\n", width, height); + + gst_vaapi_display_get_pixel_aspect_ratio(display, &par_n, &par_d); + g_print("Pixel aspect ratio: %u/%u\n", par_n, par_d); + + dump_info(display); + g_object_unref(display); + } + g_print("\n"); + + g_print("#\n"); + g_print("# Create display with gst_vaapi_display_glx_new_with_display()\n"); + g_print("#\n"); + { + Display *x11_display; + + x11_display = XOpenDisplay(NULL); + if (!x11_display) + g_error("could not create X11 display"); + + display = gst_vaapi_display_glx_new_with_display(x11_display); + if (!display) + g_error("could not create Gst/VA display"); + + dump_info(display); + g_object_unref(display); + XCloseDisplay(x11_display); + } + g_print("\n"); + +#ifdef HAVE_VA_VA_GLX_H + g_print("#\n"); + g_print("# Create display with gst_vaapi_display_new_with_display() [vaGetDisplayGLX()]\n"); + g_print("#\n"); + { + Display *x11_display; + VADisplay va_display; + + x11_display = XOpenDisplay(NULL); + if (!x11_display) + g_error("could not create X11 display"); + + va_display = vaGetDisplayGLX(x11_display); + if (!va_display) + g_error("could not create VA display"); + + display = gst_vaapi_display_new_with_display(va_display); + if (!display) + g_error("could not create Gst/VA display"); + + dump_info(display); + g_object_unref(display); + XCloseDisplay(x11_display); + } + g_print("\n"); +#endif +#endif + +#if USE_WAYLAND + g_print("#\n"); + g_print("# Create display with gst_vaapi_display_wayland_new()\n"); + g_print("#\n"); + { + display = gst_vaapi_display_wayland_new(NULL); + if (!display) + g_error("could not create Gst/VA display"); + + gst_vaapi_display_get_size(display, &width, &height); + g_print("Display size: %ux%u\n", width, height); + + gst_vaapi_display_get_pixel_aspect_ratio(display, &par_n, &par_d); + g_print("Pixel aspect ratio: %u/%u\n", par_n, par_d); + + dump_info(display); + g_object_unref(display); + } + g_print("\n"); +#endif + + gst_deinit(); + return 0; +} diff --git a/tests/test-h264.c b/tests/test-h264.c new file mode 100644 index 0000000..e25c392 --- /dev/null +++ b/tests/test-h264.c @@ -0,0 +1,1049 @@ +/* + * test-h264.c - H.264 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#include "test-h264.h" + +#define H264_CLIP_WIDTH 320 +#define H264_CLIP_HEIGHT 240 +#define H264_CLIP_DATA_SIZE 12111 + +/* Data dump of a 320x240 H.264 video clip (h264.mp4), it has a single frame */ +static const guchar h264_clip[H264_CLIP_DATA_SIZE] = { + 0x00, 0x00, 0x01, 0x67, 0x4d, 0x40, 0x0d, 0xab, 0x40, 0xa0, 0xfd, 0x80, + 0x88, 0x00, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0xc4, 0x78, + 0xa1, 0x55, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x01, + 0x65, 0x88, 0x82, 0x00, 0x45, 0xbb, 0x9d, 0x38, 0x9b, 0xe8, 0x48, 0xef, + 0xed, 0xa7, 0xd7, 0x9c, 0x19, 0x9b, 0x5a, 0xca, 0x00, 0x0d, 0x54, 0x0c, + 0xe3, 0xd5, 0xad, 0xa9, 0x5d, 0x71, 0x24, 0x83, 0xbb, 0x36, 0x4d, 0xb1, + 0xf5, 0x0f, 0xc6, 0x66, 0xb6, 0x6d, 0x1d, 0xa5, 0x45, 0xfc, 0xa0, 0x4c, + 0xbf, 0xfb, 0x2f, 0x5c, 0x1a, 0x5a, 0x3b, 0x29, 0xe0, 0x35, 0x95, 0x44, + 0x8e, 0x2f, 0x22, 0xd3, 0x3a, 0x48, 0x88, 0x7d, 0x32, 0x97, 0xff, 0xd8, + 0x54, 0x7f, 0x7f, 0x65, 0x57, 0x71, 0xaf, 0xba, 0x17, 0xe0, 0x12, 0x24, + 0xc9, 0x5b, 0xaa, 0xc7, 0xd5, 0x27, 0xc9, 0x64, 0x5d, 0x5e, 0xa0, 0xea, + 0x57, 0xd2, 0x7d, 0x55, 0x6c, 0xf2, 0x44, 0x2f, 0x4b, 0x5d, 0xbd, 0x62, + 0xb9, 0xc2, 0xfa, 0x1e, 0x8f, 0xbc, 0x57, 0x5f, 0xc1, 0x2d, 0xb3, 0x9a, + 0x0e, 0x58, 0x75, 0xf7, 0x08, 0xdf, 0x2d, 0xda, 0xc1, 0xa5, 0x55, 0x76, + 0x06, 0xaf, 0x92, 0x28, 0x43, 0xc5, 0x20, 0x16, 0x96, 0xf5, 0x79, 0x1e, + 0x88, 0x77, 0xb3, 0x4e, 0xb8, 0x4f, 0x3e, 0x51, 0x3c, 0xcf, 0xc0, 0x28, + 0xda, 0xb8, 0xa3, 0x1d, 0xed, 0x8e, 0x04, 0x74, 0x82, 0xc1, 0x5d, 0xa8, + 0x3c, 0x25, 0xd2, 0x84, 0x0b, 0x34, 0x40, 0x8b, 0x7f, 0xee, 0xae, 0xf8, + 0xde, 0x6e, 0x28, 0xf6, 0xfc, 0xfc, 0x14, 0x7e, 0x95, 0xd9, 0xd8, 0x2c, + 0x09, 0x49, 0x27, 0x64, 0x13, 0x83, 0x5c, 0x6f, 0xd4, 0x09, 0x48, 0xa8, + 0xd4, 0x1b, 0x6e, 0x4d, 0x05, 0x0a, 0xbe, 0x27, 0xff, 0xf4, 0x27, 0x04, + 0x41, 0xa0, 0x23, 0x61, 0xe6, 0x26, 0x32, 0xf4, 0xa3, 0xca, 0x97, 0xfc, + 0xeb, 0x6b, 0x45, 0x35, 0x13, 0x69, 0xd9, 0x41, 0x0f, 0xa6, 0xc0, 0xbe, + 0xd5, 0xfa, 0x28, 0xa6, 0x4f, 0x62, 0x3e, 0x1f, 0xcb, 0x98, 0x0a, 0x70, + 0x09, 0xc1, 0xe3, 0x69, 0x30, 0x20, 0xe7, 0xd5, 0x1c, 0xf0, 0x7e, 0x52, + 0x1d, 0x6a, 0xdd, 0x14, 0x58, 0x5e, 0x7a, 0x35, 0x57, 0xa1, 0xe6, 0x83, + 0x46, 0x57, 0x6e, 0x57, 0x7f, 0x72, 0x5d, 0x0c, 0x0c, 0xf4, 0x40, 0x11, + 0x8c, 0xbb, 0xdf, 0xd1, 0x54, 0xfb, 0x7d, 0xf7, 0x03, 0xb9, 0x4e, 0xa3, + 0x76, 0x4c, 0xce, 0xfb, 0x9e, 0x39, 0x02, 0xf0, 0x48, 0xb5, 0x8c, 0x36, + 0x6e, 0x93, 0x79, 0x48, 0xcc, 0x28, 0xec, 0xd7, 0xb8, 0x02, 0xe5, 0xa3, + 0x37, 0x01, 0xe1, 0x3c, 0x40, 0x8f, 0x68, 0x27, 0xbc, 0xec, 0x6b, 0x59, + 0xb9, 0xfe, 0xb8, 0x67, 0x68, 0x83, 0x99, 0x97, 0x1e, 0xcc, 0x4e, 0x23, + 0x82, 0x26, 0x93, 0x7b, 0x7a, 0x9e, 0xdc, 0x42, 0xca, 0x1b, 0x3e, 0x13, + 0x19, 0x45, 0x03, 0x40, 0xab, 0xd2, 0xda, 0x6b, 0x6c, 0x26, 0xdb, 0xe3, + 0x72, 0x06, 0x89, 0xea, 0x03, 0x95, 0xe3, 0x14, 0xe1, 0x4a, 0x16, 0x58, + 0x2d, 0x67, 0xaa, 0xbf, 0xbe, 0x37, 0x54, 0x19, 0xb1, 0x57, 0x61, 0x85, + 0x82, 0x5f, 0x63, 0x33, 0xe2, 0xf8, 0x7f, 0x4f, 0x21, 0x44, 0x8a, 0x0e, + 0x21, 0x2b, 0x12, 0x99, 0x4d, 0xd9, 0x2e, 0xea, 0x36, 0x2d, 0x45, 0xcb, + 0xe2, 0xfe, 0xdd, 0x03, 0x3b, 0x08, 0x58, 0x60, 0x1e, 0xb2, 0xfa, 0x3b, + 0x89, 0xa5, 0x03, 0xde, 0xab, 0x71, 0x32, 0x48, 0x46, 0x2c, 0xfb, 0x2b, + 0x84, 0x83, 0xc9, 0xff, 0xf6, 0xf5, 0x2f, 0xe7, 0x2f, 0x6a, 0x5d, 0x86, + 0xe2, 0x48, 0x23, 0x6d, 0x84, 0x60, 0x9b, 0xc0, 0x25, 0x1e, 0xff, 0x94, + 0xe8, 0xf4, 0xd0, 0x4e, 0x11, 0x60, 0xda, 0x20, 0xa8, 0xfd, 0xf3, 0x00, + 0x4f, 0x0e, 0x4f, 0xa2, 0xeb, 0xe1, 0xa8, 0xb3, 0x47, 0x35, 0x62, 0x83, + 0x6f, 0x08, 0x6b, 0xb8, 0x82, 0x04, 0xcc, 0x63, 0x69, 0xd7, 0xba, 0x10, + 0xd4, 0x51, 0xe6, 0xb5, 0x34, 0xe8, 0x7d, 0xaf, 0x87, 0xcf, 0x1d, 0xeb, + 0x46, 0xc1, 0xcd, 0xcb, 0xf2, 0x3b, 0x3e, 0xa0, 0x61, 0xc7, 0x68, 0x86, + 0x0b, 0x9f, 0x0b, 0x59, 0xc0, 0x79, 0x4e, 0xcc, 0x79, 0x91, 0xa0, 0xe8, + 0x80, 0x6c, 0xbd, 0x35, 0x12, 0x71, 0x2f, 0x5e, 0xa4, 0xfc, 0xe6, 0x51, + 0xe0, 0xbe, 0x41, 0x1a, 0x19, 0x60, 0xd8, 0xac, 0xcd, 0x93, 0x05, 0x70, + 0xa0, 0xda, 0x53, 0x4e, 0x5a, 0x6d, 0x9b, 0x3f, 0x28, 0x73, 0x87, 0x6f, + 0x6d, 0x41, 0x5a, 0x13, 0xd0, 0xea, 0x19, 0xb3, 0xb7, 0xf1, 0x75, 0x92, + 0xae, 0x43, 0x9d, 0xe3, 0xa7, 0x4d, 0x5a, 0x52, 0x36, 0xce, 0x6b, 0x1e, + 0x2b, 0x2e, 0xab, 0x0c, 0xd7, 0xe4, 0x1c, 0x44, 0x72, 0x9d, 0x86, 0xb6, + 0xeb, 0xe5, 0x80, 0xc4, 0x45, 0x21, 0x8b, 0xe0, 0xe0, 0x9d, 0x09, 0xfa, + 0x0b, 0x59, 0x0c, 0x2c, 0x9d, 0x97, 0x15, 0x56, 0xd0, 0x21, 0xd8, 0x90, + 0xb4, 0x89, 0xc4, 0x96, 0x76, 0xf1, 0x64, 0xa5, 0x85, 0x2a, 0x13, 0xfb, + 0xfa, 0x11, 0x1e, 0x2d, 0x63, 0xc2, 0x9a, 0x87, 0x99, 0x2c, 0x18, 0xb8, + 0xeb, 0x6a, 0x5c, 0x68, 0x26, 0x63, 0xcc, 0x1b, 0x1a, 0x5c, 0x7f, 0x0d, + 0x45, 0xcc, 0x56, 0x46, 0x92, 0xbb, 0x76, 0xf2, 0x2e, 0x52, 0x05, 0x3c, + 0xe3, 0xbb, 0x59, 0x9b, 0x89, 0x03, 0x0d, 0x48, 0xb1, 0xdc, 0x78, 0x04, + 0x03, 0x24, 0xf4, 0x62, 0xcf, 0xb1, 0xc6, 0x64, 0x05, 0xbd, 0x89, 0x94, + 0x1a, 0x8d, 0xc1, 0xbe, 0xac, 0xe0, 0xed, 0x89, 0xf3, 0x47, 0x81, 0x82, + 0xb9, 0x64, 0xcc, 0x8e, 0xc4, 0x1e, 0xa9, 0xf6, 0xde, 0x8d, 0xb7, 0x33, + 0xba, 0x5b, 0x49, 0x0d, 0x0a, 0x16, 0x96, 0x7d, 0x89, 0x82, 0xe0, 0x5a, + 0x08, 0x55, 0xbd, 0xce, 0xca, 0xc0, 0x46, 0x1a, 0x6b, 0xf9, 0x7d, 0x03, + 0xe8, 0x35, 0x69, 0x7d, 0x87, 0xc9, 0x71, 0x01, 0x7e, 0xa8, 0x3a, 0x9c, + 0xd5, 0xe2, 0x71, 0xa6, 0xc7, 0xe2, 0x2d, 0xf3, 0x6f, 0x74, 0x0f, 0x3e, + 0x03, 0x70, 0x5e, 0xec, 0x8c, 0x66, 0xf9, 0x71, 0x9a, 0xd2, 0x56, 0x57, + 0x37, 0xcd, 0x50, 0x55, 0x97, 0xea, 0x67, 0x20, 0x59, 0x06, 0x4d, 0x22, + 0xa0, 0x85, 0x90, 0xb3, 0x59, 0x15, 0x75, 0x0d, 0x70, 0xbd, 0xb5, 0x7d, + 0x72, 0xaa, 0xea, 0xfc, 0x9d, 0x08, 0x8d, 0xdf, 0x31, 0x21, 0x2d, 0xef, + 0x00, 0x24, 0x6c, 0xae, 0x82, 0x6e, 0x1a, 0x4b, 0x28, 0xa5, 0x6d, 0x98, + 0xeb, 0x50, 0x87, 0x6f, 0x1b, 0xa5, 0xba, 0x1c, 0xda, 0x59, 0xb8, 0x4c, + 0x17, 0xe3, 0xd5, 0x10, 0x46, 0x94, 0x91, 0xed, 0x0b, 0xd3, 0xfc, 0x06, + 0x81, 0x60, 0x88, 0x5f, 0x58, 0x81, 0x26, 0x54, 0xdc, 0xd5, 0x7c, 0xbe, + 0x30, 0x04, 0x17, 0x84, 0x76, 0xe8, 0xb6, 0x8a, 0xec, 0x84, 0x02, 0xcf, + 0xc7, 0xda, 0x2d, 0x2e, 0x31, 0xc2, 0x77, 0x31, 0x54, 0x32, 0xbd, 0x77, + 0xa2, 0xa5, 0x5d, 0xec, 0x1c, 0x27, 0xf6, 0xec, 0xc8, 0x3f, 0xeb, 0x1a, + 0x24, 0xcb, 0x74, 0xd0, 0xb3, 0x52, 0xa8, 0x8f, 0x4c, 0x26, 0xbf, 0x68, + 0xb2, 0x87, 0xf3, 0xa8, 0xa9, 0x4f, 0x71, 0x57, 0xc7, 0xa8, 0x34, 0x5a, + 0x01, 0x68, 0xae, 0x5c, 0xb3, 0xd8, 0x23, 0x6b, 0xea, 0x18, 0xdf, 0xa9, + 0xe5, 0xc4, 0x11, 0x49, 0x2b, 0xfa, 0xa8, 0xf3, 0x8f, 0x80, 0x47, 0xa0, + 0x19, 0xc7, 0x20, 0xef, 0xbf, 0xed, 0xe1, 0x38, 0x8b, 0x16, 0x54, 0x36, + 0x60, 0x8b, 0x04, 0x26, 0x9c, 0x6b, 0x1a, 0x95, 0x4c, 0x94, 0x6a, 0x53, + 0xcf, 0xb4, 0x4b, 0x38, 0x3a, 0x15, 0x26, 0x94, 0x10, 0x1c, 0x35, 0xe4, + 0x57, 0x80, 0x19, 0xad, 0x1f, 0x82, 0xe8, 0x47, 0xe4, 0x90, 0xa2, 0x42, + 0x30, 0x43, 0x15, 0x92, 0x2b, 0x39, 0xfb, 0x7b, 0xb3, 0xdb, 0xc7, 0x5b, + 0x79, 0x5e, 0x91, 0xba, 0x38, 0x74, 0xd6, 0x00, 0x26, 0xa5, 0x8f, 0xa4, + 0x31, 0xe6, 0x7b, 0xeb, 0x52, 0xc2, 0xe2, 0xa1, 0x6b, 0x5f, 0x17, 0xf1, + 0x15, 0xc9, 0x4b, 0x44, 0x93, 0x77, 0x28, 0xdf, 0x2a, 0xc0, 0xb5, 0x97, + 0xfc, 0xbe, 0x2e, 0x72, 0x53, 0x58, 0xf9, 0x33, 0x3a, 0xb0, 0x6e, 0xaf, + 0x0c, 0x1b, 0xcf, 0x71, 0x37, 0x6b, 0x4a, 0x9a, 0x66, 0x16, 0x90, 0x43, + 0x9b, 0x70, 0x0d, 0x8f, 0xd3, 0x04, 0x4b, 0x14, 0xf2, 0x58, 0x9f, 0x64, + 0x33, 0x21, 0xdc, 0x02, 0x8a, 0x5b, 0xd6, 0x80, 0x9c, 0x22, 0xc8, 0x39, + 0x7d, 0x2d, 0x7c, 0x09, 0x4e, 0x6a, 0x8c, 0x8d, 0x0c, 0xc4, 0xfe, 0x6f, + 0x8c, 0x50, 0xf2, 0x75, 0xc0, 0x12, 0x6f, 0xd3, 0x9d, 0x07, 0xc0, 0xe9, + 0xdf, 0x36, 0xa2, 0x6f, 0xca, 0x14, 0x5b, 0x0f, 0x5a, 0xd8, 0x35, 0x72, + 0x07, 0x08, 0x80, 0xba, 0x2f, 0x61, 0x7f, 0xb0, 0x5e, 0xbb, 0xb1, 0x47, + 0x6a, 0xbd, 0x6a, 0xe4, 0xb6, 0xa2, 0xec, 0x2e, 0x27, 0x43, 0xbc, 0xd7, + 0x2c, 0x2c, 0xf3, 0x6c, 0x12, 0x4c, 0x86, 0x5a, 0x38, 0xa4, 0x87, 0xa8, + 0xe1, 0x70, 0x17, 0x15, 0xd0, 0x2b, 0x87, 0xdb, 0x87, 0xc0, 0x85, 0x57, + 0x30, 0x31, 0x16, 0x07, 0x9b, 0x72, 0x07, 0xf5, 0x18, 0x6d, 0xd1, 0x8d, + 0x31, 0xa1, 0x25, 0x6a, 0xb4, 0xf3, 0x07, 0x5f, 0x0c, 0x99, 0x33, 0x68, + 0xbf, 0x2c, 0xa1, 0xfd, 0xde, 0x16, 0x2d, 0x4a, 0x5a, 0xa0, 0x7e, 0xe5, + 0x9b, 0x89, 0x4a, 0x8d, 0xe7, 0x18, 0x21, 0x32, 0x47, 0x3c, 0x9d, 0x48, + 0xab, 0x7d, 0xca, 0xb4, 0x63, 0xd9, 0xfd, 0x29, 0x2d, 0x4c, 0xf1, 0xf2, + 0x20, 0x0a, 0x91, 0x2e, 0x2c, 0xa1, 0x49, 0x83, 0x73, 0x15, 0xa0, 0x7d, + 0x6e, 0xae, 0x51, 0x45, 0x0d, 0x09, 0x1f, 0x8f, 0x61, 0x42, 0xbd, 0x24, + 0xcd, 0x3e, 0xe8, 0x66, 0x84, 0xc6, 0x97, 0x08, 0x7b, 0x72, 0x73, 0x7e, + 0xe7, 0x99, 0x05, 0xab, 0x63, 0xff, 0x3c, 0x44, 0xa1, 0xc0, 0x1b, 0xfc, + 0xff, 0x27, 0xe9, 0x45, 0x82, 0x75, 0x82, 0x6f, 0x9c, 0x65, 0xef, 0x67, + 0xd6, 0x00, 0xd1, 0x9f, 0x61, 0x9f, 0x38, 0xdd, 0x7f, 0x5f, 0x4d, 0x67, + 0x5b, 0x5d, 0xff, 0x98, 0x6b, 0x13, 0xe0, 0xe7, 0x69, 0xcb, 0x7f, 0x7c, + 0x11, 0x91, 0xe0, 0x05, 0xb9, 0x64, 0xd0, 0xb7, 0x91, 0xe5, 0xd4, 0x3a, + 0x47, 0x05, 0x25, 0x4f, 0x15, 0x46, 0xaf, 0x41, 0x9e, 0xc7, 0x49, 0x15, + 0x17, 0xd1, 0x9c, 0x28, 0xef, 0x80, 0xa3, 0x8b, 0x60, 0xcc, 0x60, 0xeb, + 0x96, 0x36, 0x3a, 0x23, 0x94, 0xf3, 0x6c, 0xe5, 0x3f, 0xe8, 0x8b, 0x5c, + 0x8c, 0xfe, 0x6f, 0x91, 0x65, 0x19, 0xa1, 0x4d, 0x45, 0x7b, 0x06, 0x0f, + 0x71, 0xb7, 0x9a, 0x8d, 0x8e, 0x82, 0x7b, 0x68, 0x44, 0xa4, 0xa6, 0xc3, + 0xe5, 0x67, 0x9f, 0x6c, 0xd0, 0xe4, 0xe8, 0x37, 0x08, 0x6b, 0xbb, 0xa0, + 0x3a, 0xd0, 0xa9, 0xd9, 0x04, 0xaa, 0x91, 0xac, 0x71, 0xff, 0xec, 0x7e, + 0xaf, 0xa9, 0x99, 0xa2, 0x8d, 0x91, 0x95, 0xb3, 0xd8, 0xe4, 0xf3, 0x3f, + 0xa6, 0x4b, 0x0c, 0x19, 0x23, 0xf7, 0xa7, 0xcd, 0x4c, 0x41, 0x28, 0x63, + 0x9f, 0x0b, 0x8f, 0x70, 0x70, 0xbd, 0x25, 0x16, 0x8e, 0x86, 0x8a, 0x69, + 0xe3, 0x6a, 0xd4, 0x98, 0x42, 0x56, 0x15, 0x2d, 0x3d, 0xdb, 0x17, 0x1b, + 0x23, 0x58, 0x82, 0x56, 0x11, 0x97, 0x85, 0xf2, 0x68, 0x95, 0x92, 0xd5, + 0x9e, 0x91, 0x05, 0x70, 0xc8, 0x96, 0xb2, 0x73, 0x6d, 0x1e, 0x12, 0x8c, + 0xa0, 0xe4, 0x1a, 0x84, 0x5b, 0xb4, 0x32, 0xf7, 0x9e, 0x08, 0xd0, 0x6c, + 0x42, 0xf0, 0x0b, 0xc4, 0x1f, 0xe0, 0xbb, 0x71, 0xe1, 0x2d, 0x86, 0xd7, + 0x77, 0x24, 0x43, 0x53, 0x0c, 0x88, 0x21, 0x75, 0x95, 0xd0, 0xfe, 0x10, + 0x23, 0xcd, 0xba, 0x77, 0x3d, 0x9b, 0x0f, 0xb2, 0xe2, 0xcc, 0x0f, 0x94, + 0xe0, 0x66, 0x90, 0x0e, 0xf7, 0x6a, 0x3c, 0x9f, 0xc0, 0xf6, 0x98, 0x1c, + 0x4c, 0x9f, 0x25, 0xc4, 0xeb, 0x1d, 0x91, 0x32, 0x29, 0x34, 0x2a, 0xb0, + 0x7e, 0x1c, 0x09, 0x77, 0x13, 0x83, 0xfa, 0xcf, 0x24, 0xa2, 0x5f, 0x79, + 0x78, 0x64, 0xf7, 0x45, 0x81, 0xbe, 0x6a, 0x82, 0x26, 0xfd, 0xe7, 0xc3, + 0x61, 0x41, 0x27, 0xcc, 0x99, 0x69, 0x77, 0xc8, 0xa7, 0xf3, 0x52, 0x01, + 0xa7, 0x8c, 0x0b, 0x7d, 0x86, 0x8d, 0xbb, 0x31, 0xd6, 0x67, 0xf9, 0xa7, + 0x8f, 0x76, 0xb6, 0x74, 0x26, 0x43, 0x35, 0xb8, 0x83, 0x7c, 0x16, 0x34, + 0x88, 0x0c, 0xb6, 0xec, 0xf0, 0x01, 0x8c, 0x1c, 0xe5, 0x52, 0xd4, 0xca, + 0x01, 0x2e, 0xb5, 0x87, 0xc1, 0xc1, 0x1b, 0xa3, 0x02, 0x17, 0x13, 0xd3, + 0x35, 0xe8, 0x80, 0xe1, 0xd1, 0x01, 0x9c, 0x0a, 0x62, 0x7d, 0x98, 0x7c, + 0x68, 0xa4, 0x8e, 0x3a, 0x50, 0x4b, 0x95, 0x59, 0xa3, 0x11, 0xf6, 0xa3, + 0xde, 0x92, 0x65, 0x00, 0xa0, 0xe8, 0x32, 0xf0, 0xc3, 0x77, 0x68, 0x0b, + 0xed, 0xc1, 0x69, 0xd2, 0x6e, 0xce, 0x80, 0xe4, 0x56, 0x9b, 0x15, 0xbf, + 0x3c, 0x4a, 0x38, 0x26, 0xf6, 0x6a, 0xdb, 0x62, 0x7a, 0xab, 0xb1, 0x77, + 0x75, 0x0d, 0xa7, 0xa4, 0xcf, 0x5e, 0x2d, 0xea, 0x24, 0x84, 0xbd, 0x83, + 0x8e, 0xaa, 0x91, 0xe1, 0x72, 0x5f, 0x7f, 0x26, 0x54, 0x4f, 0xab, 0xa6, + 0x50, 0x22, 0x68, 0x8c, 0xa6, 0x06, 0x67, 0x3c, 0x3e, 0x93, 0x9a, 0xc2, + 0x53, 0x15, 0x08, 0x1a, 0x3c, 0xb3, 0x3f, 0xf0, 0x83, 0xf5, 0x0d, 0x9c, + 0xe3, 0x76, 0x11, 0x45, 0x21, 0x6b, 0x65, 0x97, 0xea, 0x3c, 0xdb, 0x0d, + 0xcd, 0x6e, 0xb7, 0x26, 0x7b, 0x82, 0x63, 0x35, 0x7e, 0x76, 0xf4, 0xb8, + 0x0e, 0xe5, 0x1d, 0x95, 0x94, 0x1c, 0x60, 0xc7, 0xea, 0x9c, 0x1c, 0x73, + 0x75, 0x0e, 0x9b, 0x5f, 0x78, 0x09, 0x4f, 0x90, 0x31, 0x5c, 0xc8, 0x5b, + 0x78, 0xce, 0xb3, 0x3e, 0x31, 0x61, 0x90, 0xba, 0xe0, 0xe1, 0x57, 0x1d, + 0x71, 0x80, 0x92, 0x6b, 0x75, 0xe1, 0x34, 0x95, 0xeb, 0x88, 0xe4, 0x0b, + 0x72, 0xdc, 0x34, 0x24, 0x3b, 0x6d, 0x94, 0xc9, 0xe9, 0x8d, 0x38, 0x72, + 0x9c, 0x61, 0x6e, 0x07, 0xd7, 0x35, 0xa1, 0x74, 0xc2, 0x0c, 0x36, 0xc3, + 0x54, 0xd3, 0xe5, 0xd1, 0x08, 0x8e, 0x24, 0x77, 0xf5, 0x61, 0xcf, 0x69, + 0x9b, 0x27, 0x70, 0xe7, 0x52, 0xf6, 0xef, 0x66, 0x8f, 0x0e, 0x8b, 0xc0, + 0xf3, 0x64, 0x2a, 0xa8, 0xff, 0xcc, 0xd9, 0x61, 0x53, 0xac, 0x36, 0x23, + 0x4f, 0x3c, 0x0f, 0xe0, 0xec, 0xad, 0xc5, 0x35, 0x3f, 0x3b, 0x74, 0x26, + 0x84, 0x48, 0xd1, 0xfe, 0x72, 0x01, 0xea, 0x4d, 0x03, 0x46, 0x66, 0x5a, + 0xc4, 0x0a, 0x55, 0x43, 0x61, 0x36, 0x6a, 0xc1, 0xd2, 0x74, 0x0a, 0x8f, + 0x01, 0xb2, 0xc2, 0xaa, 0xd7, 0x2d, 0x0a, 0x0f, 0x67, 0xa1, 0x25, 0x7d, + 0x45, 0x60, 0x0f, 0x06, 0xfb, 0x8f, 0x8b, 0xe0, 0x4a, 0x8c, 0xd7, 0x19, + 0xac, 0xcc, 0x47, 0xa2, 0x7c, 0x30, 0x90, 0x94, 0x81, 0xab, 0xde, 0x38, + 0xb8, 0xc9, 0xdb, 0x63, 0x9c, 0xcb, 0xdd, 0x71, 0xde, 0x4f, 0x1e, 0x43, + 0x08, 0xe4, 0xe3, 0x83, 0x86, 0x0f, 0x34, 0xb7, 0x1e, 0x53, 0xc1, 0xde, + 0x46, 0xf1, 0x70, 0xf5, 0xd8, 0x47, 0xd2, 0x9b, 0x44, 0x88, 0x85, 0x8e, + 0x32, 0xa9, 0x0c, 0x09, 0x2f, 0xd0, 0xe4, 0x4b, 0x30, 0x3a, 0x2e, 0x65, + 0x0c, 0xff, 0xb4, 0x0d, 0xa8, 0x8f, 0x61, 0x3e, 0x7e, 0x90, 0x66, 0xbb, + 0xf6, 0xbe, 0xfd, 0x7d, 0xe4, 0xdc, 0x2c, 0x59, 0x87, 0x81, 0x60, 0x96, + 0xd7, 0x1d, 0x10, 0x02, 0x35, 0xdd, 0x16, 0x4c, 0xe9, 0x2d, 0x52, 0x45, + 0xdd, 0x3f, 0xc9, 0xff, 0x8d, 0x19, 0xad, 0x02, 0x74, 0xf1, 0x09, 0x99, + 0x94, 0x66, 0x2e, 0x8b, 0xa3, 0xdc, 0x3d, 0xf3, 0xf5, 0x85, 0xf2, 0x60, + 0x7d, 0x9d, 0xe0, 0xd3, 0x0f, 0xa4, 0x92, 0xf3, 0x55, 0xbc, 0x7b, 0x20, + 0x6b, 0xf6, 0xc4, 0xc4, 0x0f, 0x8a, 0xd7, 0x5a, 0x02, 0xb0, 0xb7, 0x78, + 0xb4, 0x9e, 0xb6, 0x93, 0x95, 0x2e, 0x76, 0x06, 0x1e, 0x34, 0x5d, 0x34, + 0x77, 0x77, 0x6d, 0x32, 0xbb, 0x46, 0xad, 0x43, 0xd7, 0x72, 0x61, 0x33, + 0x4f, 0x98, 0xe9, 0x56, 0x3a, 0x96, 0x89, 0x6e, 0x1f, 0xaf, 0x6b, 0xa0, + 0x9a, 0xe4, 0x42, 0x5a, 0xb3, 0xb8, 0x2a, 0xe1, 0x2d, 0xa6, 0x32, 0xa2, + 0x01, 0xf5, 0x3a, 0x9a, 0xbb, 0x06, 0x76, 0x0b, 0xa8, 0xac, 0x02, 0x96, + 0x0c, 0x58, 0xd3, 0x64, 0xc8, 0xe2, 0xae, 0x6c, 0xf7, 0xa7, 0x32, 0x4b, + 0x51, 0x50, 0x11, 0x90, 0xcf, 0x37, 0xed, 0xd2, 0xa0, 0xa4, 0x97, 0xb3, + 0x45, 0x1d, 0x7d, 0xf3, 0xff, 0xde, 0x9f, 0x80, 0xa9, 0x61, 0xac, 0x37, + 0x7f, 0x5d, 0xc9, 0xf6, 0xdc, 0x26, 0xd0, 0x65, 0xf2, 0xdc, 0x0c, 0x1a, + 0xcb, 0xde, 0x6b, 0x77, 0xf3, 0x08, 0xa4, 0x93, 0xab, 0x2a, 0xdf, 0x18, + 0x1a, 0xc7, 0xa6, 0xa1, 0x7e, 0x43, 0x75, 0xca, 0x88, 0xcc, 0x6f, 0xa2, + 0x85, 0x0e, 0xb0, 0xd5, 0xcd, 0x8a, 0xff, 0xc1, 0x57, 0x20, 0x66, 0xf7, + 0x19, 0x7a, 0x52, 0x5b, 0x46, 0x87, 0x5f, 0xf7, 0x77, 0xe2, 0xab, 0x4e, + 0x4a, 0xce, 0x8f, 0x3f, 0xe6, 0x9f, 0x88, 0x3a, 0x33, 0x65, 0x3c, 0x3a, + 0x41, 0xc3, 0x8e, 0xee, 0x79, 0xe7, 0x2c, 0xb0, 0x3b, 0x93, 0x82, 0xa0, + 0x1a, 0x71, 0x0e, 0xf6, 0x31, 0xc5, 0x6f, 0xc1, 0xa8, 0x32, 0x89, 0x3b, + 0x33, 0x68, 0x53, 0x81, 0x15, 0x70, 0x5e, 0x22, 0xdc, 0x99, 0xc6, 0x88, + 0xf8, 0x11, 0x06, 0x56, 0x1f, 0x80, 0x7e, 0x0b, 0x27, 0x90, 0xfc, 0x97, + 0x76, 0x61, 0xdc, 0x30, 0x5d, 0x34, 0x4e, 0x83, 0x85, 0xce, 0xe2, 0x91, + 0x4d, 0x8d, 0x92, 0x88, 0x26, 0xa0, 0xde, 0x47, 0x82, 0xd2, 0xa8, 0xa5, + 0xe7, 0x27, 0x0c, 0x45, 0x41, 0x85, 0xa1, 0x12, 0xcb, 0x3a, 0x74, 0x53, + 0x93, 0x77, 0xd0, 0x8b, 0x42, 0x8d, 0x00, 0xca, 0x44, 0x67, 0xa0, 0x6a, + 0xbd, 0xcd, 0x4a, 0x3c, 0xfe, 0x6c, 0xa1, 0x48, 0x26, 0x0d, 0x51, 0x54, + 0x59, 0xc9, 0xf9, 0x51, 0x5c, 0xd3, 0x55, 0xf0, 0x72, 0x77, 0xdb, 0x52, + 0xee, 0x0a, 0x5e, 0x8a, 0xf0, 0xbe, 0x9a, 0x37, 0xa0, 0x1b, 0x94, 0xe3, + 0x2d, 0x17, 0xc4, 0xbe, 0x9c, 0xad, 0x9c, 0xd1, 0xc6, 0xbc, 0x36, 0x5c, + 0x3b, 0xe3, 0x2e, 0x66, 0x29, 0x0c, 0x3a, 0x3d, 0xe7, 0xe3, 0xf3, 0x58, + 0x70, 0x3e, 0x59, 0xb2, 0x6c, 0x91, 0x14, 0xfe, 0x9e, 0x5e, 0x5d, 0xb2, + 0x7b, 0x46, 0x66, 0x46, 0x55, 0xe2, 0x78, 0x47, 0xeb, 0xdf, 0x2b, 0xb4, + 0xf2, 0xb2, 0x14, 0xbe, 0x64, 0x9e, 0x17, 0x16, 0x9f, 0xf5, 0x6a, 0xdd, + 0x25, 0xa1, 0x55, 0x6e, 0xb1, 0xfa, 0x09, 0xd0, 0x97, 0x7c, 0x13, 0xde, + 0x1d, 0xd4, 0x94, 0x19, 0xde, 0x8b, 0x4d, 0xe7, 0xee, 0x1f, 0xdf, 0xe5, + 0x3b, 0xdd, 0xbd, 0x13, 0x9c, 0xec, 0xcd, 0xb6, 0xb6, 0xbb, 0x3f, 0xbd, + 0x54, 0xca, 0x47, 0x5c, 0x05, 0x3c, 0x03, 0x30, 0x9d, 0x56, 0xf6, 0xc6, + 0x48, 0x6b, 0x74, 0x49, 0x58, 0xa2, 0xd8, 0x45, 0x42, 0x6f, 0xe4, 0x46, + 0x27, 0x92, 0x83, 0x78, 0x97, 0x55, 0x5b, 0x82, 0xce, 0x2a, 0x08, 0x41, + 0xb9, 0x7a, 0x66, 0x0f, 0x3c, 0x5b, 0xdf, 0x8d, 0x1d, 0x02, 0x11, 0xa4, + 0xa7, 0x0a, 0x80, 0x1e, 0xbb, 0x7a, 0xc9, 0x2f, 0xb9, 0x35, 0xc8, 0xd7, + 0x98, 0x04, 0x29, 0xaa, 0x4b, 0x88, 0x66, 0x73, 0xe4, 0x59, 0xc4, 0x3e, + 0x50, 0xad, 0xe5, 0x64, 0x54, 0xf0, 0x29, 0x38, 0xee, 0xc0, 0x00, 0xc4, + 0x22, 0x16, 0xf2, 0xc5, 0x46, 0x5c, 0xee, 0x9e, 0xf2, 0x9a, 0xe7, 0xfd, + 0x62, 0x50, 0xa2, 0xeb, 0x47, 0x56, 0x4c, 0xe4, 0x75, 0x46, 0xe4, 0xd5, + 0x25, 0xec, 0xe0, 0x35, 0x33, 0x31, 0x34, 0x1b, 0xcb, 0x72, 0x78, 0x1c, + 0x4d, 0x3a, 0x19, 0x2e, 0xc4, 0xb7, 0xa4, 0x80, 0xd2, 0x91, 0xeb, 0x2a, + 0x1d, 0xf2, 0xd1, 0xa3, 0xae, 0xac, 0x41, 0xae, 0xc2, 0x44, 0xd2, 0x3f, + 0xb4, 0x87, 0x8d, 0x69, 0x6c, 0x67, 0xd6, 0x85, 0xee, 0xd6, 0x3b, 0x03, + 0xdc, 0x58, 0x46, 0x07, 0x73, 0xb4, 0xb0, 0x3f, 0x5e, 0xc1, 0x13, 0x2c, + 0x36, 0x58, 0xd0, 0x1c, 0x34, 0x3e, 0x01, 0x88, 0xfa, 0xb1, 0x9a, 0x03, + 0x85, 0x4f, 0x4c, 0xd2, 0xac, 0xd9, 0x12, 0x09, 0xaa, 0x5f, 0x20, 0x06, + 0x1f, 0x0a, 0x44, 0x28, 0x50, 0xd1, 0x8f, 0x51, 0x8a, 0x1d, 0xfa, 0xaa, + 0x46, 0x33, 0xac, 0x0c, 0xb3, 0x10, 0xcf, 0x24, 0x4d, 0x0f, 0xcd, 0xee, + 0xd9, 0x64, 0x4a, 0x1a, 0x84, 0x0f, 0xff, 0x48, 0x8d, 0x79, 0xd4, 0x43, + 0x70, 0x1c, 0x7e, 0x7e, 0x12, 0x43, 0x51, 0x4a, 0x7e, 0x45, 0x9e, 0xa4, + 0x3c, 0x12, 0xbd, 0x95, 0xe9, 0xd6, 0xd4, 0x3f, 0xbf, 0x03, 0xae, 0x9e, + 0x24, 0x1a, 0x36, 0xbd, 0xea, 0x5d, 0x65, 0xff, 0x9f, 0x95, 0x70, 0xda, + 0xb0, 0x53, 0x6a, 0x5f, 0x64, 0x7b, 0xb6, 0x7a, 0x8d, 0xa2, 0xd4, 0x9c, + 0xb1, 0xf9, 0xe6, 0x14, 0x62, 0x3b, 0xe7, 0x5b, 0x40, 0x9d, 0xf4, 0x19, + 0xb5, 0x50, 0xc8, 0xbd, 0x76, 0xd3, 0xbc, 0x0e, 0x6d, 0x62, 0x91, 0x73, + 0x3e, 0x7f, 0xbf, 0xd0, 0xf0, 0x33, 0xf8, 0x6a, 0x9f, 0xa6, 0xad, 0xc3, + 0xa0, 0x8f, 0x45, 0x99, 0x86, 0xa7, 0x49, 0x18, 0x8a, 0xed, 0xf1, 0x7d, + 0x39, 0xf4, 0xb4, 0xf9, 0x82, 0x62, 0xd0, 0xa1, 0xb8, 0x3f, 0xe8, 0x25, + 0xf7, 0xb1, 0x59, 0xce, 0x31, 0xba, 0x1d, 0x0b, 0x1f, 0x3d, 0x6c, 0x8b, + 0xd2, 0xc5, 0x4e, 0x8e, 0xe8, 0x09, 0x9e, 0x1f, 0xf3, 0x67, 0x6f, 0x09, + 0x03, 0x9d, 0xfe, 0x57, 0x6d, 0x9b, 0xce, 0x99, 0x7b, 0x01, 0x04, 0x52, + 0xf5, 0x41, 0x7e, 0x38, 0x56, 0xb8, 0x71, 0x44, 0x43, 0x2c, 0x5e, 0x92, + 0x9d, 0x95, 0xff, 0x0b, 0xf8, 0xfa, 0x89, 0x2c, 0x58, 0xde, 0xc5, 0x4e, + 0x02, 0xe3, 0x82, 0xf7, 0xdc, 0x92, 0xa8, 0x7c, 0x39, 0x32, 0x76, 0x68, + 0x9c, 0x73, 0x75, 0x1f, 0xbc, 0x6b, 0x46, 0x33, 0x5a, 0xdb, 0x94, 0x8c, + 0x76, 0x79, 0x7e, 0x9b, 0xcc, 0x37, 0xeb, 0xed, 0xdc, 0xd5, 0xee, 0x2b, + 0x30, 0x3f, 0x7b, 0x9b, 0xac, 0x38, 0x8f, 0xf1, 0x5e, 0xec, 0xa0, 0x46, + 0x2c, 0xd1, 0x27, 0x19, 0x60, 0xec, 0xe2, 0xa7, 0x45, 0x61, 0x2d, 0xa8, + 0x7e, 0xa9, 0xf8, 0x93, 0xa4, 0x23, 0x3e, 0xd8, 0x9c, 0xcc, 0xb3, 0xee, + 0xc3, 0x1c, 0xfb, 0xbb, 0xad, 0xec, 0x73, 0x66, 0x31, 0x5d, 0x88, 0x9a, + 0xec, 0x84, 0x91, 0x1e, 0x58, 0xdd, 0xb0, 0x01, 0x46, 0x18, 0x43, 0x64, + 0xe2, 0xad, 0xac, 0x5a, 0x63, 0x4c, 0x32, 0x6b, 0xfd, 0xff, 0x66, 0x6d, + 0xb4, 0x66, 0x88, 0xec, 0xfe, 0x23, 0xaa, 0x3a, 0x2a, 0xd5, 0xff, 0xed, + 0x3a, 0x13, 0x9a, 0xae, 0x73, 0xc5, 0x62, 0x32, 0x47, 0x89, 0x19, 0x7f, + 0x2c, 0x88, 0x62, 0x34, 0xc2, 0x90, 0xa9, 0x59, 0x7c, 0x45, 0xdb, 0x98, + 0xaf, 0xf4, 0xba, 0x4e, 0x45, 0x55, 0xfc, 0x70, 0xa9, 0xfd, 0xb4, 0xa3, + 0xd9, 0xa8, 0xfb, 0xe2, 0xe6, 0xf9, 0x60, 0xc1, 0x42, 0x70, 0x3d, 0xa5, + 0x28, 0xcc, 0xd3, 0x54, 0x87, 0xda, 0x93, 0x91, 0x42, 0xa8, 0x8b, 0x62, + 0xf3, 0x4e, 0xb7, 0x86, 0xfa, 0x52, 0x19, 0x69, 0xe3, 0x6c, 0xd1, 0xc3, + 0x23, 0x82, 0xf7, 0x1d, 0xa1, 0x80, 0x92, 0xcd, 0x5e, 0x1a, 0x62, 0x3e, + 0x1b, 0x31, 0x9d, 0x0d, 0xa8, 0x25, 0x3e, 0x83, 0xae, 0x36, 0xce, 0xfd, + 0xac, 0xf7, 0x35, 0x7f, 0x74, 0xf4, 0x66, 0xa3, 0x5f, 0x00, 0xe5, 0x30, + 0xc1, 0x11, 0x70, 0x00, 0xb5, 0xd9, 0xd4, 0x6e, 0x95, 0xc4, 0xbc, 0x5b, + 0x7d, 0x62, 0x6c, 0xd5, 0xc0, 0x1e, 0x81, 0xc0, 0x61, 0x69, 0x13, 0x63, + 0xbc, 0x7f, 0x70, 0x3f, 0x3d, 0x96, 0x18, 0x39, 0xef, 0x51, 0xc6, 0xe9, + 0xcc, 0x59, 0xda, 0xc7, 0x5d, 0xb5, 0x59, 0xb0, 0xf2, 0x99, 0x5a, 0x36, + 0x21, 0x0d, 0xcc, 0x97, 0x16, 0x2b, 0x61, 0x3d, 0x0a, 0xd1, 0x6e, 0x05, + 0x86, 0x42, 0xff, 0xd8, 0xa7, 0x5c, 0x02, 0xcf, 0x90, 0x6b, 0x4e, 0xee, + 0x4e, 0xca, 0xdb, 0xd3, 0xfe, 0x7e, 0x9b, 0xe2, 0xf0, 0xa3, 0x45, 0x6d, + 0xa9, 0x92, 0xba, 0xce, 0xc6, 0x2e, 0x0a, 0xbc, 0xb2, 0x7a, 0x57, 0x07, + 0x33, 0xc2, 0xa7, 0x16, 0x25, 0x06, 0x36, 0x83, 0x35, 0x31, 0x87, 0x18, + 0x83, 0xa3, 0xc2, 0x88, 0x55, 0xcc, 0xe4, 0x84, 0x4c, 0xce, 0xb9, 0xeb, + 0xd5, 0xb2, 0xbe, 0x3d, 0x76, 0x85, 0x10, 0x07, 0x83, 0xfa, 0x1c, 0x42, + 0xbc, 0xa3, 0x4c, 0x29, 0x49, 0xe6, 0xc0, 0x30, 0x59, 0xe0, 0xc6, 0xbe, + 0xa7, 0x48, 0x4a, 0xcf, 0x0e, 0x8e, 0xb7, 0x38, 0xf2, 0xa6, 0x26, 0xd3, + 0x88, 0x06, 0x99, 0x46, 0x19, 0x65, 0x1c, 0x91, 0x8e, 0xae, 0x90, 0x78, + 0x77, 0x7f, 0xe0, 0xc2, 0x51, 0x6f, 0xb6, 0x44, 0x15, 0xf9, 0xc5, 0x8a, + 0x6c, 0x33, 0xd5, 0x90, 0x17, 0xc2, 0xca, 0x4e, 0xe1, 0x1f, 0xef, 0x02, + 0x43, 0x05, 0x3f, 0x1e, 0xb1, 0x13, 0x23, 0x1f, 0xd6, 0xc2, 0xac, 0xc4, + 0x49, 0x7a, 0x86, 0x06, 0x4b, 0xa1, 0x55, 0x6a, 0x75, 0x91, 0x4e, 0x6b, + 0x86, 0x95, 0xa7, 0xbc, 0xdc, 0x64, 0xdb, 0x81, 0xc6, 0xa5, 0x33, 0x38, + 0x98, 0xbb, 0xac, 0x03, 0xf0, 0xba, 0x49, 0xcf, 0x1c, 0xce, 0xe2, 0x3d, + 0xe5, 0x06, 0xbc, 0x5e, 0xd0, 0xf7, 0x1c, 0xbb, 0x52, 0xa1, 0x47, 0x98, + 0x12, 0xef, 0x1c, 0xb9, 0x53, 0xec, 0x67, 0x2c, 0xf0, 0x7d, 0x85, 0x9e, + 0x45, 0x87, 0x00, 0x67, 0x2f, 0xa5, 0x19, 0x9f, 0x3e, 0x20, 0x8c, 0xe9, + 0xfa, 0x8a, 0xd8, 0x02, 0x6e, 0x16, 0xc4, 0x43, 0xff, 0x08, 0x3f, 0xf3, + 0x76, 0x53, 0x95, 0x17, 0x6e, 0x74, 0xfe, 0x7e, 0x87, 0x66, 0xc9, 0xe8, + 0x8d, 0x21, 0xea, 0xd2, 0x4d, 0xc7, 0x9c, 0x5a, 0xef, 0xd5, 0xe1, 0x12, + 0x85, 0x22, 0x40, 0x3c, 0x9d, 0x89, 0x4f, 0x12, 0xb5, 0x01, 0x95, 0x0e, + 0x9b, 0xd3, 0x38, 0x5e, 0x21, 0x5a, 0x4e, 0x7e, 0xce, 0xf7, 0xa6, 0x5a, + 0x63, 0x78, 0x40, 0xba, 0x9f, 0x29, 0xf0, 0x75, 0xb6, 0x8b, 0xd9, 0x4c, + 0xab, 0xb9, 0xf4, 0xe9, 0x1f, 0x39, 0x01, 0xb3, 0xfc, 0x2c, 0xa4, 0x74, + 0xa9, 0xa9, 0x90, 0xed, 0x77, 0xd8, 0x0c, 0x6d, 0x5c, 0x7b, 0xfc, 0xbd, + 0x96, 0x96, 0xcb, 0x9b, 0x9f, 0x88, 0x86, 0x5c, 0x3c, 0x0a, 0xde, 0x28, + 0x7c, 0xf0, 0x91, 0x1c, 0x06, 0x52, 0xbe, 0xad, 0xc8, 0xef, 0xa5, 0xd3, + 0x1e, 0x29, 0xbd, 0x1d, 0xd5, 0xba, 0xf4, 0x83, 0x2d, 0x36, 0x9a, 0x8c, + 0x8d, 0x83, 0xac, 0x3f, 0xea, 0xd2, 0x2e, 0xfb, 0xf1, 0xaa, 0x7a, 0x2e, + 0xce, 0xd3, 0x90, 0x9f, 0x3c, 0x2c, 0xee, 0xed, 0xf8, 0xfc, 0x3c, 0x0e, + 0x5f, 0xd1, 0xda, 0x9c, 0x32, 0x52, 0xcd, 0x09, 0xa1, 0x53, 0x33, 0x37, + 0xe0, 0x37, 0x95, 0xb2, 0x8d, 0x03, 0x46, 0x1f, 0xb5, 0x99, 0x65, 0x54, + 0x61, 0xa2, 0xdc, 0xe9, 0x87, 0x4d, 0x41, 0xdf, 0xd1, 0xb5, 0x2c, 0x7a, + 0x46, 0x08, 0x5e, 0x0f, 0xcc, 0x80, 0x96, 0x52, 0x98, 0xa0, 0x82, 0x52, + 0x6d, 0x62, 0x6f, 0xd9, 0x48, 0xc1, 0x36, 0x0c, 0x5c, 0x7f, 0xad, 0x2c, + 0x27, 0xcf, 0x17, 0xee, 0xfa, 0xca, 0x14, 0xe7, 0x88, 0xc4, 0x20, 0xb2, + 0xa1, 0xd2, 0x66, 0xe8, 0x81, 0xce, 0x35, 0x2b, 0x30, 0x54, 0x16, 0x9e, + 0x42, 0x77, 0x16, 0x3b, 0x84, 0x77, 0x42, 0x71, 0x33, 0xf8, 0x62, 0x9e, + 0xd4, 0x1d, 0x1d, 0xf3, 0x91, 0x60, 0x97, 0xd8, 0x10, 0x29, 0xc8, 0xf9, + 0xfa, 0xca, 0x0a, 0xe9, 0x50, 0xe1, 0xcc, 0xa7, 0xe3, 0x77, 0xc2, 0x93, + 0x68, 0x50, 0x1a, 0x98, 0xd7, 0x68, 0x40, 0x80, 0x12, 0x64, 0xa7, 0x1d, + 0xb4, 0x52, 0x85, 0x7b, 0x0e, 0x85, 0x0a, 0x59, 0x6a, 0xc8, 0xe4, 0x4b, + 0xff, 0xd7, 0x0d, 0x7d, 0x9e, 0xef, 0x07, 0x2f, 0x6d, 0x46, 0x05, 0xf9, + 0x05, 0xb1, 0x97, 0x94, 0x23, 0xc5, 0x2a, 0x99, 0xcc, 0x9c, 0xc2, 0x82, + 0x97, 0xbc, 0x24, 0x9b, 0xe4, 0xf2, 0xb3, 0x12, 0x84, 0xa0, 0x2a, 0xc4, + 0x7d, 0x29, 0x4d, 0xa4, 0x97, 0xd0, 0x85, 0xa6, 0x39, 0x18, 0xd2, 0xfb, + 0xa7, 0x08, 0x53, 0x75, 0x6b, 0xbd, 0xe3, 0x98, 0x4c, 0x94, 0xdd, 0xd4, + 0x86, 0x94, 0xc2, 0x6a, 0x14, 0x23, 0xdd, 0x69, 0xae, 0x53, 0xec, 0x83, + 0x58, 0x8e, 0x87, 0x7b, 0xf1, 0xcf, 0xff, 0x34, 0xda, 0x39, 0x67, 0xba, + 0x90, 0xc5, 0xec, 0xe0, 0xb3, 0xad, 0xad, 0x3d, 0x4c, 0x8e, 0x3f, 0x08, + 0x62, 0x80, 0x5b, 0x2d, 0xf8, 0xe1, 0x67, 0x61, 0x79, 0xf5, 0xc9, 0xbe, + 0x74, 0x1b, 0x72, 0x02, 0x56, 0xc6, 0xf8, 0xd5, 0x87, 0x3a, 0x08, 0x7b, + 0x35, 0x8f, 0xdf, 0xdf, 0x87, 0x3e, 0x09, 0xf7, 0xd2, 0x74, 0xbb, 0xec, + 0x8c, 0x49, 0x0c, 0xb5, 0x3a, 0x6b, 0x33, 0x43, 0x52, 0xe2, 0x2f, 0x71, + 0x3e, 0x6f, 0x59, 0x52, 0x50, 0x8f, 0xdb, 0xa6, 0x52, 0xa7, 0x5d, 0xda, + 0x16, 0x71, 0xb2, 0x52, 0xd7, 0x3e, 0x2d, 0xf6, 0x98, 0x53, 0x0f, 0x8f, + 0xc1, 0x79, 0xd0, 0xcf, 0xe0, 0xc8, 0x22, 0x27, 0x41, 0x14, 0xe8, 0xb8, + 0xed, 0x65, 0x3c, 0xaa, 0x11, 0x72, 0x41, 0xa8, 0xd8, 0x0b, 0x35, 0x81, + 0xec, 0xa6, 0x12, 0x30, 0x23, 0x0b, 0x71, 0x7a, 0x28, 0xd9, 0x01, 0x82, + 0x35, 0xd1, 0x64, 0x6d, 0xf3, 0x63, 0x69, 0x78, 0xb4, 0x93, 0x1e, 0x05, + 0xc9, 0xb3, 0xbc, 0xb6, 0xc4, 0x5e, 0xb6, 0x2a, 0x6e, 0xec, 0x91, 0x4a, + 0x5c, 0xa2, 0x5c, 0xea, 0x2b, 0xe3, 0x33, 0x1a, 0xb3, 0x70, 0xd5, 0x39, + 0x77, 0x3e, 0xa2, 0x96, 0xd5, 0x10, 0x75, 0x8a, 0x91, 0xc6, 0xbc, 0xb6, + 0x86, 0xa6, 0x8f, 0xd3, 0x50, 0x09, 0xa3, 0x9a, 0x1f, 0xd0, 0xd7, 0xd7, + 0x23, 0xa0, 0x32, 0xd0, 0x69, 0x33, 0x2f, 0x18, 0xf2, 0x6f, 0xe2, 0xbc, + 0x2f, 0x7f, 0xf5, 0x46, 0x81, 0x2e, 0xad, 0x14, 0xc9, 0x57, 0x10, 0xa4, + 0x71, 0xa9, 0xa4, 0x05, 0x50, 0xcb, 0x93, 0xc7, 0x53, 0x84, 0x68, 0xa5, + 0x7c, 0x65, 0xc0, 0xe0, 0x37, 0xd6, 0xc3, 0xbb, 0x36, 0xef, 0x22, 0x9e, + 0x09, 0x32, 0xa5, 0xa6, 0x73, 0x61, 0xb6, 0x3c, 0x5a, 0xbe, 0x2f, 0x63, + 0x01, 0x35, 0xfe, 0xd8, 0x98, 0xd5, 0x7e, 0xfd, 0x68, 0xd8, 0x96, 0x51, + 0x6e, 0x3a, 0x17, 0x90, 0x16, 0xeb, 0x03, 0xfa, 0x0a, 0x83, 0x1a, 0xc9, + 0x48, 0x14, 0x31, 0x32, 0x07, 0x7d, 0xa8, 0xa8, 0x64, 0xd8, 0xba, 0xcf, + 0x87, 0xc5, 0x0e, 0xc3, 0x1c, 0x5b, 0xfe, 0x31, 0x98, 0xea, 0x25, 0x29, + 0x9c, 0x77, 0xf2, 0x9f, 0x5e, 0x16, 0x11, 0x6b, 0x29, 0x08, 0xab, 0xb0, + 0x57, 0xd8, 0x3d, 0x85, 0xdc, 0x3b, 0x69, 0xea, 0xd5, 0xe6, 0x90, 0xfa, + 0x95, 0x8d, 0xcc, 0x3c, 0x2d, 0x86, 0x07, 0xc6, 0x7e, 0x8d, 0xc4, 0x7a, + 0x3a, 0xcd, 0x61, 0xa4, 0x1f, 0xd9, 0x6f, 0x07, 0xa3, 0x45, 0xe8, 0x41, + 0xed, 0x51, 0x14, 0xe4, 0x3d, 0x20, 0x3b, 0x11, 0x9e, 0x93, 0xc3, 0x2e, + 0xcd, 0x29, 0x85, 0xf0, 0x61, 0x68, 0x8e, 0x19, 0xdc, 0x20, 0x0a, 0xbd, + 0xc0, 0x15, 0x90, 0x08, 0x96, 0xcf, 0x9b, 0xf3, 0xb5, 0x7b, 0xe4, 0x9a, + 0x97, 0x22, 0x93, 0x40, 0xd4, 0xde, 0x7a, 0x6e, 0x6b, 0xc4, 0x16, 0x9e, + 0x1c, 0x98, 0x9b, 0x83, 0x6e, 0x4d, 0xde, 0x11, 0x4f, 0x22, 0xed, 0x2d, + 0xe1, 0xb3, 0xfa, 0x86, 0xb0, 0xd2, 0x53, 0xd2, 0x34, 0x8a, 0x58, 0xdc, + 0x8c, 0xd9, 0x60, 0xd3, 0x46, 0x0a, 0xde, 0x48, 0xa3, 0xda, 0x5b, 0x74, + 0x3e, 0x4c, 0x51, 0xa6, 0x02, 0x20, 0xc6, 0x0d, 0xdb, 0x13, 0x42, 0xad, + 0xc6, 0x90, 0xb1, 0xe0, 0xb0, 0xac, 0xdc, 0xa7, 0x48, 0xf8, 0x2d, 0x8f, + 0xd7, 0xd9, 0x10, 0xeb, 0xd8, 0xdb, 0xf0, 0x53, 0x67, 0xa9, 0x03, 0x3e, + 0x97, 0xbf, 0xe6, 0xc3, 0xa8, 0x87, 0x3a, 0x91, 0xb8, 0xcf, 0x88, 0x5b, + 0x0d, 0x06, 0xe1, 0xe2, 0x39, 0x74, 0xc8, 0x59, 0xe0, 0x90, 0x9f, 0xc9, + 0x0a, 0x74, 0xa3, 0xb2, 0xae, 0x69, 0x79, 0xfa, 0x0d, 0xf2, 0xee, 0xde, + 0xec, 0x88, 0xbf, 0x09, 0x54, 0xd6, 0xbe, 0xbb, 0x25, 0x91, 0xe4, 0x66, + 0xd2, 0x08, 0x78, 0xda, 0x9d, 0x07, 0xc3, 0x0b, 0x3f, 0x1a, 0xd9, 0xf4, + 0xb2, 0x2d, 0x69, 0x74, 0xb1, 0x78, 0x5f, 0xc1, 0xaf, 0x7f, 0x6d, 0x17, + 0xfc, 0x2c, 0x67, 0x62, 0xce, 0xb4, 0x41, 0x6e, 0x21, 0x4b, 0x5c, 0x77, + 0xa1, 0x1f, 0xfe, 0xe6, 0x28, 0xc8, 0x52, 0xd1, 0x8e, 0x66, 0x88, 0x65, + 0x0c, 0x58, 0xec, 0x1c, 0x71, 0x4c, 0x8a, 0xc0, 0xef, 0x3e, 0x34, 0xf7, + 0x90, 0x67, 0x28, 0x16, 0x20, 0x3a, 0x2c, 0x3f, 0x51, 0x53, 0x15, 0x1c, + 0x6c, 0x75, 0x0e, 0xe1, 0xb4, 0xf3, 0x7f, 0x60, 0x3a, 0x81, 0x34, 0x82, + 0x51, 0x5e, 0x75, 0xb0, 0x5c, 0x37, 0x87, 0x2d, 0xd5, 0xc5, 0x2c, 0xab, + 0x33, 0x8a, 0x60, 0x49, 0x2c, 0xde, 0x90, 0x12, 0x11, 0x1f, 0x4b, 0x27, + 0x15, 0x92, 0xa2, 0xf1, 0x1a, 0xde, 0x35, 0x34, 0x4d, 0x52, 0xcd, 0xc0, + 0x71, 0x46, 0x7f, 0x3e, 0x21, 0x92, 0x5f, 0xc8, 0x25, 0xd4, 0x2c, 0xf4, + 0xd9, 0x38, 0xde, 0xa5, 0xae, 0x83, 0xe3, 0x50, 0x9b, 0x1b, 0xad, 0x4b, + 0xd8, 0x3f, 0x0a, 0x23, 0x40, 0x1e, 0x46, 0x7a, 0x71, 0x06, 0xac, 0x9e, + 0x06, 0xb8, 0x96, 0xef, 0x07, 0xef, 0x38, 0xe9, 0x79, 0xaa, 0x64, 0x44, + 0xa9, 0xa3, 0xc5, 0x1d, 0x5d, 0xd3, 0xa7, 0x01, 0xef, 0xf6, 0x3b, 0x15, + 0x00, 0x0c, 0xf7, 0x59, 0x4a, 0x1c, 0x12, 0x20, 0x89, 0xa8, 0x4e, 0x7b, + 0xf8, 0x9d, 0x02, 0xa6, 0x5e, 0x19, 0x7e, 0xb8, 0x5f, 0x46, 0xd9, 0xb1, + 0xbe, 0x25, 0x2c, 0x3c, 0xe7, 0x5d, 0x3b, 0x3f, 0x6f, 0x6e, 0x94, 0x83, + 0xc3, 0x8e, 0x85, 0x65, 0xff, 0xe9, 0x8e, 0x32, 0xcc, 0x68, 0x51, 0x14, + 0xbf, 0x94, 0x21, 0x3f, 0x85, 0xa8, 0x76, 0x44, 0xe6, 0xca, 0x20, 0x84, + 0xec, 0x83, 0x84, 0x64, 0xfb, 0x80, 0x01, 0x73, 0x76, 0x21, 0xd3, 0xf0, + 0x7b, 0x74, 0x5c, 0xbf, 0x71, 0xe6, 0x34, 0xff, 0x58, 0xe8, 0x6f, 0x88, + 0xa6, 0xad, 0xcf, 0x93, 0x2a, 0xc5, 0xc5, 0x23, 0x32, 0xc8, 0xec, 0xbd, + 0xf9, 0x54, 0x3d, 0xda, 0xe4, 0x81, 0x74, 0x94, 0xbf, 0x36, 0x72, 0x11, + 0xf0, 0x8a, 0x8f, 0x1b, 0x55, 0x47, 0x70, 0x7d, 0x61, 0xf0, 0x7b, 0x11, + 0x56, 0xdb, 0xbc, 0xe5, 0x72, 0xf2, 0xbd, 0x0b, 0xa0, 0x80, 0x03, 0x1a, + 0xc6, 0xe9, 0xfc, 0xcd, 0xde, 0x42, 0xae, 0x1a, 0x7d, 0x90, 0x5d, 0x21, + 0x5b, 0x3d, 0x69, 0x6f, 0x42, 0x42, 0xf2, 0x8a, 0xc8, 0xfc, 0xb9, 0xa9, + 0xdf, 0x18, 0xc4, 0x97, 0x91, 0x21, 0x28, 0xfd, 0x82, 0x8a, 0xe7, 0xac, + 0xe5, 0x5d, 0x33, 0x7b, 0x78, 0x0a, 0x48, 0x43, 0xfe, 0xfe, 0xcf, 0x09, + 0x5f, 0xed, 0x18, 0x33, 0x0c, 0xab, 0x8a, 0x5d, 0x63, 0xd5, 0x43, 0x0b, + 0xde, 0x75, 0x56, 0xef, 0x11, 0x05, 0x8c, 0xbb, 0xc0, 0x10, 0x4e, 0x85, + 0x70, 0xe1, 0x7e, 0x62, 0xb6, 0x3a, 0x84, 0x80, 0x17, 0xab, 0x38, 0x59, + 0x0b, 0xe2, 0xb1, 0x31, 0xb8, 0xb5, 0xf5, 0xad, 0xf6, 0xbf, 0x5b, 0xfb, + 0x69, 0xc8, 0xb3, 0xce, 0x65, 0xd4, 0x8e, 0x04, 0xc5, 0xc4, 0x09, 0xba, + 0x36, 0xc9, 0x90, 0xe0, 0xc2, 0x21, 0x3a, 0x94, 0x83, 0xa5, 0xd1, 0xb2, + 0xe1, 0xae, 0x6a, 0x28, 0x22, 0x59, 0x79, 0x72, 0x82, 0x42, 0x89, 0x42, + 0x9c, 0xc3, 0xdf, 0x8d, 0x15, 0x22, 0x14, 0xb3, 0xfd, 0x2a, 0x85, 0xbe, + 0xd3, 0x12, 0xa5, 0x3b, 0x0c, 0x99, 0xb2, 0xe5, 0x43, 0x8d, 0xd7, 0xc0, + 0xa1, 0xb6, 0xb2, 0xae, 0x42, 0x4a, 0xc0, 0xe5, 0x09, 0xa2, 0xf6, 0xa4, + 0xbc, 0x01, 0xee, 0x94, 0xd2, 0x0b, 0xeb, 0x28, 0x80, 0xc9, 0x7a, 0x07, + 0xd7, 0x4b, 0xee, 0x01, 0x10, 0x48, 0xcc, 0xc6, 0x03, 0x99, 0x9d, 0x67, + 0x2a, 0xbd, 0xa0, 0x6f, 0x51, 0xa4, 0x75, 0x50, 0xe1, 0x84, 0x8e, 0xda, + 0x7b, 0x5e, 0x9e, 0x78, 0x18, 0x2a, 0x6b, 0xfa, 0xef, 0x87, 0x81, 0xe9, + 0x48, 0x3f, 0x29, 0x2d, 0xfb, 0x15, 0xd2, 0x15, 0xb5, 0x5c, 0xed, 0x45, + 0x48, 0x30, 0xec, 0x00, 0x55, 0x15, 0x13, 0xc7, 0x11, 0xc4, 0x29, 0xef, + 0x0f, 0xa8, 0xa6, 0xef, 0x19, 0x41, 0xc2, 0xb6, 0x11, 0xdc, 0xe8, 0xf4, + 0xa7, 0x03, 0x80, 0x2d, 0x92, 0xad, 0x7e, 0x7e, 0x8a, 0x71, 0xa4, 0x6c, + 0x16, 0xb9, 0x84, 0xf5, 0x8d, 0x94, 0xc5, 0xd5, 0x82, 0x29, 0x42, 0x22, + 0x1f, 0x06, 0xca, 0xdd, 0xbf, 0x74, 0x0f, 0x14, 0x79, 0x26, 0x9c, 0x79, + 0x30, 0xcb, 0x01, 0x02, 0x76, 0x22, 0x4f, 0x54, 0xff, 0x49, 0xa3, 0x03, + 0x35, 0x23, 0x45, 0x91, 0xac, 0xed, 0x13, 0x31, 0xa4, 0x4e, 0x51, 0xe8, + 0x9c, 0x5b, 0xe4, 0xcf, 0x41, 0xd3, 0xa0, 0x86, 0x7f, 0x3a, 0x4d, 0xaf, + 0xa7, 0x49, 0x63, 0x47, 0x86, 0x08, 0x88, 0xcf, 0x01, 0x7a, 0xc4, 0xf5, + 0x29, 0x67, 0x8a, 0xd4, 0xdd, 0x6a, 0x6d, 0x81, 0xb8, 0x29, 0x9d, 0x7c, + 0x32, 0x4e, 0x8f, 0x0c, 0x9f, 0x8c, 0x7e, 0x76, 0xa3, 0xd4, 0x32, 0x80, + 0xd0, 0x79, 0x7d, 0x56, 0x99, 0x6d, 0x0b, 0x88, 0xfc, 0x98, 0xdb, 0xaf, + 0x13, 0xf3, 0xb2, 0x20, 0x3f, 0x19, 0xe1, 0x83, 0x70, 0xd2, 0x26, 0xd0, + 0xd2, 0xad, 0x11, 0xeb, 0x3b, 0x31, 0x03, 0x55, 0x62, 0xca, 0xb5, 0x87, + 0x31, 0x7a, 0x11, 0x4c, 0xf2, 0xc3, 0xc2, 0x1c, 0x42, 0x94, 0x7b, 0xe6, + 0x29, 0x86, 0x70, 0x8e, 0x51, 0x4a, 0xa3, 0xf2, 0xf0, 0xed, 0xa1, 0xc6, + 0x18, 0xff, 0xf2, 0xff, 0xe0, 0x07, 0x85, 0xf1, 0x93, 0x5a, 0x83, 0x1c, + 0x4c, 0xa9, 0x9b, 0xc5, 0x0c, 0xc4, 0xf0, 0xde, 0x71, 0x93, 0x78, 0xd1, + 0x3b, 0xcc, 0x5b, 0x51, 0x1f, 0xd7, 0x21, 0x12, 0x57, 0xd5, 0x2a, 0xea, + 0x64, 0x08, 0x0e, 0xf0, 0x3d, 0x42, 0xe7, 0xdf, 0xc8, 0xea, 0x42, 0x2b, + 0x41, 0x55, 0x85, 0xb8, 0x54, 0xa4, 0xc9, 0x3f, 0xce, 0xfc, 0x1a, 0xde, + 0x73, 0x08, 0xaa, 0x09, 0x25, 0x08, 0xa0, 0xdc, 0x64, 0xb7, 0xe7, 0xcc, + 0xde, 0x85, 0xa6, 0xc3, 0xe9, 0xe1, 0x43, 0x71, 0x86, 0x05, 0x55, 0x86, + 0x47, 0xf8, 0x71, 0xbd, 0xf5, 0xd7, 0x38, 0x64, 0x7f, 0x71, 0x63, 0xe1, + 0x22, 0x39, 0x99, 0xc3, 0xdf, 0x27, 0x5d, 0xdd, 0xd0, 0x57, 0x99, 0xd5, + 0x97, 0xcd, 0xd4, 0x2e, 0xc1, 0x25, 0x3d, 0x2e, 0x03, 0x0b, 0x04, 0x20, + 0x70, 0xec, 0x46, 0x6c, 0x4b, 0x55, 0x16, 0x02, 0x00, 0x71, 0xfd, 0x8a, + 0xa0, 0x1e, 0x5f, 0x41, 0xe6, 0x96, 0x58, 0xbe, 0x02, 0x73, 0x91, 0x71, + 0xb2, 0x7e, 0xc4, 0xcd, 0xce, 0xa5, 0x26, 0xee, 0xff, 0x8c, 0x9a, 0x4c, + 0xf4, 0x0a, 0x89, 0xba, 0x14, 0x6e, 0x06, 0x86, 0xb0, 0xba, 0x41, 0xdd, + 0x27, 0xf8, 0xc3, 0x46, 0x4f, 0x39, 0xac, 0x2c, 0x8a, 0x69, 0x09, 0xb7, + 0x36, 0x0f, 0xe0, 0x8d, 0x31, 0x0f, 0xc3, 0xee, 0x3a, 0x6a, 0x9e, 0x96, + 0x91, 0xf5, 0x6a, 0x12, 0x98, 0x5a, 0xc3, 0xf3, 0xb8, 0x9b, 0x07, 0xdb, + 0x8e, 0x2a, 0xb0, 0x91, 0x86, 0xb5, 0xc7, 0xe9, 0x06, 0xe1, 0x4e, 0x83, + 0x28, 0x3a, 0x0e, 0x67, 0xe5, 0x7e, 0x88, 0x2a, 0x31, 0xd2, 0xfe, 0xf6, + 0x19, 0x3d, 0x09, 0xd1, 0xef, 0x5d, 0xe1, 0x15, 0x2d, 0xb4, 0xec, 0x23, + 0xc2, 0x0c, 0x7a, 0xbf, 0xd3, 0x6f, 0xf7, 0x8a, 0x3b, 0x3a, 0x0f, 0x20, + 0xc4, 0x78, 0xbe, 0x46, 0x30, 0x0f, 0xc2, 0xd0, 0x8c, 0x23, 0xb7, 0xfa, + 0x3c, 0x19, 0x35, 0x53, 0x5f, 0xf9, 0x94, 0xf5, 0x23, 0xbe, 0xb3, 0x56, + 0x42, 0xa1, 0x27, 0xff, 0xac, 0xbf, 0x72, 0x7e, 0x89, 0xbe, 0xb9, 0x6d, + 0x2d, 0xc4, 0x3f, 0x6c, 0x7f, 0xc4, 0x7e, 0x01, 0x09, 0xc8, 0x35, 0x80, + 0x99, 0x8f, 0x1c, 0x43, 0xd3, 0xb2, 0x4a, 0xb7, 0x08, 0x06, 0x63, 0xcd, + 0x8a, 0x5e, 0x64, 0xa2, 0x93, 0xa5, 0x15, 0xa0, 0x38, 0xa0, 0xf2, 0x1c, + 0xab, 0xe1, 0x2d, 0x19, 0x30, 0xee, 0x9b, 0x87, 0x42, 0x54, 0xfb, 0xcc, + 0xfe, 0x2a, 0xcd, 0x54, 0xf5, 0xeb, 0x52, 0x6b, 0xd4, 0x1d, 0xa3, 0x7c, + 0xec, 0xf2, 0x56, 0x51, 0x54, 0xab, 0x66, 0xb0, 0x73, 0x49, 0x3e, 0xc4, + 0x89, 0xac, 0xb0, 0xc1, 0x41, 0x6f, 0x19, 0xd6, 0x41, 0xbd, 0xc2, 0xe2, + 0x1a, 0x56, 0xb3, 0x01, 0xc9, 0xdf, 0x46, 0xe7, 0xa1, 0x42, 0xfa, 0x1c, + 0x18, 0x86, 0xe2, 0x07, 0xe4, 0xfe, 0x19, 0x03, 0x7d, 0xc4, 0x51, 0x78, + 0x29, 0x68, 0x73, 0x70, 0x82, 0x98, 0x34, 0x2e, 0x41, 0x59, 0xd5, 0x20, + 0x36, 0xe3, 0xe5, 0x2c, 0xbe, 0x76, 0x23, 0x5d, 0xb1, 0xf0, 0xda, 0xee, + 0x65, 0x54, 0xd9, 0xa1, 0x77, 0x6e, 0xd8, 0x56, 0xcb, 0x6a, 0x35, 0xb5, + 0xaa, 0x97, 0x22, 0x28, 0x4d, 0x74, 0x13, 0x96, 0x59, 0x3d, 0x3a, 0xe2, + 0x26, 0xde, 0xd3, 0xc7, 0xed, 0x97, 0x98, 0xa8, 0x4a, 0x6b, 0x4b, 0xd1, + 0x52, 0xca, 0x84, 0xd6, 0x19, 0x7a, 0x6c, 0x0d, 0xb4, 0x28, 0x4f, 0xb1, + 0xa2, 0xcc, 0x07, 0x08, 0x57, 0xc9, 0x32, 0xd4, 0xe0, 0xef, 0x96, 0x9a, + 0x31, 0x1e, 0x68, 0x1d, 0x7b, 0x57, 0x26, 0x62, 0xa4, 0x26, 0xaf, 0xc7, + 0xd0, 0xab, 0xb6, 0x9e, 0x00, 0x6d, 0xfe, 0x29, 0x30, 0x53, 0xcd, 0xb8, + 0x4e, 0x30, 0x4e, 0xa5, 0xcc, 0xf6, 0xab, 0xca, 0x4d, 0x74, 0x40, 0xc2, + 0xb4, 0xfb, 0x3f, 0x75, 0x0a, 0x9d, 0x88, 0xa3, 0xb0, 0x5b, 0x4e, 0x88, + 0x50, 0x90, 0xcb, 0x5c, 0xcd, 0xc7, 0xff, 0x75, 0x97, 0xc4, 0x1b, 0xe9, + 0x03, 0x8a, 0xa7, 0x62, 0x32, 0x98, 0x60, 0x39, 0x56, 0xe5, 0x25, 0xed, + 0xba, 0x58, 0x67, 0xa3, 0xe8, 0x23, 0xd1, 0x55, 0xb3, 0xa5, 0xc0, 0xc9, + 0x75, 0x14, 0x91, 0xe6, 0x7d, 0x0e, 0xe3, 0xac, 0xc8, 0x6b, 0xa7, 0xdb, + 0x36, 0xe8, 0x44, 0x92, 0x72, 0xf2, 0x6d, 0x10, 0xeb, 0xd0, 0x7a, 0xdd, + 0x00, 0x9b, 0xf8, 0x65, 0xaa, 0xef, 0xed, 0xfb, 0x84, 0x5f, 0xfb, 0xd8, + 0xe9, 0xa8, 0x71, 0xab, 0x20, 0x98, 0x4f, 0x21, 0x7d, 0x33, 0xe2, 0xb1, + 0x3f, 0x95, 0x9c, 0x28, 0xf5, 0xd5, 0x83, 0x01, 0xe9, 0x71, 0x68, 0xa9, + 0x3d, 0x9e, 0x49, 0xfb, 0x6c, 0x83, 0x5f, 0x48, 0x9d, 0x91, 0x00, 0xab, + 0x54, 0x17, 0x11, 0x5b, 0x9d, 0x0a, 0x17, 0x8e, 0x3a, 0xbc, 0xd5, 0x33, + 0xcd, 0x2a, 0x5b, 0x14, 0x39, 0xe4, 0x30, 0x45, 0xde, 0x6e, 0xde, 0x92, + 0x7f, 0xb5, 0x91, 0x5d, 0x5b, 0xe4, 0x18, 0x17, 0x7c, 0x22, 0x1e, 0x2d, + 0x97, 0x8b, 0x6f, 0xe0, 0x54, 0x2e, 0x25, 0xbc, 0x5f, 0xef, 0x27, 0x1b, + 0x95, 0x71, 0xcc, 0x29, 0x96, 0x30, 0x82, 0xb1, 0x99, 0x98, 0x28, 0x36, + 0x5f, 0xd6, 0xf9, 0x13, 0xb3, 0x3d, 0x14, 0x91, 0x8a, 0x2f, 0xbf, 0x6e, + 0x8c, 0x57, 0xf6, 0x8e, 0x32, 0xf2, 0xd3, 0xa5, 0x1b, 0x2b, 0xba, 0xc8, + 0x0d, 0xa4, 0xd3, 0xc2, 0x16, 0x1f, 0x5f, 0xb6, 0x89, 0x77, 0xa9, 0xf3, + 0x7b, 0xb8, 0x11, 0x23, 0x41, 0xd6, 0xe0, 0x47, 0x3c, 0x94, 0xe0, 0xed, + 0xa9, 0xb1, 0x0e, 0x90, 0x38, 0xdd, 0x60, 0xcd, 0x75, 0x00, 0x36, 0x3a, + 0x42, 0xbb, 0xfd, 0xd7, 0xc6, 0x16, 0x38, 0xb4, 0xc0, 0x1d, 0xb6, 0x46, + 0x5c, 0x2f, 0x70, 0x95, 0x8d, 0x74, 0x68, 0xb2, 0xb5, 0xae, 0x73, 0x22, + 0xa1, 0xca, 0x5d, 0xd4, 0x28, 0x1a, 0xd2, 0x19, 0x1c, 0x43, 0x5e, 0x12, + 0x16, 0x15, 0xb4, 0x97, 0x64, 0x10, 0x07, 0x48, 0xf8, 0xe3, 0xfb, 0x3e, + 0xa5, 0x05, 0xcd, 0xc1, 0x29, 0xf0, 0x67, 0xb7, 0x24, 0x02, 0xac, 0x76, + 0x91, 0x64, 0x63, 0x46, 0xfb, 0xfd, 0xaa, 0x5b, 0x3f, 0xeb, 0xe0, 0xb2, + 0x5a, 0x8d, 0xde, 0xdc, 0x92, 0x0c, 0x1e, 0xfc, 0x82, 0x55, 0xc7, 0x8a, + 0xe3, 0x28, 0x57, 0xfe, 0x10, 0xe1, 0xa3, 0x5a, 0x9e, 0x67, 0x86, 0xf4, + 0xa5, 0xf5, 0xa0, 0xbd, 0xa4, 0x3c, 0xda, 0xf3, 0x83, 0x27, 0x2f, 0x55, + 0x73, 0xb6, 0x74, 0x3e, 0xd3, 0xc9, 0x84, 0x1d, 0xff, 0x61, 0x01, 0x56, + 0x30, 0x2a, 0x23, 0x57, 0xbc, 0x88, 0xa7, 0x2f, 0x6f, 0x95, 0x91, 0x4e, + 0x5b, 0x41, 0xd9, 0x95, 0x1f, 0x09, 0x95, 0x79, 0x36, 0xe3, 0x7f, 0xbd, + 0x4b, 0x09, 0x4e, 0x7f, 0x6a, 0x58, 0x6e, 0xd0, 0x60, 0xaf, 0xf1, 0x8f, + 0x4c, 0xc5, 0x5a, 0x5c, 0xb7, 0x74, 0x83, 0x3c, 0xb3, 0x7e, 0xdc, 0x76, + 0x89, 0xa5, 0xca, 0xd7, 0x75, 0x35, 0xb2, 0x4c, 0x0a, 0x67, 0x2b, 0x7a, + 0xe8, 0xac, 0x9e, 0x26, 0xa3, 0xae, 0x87, 0x66, 0x12, 0x4e, 0x74, 0xc8, + 0xd8, 0x6d, 0x89, 0x9c, 0x34, 0x63, 0x61, 0x33, 0x1b, 0x6a, 0x78, 0x7f, + 0x2f, 0xa7, 0x9b, 0xe7, 0x42, 0x0d, 0xcb, 0xc9, 0xf0, 0xa6, 0xb5, 0x38, + 0x66, 0x80, 0xca, 0x7a, 0xa9, 0xe4, 0x93, 0xe3, 0xfc, 0x7d, 0x38, 0x7d, + 0x7a, 0x2c, 0x03, 0xb4, 0x35, 0xde, 0x1b, 0x2e, 0x29, 0x24, 0x40, 0x93, + 0x6c, 0x52, 0x21, 0xd6, 0x70, 0x88, 0xfd, 0xc7, 0x5c, 0x94, 0x95, 0xc0, + 0x03, 0xce, 0x1b, 0xb3, 0x0e, 0x87, 0xac, 0xa0, 0x88, 0xcd, 0x20, 0x3d, + 0x88, 0x6f, 0xac, 0x29, 0x2e, 0xcc, 0x7d, 0xa7, 0x09, 0x16, 0xc0, 0xcc, + 0x55, 0x43, 0x19, 0xdc, 0x5e, 0xc4, 0xe5, 0x7c, 0xfb, 0x50, 0x01, 0x41, + 0xe1, 0x70, 0x84, 0x3e, 0x60, 0x88, 0x05, 0x27, 0x4b, 0x6c, 0x59, 0x9a, + 0x01, 0x50, 0xec, 0x74, 0x6a, 0x98, 0x57, 0xfe, 0xf5, 0x63, 0xc3, 0x60, + 0x55, 0x23, 0x33, 0xf9, 0x2d, 0xf0, 0x68, 0xff, 0xad, 0x61, 0xdb, 0x5e, + 0xdb, 0x0c, 0x54, 0x68, 0x8c, 0x4b, 0x64, 0x94, 0x3c, 0xa8, 0xb1, 0x31, + 0x61, 0xf3, 0xb3, 0xed, 0x8f, 0xd5, 0x07, 0x27, 0xbf, 0xa3, 0xa2, 0x42, + 0x4a, 0xa1, 0x5e, 0xc9, 0xb3, 0x9a, 0x0f, 0xbb, 0xf7, 0xc7, 0x4d, 0x0b, + 0xee, 0xbd, 0xce, 0x9e, 0x8c, 0x14, 0x7e, 0x06, 0x6e, 0x6d, 0x9b, 0xdd, + 0x22, 0xc6, 0xc2, 0x62, 0xa5, 0x45, 0xc1, 0xe1, 0x97, 0xe2, 0x50, 0x25, + 0xcc, 0x9b, 0xc4, 0x5d, 0x2d, 0x45, 0x10, 0xad, 0xa8, 0x4f, 0x27, 0xc3, + 0x1a, 0x2c, 0xef, 0x38, 0x2d, 0xa7, 0xaf, 0xe5, 0x23, 0x7a, 0x8f, 0xbf, + 0x9c, 0xd0, 0xb6, 0x31, 0x5c, 0xaa, 0xd2, 0x8c, 0xd8, 0x91, 0x00, 0xa1, + 0x8b, 0x4d, 0x3e, 0x27, 0x22, 0x6c, 0x0f, 0x64, 0x95, 0x89, 0xa6, 0x29, + 0x90, 0xf9, 0xa9, 0x24, 0x24, 0xb8, 0x71, 0x56, 0x7a, 0xc5, 0xa9, 0x26, + 0x9f, 0xf6, 0x2a, 0xa6, 0xf1, 0xca, 0x2a, 0x17, 0x14, 0x8c, 0x8d, 0xf2, + 0x44, 0x7d, 0x49, 0x4e, 0x9b, 0x4f, 0xef, 0x72, 0x7e, 0xe8, 0x0f, 0x45, + 0xb3, 0x3d, 0x61, 0xf5, 0x9d, 0x3f, 0x9a, 0xe3, 0x93, 0xdd, 0x3d, 0x02, + 0x84, 0x7d, 0xd4, 0x84, 0xa8, 0x23, 0xe9, 0x43, 0xb6, 0x66, 0xf2, 0xb7, + 0x35, 0xcf, 0xa3, 0x2f, 0xbe, 0x48, 0x0e, 0xaa, 0xfe, 0xe9, 0x7e, 0xb0, + 0x4d, 0xb3, 0x6b, 0x69, 0xdc, 0xef, 0x20, 0xec, 0xce, 0x6c, 0xad, 0x7a, + 0x20, 0x35, 0xf2, 0xfd, 0x09, 0xe1, 0xdb, 0xca, 0x2a, 0x55, 0xf7, 0x60, + 0xca, 0xf3, 0x85, 0x12, 0xe6, 0x05, 0x4f, 0xc8, 0x6e, 0x76, 0xda, 0x5f, + 0x45, 0x1e, 0xed, 0xdf, 0x57, 0x4c, 0xeb, 0x7e, 0x28, 0xf7, 0x39, 0xc4, + 0xd0, 0x10, 0x32, 0xa9, 0xcc, 0x25, 0xd9, 0x0b, 0x8c, 0x8a, 0xf6, 0x6c, + 0x84, 0xde, 0x09, 0x8c, 0xf6, 0xa4, 0x95, 0xb3, 0x65, 0x5e, 0x49, 0x36, + 0x8c, 0x51, 0x85, 0x62, 0xcc, 0xe6, 0x2a, 0x3d, 0xdc, 0x68, 0x08, 0x41, + 0x73, 0x18, 0x74, 0x10, 0xe5, 0x18, 0xfa, 0xbe, 0x2f, 0xaa, 0x98, 0x3c, + 0x7c, 0x44, 0x43, 0x3f, 0xd6, 0x27, 0xd3, 0x28, 0xf0, 0x2b, 0xeb, 0xf2, + 0x46, 0xfc, 0xf6, 0x3f, 0xc7, 0xa8, 0xc0, 0xf0, 0x17, 0xef, 0x35, 0xde, + 0x55, 0x30, 0xef, 0xf7, 0x7b, 0x57, 0xf3, 0x9f, 0x00, 0xb5, 0x49, 0x1e, + 0xc4, 0x6a, 0xea, 0x0e, 0x40, 0x95, 0x47, 0x55, 0x32, 0x4f, 0x4f, 0x24, + 0x5a, 0x10, 0xaa, 0x1f, 0x5b, 0x9b, 0xc1, 0xb3, 0xaa, 0xa3, 0x40, 0x32, + 0x56, 0x80, 0xbf, 0x38, 0xbc, 0x89, 0xad, 0xa8, 0x0e, 0x8f, 0x8e, 0x14, + 0x17, 0x5a, 0x9b, 0x25, 0x85, 0x85, 0xa7, 0x43, 0xc8, 0x19, 0x21, 0xf9, + 0xa3, 0xdc, 0xb9, 0xc8, 0x70, 0x7b, 0xc8, 0x42, 0x38, 0x50, 0xb9, 0xcf, + 0x90, 0x6e, 0x88, 0x7f, 0x5a, 0x56, 0xc8, 0xd7, 0x84, 0x7b, 0x69, 0xe1, + 0x31, 0x6d, 0xe9, 0xc7, 0x7f, 0x39, 0x78, 0x52, 0xa2, 0x0c, 0xc7, 0x3b, + 0x89, 0x05, 0x9d, 0x66, 0xc6, 0xea, 0x48, 0x75, 0xa5, 0xd6, 0x89, 0x8e, + 0x47, 0xdf, 0x81, 0x28, 0x94, 0xc7, 0x98, 0xd4, 0x1c, 0x6f, 0x95, 0xdd, + 0x20, 0x74, 0xe9, 0xde, 0xb5, 0x3b, 0x87, 0xa1, 0x1a, 0x1e, 0xee, 0xc7, + 0xbc, 0xa4, 0x12, 0x30, 0x92, 0x60, 0x9f, 0x0d, 0x4d, 0x23, 0x1f, 0xa0, + 0xea, 0x07, 0x84, 0x10, 0xb3, 0xd3, 0x2a, 0x2f, 0x27, 0xdb, 0x27, 0x76, + 0xb8, 0x43, 0xe2, 0x9a, 0xfc, 0x9b, 0x81, 0x43, 0xd2, 0xbc, 0xc2, 0xbb, + 0x40, 0xbd, 0xe8, 0x10, 0xd5, 0xca, 0xd2, 0x10, 0x5e, 0x18, 0xfe, 0x45, + 0x1d, 0xc2, 0xf9, 0x99, 0x50, 0xbe, 0x7e, 0xca, 0x1a, 0x45, 0x17, 0x99, + 0x03, 0x9d, 0x2b, 0x68, 0xb7, 0x76, 0x3e, 0x68, 0x41, 0x81, 0x6d, 0xe3, + 0x77, 0xbe, 0x4e, 0xc9, 0x41, 0xb7, 0x8a, 0xb7, 0xa7, 0x59, 0xfa, 0x04, + 0x7b, 0xde, 0xd0, 0x3f, 0x7a, 0x57, 0xa3, 0xf1, 0x9e, 0x0a, 0x66, 0x98, + 0xb0, 0xc1, 0xc2, 0xb4, 0x7a, 0x3b, 0x2f, 0x54, 0x3b, 0x66, 0xe6, 0x6b, + 0xc5, 0x2c, 0xa1, 0xb1, 0xd2, 0xee, 0xd8, 0x30, 0xf3, 0xa9, 0x2f, 0xe8, + 0xf0, 0x3e, 0xd8, 0x2b, 0x9a, 0x75, 0x58, 0x59, 0xc7, 0x3a, 0x39, 0xa1, + 0x58, 0x19, 0x87, 0x3f, 0x90, 0xe5, 0xb3, 0xb6, 0xfe, 0x39, 0x34, 0xc8, + 0x4c, 0x21, 0x7b, 0x96, 0x9e, 0x3e, 0x38, 0x48, 0x3e, 0xaa, 0x0b, 0x1b, + 0xbf, 0xa9, 0x45, 0x83, 0x8e, 0x38, 0xf3, 0x96, 0xb8, 0x24, 0x23, 0xc1, + 0xd3, 0x5c, 0x77, 0xeb, 0x6f, 0xf8, 0x16, 0xa8, 0x94, 0xbc, 0xab, 0x2a, + 0x20, 0x52, 0xec, 0x9a, 0x5c, 0xd9, 0x99, 0xb4, 0x84, 0x50, 0x90, 0xbb, + 0xf7, 0x80, 0x51, 0x61, 0x95, 0x61, 0xaa, 0x03, 0xd6, 0xd4, 0xa9, 0x73, + 0x86, 0x3b, 0xf1, 0x7e, 0xca, 0x7c, 0xfb, 0xf9, 0x33, 0xe6, 0x96, 0x66, + 0x13, 0x7a, 0x35, 0xae, 0x71, 0xcc, 0x13, 0x4b, 0x5e, 0x73, 0xbd, 0xf8, + 0xf2, 0x5e, 0x51, 0x5c, 0x50, 0x09, 0x3c, 0x59, 0xfa, 0xd0, 0xd4, 0x8e, + 0xe0, 0x21, 0xb4, 0x97, 0xa4, 0x7d, 0xeb, 0x17, 0xef, 0x4c, 0xf4, 0xd0, + 0x0b, 0xf5, 0x42, 0xaf, 0x07, 0x8e, 0xe9, 0x5f, 0x2b, 0xce, 0xb4, 0xf9, + 0x17, 0xea, 0x9e, 0x83, 0x94, 0xf5, 0x1d, 0x49, 0x91, 0x42, 0x65, 0x84, + 0x77, 0x56, 0xc0, 0x4f, 0x67, 0x37, 0xed, 0xa3, 0x18, 0x22, 0x69, 0xd7, + 0x40, 0xfb, 0x39, 0xfd, 0xc2, 0x37, 0x68, 0x98, 0x30, 0x6a, 0x33, 0xad, + 0x2f, 0xf2, 0x3d, 0x5c, 0xe0, 0x4a, 0x29, 0x38, 0xe5, 0xe0, 0x5c, 0xb3, + 0x79, 0xd5, 0x8c, 0xcd, 0x25, 0xad, 0xab, 0xd3, 0x75, 0x2f, 0x54, 0x3a, + 0xfe, 0x8e, 0x0d, 0x3f, 0xfa, 0x6e, 0xcc, 0x80, 0x26, 0x08, 0x7f, 0xa3, + 0x9e, 0xba, 0x80, 0x4c, 0x36, 0x4c, 0x4d, 0x74, 0xc0, 0x3f, 0xd1, 0xb3, + 0xad, 0xa3, 0xc8, 0xcf, 0x7a, 0x73, 0xb7, 0x09, 0x67, 0x3b, 0xf8, 0x6f, + 0x7a, 0x26, 0x57, 0x65, 0x83, 0xcf, 0x18, 0x3c, 0x86, 0x2c, 0xb4, 0xcd, + 0xe8, 0x74, 0xfa, 0x63, 0xd4, 0xb4, 0x36, 0x36, 0xd9, 0xb0, 0xeb, 0x29, + 0xe3, 0x3a, 0x7f, 0x06, 0x80, 0x29, 0x4c, 0x86, 0x94, 0x49, 0x42, 0x22, + 0x57, 0x0c, 0x4f, 0xfa, 0x08, 0xb5, 0x12, 0xbe, 0x76, 0xf5, 0x52, 0x10, + 0x47, 0x48, 0x1f, 0xbd, 0x87, 0x51, 0xd1, 0x39, 0xc8, 0x50, 0x7c, 0xfa, + 0x92, 0xe7, 0xea, 0x40, 0x55, 0xf7, 0x61, 0x9f, 0x19, 0xc2, 0x65, 0x23, + 0x6d, 0xe0, 0x41, 0xb9, 0x5b, 0xb7, 0x8c, 0x9a, 0xee, 0x50, 0x53, 0xa6, + 0xe8, 0x80, 0x14, 0x8c, 0xeb, 0x2a, 0xc1, 0x44, 0xda, 0x6d, 0x90, 0x96, + 0xb8, 0xf1, 0xc4, 0x0d, 0xf1, 0xd8, 0x8e, 0xd0, 0xb4, 0x73, 0x49, 0xe5, + 0x34, 0xab, 0x00, 0x0f, 0x0b, 0x7b, 0xc3, 0x7d, 0x53, 0x1d, 0x75, 0xef, + 0x27, 0xfb, 0xdf, 0x29, 0xfd, 0x61, 0xb3, 0x71, 0x25, 0xac, 0x62, 0x2d, + 0xaa, 0x1a, 0x2a, 0x55, 0x6e, 0x11, 0x50, 0x4b, 0x2c, 0x3d, 0xd8, 0x8d, + 0xb9, 0xcb, 0xc2, 0x21, 0x77, 0x4e, 0x40, 0x56, 0x45, 0xc1, 0x07, 0x79, + 0xdb, 0x66, 0x2f, 0x6d, 0x4d, 0xac, 0x2b, 0x2d, 0x29, 0xff, 0xa1, 0x79, + 0x10, 0x03, 0x72, 0x09, 0xe8, 0xe9, 0x31, 0xd5, 0x6f, 0x42, 0x97, 0x3e, + 0x09, 0xf0, 0x4a, 0xb5, 0xe6, 0x73, 0x94, 0xc1, 0xb4, 0x94, 0xa1, 0xd9, + 0x44, 0xe8, 0x50, 0xe2, 0x6c, 0x82, 0xea, 0x89, 0x06, 0xd6, 0x44, 0xe9, + 0x53, 0xd0, 0x5c, 0xcf, 0x0a, 0x3b, 0x89, 0x50, 0x8d, 0x1e, 0x44, 0xbd, + 0xb2, 0xb6, 0x68, 0xf4, 0xbb, 0x2d, 0x65, 0x95, 0x5c, 0xb5, 0xdc, 0xe2, + 0xb7, 0x70, 0x86, 0xfd, 0x5b, 0xcc, 0x99, 0x41, 0x5d, 0x22, 0x11, 0xa8, + 0x22, 0x8c, 0xc1, 0x73, 0x70, 0x5b, 0x31, 0x11, 0xc3, 0xdb, 0x7f, 0xca, + 0x2b, 0xcb, 0xeb, 0x7d, 0x2b, 0xd1, 0x32, 0xe6, 0xf8, 0x22, 0x22, 0x69, + 0xea, 0xb7, 0xcd, 0x25, 0x22, 0x33, 0x2f, 0x83, 0x3f, 0xb7, 0x2d, 0x22, + 0x61, 0x24, 0x01, 0xb3, 0xe9, 0xd0, 0xf6, 0x21, 0xe6, 0x2d, 0xea, 0x0e, + 0x53, 0x7a, 0x97, 0xcd, 0xcf, 0x6c, 0xe2, 0xd5, 0x8b, 0xdc, 0xe9, 0xe0, + 0xfd, 0xd0, 0xa0, 0xbf, 0xa5, 0x39, 0x7e, 0xd4, 0xdd, 0xfe, 0x1a, 0xce, + 0xb0, 0x85, 0x8e, 0xc1, 0x05, 0x36, 0xf9, 0xd3, 0x6a, 0x35, 0xab, 0x53, + 0x1d, 0xc2, 0xa0, 0xfa, 0xc2, 0x6b, 0x8b, 0x8c, 0x2d, 0x5d, 0x5f, 0xb8, + 0x18, 0x43, 0x53, 0xb9, 0x5d, 0x08, 0x07, 0xd1, 0x8f, 0xc6, 0xe9, 0xef, + 0xaf, 0x3b, 0xbb, 0x60, 0xaa, 0x28, 0xac, 0x4c, 0x03, 0x5d, 0xc8, 0x05, + 0xba, 0x82, 0x5c, 0xcb, 0xc6, 0x2a, 0x13, 0xf6, 0xfc, 0x54, 0xf3, 0xea, + 0x20, 0xce, 0xcf, 0x05, 0x00, 0xb9, 0x98, 0x0b, 0x9f, 0x96, 0xe0, 0x7b, + 0x85, 0x8e, 0x43, 0xbd, 0xf2, 0x3e, 0x17, 0x19, 0x8d, 0x23, 0x72, 0x85, + 0x93, 0xdf, 0x3a, 0x21, 0x94, 0x34, 0x32, 0x53, 0x02, 0xba, 0x34, 0xba, + 0xa5, 0x2e, 0x5c, 0x0b, 0x1e, 0x3f, 0xa9, 0x83, 0x92, 0x63, 0x0b, 0x12, + 0xc9, 0xf8, 0x35, 0xef, 0x78, 0xa0, 0xee, 0xc0, 0xbb, 0x14, 0xd4, 0x68, + 0x39, 0xa0, 0x00, 0x38, 0x77, 0x1e, 0xfc, 0x94, 0xb4, 0xd4, 0xc1, 0x98, + 0xe1, 0x43, 0x8e, 0xc6, 0xa7, 0x58, 0x33, 0x1b, 0xa3, 0x73, 0xf7, 0x4c, + 0x49, 0x9d, 0xc0, 0xb8, 0xbf, 0x30, 0x84, 0x2e, 0x5a, 0x8b, 0x6c, 0xa5, + 0xde, 0xb5, 0x6a, 0x79, 0x67, 0x54, 0xe7, 0x8c, 0x3c, 0xf3, 0x70, 0x1b, + 0x3d, 0x35, 0x23, 0x65, 0x17, 0xc9, 0x74, 0x11, 0x0b, 0xb1, 0x64, 0xc0, + 0x65, 0xa3, 0x9e, 0x5a, 0x7b, 0xa2, 0xda, 0xe1, 0xf4, 0xeb, 0xb8, 0x13, + 0x90, 0x30, 0xc1, 0x72, 0x6a, 0x2a, 0x13, 0xe3, 0x36, 0xe1, 0x05, 0x47, + 0x56, 0x42, 0xf2, 0x59, 0x44, 0x12, 0x23, 0x27, 0xe4, 0xfe, 0xae, 0x83, + 0x39, 0x0f, 0x4c, 0x85, 0x3f, 0xaf, 0x97, 0x2e, 0xae, 0x3c, 0x12, 0x0e, + 0xfd, 0x5b, 0xfd, 0x8e, 0x58, 0x58, 0x4a, 0xbd, 0x05, 0x98, 0x6b, 0x82, + 0x03, 0x02, 0x0a, 0x2d, 0x1c, 0x19, 0x0f, 0x95, 0x12, 0x5d, 0x8c, 0x1e, + 0x7b, 0x49, 0xbb, 0x83, 0xe2, 0xd2, 0x53, 0x60, 0xe1, 0xab, 0xd2, 0x8b, + 0x02, 0xeb, 0x49, 0x27, 0xd7, 0xda, 0x22, 0xd3, 0x26, 0x6f, 0x3e, 0x5b, + 0x3f, 0x33, 0xcb, 0xa8, 0x08, 0x98, 0xa6, 0xc5, 0x35, 0xc1, 0x81, 0xc1, + 0xd6, 0x28, 0xe5, 0xba, 0x50, 0xe9, 0x14, 0x1a, 0x0b, 0x0a, 0x8a, 0x9e, + 0xa3, 0xaa, 0xbc, 0x3b, 0x38, 0x5b, 0xe0, 0x1f, 0xf6, 0xb8, 0x95, 0x79, + 0xa4, 0x45, 0x5f, 0xc4, 0x63, 0x86, 0xd0, 0x15, 0xe0, 0x25, 0x6e, 0x5f, + 0x8d, 0x75, 0x25, 0x67, 0xea, 0xf3, 0x92, 0x33, 0xd1, 0x07, 0xf3, 0x43, + 0x21, 0x42, 0x40, 0x70, 0x9b, 0x8e, 0x0b, 0x41, 0x54, 0x30, 0x73, 0xd0, + 0x49, 0xe4, 0x70, 0xf6, 0xd3, 0x7d, 0x59, 0xd6, 0x1f, 0x06, 0xfc, 0x12, + 0x89, 0x9f, 0x26, 0x09, 0x34, 0xf6, 0x64, 0x56, 0x37, 0x68, 0x59, 0x33, + 0x9c, 0xa0, 0xfa, 0x65, 0x70, 0xb3, 0xe1, 0x29, 0xd1, 0x5b, 0xaf, 0xe7, + 0xa5, 0x39, 0x64, 0x38, 0x8b, 0xb1, 0xd6, 0xce, 0xa4, 0xb4, 0xb6, 0xdb, + 0x01, 0xb4, 0xf9, 0xb7, 0x1f, 0x8f, 0xcd, 0x28, 0xe6, 0x27, 0x47, 0xf2, + 0x53, 0x1d, 0xea, 0xb4, 0x53, 0xfa, 0xe0, 0x22, 0xea, 0xc5, 0xd2, 0xfc, + 0x4e, 0x45, 0xcf, 0xef, 0xaa, 0xea, 0xaf, 0x7e, 0x77, 0xe2, 0x39, 0x1c, + 0x5d, 0x9c, 0x77, 0x7b, 0x71, 0xb5, 0x11, 0xef, 0xc7, 0xf8, 0xba, 0x2b, + 0x7b, 0x15, 0xfa, 0x2d, 0xd5, 0xd8, 0xe0, 0xee, 0xbe, 0x10, 0xd6, 0xdb, + 0x47, 0xf1, 0x11, 0xcc, 0x35, 0x4c, 0x2d, 0xa8, 0x12, 0x12, 0x23, 0x78, + 0x0b, 0xd3, 0xb8, 0x90, 0x8a, 0x1d, 0xc4, 0x90, 0x4b, 0x7e, 0x35, 0xb9, + 0x9f, 0x5b, 0x68, 0x97, 0x9c, 0x09, 0xc3, 0x0d, 0x0a, 0x20, 0xd9, 0x25, + 0x07, 0xeb, 0x56, 0xb5, 0xd6, 0x93, 0x31, 0x3d, 0x71, 0x7c, 0x0f, 0x48, + 0x26, 0x32, 0x0f, 0x1b, 0x43, 0x75, 0xc2, 0xcd, 0xf6, 0xaa, 0x88, 0x38, + 0x7b, 0xe9, 0xc0, 0x98, 0x51, 0xa4, 0x06, 0x15, 0x7f, 0x11, 0x0b, 0x91, + 0xcb, 0x59, 0x92, 0x1c, 0xa1, 0x44, 0x63, 0xa4, 0x3a, 0xad, 0xd7, 0x1d, + 0x9e, 0x63, 0xfb, 0xb9, 0x7d, 0x43, 0x80, 0x79, 0xe8, 0x01, 0xba, 0x08, + 0x47, 0x78, 0x57, 0xd6, 0x0b, 0x38, 0x94, 0x64, 0xac, 0x64, 0x77, 0xdc, + 0xb8, 0xa9, 0xa5, 0xa2, 0x62, 0x70, 0x36, 0x4f, 0x39, 0xd9, 0xae, 0x2f, + 0x15, 0xd3, 0x07, 0xc4, 0x01, 0x03, 0x96, 0x5e, 0x51, 0xa7, 0x15, 0x2a, + 0x9d, 0x22, 0x74, 0xae, 0x8a, 0xd4, 0xb9, 0x91, 0xed, 0xad, 0xa7, 0x76, + 0xad, 0x38, 0x33, 0xef, 0x3c, 0xe4, 0xd0, 0x7c, 0x6e, 0x53, 0xae, 0x0c, + 0x7a, 0xdf, 0x2c, 0x18, 0xeb, 0xc4, 0x8c, 0xfe, 0xab, 0x10, 0xcd, 0xaf, + 0x8f, 0x88, 0x3f, 0xac, 0xe3, 0x20, 0xed, 0x0c, 0x62, 0x81, 0x2e, 0x12, + 0xa9, 0xa5, 0xe7, 0xd5, 0x3a, 0xef, 0x40, 0xb4, 0x91, 0x52, 0x4c, 0xfd, + 0xd5, 0xb8, 0x98, 0x19, 0xcd, 0x1b, 0xa9, 0x17, 0xe7, 0x9a, 0xda, 0x8a, + 0xb4, 0x8f, 0x1a, 0x5c, 0x78, 0xd2, 0x28, 0x7a, 0xb6, 0x66, 0xac, 0x73, + 0xd4, 0x11, 0xc0, 0x81, 0xff, 0x71, 0x57, 0x4c, 0x23, 0x90, 0x2a, 0xd8, + 0x67, 0x7a, 0x6a, 0x58, 0xb7, 0x5b, 0xbe, 0x80, 0x62, 0x17, 0x10, 0x90, + 0xc1, 0xb7, 0x2c, 0xbe, 0xbe, 0x97, 0x2e, 0x85, 0x36, 0x07, 0x8e, 0x63, + 0xfc, 0x38, 0xc5, 0x66, 0x20, 0x33, 0x2b, 0xe8, 0x25, 0x25, 0xc1, 0x11, + 0xba, 0x5b, 0x12, 0xd9, 0x06, 0x4d, 0xfc, 0x49, 0x20, 0x27, 0x6b, 0x79, + 0x92, 0x8b, 0xde, 0x22, 0x39, 0xf9, 0x2e, 0xc9, 0x1b, 0xb9, 0x97, 0x2f, + 0xc3, 0x37, 0xf5, 0xa3, 0x6b, 0xd3, 0x3b, 0x94, 0xa5, 0x56, 0xb7, 0x81, + 0x7c, 0x9d, 0x28, 0xff, 0x57, 0xe7, 0x02, 0xa1, 0xd1, 0x3a, 0x3d, 0xac, + 0x74, 0x45, 0xb3, 0xab, 0x95, 0xec, 0x68, 0x8a, 0x9c, 0xf7, 0x43, 0xa4, + 0x14, 0x0d, 0x68, 0x40, 0x5f, 0x7e, 0x25, 0x8a, 0x47, 0x3f, 0x9c, 0xaf, + 0x88, 0x0b, 0x4a, 0xc0, 0x98, 0xc2, 0x57, 0xf4, 0xde, 0x04, 0x09, 0x37, + 0x9c, 0x87, 0x83, 0xb6, 0xa5, 0xa8, 0x5e, 0xc4, 0xec, 0x2e, 0xfd, 0xc9, + 0xf3, 0x85, 0x4f, 0x7d, 0xb8, 0xba, 0x6e, 0x6d, 0xc0, 0xd2, 0x37, 0xb2, + 0xba, 0x17, 0xad, 0x29, 0xf8, 0x71, 0x74, 0x0c, 0x93, 0x1e, 0x07, 0x34, + 0xec, 0xc3, 0x5f, 0x15, 0x21, 0x49, 0x0f, 0xa7, 0x7e, 0x72, 0x79, 0x66, + 0xfd, 0x3e, 0x29, 0xce, 0x12, 0xeb, 0x57, 0x88, 0xd8, 0xcc, 0x14, 0x96, + 0x33, 0x44, 0x64, 0x6c, 0x34, 0x55, 0xb3, 0x76, 0xc9, 0xa7, 0x3f, 0x7b, + 0x16, 0x9d, 0x7e, 0x95, 0x4c, 0xfa, 0xc9, 0x46, 0x17, 0x18, 0x18, 0x78, + 0xe7, 0xfb, 0x6b, 0x86, 0xf4, 0x25, 0x3a, 0x0b, 0x4a, 0xcd, 0x1a, 0x51, + 0xde, 0xa4, 0x45, 0xdd, 0xdb, 0xc9, 0x9f, 0xa9, 0xc3, 0x58, 0xb2, 0x43, + 0x90, 0x8b, 0xc1, 0x59, 0x47, 0x1a, 0x89, 0xcb, 0x9c, 0x6d, 0x46, 0x1f, + 0x0d, 0xe9, 0xfa, 0xd8, 0xe9, 0xde, 0xdb, 0xf5, 0x22, 0x9b, 0xe3, 0xef, + 0xb4, 0x0c, 0xc7, 0x34, 0xd0, 0x2a, 0x0f, 0x0b, 0x8e, 0x11, 0x88, 0x91, + 0xb7, 0xce, 0x92, 0xf2, 0x83, 0x3c, 0xd2, 0xf8, 0x42, 0x32, 0x82, 0x48, + 0xad, 0x67, 0x44, 0x45, 0x59, 0xac, 0x57, 0xb7, 0x7e, 0x1b, 0xce, 0xca, + 0x51, 0xfb, 0x1b, 0x12, 0x39, 0xaf, 0xe4, 0xfb, 0xdb, 0xc5, 0xb7, 0xcc, + 0x4a, 0x5d, 0xc4, 0xa6, 0x95, 0xaf, 0x5b, 0x39, 0x4e, 0x47, 0xc5, 0x50, + 0x67, 0x92, 0x84, 0x62, 0xeb, 0x81, 0x77, 0x24, 0xda, 0x27, 0x64, 0xfe, + 0xe4, 0x83, 0x40, 0x33, 0xc8, 0xb1, 0xaa, 0xbb, 0xbf, 0x13, 0xc3, 0x18, + 0x9a, 0x24, 0x06, 0xbd, 0x0a, 0x07, 0xa3, 0xd6, 0xd8, 0x38, 0x32, 0x73, + 0x8d, 0x40, 0x5f, 0xc2, 0x3f, 0xeb, 0xd2, 0x0e, 0x3d, 0x6d, 0xf5, 0x72, + 0x5a, 0xa6, 0x56, 0x22, 0x41, 0xe5, 0x0c, 0xb5, 0x0c, 0xda, 0xcd, 0x46, + 0xbc, 0xd7, 0x98, 0x89, 0x5e, 0x97, 0x54, 0x4f, 0x4b, 0xc0, 0x27, 0x51, + 0x0d, 0x20, 0x3f, 0x55, 0x78, 0xdc, 0x5a, 0x79, 0x08, 0xed, 0xd3, 0xaa, + 0x9c, 0xc3, 0x7d, 0x75, 0x76, 0x81, 0xa4, 0xe0, 0xfc, 0x90, 0x6a, 0x83, + 0x37, 0x53, 0xb8, 0xb5, 0xd9, 0x7a, 0xd9, 0x7d, 0xeb, 0x50, 0x72, 0xd3, + 0x5d, 0xed, 0x22, 0xfb, 0x6e, 0x67, 0x79, 0x9c, 0xb9, 0xea, 0xac, 0xc1, + 0x6d, 0x68, 0xf5, 0x12, 0xaa, 0x54, 0x90, 0xd8, 0x7f, 0xe0, 0xf4, 0xdd, + 0x3b, 0x88, 0xe3, 0xec, 0x7f, 0x1c, 0x2b, 0x08, 0x32, 0xc6, 0x05, 0x53, + 0xae, 0xa4, 0x46, 0xa7, 0xf3, 0xe6, 0xcb, 0xe7, 0x04, 0xc1, 0x52, 0xa7, + 0xfe, 0x68, 0x55, 0xc1, 0x91, 0xb2, 0x9a, 0x3b, 0x05, 0xc6, 0xae, 0x15, + 0x89, 0xdc, 0xb2, 0x0b, 0xeb, 0x19, 0x96, 0x62, 0xe3, 0x67, 0xc5, 0xdc, + 0xf5, 0xe8, 0xbe, 0x16, 0xbe, 0xf6, 0xe4, 0x0b, 0xeb, 0x99, 0x82, 0x65, + 0x0a, 0x97, 0xf5, 0xc2, 0x19, 0x1c, 0x1e, 0xa1, 0xf1, 0x75, 0x06, 0xa7, + 0xdb, 0x97, 0x68, 0x94, 0x0b, 0xea, 0xc4, 0xda, 0x70, 0x72, 0x3e, 0x9f, + 0xfc, 0x20, 0x4e, 0x54, 0xfb, 0x18, 0x01, 0x74, 0x9a, 0x24, 0x1d, 0x20, + 0x3a, 0x25, 0xe1, 0xd8, 0xaf, 0xe3, 0x76, 0xe0, 0x47, 0x53, 0x86, 0xd9, + 0x3f, 0xc2, 0x46, 0x4a, 0x02, 0x05, 0xaf, 0xbf, 0x49, 0x12, 0x22, 0x66, + 0x81, 0xf5, 0x9d, 0xdd, 0xae, 0x7f, 0xf5, 0x99, 0x2b, 0x89, 0xa6, 0x25, + 0x30, 0xd6, 0xb3, 0x00, 0xa4, 0x62, 0xd2, 0xb3, 0x8e, 0xdd, 0xc2, 0x04, + 0x62, 0x17, 0x44, 0xa3, 0x62, 0xf7, 0x8c, 0x56, 0x00, 0x4f, 0x98, 0xfe, + 0x7a, 0xdf, 0x9d, 0x47, 0xab, 0xc9, 0xb7, 0x0e, 0x0d, 0x02, 0x54, 0x6a, + 0xab, 0xf9, 0x22, 0xb9, 0x11, 0xb3, 0xec, 0x17, 0xb9, 0xc9, 0x86, 0xf6, + 0x66, 0x97, 0x1f, 0xa9, 0x38, 0xd8, 0x66, 0x8e, 0x41, 0xd9, 0x9a, 0x35, + 0xfd, 0x19, 0x64, 0xcb, 0x1e, 0x77, 0x80, 0xd4, 0x6d, 0xea, 0x00, 0xf5, + 0x9b, 0xc9, 0x55, 0xef, 0x80, 0x14, 0x79, 0xab, 0xf5, 0x5e, 0xb0, 0x4b, + 0x73, 0x52, 0x17, 0x2a, 0xd7, 0x68, 0x79, 0x6a, 0xf1, 0xc0, 0x04, 0xce, + 0x33, 0xd2, 0x18, 0xad, 0x39, 0x4d, 0xda, 0x40, 0x49, 0xce, 0x00, 0xca, + 0x89, 0xf3, 0xbd, 0x13, 0xe5, 0x7a, 0x03, 0x99, 0xa3, 0x4b, 0x29, 0xcd, + 0x18, 0xbd, 0xc8, 0xd7, 0x30, 0xcd, 0x4f, 0x65, 0xdc, 0xca, 0xc2, 0x9f, + 0x84, 0x2d, 0x83, 0xf6, 0x69, 0x0d, 0x55, 0x08, 0x5b, 0x6c, 0x87, 0x53, + 0xda, 0x13, 0x2a, 0x34, 0xf7, 0xea, 0x13, 0xec, 0x14, 0x90, 0xe8, 0x94, + 0xdc, 0xa6, 0xcf, 0xe9, 0x9b, 0x99, 0x63, 0x48, 0xf3, 0x34, 0xac, 0xf2, + 0x78, 0x76, 0x90, 0x46, 0xd8, 0x7d, 0x2b, 0xc1, 0xd2, 0xdd, 0xf1, 0xda, + 0x23, 0xc8, 0x3c, 0xd6, 0x58, 0x2e, 0xaf, 0x2c, 0xf6, 0x8a, 0xb3, 0x93, + 0x0e, 0x4f, 0x82, 0x7e, 0x26, 0x88, 0x0b, 0x3b, 0xe4, 0xe9, 0x85, 0x2b, + 0x99, 0xca, 0xdc, 0xad, 0x84, 0x26, 0xee, 0x35, 0x6a, 0x50, 0xc4, 0xae, + 0x95, 0x30, 0x0d, 0x09, 0xef, 0xdb, 0x4b, 0x4c, 0x9b, 0x0f, 0x04, 0x0a, + 0x6e, 0xf0, 0x92, 0x43, 0x06, 0xb9, 0x73, 0x16, 0x79, 0x15, 0x3f, 0x08, + 0xcc, 0x78, 0x2b, 0x35, 0x8c, 0xa3, 0x2a, 0x6e, 0xf6, 0x5c, 0x61, 0xf3, + 0xc6, 0x4b, 0x8a, 0xbc, 0x75, 0x1f, 0x4a, 0x00, 0x4e, 0x5f, 0x9e, 0x24, + 0x03, 0x2d, 0x86, 0x26, 0xa7, 0x78, 0xb7, 0xc3, 0x6f, 0x74, 0x6d, 0x32, + 0x34, 0xcd, 0x37, 0x42, 0x56, 0x24, 0x83, 0x7f, 0xa8, 0x1b, 0x9b, 0xae, + 0x97, 0x55, 0x2d, 0xba, 0x67, 0x75, 0x67, 0xca, 0xa5, 0xd1, 0x6e, 0xd6, + 0x48, 0xaf, 0xeb, 0x71, 0xdc, 0x31, 0xfb, 0x3b, 0xe3, 0x7c, 0x64, 0x9d, + 0xe5, 0x5a, 0xe4, 0x87, 0x6e, 0xed, 0xed, 0xca, 0xb6, 0x51, 0xfd, 0x73, + 0xef, 0x7c, 0xbc, 0x15, 0x69, 0xfd, 0x9f, 0x1f, 0x0f, 0x17, 0x1a, 0x8d, + 0x73, 0x61, 0x7d, 0xf1, 0x09, 0x97, 0x06, 0xbe, 0x90, 0x38, 0xdf, 0xac, + 0xfd, 0xe2, 0x87, 0xe8, 0xc1, 0xc3, 0x9b, 0x83, 0x79, 0xa6, 0xdd, 0x6d, + 0x58, 0x4d, 0x03, 0x26, 0x99, 0x1d, 0x2e, 0x47, 0xb0, 0x20, 0x3f, 0x84, + 0xaf, 0xfa, 0xf9, 0xf1, 0x62, 0xd5, 0x80, 0xb8, 0x6e, 0x69, 0x7e, 0x53, + 0x80, 0x05, 0xc4, 0x2f, 0xba, 0xed, 0x0d, 0x75, 0xca, 0x01, 0xde, 0x6e, + 0xf0, 0xd3, 0x23, 0x9b, 0x1e, 0xae, 0x02, 0x57, 0xeb, 0x40, 0xf2, 0x55, + 0x89, 0xd7, 0x70, 0xd6, 0x45, 0xe7, 0x67, 0xd3, 0x3e, 0x21, 0xda, 0xb6, + 0xae, 0xe5, 0xe6, 0x82, 0x0c, 0x3e, 0x3e, 0xe8, 0xbe, 0x85, 0x3d, 0x79, + 0x75, 0x90, 0x9b, 0x9c, 0x01, 0x88, 0x8d, 0x5a, 0x34, 0x1d, 0x10, 0x83, + 0x85, 0x08, 0xea, 0x88, 0x51, 0x29, 0xea, 0x95, 0x40, 0x2f, 0x16, 0x90, + 0xec, 0x1b, 0xb7, 0x22, 0x81, 0xcb, 0x1b, 0x8c, 0xf5, 0xe2, 0xfd, 0xcb, + 0x1f, 0xe7, 0xb0, 0x4b, 0x4d, 0x7c, 0x7d, 0x11, 0x17, 0x20, 0x89, 0x8b, + 0x4a, 0x80, 0xa3, 0x10, 0x6f, 0x68, 0x09, 0x01, 0x68, 0x86, 0x3b, 0x2a, + 0xfb, 0x48, 0x80, 0xa0, 0xd1, 0xdb, 0x3f, 0x91, 0x44, 0x58, 0x83, 0xc6, + 0x85, 0x77, 0x6b, 0xb1, 0x35, 0x4a, 0x03, 0xa2, 0xcf, 0x2f, 0xbd, 0xcd, + 0x4b, 0xfa, 0x5a, 0x5e, 0x8f, 0x8b, 0x95, 0x62, 0xaa, 0xe7, 0x3b, 0x54, + 0xb1, 0xec, 0xd5, 0x85, 0x4f, 0xd9, 0x59, 0x56, 0xb4, 0xec, 0xc1, 0x21, + 0xc5, 0xa6, 0x35, 0x1d, 0x7b, 0x60, 0xe1, 0xb1, 0x7c, 0x8f, 0x47, 0xa1, + 0xf1, 0x13, 0x4b, 0xaf, 0x23, 0xcb, 0x5e, 0xe2, 0x74, 0x16, 0x16, 0x96, + 0x3b, 0xff, 0xbf, 0x26, 0x5f, 0x68, 0xd5, 0x64, 0xc6, 0x62, 0xaf, 0x4a, + 0xfc, 0x0f, 0x27, 0x3e, 0x96, 0x5b, 0x7c, 0xeb, 0x78, 0x81, 0x3c, 0x0a, + 0x63, 0xd5, 0x6b, 0x3c, 0xa9, 0xd4, 0x37, 0x03, 0x3b, 0x5c, 0x62, 0x7a, + 0xd5, 0x69, 0xbe, 0x44, 0x50, 0xab, 0x0a, 0x54, 0x31, 0x5c, 0x44, 0x52, + 0xfe, 0xde, 0xbb, 0x10, 0x80, 0x79, 0xb2, 0x69, 0xc5, 0x75, 0x8b, 0xba, + 0x1d, 0x4d, 0x2d, 0xfa, 0xc8, 0x0e, 0xc0, 0xaf, 0xc2, 0x31, 0xa1, 0x53, + 0xc7, 0x9f, 0x3e, 0x1f, 0x38, 0x8c, 0x1e, 0x00, 0x78, 0x76, 0xb6, 0xb5, + 0x68, 0xa4, 0x68, 0xe9, 0xba, 0xda, 0x97, 0xca, 0x16, 0xde, 0xba, 0xa1, + 0xb7, 0x17, 0x26, 0xb3, 0x4b, 0x4b, 0x4e, 0x21, 0x9c, 0xaf, 0xce, 0xf0, + 0x52, 0x41, 0x13, 0x87, 0x75, 0xc4, 0xd7, 0x34, 0x0c, 0x2d, 0xfe, 0xc1, + 0xb6, 0x60, 0x84, 0xd2, 0x57, 0xc2, 0xb2, 0x6c, 0xa6, 0x97, 0x51, 0xea, + 0x49, 0x07, 0x7d, 0xac, 0x15, 0x75, 0x71, 0x67, 0x2c, 0xdf, 0x09, 0x0c, + 0x63, 0x38, 0x6a, 0x25, 0xf3, 0x9b, 0x5d, 0x5d, 0x63, 0xe7, 0x20, 0xa3, + 0xf5, 0x6f, 0x8c, 0x77, 0x91, 0xb0, 0x6d, 0xad, 0x01, 0x1d, 0x40, 0x65, + 0xcd, 0x31, 0xbf, 0xb2, 0x0a, 0x1f, 0xf9, 0xb0, 0x34, 0x7f, 0x6a, 0xfe, + 0xca, 0x2e, 0x28, 0xc4, 0x5b, 0xdb, 0xa9, 0xd4, 0xdc, 0xe6, 0x3a, 0x0a, + 0xeb, 0xe2, 0xc5, 0xb8, 0xbe, 0xad, 0x8d, 0x7d, 0xa2, 0x5e, 0x88, 0xad, + 0xb8, 0xda, 0x41, 0x12, 0x1f, 0xc5, 0x85, 0xa1, 0x83, 0x3d, 0xc7, 0xbb, + 0x6d, 0x55, 0x63, 0xd0, 0x8b, 0x06, 0x76, 0x96, 0xf5, 0x0b, 0xd9, 0x2f, + 0x45, 0xf4, 0x9b, 0xc8, 0x18, 0xba, 0xbd, 0x30, 0xdc, 0x4d, 0x47, 0xde, + 0xbc, 0xc0, 0xc0, 0xca, 0x9f, 0xd7, 0xda, 0xcb, 0xd8, 0xdd, 0x7e, 0x98, + 0x25, 0xfd, 0x9f, 0xa4, 0x22, 0x5d, 0x4b, 0x63, 0x1b, 0xfa, 0x78, 0xdb, + 0x3d, 0x39, 0xcc, 0x26, 0x00, 0x70, 0x0e, 0xac, 0xf7, 0x30, 0xc0, 0x8c, + 0x97, 0xbe, 0x57, 0xeb, 0x1a, 0xc0, 0xfd, 0x4c, 0x81, 0x69, 0x54, 0x1b, + 0xd4, 0x8c, 0xb2, 0xe7, 0xf0, 0x5f, 0x0e, 0x46, 0x95, 0x7a, 0x2b, 0x0c, + 0x69, 0x37, 0x89, 0x45, 0x6a, 0xb2, 0x9f, 0xa8, 0x99, 0xd2, 0x6c, 0xa0, + 0x9d, 0xc0, 0x36, 0x65, 0x2f, 0x37, 0xe3, 0xc8, 0xba, 0x4f, 0xd2, 0x4c, + 0x69, 0x2e, 0x15, 0x2c, 0x92, 0x13, 0x44, 0x96, 0xa5, 0xe9, 0x90, 0x24, + 0x0a, 0x94, 0x44, 0x16, 0x6a, 0x8e, 0x4a, 0x7b, 0xf4, 0x65, 0x41, 0xd0, + 0x4e, 0xf3, 0xf2, 0x6d, 0x8e, 0xc0, 0x70, 0xdf, 0x56, 0x2f, 0x11, 0x80, + 0x03, 0x42, 0xb5, 0x9c, 0x59, 0xea, 0xe1, 0x2d, 0xc7, 0xd1, 0x29, 0x4a, + 0xce, 0x78, 0x83, 0x8f, 0x9b, 0xd4, 0x6b, 0x91, 0xd8, 0x7b, 0xd1, 0x03, + 0xc1, 0xe8, 0x84, 0xbc, 0xca, 0x64, 0xdd, 0xac, 0xdd, 0x39, 0xaf, 0x7c, + 0x5d, 0x7a, 0x5f, 0xc3, 0x8b, 0x0f, 0xd7, 0x18, 0x43, 0x4a, 0x8e, 0x3f, + 0x2f, 0x02, 0x91, 0xa2, 0xdc, 0x3e, 0x2c, 0x9c, 0x3b, 0x3c, 0xe3, 0xd4, + 0x9a, 0xb3, 0x59, 0x43, 0xd4, 0x75, 0x1c, 0x4b, 0x0b, 0xad, 0x84, 0x2d, + 0xbd, 0x05, 0x66, 0xdb, 0x0a, 0xda, 0x77, 0x75, 0x46, 0x78, 0x99, 0x44, + 0xdf, 0x12, 0x58, 0xa9, 0x3a, 0x5f, 0x04, 0x18, 0x81, 0xa2, 0x2d, 0xcf, + 0x9c, 0x35, 0x8d, 0x67, 0x73, 0x9e, 0x8d, 0xe4, 0xc9, 0x9d, 0x15, 0x80, + 0xe3, 0x36, 0xf9, 0xbd, 0xf2, 0x65, 0xb2, 0x10, 0xa9, 0xe8, 0x2a, 0x03, + 0x9d, 0x03, 0x11, 0xe5, 0xcc, 0x32, 0x12, 0xef, 0xee, 0x22, 0xa3, 0x0c, + 0x35, 0x28, 0xc0, 0x17, 0x9b, 0x43, 0x75, 0x5f, 0x2c, 0xbf, 0xeb, 0xc4, + 0xf2, 0xa0, 0x6e, 0xcb, 0x06, 0x1c, 0x5c, 0xd9, 0xe8, 0x56, 0xaf, 0xe4, + 0x2c, 0x6a, 0x8a, 0x9e, 0xea, 0x34, 0x60, 0x09, 0x94, 0xe7, 0xb2, 0x50, + 0x4b, 0xc9, 0xeb, 0xce, 0xd2, 0x7f, 0x1d, 0xc1, 0x22, 0xe1, 0x71, 0x1f, + 0xac, 0xb7, 0xb9, 0x5c, 0x8e, 0x44, 0xe9, 0x51, 0x58, 0x5c, 0x0e, 0x12, + 0x34, 0xb5, 0xab, 0xa1, 0x0d, 0xf1, 0xc6, 0x71, 0xf0, 0x51, 0x6f, 0xa8, + 0x72, 0xde, 0xad, 0x42, 0xe6, 0x39, 0x28, 0xb0, 0x66, 0xf8, 0xcb, 0x09, + 0xb2, 0x82, 0x5a, 0x02, 0x15, 0xca, 0x17, 0xa9, 0x63, 0xd8, 0xac, 0x18, + 0x49, 0xf7, 0xfa, 0x6d, 0xad, 0x3f, 0xf5, 0x2a, 0xd2, 0x1a, 0x9e, 0x4f, + 0xdc, 0xb1, 0xb5, 0x5b, 0x93, 0x59, 0x44, 0x72, 0x0c, 0xf4, 0x7e, 0xe4, + 0x62, 0x10, 0x64, 0xad, 0x2d, 0xb0, 0x2e, 0xcb, 0xf8, 0xd9, 0xbb, 0xf9, + 0xfc, 0xc5, 0xe1, 0x31, 0x6e, 0x0e, 0x8b, 0x12, 0x62, 0x25, 0x92, 0xd6, + 0xb0, 0x0d, 0x78, 0x7e, 0x03, 0x13, 0x65, 0xe0, 0xa3, 0x5d, 0x33, 0xc7, + 0x04, 0x8b, 0xe7, 0x45, 0xa8, 0x9f, 0xd1, 0x70, 0x27, 0x32, 0x6e, 0x50, + 0x48, 0x6a, 0xd3, 0x32, 0xcb, 0xca, 0xd5, 0xcd, 0xd4, 0x0a, 0x76, 0x8e, + 0x6b, 0xb1, 0x73, 0x68, 0x38, 0xf5, 0x73, 0xb2, 0x46, 0x7a, 0xb5, 0xff, + 0xea, 0x52, 0xc9, 0x5b, 0x56, 0xff, 0xf0, 0x35, 0x4b, 0xae, 0x88, 0x61, + 0x8a, 0x3c, 0xb9, 0x78, 0x1c, 0x51, 0xaa, 0x5d, 0xaf, 0xe0, 0xe7, 0x8c, + 0x03, 0x85, 0x6a, 0x1f, 0xca, 0xb9, 0x8c, 0xf4, 0x37, 0xea, 0xae, 0x54, + 0xf1, 0xb8, 0x4c, 0x94, 0x42, 0xcf, 0x2a, 0x8d, 0x13, 0xef, 0x66, 0xf8, + 0x1b, 0xbe, 0x5d, 0x9a, 0x24, 0x12, 0xb5, 0xe8, 0xe8, 0x44, 0x6b, 0x95, + 0xd6, 0xed, 0x98, 0xd8, 0x10, 0xeb, 0x19, 0xe5, 0x42, 0x01, 0xaa, 0x1c, + 0x6a, 0x62, 0xd2, 0xf0, 0xc3, 0x33, 0x4d, 0xf0, 0x3e, 0x76, 0x8d, 0xec, + 0xbb, 0xb9, 0xeb, 0x14, 0x77, 0x02, 0x39, 0xb7, 0x75, 0x21, 0x3a, 0xa5, + 0xef, 0x04, 0xb3, 0x20, 0x50, 0xaf, 0xed, 0x99, 0x0b, 0xec, 0x12, 0x6d, + 0xad, 0x9f, 0x23, 0x02, 0xc0, 0x01, 0x5a, 0xfe, 0xfc, 0xee, 0xa9, 0xc1, + 0x23, 0x51, 0x71, 0xb0, 0xe6, 0xee, 0xcc, 0xcd, 0x6a, 0x59, 0xcf, 0xad, + 0xff, 0x4b, 0x36, 0xbf, 0x2a, 0xaf, 0x56, 0xae, 0xd7, 0x35, 0x47, 0xc4, + 0x11, 0xef, 0x66, 0x18, 0xd1, 0xec, 0x2a, 0x5c, 0xca, 0xfe, 0x8f, 0x8b, + 0xa2, 0x80, 0x57, 0x42, 0xe5, 0xa5, 0xb4, 0x7a, 0x34, 0xd0, 0x1b, 0xca, + 0xb3, 0x7f, 0x2c, 0x54, 0x47, 0x50, 0xf0, 0xdd, 0xde, 0x87, 0xc0, 0x8f, + 0x3a, 0x79, 0x49, 0x50, 0xe9, 0x4a, 0xe2, 0x74, 0x08, 0x18, 0x61, 0xaa, + 0x17, 0xe4, 0x44, 0xdf, 0xeb, 0xf8, 0x2f, 0x5f, 0x06, 0x19, 0x06, 0x13, + 0xec, 0x14, 0x47, 0x04, 0x51, 0x03, 0x55, 0x62, 0x78, 0x73, 0x7d, 0xe9, + 0x15, 0xff, 0xd3, 0xb2, 0x5c, 0x54, 0x79, 0xca, 0x58, 0x10, 0x86, 0x66, + 0x4d, 0x6a, 0x73, 0x13, 0x20, 0x60, 0xd1, 0xaa, 0x54, 0xa8, 0xf3, 0x45, + 0x1c, 0x02, 0x23, 0xc6, 0x43, 0xee, 0xb4, 0xf4, 0xed, 0xa3, 0x59, 0xb7, + 0xb3, 0x4e, 0xda, 0xdf, 0x5f, 0x12, 0xed, 0xb0, 0x03, 0x93, 0xc7, 0xb7, + 0xa9, 0x52, 0xdb, 0x91, 0x39, 0x4f, 0x0d, 0x6d, 0x31, 0x08, 0xf5, 0x91, + 0x90, 0xe5, 0x11, 0xbf, 0x33, 0x4d, 0x3f, 0x7b, 0xc8, 0x46, 0xbf, 0x8f, + 0x27, 0x61, 0xc3, 0x6c, 0xea, 0xfa, 0xaf, 0xeb, 0x92, 0xd1, 0x86, 0xb4, + 0x50, 0x64, 0x6c, 0xba, 0xdf, 0x1f, 0xe9, 0xc6, 0x2f, 0xad, 0x8d, 0x95, + 0xe7, 0xfe, 0xcb, 0xbf, 0xcc, 0xba, 0xbd, 0xcc, 0x62, 0x85, 0x62, 0x7a, + 0x96, 0x85, 0x02, 0x1c, 0xc1, 0x8f, 0x4b, 0xfc, 0x4f, 0xea, 0x69, 0x8b, + 0x1c, 0x83, 0x81, 0x34, 0x15, 0x12, 0x16, 0x6f, 0x9c, 0x0e, 0xa4, 0x83, + 0xb6, 0x28, 0x2f, 0xd7, 0x6d, 0x2e, 0x98, 0x6a, 0xe7, 0x6f, 0x53, 0x83, + 0x18, 0x43, 0x75, 0x25, 0x97, 0x14, 0x15, 0x8d, 0x2f, 0x7f, 0x72, 0x1a, + 0x07, 0x42, 0x2a, 0x7a, 0xe4, 0x7e, 0xc4, 0x7a, 0x6a, 0xc9, 0x0f, 0xeb, + 0x4b, 0x60, 0x56, 0x15, 0x51, 0x23, 0x5d, 0xfa, 0x0e, 0x56, 0x06, 0x35, + 0x89, 0x89, 0x77, 0x55, 0xd3, 0xd7, 0x22, 0x2f, 0x41, 0xc5, 0x70, 0x3f, + 0x57, 0x80, 0xc6, 0xab, 0x30, 0x7e, 0xd8, 0x2b, 0xd2, 0xd2, 0xa2, 0xfc, + 0xf9, 0x32, 0x22, 0x9e, 0x63, 0x67, 0x8a, 0x55, 0xac, 0x4e, 0x66, 0x98, + 0xe6, 0x20, 0xea, 0xbd, 0x64, 0xe9, 0xd5, 0x06, 0x33, 0x33, 0xbf, 0xe2, + 0x89, 0x49, 0x91, 0x92, 0x4e, 0xf9, 0xcc, 0x23, 0xad, 0x26, 0x1a, 0xb1, + 0x01, 0x40, 0x9b, 0x3f, 0x30, 0x5c, 0x88, 0xaf, 0xce, 0x83, 0xc3, 0x45, + 0x90, 0xdc, 0xa6, 0x20, 0x3e, 0x15, 0x96, 0x25, 0xdf, 0xe1, 0xa6, 0xd6, + 0x78, 0xaf, 0xda, 0xc0, 0x0c, 0xf1, 0x21, 0x03, 0xf9, 0x7f, 0xb5, 0xfd, + 0x59, 0x20, 0x3d, 0x73, 0xad, 0xfb, 0x2b, 0x5f, 0x88, 0xbc, 0x17, 0xaf, + 0x1c, 0xaa, 0x5d, 0x17, 0x8f, 0xb7, 0x60, 0x9c, 0xc7, 0xc4, 0xe4, 0xf4, + 0xdb, 0xa9, 0x39, 0xb0, 0xd1, 0xb4, 0x6b, 0x4b, 0x20, 0xaf, 0xd5, 0xcc, + 0xd9, 0x68, 0x17, 0x4c, 0x9a, 0xd4, 0x35, 0x25, 0x17, 0x3b, 0xc3, 0x41, + 0x7b, 0x05, 0xe9, 0xe8, 0xdd, 0x02, 0x9d, 0x0f, 0x6a, 0xd7, 0xf5, 0xfa, + 0xae, 0xf2, 0x5b, 0xfe, 0xc4, 0x44, 0x62, 0xd6, 0xc4, 0x8e, 0x4b, 0x28, + 0x6a, 0x87, 0x3c, 0xe3, 0xf8, 0x01, 0xb5, 0xf9, 0x77, 0x4e, 0x07, 0x8f, + 0x40, 0x02, 0x72, 0x81, 0xa9, 0x6e, 0xa8, 0x84, 0x1f, 0xfe, 0x2e, 0x06, + 0x83, 0xb8, 0x14, 0x2b, 0xf8, 0x6e, 0x8b, 0xb2, 0xed, 0xff, 0xc5, 0x90, + 0x09, 0x86, 0xef, 0xe7, 0x64, 0xb3, 0x3f, 0x10, 0xe1, 0x47, 0xff, 0x4f, + 0xac, 0x76, 0x45, 0xa8, 0xba, 0xac, 0xab, 0x82, 0x07, 0x86, 0x8a, 0x24, + 0xf5, 0xc0, 0x01, 0x5f, 0x54, 0x8b, 0xdc, 0xbd, 0xd6, 0x28, 0x05, 0x56, + 0xfd, 0x13, 0xdf, 0x93, 0x9b, 0x68, 0x03, 0x90, 0x2c, 0x08, 0xcc, 0x0b, + 0xf9, 0x14, 0x44, 0x84, 0x79, 0x15, 0xab, 0xbc, 0x54, 0x1b, 0x76, 0xe3, + 0xfa, 0xf8, 0x32, 0xab, 0xf2, 0xcd, 0xed, 0x04, 0x15, 0x94, 0xb4, 0xb3, + 0xcc, 0x09, 0xf1, 0xb2, 0x35, 0x60, 0x0b, 0x05, 0xa1, 0x31, 0xd6, 0x6d, + 0xc6, 0x46, 0x6d, 0xe4, 0xe7, 0xbc, 0x5f, 0x3a, 0x72, 0xfd, 0x42, 0xb0, + 0x0e, 0xbb, 0xd2, 0xeb, 0x50, 0x26, 0x60, 0x38, 0xd6, 0x96, 0x1b, 0x5b, + 0x9d, 0xcc, 0xb4, 0x98, 0x9f, 0xe8, 0xf2, 0x95, 0xa3, 0x11, 0x9a, 0xcb, + 0x6d, 0x56, 0x87, 0x4b, 0x95, 0xb9, 0x41, 0xa3, 0x89, 0x2d, 0x2c, 0x29, + 0xe8, 0x29, 0x86, 0x47, 0x3e, 0x91, 0x2a, 0x59, 0x7d, 0x9c, 0x03, 0x9d, + 0x2d, 0xff, 0x05, 0x50, 0x21, 0x88, 0x12, 0x55, 0x2b, 0x25, 0x0c, 0x0c, + 0x59, 0xa9, 0x1f, 0xbd, 0x1c, 0xa0, 0xf9, 0xc2, 0x23, 0x4b, 0xaa, 0xbe, + 0x10, 0x4f, 0xf7, 0x5a, 0x25, 0x49, 0xb2, 0xc8, 0xdc, 0xf7, 0xb1, 0x45, + 0xdf, 0xbb, 0x15, 0xd9, 0x48, 0x49, 0x01, 0x27, 0xf6, 0xdc, 0x59, 0x48, + 0xb7, 0xd7, 0x5e, 0x46, 0xde, 0x2c, 0x27, 0x64, 0xf9, 0xc2, 0xc5, 0x37, + 0x21, 0x9a, 0xbf, 0x62, 0x14, 0xdd, 0x13, 0x26, 0x9f, 0x62, 0x65, 0x55, + 0xe8, 0xd7, 0x6f, 0x10, 0x5c, 0xd7, 0x19, 0x16, 0x1b, 0x87, 0xd3, 0x74, + 0xd2, 0x8a, 0x89, 0x15, 0x17, 0xd8, 0x83, 0x8f, 0x3f, 0x38, 0x98, 0x9b, + 0x25, 0x03, 0xc7, 0x7c, 0x35, 0x88, 0x53, 0x48, 0xca, 0xd6, 0x4d, 0x20, + 0x23, 0x54, 0x15, 0x51, 0xda, 0xfb, 0x7e, 0x41, 0xbc, 0x88, 0xf5, 0x53, + 0xf6, 0xe2, 0x54, 0xe6, 0xa8, 0xb1, 0x04, 0xac, 0xd1, 0xd6, 0x37, 0xd2, + 0xa9, 0x6f, 0x96, 0xc0, 0x6a, 0xb1, 0xd4, 0xcf, 0x1e, 0xda, 0xda, 0x72, + 0x43, 0xaa, 0x7b, 0x7d, 0x39, 0x19, 0x11, 0x06, 0x2a, 0x73, 0x87, 0xe6, + 0xdb, 0x8a, 0xcf, 0x66, 0xf2, 0x77, 0xc9, 0x0a, 0xe2, 0x13, 0x90, 0xd6, + 0x1b, 0xa6, 0xfb, 0xfd, 0xda, 0x63, 0x80, 0x81, 0x55, 0x7a, 0x4b, 0xea, + 0x79, 0x4d, 0xa9, 0x46, 0x2b, 0xb1, 0xa5, 0x98, 0x8d, 0x34, 0x32, 0x07, + 0xc6, 0xff, 0x98, 0x17, 0xd1, 0x55, 0x85, 0xc6, 0x8d, 0x0a, 0x3b, 0x58, + 0x1e, 0x82, 0x24, 0xa2, 0xef, 0x83, 0xed, 0xf6, 0xe2, 0x79, 0x1b, 0x2b, + 0x46, 0x7e, 0x94, 0x5b, 0xc8, 0x5a, 0x93, 0xef, 0xca, 0x76, 0xc7, 0xef, + 0x71, 0xce, 0x15, 0x33, 0x91, 0xef, 0x46, 0xa9, 0x58, 0xd8, 0x6d, 0xa9, + 0x47, 0x45, 0x35, 0xbb, 0xce, 0x96, 0xb7, 0x44, 0xd4, 0x7a, 0x90, 0xd4, + 0xcb, 0x18, 0xbc, 0x7b, 0x64, 0xf3, 0x8e, 0xf5, 0xd5, 0xf7, 0x82, 0xdb, + 0xff, 0xd6, 0x50, 0x17, 0xdf, 0x9a, 0x11, 0x75, 0x85, 0x36, 0xc8, 0x0c, + 0x44, 0xcc, 0xdc, 0x76, 0xfc, 0x9f, 0x3e, 0x84, 0x8f, 0xea, 0xc6, 0xb1, + 0xfa, 0x97, 0x75, 0x31, 0xe8, 0xc2, 0x81, 0x7b, 0x39, 0x14, 0xad, 0xdf, + 0x67, 0xf2, 0x44, 0xe0, 0xc4, 0x7a, 0x21, 0x63, 0x74, 0x73, 0x41, 0xf4, + 0xb5, 0xbd, 0x87, 0x36, 0xd0, 0x64, 0xb6, 0x8e, 0x98, 0xd2, 0x79, 0x5f, + 0x4d, 0x22, 0x8c, 0xc1, 0x41, 0x4c, 0xea, 0xb7, 0xab, 0x4b, 0x2e, 0xca, + 0x35, 0x14, 0xd3, 0x90, 0x9e, 0xd6, 0x94, 0x3e, 0x7e, 0xe4, 0x57, 0x09, + 0x22, 0x3c, 0xe6, 0xbe, 0x04, 0x95, 0x75, 0xf8, 0xe0, 0x42, 0xe9, 0xe2, + 0x5e, 0x2e, 0x2a, 0xc6, 0x48, 0x55, 0x42, 0x39, 0xc4, 0x81, 0x6a, 0xc6, + 0x19, 0xea, 0x4c, 0x63, 0x60, 0x11, 0xdf, 0xe7, 0xde, 0x4d, 0x0f, 0xec, + 0x0c, 0x8f, 0x21, 0xe7, 0x94, 0x72, 0x24, 0x4d, 0xc0, 0x44, 0x30, 0x63, + 0x18, 0x06, 0x9b, 0xb9, 0x63, 0xc2, 0x94, 0x6d, 0x78, 0xba, 0x36, 0x58, + 0xe3, 0x07, 0x0f, 0xd4, 0x16, 0xe5, 0xc7, 0x58, 0xb1, 0x5e, 0x96, 0x25, + 0x80, 0xc0, 0x0c, 0x4d, 0xf1, 0xda, 0x8b, 0xc6, 0x66, 0x56, 0x1e, 0x7c, + 0x64, 0x6b, 0x2c, 0xb2, 0x8c, 0xed, 0x07, 0xa7, 0x52, 0x70, 0xbd, 0x68, + 0xd3, 0x48, 0x18, 0x38, 0xa6, 0x60, 0x18, 0x97, 0x4a, 0xd0, 0x88, 0xed, + 0x4c, 0x99, 0xad, 0x88, 0x56, 0xec, 0x2b, 0xd7, 0xb4, 0xd6, 0xc6, 0x43, + 0x58, 0xf6, 0x9b, 0xfb, 0x28, 0xa7, 0xb4, 0xaa, 0x61, 0xc4, 0x09, 0x0b, + 0xa7, 0x51, 0x7a, 0xd3, 0x2f, 0x84, 0xeb, 0x9e, 0xc9, 0xc9, 0xac, 0x7e, + 0x80, 0x2e, 0xa6, 0x88, 0x84, 0xd2, 0x54, 0xca, 0xe6, 0xf1, 0x7c, 0x97, + 0x7c, 0x8a, 0x8a, 0x66, 0x7f, 0x00, 0x4b, 0x73, 0x3f, 0x2e, 0xfb, 0xcc, + 0xe5, 0x07, 0xe6, 0x4e, 0xa1, 0x8e, 0xfc, 0x62, 0xb7, 0xd7, 0xbe, 0xa4, + 0x4a, 0x65, 0xd7, 0xe2, 0xaa, 0x0c, 0xdd, 0x93, 0x93, 0x63, 0x56, 0x46, + 0xe5, 0xe5, 0xf5, 0x47, 0xb1, 0xe4, 0x4e, 0x60, 0x97, 0x83, 0x82, 0x23, + 0x84, 0x37, 0x20, 0xbd, 0xb5, 0x8b, 0x9d, 0x5d, 0xc8, 0xca, 0xe1, 0xa8, + 0x5a, 0xc4, 0xaa, 0xe2, 0x79, 0xda, 0x1d, 0x48, 0x60, 0x4c, 0x2e, 0x06, + 0x95, 0xb4, 0x76, 0x42, 0xa0, 0x6e, 0x52, 0x52, 0x0f, 0xf8, 0x24, 0x81, + 0x21, 0x6f, 0x67, 0x27, 0x9e, 0xe5, 0xf9, 0x9b, 0x8c, 0x82, 0x90, 0x90, + 0xdd, 0xe7, 0xd4, 0x24, 0x54, 0xa7, 0x26, 0x41, 0xd2, 0x54, 0x50, 0x6a, + 0x66, 0xf0, 0xd5, 0x68, 0xaf, 0xd1, 0xd2, 0x00, 0x66, 0xa1, 0x9e, 0x1b, + 0xab, 0xe6, 0x43, 0xa2, 0xb8, 0x05, 0x2f, 0xae, 0x9b, 0xce, 0x15, 0xa2, + 0x5b, 0xd1, 0xb5, 0x53, 0x66, 0x6e, 0xc9, 0x44, 0x7b, 0x8c, 0x5d, 0x94, + 0x63, 0x3c, 0xa5, 0xc5, 0x81, 0x48, 0xd7, 0x98, 0x6b, 0xb7, 0xce, 0xe4, + 0xd9, 0xaf, 0x1c, 0xa9, 0x76, 0x8c, 0x1b, 0x4b, 0x5c, 0x1e, 0x9c, 0x98, + 0xef, 0x74, 0x40, 0xe3, 0xf1, 0x48, 0x8c, 0x14, 0x66, 0xe4, 0x7d, 0xbd, + 0xff, 0xcf, 0xae, 0xf8, 0x36, 0x79, 0x83, 0x76, 0xe7, 0x66, 0x36, 0x12, + 0x60, 0x17, 0x2f, 0xb0, 0x2f, 0x22, 0x32, 0x4b, 0x42, 0x65, 0xed, 0x76, + 0x6e, 0x4c, 0x9d, 0xb9, 0x54, 0x9b, 0x98, 0x8b, 0x79, 0x8b, 0x0e, 0xaf, + 0x9c, 0x8c, 0xa9, 0x58, 0xaa, 0xa2, 0xde, 0x1a, 0x9b, 0x6d, 0x75, 0x0f, + 0xd2, 0xd4, 0x28, 0xdc, 0xca, 0xcd, 0x91, 0x66, 0xd0, 0xd9, 0xab, 0x3c, + 0x22, 0x55, 0x36, 0x87, 0x4f, 0x41, 0x24, 0x5c, 0xee, 0x5a, 0x54, 0x1a, + 0xe0, 0xf5, 0x2c, 0x01, 0x98, 0xa3, 0x54, 0x6e, 0x6f, 0xdc, 0x88, 0xf7, + 0x86, 0xba, 0xe2, 0x8d, 0x84, 0x95, 0x78, 0x84, 0x8c, 0xc1, 0xae, 0x8c, + 0x7f, 0xa7, 0x91, 0xbc, 0x6d, 0x3b, 0x48, 0x7a, 0x42, 0xa0, 0xc0, 0x0a, + 0xfe, 0xda, 0xbc, 0xe7, 0xa6, 0x76, 0xcb, 0xca, 0x68, 0xb0, 0xda, 0xb3, + 0x2e, 0x4c, 0x57, 0x50, 0xeb, 0xbb, 0x0a, 0x35, 0x94, 0x80, 0xab, 0xcf, + 0xa7, 0xdc, 0xab, 0x31, 0x54, 0xef, 0xe0, 0x77, 0xa5, 0x7e, 0x9e, 0x76, + 0x96, 0x62, 0x92, 0x25, 0xf1, 0xa1, 0xa5, 0x91, 0x06, 0x9e, 0x2f, 0x81, + 0xd8, 0x5f, 0x2e, 0xe4, 0xe8, 0xda, 0x9f, 0xe1, 0x62, 0xe1, 0x30, 0xd0, + 0x16, 0x02, 0xc6, 0xeb, 0x3a, 0x43, 0x4e, 0x64, 0x07, 0x77, 0xf2, 0xda, + 0x0d, 0xf5, 0xd3, 0x1c, 0x26, 0x4c, 0xcd, 0xa4, 0xb3, 0xc5, 0xd6, 0x73, + 0xb4, 0xbc, 0xc0, 0x07, 0x64, 0x98, 0xfb, 0xf6, 0x32, 0xe4, 0xe1, 0xca, + 0x74, 0x4c, 0x64, 0xad, 0x04, 0x53, 0x1b, 0x99, 0x24, 0x7b, 0x2e, 0xd7, + 0x3e, 0x07, 0xba, 0x7a, 0x08, 0x7b, 0xb1, 0xb0, 0x11, 0x3f, 0x4e, 0x66, + 0xd8, 0xa5, 0x4e, 0x72, 0x67, 0xa6, 0xbe, 0x38, 0x76, 0xcf, 0x72, 0x07, + 0x9a, 0x57, 0x2f, 0x29, 0x6d, 0x55, 0xcd, 0x69, 0xed, 0xcf, 0x59, 0x5e, + 0xd9, 0xe5, 0x29, 0x5b, 0xd0, 0x4d, 0x85, 0xea, 0x44, 0x0c, 0xac, 0x2d, + 0x76, 0x28, 0x65, 0x39, 0x2a, 0xfc, 0x9f, 0xe8, 0xd8, 0xce, 0x5c, 0x56, + 0xc0, 0x33, 0xa4, 0xcc, 0x32, 0xa6, 0x00, 0xd8, 0x9d, 0x9d, 0x0a, 0x28, + 0x27, 0x15, 0x42, 0x8e, 0xeb, 0xb0, 0xef, 0x6f, 0xb8, 0x93, 0xe2, 0xdf, + 0x6e, 0x17, 0x46, 0x67, 0x59, 0x05, 0x92, 0xad, 0x87, 0xc6, 0x06, 0x35, + 0xc8, 0x4c, 0x05, 0x1c, 0x9f, 0xf4, 0xa4, 0xa4, 0xa1, 0x8d, 0x11, 0xc7, + 0xab, 0x4b, 0x9b, 0x3a, 0x71, 0xcb, 0x2d, 0x1f, 0xec, 0x61, 0xa0, 0x66, + 0x5f, 0x3d, 0xa3, 0x95, 0x39, 0x7f, 0x98, 0x34, 0x79, 0x32, 0x15, 0x94, + 0xa0, 0x16, 0xa4, 0xf3, 0x45, 0x7b, 0x31, 0xfe, 0xf2, 0xe3, 0x65, 0x01, + 0xc1, 0xf7, 0xcd, 0xcb, 0x59, 0x52, 0xbb, 0xf6, 0xa4, 0x12, 0x22, 0x9e, + 0x5f, 0xd0, 0x50, 0x8a, 0x43, 0x62, 0xfd, 0x22, 0x21, 0xfb, 0xae, 0x08, + 0x57, 0xc7, 0x00, 0xa6, 0x48, 0x2e, 0xcb, 0x0b, 0x76, 0x08, 0xf9, 0xd4, + 0x14, 0x9a, 0xb5, 0xcd, 0xb8, 0x33, 0xc3, 0x0d, 0x2a, 0x3a, 0xf0, 0xe2, + 0x5f, 0x0e, 0x1f, 0xa1, 0x1c, 0x71, 0x38, 0x2e, 0x8e, 0x93, 0x13, 0x27, + 0xa2, 0x4a, 0xdc, 0x95, 0x1e, 0x26, 0x30, 0x5f, 0xdd, 0xc4, 0x15, 0x8e, + 0xa8, 0xfd, 0x80, 0xf4, 0x9e, 0x31, 0x80, 0xc9, 0xa0, 0xf7, 0x61, 0xb5, + 0x55, 0x40, 0xb4, 0x7f, 0xd8, 0xb2, 0x6b, 0x58, 0xba, 0x34, 0xba, 0x78, + 0xa0, 0xee, 0xa2, 0xc4, 0x73, 0x19, 0xc7, 0xdf, 0x1b, 0x46, 0x3c, 0xe0, + 0x7c, 0xb3, 0xf9, 0x7c, 0x35, 0xd5, 0xf0, 0xbf, 0x2c, 0xed, 0xa4, 0x20, + 0x95, 0x0b, 0x05, 0x7a, 0xce, 0xdc, 0x81, 0x95, 0xf3, 0x12, 0x8a, 0x7f, + 0xcb, 0xa8, 0xdc, 0x77, 0xbf, 0x8b, 0xdf, 0xf6, 0xb0, 0xce, 0xce, 0x0b, + 0xdf, 0xe9, 0xcf, 0x92, 0x02, 0x20, 0x82, 0x81, 0x9c, 0x03, 0x72, 0xe8, + 0x41, 0x6b, 0xbe, 0xb6, 0x87, 0x8b, 0xf9, 0x9e, 0x49, 0x77, 0xc5, 0xcf, + 0x73, 0x9d, 0xf6, 0x1c, 0x42, 0x7c, 0xa8, 0xbb, 0xe3, 0x24, 0x70, 0x9f, + 0xef, 0x28, 0xce, 0x45, 0x13, 0x13, 0x5f, 0xad, 0x02, 0x2a, 0xb4, 0x14, + 0x80, 0x66, 0xe1, 0x6b, 0x29, 0x72, 0x77, 0xa3, 0x04, 0x36, 0x28, 0x8d, + 0xc6, 0x39, 0xa3, 0x29, 0x59, 0xbf, 0x1e, 0x69, 0xcc, 0x8f, 0x25, 0x28, + 0xb8, 0x24, 0x7c, 0xea, 0xe9, 0x4c, 0x43, 0x6e, 0x6c, 0x7b, 0x1d, 0x41, + 0x7f, 0xd9, 0xd9, 0x59, 0x1e, 0x45, 0x76, 0xcc, 0x26, 0x6e, 0xe1, 0x80, + 0x73, 0x4d, 0x79, 0x3c, 0x5c, 0x1d, 0x78, 0xf3, 0xf9, 0x75, 0x2c, 0x9d, + 0x9d, 0x8e, 0x90, 0x23, 0xf3, 0xf9, 0xd7, 0x68, 0x14, 0xf3, 0x09, 0x2f, + 0xa1, 0x86, 0xb1, 0x9d, 0xe2, 0x3c, 0xd3, 0x16, 0xc4, 0xdf, 0x7c, 0xcf, + 0xc5, 0xf2, 0x3e, 0x67, 0x8b, 0xc8, 0x3e, 0x23, 0x17, 0xbf, 0x75, 0x1e, + 0xf3, 0x35, 0xee, 0x9f, 0x14, 0xae, 0xc1, 0x5b, 0xe7, 0x92, 0x68, 0xb8, + 0x0f, 0x95, 0x67, 0x1b, 0x55, 0xe7, 0x90, 0x6f, 0x72, 0xa0, 0x78, 0xd2, + 0x57, 0xca, 0x0a, 0x92, 0x62, 0x8d, 0x20, 0x52, 0x84, 0xb3, 0xae, 0x8e, + 0x22, 0x3d, 0x36, 0x3a, 0xfe, 0x68, 0x2d, 0x89, 0x8f, 0x51, 0x5b, 0x87, + 0x87, 0x21, 0x69, 0x1a, 0x90, 0x97, 0x9e, 0x2f, 0x91, 0xae, 0x32, 0x17, + 0x08, 0x0b, 0x3e, 0x65, 0x8a, 0xaa, 0x8e, 0xf3, 0x7b, 0x43, 0xc4, 0x2d, + 0x05, 0xac, 0x7a, 0xd9, 0x29, 0x41, 0xf8, 0x80, 0x64, 0x99, 0x98, 0xc3, + 0xb8, 0x4b, 0x4a, 0x4b, 0x48, 0x2a, 0xbd, 0x38, 0x42, 0x3a, 0xf1, 0x67, + 0x03, 0x1d, 0xd8, 0x00, 0x50, 0xc9, 0xce, 0x3a, 0x34, 0xe5, 0xac, 0x5f, + 0x36, 0x55, 0xf4, 0xf2, 0xa6, 0x09, 0x04, 0x20, 0x64, 0x56, 0xa1, 0x15, + 0x65, 0x4d, 0x07, 0x7e, 0x47, 0xf7, 0x34, 0x30, 0x3a, 0xbe, 0x49, 0xc1, + 0x75, 0xa3, 0x7d, 0xe5, 0x0e, 0xba, 0xdf, 0x81, 0xc0, 0x94, 0xf8, 0xec, + 0x1d, 0x81, 0x63, 0x48, 0x12, 0x16, 0x82, 0x12, 0x8b, 0x2a, 0xf7, 0x6e, + 0x23, 0xa4, 0x11, 0x8b, 0x70, 0xb3, 0x8a, 0xce, 0xd0, 0xdf, 0xc4, 0x6f, + 0x65, 0x01, 0xe4, 0x6e, 0x61, 0x58, 0x78, 0x2a, 0x4b, 0x9a, 0x1b, 0x65, + 0x94, 0xc4, 0xc5, 0x9d, 0x95, 0xc6, 0x12, 0x6f, 0xfc, 0x8a, 0x5e, 0x7f, + 0xc8, 0xbe, 0xa9, 0xf0, 0x65, 0xb9, 0xa7, 0xe5, 0xa9, 0x39, 0xc3, 0x7a, + 0x79, 0x05, 0x72, 0x77, 0x1f, 0xf7, 0x2b, 0x29, 0xf5, 0xb9, 0xce, 0x20, + 0x82, 0x01, 0x21, 0xa0, 0x0c, 0xd5, 0x7c, 0x7b, 0xe5, 0x9a, 0xea, 0xdb, + 0x71, 0xa6, 0xef, 0x57, 0xca, 0x0d, 0x55, 0x3e, 0x3c, 0x9e, 0xac, 0x6c, + 0x18, 0x4e, 0xe9, 0xc4, 0x67, 0x00, 0x1d, 0xc3, 0xf6, 0x88, 0x9d, 0xd5, + 0xb4, 0x1a, 0xa8, 0xde, 0xfa, 0x8c, 0xe8, 0xb5, 0x8a, 0xec, 0x6c, 0x94, + 0x62, 0x63, 0x00, 0xaf, 0x8a, 0x91, 0x4b, 0x1b, 0x01, 0x90, 0x72, 0xa5, + 0x0a, 0x03, 0x50, 0xc7, 0x0d, 0x66, 0xaf, 0xca, 0xae, 0xe5, 0x7f, 0x00, + 0x00, 0x01, 0x0a +}; + +void h264_get_video_info(VideoDecodeInfo *info) +{ + info->profile = GST_VAAPI_PROFILE_H264_MAIN; + info->width = H264_CLIP_WIDTH; + info->height = H264_CLIP_HEIGHT; + info->data = h264_clip; + info->data_size = H264_CLIP_DATA_SIZE; +} diff --git a/tests/test-h264.h b/tests/test-h264.h new file mode 100644 index 0000000..93b79ca --- /dev/null +++ b/tests/test-h264.h @@ -0,0 +1,30 @@ +/* + * test-h264.h - H.264 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#ifndef TEST_H264_H +#define TEST_H264_H + +#include +#include "test-decode.h" + +void h264_get_video_info(VideoDecodeInfo *info); + +#endif /* TEST_H264_H */ diff --git a/tests/test-jpeg.c b/tests/test-jpeg.c new file mode 100644 index 0000000..ab7aff0 --- /dev/null +++ b/tests/test-jpeg.c @@ -0,0 +1,2080 @@ +/* + * test-jpeg.c - JPEG test data + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#include "test-jpeg.h" + +#define JPEG_CLIP_WIDTH 320 +#define JPEG_CLIP_HEIGHT 240 +#define JPEG_CLIP_DATA_SIZE 24481 + +/* Data dump of a 320x240 VC-1 video clip (jpeg.raw), it has a single frame */ +static const guchar jpeg_clip[JPEG_CLIP_DATA_SIZE] = { + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, + 0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43, + 0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04, 0x04, 0x05, + 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, + 0x0b, 0x09, 0x0c, 0x11, 0x0f, 0x12, 0x12, 0x11, 0x0f, 0x11, 0x11, 0x13, + 0x16, 0x1c, 0x17, 0x13, 0x14, 0x1a, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, + 0x1a, 0x1d, 0x1d, 0x1f, 0x1f, 0x1f, 0x13, 0x17, 0x22, 0x24, 0x22, 0x1e, + 0x24, 0x1c, 0x1e, 0x1f, 0x1e, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x05, 0x05, + 0x05, 0x07, 0x06, 0x07, 0x0e, 0x08, 0x08, 0x0e, 0x1e, 0x14, 0x11, 0x14, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01, 0x40, 0x03, + 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00, + 0x1d, 0x00, 0x00, 0x02, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x03, 0x06, 0x07, 0x02, + 0x08, 0x01, 0x00, 0x09, 0xff, 0xc4, 0x00, 0x43, 0x10, 0x00, 0x02, 0x01, + 0x03, 0x02, 0x04, 0x04, 0x05, 0x02, 0x04, 0x03, 0x07, 0x03, 0x04, 0x03, + 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x11, 0x00, 0x21, 0x06, 0x12, 0x31, + 0x41, 0x13, 0x22, 0x51, 0x61, 0x07, 0x14, 0x32, 0x71, 0x81, 0x91, 0xa1, + 0x15, 0x23, 0x42, 0xb1, 0x52, 0xc1, 0xd1, 0x08, 0x24, 0x33, 0x62, 0xe1, + 0xf0, 0xf1, 0x16, 0x43, 0x72, 0x25, 0x26, 0x34, 0x82, 0x17, 0x53, 0x83, + 0x93, 0xff, 0xc4, 0x00, 0x19, 0x01, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, + 0x00, 0x01, 0x04, 0x05, 0xff, 0xc4, 0x00, 0x2b, 0x11, 0x00, 0x02, 0x02, + 0x01, 0x04, 0x02, 0x02, 0x02, 0x01, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x11, 0x03, 0x04, 0x12, 0x21, 0x31, 0x22, 0x41, + 0x13, 0x32, 0x05, 0x51, 0x14, 0x23, 0x42, 0x61, 0x33, 0x52, 0x91, 0xb1, + 0xc1, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, + 0x00, 0x3f, 0x00, 0xcc, 0xb8, 0xce, 0xf5, 0x70, 0x83, 0x8b, 0x2f, 0x40, + 0x79, 0xe2, 0x4b, 0x8c, 0xe8, 0x17, 0xd8, 0x48, 0xdf, 0xe9, 0xa8, 0x2d, + 0xbc, 0x52, 0xa1, 0xb3, 0x2d, 0x34, 0xa8, 0x00, 0xc1, 0xc2, 0x67, 0x6f, + 0x5f, 0xdb, 0x53, 0xf1, 0x9d, 0x08, 0x97, 0x8b, 0xef, 0x72, 0x0d, 0xc7, + 0xcf, 0xcf, 0xb7, 0x4f, 0xfd, 0xc3, 0xa4, 0x33, 0x47, 0x15, 0x0d, 0x1c, + 0xac, 0x55, 0x89, 0x70, 0x42, 0xb7, 0x4c, 0x1c, 0xf4, 0xd6, 0x13, 0x97, + 0x3f, 0xb3, 0x2d, 0x74, 0xfc, 0x6f, 0xc3, 0xe1, 0xc2, 0xbd, 0x4c, 0x8a, + 0x71, 0x82, 0x5a, 0x3c, 0x63, 0x56, 0x4b, 0x1f, 0x10, 0xf0, 0xfd, 0x7b, + 0xaa, 0x0b, 0xa5, 0x2a, 0xf3, 0x79, 0x40, 0x69, 0x00, 0x39, 0xfc, 0xeb, + 0x13, 0xf0, 0x62, 0x7e, 0x5e, 0x65, 0x00, 0xb6, 0xdb, 0x6b, 0xa1, 0x48, + 0x88, 0x4a, 0x82, 0x36, 0xf6, 0xd4, 0xb7, 0xec, 0x1d, 0x87, 0xa5, 0xae, + 0x57, 0x24, 0x8b, 0x84, 0x2a, 0x28, 0x28, 0xcd, 0x34, 0x8a, 0xb3, 0x2b, + 0x19, 0xe3, 0x91, 0x5c, 0x91, 0x83, 0xb6, 0xdd, 0x35, 0x41, 0xba, 0xd7, + 0x25, 0x35, 0xbe, 0x69, 0xb0, 0x43, 0x46, 0xa4, 0xe7, 0x3e, 0xc7, 0x59, + 0xcf, 0x0d, 0x41, 0x39, 0xba, 0x2c, 0x71, 0xd4, 0xcb, 0x1c, 0x64, 0x67, + 0x0a, 0xdb, 0x67, 0x3e, 0x9a, 0x7f, 0x7c, 0xba, 0x25, 0x45, 0x9a, 0xb2, + 0xdf, 0x24, 0x85, 0x6a, 0xb2, 0x10, 0x77, 0xe7, 0x5c, 0xf5, 0x3e, 0x9d, + 0x34, 0x8d, 0x9f, 0x17, 0x3f, 0xb2, 0x64, 0x85, 0xd3, 0x33, 0xfa, 0xd9, + 0xcd, 0x5d, 0x4b, 0xd4, 0x33, 0x12, 0xd2, 0x31, 0x6e, 0xbe, 0xa7, 0x3a, + 0x6b, 0xc3, 0x7c, 0x9f, 0xf0, 0xd9, 0xca, 0x9e, 0x6c, 0xfd, 0xf4, 0x0b, + 0xdb, 0xe6, 0x4f, 0x30, 0x4d, 0xb3, 0xd3, 0x4d, 0xf8, 0x76, 0x13, 0x1c, + 0xab, 0x24, 0x83, 0x03, 0x9f, 0x97, 0xec, 0x74, 0x68, 0x7a, 0xe8, 0xbc, + 0xd8, 0x69, 0xa9, 0xa3, 0x9c, 0x9d, 0x98, 0x95, 0x07, 0x61, 0x81, 0xbe, + 0xfd, 0x34, 0xf2, 0xa9, 0x20, 0x82, 0x21, 0x24, 0xd8, 0x8c, 0x75, 0x43, + 0x8c, 0xef, 0xdb, 0x48, 0xa8, 0x9d, 0x92, 0xea, 0xaa, 0x47, 0x2a, 0x34, + 0x60, 0x07, 0xf5, 0x20, 0x7a, 0x6a, 0xc5, 0x27, 0x87, 0x24, 0x2f, 0x05, + 0x41, 0xcc, 0x6c, 0x31, 0xd3, 0x4e, 0x42, 0x19, 0x58, 0xbe, 0xc5, 0x35, + 0x5c, 0x6b, 0x24, 0xbc, 0xde, 0x2c, 0x24, 0xb2, 0x8c, 0x90, 0x0f, 0xb6, + 0xda, 0x87, 0x83, 0x2e, 0xa2, 0x5b, 0x8c, 0x94, 0xd2, 0xc9, 0xbb, 0x6d, + 0x8c, 0x6c, 0xac, 0x31, 0xb0, 0xd3, 0xca, 0xea, 0x4e, 0x68, 0x1f, 0xc2, + 0x66, 0x78, 0xd4, 0x1f, 0x38, 0x19, 0x03, 0xd8, 0xea, 0x92, 0xb4, 0xb2, + 0xd3, 0x5f, 0x84, 0xb1, 0x1e, 0x53, 0xf5, 0x67, 0xdc, 0x77, 0xd5, 0x9a, + 0xb1, 0x3d, 0xd1, 0xda, 0x5d, 0x38, 0xc4, 0xc1, 0x1d, 0x8a, 0xa4, 0xd4, + 0xc5, 0xe2, 0xa0, 0x1d, 0x39, 0x72, 0x47, 0xb8, 0xf7, 0xd5, 0x52, 0x86, + 0xd7, 0x6e, 0x8e, 0x18, 0xea, 0xa0, 0xb9, 0x20, 0x9a, 0x51, 0x85, 0xa7, + 0x64, 0x6e, 0x6f, 0x5d, 0xfd, 0x35, 0x77, 0x85, 0xc5, 0x5d, 0x2a, 0x3b, + 0x90, 0x4b, 0x27, 0xf3, 0x36, 0xf6, 0xd6, 0x69, 0x55, 0x55, 0x24, 0xb7, + 0x29, 0x62, 0x81, 0x3f, 0x9b, 0x03, 0x98, 0x99, 0xf9, 0x80, 0x07, 0x07, + 0x18, 0xfb, 0x9c, 0x6a, 0x07, 0x81, 0x26, 0x9c, 0x18, 0xc9, 0x6a, 0x39, + 0xeb, 0xa3, 0x82, 0x86, 0x6f, 0x1a, 0x76, 0x7e, 0x54, 0x0a, 0xb8, 0xdf, + 0xed, 0xab, 0x5d, 0x3d, 0x38, 0xa1, 0x52, 0xe6, 0xa6, 0x29, 0x2e, 0x52, + 0x0c, 0x73, 0xf2, 0x73, 0x01, 0x26, 0x73, 0x80, 0x7d, 0x14, 0x6f, 0xf8, + 0xd7, 0x1c, 0x23, 0x6d, 0x82, 0x0a, 0x46, 0xa8, 0xa7, 0xa7, 0xcd, 0x5c, + 0x91, 0xff, 0x00, 0x31, 0x07, 0xd4, 0x89, 0xb6, 0xd9, 0xec, 0x31, 0xd4, + 0xf7, 0xd4, 0xf4, 0xd5, 0x4d, 0x15, 0x73, 0xd4, 0x49, 0x1a, 0xd5, 0x33, + 0x29, 0x8d, 0x40, 0x5c, 0x0f, 0xfe, 0x2a, 0xbb, 0xe3, 0xef, 0xdf, 0x03, + 0x52, 0x97, 0xa1, 0xeb, 0x0c, 0x62, 0x2b, 0x96, 0x2a, 0x98, 0xea, 0x2a, + 0x4c, 0x93, 0x4b, 0x3b, 0x2a, 0x33, 0x4c, 0x4b, 0x60, 0x06, 0x3f, 0x4f, + 0x31, 0xf5, 0x39, 0xce, 0x3b, 0x69, 0x61, 0x3e, 0x74, 0xa8, 0x8f, 0x0c, + 0x8a, 0x70, 0x37, 0xc7, 0x37, 0xdb, 0xdb, 0x53, 0xde, 0xc4, 0xbc, 0xe5, + 0xa4, 0x51, 0x0c, 0x21, 0xcf, 0x88, 0x13, 0xe9, 0x5c, 0x12, 0x06, 0x74, + 0x38, 0x65, 0x91, 0x55, 0xa2, 0x45, 0x58, 0x97, 0x60, 0x1b, 0xea, 0xfb, + 0x0f, 0x6c, 0xff, 0x00, 0xa6, 0xa0, 0xcd, 0xa0, 0xb5, 0x28, 0xd3, 0x32, + 0xac, 0x3c, 0xa5, 0xe4, 0x7c, 0x28, 0x0b, 0xe6, 0xc9, 0xd7, 0x70, 0xc6, + 0x60, 0x79, 0x21, 0x90, 0xf3, 0xf8, 0x7f, 0x4b, 0x0e, 0x80, 0xff, 0x00, + 0xde, 0xfa, 0xea, 0xb4, 0x55, 0x53, 0xd7, 0x37, 0x38, 0x0a, 0xe1, 0x41, + 0x1c, 0xbe, 0x50, 0xb9, 0xdf, 0x61, 0xa8, 0x22, 0xcc, 0x91, 0xba, 0x9d, + 0x98, 0xb9, 0x63, 0xef, 0xbe, 0xa1, 0x36, 0x8e, 0xf8, 0x5a, 0x08, 0xaa, + 0xee, 0x71, 0xa5, 0x6c, 0xf2, 0x45, 0x4e, 0x5c, 0xb4, 0x92, 0x20, 0x04, + 0xa8, 0x03, 0x3b, 0x0f, 0xbe, 0x34, 0xce, 0xb5, 0x6c, 0x86, 0xa9, 0x84, + 0x92, 0x48, 0xa8, 0xe3, 0x9c, 0x4a, 0xa3, 0x94, 0x31, 0xef, 0xb7, 0xf9, + 0xe9, 0x47, 0x0b, 0xc6, 0x2a, 0x0d, 0x42, 0x24, 0xca, 0xb2, 0x02, 0x07, + 0x23, 0x6d, 0x90, 0x3b, 0xe7, 0x4e, 0xe7, 0xa2, 0xf0, 0xe8, 0x5a, 0xa2, + 0xa4, 0x0e, 0x48, 0xce, 0xc0, 0xf5, 0x3f, 0x6d, 0x26, 0x53, 0x51, 0x97, + 0x26, 0x1c, 0xb1, 0x79, 0x1f, 0x04, 0x7c, 0x35, 0x4d, 0x40, 0x2f, 0x52, + 0x34, 0x51, 0xc8, 0xcb, 0xe1, 0x16, 0x46, 0x77, 0xc8, 0x27, 0x9b, 0x6d, + 0xbf, 0x1a, 0xb0, 0x52, 0xda, 0xcd, 0x69, 0x92, 0xae, 0xb7, 0x3e, 0x00, + 0x25, 0x82, 0xe3, 0xf7, 0xd5, 0x52, 0xdb, 0x71, 0x88, 0xcc, 0x4c, 0x50, + 0xb4, 0x2a, 0xad, 0xb4, 0x85, 0xb7, 0x1e, 0xf8, 0xd5, 0x8e, 0xa6, 0xf3, + 0x5e, 0xd6, 0x7a, 0x81, 0x4a, 0x91, 0xc8, 0xdc, 0xbc, 0x85, 0x97, 0xfa, + 0x57, 0xa1, 0x3a, 0xc1, 0x9b, 0x0e, 0x4c, 0xb2, 0xdd, 0x01, 0x19, 0x31, + 0xc9, 0x3a, 0xa1, 0x35, 0xc6, 0xf9, 0x68, 0xfe, 0x16, 0xca, 0xb4, 0xfe, + 0x13, 0xb4, 0x8d, 0xc9, 0x18, 0x39, 0x63, 0xd8, 0x12, 0x7b, 0x0c, 0x01, + 0xaa, 0x25, 0x7d, 0x52, 0xb5, 0x67, 0x8e, 0xb1, 0x85, 0x93, 0x94, 0x28, + 0x20, 0xe4, 0x80, 0x3a, 0x81, 0xa3, 0x2a, 0xa3, 0xa7, 0x2c, 0xdc, 0xa4, + 0xb7, 0x2e, 0xd9, 0xf4, 0xf6, 0xd2, 0xba, 0x88, 0xcb, 0xca, 0xbc, 0x83, + 0x7c, 0xe3, 0x5b, 0x63, 0x8f, 0x64, 0x52, 0xb0, 0x94, 0x47, 0x91, 0x99, + 0xa8, 0x7c, 0x09, 0xa1, 0xa8, 0x61, 0x04, 0xe8, 0x32, 0xbf, 0xe1, 0xce, + 0x08, 0x03, 0xdb, 0x56, 0x9a, 0x6a, 0x51, 0x53, 0x4a, 0x23, 0xa7, 0x5f, + 0xe7, 0x8f, 0xe6, 0x28, 0x27, 0x0a, 0x70, 0x37, 0xcf, 0xbe, 0x33, 0xa0, + 0xac, 0xd4, 0xf1, 0xf8, 0x54, 0xa9, 0x38, 0x60, 0xa2, 0x24, 0x0d, 0xca, + 0x33, 0xd4, 0x01, 0x9d, 0x59, 0xb8, 0xd2, 0xd3, 0x45, 0xc3, 0x95, 0x74, + 0xb0, 0xd0, 0xd7, 0x23, 0x89, 0x69, 0x23, 0x95, 0xd9, 0x58, 0x33, 0x07, + 0x61, 0xb8, 0xdb, 0xfe, 0x9d, 0x74, 0xc2, 0xf7, 0x15, 0xc6, 0xc7, 0x55, + 0x18, 0x53, 0xb8, 0x1e, 0x9e, 0xda, 0x1e, 0x3a, 0x5a, 0x58, 0xe6, 0x92, + 0x72, 0xaa, 0xae, 0xf9, 0xe6, 0x62, 0x7a, 0x92, 0x73, 0xa9, 0xa3, 0xff, + 0x00, 0x84, 0x06, 0x73, 0xe8, 0x71, 0xa1, 0xee, 0x0e, 0xb1, 0xdb, 0x65, + 0x24, 0x02, 0x4b, 0x80, 0x06, 0xa7, 0x6e, 0x80, 0xa3, 0xae, 0x5c, 0x9f, + 0x2e, 0x08, 0xf5, 0x07, 0x5f, 0x79, 0x0e, 0x71, 0xa5, 0xb4, 0x15, 0x92, + 0x52, 0x55, 0x29, 0x18, 0xe4, 0x66, 0xc3, 0x7e, 0x74, 0xff, 0x00, 0xc1, + 0x1e, 0x28, 0x65, 0x3d, 0x57, 0xa9, 0xef, 0xa7, 0x55, 0x3a, 0x0a, 0x82, + 0x28, 0x61, 0x0f, 0x42, 0xfb, 0xf3, 0x1c, 0x15, 0x0b, 0xf8, 0xd2, 0xbf, + 0xe1, 0x61, 0x79, 0x39, 0x0a, 0x1c, 0x80, 0x5c, 0xfa, 0x67, 0xb6, 0x9f, + 0xdb, 0x14, 0xa5, 0x34, 0x9c, 0x87, 0x07, 0x7d, 0x72, 0x88, 0x42, 0xfb, + 0xe9, 0x30, 0x7e, 0x4c, 0x18, 0xbe, 0x40, 0xa8, 0x69, 0x4a, 0x44, 0x63, + 0x8d, 0x41, 0x39, 0x27, 0xf1, 0xa6, 0x56, 0xda, 0x39, 0x1a, 0x60, 0x3b, + 0x91, 0x80, 0x35, 0x6d, 0xf8, 0x4d, 0x69, 0xb1, 0x5c, 0x78, 0xba, 0x2a, + 0x6e, 0x21, 0x93, 0x92, 0x8e, 0x48, 0x5f, 0xff, 0x00, 0x73, 0xc3, 0x1c, + 0xfb, 0x10, 0x0b, 0x7a, 0x75, 0xd6, 0x87, 0x3f, 0xc2, 0xca, 0xb8, 0xde, + 0x6a, 0xeb, 0x40, 0x59, 0xa0, 0x8a, 0x46, 0x11, 0x46, 0xc7, 0xcc, 0xca, + 0x0e, 0xc5, 0x4f, 0x7d, 0xb4, 0x53, 0x77, 0xe3, 0xfb, 0x2b, 0x63, 0x7d, + 0x06, 0xfc, 0x2a, 0x5e, 0x1e, 0x6b, 0x3c, 0x34, 0x17, 0xaa, 0x01, 0xe2, + 0x46, 0x00, 0xf9, 0x82, 0x4f, 0x2f, 0x41, 0xb1, 0xdf, 0x6d, 0x58, 0xef, + 0x50, 0x7c, 0x36, 0x9a, 0x9a, 0x5a, 0x19, 0xe9, 0x12, 0x71, 0xbe, 0xf1, + 0x46, 0xc5, 0x94, 0xf4, 0xc8, 0x27, 0xd3, 0xf3, 0xa5, 0x1c, 0x2d, 0x62, + 0xa4, 0x7a, 0x29, 0x4d, 0xc6, 0xbe, 0x3b, 0x7f, 0x82, 0x71, 0x22, 0x49, + 0x80, 0xd9, 0xea, 0x73, 0x9f, 0xce, 0x9e, 0xd2, 0xdd, 0x38, 0x0e, 0xd4, + 0x04, 0x00, 0xa5, 0x5b, 0x05, 0xc3, 0x49, 0xe1, 0x19, 0x33, 0xf9, 0xc6, + 0x3f, 0x4d, 0x66, 0xd3, 0xe3, 0xcd, 0x1b, 0x5b, 0x52, 0xff, 0x00, 0x23, + 0x31, 0x6e, 0x4a, 0x9a, 0x46, 0x79, 0x71, 0xf8, 0x67, 0xc3, 0x55, 0xb0, + 0x3d, 0x45, 0x97, 0x89, 0x54, 0xd4, 0xf5, 0x5a, 0x6a, 0xa5, 0x0a, 0x48, + 0xf4, 0xc8, 0xef, 0xd3, 0x48, 0x2d, 0xdc, 0x05, 0x56, 0xd5, 0xb4, 0xf6, + 0xea, 0x9a, 0x39, 0x56, 0x6a, 0x99, 0x00, 0x47, 0xe4, 0x21, 0x4a, 0xe7, + 0xb1, 0xef, 0xb6, 0xb7, 0xbb, 0x47, 0x14, 0xf0, 0x9d, 0x64, 0x89, 0x47, + 0x4d, 0x24, 0x30, 0x92, 0xdc, 0xa8, 0x92, 0x40, 0x10, 0x13, 0xe8, 0x36, + 0xc6, 0x75, 0x64, 0x9c, 0x42, 0x90, 0x88, 0xcb, 0x47, 0x12, 0x9d, 0xb7, + 0x20, 0x01, 0xae, 0x87, 0xc7, 0xb9, 0x72, 0x37, 0xe1, 0xbf, 0x67, 0xf3, + 0x9f, 0x8a, 0x2a, 0x64, 0x8f, 0x8c, 0xb8, 0x82, 0x30, 0xfc, 0xa9, 0xfc, + 0x4a, 0xa4, 0xed, 0xdc, 0xf8, 0xad, 0xa4, 0x97, 0x3a, 0xc7, 0x89, 0x92, + 0x27, 0x84, 0x32, 0x32, 0x73, 0x37, 0x9b, 0x1b, 0x9e, 0x87, 0x56, 0xdb, + 0xf5, 0xad, 0x62, 0xe2, 0xeb, 0xe5, 0x55, 0x44, 0x8c, 0xfe, 0x25, 0xc6, + 0xa5, 0x95, 0x7b, 0x00, 0x64, 0x63, 0xaa, 0x1d, 0xd6, 0x56, 0x9e, 0xbe, + 0x57, 0x41, 0xcc, 0x39, 0x88, 0x51, 0xe8, 0x35, 0x9c, 0xcd, 0x3f, 0xb3, + 0x24, 0xa3, 0x2f, 0x35, 0x6a, 0x4b, 0x08, 0x29, 0xcb, 0xdf, 0xae, 0xfa, + 0x26, 0xe0, 0xd1, 0x73, 0xaa, 0x02, 0x39, 0xb3, 0x83, 0x83, 0xfe, 0x5a, + 0x5d, 0x12, 0x4a, 0x57, 0x94, 0x61, 0x79, 0x8f, 0x73, 0xa2, 0x23, 0x49, + 0x04, 0xa2, 0x05, 0xf3, 0x3e, 0x36, 0x3f, 0xf5, 0xd4, 0x08, 0xb0, 0xf0, + 0xcc, 0x4b, 0x4c, 0x79, 0xd8, 0x6d, 0x30, 0xc0, 0x3e, 0xfa, 0x87, 0x89, + 0x68, 0xbc, 0x1b, 0x87, 0x88, 0xd1, 0xb0, 0xf1, 0x94, 0x30, 0x24, 0x75, + 0xd4, 0x31, 0x5c, 0x66, 0xf1, 0xe1, 0xa1, 0x47, 0xc4, 0x68, 0x06, 0x40, + 0x1d, 0x70, 0x37, 0xfd, 0x74, 0xc2, 0xfb, 0x4e, 0xe6, 0x18, 0xdf, 0x9d, + 0x98, 0xc5, 0x91, 0xbf, 0xf8, 0x4e, 0x08, 0x1a, 0x0c, 0x9c, 0x2a, 0x2e, + 0x5d, 0x08, 0xe0, 0x85, 0xe5, 0x90, 0xc2, 0xbb, 0x93, 0xd0, 0x68, 0x8a, + 0x75, 0x64, 0xa6, 0x32, 0x28, 0xf3, 0x83, 0x8d, 0xba, 0x1f, 0x43, 0xa1, + 0xe9, 0x25, 0x10, 0xdc, 0x12, 0x5c, 0xe0, 0x86, 0xf2, 0x9f, 0x7d, 0x3d, + 0xa6, 0xa4, 0x92, 0x76, 0x03, 0x99, 0x10, 0xb6, 0xe4, 0x1f, 0x7d, 0x54, + 0x45, 0xa0, 0x1a, 0x2a, 0x8a, 0x85, 0x98, 0x4c, 0x67, 0x22, 0x44, 0x3c, + 0xc4, 0x9d, 0xf5, 0x75, 0xa3, 0xaf, 0x59, 0xa2, 0x8d, 0xe1, 0x95, 0x24, + 0x57, 0x50, 0x7d, 0xc1, 0xf4, 0xc6, 0xab, 0xb2, 0x70, 0xed, 0xc3, 0xc4, + 0x63, 0x17, 0x86, 0xc9, 0xca, 0x49, 0x3c, 0xdd, 0xb5, 0xf6, 0xcb, 0x47, + 0x35, 0x34, 0xe9, 0x1a, 0x48, 0x4a, 0x44, 0xaf, 0xe2, 0xc6, 0xaf, 0x8d, + 0xce, 0x0e, 0x7e, 0xda, 0x6f, 0xd4, 0xd0, 0xb1, 0x6f, 0xa4, 0x59, 0x12, + 0xf7, 0x14, 0x15, 0x5e, 0x11, 0x3c, 0xc3, 0x18, 0x75, 0xec, 0x74, 0x6d, + 0x96, 0x0a, 0x58, 0xee, 0xa6, 0x48, 0x54, 0x2c, 0x75, 0x28, 0x59, 0x73, + 0xb8, 0xcf, 0x70, 0x74, 0x92, 0x8a, 0x4a, 0x0a, 0x8a, 0x59, 0x96, 0x7f, + 0x0e, 0x9e, 0xad, 0xd8, 0xb4, 0x0f, 0xfe, 0x21, 0xfe, 0x1f, 0xef, 0xfa, + 0x68, 0xae, 0x1a, 0x92, 0x49, 0xa8, 0xe5, 0x12, 0x48, 0xce, 0x12, 0x5f, + 0x26, 0xfd, 0x0f, 0xa8, 0xd2, 0x66, 0xf7, 0x0b, 0x71, 0xae, 0x03, 0x78, + 0x86, 0x9a, 0xa2, 0x9a, 0x17, 0xa5, 0xb5, 0x43, 0xfc, 0xc6, 0x89, 0xb9, + 0x14, 0x1e, 0xe7, 0x7d, 0xbf, 0xd3, 0x59, 0xc5, 0x9a, 0x92, 0x15, 0xa7, + 0x8e, 0x26, 0x86, 0x46, 0xac, 0xf1, 0x49, 0x98, 0xb6, 0xd8, 0x39, 0xdf, + 0x27, 0xb6, 0x0f, 0x6d, 0x6c, 0x54, 0x6a, 0x95, 0x02, 0x29, 0x65, 0x24, + 0xca, 0x23, 0xfa, 0x86, 0xc7, 0x39, 0xdf, 0xfb, 0x7e, 0xfa, 0xab, 0x71, + 0x8d, 0x25, 0x35, 0x3d, 0xd1, 0xe7, 0x76, 0x31, 0xc1, 0x30, 0xf1, 0x58, + 0x29, 0xfa, 0xe4, 0x1b, 0x15, 0xfc, 0xee, 0x7f, 0x1a, 0xac, 0x19, 0x29, + 0xb1, 0xd8, 0x1f, 0x20, 0xaf, 0x5c, 0x69, 0x21, 0x45, 0x3e, 0x49, 0x1c, + 0x0f, 0x0c, 0x46, 0xdb, 0x10, 0x47, 0x5c, 0x0c, 0x02, 0xc7, 0xae, 0x4f, + 0x4d, 0x75, 0x44, 0xf1, 0x07, 0x0e, 0xc0, 0xa3, 0xa3, 0x06, 0x96, 0x51, + 0x21, 0x27, 0x1f, 0xe0, 0x5f, 0xb9, 0xfe, 0xda, 0x46, 0x6a, 0x67, 0x92, + 0x59, 0x26, 0xa7, 0x79, 0x23, 0x55, 0xd8, 0x21, 0xfa, 0x98, 0x74, 0xeb, + 0x8d, 0x1d, 0x0d, 0x4c, 0x8a, 0x64, 0x91, 0x89, 0x42, 0x1b, 0x99, 0x54, + 0x11, 0xb9, 0xfc, 0x7d, 0xf5, 0xa4, 0xdf, 0x10, 0x5b, 0xcc, 0x6a, 0x79, + 0x1d, 0x97, 0x9a, 0x10, 0xac, 0x47, 0xaa, 0xef, 0xa5, 0xb4, 0xcc, 0xd2, + 0x4a, 0x22, 0x2c, 0xa8, 0xe7, 0xb4, 0x87, 0x1b, 0x7a, 0xe7, 0x4d, 0x4c, + 0xae, 0xf5, 0x45, 0x98, 0x02, 0x5c, 0x73, 0x1f, 0x4d, 0xf7, 0xd7, 0xeb, + 0x7c, 0xd1, 0x2c, 0x35, 0x08, 0xd4, 0xc7, 0x92, 0x6c, 0x2b, 0x33, 0x0e, + 0x60, 0xbb, 0xef, 0xbf, 0x6e, 0xdf, 0xa6, 0xa1, 0x05, 0xb2, 0x24, 0xb8, + 0x25, 0xc9, 0x25, 0x8f, 0x36, 0xfa, 0x82, 0xae, 0xa5, 0x29, 0x60, 0x0c, + 0x06, 0xe3, 0x1f, 0xae, 0x8d, 0xb8, 0x47, 0x1c, 0x55, 0x07, 0xc2, 0xa9, + 0x2c, 0x87, 0x3c, 0xa7, 0xaa, 0x8f, 0x63, 0xe9, 0xa4, 0xb7, 0xa6, 0x32, + 0x4e, 0x90, 0x73, 0x0c, 0x28, 0xe6, 0x38, 0xf5, 0xd4, 0x02, 0x7e, 0x28, + 0xf9, 0x4b, 0x70, 0x9a, 0x9a, 0xbd, 0xaa, 0x11, 0xbc, 0x8d, 0x91, 0x8e, + 0xc7, 0xef, 0xab, 0x62, 0x55, 0x25, 0xca, 0x89, 0x57, 0xc5, 0x63, 0x4e, + 0x76, 0x92, 0x32, 0x7a, 0x7a, 0x7e, 0x87, 0x1a, 0xa4, 0x26, 0x54, 0x95, + 0xd5, 0x9b, 0x85, 0xff, 0x00, 0xfc, 0x57, 0x1e, 0xa7, 0x4a, 0x66, 0x7c, + 0x55, 0xbd, 0x26, 0x7e, 0xa9, 0x53, 0x4f, 0x51, 0x1c, 0x4a, 0xcc, 0x6a, + 0x89, 0xdc, 0x93, 0x84, 0xe5, 0xf7, 0xd3, 0x2a, 0x74, 0x96, 0x4a, 0x69, + 0x97, 0xc4, 0x09, 0x19, 0x19, 0x24, 0xf4, 0xeb, 0xa5, 0x15, 0x33, 0x78, + 0x26, 0xbd, 0xa6, 0xe6, 0x66, 0x7c, 0x2a, 0x38, 0xfe, 0x91, 0xe9, 0xa6, + 0x7e, 0x1b, 0x25, 0xa6, 0x09, 0x26, 0x24, 0x73, 0xa0, 0x0c, 0x73, 0xd7, + 0x1f, 0xf8, 0xd1, 0x35, 0xd3, 0x1f, 0xac, 0xc7, 0xfd, 0x35, 0x21, 0x64, + 0xe9, 0x0a, 0x8c, 0x46, 0x79, 0xc0, 0xdb, 0x9b, 0xdf, 0x51, 0x59, 0xe9, + 0x7e, 0x66, 0xf5, 0x0a, 0x15, 0xca, 0x2b, 0x73, 0xb6, 0xfd, 0x86, 0x88, + 0x48, 0x8c, 0xaa, 0x4c, 0x43, 0x2b, 0xbe, 0xda, 0x71, 0xc3, 0x76, 0xe9, + 0x21, 0xfe, 0x7b, 0xaf, 0x99, 0xdb, 0x39, 0xf6, 0xd1, 0x98, 0x10, 0xe2, + 0xa5, 0x39, 0xa5, 0x2c, 0xa7, 0xa0, 0x03, 0x41, 0xd5, 0x40, 0x85, 0x9e, + 0x37, 0xce, 0x64, 0xe5, 0xc1, 0x27, 0xa1, 0x3a, 0x32, 0x5c, 0x78, 0x87, + 0x1d, 0x73, 0xa8, 0xfe, 0x5c, 0xcd, 0x59, 0xe1, 0xc8, 0xab, 0x24, 0x52, + 0x27, 0x9c, 0x1f, 0x4c, 0x63, 0x1f, 0xdb, 0x41, 0x3a, 0xf6, 0x00, 0x3d, + 0x45, 0x24, 0x94, 0xf2, 0x98, 0x88, 0xc1, 0xf5, 0xd4, 0xd3, 0xda, 0xfc, + 0x68, 0x52, 0x96, 0x45, 0x67, 0x86, 0x68, 0xc4, 0xa1, 0xb3, 0x83, 0xcd, + 0xdc, 0x7d, 0x86, 0xa6, 0xb9, 0xd3, 0xc9, 0xcf, 0x12, 0xc0, 0xbe, 0x45, + 0xc0, 0x03, 0xd1, 0x40, 0xe9, 0xa6, 0x75, 0x17, 0xa9, 0x85, 0x9e, 0x92, + 0x8d, 0x59, 0x55, 0x0b, 0xb6, 0x58, 0x0d, 0x94, 0xf4, 0x0a, 0x4f, 0xed, + 0xa4, 0x2c, 0x91, 0x95, 0x32, 0x14, 0xca, 0x5b, 0x44, 0x95, 0xf5, 0x1c, + 0xbc, 0x8e, 0xa2, 0x36, 0xc1, 0x77, 0x1d, 0x48, 0xd5, 0xba, 0x9a, 0xdb, + 0x24, 0x86, 0x2a, 0x68, 0x91, 0x9d, 0xdb, 0x08, 0x8b, 0xcb, 0xb9, 0x3e, + 0x9a, 0x8e, 0x3a, 0xe9, 0xe1, 0x26, 0x07, 0x44, 0x56, 0x2d, 0x8c, 0x95, + 0xdf, 0x4c, 0xa8, 0x3c, 0x29, 0x1a, 0x28, 0xea, 0x64, 0x78, 0xd9, 0x66, + 0x59, 0x04, 0x88, 0x3a, 0x01, 0xdb, 0xef, 0xd3, 0xf4, 0xd3, 0x3e, 0x47, + 0x77, 0x22, 0x16, 0x9b, 0x27, 0x04, 0x45, 0x2d, 0xbd, 0xda, 0x69, 0x2b, + 0xe9, 0xeb, 0x60, 0x89, 0xd9, 0xa9, 0xa3, 0xa5, 0x32, 0xe4, 0x8c, 0xee, + 0x4e, 0x40, 0x51, 0xb6, 0xa9, 0x74, 0xf4, 0xed, 0xcc, 0x55, 0xb1, 0xe5, + 0xd6, 0xf3, 0x5b, 0x61, 0x9a, 0xff, 0x00, 0x60, 0xf9, 0xee, 0x1c, 0xe3, + 0x79, 0x6a, 0x65, 0x31, 0x05, 0x96, 0x92, 0x47, 0x11, 0x07, 0x00, 0x64, + 0xae, 0x07, 0x43, 0xee, 0x73, 0x9c, 0x1d, 0xf5, 0x4b, 0xe0, 0x4b, 0x7d, + 0x96, 0x3b, 0xe4, 0x53, 0xf1, 0x0d, 0x34, 0x86, 0x28, 0x58, 0x23, 0x44, + 0x98, 0x0a, 0xc4, 0x11, 0xe6, 0x3e, 0xa3, 0xed, 0xff, 0x00, 0x4d, 0x0f, + 0xd2, 0x7e, 0x5e, 0xca, 0xa6, 0x9a, 0xbf, 0x62, 0xab, 0x4f, 0x0f, 0x57, + 0xc1, 0x43, 0x4b, 0x75, 0xaa, 0xa6, 0x78, 0xa9, 0xaa, 0x8f, 0x2d, 0x3c, + 0xa4, 0xec, 0xe0, 0x75, 0xfd, 0xf5, 0xe8, 0xcf, 0x86, 0xb7, 0x29, 0x2b, + 0xb8, 0x6e, 0x18, 0xa6, 0x6c, 0xcd, 0x4c, 0x04, 0x6d, 0xee, 0xb8, 0xf2, + 0x9f, 0xd3, 0x4c, 0xab, 0xed, 0x96, 0xdb, 0xcd, 0x84, 0x51, 0xa2, 0x45, + 0xf2, 0x92, 0xc4, 0xa6, 0x06, 0x88, 0x00, 0x14, 0x63, 0x2a, 0x57, 0x1d, + 0x34, 0x2f, 0x06, 0xd9, 0xaa, 0x2c, 0xf4, 0xf3, 0x47, 0x55, 0x22, 0x49, + 0x24, 0x8c, 0x30, 0xcb, 0xdd, 0x54, 0x60, 0x67, 0xdf, 0x1a, 0xd7, 0x8e, + 0x1b, 0x65, 0xb8, 0xd7, 0x0c, 0x7b, 0x58, 0x48, 0xe1, 0xfb, 0x79, 0xbc, + 0xcd, 0x72, 0x7a, 0x68, 0x24, 0x69, 0x54, 0x64, 0x32, 0x03, 0xca, 0xc3, + 0xb8, 0xcf, 0xaf, 0xf9, 0x68, 0xf8, 0x68, 0x69, 0x61, 0x04, 0x45, 0x4d, + 0x02, 0x02, 0x72, 0x71, 0x18, 0x19, 0x3a, 0x23, 0x7d, 0x55, 0x38, 0xeb, + 0x8b, 0xa0, 0xe1, 0xe8, 0x8c, 0x08, 0x04, 0x95, 0xae, 0xb9, 0x44, 0xcf, + 0xd2, 0x3d, 0x4e, 0x9d, 0x63, 0x5d, 0x25, 0x6c, 0x0f, 0x8e, 0x78, 0x6e, + 0xeb, 0x53, 0x23, 0xd7, 0x58, 0xaa, 0x42, 0x54, 0x4a, 0x04, 0x6f, 0x0b, + 0x72, 0x85, 0x2a, 0x06, 0xc5, 0x72, 0x30, 0x0e, 0x7b, 0xfb, 0xeb, 0x14, + 0xe3, 0x19, 0x78, 0x8a, 0x9e, 0xe5, 0xf2, 0xf7, 0xa7, 0xaa, 0x15, 0x51, + 0x6c, 0x04, 0xec, 0x58, 0x72, 0xf6, 0x03, 0x7c, 0x6a, 0xfd, 0x6e, 0xe2, + 0x7f, 0x88, 0x57, 0x27, 0x15, 0x16, 0xda, 0x69, 0x6a, 0x62, 0x0f, 0xbf, + 0xf2, 0x70, 0x9f, 0xf8, 0xd7, 0x5c, 0x6b, 0x6a, 0xe3, 0xae, 0x2e, 0xa4, + 0xa3, 0x82, 0xb6, 0xcb, 0x49, 0x4f, 0xf2, 0xef, 0xce, 0x24, 0x59, 0x57, + 0x3b, 0x8c, 0x1c, 0x8e, 0x62, 0x7d, 0xfa, 0x6a, 0xb7, 0x19, 0x9a, 0x8e, + 0x4e, 0x8f, 0x34, 0x71, 0x50, 0xf1, 0x38, 0x92, 0xec, 0xb9, 0xc0, 0x35, + 0x53, 0x2f, 0xea, 0xe7, 0x59, 0x84, 0x71, 0x73, 0x49, 0x22, 0xe7, 0x04, + 0x31, 0xdf, 0x5a, 0x5f, 0x15, 0x48, 0xe9, 0xc4, 0xd7, 0x99, 0x1a, 0x36, + 0x58, 0x23, 0xab, 0x97, 0x2c, 0x47, 0x52, 0x64, 0x3d, 0x35, 0x9f, 0x53, + 0x52, 0xd4, 0x2d, 0x1b, 0xd6, 0x3a, 0xaa, 0xc5, 0x25, 0x43, 0x04, 0xf3, + 0x79, 0xba, 0x9e, 0xda, 0xc9, 0x36, 0xab, 0x83, 0x3c, 0xfe, 0xcc, 0x85, + 0x56, 0x35, 0x04, 0x18, 0xcb, 0x39, 0xdb, 0x39, 0xfd, 0xf5, 0x24, 0x23, + 0xc3, 0x8d, 0x99, 0x8e, 0xfd, 0x0f, 0xbe, 0x88, 0x86, 0x9f, 0xc4, 0x26, + 0x42, 0x3c, 0xa8, 0x32, 0x75, 0xc3, 0x46, 0x67, 0x94, 0x3b, 0x82, 0x91, + 0x2f, 0x4d, 0xb3, 0xb6, 0x84, 0xa3, 0x9a, 0x05, 0x06, 0xba, 0x29, 0x58, + 0x75, 0x70, 0x18, 0xfd, 0xce, 0xa7, 0xbf, 0x57, 0xbc, 0xd7, 0x45, 0x46, + 0x93, 0x09, 0x0c, 0x62, 0x12, 0x40, 0xd8, 0x90, 0x49, 0xce, 0x84, 0xab, + 0x7c, 0x05, 0xf0, 0xf6, 0x03, 0x6d, 0x07, 0x2e, 0x49, 0xcf, 0xeb, 0xa5, + 0x86, 0xb8, 0x54, 0x4b, 0x3c, 0xb1, 0x4e, 0x08, 0x40, 0x4e, 0x07, 0x36, + 0x74, 0xe7, 0x87, 0xa6, 0x9a, 0xa6, 0x9d, 0x8c, 0x7b, 0xc9, 0x4e, 0x07, + 0x36, 0xfd, 0x06, 0x90, 0x40, 0xb8, 0x32, 0x30, 0xe8, 0x50, 0xff, 0x00, + 0x96, 0xaf, 0x1c, 0x07, 0x4e, 0x23, 0xb4, 0xbc, 0xb2, 0x79, 0x44, 0x8d, + 0x91, 0xb7, 0x5d, 0x1c, 0x08, 0x13, 0x41, 0x73, 0xe5, 0x0b, 0xce, 0xd8, + 0xf3, 0x6c, 0x74, 0x25, 0x45, 0xc6, 0x9d, 0x24, 0xb8, 0xcf, 0x1c, 0x73, + 0xc8, 0xd1, 0x48, 0xac, 0x44, 0x5d, 0x48, 0xd9, 0x48, 0xc7, 0xa0, 0x38, + 0xd2, 0xcb, 0x95, 0x3c, 0xd4, 0xb7, 0x59, 0x24, 0x15, 0x29, 0x35, 0x20, + 0x93, 0x9c, 0x28, 0x18, 0x3e, 0xbc, 0xb9, 0xec, 0x75, 0xfa, 0xd5, 0x5f, + 0x25, 0x0c, 0x73, 0xac, 0x30, 0xa8, 0x59, 0xf7, 0x04, 0xef, 0x91, 0xe9, + 0xa6, 0x3e, 0x43, 0x53, 0xa7, 0x63, 0x08, 0x2e, 0x10, 0x57, 0x94, 0x9a, + 0x5a, 0x42, 0x7f, 0x9b, 0xc8, 0x5f, 0xc3, 0xce, 0xfe, 0xa7, 0xfd, 0x75, + 0x6a, 0xb4, 0x52, 0xcf, 0x35, 0x72, 0x3a, 0x55, 0xf8, 0x74, 0xb1, 0x27, + 0x99, 0x00, 0xc7, 0x30, 0xed, 0x8d, 0xf6, 0xd5, 0x0a, 0x20, 0x83, 0x3c, + 0x9e, 0x54, 0x24, 0x92, 0x80, 0xec, 0x09, 0x39, 0x3a, 0xb8, 0x70, 0xf5, + 0x47, 0x3d, 0x02, 0xc5, 0xcf, 0xba, 0x80, 0x31, 0xed, 0xdb, 0x48, 0x71, + 0xe6, 0x8b, 0x94, 0xf7, 0x16, 0xd8, 0x04, 0xe0, 0xbb, 0xc2, 0x79, 0xe3, + 0x62, 0x40, 0xef, 0x81, 0xe8, 0x75, 0xf1, 0xa9, 0x1e, 0x48, 0x8c, 0x35, + 0x51, 0x2b, 0x21, 0x1f, 0x4b, 0x0c, 0x82, 0x34, 0x9a, 0xe6, 0x2e, 0x12, + 0xd9, 0x8c, 0x56, 0xfa, 0xa6, 0x86, 0x74, 0xf3, 0x01, 0xda, 0x4f, 0xf9, + 0x4f, 0xb7, 0x6d, 0x7d, 0xb1, 0x5c, 0xea, 0x2a, 0xad, 0xbe, 0x2c, 0x0e, + 0x60, 0xa8, 0x21, 0x83, 0x20, 0x3d, 0x18, 0x1c, 0x11, 0xfa, 0xea, 0x2c, + 0x39, 0x12, 0xab, 0x12, 0xa1, 0x6a, 0xc1, 0xae, 0xbc, 0x22, 0x99, 0xf1, + 0x6d, 0x93, 0x78, 0x0c, 0x09, 0x26, 0x36, 0x3e, 0x56, 0x07, 0xa8, 0x1a, + 0xac, 0xbc, 0x33, 0x51, 0xce, 0x52, 0x60, 0xd0, 0xbf, 0x39, 0x5f, 0x04, + 0x8c, 0x96, 0x00, 0xf4, 0xfb, 0x1f, 0x5d, 0x5c, 0xe8, 0xb8, 0x88, 0x21, + 0xf9, 0x6b, 0xcb, 0x2a, 0xcc, 0x84, 0xf8, 0xa0, 0x0c, 0xba, 0x8e, 0xcd, + 0x8f, 0xea, 0x07, 0xae, 0xbe, 0x71, 0x9d, 0x95, 0x6f, 0xf6, 0xea, 0x5a, + 0x9a, 0x09, 0xd7, 0xc7, 0x8b, 0x78, 0xa4, 0x4e, 0x92, 0x0f, 0x42, 0x7b, + 0x68, 0xa3, 0x36, 0xbe, 0xcc, 0xd3, 0xa7, 0xc9, 0x2c, 0x7c, 0x48, 0xa2, + 0xd6, 0xca, 0x5e, 0x4e, 0x45, 0x26, 0x08, 0x49, 0xca, 0xef, 0x9e, 0xfd, + 0x34, 0x4d, 0xe7, 0xc3, 0xa7, 0xa5, 0x58, 0x39, 0xd5, 0xe4, 0x75, 0xc9, + 0x03, 0x62, 0xbf, 0x8d, 0x09, 0x52, 0xe4, 0x43, 0x25, 0x1d, 0x50, 0x6f, + 0x1a, 0x17, 0xc4, 0x6a, 0xe3, 0x0d, 0x11, 0x07, 0x7c, 0xff, 0x00, 0xae, + 0xa0, 0xb9, 0x97, 0x79, 0x12, 0x69, 0x25, 0x67, 0x79, 0x06, 0x58, 0x9e, + 0xb9, 0xd3, 0xce, 0x92, 0xe5, 0x59, 0x02, 0xb3, 0x3c, 0x8a, 0x07, 0xd3, + 0xf4, 0x9c, 0xe8, 0x2a, 0xf4, 0x31, 0xb4, 0x8d, 0x9c, 0xef, 0x80, 0x71, + 0xe9, 0xdb, 0x47, 0x40, 0xb9, 0x46, 0x61, 0xf5, 0x76, 0xd1, 0xf6, 0xdb, + 0x1c, 0x97, 0xc9, 0x79, 0x96, 0x64, 0xa7, 0x8e, 0x22, 0x64, 0x9e, 0x46, + 0xec, 0xa0, 0xe3, 0xf5, 0x3a, 0x19, 0xc9, 0x46, 0x2e, 0x4c, 0xc9, 0xa8, + 0xe9, 0x15, 0xda, 0x0a, 0x67, 0xaa, 0x91, 0x55, 0x06, 0xed, 0xb9, 0x3e, + 0x9a, 0xb9, 0x51, 0xdb, 0x65, 0x86, 0xdc, 0xa9, 0x19, 0x08, 0xc7, 0xbe, + 0x3a, 0xe8, 0x8b, 0x6d, 0x3d, 0xb2, 0x28, 0xe6, 0x36, 0xb2, 0x1c, 0x09, + 0x44, 0x63, 0xcd, 0x92, 0xd9, 0xd5, 0xda, 0xa6, 0xca, 0xd4, 0xfc, 0x25, + 0x4a, 0xf2, 0x14, 0xf1, 0x9a, 0x56, 0xf2, 0xe7, 0x7c, 0xb6, 0xe3, 0x6f, + 0xd7, 0x59, 0x33, 0x6a, 0x16, 0x2a, 0xbf, 0x62, 0x31, 0x64, 0x58, 0xe6, + 0x9b, 0x33, 0x35, 0xa4, 0x96, 0x66, 0x82, 0x8d, 0x90, 0xb9, 0x33, 0x90, + 0x40, 0xf4, 0xcf, 0xae, 0xae, 0x37, 0xdb, 0x34, 0xaf, 0x6a, 0xf9, 0x11, + 0x16, 0x39, 0x23, 0x00, 0x7d, 0xc6, 0x35, 0x3a, 0x58, 0xea, 0x63, 0xf0, + 0x2b, 0x17, 0xfe, 0x32, 0xb8, 0x21, 0x40, 0xdc, 0x6c, 0x7b, 0xfa, 0xfb, + 0x6b, 0xb9, 0x78, 0x90, 0xd2, 0x31, 0xa7, 0xaf, 0xa7, 0x2f, 0x0c, 0x47, + 0x1e, 0x2c, 0x6b, 0xe6, 0x66, 0x1e, 0xda, 0x44, 0xf3, 0x4b, 0x23, 0x4f, + 0x13, 0xe8, 0x7f, 0xe4, 0x33, 0x47, 0x22, 0xac, 0x6e, 0xd0, 0x8e, 0x9e, + 0xc9, 0xf2, 0x74, 0x86, 0x77, 0x41, 0x95, 0x19, 0x6d, 0xb7, 0xc7, 0xae, + 0x8c, 0xa1, 0x96, 0x2f, 0x94, 0x59, 0x0b, 0x79, 0x1b, 0xa1, 0xc6, 0x98, + 0x55, 0x5f, 0x53, 0xc2, 0x47, 0x36, 0xc9, 0x96, 0x49, 0x90, 0x98, 0xd2, + 0x43, 0xca, 0x59, 0x7d, 0x4e, 0xda, 0x22, 0xc7, 0x60, 0xab, 0x9e, 0xde, + 0x93, 0x25, 0x20, 0x82, 0x09, 0x14, 0x4a, 0xbc, 0xfe, 0x52, 0xca, 0x73, + 0x83, 0x8e, 0xac, 0x36, 0x38, 0x3e, 0xc7, 0x5b, 0x74, 0xd3, 0x9c, 0xbe, + 0xc6, 0x0c, 0x49, 0xfb, 0x2a, 0x95, 0xb7, 0xba, 0x6f, 0x9c, 0x6a, 0x3a, + 0x5e, 0x71, 0x3f, 0xd2, 0x24, 0x65, 0xc2, 0x83, 0xdf, 0xef, 0xa6, 0x7c, + 0x3c, 0x87, 0xe5, 0x5e, 0x49, 0x01, 0xf1, 0x41, 0xf3, 0x16, 0x18, 0x3c, + 0xbd, 0x8e, 0x35, 0xdf, 0x11, 0xda, 0x61, 0xc1, 0x8a, 0x78, 0x44, 0xad, + 0xcf, 0x91, 0x85, 0xc1, 0x23, 0xd3, 0x3a, 0xfa, 0x9e, 0x05, 0x02, 0x88, + 0x69, 0xe5, 0xa9, 0x91, 0x7c, 0x24, 0x88, 0x09, 0x76, 0xe5, 0xee, 0x47, + 0xe0, 0xe4, 0x68, 0xb5, 0x18, 0x9d, 0xd2, 0x18, 0xe2, 0xab, 0x83, 0xa9, + 0xa6, 0x91, 0xe4, 0x25, 0x5f, 0xe9, 0xd9, 0x7d, 0xf1, 0xa6, 0x91, 0xd0, + 0xd1, 0x85, 0x5a, 0x84, 0x60, 0x8b, 0x3e, 0x25, 0x0b, 0x9c, 0x05, 0x63, + 0x8e, 0x6c, 0x67, 0xbe, 0x46, 0x92, 0x48, 0x09, 0xf2, 0x29, 0xc1, 0x03, + 0x3a, 0x7d, 0x5f, 0x6b, 0xf0, 0x69, 0xe9, 0x92, 0xbe, 0x12, 0x95, 0x31, + 0xc6, 0xac, 0x87, 0x39, 0xc0, 0x2a, 0x08, 0x3f, 0xbe, 0xb3, 0x4d, 0x52, + 0xab, 0xa1, 0x32, 0x74, 0x45, 0xc4, 0x10, 0xd3, 0xb3, 0xc3, 0x55, 0x4d, + 0x23, 0x4b, 0xcd, 0xb3, 0xf3, 0x30, 0x24, 0x37, 0x7c, 0xfe, 0x83, 0xf4, + 0xd7, 0x74, 0x12, 0x52, 0xca, 0x82, 0x29, 0x1c, 0x09, 0x06, 0x06, 0xfd, + 0x34, 0x2c, 0xce, 0xca, 0xe1, 0x0e, 0x32, 0x57, 0x25, 0xc0, 0xdd, 0xbd, + 0x33, 0xa1, 0x95, 0x17, 0xc4, 0x75, 0x63, 0xb9, 0x39, 0x07, 0x53, 0x6e, + 0xf8, 0x51, 0x1f, 0x45, 0xda, 0xc9, 0x6e, 0xa8, 0xa8, 0x12, 0xad, 0x2c, + 0x4e, 0x59, 0x50, 0x15, 0x58, 0x50, 0xb9, 0x63, 0xef, 0x8e, 0x9d, 0x33, + 0xa7, 0xb6, 0xae, 0x1f, 0xe2, 0x53, 0x22, 0x1a, 0x7b, 0x65, 0x53, 0x97, + 0xc1, 0x52, 0xd1, 0x15, 0x18, 0xf7, 0x27, 0x4f, 0x7e, 0x0f, 0x71, 0x1c, + 0x56, 0x9e, 0x12, 0xa8, 0xad, 0x8e, 0x8d, 0xdd, 0x68, 0xd9, 0x52, 0xb3, + 0xc2, 0x4e, 0x63, 0xbe, 0x79, 0x5c, 0xfe, 0x32, 0x33, 0xdb, 0xf3, 0xab, + 0xec, 0xdc, 0x61, 0x59, 0x3d, 0x96, 0x7a, 0xaa, 0x2a, 0x38, 0x9f, 0x9d, + 0x39, 0xa0, 0x2d, 0x9c, 0x0d, 0xf0, 0x79, 0x94, 0xfe, 0x4e, 0x85, 0x69, + 0xe3, 0x35, 0xcc, 0xa9, 0x95, 0xf1, 0xc2, 0xae, 0x4c, 0x17, 0x80, 0x38, + 0xaa, 0x7a, 0x4b, 0x55, 0x35, 0x0d, 0xca, 0x95, 0x95, 0x10, 0x94, 0x12, + 0x73, 0x67, 0x90, 0x0e, 0xc7, 0x6d, 0x68, 0xf0, 0xcb, 0x1c, 0xd1, 0x2c, + 0xb1, 0x38, 0x74, 0x61, 0x95, 0x20, 0xec, 0x75, 0x90, 0xd0, 0xf1, 0x7d, + 0xa9, 0x69, 0x4d, 0x15, 0x55, 0x15, 0x0b, 0xd4, 0x16, 0x69, 0x48, 0x4d, + 0x83, 0x39, 0xea, 0x48, 0xc7, 0xa9, 0xd0, 0x75, 0x9c, 0x57, 0x79, 0x85, + 0xfc, 0x6a, 0x6a, 0xd5, 0xa5, 0x45, 0x3b, 0x45, 0x1a, 0x0f, 0x0c, 0x7e, + 0x3b, 0xf6, 0xd0, 0xad, 0x7c, 0x34, 0xbe, 0x32, 0x96, 0xe4, 0x37, 0x16, + 0xad, 0x41, 0x53, 0x76, 0x6b, 0x37, 0x5b, 0xcd, 0xb6, 0x86, 0x51, 0x0d, + 0x5c, 0xfe, 0x1b, 0x1d, 0xfe, 0x82, 0xd8, 0xfd, 0x3a, 0x69, 0x1d, 0xca, + 0x8f, 0x82, 0x2b, 0xa9, 0xde, 0xef, 0x5c, 0xd4, 0x92, 0x2c, 0x6e, 0x26, + 0x7a, 0x89, 0x1f, 0xcd, 0xb7, 0x62, 0x4e, 0xe4, 0x7f, 0xcb, 0xfb, 0x6a, + 0x8b, 0x4f, 0x37, 0x13, 0xdd, 0x2a, 0x24, 0x28, 0x68, 0x9c, 0xcc, 0x7f, + 0x99, 0x2b, 0xf3, 0x2f, 0x20, 0xc6, 0xf9, 0x1f, 0xa7, 0x7d, 0x2c, 0xb9, + 0x5b, 0x28, 0x64, 0x95, 0xbf, 0x8f, 0xf1, 0x3d, 0x24, 0x4b, 0x8c, 0x98, + 0xe9, 0x50, 0xcb, 0x8f, 0xf4, 0xd1, 0x43, 0xf2, 0x73, 0xc9, 0xcc, 0x63, + 0xc0, 0x6f, 0x52, 0xdf, 0xa0, 0x8e, 0x30, 0xf8, 0x8d, 0x51, 0x24, 0x92, + 0xd2, 0xda, 0xa5, 0x11, 0x52, 0xae, 0x52, 0x24, 0x89, 0x79, 0x7c, 0x9d, + 0xbe, 0xdd, 0xb6, 0xd4, 0x7c, 0x03, 0x7d, 0xe2, 0xeb, 0xed, 0x44, 0x76, + 0x5b, 0x4d, 0x5c, 0x54, 0x28, 0x01, 0x92, 0x59, 0x79, 0x01, 0x60, 0x32, + 0x32, 0xc7, 0x3d, 0x7a, 0x8f, 0x4d, 0x65, 0x9c, 0x45, 0x76, 0xa2, 0xa4, + 0xaa, 0x96, 0x2b, 0x7b, 0x3b, 0x53, 0x87, 0x22, 0x27, 0x91, 0x40, 0x76, + 0x1d, 0xbe, 0xd9, 0xd1, 0xdc, 0x1f, 0xc5, 0xf7, 0xa5, 0x34, 0xb6, 0x4b, + 0x2d, 0x33, 0x47, 0x3c, 0xf3, 0x79, 0x8d, 0x39, 0xc4, 0xb2, 0x92, 0x73, + 0xe6, 0x6c, 0x74, 0x03, 0xdc, 0x0e, 0xa7, 0x4d, 0xc2, 0xf2, 0x39, 0xdb, + 0x17, 0x8d, 0xc9, 0xca, 0xdb, 0x28, 0x1c, 0x62, 0x3c, 0x4b, 0xb5, 0xd9, + 0x47, 0xd0, 0x2e, 0x13, 0x78, 0x8b, 0xdc, 0x8e, 0x73, 0xbe, 0x94, 0x5c, + 0x62, 0xa1, 0xa3, 0x31, 0x3c, 0x71, 0x7f, 0xbb, 0xc8, 0xbf, 0xe2, 0xe8, + 0x74, 0xc7, 0x89, 0xa1, 0xa9, 0x6e, 0x2a, 0xba, 0xf3, 0x30, 0x78, 0xcd, + 0x74, 0xe7, 0x04, 0x63, 0x6e, 0x76, 0xdb, 0xf1, 0xa5, 0x35, 0x54, 0x72, + 0x4c, 0xa2, 0x9c, 0x4a, 0xa4, 0x7d, 0x5c, 0xad, 0xb7, 0x4e, 0xc0, 0xe9, + 0xf4, 0xfd, 0x03, 0x3f, 0xb3, 0x01, 0xe4, 0xf9, 0xa2, 0xb1, 0x44, 0x79, + 0x63, 0xea, 0x7f, 0xe6, 0x3a, 0x31, 0x6d, 0x63, 0x90, 0xbc, 0x84, 0x72, + 0x85, 0xc7, 0x36, 0x0e, 0xc3, 0xf1, 0xaf, 0x94, 0xf5, 0x46, 0x89, 0x92, + 0x13, 0x44, 0xf1, 0xb1, 0x50, 0x57, 0xc4, 0xdb, 0x27, 0x44, 0x45, 0x77, + 0xa2, 0x69, 0x58, 0xd4, 0x48, 0xef, 0x57, 0x1b, 0x7f, 0xc2, 0x44, 0xf2, + 0xae, 0xff, 0x00, 0xf7, 0xbe, 0xaf, 0xc2, 0xae, 0x4c, 0x15, 0xd5, 0x95, + 0xda, 0xdb, 0x5d, 0x5c, 0x6f, 0x98, 0xe2, 0x95, 0xd3, 0x19, 0x07, 0xc3, + 0xc6, 0x47, 0xae, 0x35, 0x0d, 0x25, 0xb2, 0xba, 0xae, 0x46, 0x8a, 0x2a, + 0x66, 0x2c, 0xa4, 0x73, 0x0c, 0x7d, 0x20, 0xf4, 0x27, 0x57, 0x19, 0x2b, + 0x94, 0x4c, 0x2a, 0x15, 0x0c, 0x4e, 0xbb, 0x60, 0xff, 0x00, 0xa6, 0x99, + 0x70, 0xa5, 0x31, 0x4a, 0x0a, 0xa9, 0xd4, 0x78, 0x93, 0xcd, 0x29, 0x76, + 0xed, 0xb1, 0xd6, 0x5e, 0xdf, 0x03, 0x0a, 0xb4, 0x1c, 0x33, 0x24, 0x7c, + 0xb4, 0x2b, 0x2a, 0x3d, 0x44, 0xaa, 0x64, 0x73, 0xd0, 0x2a, 0x82, 0x32, + 0x3d, 0xfa, 0xeb, 0xbb, 0xb5, 0x49, 0xa5, 0x46, 0xa3, 0xa6, 0x99, 0xbc, + 0x15, 0xc2, 0xe0, 0x1d, 0x89, 0x03, 0x1f, 0xa6, 0xac, 0x75, 0xee, 0xf4, + 0xd5, 0xd2, 0xc9, 0x51, 0x1b, 0x20, 0x92, 0x97, 0x11, 0xb6, 0x36, 0xfa, + 0xba, 0x67, 0xf1, 0xaa, 0x95, 0x73, 0x47, 0x33, 0x15, 0x41, 0xd3, 0xbf, + 0xae, 0xb6, 0x6d, 0xa4, 0x40, 0x15, 0x12, 0x54, 0xcd, 0x1d, 0x3a, 0xe0, + 0x07, 0x38, 0xc0, 0xe8, 0x34, 0xc5, 0xe0, 0x64, 0x41, 0x1b, 0x6c, 0x54, + 0x6c, 0x3d, 0x34, 0xbe, 0xdd, 0xe2, 0x45, 0x71, 0x0e, 0x9f, 0x50, 0xdc, + 0x1d, 0x3e, 0xf0, 0xe7, 0xa8, 0x4c, 0xcc, 0xc0, 0xef, 0xbe, 0xaa, 0x3d, + 0x94, 0x28, 0x65, 0xc3, 0x6e, 0x37, 0xd3, 0x0b, 0x65, 0x63, 0xd2, 0xb2, + 0xbc, 0x6f, 0xb8, 0x6c, 0x91, 0xed, 0xaf, 0xd2, 0xd0, 0xcb, 0xe1, 0xb1, + 0x5c, 0x72, 0xaf, 0x56, 0x63, 0x80, 0x34, 0xbe, 0x17, 0x4e, 0x40, 0x7b, + 0x8c, 0xfe, 0xfa, 0x94, 0x59, 0xa6, 0x50, 0xc8, 0x92, 0xa2, 0xcc, 0x87, + 0xf9, 0x6e, 0x9c, 0xde, 0xb8, 0xd0, 0xf4, 0x94, 0xe9, 0x05, 0x75, 0x50, + 0x0a, 0x02, 0xca, 0xc2, 0x55, 0xfb, 0x91, 0x83, 0xfd, 0xbf, 0x7d, 0x07, + 0xc2, 0x12, 0x78, 0xb6, 0x7c, 0xe3, 0xfe, 0x1b, 0x60, 0x0f, 0x63, 0xa3, + 0x2b, 0x65, 0x29, 0x71, 0xa7, 0x32, 0x48, 0xb1, 0xc4, 0x62, 0x39, 0x76, + 0x3b, 0x64, 0x11, 0x81, 0xa9, 0x40, 0x47, 0xb1, 0x17, 0x18, 0x43, 0x3f, + 0xf1, 0x9a, 0x0a, 0xda, 0x2a, 0x66, 0x91, 0xd5, 0x5c, 0x4e, 0x14, 0xee, + 0xc1, 0x46, 0x41, 0xfd, 0xf5, 0x15, 0x92, 0xeb, 0x5d, 0x68, 0xa5, 0xf9, + 0xb6, 0x71, 0x2b, 0x99, 0x83, 0xcb, 0x4e, 0xe7, 0x39, 0xce, 0x70, 0x40, + 0xec, 0x71, 0xdf, 0x5f, 0xae, 0x55, 0x15, 0x17, 0xdb, 0x89, 0x96, 0xd9, + 0x28, 0x86, 0x9e, 0x89, 0x49, 0x91, 0xe4, 0x7f, 0x0c, 0xc9, 0xb6, 0x4f, + 0x2e, 0x77, 0xea, 0x31, 0xf8, 0xd0, 0x6f, 0x1a, 0xca, 0x6a, 0x24, 0x97, + 0x2e, 0xae, 0xc1, 0x06, 0x5b, 0x3c, 0xc4, 0x75, 0x27, 0xd7, 0x52, 0x93, + 0x54, 0xce, 0x8e, 0x2a, 0x9c, 0x29, 0xa3, 0x43, 0xab, 0xb3, 0x5a, 0x38, + 0xae, 0x85, 0x2b, 0x56, 0x23, 0x1c, 0xc1, 0x7c, 0xb2, 0xa7, 0xd6, 0x87, + 0xd0, 0xfa, 0x8d, 0x51, 0x78, 0xa3, 0x86, 0x2e, 0x16, 0xb8, 0xfc, 0x59, + 0x23, 0x33, 0xc4, 0x36, 0x33, 0x46, 0x3f, 0x72, 0x3b, 0x6a, 0xcd, 0xc0, + 0xb7, 0xe8, 0xa9, 0x7f, 0xfa, 0x7c, 0xbf, 0xcb, 0x5e, 0x63, 0xe1, 0x9c, + 0xec, 0x3d, 0xb5, 0x7f, 0x0c, 0x93, 0x47, 0xb8, 0x0c, 0xa7, 0xa8, 0xd2, + 0x37, 0x38, 0x3a, 0x7c, 0x99, 0xa7, 0x97, 0x26, 0x9d, 0xd7, 0xa3, 0xcf, + 0xf6, 0xe0, 0xaf, 0x1c, 0xc3, 0x38, 0xe8, 0x41, 0xfb, 0x6d, 0xa6, 0xd6, + 0x8a, 0x3a, 0x99, 0xec, 0xb5, 0x66, 0x2a, 0x81, 0x4e, 0xbb, 0x82, 0x4a, + 0x92, 0x09, 0x2d, 0xd3, 0x6f, 0xb6, 0x8e, 0xf8, 0xad, 0x45, 0x4f, 0x6f, + 0xe2, 0xaa, 0x24, 0xa3, 0x8c, 0x43, 0x1d, 0x54, 0x1c, 0xcd, 0x1a, 0x0c, + 0x2f, 0x30, 0x27, 0xcd, 0xf7, 0xd7, 0x74, 0x73, 0x46, 0x6c, 0xc9, 0x47, + 0x17, 0xf2, 0xf0, 0xdc, 0xcd, 0x8d, 0xf7, 0x3d, 0x75, 0x32, 0x4e, 0xe9, + 0x0c, 0xcd, 0x3d, 0xf0, 0x8b, 0x06, 0xb1, 0xd3, 0xc9, 0x41, 0x6f, 0xf1, + 0x50, 0xa8, 0x74, 0x97, 0x99, 0x64, 0xcf, 0x5d, 0xf3, 0xfa, 0xeb, 0x5e, + 0xe1, 0xa5, 0x3c, 0x79, 0xf1, 0x16, 0x8a, 0x9a, 0xd1, 0x0d, 0x55, 0xae, + 0x8d, 0x60, 0xe4, 0x90, 0xcd, 0x27, 0x3b, 0x04, 0x2b, 0xfc, 0xc2, 0x01, + 0xff, 0x00, 0x10, 0x3f, 0xbe, 0xb3, 0x6b, 0x5f, 0x83, 0x15, 0x39, 0x12, + 0x29, 0x2e, 0x58, 0x88, 0x80, 0xe8, 0x0f, 0xa9, 0x1a, 0x63, 0xc3, 0xb7, + 0x4e, 0x29, 0xb4, 0xde, 0x3e, 0x6a, 0x82, 0xb1, 0xe2, 0x98, 0x73, 0x24, + 0x6d, 0x1a, 0xe7, 0x00, 0xec, 0x40, 0xfc, 0x77, 0xd2, 0xf2, 0xe4, 0x86, + 0xeb, 0x92, 0xe8, 0xcb, 0x29, 0xf2, 0x8b, 0xdd, 0xd1, 0x28, 0xed, 0xb7, + 0xaa, 0x9b, 0x75, 0x2d, 0x4c, 0x6f, 0x0c, 0x32, 0xbc, 0x4a, 0x92, 0x1f, + 0x3e, 0x15, 0xb1, 0xe6, 0x1e, 0xbb, 0x68, 0xde, 0x0b, 0xe0, 0xbe, 0x17, + 0xe2, 0x0b, 0xdd, 0x7b, 0x5c, 0xe5, 0xa8, 0x89, 0xe3, 0x8b, 0xe6, 0xa1, + 0x2b, 0x22, 0x88, 0x9b, 0x0a, 0x32, 0x47, 0xe7, 0x72, 0x35, 0x44, 0xe2, + 0x5a, 0x49, 0xe4, 0xba, 0xc7, 0x70, 0x84, 0x08, 0xe6, 0x91, 0x33, 0x50, + 0x06, 0xc0, 0x38, 0xeb, 0xb7, 0xbe, 0x73, 0xf7, 0xce, 0x9e, 0xf0, 0x7c, + 0x52, 0xbd, 0xa1, 0x1e, 0x4d, 0xbc, 0x09, 0x48, 0x76, 0x0f, 0xe6, 0xf3, + 0x6f, 0x9c, 0x7a, 0x7f, 0xd3, 0x5c, 0xb8, 0xe5, 0x58, 0x5b, 0xcb, 0x1e, + 0x53, 0x33, 0xef, 0xa7, 0x67, 0xce, 0x0f, 0xf8, 0x75, 0x5d, 0xc5, 0x57, + 0xab, 0x8d, 0x5b, 0xa1, 0x78, 0x69, 0xb9, 0x9d, 0xd8, 0x37, 0xd6, 0xd9, + 0xf2, 0xa0, 0xf6, 0xc1, 0x3a, 0x9b, 0x8a, 0x6a, 0x20, 0xe1, 0xf4, 0x92, + 0x89, 0xd4, 0xad, 0x74, 0x51, 0x08, 0x84, 0x6c, 0x30, 0xf1, 0xa0, 0xfa, + 0x57, 0x1d, 0x80, 0xdf, 0x57, 0xee, 0x1b, 0xe2, 0xfa, 0x8a, 0x3b, 0x74, + 0x96, 0xfa, 0x0a, 0x95, 0xa6, 0x09, 0x2f, 0x95, 0xd9, 0x72, 0x5d, 0xb1, + 0xbe, 0x07, 0xa6, 0x4e, 0xaa, 0x3c, 0x6d, 0xc5, 0x7c, 0x41, 0x57, 0x53, + 0x2a, 0x57, 0xdb, 0xed, 0x13, 0xa0, 0xc8, 0x69, 0x85, 0x0a, 0x17, 0x91, + 0x7a, 0x0c, 0xb9, 0x05, 0x81, 0xe8, 0x76, 0x23, 0x5b, 0xf4, 0xb9, 0xf1, + 0xea, 0x9d, 0xc1, 0xb5, 0x43, 0xa1, 0x35, 0x2e, 0x8c, 0xb5, 0x65, 0xa9, + 0xaf, 0x97, 0xc4, 0xaa, 0x9d, 0xdc, 0x86, 0xca, 0xa3, 0x1c, 0x80, 0x3d, + 0x46, 0x88, 0x58, 0x23, 0x07, 0x38, 0x27, 0xee, 0x74, 0xc6, 0xe3, 0x70, + 0x8a, 0xa0, 0x08, 0x7e, 0x4a, 0x3a, 0x52, 0x3f, 0x98, 0x0a, 0x1e, 0xa3, + 0xbe, 0x83, 0xe1, 0x4b, 0x8d, 0x9e, 0xe7, 0xc4, 0xb3, 0x59, 0xa7, 0x95, + 0x48, 0x10, 0x12, 0x18, 0xb7, 0x2a, 0xb3, 0x02, 0x36, 0xfd, 0x37, 0xd6, + 0xa6, 0xdd, 0xf2, 0xc2, 0xb3, 0xf2, 0x4f, 0x43, 0x44, 0x5a, 0xb2, 0xb2, + 0x39, 0x5d, 0x62, 0x52, 0xd1, 0xac, 0x6a, 0x0f, 0xf3, 0x3f, 0xa7, 0x39, + 0xfe, 0x9f, 0x5f, 0xd3, 0xbe, 0xad, 0x22, 0xf8, 0xfc, 0x4b, 0x6c, 0xa2, + 0xb8, 0xcf, 0x6d, 0x7a, 0x3a, 0xaf, 0x07, 0xc2, 0x92, 0x45, 0x1f, 0xcb, + 0x94, 0xaf, 0x42, 0x3d, 0x0e, 0x3b, 0x63, 0xfa, 0x75, 0x35, 0x87, 0x84, + 0xc5, 0xf3, 0x88, 0x63, 0xb1, 0x59, 0x68, 0xe3, 0xa9, 0x9a, 0x37, 0x06, + 0xb8, 0x01, 0x88, 0x69, 0xc7, 0xac, 0x87, 0xb1, 0x3e, 0x9d, 0x75, 0xe8, + 0x7e, 0x1e, 0xf8, 0x79, 0x62, 0xb6, 0xf0, 0xf1, 0xb4, 0xc9, 0x09, 0x96, + 0x39, 0x7c, 0xd2, 0xa8, 0x1c, 0xab, 0xcc, 0x7a, 0xf2, 0x81, 0xd3, 0xf5, + 0xd1, 0x3d, 0x3a, 0xca, 0xa9, 0x85, 0x1c, 0x7f, 0x22, 0xb3, 0xcb, 0xf5, + 0x34, 0xfc, 0xe3, 0x07, 0x63, 0xeb, 0xa1, 0x16, 0x90, 0xac, 0x98, 0x63, + 0xbf, 0x5c, 0xe3, 0x5e, 0xac, 0x8f, 0xe1, 0x7f, 0x05, 0x2c, 0x85, 0xcd, + 0xa8, 0xb0, 0x23, 0xe9, 0x69, 0xdc, 0x81, 0xf6, 0xdf, 0x5c, 0x5d, 0x7e, + 0x16, 0x70, 0x75, 0x6d, 0x32, 0xc5, 0x15, 0xb8, 0xd1, 0xba, 0x7d, 0x32, + 0xc0, 0xe4, 0x37, 0xe7, 0x3d, 0x46, 0x97, 0x0d, 0x16, 0x48, 0xaa, 0x6e, + 0xcb, 0x8e, 0x96, 0x48, 0xc9, 0xfe, 0x09, 0xd8, 0xae, 0x37, 0x1a, 0x7b, + 0xe8, 0xa2, 0xad, 0x6a, 0x4e, 0x7a, 0x5f, 0x08, 0x4a, 0x14, 0x15, 0x67, + 0x24, 0x10, 0x18, 0x1e, 0xd8, 0x07, 0xa6, 0x94, 0xd1, 0x5c, 0xae, 0xf6, + 0x5b, 0xe5, 0x6f, 0x0b, 0x5d, 0x29, 0x62, 0x47, 0x99, 0x4c, 0x4c, 0x40, + 0xc0, 0x52, 0x08, 0xc3, 0x7b, 0x83, 0x8d, 0x7a, 0x0b, 0x82, 0xb8, 0x6a, + 0x9b, 0x84, 0xec, 0xa6, 0x86, 0x12, 0x66, 0x2f, 0x33, 0x3b, 0x38, 0x5d, + 0xdb, 0x24, 0xe3, 0x3f, 0x8c, 0x0d, 0x65, 0x9f, 0xed, 0x01, 0x62, 0x9a, + 0xae, 0xb0, 0x5f, 0xe8, 0x23, 0xfe, 0x65, 0x2a, 0xac, 0x53, 0x28, 0x19, + 0x66, 0xe6, 0x3b, 0x6d, 0xfa, 0x7e, 0xba, 0xbc, 0x9a, 0x5f, 0x15, 0x7d, + 0x93, 0x26, 0x0e, 0x0a, 0x79, 0xb3, 0xc8, 0x6a, 0xd6, 0x38, 0xdc, 0x44, + 0xec, 0xdf, 0x50, 0x1e, 0x51, 0x93, 0xad, 0x1f, 0x86, 0xb8, 0x56, 0x86, + 0x8e, 0x96, 0x5a, 0x8b, 0xad, 0x6c, 0x75, 0xf7, 0x06, 0x24, 0x53, 0x25, + 0x31, 0xe6, 0x55, 0x51, 0xd1, 0xbd, 0xf3, 0xfb, 0x67, 0x59, 0x9d, 0x82, + 0xc9, 0x5f, 0x50, 0xcd, 0x4b, 0x77, 0xb9, 0xc9, 0x46, 0x01, 0xf3, 0x43, + 0x19, 0x2c, 0xfd, 0x7e, 0x9d, 0xb6, 0x1e, 0xfd, 0x71, 0xe9, 0xad, 0x83, + 0x82, 0xeb, 0xec, 0x7c, 0x2b, 0x42, 0x20, 0xac, 0x95, 0x90, 0x22, 0x05, + 0xf1, 0xa5, 0x39, 0xe5, 0x03, 0xa0, 0x19, 0xdf, 0x03, 0x5c, 0xfd, 0x2e, + 0x9a, 0x0a, 0x4d, 0x4d, 0x70, 0x2b, 0x0e, 0x15, 0x16, 0xdb, 0x14, 0xd4, + 0xb5, 0x65, 0x65, 0x9a, 0xa2, 0x96, 0x24, 0x11, 0xc4, 0x1c, 0xe1, 0x10, + 0x05, 0xe6, 0x8c, 0x1d, 0x83, 0x0c, 0xe7, 0x27, 0x62, 0x75, 0x50, 0xbc, + 0x3c, 0x31, 0x40, 0x1a, 0xa9, 0xe3, 0x86, 0x28, 0xb2, 0xbb, 0x26, 0x02, + 0xe4, 0xee, 0x4e, 0x37, 0x3b, 0xea, 0xdd, 0xc4, 0xfc, 0x5f, 0xc3, 0xb3, + 0x55, 0xca, 0xd4, 0xa6, 0x59, 0x63, 0xa9, 0x1c, 0xa5, 0xd6, 0x12, 0xbc, + 0x8c, 0x77, 0x27, 0x27, 0xec, 0x75, 0x97, 0xfc, 0x4c, 0xbd, 0xd2, 0x57, + 0xc9, 0x45, 0x6b, 0xb5, 0xac, 0x92, 0xa1, 0x72, 0xd3, 0xc8, 0xfd, 0x5d, + 0xb3, 0x85, 0xfc, 0x60, 0xe8, 0x73, 0x60, 0x59, 0x73, 0xa8, 0x63, 0x92, + 0xa5, 0xd8, 0x39, 0x60, 0xb7, 0x70, 0xc4, 0x5c, 0x4d, 0x6b, 0xa2, 0x9e, + 0xba, 0x13, 0x41, 0x72, 0x86, 0xe1, 0x55, 0x2b, 0xe3, 0xc2, 0x81, 0x58, + 0xf8, 0x64, 0x9c, 0x2a, 0xef, 0x8d, 0xce, 0x75, 0xbd, 0x7c, 0x19, 0xf8, + 0x6f, 0x6e, 0xe1, 0xbb, 0x5b, 0x54, 0xdd, 0x12, 0x9e, 0xaa, 0xf1, 0x3a, + 0x7f, 0x3b, 0x1b, 0xf8, 0x00, 0xff, 0x00, 0x42, 0xff, 0x00, 0x99, 0xfb, + 0x6a, 0x9b, 0xf0, 0xaf, 0x86, 0xe8, 0xa8, 0xab, 0x1e, 0xbe, 0xbd, 0x44, + 0xd5, 0x2a, 0x02, 0xd3, 0x29, 0xc0, 0x45, 0x73, 0xd4, 0xe4, 0xfe, 0x9f, + 0x9d, 0x69, 0xca, 0x12, 0x95, 0xa4, 0x96, 0xa6, 0x59, 0x10, 0xca, 0x87, + 0xf9, 0x3c, 0xbb, 0x02, 0x3a, 0x01, 0xeb, 0xae, 0x9e, 0x1c, 0xf1, 0xde, + 0xe1, 0x1e, 0x90, 0xec, 0x4e, 0x8f, 0x1f, 0x71, 0x08, 0xab, 0xa8, 0xe2, + 0x6b, 0xba, 0x48, 0x42, 0xc2, 0x2b, 0xa6, 0x0b, 0xca, 0x30, 0x48, 0xe7, + 0x6e, 0xfa, 0x56, 0x68, 0xd5, 0x7c, 0xb3, 0x4e, 0x52, 0x2e, 0x6c, 0x2a, + 0x06, 0xc9, 0xfb, 0xea, 0xc1, 0xc4, 0x66, 0x25, 0xe2, 0x1b, 0x97, 0x8a, + 0x55, 0x54, 0xd6, 0x4b, 0x82, 0x4f, 0x7e, 0x73, 0xa5, 0xcd, 0x5b, 0x68, + 0x84, 0x34, 0x6f, 0x39, 0x72, 0x06, 0xea, 0x91, 0x13, 0xbf, 0xa6, 0x4e, + 0x9e, 0x80, 0xdc, 0xb7, 0xbb, 0x42, 0xd9, 0x28, 0xa4, 0x69, 0x0c, 0x18, + 0x0f, 0x01, 0xf3, 0x73, 0xc8, 0x7d, 0xfb, 0x77, 0xfd, 0x3f, 0x5d, 0x10, + 0x94, 0x74, 0xb1, 0xc7, 0x35, 0x74, 0xd4, 0x08, 0xc8, 0x8f, 0xc8, 0x85, + 0x48, 0xe6, 0x66, 0x3d, 0xcf, 0x36, 0x36, 0xf7, 0xc9, 0xd3, 0x4a, 0x29, + 0x20, 0x92, 0x9d, 0x9c, 0x7c, 0xda, 0xc5, 0xc9, 0xe5, 0x0c, 0xa3, 0xcb, + 0xb6, 0xc7, 0x19, 0xce, 0x34, 0x65, 0x0a, 0x2a, 0x70, 0x65, 0x5d, 0xa5, + 0xed, 0xf4, 0x37, 0x25, 0xad, 0x71, 0x22, 0xcd, 0x3c, 0x38, 0x92, 0x26, + 0x52, 0x30, 0x50, 0x9c, 0x15, 0x23, 0xef, 0x8c, 0x9d, 0x66, 0xcc, 0xd5, + 0xd3, 0x1a, 0x8a, 0xbb, 0xc2, 0x22, 0x75, 0x3f, 0xfb, 0x7d, 0x31, 0xe8, + 0x3f, 0xb6, 0xad, 0xd6, 0x3a, 0x8a, 0x51, 0x4d, 0x2b, 0x23, 0x72, 0xa2, + 0x2a, 0xf3, 0x85, 0x3b, 0x92, 0x37, 0xd5, 0x6a, 0x4a, 0x79, 0x67, 0xaf, + 0x58, 0x99, 0x8e, 0xc0, 0x02, 0x71, 0x8f, 0xce, 0xa1, 0xbd, 0x17, 0xb7, + 0x57, 0xab, 0xd3, 0x33, 0x47, 0x95, 0x1e, 0x6c, 0xec, 0x40, 0x18, 0xdc, + 0x69, 0x69, 0x50, 0x89, 0x21, 0xcf, 0x16, 0xd4, 0x51, 0x57, 0x33, 0x54, + 0x5a, 0xe3, 0x96, 0x9a, 0x90, 0xb7, 0x86, 0x91, 0xbb, 0xf3, 0x90, 0x40, + 0x01, 0x8e, 0x70, 0x3b, 0xe7, 0x1e, 0x9a, 0xa5, 0x5c, 0x33, 0x1a, 0x1f, + 0x50, 0x71, 0x9f, 0x6d, 0x34, 0x8e, 0xea, 0x6a, 0x03, 0x25, 0x53, 0x20, + 0x55, 0xc9, 0x18, 0x1f, 0x56, 0x7a, 0x69, 0x5d, 0x5f, 0x33, 0xc8, 0x59, + 0x17, 0x2b, 0x9e, 0x50, 0xa7, 0xbe, 0x4e, 0xb7, 0x3a, 0xa5, 0x43, 0x10, + 0x45, 0x86, 0xde, 0x64, 0x8b, 0xe6, 0x0a, 0x9e, 0x57, 0x3b, 0x9f, 0x5e, + 0xe7, 0x47, 0x5c, 0x2e, 0x73, 0xd1, 0x8f, 0x06, 0x9e, 0x34, 0x03, 0xa2, + 0x67, 0xaa, 0xfb, 0xfb, 0xe9, 0xc5, 0x24, 0x42, 0x1b, 0x4c, 0x54, 0xa5, + 0x70, 0xc1, 0x41, 0x03, 0x3d, 0xf1, 0xbe, 0xab, 0xf7, 0x57, 0x57, 0x06, + 0x1e, 0x5c, 0x31, 0x38, 0x07, 0x3d, 0x3b, 0x1d, 0x13, 0xe1, 0x10, 0x29, + 0x6e, 0x8a, 0x38, 0x42, 0xa2, 0x9e, 0x62, 0x7e, 0x7e, 0x69, 0x79, 0x5d, + 0xf1, 0xf5, 0xab, 0x0c, 0xfe, 0x31, 0xb6, 0xab, 0xa1, 0x82, 0x46, 0x00, + 0x19, 0xc6, 0xda, 0x7b, 0xc4, 0xd5, 0x14, 0x4c, 0x29, 0x61, 0xa3, 0x62, + 0xea, 0xb1, 0x00, 0x77, 0xd8, 0x10, 0x31, 0xa4, 0x72, 0xe0, 0x81, 0xeb, + 0xd7, 0x48, 0x28, 0x69, 0xc3, 0x17, 0x7a, 0xa8, 0xae, 0x94, 0x74, 0x11, + 0x95, 0x58, 0x4c, 0x86, 0x46, 0x23, 0xea, 0x27, 0x38, 0xc6, 0x7d, 0x37, + 0xd3, 0x7f, 0x88, 0x52, 0x98, 0xea, 0xad, 0x92, 0x54, 0x42, 0x66, 0xa5, + 0xf1, 0x5c, 0x4b, 0xca, 0x3a, 0x74, 0xc7, 0xe9, 0xa4, 0x1c, 0x3f, 0x02, + 0xa7, 0x10, 0x51, 0xd5, 0xce, 0x00, 0x8c, 0x2f, 0x2c, 0x67, 0xd5, 0xb2, + 0x3f, 0xeb, 0xa6, 0xff, 0x00, 0x11, 0x24, 0x35, 0x37, 0x33, 0x42, 0x8c, + 0x24, 0x8e, 0x0a, 0x6f, 0x17, 0x38, 0xc6, 0x0f, 0x36, 0xff, 0x00, 0xd8, + 0x69, 0xa9, 0x9a, 0xa2, 0x9d, 0xc6, 0x8e, 0xed, 0xd1, 0xd2, 0x55, 0xdc, + 0xeb, 0xa1, 0xf9, 0x8a, 0x9a, 0x87, 0x34, 0xab, 0x94, 0xc6, 0x59, 0x90, + 0x6f, 0x93, 0xbf, 0xb8, 0x3b, 0x76, 0x07, 0x3a, 0x86, 0xbe, 0x99, 0x60, + 0xa2, 0x8a, 0x51, 0x3a, 0x48, 0x5d, 0x1b, 0x1c, 0x9b, 0x80, 0x01, 0xd8, + 0x7e, 0x9a, 0x67, 0xf0, 0xfe, 0xe5, 0x4e, 0xb5, 0xe2, 0x09, 0x56, 0x34, + 0x9a, 0xa9, 0x42, 0x2b, 0x9f, 0xeb, 0x5c, 0x12, 0xc8, 0x7d, 0x71, 0xb6, + 0x89, 0xbe, 0x51, 0xd3, 0x43, 0xc3, 0x6f, 0x14, 0x14, 0xfe, 0x1c, 0xb5, + 0x35, 0xd2, 0x95, 0x2b, 0xf4, 0x80, 0x0f, 0xfd, 0x3f, 0x7d, 0x18, 0x70, + 0x96, 0xdc, 0x8e, 0x25, 0x66, 0xdf, 0x50, 0x94, 0xce, 0xd8, 0x3c, 0x8c, + 0xe8, 0xbc, 0xad, 0xff, 0x00, 0x31, 0x1a, 0xd2, 0xf8, 0x2a, 0xfa, 0x95, + 0x51, 0x0a, 0x3a, 0x89, 0x57, 0xc7, 0x85, 0x54, 0x33, 0x67, 0xeb, 0xf7, + 0xc6, 0xb3, 0x14, 0x12, 0x47, 0x2a, 0x4b, 0x9e, 0x56, 0x55, 0xc7, 0x4f, + 0xdf, 0x47, 0xdb, 0xe9, 0xdc, 0x89, 0x24, 0x8e, 0x69, 0x3c, 0x58, 0xc0, + 0x20, 0xe7, 0x7d, 0x23, 0x24, 0x2c, 0x76, 0xa3, 0x12, 0xcb, 0x1a, 0x63, + 0x5f, 0x8b, 0x8d, 0x2c, 0x7c, 0x65, 0x6b, 0x95, 0xc7, 0x3c, 0x26, 0x9b, + 0xc9, 0xf6, 0xe6, 0x20, 0xe9, 0xcf, 0x0e, 0xdb, 0x79, 0x28, 0xe9, 0xeb, + 0x4c, 0x69, 0x53, 0x12, 0x02, 0x15, 0x17, 0x62, 0x8d, 0xd8, 0xe4, 0x63, + 0x3d, 0x08, 0xdf, 0x3d, 0x75, 0x56, 0xe2, 0x4a, 0xa9, 0xae, 0x94, 0xb6, + 0xea, 0xa9, 0x9d, 0x9a, 0x5a, 0x34, 0x31, 0xb0, 0x27, 0x24, 0x8d, 0x59, + 0xb8, 0x3e, 0xfb, 0x4d, 0x05, 0xa4, 0xc7, 0xe2, 0x10, 0x00, 0xcf, 0xeb, + 0xac, 0xba, 0xcd, 0xff, 0x00, 0x12, 0x94, 0x7f, 0x66, 0x5c, 0xf8, 0x9c, + 0x31, 0xa4, 0xbd, 0x0b, 0xae, 0x94, 0xf5, 0x35, 0x57, 0x24, 0x9c, 0x2a, + 0xd2, 0x4a, 0xbb, 0xa2, 0xc6, 0xb8, 0x52, 0x77, 0xd8, 0x8f, 0x5e, 0xbb, + 0xea, 0xe7, 0xc0, 0x33, 0x4b, 0x5e, 0xcd, 0x6f, 0xa6, 0xa0, 0x98, 0x56, + 0x49, 0x11, 0x90, 0x2f, 0x3a, 0x9e, 0x60, 0x33, 0xcd, 0xbf, 0xdc, 0x77, + 0xd2, 0x9a, 0xea, 0xda, 0x4b, 0x8d, 0xb8, 0xd5, 0xd3, 0xef, 0x24, 0x4d, + 0xfc, 0xc0, 0x3b, 0x80, 0x0e, 0xfa, 0xe3, 0xfd, 0x9f, 0xa6, 0xa9, 0x8f, + 0x8d, 0xe3, 0x7a, 0x58, 0x64, 0x92, 0x94, 0xb3, 0x78, 0xf2, 0xe3, 0xca, + 0x85, 0x81, 0x3f, 0xe5, 0xfb, 0xe9, 0x2b, 0x4d, 0x1d, 0x42, 0x70, 0x97, + 0x4c, 0xcb, 0x8b, 0x1a, 0xcb, 0x3d, 0xac, 0x86, 0xff, 0x00, 0x59, 0x70, + 0x8e, 0xb8, 0xc9, 0xc8, 0xb1, 0x78, 0x2c, 0x47, 0x29, 0x52, 0x1e, 0x33, + 0xbe, 0xcf, 0x9e, 0xfa, 0xfb, 0xc3, 0x3c, 0x45, 0xf2, 0x97, 0x07, 0xaa, + 0xaa, 0xa7, 0x6a, 0x88, 0x79, 0x1a, 0x29, 0x23, 0x56, 0xe5, 0x3b, 0xff, + 0x00, 0x50, 0x3e, 0xda, 0xf4, 0x9d, 0xc7, 0xe1, 0x87, 0x09, 0x71, 0xc5, + 0x44, 0x57, 0x1b, 0xe5, 0xba, 0x4f, 0x1a, 0x35, 0x18, 0x96, 0x39, 0x0c, + 0x52, 0x3f, 0xff, 0x00, 0x2c, 0x75, 0x03, 0xb6, 0x7a, 0x6a, 0x7a, 0xcf, + 0x84, 0x1c, 0x0b, 0x47, 0x69, 0x31, 0x52, 0xd9, 0xe4, 0xfe, 0x5e, 0x09, + 0x26, 0xa5, 0xcf, 0x3e, 0x3f, 0xc5, 0x93, 0xbe, 0xb5, 0xc7, 0xf1, 0xca, + 0x0a, 0xa0, 0xcd, 0x0f, 0x48, 0xa3, 0xd3, 0x3c, 0xf1, 0x76, 0xe2, 0x2b, + 0xd4, 0x42, 0xa2, 0xec, 0xb6, 0xf8, 0x3f, 0x85, 0x48, 0xe9, 0x4f, 0x13, + 0xc9, 0x4f, 0xcf, 0x18, 0x20, 0x79, 0x4a, 0xbe, 0xc7, 0x9b, 0x6c, 0xed, + 0x8d, 0xf4, 0xca, 0xdf, 0x52, 0xf7, 0x38, 0x17, 0x99, 0x05, 0x4f, 0x24, + 0x79, 0x76, 0x07, 0x00, 0x1f, 0x5d, 0x6b, 0x7c, 0x75, 0xc1, 0x75, 0x1c, + 0x69, 0xc3, 0x27, 0x86, 0xed, 0x2b, 0x4b, 0x4b, 0x0c, 0x72, 0x46, 0xf9, + 0x71, 0xca, 0xaa, 0x17, 0xd9, 0x47, 0xbe, 0xa4, 0xb6, 0xfc, 0x19, 0x16, + 0xfb, 0x04, 0x74, 0x34, 0xf7, 0x58, 0xc4, 0xf8, 0xe5, 0x92, 0x4f, 0x00, + 0xe1, 0x86, 0x37, 0xfe, 0xad, 0x36, 0x1a, 0x79, 0x63, 0xfa, 0x93, 0x26, + 0x99, 0xc1, 0xd2, 0xe4, 0xf2, 0xa7, 0x19, 0x54, 0xc8, 0x95, 0x55, 0x12, + 0x42, 0x39, 0x49, 0x52, 0x83, 0x7e, 0x8b, 0xd3, 0x1a, 0x6f, 0xf0, 0x5b, + 0xe1, 0x07, 0x11, 0xf1, 0xb5, 0xca, 0x1a, 0xc3, 0x1c, 0xf6, 0xdb, 0x42, + 0x38, 0xf1, 0x2b, 0xdc, 0x63, 0x98, 0x67, 0xa4, 0x7f, 0xe2, 0x6f, 0xed, + 0xaf, 0x57, 0xf0, 0x2f, 0xc2, 0x2e, 0x18, 0xe1, 0xe0, 0x2a, 0xeb, 0x28, + 0xa9, 0xee, 0x97, 0x2e, 0x6e, 0x6f, 0x98, 0xa8, 0x8f, 0x98, 0x27, 0xb2, + 0xa9, 0xd8, 0x7d, 0xfa, 0xea, 0xf4, 0xf8, 0xa7, 0x41, 0x1c, 0x68, 0xa8, + 0x8b, 0xb0, 0x54, 0x18, 0x03, 0xf1, 0xad, 0x31, 0x80, 0xd5, 0x8b, 0x81, + 0x67, 0x06, 0x70, 0xb5, 0x9f, 0x84, 0xac, 0xd1, 0xda, 0xec, 0xb4, 0xa2, + 0x18, 0x86, 0xf2, 0x3b, 0x79, 0xa4, 0x99, 0xfb, 0xbb, 0xb7, 0x56, 0x27, + 0x4f, 0x34, 0x2a, 0x4a, 0x09, 0xeb, 0x83, 0xa9, 0x1a, 0x42, 0xcb, 0x82, + 0x34, 0xc4, 0x86, 0x25, 0x47, 0x53, 0x49, 0xc8, 0xa4, 0x8e, 0xb8, 0xce, + 0xa0, 0xa0, 0xac, 0x4a, 0x99, 0x5c, 0x67, 0x74, 0x38, 0x23, 0x5c, 0xd5, + 0x49, 0x88, 0xcf, 0xdb, 0x1a, 0x4d, 0x6b, 0x99, 0xe3, 0xba, 0x4a, 0xc4, + 0xe1, 0x1d, 0xb1, 0xfa, 0x77, 0xd5, 0xd1, 0x76, 0x3c, 0xbe, 0xb4, 0xd1, + 0xda, 0x2a, 0xa4, 0xa6, 0xe6, 0xf1, 0x92, 0x26, 0x64, 0x55, 0xea, 0xc4, + 0x02, 0x70, 0x3d, 0xcf, 0xe7, 0x59, 0x27, 0x0d, 0xdc, 0xe9, 0xaf, 0xfc, + 0x3f, 0x70, 0x14, 0x37, 0xea, 0x5b, 0x6c, 0xaf, 0x2f, 0x8d, 0x53, 0x1c, + 0xc9, 0x99, 0xe3, 0x20, 0x8c, 0x0f, 0x36, 0x01, 0xf7, 0x6d, 0xfa, 0x0d, + 0x6c, 0xaa, 0x43, 0x2e, 0x7a, 0x8d, 0x79, 0x63, 0xe3, 0x1c, 0x6f, 0x07, + 0xc4, 0xab, 0xbc, 0x64, 0x15, 0xcb, 0xab, 0xa6, 0xfb, 0x10, 0xca, 0x0f, + 0xfd, 0xfd, 0xf5, 0x8f, 0x59, 0xe3, 0x14, 0xc4, 0x67, 0x7c, 0x07, 0x3d, + 0x86, 0xae, 0xa6, 0xf1, 0xf2, 0xc6, 0x76, 0xf1, 0x5c, 0xb3, 0x25, 0x64, + 0x47, 0x21, 0x80, 0x04, 0xe7, 0x23, 0x6d, 0xfd, 0x06, 0xa6, 0x58, 0x6e, + 0xb6, 0x8b, 0x85, 0x3f, 0xf1, 0xa8, 0x12, 0xbe, 0x87, 0xc4, 0x1b, 0xcd, + 0x1f, 0x37, 0x32, 0xfb, 0x6f, 0xb6, 0x46, 0xaa, 0xdc, 0x1d, 0x7a, 0xac, + 0xb3, 0x5e, 0xa9, 0xe5, 0x49, 0x0f, 0x82, 0xf2, 0x72, 0xcc, 0xa4, 0xed, + 0xca, 0x7a, 0x9c, 0x7e, 0x9a, 0xd9, 0xb8, 0x9a, 0x4b, 0x5c, 0xf6, 0xb8, + 0xd2, 0x3a, 0x87, 0xa8, 0xe6, 0x41, 0x18, 0x43, 0x16, 0x39, 0x97, 0xa8, + 0xdf, 0x3d, 0x80, 0xd7, 0x2b, 0x0e, 0x24, 0xed, 0x27, 0xc9, 0x96, 0x00, + 0x97, 0x3e, 0x1b, 0xe1, 0x3b, 0x85, 0xbd, 0x6a, 0xa8, 0x2d, 0xa1, 0x15, + 0x9d, 0x9d, 0x0d, 0x3b, 0x91, 0x90, 0x47, 0x42, 0x0e, 0x40, 0x3e, 0xda, + 0xce, 0xab, 0xb8, 0x52, 0x25, 0xbf, 0x41, 0x55, 0x43, 0x89, 0xd2, 0x22, + 0xee, 0x61, 0x99, 0x72, 0xcb, 0xb1, 0x23, 0x3e, 0xa0, 0x6a, 0xdf, 0x6b, + 0x35, 0x34, 0xa1, 0xe9, 0xe9, 0x29, 0x66, 0x78, 0x26, 0x3c, 0xd0, 0xb4, + 0x9f, 0x48, 0x1d, 0xf7, 0xef, 0xbe, 0x35, 0xfa, 0x0a, 0x86, 0xc4, 0x93, + 0xff, 0x00, 0x0a, 0x32, 0xd6, 0x73, 0xf8, 0x11, 0xc9, 0x10, 0xc1, 0x1b, + 0xf4, 0xc7, 0x7e, 0x9a, 0xd9, 0x87, 0x0b, 0x4b, 0x73, 0x8d, 0x30, 0xc9, + 0x78, 0x2a, 0xba, 0xae, 0x59, 0x05, 0xbe, 0xaa, 0x99, 0x24, 0xab, 0x8d, + 0x1b, 0xc3, 0x90, 0x30, 0x5f, 0x10, 0x0f, 0xe9, 0xdf, 0x62, 0x71, 0xd3, + 0xed, 0xae, 0xb8, 0x8b, 0x88, 0xa9, 0x25, 0xa6, 0xf9, 0x95, 0x72, 0xf0, + 0x42, 0x07, 0x8d, 0x86, 0xc4, 0x91, 0x63, 0xa8, 0xc1, 0xed, 0x9d, 0xb4, + 0x9b, 0x88, 0xaa, 0xaf, 0x74, 0x9c, 0xa2, 0xae, 0x90, 0x46, 0x86, 0x40, + 0x1d, 0x8a, 0x6e, 0x7a, 0xec, 0x7d, 0xf6, 0xd6, 0x7b, 0xc7, 0x46, 0x94, + 0x5e, 0xb1, 0x49, 0x17, 0x20, 0x68, 0xd5, 0xa4, 0x6c, 0xec, 0xcd, 0xf6, + 0xfc, 0xe8, 0x31, 0xe9, 0xa3, 0x82, 0x4f, 0x22, 0xec, 0xb9, 0x45, 0x41, + 0x5a, 0x33, 0xfe, 0x32, 0x88, 0x0e, 0x29, 0xbb, 0xbb, 0x10, 0x8a, 0x2b, + 0x67, 0x39, 0x27, 0xa9, 0xf1, 0x0e, 0x97, 0x50, 0xbc, 0x3c, 0xe1, 0xde, + 0x15, 0x9f, 0x1b, 0x85, 0x27, 0x6d, 0x1b, 0xc5, 0x4b, 0x2d, 0x47, 0x17, + 0xde, 0x7c, 0x4f, 0xf8, 0x6b, 0x5f, 0x38, 0x07, 0xff, 0x00, 0xf4, 0x3b, + 0x6b, 0xf5, 0x05, 0x0b, 0x4a, 0xc0, 0x47, 0xf4, 0xf5, 0x63, 0x8f, 0xdb, + 0x4c, 0x7d, 0x99, 0xe7, 0xf6, 0x67, 0x75, 0x35, 0xb3, 0x4c, 0xea, 0xef, + 0x4e, 0xab, 0x10, 0xc7, 0x94, 0x36, 0xe7, 0xf3, 0x8d, 0x47, 0x25, 0xc2, + 0xae, 0xaa, 0x9b, 0x7c, 0xc4, 0x80, 0x91, 0x84, 0x63, 0x8d, 0xf4, 0x5d, + 0x72, 0x43, 0x0c, 0x4d, 0x1b, 0x46, 0xdb, 0x0c, 0x82, 0x47, 0x7d, 0x2c, + 0x89, 0x83, 0x92, 0x80, 0xf2, 0xe3, 0xaf, 0xbe, 0x95, 0x96, 0xe5, 0xd8, + 0x1b, 0xda, 0x54, 0x86, 0x9c, 0x39, 0x17, 0xf3, 0x86, 0xd8, 0xdc, 0xef, + 0xa2, 0xae, 0xeb, 0x43, 0x25, 0xd6, 0x1a, 0x6a, 0xe0, 0x48, 0x68, 0x18, + 0xa9, 0x53, 0x82, 0xa7, 0x98, 0x60, 0xff, 0x00, 0x7d, 0x15, 0xc2, 0x54, + 0xdf, 0x54, 0x84, 0x63, 0xcb, 0xb1, 0xf5, 0xd5, 0x4e, 0xfd, 0x5f, 0x3b, + 0xf1, 0x7b, 0xbb, 0xb6, 0x4c, 0x4e, 0x23, 0x5f, 0x60, 0x32, 0x31, 0xa7, + 0x41, 0xf2, 0x83, 0x8b, 0x0b, 0xbc, 0x59, 0x1a, 0x98, 0x37, 0xcb, 0xc8, + 0x25, 0x55, 0x19, 0x23, 0x9b, 0x24, 0x7e, 0x7b, 0xe8, 0x1b, 0x4a, 0xab, + 0xd5, 0xc4, 0x65, 0x1c, 0xcc, 0x18, 0x60, 0x74, 0xdb, 0x1a, 0xb5, 0xc1, + 0x50, 0x95, 0x36, 0xf8, 0xa7, 0x45, 0x1e, 0x2c, 0x43, 0x1b, 0x9e, 0xa4, + 0x6c, 0x47, 0xe7, 0x55, 0x4a, 0x80, 0x61, 0xb9, 0x4b, 0x2a, 0x46, 0xd1, + 0xa3, 0x13, 0xca, 0x06, 0xe4, 0x12, 0x7a, 0x69, 0xcb, 0xc3, 0x25, 0x16, + 0x5a, 0x89, 0x12, 0x47, 0x91, 0xf5, 0x0d, 0xf5, 0x55, 0xe2, 0x66, 0x4a, + 0x69, 0x0d, 0x44, 0x67, 0xcf, 0x9f, 0xd0, 0xe9, 0x9b, 0xd4, 0x4c, 0x82, + 0x92, 0x26, 0x86, 0x68, 0xda, 0xa1, 0x80, 0x42, 0xd1, 0xf6, 0xe8, 0x71, + 0xbf, 0x5d, 0x53, 0x78, 0xb6, 0xa1, 0xa3, 0xe2, 0x1a, 0x8a, 0x0c, 0x3a, + 0xc3, 0x4f, 0x21, 0x8c, 0xc6, 0xdd, 0x43, 0x03, 0xe6, 0xcf, 0xbe, 0x46, + 0xaf, 0x3e, 0x54, 0xfc, 0x50, 0x49, 0x86, 0x96, 0x79, 0x5b, 0xc4, 0x73, + 0x92, 0x7a, 0xeb, 0x87, 0xcf, 0x36, 0x74, 0x4b, 0x18, 0xe5, 0xa7, 0x8e, + 0x48, 0x54, 0x05, 0x2b, 0xa2, 0xf8, 0x7e, 0xdf, 0x51, 0x57, 0x5c, 0xb2, + 0x47, 0x1a, 0x48, 0x91, 0x9e, 0x66, 0x0f, 0x9c, 0x1c, 0x1e, 0x87, 0x1a, + 0x5a, 0xe8, 0xb3, 0xba, 0x41, 0xfc, 0x3e, 0x38, 0x6b, 0xe4, 0x6c, 0x3c, + 0x11, 0x16, 0x89, 0x39, 0x72, 0x09, 0x6d, 0xc1, 0x3f, 0x63, 0x83, 0xa8, + 0x6d, 0xa9, 0x1d, 0x4b, 0x9a, 0xaa, 0x89, 0x32, 0x5c, 0x31, 0xa8, 0x90, + 0x8e, 0x63, 0xd3, 0xaf, 0xf6, 0xc6, 0xac, 0x17, 0xb1, 0x59, 0x32, 0xcc, + 0x95, 0x0b, 0x0a, 0xf9, 0x08, 0x41, 0x1a, 0x72, 0xa8, 0xff, 0x00, 0x97, + 0x19, 0xd2, 0x9b, 0x3c, 0xd1, 0xc0, 0x94, 0x91, 0x14, 0x42, 0xf2, 0xc0, + 0xf0, 0x37, 0x30, 0xcf, 0x29, 0x23, 0x63, 0xa6, 0x23, 0x7e, 0x9f, 0x95, + 0x60, 0xdc, 0x2d, 0x22, 0xcb, 0x0c, 0x88, 0xcf, 0x29, 0xa9, 0x86, 0x63, + 0x24, 0x4c, 0xa4, 0xe5, 0x81, 0x1d, 0xf1, 0xf6, 0xd5, 0xba, 0x3a, 0xb8, + 0xab, 0xf8, 0x6e, 0x38, 0x48, 0x65, 0x9e, 0x4f, 0x17, 0x92, 0x10, 0x3e, + 0x97, 0x56, 0xff, 0x00, 0x3c, 0xe3, 0x3e, 0xda, 0x43, 0xc3, 0x4d, 0x10, + 0xb9, 0x1f, 0x91, 0x4c, 0xcb, 0x4e, 0x18, 0xbc, 0x8c, 0x00, 0x51, 0xb7, + 0x98, 0x31, 0x3d, 0xbb, 0x0f, 0x4d, 0xb5, 0xf2, 0x9f, 0xf9, 0xbc, 0x49, + 0x0c, 0x85, 0x84, 0x8b, 0x34, 0x26, 0xa2, 0x6c, 0x9c, 0x98, 0xf2, 0x32, + 0xc0, 0x1e, 0xfb, 0xe3, 0xf4, 0xd1, 0xa6, 0x5a, 0x85, 0x4a, 0xc8, 0x61, + 0x91, 0x7c, 0xa9, 0x22, 0x81, 0x20, 0x1f, 0x4b, 0x0e, 0x87, 0xd3, 0xef, + 0xa2, 0x62, 0x63, 0x4d, 0x2a, 0x54, 0x14, 0xe5, 0x0c, 0x4a, 0xb2, 0xe7, + 0xb6, 0x86, 0x42, 0xf2, 0x09, 0x9d, 0xfe, 0xb2, 0xdc, 0xf9, 0xf7, 0x27, + 0x4c, 0xae, 0x54, 0xc1, 0x6d, 0xf4, 0xd5, 0x87, 0xac, 0xab, 0xca, 0xdf, + 0x71, 0xd3, 0x43, 0x66, 0xcb, 0x21, 0x30, 0x14, 0xb9, 0xff, 0x00, 0x31, + 0x1e, 0x28, 0x66, 0x5c, 0x83, 0x8d, 0x98, 0x7d, 0xf4, 0x1d, 0xd1, 0x15, + 0x2c, 0xd5, 0x6a, 0xb1, 0xf3, 0x34, 0x28, 0xd2, 0x28, 0x0c, 0x40, 0x20, + 0x03, 0xb1, 0xc7, 0x51, 0xa7, 0xd1, 0x47, 0xf3, 0x02, 0xcc, 0x5d, 0xb9, + 0xd4, 0xc6, 0xeb, 0x9f, 0x42, 0x08, 0x1a, 0x89, 0x21, 0x8d, 0x2e, 0x8f, + 0x04, 0xcb, 0x98, 0xca, 0xb0, 0xfb, 0x8d, 0x4b, 0x24, 0xe3, 0xc1, 0x4b, + 0xb2, 0x99, 0x3c, 0x08, 0xe4, 0x32, 0x25, 0x24, 0x72, 0xec, 0xdc, 0xf2, + 0x16, 0xc8, 0xef, 0xb6, 0x33, 0x8d, 0x6b, 0x3f, 0x09, 0x67, 0xa2, 0xb4, + 0xf1, 0xc5, 0x80, 0xc1, 0x75, 0x49, 0x12, 0xa2, 0xa1, 0x44, 0xa8, 0xb1, + 0x91, 0xb6, 0x3a, 0x80, 0x7b, 0x7f, 0xae, 0xa9, 0x13, 0x9b, 0x5d, 0xb1, + 0x27, 0xa2, 0xaf, 0x94, 0xc0, 0xc8, 0xc7, 0xc1, 0x65, 0x21, 0x81, 0x5c, + 0xe0, 0x65, 0x7e, 0xda, 0x55, 0x45, 0x55, 0x15, 0x1d, 0xca, 0x39, 0x29, + 0xe4, 0x2b, 0x89, 0x39, 0xe1, 0x60, 0x70, 0xcb, 0x83, 0xdb, 0xdb, 0x52, + 0x16, 0x9f, 0x28, 0xe7, 0x38, 0xf2, 0x7b, 0xea, 0x4b, 0xcd, 0x6d, 0xbe, + 0xef, 0x4d, 0x45, 0x0d, 0xb6, 0x69, 0xe8, 0x66, 0x1b, 0xce, 0xb9, 0x21, + 0x0f, 0xf9, 0x68, 0x8b, 0xdf, 0x11, 0x4f, 0x47, 0x75, 0xa3, 0xa0, 0xa6, + 0xb4, 0xcd, 0x58, 0x95, 0x07, 0x0c, 0xe8, 0xdb, 0x2f, 0xa9, 0x3b, 0x1d, + 0x65, 0x3f, 0x07, 0x3e, 0x2c, 0x45, 0x7e, 0xa7, 0x92, 0xd3, 0x5c, 0x39, + 0x6e, 0x09, 0x1f, 0x2a, 0x11, 0xd2, 0x53, 0x8e, 0xb8, 0xed, 0xd3, 0x5a, + 0x65, 0x96, 0xed, 0x53, 0x25, 0xa9, 0x5a, 0xb5, 0x39, 0x6b, 0x5c, 0x9e, + 0x6c, 0x2e, 0x00, 0x1a, 0xd3, 0x43, 0x93, 0x2c, 0xf4, 0x2b, 0x04, 0x61, + 0x96, 0x24, 0xe5, 0x27, 0x73, 0xeb, 0xed, 0xa2, 0x5d, 0xd5, 0x17, 0x2d, + 0xf6, 0xd2, 0x9b, 0x5c, 0xc5, 0x61, 0x52, 0xdb, 0x93, 0xbe, 0x74, 0x75, + 0x44, 0x88, 0xf0, 0x1d, 0x1d, 0x96, 0xd9, 0x29, 0x94, 0x75, 0x07, 0x6c, + 0x68, 0x2a, 0xc9, 0xb6, 0x03, 0x27, 0x73, 0x8d, 0x41, 0x2c, 0x98, 0x5c, + 0x73, 0x76, 0xd0, 0xd3, 0x4b, 0x90, 0xbe, 0x6e, 0x9b, 0xea, 0x14, 0x1d, + 0x03, 0x79, 0x80, 0x3b, 0xfb, 0xe8, 0x95, 0x21, 0x77, 0x63, 0x8d, 0x2e, + 0xa5, 0x94, 0x39, 0x07, 0x47, 0x9f, 0x32, 0x11, 0xea, 0x35, 0x08, 0x2c, + 0xbb, 0xd4, 0x72, 0x82, 0x01, 0xfb, 0x68, 0x2a, 0x75, 0x21, 0x10, 0x8f, + 0xa8, 0xef, 0xae, 0x6e, 0x44, 0x9a, 0xd1, 0x1b, 0x74, 0xd1, 0x74, 0x91, + 0x86, 0x95, 0x41, 0xc0, 0x5e, 0xe4, 0x9c, 0x76, 0xd0, 0xc8, 0xbf, 0x56, + 0x35, 0xa2, 0xa8, 0xcc, 0x18, 0x3b, 0x91, 0xac, 0xd7, 0xe3, 0x77, 0x06, + 0xd5, 0x5f, 0x0c, 0x17, 0xdb, 0x72, 0xc6, 0x65, 0x82, 0x13, 0x1c, 0xca, + 0xcc, 0x17, 0x2a, 0x0e, 0x41, 0xcf, 0x73, 0xbf, 0x4d, 0x5a, 0x6c, 0xf7, + 0x8a, 0x09, 0xa4, 0x6a, 0x68, 0x2a, 0x01, 0x62, 0xc7, 0xcb, 0xe8, 0x7d, + 0x34, 0xf2, 0x0a, 0x98, 0xd9, 0x4c, 0x13, 0xae, 0x53, 0x3b, 0xfa, 0x1f, + 0xbe, 0xb3, 0xc5, 0xc3, 0x53, 0x8d, 0xa1, 0x52, 0x71, 0xc8, 0xb6, 0xa6, + 0x79, 0x49, 0xa9, 0xe5, 0x8d, 0xf9, 0x1e, 0x32, 0x0e, 0x31, 0x9e, 0xda, + 0xbd, 0x58, 0xab, 0x26, 0x7b, 0x4c, 0x34, 0x4a, 0x04, 0xd5, 0x0a, 0xa3, + 0x94, 0xbf, 0x51, 0xe8, 0x3e, 0xda, 0xd4, 0xef, 0x5c, 0x07, 0xc3, 0x37, + 0x69, 0x3c, 0x6f, 0x0e, 0x4a, 0x67, 0x0d, 0x9c, 0xc0, 0xc0, 0x64, 0xfd, + 0x88, 0x3a, 0x92, 0xd1, 0xc2, 0xdc, 0x37, 0x60, 0xcc, 0xf1, 0xc6, 0xd3, + 0x54, 0x0f, 0x31, 0x79, 0xbc, 0xc7, 0xf4, 0xe9, 0xac, 0x7a, 0x5d, 0x04, + 0xb1, 0xcd, 0xb6, 0xf8, 0x11, 0x0d, 0x3b, 0x83, 0xe4, 0x49, 0xc2, 0xfc, + 0x39, 0x72, 0xac, 0x8a, 0x37, 0xbb, 0xc5, 0x4c, 0xb4, 0x44, 0x15, 0x6a, + 0x67, 0x4c, 0xb3, 0x83, 0x82, 0x18, 0x10, 0x46, 0x3a, 0x68, 0x3e, 0x36, + 0xb1, 0x35, 0x92, 0xa6, 0x3a, 0xfa, 0x31, 0x31, 0xa5, 0x3b, 0x2a, 0x46, + 0x76, 0x88, 0xf4, 0xdf, 0x3f, 0x7e, 0xba, 0xb0, 0x71, 0x0d, 0xfe, 0x0a, + 0x78, 0xcc, 0xb3, 0x55, 0x88, 0x3c, 0xb9, 0x89, 0x72, 0x00, 0x3e, 0x99, + 0xc9, 0x03, 0x1f, 0xe9, 0xaa, 0x5c, 0x7f, 0x16, 0x2d, 0x36, 0x62, 0xd4, + 0xf5, 0xd7, 0x1f, 0xe2, 0x21, 0x9f, 0x99, 0x97, 0x93, 0x9d, 0x87, 0xa8, + 0xe6, 0x1e, 0x50, 0x07, 0xa0, 0x27, 0x5b, 0xd4, 0x03, 0xd8, 0x9f, 0x42, + 0xfa, 0x4e, 0x17, 0xae, 0x37, 0x75, 0xbc, 0xd7, 0xd5, 0x8a, 0xce, 0x64, + 0x23, 0xc0, 0x66, 0xce, 0x33, 0xbe, 0x73, 0xed, 0xd3, 0x54, 0x1f, 0x8a, + 0x94, 0x33, 0xc1, 0xc4, 0x9e, 0x38, 0xa4, 0x30, 0xc1, 0x34, 0x4a, 0x50, + 0x21, 0xe6, 0x24, 0x8c, 0x0d, 0xbf, 0xd3, 0x57, 0x4b, 0xc7, 0xc5, 0x4e, + 0x1b, 0xbc, 0x56, 0xc9, 0x0d, 0xb2, 0xd7, 0x74, 0xab, 0x90, 0x27, 0x24, + 0x2b, 0x4d, 0xf4, 0xc4, 0xc3, 0x6c, 0x9c, 0xed, 0x81, 0xef, 0x81, 0xaa, + 0xb9, 0x5b, 0x9d, 0x7c, 0x82, 0xbe, 0xf1, 0x0c, 0xa2, 0x9f, 0x18, 0x8e, + 0x57, 0xab, 0x40, 0x99, 0xea, 0x72, 0xc0, 0x04, 0x03, 0xdb, 0x9b, 0xf5, + 0x3a, 0xcb, 0x2c, 0x79, 0x25, 0x26, 0x9a, 0x2f, 0xf8, 0xae, 0x5d, 0x99, + 0xbf, 0x10, 0xd1, 0x49, 0x51, 0xc4, 0xf7, 0x18, 0x60, 0x4f, 0x11, 0x9e, + 0xb6, 0x5c, 0x8e, 0x9d, 0x5c, 0xef, 0xaf, 0xd7, 0x27, 0xa6, 0xb5, 0xdb, + 0x7f, 0x87, 0xc5, 0x2b, 0x7c, 0xcb, 0x6e, 0xee, 0x9d, 0xbd, 0x8e, 0xae, + 0x8b, 0x69, 0xaa, 0x9a, 0xff, 0x00, 0x51, 0x41, 0x6c, 0xa6, 0xf1, 0xee, + 0x97, 0x4a, 0xa9, 0x92, 0x05, 0xce, 0xc0, 0x73, 0x12, 0x58, 0x9f, 0xe9, + 0x03, 0x1a, 0x33, 0x8c, 0x3e, 0x03, 0xf1, 0x3d, 0x05, 0x8e, 0xba, 0xf1, + 0xf3, 0xf4, 0xf5, 0xa6, 0x91, 0x11, 0xd2, 0x08, 0x54, 0x97, 0x75, 0xc6, + 0x64, 0x3f, 0xfe, 0xbe, 0x9b, 0xe7, 0xdb, 0x57, 0x91, 0x78, 0xd9, 0x96, + 0x78, 0x9b, 0x6d, 0xa3, 0x19, 0xab, 0xa9, 0x96, 0x56, 0x26, 0x49, 0x1e, + 0x42, 0x06, 0x01, 0x63, 0x9d, 0x4b, 0x6a, 0x89, 0x5d, 0x59, 0x83, 0x79, + 0xbd, 0x31, 0xa8, 0xe7, 0xa6, 0x90, 0x30, 0x52, 0xaf, 0xcf, 0x9d, 0xd7, + 0x97, 0x7d, 0x3c, 0xb6, 0x5b, 0xda, 0x9a, 0x8f, 0xc7, 0x64, 0x09, 0x2c, + 0xa5, 0x17, 0x04, 0x67, 0x0a, 0x71, 0x81, 0xf7, 0xff, 0x00, 0xc6, 0xb1, + 0xa7, 0xb8, 0xcc, 0xe0, 0x19, 0x67, 0xb8, 0x47, 0x6d, 0x82, 0x59, 0x67, + 0x93, 0x96, 0x30, 0xa4, 0x6b, 0x3c, 0xb8, 0x39, 0x9e, 0xe9, 0x51, 0x3a, + 0x93, 0x99, 0x27, 0x66, 0x5c, 0xf6, 0x19, 0x3a, 0xd3, 0x69, 0x68, 0xd3, + 0xe6, 0x5a, 0xa2, 0xa6, 0x30, 0xe3, 0x9b, 0x11, 0xa9, 0x18, 0xc0, 0xf5, + 0xfb, 0xeb, 0x39, 0xbb, 0xd2, 0x9a, 0x6b, 0xbd, 0x44, 0x1c, 0xc4, 0xf2, + 0xc8, 0x70, 0x71, 0xef, 0xa7, 0xec, 0xa4, 0x83, 0x8a, 0xa2, 0xc1, 0xc3, + 0xb5, 0x8d, 0x08, 0x62, 0x42, 0xb8, 0x65, 0x1e, 0x56, 0x19, 0x04, 0xea, + 0xc5, 0xc2, 0xd4, 0xf0, 0xdc, 0x38, 0x80, 0x07, 0x89, 0xe9, 0xbc, 0xa7, + 0x2c, 0x06, 0x42, 0x9c, 0x8f, 0xb6, 0xda, 0xa7, 0xd2, 0x18, 0xd6, 0x8c, + 0xc6, 0xc0, 0x99, 0x41, 0x05, 0x5b, 0xdb, 0x5a, 0x0f, 0x00, 0xa5, 0x6a, + 0x8a, 0x79, 0x62, 0x85, 0xd9, 0x2a, 0x33, 0x0b, 0xbe, 0x3c, 0xb8, 0xe5, + 0xce, 0x33, 0xeb, 0xb8, 0x3a, 0x73, 0x9d, 0x2b, 0xfd, 0x06, 0x32, 0xe2, + 0xee, 0x1c, 0xb0, 0xd8, 0xfe, 0x21, 0xd0, 0x0a, 0xab, 0xbd, 0x45, 0x55, + 0x35, 0x34, 0x70, 0x4c, 0x44, 0x6a, 0x3e, 0xb2, 0xbc, 0xc5, 0x48, 0x1e, + 0xf8, 0xeb, 0xd3, 0x3a, 0xcd, 0x38, 0xa6, 0xcf, 0x4b, 0x5d, 0xc6, 0xb7, + 0xab, 0xa4, 0xf5, 0x11, 0x52, 0xc5, 0x2c, 0x8e, 0xeb, 0x19, 0x04, 0x99, + 0x25, 0x7d, 0xf9, 0x17, 0x19, 0xe9, 0x83, 0xbf, 0xdb, 0xd7, 0x56, 0xab, + 0xdd, 0xd6, 0x3b, 0xab, 0x19, 0xa2, 0x6e, 0x49, 0xa1, 0x25, 0x1c, 0x31, + 0xfa, 0x58, 0x10, 0x33, 0xf6, 0xdb, 0x55, 0x8f, 0x88, 0x15, 0xd4, 0xa6, + 0x3b, 0x5c, 0x14, 0x30, 0x39, 0xae, 0x87, 0x9d, 0xab, 0x66, 0x32, 0x65, + 0x67, 0x91, 0xfb, 0xa6, 0xdb, 0x00, 0x30, 0x3f, 0x1a, 0xcc, 0xa5, 0xf2, + 0x64, 0xe3, 0xa2, 0xd1, 0x52, 0x2f, 0xfc, 0x3e, 0x8a, 0x65, 0x48, 0xc4, + 0xb2, 0x87, 0x0a, 0xa5, 0x86, 0x00, 0x04, 0x1c, 0x6d, 0xed, 0x8d, 0x4d, + 0x69, 0xe2, 0xbb, 0xc5, 0x34, 0x4b, 0x1c, 0x12, 0xc5, 0x1a, 0xa8, 0x21, + 0x93, 0xc3, 0x18, 0x66, 0xf5, 0x3d, 0xce, 0x87, 0xe2, 0x58, 0xd9, 0x2b, + 0xa3, 0xb6, 0x42, 0xe1, 0xc5, 0x10, 0xc0, 0x23, 0x6c, 0xb9, 0xc1, 0x63, + 0xf8, 0x27, 0x1a, 0x0c, 0x4b, 0x19, 0x5e, 0x42, 0xac, 0x58, 0x7f, 0xc4, + 0x38, 0xfa, 0x4e, 0xb5, 0xf4, 0x39, 0x16, 0x7b, 0x15, 0xc6, 0xe7, 0x73, + 0xae, 0x35, 0xb5, 0x0c, 0x25, 0x00, 0x9e, 0x71, 0xd1, 0x11, 0x7d, 0x00, + 0xec, 0x75, 0x2d, 0x4c, 0x40, 0x1a, 0x98, 0xa9, 0xd5, 0xb1, 0x16, 0x64, + 0x4d, 0xf3, 0xe5, 0x27, 0xae, 0x74, 0x82, 0xd1, 0x72, 0xa9, 0xb7, 0x64, + 0x42, 0xd9, 0x89, 0x98, 0x97, 0x18, 0xea, 0x0e, 0xad, 0x36, 0xf9, 0xc5, + 0x6c, 0x2c, 0x88, 0x03, 0x10, 0x79, 0xe2, 0x5f, 0x62, 0x3a, 0x7e, 0xfa, + 0xb4, 0x6c, 0xd3, 0x83, 0x50, 0xc0, 0xb3, 0xd4, 0xc5, 0x5b, 0x01, 0xf0, + 0x96, 0x58, 0xb9, 0x26, 0xe6, 0x53, 0x82, 0xc3, 0x6e, 0xde, 0xa7, 0x18, + 0xd3, 0x7b, 0x2c, 0x71, 0x52, 0xdf, 0xed, 0xf5, 0xf1, 0x0c, 0x53, 0x73, + 0x9a, 0x1a, 0x96, 0x1f, 0xff, 0x00, 0x66, 0x3f, 0xb6, 0x30, 0x7f, 0x3a, + 0x5d, 0x65, 0x45, 0x8a, 0xa5, 0xa1, 0x9d, 0xfc, 0x0d, 0xd8, 0xb6, 0xdc, + 0xc0, 0x95, 0xdf, 0x18, 0xfb, 0x8e, 0xba, 0xea, 0xcf, 0x3a, 0xcb, 0x69, + 0xbc, 0xa5, 0x53, 0xb1, 0x95, 0x58, 0xbb, 0x39, 0x3d, 0xf9, 0x87, 0x2e, + 0x3e, 0xc7, 0x23, 0xf1, 0xa2, 0x43, 0x3d, 0x93, 0x49, 0x11, 0xa7, 0x9a, + 0x78, 0x60, 0x3e, 0x54, 0x6f, 0x5c, 0xe0, 0x69, 0x84, 0x15, 0x08, 0xd6, + 0x41, 0x4f, 0x50, 0x39, 0x8b, 0x49, 0x98, 0x37, 0xdd, 0x98, 0x03, 0xd3, + 0xf7, 0xd0, 0x15, 0x14, 0xb5, 0x0e, 0x94, 0xf7, 0x17, 0x85, 0x9a, 0x39, + 0x23, 0x0b, 0x20, 0x88, 0xe4, 0x82, 0x36, 0x39, 0xd7, 0x0e, 0xc6, 0x98, + 0x2c, 0x94, 0x75, 0x0d, 0xe4, 0x60, 0x40, 0xce, 0xe1, 0xbd, 0xff, 0x00, + 0x7d, 0x50, 0xf4, 0x7e, 0x6a, 0xa9, 0xff, 0x00, 0x85, 0x53, 0x49, 0x48, + 0x18, 0x4b, 0x04, 0xce, 0x84, 0x77, 0xc6, 0x73, 0x9f, 0xdb, 0x45, 0xb2, + 0x4b, 0x2d, 0xe2, 0x63, 0xcc, 0x59, 0xbc, 0x2e, 0x60, 0x01, 0xc6, 0x0e, + 0x3d, 0x75, 0xc9, 0x84, 0x5d, 0xe9, 0x25, 0xa8, 0x5c, 0x53, 0x55, 0x27, + 0xf5, 0x46, 0x70, 0x8c, 0xc7, 0x3e, 0x56, 0x1d, 0x8e, 0x74, 0x4d, 0x9a, + 0x41, 0x58, 0xd4, 0x8d, 0x2e, 0x56, 0xaa, 0x37, 0x30, 0xb8, 0x23, 0xa8, + 0x39, 0xe5, 0x38, 0xfd, 0xb5, 0x54, 0x49, 0x15, 0xae, 0x28, 0xa3, 0x2f, + 0xc4, 0xd3, 0x54, 0x48, 0xac, 0xf0, 0x48, 0x82, 0x52, 0x71, 0xb1, 0x63, + 0x8d, 0x89, 0xf5, 0xeb, 0xa5, 0xdc, 0xb8, 0x6f, 0x11, 0x5b, 0x0f, 0x1e, + 0x42, 0xae, 0x3a, 0x2f, 0xae, 0xad, 0x9c, 0x49, 0x56, 0xf4, 0xf6, 0xfa, + 0x3b, 0x8d, 0x1c, 0x41, 0xd3, 0xc3, 0xe4, 0x92, 0x22, 0xde, 0x5d, 0xb2, + 0x37, 0xfd, 0x35, 0x4b, 0x37, 0xba, 0xda, 0x89, 0x8a, 0x9a, 0x6a, 0x78, + 0x81, 0x18, 0xe9, 0x80, 0x07, 0xaf, 0xbf, 0x6d, 0x15, 0x18, 0x72, 0x7d, + 0xd9, 0x75, 0xf8, 0x4f, 0x7c, 0xa5, 0xb3, 0xf1, 0xc5, 0xb2, 0xbe, 0xa9, + 0x4a, 0x94, 0x94, 0x02, 0xfc, 0xd8, 0x18, 0xf7, 0xd7, 0xb7, 0xa8, 0xea, + 0xe9, 0xea, 0x29, 0xa3, 0x9a, 0x98, 0xa3, 0x41, 0x22, 0x86, 0x46, 0x43, + 0x90, 0x41, 0xe8, 0x75, 0xe0, 0x2b, 0x7c, 0x15, 0x0b, 0x02, 0x4d, 0x3d, + 0x3a, 0x87, 0xce, 0x41, 0xe5, 0xc1, 0x03, 0x5e, 0x90, 0xff, 0x00, 0x67, + 0x6e, 0x2a, 0x6b, 0x85, 0xa4, 0xd8, 0x2b, 0x80, 0x13, 0x52, 0xe5, 0xa9, + 0xb2, 0x73, 0x94, 0xcf, 0x4d, 0x32, 0x2c, 0xa8, 0x48, 0xdd, 0xe0, 0x99, + 0x55, 0xf1, 0xeb, 0xdf, 0x45, 0xbc, 0xbc, 0x89, 0x91, 0xbe, 0xfa, 0x4b, + 0x4a, 0xdc, 0xca, 0x07, 0x71, 0xa2, 0x26, 0x9f, 0x92, 0x22, 0x19, 0xbb, + 0x69, 0xa8, 0x68, 0x45, 0x44, 0xfe, 0x5e, 0xb8, 0xd2, 0xca, 0xa9, 0xfa, + 0xf9, 0xbb, 0xe9, 0x7c, 0xb5, 0x8a, 0xb2, 0x31, 0x2c, 0xaa, 0xbe, 0xa5, + 0x80, 0xc0, 0xd2, 0xea, 0xdb, 0xac, 0x14, 0xea, 0xd3, 0xb3, 0x3b, 0xc0, + 0x33, 0xe7, 0x8d, 0x4b, 0xef, 0xd7, 0xb6, 0xac, 0x83, 0xbb, 0x75, 0x63, + 0xa5, 0x49, 0x8d, 0x8f, 0x95, 0x89, 0x20, 0xea, 0xd1, 0x4a, 0xcc, 0x62, + 0x04, 0xee, 0x35, 0xe7, 0xeb, 0xd7, 0x12, 0x5c, 0xab, 0x49, 0xa9, 0x49, + 0x24, 0xa3, 0x89, 0x1f, 0xc2, 0x86, 0x15, 0xf3, 0x4b, 0x29, 0x39, 0x39, + 0xed, 0xca, 0x36, 0x1b, 0x9f, 0x5e, 0x9a, 0xdb, 0x12, 0xbd, 0xa8, 0xf8, + 0x7e, 0x0a, 0xaa, 0x85, 0x31, 0x4e, 0xd0, 0x2b, 0x14, 0x3d, 0x41, 0x2a, + 0x09, 0xce, 0x91, 0x8b, 0x3a, 0xc9, 0x26, 0x97, 0xa0, 0x20, 0xd4, 0x9d, + 0x20, 0x6b, 0xcb, 0x78, 0x77, 0x50, 0x3a, 0xe4, 0x67, 0x46, 0x51, 0x1f, + 0x19, 0x25, 0x88, 0x0c, 0x17, 0x52, 0x07, 0xdf, 0x1a, 0xa5, 0x35, 0xf2, + 0xbe, 0xe3, 0xc4, 0x51, 0x43, 0x48, 0x61, 0x9e, 0x30, 0xa7, 0xc6, 0x04, + 0x79, 0x90, 0x9d, 0xfa, 0xfd, 0xb5, 0x64, 0xa4, 0xb8, 0x2d, 0x3b, 0xc5, + 0x29, 0x39, 0x05, 0x82, 0xe7, 0xd7, 0x3a, 0xa8, 0xe5, 0x8e, 0x44, 0xf6, + 0xbe, 0x86, 0x5a, 0x92, 0x69, 0x3e, 0x80, 0xa3, 0xe1, 0x1b, 0x65, 0x4c, + 0x4b, 0x2d, 0x7f, 0x96, 0x44, 0x5e, 0x42, 0xb1, 0xca, 0x76, 0x23, 0xb8, + 0xc6, 0x30, 0x74, 0x8a, 0xe4, 0x38, 0x96, 0xc7, 0x7b, 0xa7, 0xb7, 0x5b, + 0x64, 0x96, 0xe7, 0x4b, 0x3a, 0x99, 0x14, 0x48, 0x33, 0x22, 0x28, 0x38, + 0xe5, 0x2d, 0xd8, 0x6e, 0x34, 0xcb, 0x8e, 0xea, 0x64, 0xb4, 0x66, 0x7a, + 0xdb, 0xd5, 0xb2, 0xdf, 0x04, 0x8e, 0x79, 0x92, 0x49, 0xf9, 0x5c, 0x8c, + 0xfd, 0x41, 0x71, 0x92, 0x7d, 0xbb, 0xea, 0x9b, 0x37, 0xc5, 0xce, 0x1b, + 0xa5, 0xb4, 0x34, 0x34, 0x13, 0xd6, 0xd6, 0x4c, 0xb1, 0xf2, 0xc2, 0x44, + 0x44, 0x79, 0xb1, 0xf5, 0x1e, 0xbe, 0x53, 0xe9, 0xae, 0x16, 0x3c, 0x9a, + 0x95, 0x36, 0xa1, 0x0a, 0xff, 0x00, 0x3e, 0x8c, 0xdf, 0x14, 0xa5, 0xe8, + 0xb8, 0xcd, 0xc4, 0x73, 0x50, 0x31, 0xa6, 0xb8, 0xd3, 0xc9, 0x4c, 0xdc, + 0x9c, 0xfb, 0xb6, 0x46, 0x3e, 0xfa, 0xad, 0xdf, 0xbe, 0x23, 0x59, 0xe8, + 0x22, 0x59, 0x85, 0x55, 0x2c, 0x93, 0xf3, 0xf2, 0xad, 0x3b, 0x31, 0x63, + 0x8c, 0xe3, 0x99, 0xb1, 0xd0, 0x7e, 0x7b, 0xeb, 0x22, 0x96, 0xb2, 0xf9, + 0xc6, 0x55, 0xf3, 0x09, 0x1a, 0x69, 0x51, 0x5c, 0xb9, 0x54, 0x41, 0x15, + 0x3c, 0x64, 0xf4, 0xe6, 0xc6, 0xe4, 0x9d, 0xc6, 0x0e, 0x4f, 0x6d, 0x29, + 0x96, 0x2e, 0x1c, 0xa4, 0xac, 0xe6, 0xbe, 0x5c, 0x64, 0x75, 0x89, 0x5d, + 0x65, 0xa7, 0xa3, 0x42, 0x5d, 0x88, 0x38, 0xc1, 0x6f, 0xe9, 0xff, 0x00, + 0xa7, 0x4d, 0x76, 0x71, 0xbc, 0x95, 0x52, 0xec, 0xd4, 0xb0, 0x3f, 0x6c, + 0xb6, 0x71, 0xad, 0xde, 0xcf, 0xc4, 0xb7, 0x65, 0xaa, 0xb9, 0xf1, 0x15, + 0xb6, 0x8a, 0x8a, 0x37, 0xc8, 0x86, 0x29, 0x5e, 0x50, 0xa4, 0xfd, 0x44, + 0xe4, 0x6e, 0x7a, 0x0c, 0x69, 0x7c, 0xf7, 0xbe, 0x04, 0xb4, 0xc4, 0x63, + 0xa2, 0xa9, 0x6a, 0xf9, 0x1b, 0x67, 0x10, 0xc2, 0x79, 0xa5, 0xfc, 0x9c, + 0x05, 0xfd, 0xfa, 0xea, 0xab, 0x57, 0x37, 0x0e, 0x04, 0x0d, 0x64, 0xe1, + 0xaa, 0x8a, 0x97, 0x00, 0x7f, 0x32, 0xb6, 0x76, 0x92, 0x34, 0xce, 0xd9, + 0xe5, 0x18, 0xe6, 0x39, 0x23, 0xfd, 0x34, 0xef, 0x87, 0xb8, 0x16, 0x77, + 0xa4, 0xf9, 0xaa, 0xc7, 0x8a, 0xd9, 0xce, 0xbe, 0x21, 0x62, 0x8a, 0x18, + 0x67, 0xb8, 0xe7, 0xfa, 0x74, 0xdb, 0x1d, 0x08, 0xb5, 0xd1, 0x61, 0x86, + 0xe5, 0x77, 0x7b, 0x64, 0xa2, 0x38, 0xad, 0xbc, 0x27, 0x6a, 0x68, 0xf1, + 0xcd, 0x33, 0x8f, 0x98, 0xe5, 0x3d, 0x08, 0x41, 0xfd, 0x47, 0xfe, 0x6f, + 0x53, 0xaa, 0xcd, 0xde, 0xf1, 0xc2, 0x23, 0x99, 0x5c, 0x5d, 0x2f, 0x72, + 0xa1, 0xc2, 0xd5, 0x56, 0xce, 0x4c, 0x63, 0xd9, 0x46, 0x7a, 0x7a, 0x0c, + 0x0d, 0xb4, 0xba, 0xae, 0xc1, 0x49, 0x3d, 0xda, 0x4a, 0x5a, 0x2a, 0xe1, + 0x58, 0x15, 0xb9, 0x66, 0xa9, 0x79, 0x76, 0x62, 0x33, 0xe5, 0x1d, 0xc9, + 0x1b, 0xe7, 0x1b, 0x68, 0xb8, 0xe2, 0xe1, 0x7a, 0x08, 0x42, 0xd4, 0xd5, + 0xc4, 0xd2, 0x01, 0x90, 0x24, 0xc9, 0x1c, 0xd8, 0xe9, 0x8f, 0x4f, 0x4d, + 0x1b, 0x65, 0xb4, 0x4c, 0xb7, 0xba, 0xfb, 0x4f, 0x1d, 0x56, 0xdc, 0x69, + 0x2b, 0x65, 0xa3, 0xaa, 0xa7, 0xa9, 0x99, 0x20, 0x70, 0x7c, 0xc4, 0x19, + 0x1b, 0x3f, 0x8e, 0xda, 0xd3, 0xf8, 0x67, 0xe3, 0x45, 0xd6, 0x39, 0x61, + 0x8a, 0xfb, 0x8a, 0x88, 0x73, 0xca, 0xd2, 0x20, 0x0a, 0xe4, 0x7b, 0x8e, + 0x87, 0xfb, 0xeb, 0x23, 0xbe, 0xc6, 0x0f, 0x13, 0xdc, 0x9a, 0x60, 0xc5, + 0x8d, 0x54, 0x9c, 0x80, 0x0c, 0xec, 0x1c, 0xe8, 0xfa, 0x63, 0x1b, 0xc6, + 0x09, 0x5c, 0x82, 0x30, 0x41, 0xd2, 0x6e, 0xa3, 0xb4, 0xe3, 0xe4, 0xf1, + 0x67, 0xde, 0x31, 0xa0, 0xa3, 0x8f, 0x8a, 0x6b, 0xaa, 0xed, 0xc9, 0x10, + 0xb7, 0x4c, 0xcd, 0x3d, 0x17, 0x21, 0xdb, 0x0c, 0xd9, 0xc9, 0x1d, 0xb0, + 0x0e, 0x31, 0xdb, 0x43, 0x54, 0x02, 0xd4, 0x54, 0xca, 0x18, 0x85, 0xe6, + 0x8c, 0xe3, 0xf2, 0x34, 0xc6, 0x44, 0x89, 0xa9, 0x8d, 0x3c, 0x69, 0x1b, + 0x33, 0x1f, 0x21, 0x2b, 0xba, 0x3f, 0x62, 0x3e, 0xe7, 0x63, 0xf7, 0xd0, + 0x56, 0x5a, 0x0f, 0xe2, 0x17, 0xcb, 0x75, 0xa2, 0x6a, 0xc4, 0xa7, 0x8e, + 0x79, 0x04, 0x52, 0x36, 0x39, 0xb9, 0x3c, 0xd9, 0x07, 0x1e, 0xb9, 0xc6, + 0xb3, 0x28, 0xed, 0x95, 0x02, 0x9d, 0xc4, 0xb0, 0xf0, 0x55, 0x82, 0x6b, + 0xfd, 0xfa, 0x9e, 0x85, 0x00, 0x31, 0x31, 0x1e, 0x33, 0x90, 0x71, 0x1c, + 0x7d, 0xcf, 0xf6, 0x1f, 0x9d, 0x50, 0xfe, 0x32, 0x5a, 0xa9, 0x6d, 0x5f, + 0x10, 0xaf, 0x94, 0xd4, 0x34, 0xc1, 0x29, 0x29, 0xeb, 0x4a, 0x46, 0x46, + 0xf8, 0x05, 0x43, 0x72, 0x93, 0xeb, 0xb9, 0xd7, 0xaa, 0xed, 0x16, 0x5a, + 0x5e, 0x13, 0x85, 0xe8, 0x28, 0xd8, 0x62, 0x48, 0xd9, 0xaa, 0x4f, 0xf5, + 0xc8, 0x01, 0x1e, 0x6d, 0xba, 0x36, 0x3f, 0x1a, 0xf3, 0x97, 0x19, 0xdd, + 0x29, 0xeb, 0x6d, 0x7c, 0x55, 0x0d, 0x25, 0x12, 0xb0, 0xae, 0xba, 0x1a, + 0xb8, 0xea, 0xa4, 0x39, 0x91, 0x52, 0x2e, 0x60, 0xa9, 0xf6, 0x20, 0x92, + 0x4f, 0xe3, 0x4d, 0xc9, 0xe5, 0x51, 0x06, 0x8c, 0xe2, 0x09, 0xd0, 0x37, + 0x32, 0x8d, 0xba, 0x11, 0x9d, 0x6e, 0x3c, 0x2b, 0x55, 0x40, 0x7e, 0x16, + 0xd1, 0x5b, 0xe5, 0xa3, 0x9e, 0x3a, 0xd4, 0x91, 0xea, 0x22, 0xa9, 0x59, + 0x30, 0x00, 0x6c, 0x13, 0xe5, 0xfb, 0x05, 0xdf, 0xdb, 0x59, 0x07, 0x04, + 0x59, 0xc5, 0xfb, 0x89, 0xe8, 0x6d, 0x23, 0x64, 0xa8, 0x90, 0xf3, 0x9f, + 0x45, 0x00, 0xb1, 0xfe, 0xdf, 0xdb, 0x5e, 0x9c, 0x8b, 0xe1, 0xfc, 0xf1, + 0xd1, 0x22, 0x55, 0xc9, 0x4d, 0x6f, 0xa5, 0x5a, 0x7c, 0x86, 0x73, 0x9e, + 0x45, 0x1b, 0x00, 0x07, 0xae, 0xb8, 0xda, 0xdc, 0xfa, 0x88, 0xc9, 0x43, + 0x12, 0xbf, 0xd8, 0x13, 0x52, 0xfe, 0xd3, 0x05, 0xae, 0xe1, 0xda, 0x81, + 0x0c, 0xdc, 0xd3, 0x89, 0x91, 0xdc, 0xb4, 0x8d, 0xcb, 0xe6, 0x6d, 0xf2, + 0x73, 0xf9, 0xd2, 0xdb, 0x9d, 0x0d, 0xb1, 0xa9, 0x84, 0x1e, 0x19, 0x04, + 0xe0, 0xb3, 0x03, 0xe6, 0xce, 0x3f, 0xb6, 0xac, 0x9c, 0x4b, 0x5a, 0x69, + 0x0c, 0xf0, 0xa4, 0x81, 0xe3, 0xe6, 0x60, 0xa5, 0x98, 0x2f, 0x32, 0xee, + 0x01, 0xdf, 0xf1, 0xac, 0xd2, 0x82, 0x99, 0xea, 0xeb, 0x64, 0xa3, 0xa7, + 0xac, 0x20, 0x80, 0x59, 0xf1, 0xd0, 0x0c, 0xe0, 0x8c, 0xfd, 0xce, 0x9d, + 0xa5, 0xb9, 0xa4, 0xdf, 0x65, 0x20, 0x49, 0x2d, 0x46, 0xdd, 0x5b, 0x3b, + 0x02, 0x5e, 0x19, 0xd4, 0x90, 0xc7, 0xae, 0x73, 0xd0, 0xeb, 0x93, 0x1c, + 0x7f, 0x26, 0xf4, 0x7e, 0x1a, 0x04, 0x76, 0x0f, 0xcd, 0x8f, 0x36, 0x40, + 0x23, 0xaf, 0xa6, 0xfa, 0x7d, 0xf2, 0x49, 0x6e, 0x81, 0xe3, 0x3e, 0x6e, + 0x6e, 0xad, 0xeb, 0xed, 0x9d, 0x71, 0x4f, 0x46, 0x95, 0xd0, 0xb3, 0xd3, + 0x00, 0x42, 0xec, 0xc0, 0x9e, 0x87, 0x5b, 0x5c, 0x87, 0x29, 0x95, 0x65, + 0xa4, 0x44, 0x8a, 0x58, 0x02, 0x61, 0x8f, 0x98, 0x1f, 0x5c, 0x76, 0xd3, + 0xfe, 0x1e, 0x30, 0xac, 0x54, 0xb5, 0x04, 0x12, 0x23, 0x1e, 0x1c, 0xdb, + 0xe0, 0x80, 0x7b, 0xff, 0x00, 0x6d, 0x7c, 0xb8, 0x50, 0x48, 0xb0, 0x1f, + 0x05, 0x59, 0x59, 0x71, 0xcc, 0xfd, 0x40, 0xc7, 0x5c, 0xe8, 0x5a, 0x39, + 0xdd, 0x64, 0x68, 0xe4, 0x05, 0x56, 0x4c, 0x07, 0x1d, 0x41, 0xdf, 0xd7, + 0x4d, 0xc5, 0x3b, 0x56, 0x6a, 0xd2, 0xcf, 0x91, 0x85, 0x7a, 0xad, 0x05, + 0xc3, 0xc3, 0x0c, 0x4a, 0x33, 0x07, 0xe7, 0x53, 0xb3, 0x6f, 0x9f, 0xdc, + 0x68, 0x9a, 0x98, 0x20, 0xb8, 0x55, 0x5d, 0x24, 0x85, 0x4d, 0x27, 0xcc, + 0xc7, 0x12, 0x53, 0xc6, 0x83, 0x79, 0x31, 0x8e, 0x62, 0x7f, 0xd7, 0xd8, + 0xe8, 0x6f, 0x97, 0x82, 0x96, 0x7a, 0xa4, 0xa8, 0x54, 0x94, 0xbc, 0x79, + 0x8b, 0x7c, 0xf2, 0x80, 0x71, 0x91, 0xe8, 0x74, 0x55, 0xa2, 0x17, 0x7a, + 0xba, 0x66, 0xa5, 0x1e, 0x2c, 0x49, 0x19, 0x8f, 0x9a, 0x56, 0x3e, 0x47, + 0x61, 0xb9, 0xc8, 0xec, 0x0e, 0x9b, 0x66, 0xd7, 0xc9, 0x1d, 0x96, 0xb2, + 0xa5, 0x65, 0x31, 0x46, 0xdc, 0xf1, 0x16, 0xdf, 0x27, 0x66, 0x1a, 0x6f, + 0x14, 0x74, 0xa9, 0x4c, 0xce, 0x39, 0xb9, 0xea, 0x25, 0x74, 0xf0, 0x94, + 0x67, 0x93, 0x7d, 0x8e, 0x4e, 0xf8, 0xd4, 0x14, 0xd4, 0xd3, 0x5b, 0x78, + 0x82, 0xa6, 0x9a, 0xb6, 0x9d, 0x23, 0xe6, 0x50, 0x33, 0x17, 0xd0, 0xa0, + 0xee, 0x37, 0xf7, 0xce, 0xbe, 0x56, 0xd2, 0x9b, 0x4d, 0xc9, 0x6b, 0x23, + 0x8c, 0xcb, 0x09, 0x7f, 0xa4, 0x37, 0x4e, 0xf8, 0x3e, 0x9b, 0x6a, 0x30, + 0xa2, 0x88, 0x69, 0xcc, 0x94, 0x57, 0x52, 0x7c, 0xc6, 0x35, 0x2a, 0x1d, + 0x47, 0x7e, 0xbb, 0xe9, 0x90, 0x53, 0x4f, 0x78, 0x92, 0xa2, 0x17, 0x02, + 0x0a, 0xef, 0x2c, 0x52, 0x2e, 0xde, 0x14, 0x9d, 0x41, 0xfd, 0x8e, 0xba, + 0xe2, 0x2a, 0x64, 0xf9, 0x68, 0xaf, 0x14, 0x39, 0x28, 0xdc, 0xae, 0xd9, + 0x39, 0xc0, 0x3d, 0x0f, 0xe3, 0xa6, 0x34, 0x05, 0x75, 0x4d, 0x2d, 0x4f, + 0x0e, 0x35, 0x62, 0x00, 0x67, 0x49, 0x42, 0xbb, 0x2f, 0x73, 0xeb, 0xf7, + 0xef, 0xaa, 0x0d, 0x87, 0x08, 0x45, 0x4d, 0x75, 0x4d, 0x02, 0xc6, 0x40, + 0x59, 0x85, 0x42, 0x46, 0xeb, 0x80, 0x41, 0x18, 0x7f, 0xc7, 0x43, 0xaa, + 0x4d, 0xd6, 0xa6, 0x1b, 0x87, 0x10, 0x22, 0x50, 0xa2, 0xc5, 0x12, 0xc9, + 0x9d, 0x97, 0xea, 0xc6, 0x7a, 0x6a, 0xf1, 0x72, 0x0f, 0x47, 0x53, 0x41, + 0x75, 0x2e, 0xb2, 0xbc, 0x54, 0xd1, 0x34, 0x8a, 0x06, 0xcf, 0x19, 0x18, + 0x20, 0xfd, 0x8e, 0x35, 0x47, 0xe2, 0x8a, 0x38, 0x2d, 0x97, 0xea, 0x82, + 0x8b, 0xcb, 0x4f, 0x54, 0x9e, 0x3d, 0x39, 0xce, 0x70, 0x1b, 0x7f, 0xdb, + 0xa6, 0xad, 0x19, 0x73, 0xae, 0x0b, 0x50, 0xa6, 0x6a, 0x1b, 0x5b, 0xd7, + 0xdc, 0x5f, 0xcc, 0xe7, 0x96, 0x3c, 0x8c, 0xfd, 0x8f, 0xed, 0xa7, 0x1f, + 0x04, 0xaf, 0xcf, 0x6b, 0xe3, 0xfb, 0x7a, 0x00, 0x43, 0xd6, 0x54, 0xaa, + 0x6c, 0x70, 0x00, 0x3d, 0x7f, 0xf1, 0xac, 0xb3, 0xe7, 0x95, 0x6d, 0xed, + 0x14, 0xb2, 0xb4, 0xd2, 0x48, 0xc7, 0xc4, 0x24, 0xe7, 0xec, 0x33, 0xab, + 0xef, 0xc0, 0x0a, 0x09, 0x27, 0xf8, 0x89, 0x63, 0x25, 0x39, 0xb1, 0x52, + 0xa4, 0x7b, 0x0e, 0xa7, 0xf6, 0xd1, 0xc4, 0x44, 0x4f, 0x6e, 0xb1, 0x5e, + 0x75, 0x2a, 0xa1, 0x01, 0x1b, 0x01, 0xe9, 0xeb, 0xa4, 0x7c, 0x57, 0x74, + 0xa7, 0xb5, 0xda, 0xea, 0xeb, 0x6a, 0xe6, 0x11, 0x41, 0x04, 0x4c, 0xf2, + 0x31, 0xec, 0x00, 0xd3, 0xa9, 0x4a, 0x99, 0x32, 0xbf, 0x4a, 0x2e, 0xb0, + 0x7f, 0xf6, 0xa7, 0xe2, 0x94, 0xa5, 0xb0, 0xc3, 0x60, 0x81, 0xc8, 0x9e, + 0xe0, 0xe7, 0xc4, 0x55, 0x3d, 0x23, 0x53, 0xd4, 0xfd, 0xcf, 0xf6, 0x3a, + 0x63, 0x63, 0x51, 0x94, 0x5f, 0xf8, 0xf6, 0xff, 0x00, 0xc4, 0x77, 0x4a, + 0xd6, 0x35, 0xf5, 0x30, 0xd0, 0x34, 0xdc, 0xa9, 0x0a, 0x30, 0x1c, 0xb1, + 0x6f, 0x80, 0x76, 0xdf, 0x6d, 0xb5, 0xdc, 0xbc, 0x47, 0x53, 0xf3, 0xf5, + 0x74, 0x56, 0xda, 0xc9, 0x29, 0xa8, 0x0b, 0x83, 0x1c, 0x68, 0x4a, 0xb3, + 0x63, 0x6c, 0x92, 0x31, 0x9d, 0x56, 0x6d, 0x74, 0x5e, 0x2c, 0x1e, 0x29, + 0xa8, 0x58, 0xff, 0x00, 0xa5, 0x55, 0xd4, 0x8f, 0x13, 0x1e, 0x9a, 0xfd, + 0x4b, 0x14, 0x82, 0xf9, 0x0b, 0xb4, 0x4e, 0xb0, 0x44, 0xc0, 0x49, 0x21, + 0x5e, 0xdf, 0x6d, 0x62, 0x72, 0x94, 0xd3, 0x89, 0x9d, 0xdb, 0xb4, 0x8d, + 0xe7, 0xe0, 0x15, 0x8e, 0xe5, 0xc4, 0x17, 0xef, 0x98, 0xb9, 0x09, 0x1a, + 0xd3, 0x42, 0x7c, 0x4e, 0x79, 0x06, 0x79, 0xdc, 0x74, 0x50, 0x7b, 0xff, + 0x00, 0xd3, 0x5a, 0x77, 0xc5, 0x1e, 0x2b, 0xa5, 0xa2, 0x43, 0x11, 0x9c, + 0x21, 0x07, 0x94, 0x31, 0xd8, 0x2e, 0x3a, 0x93, 0xe8, 0x06, 0xa8, 0x77, + 0xef, 0x8a, 0x74, 0x74, 0x56, 0x18, 0x6d, 0x3c, 0x27, 0x47, 0xe1, 0xd2, + 0xc3, 0x12, 0xc6, 0x27, 0x90, 0x00, 0x84, 0x8e, 0xbb, 0x77, 0xc7, 0xdf, + 0x59, 0xf5, 0x4d, 0xee, 0xbe, 0xf6, 0xe6, 0x79, 0x99, 0x6e, 0x55, 0x59, + 0x38, 0x12, 0x36, 0x51, 0x47, 0xd8, 0x6c, 0x07, 0xdf, 0x27, 0x4c, 0x86, + 0x3f, 0x8f, 0x15, 0x47, 0xb3, 0x44, 0x31, 0x54, 0x69, 0x70, 0x5f, 0x69, + 0xbe, 0x21, 0xf0, 0xd5, 0xaa, 0x1f, 0xfe, 0x9f, 0x2c, 0xd5, 0x55, 0x72, + 0x00, 0x6a, 0x3c, 0x38, 0x39, 0x8c, 0x8c, 0x47, 0x9b, 0x7e, 0xc0, 0xe4, + 0xea, 0xb1, 0xc4, 0x5c, 0x6f, 0x7c, 0xba, 0xd5, 0x43, 0x50, 0x95, 0x37, + 0x0b, 0x65, 0x3c, 0x3f, 0x42, 0xc3, 0x10, 0x0e, 0xc7, 0xb1, 0x1b, 0xfe, + 0xfa, 0x54, 0xd7, 0xfe, 0x21, 0xb3, 0x42, 0x89, 0x4d, 0x6d, 0xb5, 0xd3, + 0xc1, 0x1f, 0x2f, 0x3c, 0x49, 0x16, 0x5d, 0x8e, 0x06, 0xe7, 0xbb, 0x7a, + 0xfa, 0x7b, 0x68, 0x6a, 0xee, 0x2e, 0xbe, 0xd5, 0xce, 0xe5, 0xea, 0x68, + 0xbc, 0x73, 0x9f, 0x0d, 0xd2, 0x21, 0xcc, 0x83, 0x3f, 0xd2, 0x3a, 0x03, + 0xd3, 0x7c, 0x67, 0x43, 0x87, 0x14, 0x71, 0x7d, 0x46, 0x43, 0x02, 0xc6, + 0xb8, 0x19, 0x7c, 0xe3, 0xb5, 0x48, 0xaa, 0x97, 0x87, 0x12, 0xe1, 0x70, + 0x9f, 0xfe, 0x1d, 0x55, 0xca, 0xa5, 0xe7, 0x76, 0x63, 0xbe, 0x79, 0x00, + 0xc1, 0xf5, 0xc6, 0xfd, 0xf4, 0x2c, 0xb7, 0xba, 0x1a, 0x1b, 0xa3, 0xcd, + 0x3d, 0xaf, 0xf8, 0xbd, 0x48, 0x51, 0xe7, 0xa8, 0xfe, 0x45, 0x30, 0xf6, + 0x48, 0xb1, 0xb8, 0x1b, 0xee, 0x71, 0xf9, 0xd5, 0x7e, 0xe5, 0x76, 0xb8, + 0xd7, 0xb9, 0x5b, 0xd5, 0x55, 0x55, 0x7b, 0xf2, 0xff, 0x00, 0x2d, 0x60, + 0xf2, 0x85, 0xf7, 0x3e, 0xfa, 0xf9, 0x4d, 0x14, 0x41, 0x61, 0x47, 0x81, + 0x56, 0x49, 0x59, 0x7c, 0x3f, 0x12, 0x41, 0x9d, 0xf6, 0xc1, 0xf4, 0x1d, + 0xf1, 0xa6, 0x58, 0xed, 0xa5, 0x8a, 0xa7, 0x89, 0x6a, 0x6b, 0xe3, 0x96, + 0x28, 0xea, 0x69, 0x6c, 0x74, 0xb8, 0xc9, 0x4a, 0x38, 0xda, 0x49, 0x71, + 0xf7, 0x18, 0x03, 0xa9, 0xd8, 0x63, 0x43, 0x50, 0xd5, 0x70, 0x8d, 0xb1, + 0xa1, 0x06, 0xd5, 0x55, 0x57, 0x50, 0xc0, 0x06, 0x32, 0xaf, 0x29, 0x95, + 0x8f, 0x42, 0xc4, 0xef, 0xf8, 0x18, 0xeb, 0xed, 0xa0, 0x8c, 0x36, 0xca, + 0x59, 0x1e, 0x4a, 0xdb, 0x8d, 0xbd, 0x21, 0x58, 0x8b, 0x49, 0x1d, 0x34, + 0xad, 0x27, 0x33, 0xf4, 0xe5, 0xcf, 0x63, 0x9d, 0xf1, 0xf7, 0xd2, 0xfb, + 0x6d, 0x7d, 0x20, 0x68, 0xca, 0x51, 0x97, 0x8d, 0x18, 0x16, 0xe7, 0x8f, + 0x24, 0x8e, 0xd9, 0x3d, 0x8e, 0xa5, 0x93, 0x69, 0x6c, 0xad, 0xe3, 0x28, + 0xe8, 0xa5, 0x14, 0xbc, 0x3d, 0xc2, 0xd4, 0xd4, 0x55, 0x2d, 0xb4, 0xad, + 0x2c, 0x61, 0xcf, 0x3f, 0xa8, 0x07, 0xd3, 0x1a, 0x45, 0x57, 0x3d, 0xd6, + 0xe3, 0xe2, 0xd6, 0x5d, 0xee, 0x0f, 0x2e, 0x58, 0xf3, 0x2e, 0xfb, 0x7d, + 0x87, 0x7f, 0xb6, 0xa0, 0x9e, 0xe5, 0x33, 0xdc, 0x26, 0x9e, 0x7a, 0x76, + 0x48, 0x99, 0x88, 0x48, 0xd1, 0xbc, 0xc8, 0x99, 0xeb, 0x9e, 0xf8, 0x1f, + 0x6d, 0x17, 0x15, 0xd1, 0x45, 0x33, 0x47, 0x6b, 0xa5, 0x8e, 0x05, 0x5e, + 0xb2, 0x48, 0xb9, 0x73, 0xf6, 0xf4, 0xed, 0xeb, 0xa9, 0x64, 0xda, 0x21, + 0x99, 0xa9, 0x1e, 0xa4, 0x2d, 0x3c, 0x6f, 0x22, 0x2a, 0xe1, 0x7c, 0x98, + 0x24, 0xe7, 0x73, 0xd7, 0x5c, 0x0a, 0x7a, 0x86, 0x6c, 0x78, 0x01, 0x54, + 0x37, 0xd2, 0xdb, 0x9d, 0x37, 0x82, 0x8a, 0xb1, 0xaa, 0xda, 0xa6, 0xab, + 0xce, 0xf5, 0x21, 0x71, 0xcc, 0xdb, 0x8d, 0xb6, 0x27, 0xd3, 0x6d, 0x17, + 0x5b, 0x6f, 0x4a, 0x1a, 0x7f, 0x13, 0xe7, 0x04, 0x72, 0xe3, 0x3c, 0xaa, + 0x3a, 0x9f, 0x4c, 0xea, 0x59, 0x36, 0x9d, 0x5d, 0xe4, 0x4f, 0xfd, 0x47, + 0x72, 0xdc, 0x9c, 0x55, 0x4a, 0x08, 0xff, 0x00, 0xf7, 0x3a, 0xee, 0x38, + 0x7c, 0x53, 0xfc, 0xb7, 0xc2, 0x1d, 0xf5, 0x45, 0xe3, 0x59, 0x6b, 0x2d, + 0x9c, 0x75, 0x77, 0x31, 0x48, 0xd1, 0x78, 0xb5, 0xb2, 0xca, 0x31, 0xdf, + 0xf9, 0x87, 0xae, 0xb4, 0x1f, 0x86, 0x73, 0x58, 0xef, 0xb4, 0xb1, 0xc1, + 0x57, 0xc4, 0x0b, 0x41, 0x76, 0x79, 0x02, 0x88, 0x27, 0x4f, 0xe5, 0x48, + 0x4f, 0x75, 0x61, 0xd3, 0xdc, 0x69, 0x0e, 0x67, 0x2a, 0x5f, 0x66, 0x7e, + 0x14, 0x73, 0x0a, 0x59, 0x98, 0x48, 0x39, 0x55, 0x49, 0xe9, 0xe9, 0xa9, + 0xb8, 0xae, 0x68, 0x9e, 0xa6, 0xc9, 0xc6, 0x74, 0xd1, 0x85, 0x51, 0xe1, + 0xc7, 0x5d, 0x1a, 0x9f, 0xa6, 0x74, 0xc7, 0x98, 0xff, 0x00, 0xf2, 0x5c, + 0x1f, 0xbe, 0x75, 0x71, 0xe2, 0x2b, 0x35, 0xae, 0xc9, 0x4a, 0xe9, 0x7d, + 0xbe, 0x5b, 0xbc, 0xc4, 0x72, 0x42, 0x92, 0x12, 0xf2, 0x02, 0x73, 0xba, + 0xf6, 0x00, 0x6f, 0xa6, 0x93, 0xd0, 0xda, 0x78, 0x87, 0x83, 0xe4, 0x82, + 0xd6, 0x21, 0xac, 0xa7, 0x8a, 0x23, 0xe1, 0x98, 0xc4, 0x71, 0x22, 0xb8, + 0x1f, 0x54, 0x80, 0x2e, 0x49, 0xc6, 0x76, 0x2c, 0x7a, 0xe9, 0x39, 0x73, + 0x01, 0x1c, 0x65, 0xb7, 0xc7, 0xff, 0x00, 0xd4, 0xd6, 0xc9, 0x22, 0xa7, + 0xac, 0x68, 0x7e, 0x66, 0x00, 0x66, 0xaa, 0x40, 0x1b, 0xc1, 0x8c, 0xa8, + 0xdb, 0xdd, 0x88, 0x38, 0xc7, 0x6c, 0xeb, 0x0a, 0xab, 0x8e, 0xcb, 0x6b, + 0xac, 0x5a, 0x6a, 0xd7, 0x94, 0x5b, 0xbc, 0x72, 0x82, 0x32, 0x33, 0x23, + 0xc5, 0x92, 0x09, 0xfb, 0xe3, 0xf5, 0xd6, 0xd9, 0xf0, 0x92, 0xf1, 0x41, + 0x07, 0x06, 0x51, 0x5b, 0xae, 0x6b, 0x19, 0x58, 0xd5, 0xd6, 0x39, 0x81, + 0x00, 0x45, 0xe6, 0xda, 0x26, 0xdf, 0x63, 0xd3, 0xf6, 0xd7, 0x9c, 0x38, + 0xe2, 0x29, 0x1f, 0x8a, 0xab, 0x40, 0x93, 0x31, 0x53, 0xca, 0x51, 0x30, + 0x32, 0x00, 0xc9, 0xc7, 0xeb, 0xa9, 0x0c, 0x89, 0x26, 0x56, 0x55, 0x49, + 0x17, 0x4f, 0xf6, 0x76, 0xa9, 0xe1, 0x2b, 0x37, 0x10, 0x5c, 0xd2, 0xed, + 0x3b, 0xc1, 0x25, 0x50, 0x11, 0x5b, 0xeb, 0x25, 0x8f, 0x1c, 0x89, 0xcc, + 0x4f, 0x9b, 0xfc, 0x3c, 0xde, 0x5f, 0xd3, 0x5b, 0x7f, 0xc5, 0xea, 0x0b, + 0xc5, 0x75, 0xa2, 0x8d, 0xa1, 0x9a, 0x23, 0x43, 0x1c, 0x5c, 0xd3, 0x32, + 0xb6, 0x39, 0x98, 0xf7, 0xc0, 0xeb, 0xdb, 0xf5, 0x3a, 0xf2, 0xb5, 0xba, + 0x9d, 0x8b, 0x2b, 0x73, 0x64, 0x03, 0xe9, 0xad, 0xc3, 0xe1, 0x2f, 0x17, + 0xf3, 0x52, 0x0e, 0x12, 0xe2, 0x33, 0x2c, 0x96, 0xc9, 0xd7, 0x92, 0x9e, + 0x51, 0xd6, 0x1f, 0x40, 0x4f, 0x65, 0xfe, 0xda, 0x4e, 0x45, 0xf2, 0xc1, + 0xc2, 0xe9, 0xb0, 0x23, 0x2d, 0xde, 0x26, 0x43, 0xf1, 0x67, 0x87, 0x6e, + 0xf6, 0x8a, 0x5a, 0x4b, 0xbb, 0x40, 0xcd, 0x47, 0x55, 0xcc, 0x91, 0xcc, + 0x01, 0x00, 0x15, 0xeb, 0xf8, 0x3d, 0x8f, 0xb6, 0xb2, 0xca, 0x6a, 0xaa, + 0xba, 0x5a, 0xd4, 0x96, 0x98, 0x81, 0x39, 0x6e, 0x50, 0x18, 0x64, 0x6f, + 0xd8, 0xeb, 0xd8, 0x9f, 0x18, 0x78, 0xae, 0xd5, 0x61, 0xe1, 0x8a, 0xae, + 0x10, 0xb4, 0x53, 0xbd, 0xc9, 0xaa, 0x23, 0x30, 0xca, 0x66, 0x97, 0xc4, + 0x8a, 0x9d, 0x71, 0xdb, 0x3d, 0x4f, 0xdb, 0xa6, 0xbc, 0xad, 0x5d, 0x6f, + 0x14, 0x37, 0x6a, 0x7a, 0xb4, 0x84, 0xb4, 0x62, 0x45, 0xfa, 0x17, 0x70, + 0x33, 0xbe, 0x33, 0xd3, 0x6d, 0xb3, 0xab, 0xc1, 0x1f, 0x86, 0x3b, 0x3b, + 0x18, 0xa9, 0x70, 0x99, 0x15, 0x4a, 0xdc, 0xeb, 0xe3, 0x3f, 0x35, 0x31, + 0x65, 0x8f, 0x01, 0xe3, 0x4d, 0x82, 0x92, 0x36, 0xc8, 0x1b, 0x1f, 0xbe, + 0xa3, 0xb1, 0xdc, 0x2a, 0xec, 0xb5, 0x6e, 0x20, 0x45, 0x31, 0x33, 0xf2, + 0xba, 0x30, 0xce, 0x47, 0xb7, 0xa1, 0xd5, 0xbe, 0xed, 0x34, 0x4d, 0x0c, + 0xc2, 0xc8, 0x8f, 0x15, 0x1d, 0x75, 0x51, 0x73, 0x14, 0x92, 0x66, 0x4c, + 0x2e, 0x71, 0xcd, 0x8e, 0xb8, 0xc9, 0xfd, 0x74, 0x04, 0x96, 0x3f, 0x98, + 0x77, 0xa9, 0xf0, 0x01, 0x25, 0x4e, 0xd9, 0xc6, 0x0f, 0x63, 0xf8, 0xd1, + 0x42, 0x7b, 0xc0, 0x0e, 0xb9, 0xc1, 0x69, 0xaf, 0xb2, 0x81, 0x1d, 0x44, + 0xf2, 0xd4, 0x56, 0xb8, 0x58, 0xa9, 0x23, 0x3b, 0xbb, 0x06, 0x53, 0xe7, + 0x19, 0xfa, 0x71, 0x90, 0x3b, 0x93, 0xa4, 0x2b, 0x43, 0x27, 0x81, 0x2b, + 0x0a, 0x69, 0x72, 0xaf, 0xca, 0x06, 0x31, 0xca, 0x07, 0xb6, 0x87, 0xb8, + 0x97, 0xb7, 0x54, 0xc2, 0x82, 0x36, 0x47, 0x4c, 0x32, 0x48, 0x1b, 0xa7, + 0xb6, 0x86, 0x86, 0xf3, 0x51, 0x51, 0xf3, 0x11, 0xbd, 0x43, 0x72, 0x8d, + 0x95, 0xc0, 0xdd, 0x40, 0x3d, 0x3f, 0x52, 0x4e, 0x99, 0x6d, 0x34, 0xd0, + 0xf4, 0x1f, 0x0d, 0x10, 0x5a, 0xca, 0x66, 0x58, 0xe5, 0x91, 0xe6, 0x19, + 0x20, 0x8c, 0x12, 0xdf, 0xe1, 0xd3, 0x26, 0x06, 0x82, 0x14, 0x05, 0xea, + 0x21, 0x46, 0x56, 0x95, 0x49, 0x18, 0x0c, 0x79, 0xba, 0x63, 0xd4, 0x74, + 0xce, 0xb9, 0x17, 0x28, 0xe3, 0x6b, 0x05, 0x7c, 0x2b, 0x22, 0x8a, 0x79, + 0xd0, 0x33, 0x81, 0x9c, 0x90, 0x77, 0xc0, 0xfd, 0xf5, 0xcd, 0xd6, 0x6a, + 0xba, 0xde, 0x23, 0x9e, 0x59, 0x9e, 0x59, 0x92, 0x56, 0x56, 0x0c, 0x5b, + 0x97, 0x62, 0x7b, 0x0e, 0xcb, 0xd7, 0x6d, 0xf5, 0xad, 0x1b, 0xd7, 0x41, + 0x46, 0xe3, 0x3d, 0xc5, 0x2a, 0x6a, 0xe0, 0x5e, 0x77, 0x1c, 0xb2, 0xca, + 0x59, 0x32, 0x4e, 0x36, 0xce, 0x74, 0x44, 0xd7, 0x2a, 0x4a, 0xea, 0x54, + 0x47, 0x46, 0x8d, 0xda, 0x50, 0xae, 0x0f, 0x63, 0x82, 0x03, 0x67, 0xdb, + 0xa7, 0xe7, 0x42, 0x4d, 0x44, 0xf6, 0x8b, 0xdd, 0x54, 0x0a, 0xf9, 0x8b, + 0x67, 0x60, 0x1b, 0x2c, 0xc0, 0x8c, 0x93, 0xf6, 0xce, 0x8d, 0xad, 0xa6, + 0x48, 0xec, 0xc2, 0xe3, 0x84, 0x53, 0x59, 0xe1, 0x99, 0x90, 0x27, 0x51, + 0xb9, 0x04, 0x1f, 0x7e, 0xbf, 0xa6, 0xad, 0x8d, 0x88, 0x1c, 0x7f, 0x3d, + 0x6f, 0x86, 0x52, 0xcb, 0xe2, 0x50, 0xc3, 0x28, 0x8c, 0xf7, 0x00, 0xee, + 0x0e, 0x3d, 0xb4, 0x59, 0xb3, 0xd1, 0x54, 0x5b, 0xeb, 0x83, 0x9f, 0x0a, + 0x47, 0x0d, 0x35, 0x39, 0x4e, 0x85, 0x15, 0x73, 0xfb, 0xe4, 0x6d, 0xdb, + 0x50, 0x99, 0x69, 0xc7, 0x0b, 0xc9, 0x42, 0x81, 0x85, 0x43, 0x4c, 0x5d, + 0x49, 0x5c, 0x2b, 0x63, 0x27, 0x19, 0xfc, 0x68, 0x6a, 0x99, 0x5a, 0x0b, + 0x13, 0xb8, 0x95, 0xa3, 0x2e, 0xc5, 0x02, 0x11, 0xb9, 0xce, 0xfb, 0xfb, + 0x74, 0xd5, 0x14, 0xc0, 0xe3, 0xb9, 0xd5, 0xc5, 0x6e, 0x4b, 0x6d, 0x42, + 0xab, 0xa3, 0x60, 0x29, 0xe6, 0xdd, 0x37, 0xc6, 0x3e, 0xda, 0x8f, 0x8c, + 0x56, 0x3b, 0x8f, 0xc9, 0xdb, 0xa0, 0x58, 0xd6, 0x4a, 0x28, 0x39, 0x07, + 0x20, 0xd8, 0x9e, 0x62, 0x4f, 0xf7, 0xd4, 0x34, 0xf4, 0x6f, 0x2d, 0x39, + 0x33, 0xcb, 0x1e, 0x14, 0xf5, 0xcf, 0x51, 0xe9, 0xa6, 0x86, 0x9e, 0x81, + 0x29, 0x21, 0x34, 0xec, 0xef, 0x50, 0xc4, 0xbc, 0xac, 0x63, 0xc0, 0x51, + 0xdb, 0x07, 0xf3, 0xf9, 0xeb, 0xa8, 0x51, 0x4b, 0xa4, 0xb5, 0x4a, 0x6b, + 0x42, 0x54, 0xc6, 0x42, 0xab, 0x63, 0xa6, 0xdf, 0x73, 0xad, 0xcf, 0xfd, + 0x9c, 0x78, 0x5e, 0xe2, 0x9c, 0x71, 0x15, 0xf6, 0x68, 0xa4, 0xa5, 0xb4, + 0xd2, 0x42, 0xd2, 0x0a, 0x99, 0x94, 0xac, 0x4e, 0xdf, 0x48, 0x0a, 0xdd, + 0x3b, 0xea, 0x8c, 0x23, 0xa7, 0x0a, 0x24, 0xa7, 0x9b, 0x2f, 0xc9, 0x86, + 0x2d, 0xd3, 0x71, 0xd3, 0x1d, 0xf5, 0x74, 0xa1, 0xe2, 0xba, 0xcb, 0x85, + 0xa2, 0x92, 0xd1, 0x79, 0xb8, 0x56, 0xad, 0x14, 0x51, 0x24, 0x74, 0xd4, + 0x54, 0x31, 0x15, 0x32, 0x80, 0x4e, 0x32, 0x07, 0xdb, 0x54, 0x9d, 0x3b, + 0x15, 0x2c, 0x3c, 0xa7, 0x66, 0xf5, 0x5d, 0xf1, 0x17, 0x84, 0x23, 0x8e, + 0x68, 0x92, 0xff, 0x00, 0x4b, 0x2c, 0xe1, 0x8a, 0xb3, 0xae, 0x48, 0x03, + 0xa7, 0x5c, 0x6b, 0xcd, 0x5f, 0x10, 0x6b, 0xc7, 0x17, 0x71, 0x8d, 0x4d, + 0xe6, 0xb6, 0xae, 0xa7, 0xe4, 0xd4, 0xf8, 0x54, 0xb0, 0xa4, 0x79, 0x61, + 0x1a, 0xf4, 0x3c, 0xc7, 0xa6, 0x7a, 0x9d, 0xba, 0x9d, 0x1a, 0xd5, 0x09, + 0x6e, 0x4a, 0x8a, 0x5a, 0x6b, 0x4d, 0x22, 0x38, 0x25, 0xdc, 0xcf, 0x2f, + 0x8b, 0x3f, 0x2e, 0x46, 0x32, 0x01, 0x21, 0x49, 0x24, 0x6d, 0xd7, 0x42, + 0xd6, 0x53, 0x5e, 0x26, 0xa5, 0x7a, 0xca, 0xdb, 0x7c, 0xb1, 0x53, 0xe3, + 0x0c, 0x4c, 0x61, 0x47, 0xdc, 0x6f, 0x8c, 0x7b, 0xef, 0xa6, 0xfc, 0x96, + 0x5e, 0xd5, 0xec, 0x57, 0x15, 0x1c, 0x6e, 0x23, 0x5a, 0x48, 0x59, 0x56, + 0x32, 0x70, 0xe5, 0xcb, 0x36, 0xe7, 0x39, 0xcf, 0x41, 0xfa, 0x69, 0x84, + 0x9e, 0x1d, 0x08, 0x8e, 0x55, 0x81, 0x2a, 0xaa, 0x58, 0x79, 0xbc, 0x61, + 0xcc, 0x07, 0xb8, 0xf5, 0x3a, 0x12, 0x2a, 0x84, 0x83, 0x95, 0x22, 0x2e, + 0xc3, 0x2a, 0x63, 0x50, 0xd9, 0x18, 0xf7, 0x3d, 0xfe, 0xda, 0x6a, 0xb5, + 0x55, 0xb7, 0x26, 0x94, 0xc7, 0x4b, 0x09, 0x90, 0x10, 0xa1, 0xd9, 0xb9, + 0x79, 0x33, 0xd7, 0x1b, 0x7b, 0x01, 0xbe, 0x97, 0x63, 0x94, 0x52, 0x5c, + 0x10, 0xd4, 0xf1, 0x15, 0x74, 0xb4, 0x9f, 0x2f, 0x23, 0xc1, 0x2b, 0x10, + 0x10, 0x46, 0xb4, 0xa8, 0x7c, 0x31, 0xe8, 0xa4, 0xf4, 0x23, 0xd8, 0x7e, + 0x75, 0x02, 0xd5, 0x5c, 0x82, 0xab, 0x43, 0x4a, 0x54, 0x85, 0x11, 0x86, + 0x38, 0xe7, 0xc6, 0xfb, 0x91, 0xd0, 0x69, 0xa9, 0xb4, 0xdd, 0xa6, 0x3c, + 0x83, 0xe5, 0xa0, 0xdf, 0xeb, 0x50, 0x0b, 0x63, 0xee, 0x37, 0xfe, 0xda, + 0x51, 0x71, 0xa4, 0xab, 0xb7, 0xd4, 0x34, 0x2d, 0x56, 0x80, 0x48, 0x0e, + 0xc4, 0xe1, 0x8e, 0x0e, 0x33, 0xef, 0xa9, 0xb8, 0xbd, 0xa7, 0xc8, 0x94, + 0x3d, 0x68, 0x92, 0xbd, 0x3c, 0x55, 0x1f, 0x53, 0x09, 0x80, 0xfc, 0x68, + 0xf4, 0x64, 0xaf, 0xa9, 0x86, 0x8a, 0x3b, 0x7a, 0x7c, 0x9c, 0x32, 0x9f, + 0xe6, 0xbb, 0xf9, 0x00, 0xf5, 0x3b, 0x6f, 0xa5, 0x96, 0xe9, 0x2d, 0xd4, + 0x71, 0xbd, 0x40, 0xff, 0x00, 0x7b, 0xb8, 0x33, 0x93, 0xc9, 0x92, 0xa1, + 0x17, 0xa7, 0x5f, 0x7e, 0xa7, 0x5d, 0xd4, 0xd5, 0x5d, 0xa6, 0x6f, 0x91, + 0x79, 0x82, 0xc1, 0x27, 0xd0, 0x22, 0xd9, 0x70, 0x7a, 0x0f, 0x7e, 0xd8, + 0xd5, 0xa6, 0x53, 0x1b, 0xcd, 0x6f, 0xa1, 0x7a, 0xf6, 0x89, 0x78, 0x86, + 0x08, 0x5a, 0x43, 0xcb, 0x1c, 0x14, 0xf1, 0xb0, 0x0e, 0x07, 0x60, 0xc7, + 0x63, 0xf7, 0xd3, 0x9f, 0xfe, 0xdb, 0xa4, 0xa3, 0x4a, 0x6a, 0x88, 0xa9, + 0x58, 0x46, 0x08, 0x9a, 0x77, 0x4f, 0x1a, 0x5e, 0x7c, 0x6d, 0xd3, 0x03, + 0x3d, 0x4f, 0xa6, 0xab, 0xed, 0xc3, 0x91, 0xc3, 0x68, 0x89, 0x9a, 0xf4, + 0xb1, 0xcc, 0xe4, 0xad, 0x44, 0x0f, 0x10, 0x0f, 0x18, 0x1d, 0x40, 0x6c, + 0xe7, 0xa8, 0x1b, 0x69, 0x6a, 0xc7, 0x13, 0xd6, 0xc4, 0x94, 0x95, 0x2d, + 0x38, 0x62, 0x39, 0xde, 0x52, 0x70, 0x49, 0xdb, 0x97, 0xdf, 0xae, 0x7f, + 0x1a, 0x8c, 0x0d, 0xca, 0x5c, 0x23, 0xf5, 0x7a, 0xdb, 0xa4, 0x99, 0x12, + 0xc5, 0x43, 0x54, 0x22, 0x4d, 0xe4, 0x92, 0xa0, 0x87, 0x27, 0xdc, 0x0e, + 0xdf, 0xae, 0xbe, 0x8a, 0x17, 0x99, 0x15, 0x8b, 0xc8, 0x0e, 0x76, 0x04, + 0xe3, 0x95, 0x7e, 0xda, 0xb3, 0xf1, 0x4d, 0xae, 0xa6, 0x82, 0x9a, 0x2a, + 0xba, 0xca, 0xec, 0xf3, 0x80, 0x84, 0x41, 0x1e, 0x31, 0xb6, 0xc0, 0x00, + 0x71, 0x9c, 0x7f, 0xe7, 0x55, 0xa1, 0x08, 0x5a, 0x49, 0xa6, 0xa9, 0x96, + 0x72, 0xae, 0xdc, 0xaa, 0x07, 0x5d, 0x4a, 0x19, 0x1a, 0x6a, 0xd3, 0x23, + 0x32, 0xa5, 0x14, 0x73, 0x27, 0x2b, 0xb8, 0xc9, 0xc3, 0x02, 0x00, 0xce, + 0x7d, 0x3a, 0xeb, 0xbb, 0x3d, 0xda, 0x92, 0x9d, 0xd6, 0x69, 0x29, 0x9e, + 0x49, 0x54, 0xe4, 0x3e, 0x3c, 0xa4, 0xff, 0x00, 0x96, 0xa2, 0xb6, 0xa2, + 0xf8, 0xc9, 0xe3, 0xc7, 0x2f, 0x80, 0xc7, 0xc3, 0xe7, 0xe5, 0xcf, 0xeb, + 0xef, 0x8c, 0x68, 0xda, 0xa8, 0xa8, 0xad, 0x95, 0x58, 0xc0, 0x9e, 0x9d, + 0x9b, 0x20, 0x78, 0x7e, 0x61, 0xe9, 0x9d, 0xf6, 0x07, 0x54, 0x59, 0x35, + 0x5d, 0xee, 0x79, 0x99, 0xdd, 0x22, 0x8e, 0x25, 0x29, 0x85, 0x63, 0xb1, + 0xfc, 0x7e, 0x34, 0xbd, 0xb3, 0x57, 0x34, 0x6c, 0xae, 0x65, 0x6c, 0x81, + 0x1a, 0x83, 0x90, 0x0f, 0xb9, 0xd1, 0x97, 0x1a, 0xb7, 0xac, 0x40, 0xb1, + 0x43, 0xf2, 0x94, 0xea, 0x02, 0xf2, 0x2e, 0x09, 0x62, 0x3b, 0xe9, 0x32, + 0x99, 0x21, 0x12, 0x34, 0x52, 0x14, 0x05, 0xb1, 0x19, 0x23, 0x72, 0xde, + 0xc3, 0x50, 0x84, 0x7f, 0x10, 0xb8, 0x6b, 0x88, 0xc5, 0xfa, 0xe3, 0x79, + 0x9e, 0xd9, 0x33, 0x50, 0xcb, 0x57, 0x37, 0x85, 0x2a, 0xee, 0x39, 0x3c, + 0x56, 0x03, 0x3e, 0x9d, 0x07, 0xeb, 0xa1, 0x28, 0xac, 0xf3, 0xd2, 0xd2, + 0xbd, 0x6d, 0x43, 0x72, 0x3c, 0x60, 0x15, 0x41, 0xd5, 0x75, 0x78, 0xe3, + 0x7e, 0x27, 0xa5, 0x96, 0xef, 0x3d, 0xb7, 0xe6, 0x5c, 0xc7, 0x4b, 0x33, + 0xaf, 0x86, 0x7f, 0xc6, 0x18, 0xe4, 0x9e, 0xdd, 0x49, 0xc7, 0xb6, 0xaa, + 0x35, 0x57, 0x17, 0xaa, 0x2d, 0x00, 0x3c, 0xa8, 0x73, 0xef, 0x9d, 0xf5, + 0x9b, 0x04, 0x25, 0xb5, 0xca, 0x7d, 0xff, 0x00, 0xe1, 0xc5, 0x97, 0xd9, + 0x84, 0x47, 0x55, 0x25, 0x6d, 0x74, 0x75, 0x15, 0xb3, 0xbc, 0xc4, 0xb6, + 0x4b, 0x39, 0xe6, 0x00, 0xfa, 0x9c, 0x9d, 0xc6, 0xfa, 0xb5, 0x9e, 0x24, + 0xa7, 0xa5, 0xb3, 0xd3, 0xd9, 0xa9, 0xee, 0x0c, 0x20, 0x4c, 0xf3, 0x00, + 0xa5, 0x4b, 0x39, 0xdc, 0x9f, 0x5c, 0x7f, 0xdf, 0xde, 0x91, 0x12, 0x08, + 0x21, 0x67, 0x5f, 0xab, 0x1b, 0x6b, 0xed, 0x0a, 0x78, 0x93, 0x89, 0x64, + 0xcb, 0x04, 0x39, 0xfc, 0xe8, 0x26, 0xf9, 0x48, 0x56, 0xf2, 0xfb, 0x6f, + 0xba, 0x34, 0x96, 0xba, 0xab, 0x74, 0x52, 0x7f, 0xba, 0xcb, 0xcb, 0xe2, + 0x12, 0x30, 0x3a, 0x74, 0xc6, 0xab, 0xb7, 0x68, 0xe3, 0xa7, 0xa9, 0x54, + 0x8c, 0x89, 0x09, 0x1e, 0x66, 0x1b, 0x83, 0xed, 0x9d, 0x29, 0xaf, 0xaf, + 0xa9, 0xa6, 0x63, 0x0d, 0x31, 0x68, 0xfc, 0x4e, 0x56, 0x66, 0x56, 0xec, + 0x07, 0x4f, 0xdf, 0x52, 0x5a, 0xe7, 0x79, 0xa2, 0x78, 0x66, 0x60, 0xce, + 0x4f, 0x30, 0x63, 0xd7, 0x55, 0x54, 0x54, 0xa7, 0xb8, 0xd4, 0xfe, 0x11, + 0x58, 0x7e, 0x1f, 0xde, 0xea, 0x61, 0xa1, 0xbd, 0x5e, 0xea, 0xa9, 0xeb, + 0xa5, 0xd9, 0x69, 0x5c, 0x08, 0xe3, 0x90, 0xfa, 0x09, 0x0e, 0x72, 0x7a, + 0xed, 0xb6, 0xb7, 0xe8, 0x61, 0xe1, 0x1e, 0x07, 0xa2, 0x4a, 0x5a, 0x5a, + 0x40, 0x8e, 0xc9, 0xff, 0x00, 0x06, 0x18, 0x8c, 0x92, 0x32, 0xe3, 0xa9, + 0xf6, 0xdb, 0xae, 0xc3, 0x5e, 0x53, 0xe1, 0xb8, 0x6d, 0xf5, 0x93, 0x1a, + 0x5a, 0xe8, 0x99, 0x9e, 0x48, 0xf9, 0x29, 0x9c, 0x3f, 0x2f, 0x85, 0x36, + 0x57, 0x95, 0x89, 0xf4, 0xeb, 0xfa, 0xea, 0xdd, 0x74, 0xbc, 0xf1, 0x6f, + 0x0d, 0xd3, 0x1b, 0x55, 0xce, 0xb2, 0x3b, 0x8d, 0x1b, 0x1e, 0x69, 0x8a, + 0x8c, 0xcf, 0x32, 0x67, 0xe9, 0x62, 0x7c, 0xc5, 0x7b, 0x63, 0xa6, 0xda, + 0x09, 0x6a, 0x31, 0xc7, 0xc2, 0xbc, 0xbd, 0x0d, 0xc7, 0x38, 0xae, 0x97, + 0x27, 0xcf, 0x88, 0xb7, 0x3b, 0x75, 0xf6, 0xf7, 0x57, 0x58, 0x69, 0x44, + 0x6a, 0x1d, 0xbc, 0x1f, 0x02, 0x35, 0x50, 0x17, 0x3b, 0x1d, 0xba, 0x93, + 0xea, 0x73, 0xac, 0xca, 0xba, 0x81, 0x64, 0xad, 0x32, 0x46, 0x8c, 0xa3, + 0xb3, 0x36, 0x0b, 0x63, 0xf4, 0xd5, 0xba, 0xf4, 0xa5, 0x78, 0x4a, 0xb3, + 0x8a, 0x6d, 0x55, 0x54, 0xd1, 0x50, 0xd1, 0xf2, 0xc2, 0x20, 0x95, 0xb9, + 0x5a, 0x49, 0x5b, 0xfe, 0x5e, 0xe7, 0x19, 0x39, 0xed, 0xac, 0xee, 0xd5, + 0x7e, 0x45, 0x41, 0x1d, 0x67, 0x36, 0x32, 0xcd, 0xe2, 0x01, 0x96, 0xc9, + 0xdf, 0x41, 0x8d, 0x39, 0x2b, 0x6a, 0x85, 0xbb, 0xbe, 0x06, 0x41, 0x15, + 0x67, 0xf9, 0x79, 0x23, 0x0a, 0x08, 0xf2, 0x30, 0x3e, 0x9d, 0x06, 0x34, + 0x44, 0xf1, 0xd5, 0xd2, 0x53, 0xac, 0xeb, 0x87, 0x8f, 0x62, 0x79, 0x86, + 0x70, 0x34, 0x9f, 0x88, 0xea, 0x64, 0xa8, 0xb3, 0xd1, 0x55, 0x40, 0xad, + 0x03, 0x34, 0x87, 0xae, 0xe4, 0xe3, 0x38, 0x3a, 0x0e, 0xa7, 0x88, 0x2e, + 0x15, 0x36, 0x7a, 0x9a, 0x17, 0x3e, 0x27, 0x88, 0x98, 0x04, 0x1c, 0x15, + 0xdc, 0x69, 0x98, 0xbe, 0xa0, 0x9c, 0xf1, 0x0d, 0x6c, 0xf5, 0xfc, 0xa2, + 0x6a, 0x78, 0x51, 0xe2, 0x61, 0x1a, 0xf2, 0xb7, 0x98, 0x83, 0xed, 0x8e, + 0x83, 0x5d, 0x0b, 0x39, 0xb7, 0x52, 0x0a, 0xcb, 0x8c, 0x4b, 0xe0, 0xcb, + 0x1f, 0x89, 0x4e, 0x76, 0xfe, 0x68, 0xe6, 0x23, 0xd7, 0x6d, 0xd7, 0x40, + 0xd8, 0xa9, 0xda, 0xa8, 0xb3, 0xcf, 0x0c, 0xb2, 0x78, 0x23, 0x9c, 0x0e, + 0xc0, 0x02, 0x3a, 0xfa, 0x8d, 0x38, 0xbd, 0xdf, 0xe9, 0xae, 0xf5, 0x15, + 0x8f, 0x53, 0x48, 0xb1, 0xca, 0x89, 0x1a, 0x52, 0xa4, 0x28, 0x23, 0x48, + 0x54, 0x64, 0x9d, 0x80, 0xef, 0x9d, 0x0b, 0x1b, 0x16, 0x70, 0xe5, 0xea, + 0xa8, 0xe3, 0x01, 0x7f, 0x9a, 0xaf, 0xcc, 0xb1, 0xa0, 0xf2, 0xa2, 0x67, + 0x6f, 0xce, 0x8a, 0xbd, 0xcf, 0x34, 0xa9, 0x29, 0x41, 0xe6, 0x88, 0x22, + 0xb1, 0x07, 0x21, 0x98, 0x64, 0x93, 0x9f, 0x5d, 0xfa, 0x68, 0x5e, 0x1f, + 0xaa, 0x92, 0x92, 0xb6, 0x1a, 0x93, 0x1a, 0xb7, 0x33, 0x96, 0x90, 0x11, + 0x9f, 0x21, 0xdb, 0xfe, 0xbf, 0x8d, 0x17, 0xcf, 0x51, 0x6f, 0xaf, 0xad, + 0xa5, 0x0d, 0x84, 0x9c, 0x73, 0x00, 0x06, 0xc4, 0x7a, 0x6b, 0x5e, 0x17, + 0xc5, 0x1d, 0x0c, 0x0f, 0xc4, 0x0e, 0xa6, 0x71, 0x55, 0x08, 0xb8, 0x4c, + 0xed, 0x14, 0xed, 0x20, 0x56, 0x3d, 0x79, 0x90, 0x83, 0xab, 0x2f, 0x11, + 0xc1, 0x3b, 0xdb, 0x66, 0x96, 0x01, 0x27, 0x82, 0xaa, 0xa5, 0x14, 0x8d, + 0x89, 0x39, 0x00, 0x0f, 0xb0, 0x1f, 0xf7, 0x9d, 0x27, 0xe1, 0xca, 0x58, + 0xee, 0x54, 0xb2, 0x41, 0x24, 0x2a, 0x0f, 0x3e, 0xd2, 0x16, 0xc9, 0x4f, + 0xc6, 0x37, 0x18, 0xed, 0xab, 0x2c, 0x17, 0x1f, 0xfe, 0xcf, 0xa5, 0xb5, + 0x55, 0x4f, 0x2d, 0x3c, 0xd2, 0x86, 0x85, 0x5e, 0x55, 0x3c, 0xb8, 0x2e, + 0x00, 0xc7, 0x63, 0x91, 0x9e, 0xfd, 0x34, 0xfb, 0x34, 0xd8, 0x05, 0x1c, + 0x36, 0xf8, 0xf8, 0x6e, 0x9a, 0xe3, 0x53, 0x0b, 0xa4, 0x10, 0xa3, 0x23, + 0xc6, 0xad, 0xe6, 0x79, 0x5b, 0xa3, 0x7d, 0x8e, 0x3f, 0x1a, 0xab, 0x57, + 0x61, 0xa0, 0xa7, 0x91, 0x69, 0x5a, 0x28, 0x08, 0x28, 0x27, 0xee, 0xec, + 0x7f, 0xc4, 0x3f, 0x1a, 0x3e, 0xe8, 0x93, 0x50, 0x73, 0x5a, 0x56, 0xa1, + 0xa5, 0x32, 0xb1, 0xf0, 0xd4, 0x21, 0xfa, 0x81, 0x20, 0x6a, 0x4a, 0x09, + 0x29, 0xa5, 0xa5, 0x4a, 0x4a, 0x98, 0x2a, 0x24, 0xa9, 0x84, 0x37, 0xf2, + 0x08, 0xf2, 0x87, 0x3b, 0x02, 0x7e, 0xc7, 0x54, 0x53, 0x64, 0x34, 0x86, + 0x96, 0x8a, 0x92, 0x25, 0x8e, 0x15, 0x96, 0xac, 0x64, 0x3f, 0x8a, 0xbc, + 0xd1, 0xae, 0xe3, 0x18, 0x19, 0xd3, 0x99, 0xa9, 0x1a, 0xa6, 0x64, 0xe7, + 0x67, 0x92, 0x56, 0x40, 0x5c, 0x2a, 0xe0, 0x2e, 0x71, 0xb8, 0x00, 0xe3, + 0x1e, 0xda, 0x16, 0x8a, 0xd1, 0x5b, 0x82, 0x23, 0xa6, 0x25, 0x64, 0xf2, + 0x80, 0x1f, 0x20, 0x37, 0x5d, 0xce, 0x3a, 0xf4, 0xd8, 0xfa, 0x8d, 0x39, + 0xa1, 0x57, 0xb7, 0xd4, 0xcf, 0x6f, 0xb8, 0x49, 0x1c, 0x50, 0x48, 0x8a, + 0xf2, 0x2a, 0x37, 0x3c, 0xc7, 0xa7, 0xd2, 0xc3, 0xf7, 0x1a, 0x84, 0x21, + 0xf0, 0xe8, 0x28, 0x5a, 0x28, 0xe1, 0x57, 0xab, 0xa9, 0x23, 0x99, 0x93, + 0xa9, 0x18, 0xf5, 0x5e, 0xc3, 0xdb, 0xf4, 0xd4, 0xc6, 0xba, 0xfc, 0x94, + 0xd3, 0x2b, 0x62, 0x86, 0x0a, 0x8c, 0x16, 0x64, 0x02, 0x36, 0xe5, 0xec, + 0x32, 0x4e, 0xc3, 0xa6, 0xa1, 0xae, 0xac, 0xa5, 0x9f, 0xc2, 0x86, 0xd3, + 0x6e, 0x65, 0x98, 0xcc, 0x79, 0xa6, 0x7e, 0xac, 0x4e, 0x7c, 0xbf, 0x60, + 0x75, 0xc3, 0xfc, 0xb0, 0x0f, 0x05, 0x64, 0x4e, 0xd2, 0xb1, 0xda, 0x79, + 0xc9, 0xc0, 0x1d, 0x49, 0x41, 0x8d, 0x87, 0xbe, 0xff, 0x00, 0x6d, 0x42, + 0x06, 0x43, 0x7d, 0x96, 0x1b, 0x7c, 0x34, 0x56, 0x89, 0x33, 0x51, 0x51, + 0xe7, 0xa8, 0x91, 0xa3, 0x0c, 0xfc, 0xc7, 0x6e, 0x6c, 0x9e, 0xfe, 0xfa, + 0xee, 0x9a, 0xcb, 0x78, 0xa9, 0x55, 0x96, 0xae, 0x59, 0xa5, 0x8a, 0x12, + 0x58, 0x78, 0x8d, 0xce, 0x71, 0xdf, 0xca, 0x3a, 0x01, 0xd3, 0x3f, 0xf6, + 0x07, 0x96, 0x4a, 0x68, 0x22, 0x89, 0x6d, 0xe8, 0xaa, 0xe8, 0x7c, 0x4f, + 0x1b, 0x9b, 0x97, 0x94, 0xf5, 0xdc, 0xe3, 0xd3, 0x42, 0x52, 0x56, 0x56, + 0x55, 0x21, 0xa7, 0x8e, 0xad, 0x99, 0x64, 0x62, 0xcf, 0x32, 0x13, 0xcc, + 0xfb, 0xf4, 0x3a, 0x84, 0x0c, 0xb8, 0x5c, 0xa8, 0x29, 0xa3, 0xf9, 0x6b, + 0x4c, 0x4a, 0x24, 0x66, 0x21, 0xe4, 0x45, 0x05, 0xc7, 0xb0, 0x6f, 0x5f, + 0x7f, 0xf5, 0xd7, 0x16, 0x64, 0xba, 0xb2, 0xd4, 0xd4, 0xd2, 0x52, 0xc7, + 0x14, 0x4a, 0xc3, 0x9e, 0x57, 0x39, 0x20, 0xe3, 0xbf, 0xa9, 0xd7, 0x5f, + 0x25, 0x49, 0x41, 0x28, 0x2c, 0x7c, 0x59, 0x0a, 0x61, 0x41, 0x18, 0x20, + 0xed, 0xdf, 0x46, 0x56, 0xd5, 0xc5, 0xf2, 0x06, 0x0e, 0x52, 0xaf, 0x26, + 0x19, 0xa2, 0x41, 0x85, 0x51, 0x8e, 0xff, 0x00, 0xe2, 0x3a, 0x11, 0x88, + 0xe9, 0x2e, 0xd5, 0xe9, 0x13, 0x52, 0xc7, 0x13, 0x47, 0x33, 0xc9, 0xca, + 0xae, 0xd8, 0x5e, 0x61, 0xdf, 0x18, 0x1f, 0x4e, 0x81, 0xab, 0xa4, 0xa3, + 0x42, 0xc6, 0xa2, 0xbd, 0xa5, 0x99, 0x62, 0xe7, 0x96, 0x45, 0xcb, 0x1e, + 0x6f, 0xf0, 0x80, 0x3b, 0x60, 0xe7, 0x5c, 0x56, 0xbd, 0x24, 0x94, 0xca, + 0xa7, 0x94, 0x33, 0x1c, 0xe0, 0x1f, 0x30, 0xcf, 0xb6, 0x8c, 0xb3, 0xdd, + 0xa1, 0xa4, 0x33, 0x53, 0x45, 0x4b, 0x1c, 0x6d, 0x24, 0x65, 0x10, 0xc9, + 0x0a, 0xb3, 0x1e, 0x98, 0xcb, 0x7d, 0x86, 0xa0, 0x14, 0xe3, 0xd0, 0xb6, + 0xc7, 0x1c, 0x32, 0xe5, 0xa3, 0xa7, 0x32, 0x7f, 0x49, 0x69, 0x54, 0xe4, + 0x82, 0x3d, 0xff, 0x00, 0xb6, 0x98, 0x57, 0xd1, 0x59, 0xa3, 0xaa, 0x5a, + 0x8a, 0xda, 0xb9, 0xe4, 0x99, 0xf7, 0xf0, 0x55, 0x42, 0x82, 0x70, 0x70, + 0x07, 0xa0, 0x1a, 0x81, 0x6b, 0x40, 0xcb, 0xab, 0xc6, 0xc0, 0xae, 0x15, + 0x91, 0x76, 0x07, 0xbf, 0xe9, 0xa5, 0xeb, 0x53, 0x11, 0xaa, 0x0b, 0x31, + 0x90, 0xb6, 0x7a, 0x7f, 0x4b, 0x1f, 0x5c, 0xff, 0x00, 0x96, 0xad, 0x12, + 0xac, 0xb4, 0x70, 0xf5, 0xb2, 0x8e, 0xf5, 0x6a, 0x9e, 0x05, 0x34, 0x94, + 0x45, 0x50, 0xc9, 0x3c, 0x93, 0xe5, 0xe4, 0x75, 0x04, 0x74, 0x03, 0xd0, + 0x67, 0xef, 0x8d, 0x09, 0x53, 0x6a, 0xa3, 0xa5, 0x74, 0x9e, 0x82, 0xe6, + 0x67, 0x90, 0x02, 0xdc, 0xc0, 0x05, 0x0b, 0xbf, 0xeb, 0x9f, 0x6e, 0xdb, + 0xf5, 0xd2, 0xf9, 0xa5, 0x2d, 0x4d, 0x24, 0x91, 0x88, 0x96, 0x25, 0x6c, + 0x66, 0x3f, 0xbe, 0x8b, 0x8a, 0xe0, 0xfe, 0x04, 0x94, 0xb4, 0x8b, 0xcf, + 0xcd, 0x8c, 0x86, 0x18, 0xe5, 0x03, 0x55, 0x61, 0xc3, 0x1a, 0x5d, 0x9f, + 0x6b, 0x24, 0x9a, 0xb2, 0xa4, 0x4d, 0x59, 0x53, 0xe3, 0x15, 0x1e, 0x69, + 0x65, 0x7e, 0x8b, 0xec, 0x7d, 0x75, 0xc5, 0xe2, 0x48, 0xab, 0x63, 0xa7, + 0xa4, 0xa3, 0xa7, 0x59, 0x20, 0xa7, 0x53, 0x23, 0xca, 0xab, 0x8f, 0x10, + 0x12, 0x0e, 0xe7, 0xbf, 0x6d, 0x45, 0x77, 0x45, 0xab, 0x8c, 0x2c, 0xf2, + 0xa1, 0x91, 0xf0, 0x15, 0x00, 0xfa, 0x71, 0xa9, 0xe8, 0x84, 0x66, 0x86, + 0x48, 0x9a, 0x75, 0x8d, 0xce, 0xc5, 0xdb, 0x7e, 0x6d, 0x52, 0x65, 0xed, + 0xae, 0x85, 0x57, 0x9a, 0xfa, 0xb8, 0x5e, 0x08, 0xe2, 0x05, 0xa3, 0x93, + 0x0f, 0xca, 0xaa, 0x70, 0xa7, 0xfc, 0xfd, 0x35, 0x35, 0x4c, 0xf4, 0xb1, + 0xa7, 0xcc, 0xd4, 0x54, 0xcc, 0x95, 0x12, 0x2e, 0x70, 0xbf, 0xe2, 0xff, + 0x00, 0x2f, 0x4d, 0x0b, 0x5f, 0x3c, 0x4a, 0xea, 0x8e, 0x24, 0x6f, 0x0d, + 0xb0, 0x08, 0x07, 0x71, 0xed, 0xbf, 0xdb, 0x5c, 0x4b, 0x72, 0xa1, 0x33, + 0x47, 0x1b, 0x53, 0xaa, 0xca, 0xa0, 0x2a, 0x87, 0x1e, 0x60, 0x75, 0x2c, + 0x94, 0x49, 0xe3, 0xcd, 0x3d, 0x31, 0xf0, 0xe0, 0x54, 0x56, 0x1b, 0xb6, + 0x31, 0x9f, 0x7d, 0x09, 0x4a, 0x88, 0x19, 0x96, 0x59, 0x0c, 0x93, 0xc5, + 0xe6, 0x2c, 0xdd, 0x17, 0xd3, 0x5d, 0xcf, 0x0d, 0x74, 0xc7, 0x9a, 0x7a, + 0x94, 0xa7, 0x84, 0x9c, 0x80, 0xbf, 0x57, 0xe3, 0x40, 0x56, 0xb5, 0x32, + 0x7f, 0x22, 0x08, 0x9a, 0x56, 0xfe, 0xa9, 0x1f, 0xb9, 0xf4, 0xd5, 0xd9, + 0x03, 0x38, 0x96, 0x10, 0x9c, 0x51, 0x79, 0xce, 0x0f, 0x3d, 0xc2, 0x76, + 0x3f, 0xff, 0x00, 0xd1, 0xb4, 0x3c, 0x30, 0xab, 0xb4, 0x71, 0x80, 0x00, + 0xc8, 0x3a, 0xfd, 0xc5, 0xcc, 0xff, 0x00, 0xfa, 0xbe, 0xee, 0xb1, 0x80, + 0x49, 0xaf, 0x9c, 0x1f, 0x6f, 0xe6, 0x36, 0x8e, 0xb3, 0x52, 0xb1, 0x2b, + 0x9c, 0x9c, 0x0c, 0x13, 0xe9, 0x8e, 0xfa, 0x16, 0x70, 0x72, 0x76, 0xce, + 0xde, 0x15, 0x05, 0x52, 0x31, 0xcd, 0x81, 0x86, 0x3a, 0xfc, 0xc1, 0x29, + 0xe9, 0xf0, 0x48, 0x01, 0x77, 0x27, 0x46, 0x38, 0x5c, 0x19, 0x30, 0x79, + 0x15, 0x79, 0x8b, 0x7b, 0x7a, 0xe9, 0x69, 0x9e, 0x49, 0xa6, 0x25, 0x55, + 0x58, 0x8e, 0xfd, 0xa3, 0xfb, 0x7b, 0xfb, 0xe9, 0x51, 0x8d, 0xb1, 0x62, + 0xda, 0xe6, 0x92, 0x4f, 0xf7, 0x96, 0x6e, 0x50, 0xf8, 0x48, 0xd4, 0x8d, + 0xd8, 0x6e, 0x73, 0xa6, 0x16, 0xa6, 0x2b, 0x1a, 0x13, 0xb8, 0xf5, 0xd2, + 0xfb, 0xb3, 0x7f, 0x35, 0x23, 0xe7, 0x69, 0x02, 0x8e, 0x76, 0x63, 0xd4, + 0x93, 0xb7, 0xf6, 0x1a, 0x71, 0x41, 0x4f, 0x23, 0xd2, 0x24, 0xf1, 0xc6, + 0x4c, 0x60, 0x0e, 0x9f, 0x6d, 0x04, 0xf8, 0x74, 0x08, 0xd2, 0x9c, 0x3f, + 0x97, 0x93, 0x6c, 0x60, 0xe7, 0x4c, 0xae, 0xdc, 0x61, 0x72, 0xa4, 0xe2, + 0xda, 0x5a, 0xf5, 0x68, 0xb1, 0x35, 0xb8, 0x51, 0xb4, 0x64, 0x86, 0x19, + 0x0b, 0x80, 0xec, 0x08, 0xf5, 0xdf, 0x42, 0xd9, 0x69, 0xa5, 0x9c, 0x16, + 0x2d, 0x1c, 0x51, 0x03, 0x86, 0x79, 0x1b, 0x00, 0x1f, 0x4f, 0xbe, 0xac, + 0x77, 0x2e, 0x1f, 0xb0, 0xd2, 0x59, 0x29, 0x2f, 0x55, 0xf3, 0xc7, 0xf3, + 0x8a, 0x59, 0x0a, 0x15, 0xd9, 0xa3, 0x3e, 0x56, 0x38, 0xeb, 0xce, 0x33, + 0xb1, 0x1d, 0x0f, 0xae, 0xb9, 0xf9, 0xfe, 0x36, 0xed, 0x87, 0x08, 0xd1, + 0x4b, 0xa9, 0x5a, 0x4a, 0x9a, 0x34, 0x72, 0x64, 0x12, 0x39, 0x08, 0x55, + 0x50, 0x90, 0xcc, 0x46, 0x72, 0x31, 0xdc, 0xe4, 0xfd, 0xb7, 0xd5, 0x6e, + 0xe9, 0x6a, 0x8a, 0x86, 0x71, 0x3d, 0x43, 0xc6, 0x50, 0xe7, 0x28, 0xad, + 0xe6, 0x18, 0x3b, 0xe4, 0x76, 0xd5, 0x9a, 0xe9, 0xc5, 0xd5, 0xfc, 0x25, + 0x7b, 0xaa, 0xa4, 0xb1, 0x50, 0xd1, 0x8a, 0x6a, 0x92, 0xbe, 0x0c, 0xf3, + 0xd3, 0x7f, 0x35, 0x53, 0x1b, 0x18, 0xcb, 0x6e, 0x0e, 0xe7, 0x7d, 0x57, + 0xef, 0xcd, 0x47, 0x2a, 0xc2, 0xeb, 0x70, 0x4a, 0x8a, 0xc9, 0xc0, 0x73, + 0x18, 0x88, 0x83, 0x1b, 0x13, 0xb8, 0x66, 0x27, 0x05, 0xba, 0xe7, 0x1b, + 0x7b, 0xeb, 0x55, 0x49, 0xc5, 0x49, 0x8e, 0x64, 0x53, 0x9f, 0xe2, 0x14, + 0xa0, 0xa2, 0x08, 0xa9, 0xcb, 0x1f, 0x96, 0x42, 0x77, 0x7d, 0x03, 0x1c, + 0x46, 0x13, 0xba, 0x05, 0xe5, 0x38, 0x6f, 0x63, 0xa8, 0x2f, 0xb5, 0x75, + 0x35, 0x12, 0xc5, 0x4d, 0x24, 0xb9, 0x8a, 0x8d, 0x4c, 0x70, 0x28, 0x18, + 0xe5, 0x19, 0xcb, 0x1f, 0xbe, 0x75, 0xf6, 0xcb, 0x53, 0x4f, 0x9a, 0x95, + 0xaf, 0x8d, 0xa7, 0xfe, 0x51, 0xf0, 0xdb, 0x9b, 0x74, 0x3b, 0x60, 0xfe, + 0x3a, 0x7e, 0x75, 0x70, 0x8b, 0x5d, 0x80, 0xd0, 0x5d, 0xc2, 0xf3, 0x58, + 0xf2, 0x54, 0x3c, 0x54, 0x94, 0xf0, 0x42, 0xe4, 0x23, 0x34, 0x29, 0xcb, + 0x80, 0x31, 0xb7, 0xea, 0x33, 0x9f, 0x53, 0xa3, 0x38, 0x32, 0xde, 0xd7, + 0xab, 0xb9, 0xa5, 0x32, 0xc3, 0x02, 0x4a, 0x59, 0xa4, 0xa8, 0x99, 0xb9, + 0x42, 0x80, 0x32, 0x49, 0x6e, 0xc0, 0x01, 0x9d, 0x22, 0x9b, 0x9a, 0x03, + 0x2c, 0x7c, 0xbe, 0x2c, 0x64, 0x61, 0xb2, 0x71, 0xae, 0xed, 0xeb, 0x22, + 0x51, 0x38, 0x35, 0x02, 0x2a, 0x76, 0x50, 0x65, 0xc1, 0xce, 0x7b, 0xe0, + 0xe9, 0xff, 0x00, 0x1a, 0xf4, 0x35, 0x44, 0x6f, 0x71, 0xb9, 0x41, 0x6a, + 0x81, 0x8d, 0x21, 0x47, 0x4f, 0x10, 0xac, 0x52, 0x63, 0x3e, 0x22, 0x8e, + 0xfb, 0xef, 0xff, 0x00, 0x9d, 0x75, 0x55, 0x2f, 0xce, 0xd3, 0xdb, 0x6f, + 0x10, 0x9f, 0xe7, 0x4c, 0xc2, 0x19, 0x71, 0xdb, 0x6d, 0x57, 0xef, 0x01, + 0x2b, 0x44, 0x2b, 0x02, 0x88, 0xd1, 0x00, 0x00, 0x67, 0x60, 0x31, 0xab, + 0x7d, 0xb6, 0xc1, 0x33, 0xf0, 0x55, 0x35, 0x54, 0x15, 0x10, 0x34, 0x09, + 0x2b, 0x2e, 0x43, 0x79, 0xa3, 0x97, 0x63, 0xb8, 0xed, 0x9c, 0x9c, 0x6a, + 0xf1, 0xc5, 0x46, 0x5c, 0x7b, 0x1d, 0xa7, 0x95, 0x4a, 0x8e, 0xf8, 0x46, + 0x68, 0xad, 0xd7, 0x7a, 0xba, 0x29, 0xc1, 0x8a, 0x69, 0x64, 0x0a, 0xac, + 0x47, 0x94, 0x6f, 0xbe, 0x47, 0xa6, 0x33, 0xa6, 0x5c, 0x46, 0x69, 0xa4, + 0xe1, 0x44, 0x34, 0xd3, 0x2c, 0x81, 0x18, 0xf8, 0x43, 0x3b, 0xa3, 0x07, + 0x38, 0x20, 0xf7, 0xdb, 0x51, 0x5a, 0xad, 0x54, 0x55, 0xf7, 0xca, 0x05, + 0x59, 0x98, 0x45, 0x71, 0x82, 0x58, 0xe5, 0x27, 0xcd, 0xcb, 0x2a, 0x0f, + 0x37, 0xa6, 0xc4, 0xe8, 0x8e, 0x17, 0x84, 0x53, 0xd4, 0x49, 0x62, 0xbb, + 0x27, 0xf3, 0x28, 0x5d, 0xbc, 0x0c, 0x9d, 0x9f, 0x27, 0x61, 0x8f, 0x40, + 0x0e, 0x7f, 0x3a, 0xd2, 0x6e, 0x14, 0xdf, 0x28, 0xe6, 0x17, 0xf1, 0x0c, + 0xb5, 0xb0, 0xb7, 0x2c, 0x48, 0xe7, 0xae, 0x09, 0x6c, 0x74, 0x3d, 0x36, + 0xcf, 0x5d, 0x4d, 0x6e, 0x9e, 0xa2, 0x19, 0x62, 0x7a, 0x57, 0xa7, 0x12, + 0xab, 0x32, 0x13, 0x2e, 0xea, 0x33, 0xb8, 0x23, 0xd4, 0xed, 0xfa, 0x6a, + 0x5b, 0x85, 0x12, 0x10, 0xd5, 0x10, 0x85, 0x2f, 0x22, 0x91, 0xb7, 0xd0, + 0x33, 0x90, 0x32, 0x7d, 0xb1, 0xd3, 0x40, 0x5c, 0xe6, 0x5b, 0x6d, 0xbd, + 0xcc, 0xcc, 0x5d, 0x8a, 0x8e, 0xa3, 0x04, 0xb3, 0x0e, 0x9d, 0xff, 0x00, + 0xec, 0x1d, 0x42, 0x9a, 0x38, 0x5b, 0xcd, 0x64, 0xcd, 0x53, 0x45, 0x3d, + 0x5d, 0x05, 0x2b, 0x2b, 0x9e, 0x79, 0x9a, 0x52, 0xc4, 0x80, 0x77, 0xf0, + 0xd4, 0xec, 0x09, 0xf4, 0xd1, 0x34, 0x86, 0x2a, 0xb9, 0x44, 0x76, 0xf9, + 0x1a, 0xa0, 0xf4, 0x79, 0x64, 0x3c, 0xa4, 0xfa, 0x8e, 0xfa, 0xa2, 0xba, + 0xc0, 0x55, 0xe5, 0x91, 0xd9, 0xe5, 0x46, 0xc2, 0xa9, 0x3b, 0x0f, 0xfc, + 0x6a, 0xff, 0x00, 0xf0, 0xd6, 0x84, 0xdd, 0xd5, 0x56, 0x3a, 0xa2, 0xaf, + 0x21, 0x28, 0x60, 0x43, 0x86, 0x60, 0xa0, 0x16, 0x6c, 0xfa, 0x6a, 0x15, + 0xb9, 0x2e, 0xce, 0xe5, 0x33, 0xd1, 0xd6, 0x24, 0x63, 0xc3, 0x25, 0x18, + 0x1e, 0x45, 0xf6, 0xd3, 0xca, 0x9a, 0xab, 0x65, 0x4c, 0x82, 0xb2, 0xad, + 0xa1, 0x33, 0x3e, 0x09, 0x76, 0x18, 0x03, 0x6e, 0xde, 0x9a, 0x1a, 0xba, + 0xc6, 0xf6, 0xab, 0x84, 0x8f, 0x24, 0x0d, 0x0b, 0x83, 0x82, 0xa7, 0x32, + 0x72, 0x13, 0xd0, 0x64, 0x7a, 0xe8, 0x1a, 0x8a, 0x55, 0xaa, 0xb8, 0xf2, + 0xbd, 0x4c, 0x06, 0x38, 0xcf, 0x21, 0x91, 0xdb, 0x93, 0x1b, 0x03, 0xf4, + 0x9e, 0xdd, 0xb5, 0x06, 0x45, 0x46, 0x43, 0xca, 0xba, 0x3b, 0x65, 0x4d, + 0x2c, 0x75, 0x10, 0x49, 0x2b, 0x52, 0xf2, 0x66, 0x47, 0x91, 0x79, 0x15, + 0xcf, 0xa0, 0xfb, 0x7a, 0xe9, 0x1c, 0x72, 0x5a, 0xab, 0xae, 0x93, 0xba, + 0x54, 0xcb, 0x41, 0x16, 0x15, 0x12, 0x3c, 0x1e, 0x46, 0x41, 0xeb, 0x8f, + 0x5d, 0x73, 0x0d, 0x28, 0xab, 0xaf, 0x11, 0x52, 0xd4, 0x07, 0xa5, 0x89, + 0x72, 0xf2, 0x67, 0xcb, 0xdb, 0x23, 0xdb, 0xed, 0xa9, 0xab, 0x22, 0xa4, + 0x15, 0x5f, 0xee, 0x6f, 0xe2, 0xc6, 0x83, 0x99, 0xa4, 0xe4, 0xcf, 0x39, + 0xe9, 0xb6, 0xfd, 0x34, 0x05, 0xec, 0x3f, 0x55, 0xc0, 0x22, 0x96, 0x49, + 0xf3, 0x13, 0x72, 0xb9, 0xe5, 0x4f, 0x10, 0x6c, 0xb9, 0xe9, 0x9c, 0x64, + 0xe3, 0x5f, 0x09, 0xa0, 0x69, 0xd7, 0xc4, 0x12, 0x3c, 0x6d, 0xbb, 0x3f, + 0x26, 0x06, 0x75, 0xd5, 0x0c, 0x2a, 0xb0, 0x99, 0x0a, 0x2e, 0x7a, 0xf3, + 0xb8, 0xc9, 0x1e, 0x9a, 0x1e, 0xa6, 0xad, 0x01, 0x6c, 0xc8, 0xc4, 0x11, + 0x82, 0x54, 0x72, 0x92, 0x7d, 0xb5, 0x2c, 0x24, 0x88, 0xee, 0x09, 0x4d, + 0x15, 0x63, 0x44, 0x2a, 0x92, 0x6a, 0x79, 0x14, 0x81, 0xcb, 0xb0, 0x55, + 0x3d, 0x06, 0x7a, 0x9c, 0x6a, 0x4a, 0x6b, 0x62, 0xcc, 0xac, 0xf3, 0x7c, + 0xa1, 0x87, 0x62, 0x25, 0x73, 0xbe, 0xdd, 0x40, 0xd2, 0x72, 0x61, 0x59, + 0x39, 0xa4, 0x2c, 0xa8, 0x0e, 0x48, 0x51, 0x9d, 0x33, 0xa2, 0x96, 0x81, + 0xdb, 0xe6, 0xe0, 0x89, 0x88, 0x56, 0xe5, 0xfa, 0x82, 0x9f, 0xbe, 0xfa, + 0x96, 0x48, 0x47, 0x90, 0xca, 0xa0, 0x5e, 0x1c, 0xc3, 0x22, 0x98, 0x90, + 0xe5, 0x42, 0x0f, 0x20, 0x1f, 0xf2, 0xfe, 0xa7, 0xf5, 0xd4, 0x10, 0xab, + 0x46, 0x85, 0xd8, 0x0f, 0x31, 0xd8, 0x93, 0xa6, 0x72, 0xd5, 0x17, 0x89, + 0x56, 0x33, 0x85, 0x23, 0x38, 0x6d, 0xf1, 0x9d, 0x05, 0x51, 0x19, 0x78, + 0xb9, 0x24, 0x95, 0x37, 0x39, 0xc8, 0x19, 0x00, 0x7a, 0x7d, 0xf4, 0x36, + 0x32, 0x8e, 0x23, 0xe4, 0x2f, 0x97, 0x78, 0xbc, 0x6c, 0xf9, 0x15, 0xba, + 0x0f, 0x7f, 0xfa, 0xe8, 0x5a, 0x95, 0x8d, 0xe7, 0x0d, 0x53, 0x52, 0xc9, + 0x17, 0x49, 0x18, 0x30, 0x23, 0x3e, 0xc3, 0xbe, 0x8e, 0x8e, 0xaa, 0x8a, + 0x9c, 0x32, 0x1c, 0x29, 0xc7, 0x95, 0x89, 0xce, 0x80, 0xaa, 0xf0, 0x1a, + 0x21, 0x15, 0x35, 0x32, 0x7f, 0x88, 0x1e, 0x5c, 0x67, 0xdf, 0x3a, 0x89, + 0x83, 0x41, 0x31, 0x44, 0x21, 0x85, 0xa4, 0x86, 0x6c, 0x43, 0x8f, 0x2b, + 0x14, 0xc3, 0x63, 0xfc, 0xb5, 0x09, 0xab, 0xa4, 0x40, 0xaf, 0x83, 0x2c, + 0xa0, 0x7d, 0x4c, 0x37, 0xd0, 0x71, 0x53, 0x4d, 0x22, 0xa4, 0x50, 0xc1, + 0x34, 0xf3, 0x31, 0xc6, 0x22, 0x56, 0x60, 0xb8, 0xfc, 0x6f, 0xab, 0x5f, + 0x0b, 0xfc, 0x32, 0xe3, 0x2e, 0x24, 0x9a, 0x37, 0x86, 0xc1, 0x58, 0x60, + 0xe5, 0x00, 0xcb, 0x51, 0x88, 0x50, 0x6e, 0x33, 0xf5, 0x60, 0x9c, 0x0f, + 0x4c, 0xea, 0xec, 0x85, 0x62, 0x6b, 0xc4, 0xb2, 0x6c, 0x94, 0xa4, 0xb2, + 0x9c, 0x00, 0xfd, 0x0e, 0x3d, 0x35, 0xf2, 0xa2, 0xae, 0xaa, 0xb9, 0x07, + 0x8a, 0x90, 0xaf, 0x37, 0xd3, 0x91, 0xb6, 0x75, 0xb3, 0x56, 0x7c, 0x06, + 0x96, 0xcf, 0x2c, 0xd5, 0x95, 0xd7, 0x75, 0x34, 0x71, 0x6e, 0x9e, 0x04, + 0x21, 0x5a, 0x4f, 0xc9, 0x27, 0x97, 0xf7, 0xd5, 0x83, 0x83, 0x57, 0x86, + 0x78, 0x76, 0xa5, 0x0f, 0xf0, 0x2a, 0x22, 0x09, 0x21, 0xe6, 0x91, 0x3c, + 0x49, 0x37, 0xea, 0x43, 0x36, 0x71, 0xf6, 0xd6, 0x0c, 0xdf, 0x90, 0xc5, + 0x87, 0x26, 0xc9, 0xf0, 0x64, 0xcb, 0xac, 0xc7, 0x89, 0xd4, 0x8c, 0x9b, + 0xe1, 0xf7, 0xc2, 0x4e, 0x30, 0xe2, 0xdc, 0x55, 0x4d, 0x1c, 0x94, 0x16, + 0xdf, 0xe9, 0xa9, 0xa8, 0x04, 0x07, 0x1f, 0xf2, 0xa9, 0xc1, 0x23, 0x7e, + 0xba, 0xde, 0xf8, 0x1f, 0xe1, 0x0f, 0x06, 0x70, 0xd5, 0x10, 0x7a, 0x8a, + 0x75, 0xbb, 0x5c, 0x39, 0x73, 0x24, 0xd5, 0x03, 0x2a, 0x0e, 0x07, 0xd2, + 0x9d, 0x06, 0xfe, 0xb9, 0x3e, 0xfa, 0xb7, 0xdc, 0x78, 0xc2, 0x8e, 0x9e, + 0x8e, 0x19, 0x62, 0x41, 0x3f, 0x38, 0xda, 0x3e, 0x81, 0x75, 0xd5, 0x97, + 0x88, 0xa3, 0xba, 0xb8, 0x8e, 0x4a, 0x55, 0x87, 0x23, 0x20, 0x0d, 0xc7, + 0xeb, 0xeb, 0xab, 0x7a, 0xcd, 0x33, 0x96, 0xc8, 0xcd, 0x36, 0xcc, 0xdf, + 0xca, 0xc7, 0x3e, 0x99, 0xe7, 0x2f, 0xff, 0x00, 0x88, 0x6b, 0xab, 0x6e, + 0xf5, 0x17, 0xbb, 0xd5, 0xc2, 0x9a, 0xd3, 0x6e, 0xad, 0xac, 0x92, 0x58, + 0x9b, 0x9c, 0x3c, 0x92, 0xa1, 0x72, 0xc4, 0x85, 0xe8, 0x36, 0x23, 0xaf, + 0xae, 0x99, 0x70, 0xef, 0x03, 0xc1, 0x59, 0x5d, 0xc5, 0x31, 0x59, 0xe9, + 0x95, 0xe9, 0xe0, 0x81, 0xe9, 0xe9, 0xcc, 0xad, 0xb9, 0xc9, 0x05, 0x7e, + 0xec, 0x40, 0xeb, 0x9d, 0x69, 0x1c, 0x5b, 0x15, 0xba, 0x4a, 0xae, 0x1d, + 0x92, 0xe7, 0x33, 0x24, 0x51, 0x5b, 0x61, 0xe4, 0xe5, 0x6c, 0xb0, 0x24, + 0x1f, 0xe9, 0xf4, 0x3b, 0x6f, 0xa6, 0x1c, 0x1d, 0x4b, 0x5b, 0x6f, 0xa5, + 0xb9, 0xcf, 0x1c, 0x50, 0x47, 0x4a, 0x19, 0xa6, 0x46, 0x55, 0xda, 0x47, + 0xe5, 0x3c, 0xa7, 0x3d, 0xc0, 0xc6, 0x7e, 0xf8, 0xd3, 0xe7, 0xe1, 0x22, + 0x64, 0xc6, 0x94, 0xa9, 0x1e, 0x53, 0xbd, 0xb3, 0xc2, 0xe6, 0x85, 0xd5, + 0xe3, 0x90, 0x31, 0xf1, 0x50, 0x8f, 0x30, 0xc6, 0xdc, 0xa7, 0xdf, 0x39, + 0xfd, 0x34, 0x34, 0x4b, 0x31, 0x89, 0x62, 0x08, 0xb1, 0x21, 0x20, 0x10, + 0x06, 0xe7, 0xef, 0xa2, 0xae, 0xd3, 0x34, 0xb7, 0x09, 0x6a, 0x27, 0x72, + 0xf2, 0xca, 0xd9, 0x77, 0x3d, 0xcf, 0x7d, 0x45, 0x16, 0x19, 0x58, 0x91, + 0xb6, 0x36, 0xd1, 0xc5, 0xd1, 0x81, 0xf6, 0x03, 0x5f, 0x01, 0x77, 0x66, + 0x55, 0xc1, 0x52, 0x47, 0xdf, 0x56, 0x9e, 0x1f, 0x88, 0xa5, 0x8e, 0x33, + 0x08, 0x01, 0xca, 0xe4, 0xae, 0x92, 0x34, 0x6a, 0xd1, 0xb6, 0x7e, 0xc3, + 0x5a, 0x25, 0xa2, 0xd9, 0x1c, 0x74, 0x34, 0x50, 0xca, 0xeb, 0x1a, 0xb6, + 0x09, 0x94, 0x9c, 0x05, 0x07, 0xa9, 0xfd, 0x33, 0xaa, 0x84, 0xb9, 0x6c, + 0xa0, 0xeb, 0x35, 0xda, 0xe9, 0x07, 0x04, 0x09, 0x23, 0xb7, 0xc3, 0x1c, + 0x36, 0xe5, 0x92, 0x45, 0x9f, 0x00, 0x18, 0xe6, 0x66, 0xc2, 0xc9, 0xbf, + 0xd4, 0xdd, 0x40, 0x03, 0xa0, 0xce, 0xdd, 0xf5, 0x47, 0xaa, 0x7b, 0x95, + 0x65, 0xc9, 0xaa, 0x6b, 0x6a, 0x1a, 0x67, 0x93, 0x76, 0x9b, 0x3b, 0x9d, + 0xf3, 0xd7, 0xae, 0x72, 0x35, 0x0d, 0xd2, 0x6a, 0xba, 0x9a, 0x99, 0x16, + 0x33, 0x53, 0x1d, 0x03, 0x4a, 0x3e, 0x5e, 0x9e, 0x59, 0x08, 0xe6, 0x03, + 0xa3, 0x15, 0xf5, 0xc6, 0xbe, 0x73, 0x4d, 0x44, 0xfc, 0xa8, 0x43, 0xc4, + 0x40, 0x62, 0x31, 0xea, 0x33, 0xae, 0x7d, 0xb9, 0xab, 0x7d, 0x92, 0xdf, + 0xb1, 0xef, 0xfe, 0xab, 0xe1, 0xdb, 0x35, 0x1c, 0xd5, 0xf7, 0xdb, 0x3c, + 0x97, 0xab, 0xc8, 0x46, 0x58, 0x04, 0xa5, 0x4c, 0x4c, 0x36, 0xf3, 0x3e, + 0x73, 0xb8, 0xf4, 0x00, 0x1d, 0xf5, 0x93, 0x5d, 0x6a, 0x7f, 0x8a, 0xdc, + 0x26, 0xae, 0x11, 0x47, 0x4d, 0x23, 0x31, 0x2b, 0x14, 0x43, 0x0a, 0x83, + 0x39, 0xc0, 0xd3, 0x5e, 0x2c, 0x91, 0x66, 0xaa, 0x05, 0x0e, 0xeb, 0x93, + 0x8f, 0x63, 0xa4, 0x44, 0xaa, 0xc7, 0x14, 0x7c, 0xc0, 0x78, 0xe7, 0x90, + 0xb1, 0xe8, 0x0f, 0xa1, 0xd7, 0x46, 0x2d, 0xec, 0x49, 0x8f, 0x8c, 0x9b, + 0xec, 0xec, 0x1f, 0x15, 0x73, 0x27, 0x99, 0xb3, 0xe6, 0xcf, 0xae, 0xa2, + 0xaf, 0x44, 0x82, 0x08, 0xc8, 0x60, 0xbc, 0xc7, 0x66, 0xf7, 0xd3, 0x7a, + 0x2b, 0x44, 0xf1, 0xe0, 0xa0, 0x0b, 0x8d, 0xb0, 0x76, 0x24, 0x6b, 0x8b, + 0xe4, 0x3e, 0x15, 0x19, 0xf1, 0xd2, 0x2d, 0xfe, 0xa0, 0x17, 0xbf, 0xae, + 0xab, 0x22, 0xb4, 0x8a, 0x8f, 0x62, 0x4a, 0x47, 0x69, 0x27, 0x45, 0x69, + 0x39, 0x57, 0x1b, 0x9e, 0xde, 0xff, 0x00, 0xdb, 0x47, 0xdc, 0x2a, 0x69, + 0xa3, 0x50, 0xd4, 0xf0, 0xc6, 0x25, 0xe8, 0xdb, 0x6d, 0x9f, 0x4c, 0x69, + 0x13, 0x2b, 0xae, 0x02, 0xbb, 0x04, 0xd8, 0x92, 0x36, 0xfc, 0x68, 0xe6, + 0x81, 0x10, 0x23, 0x40, 0xc4, 0xae, 0x03, 0x12, 0xdd, 0x73, 0xdf, 0xf1, + 0xa5, 0xa4, 0x12, 0x64, 0x31, 0xc9, 0x14, 0x93, 0xe1, 0x93, 0x90, 0x92, + 0x7a, 0x74, 0xfd, 0x35, 0xe8, 0xfa, 0x0e, 0x0d, 0xb3, 0x5b, 0x3e, 0x09, + 0x48, 0x68, 0x96, 0x79, 0xeb, 0xaa, 0x04, 0x15, 0xf5, 0x12, 0x33, 0x79, + 0x49, 0x5d, 0xc8, 0x51, 0x9d, 0x80, 0x42, 0xda, 0xf3, 0xfa, 0xc2, 0x12, + 0x56, 0x2e, 0x42, 0xb8, 0x00, 0xa9, 0x03, 0xa8, 0x3b, 0xeb, 0xd0, 0xdc, + 0x0f, 0xf1, 0x04, 0x55, 0xf0, 0x5d, 0xbe, 0xd0, 0x91, 0xc4, 0xd3, 0x52, + 0xd3, 0x0a, 0x69, 0x55, 0x86, 0x4e, 0x00, 0xc0, 0x3f, 0x91, 0xa5, 0x67, + 0xda, 0xaa, 0x52, 0x74, 0x90, 0x37, 0xcd, 0x99, 0xa8, 0x13, 0xc5, 0x43, + 0x25, 0xc5, 0x1f, 0x96, 0x7a, 0x3a, 0x91, 0x32, 0xa9, 0x18, 0xf1, 0x14, + 0x9e, 0x57, 0xc0, 0xef, 0xe6, 0x03, 0xf5, 0x1a, 0x6d, 0x7f, 0x78, 0xe4, + 0xbd, 0x5a, 0xaa, 0xea, 0x52, 0x58, 0x52, 0x5a, 0x57, 0xdc, 0x1f, 0x36, + 0x7a, 0x8c, 0x8f, 0x61, 0x8d, 0x7e, 0xa5, 0xa3, 0x86, 0xa0, 0x5e, 0xad, + 0x0d, 0x21, 0x5a, 0xa8, 0x49, 0x11, 0x87, 0xd8, 0x3c, 0x6c, 0x83, 0x60, + 0x3b, 0x79, 0x94, 0x7e, 0xba, 0xe6, 0xae, 0x2a, 0x9b, 0x9d, 0x8f, 0x87, + 0x1c, 0x6f, 0x50, 0xb2, 0xc7, 0x18, 0x3f, 0xf2, 0x82, 0x57, 0xfb, 0x0d, + 0x74, 0x62, 0xd4, 0x95, 0xa3, 0xac, 0xb9, 0x42, 0xca, 0x8a, 0xb1, 0x00, + 0x96, 0x9e, 0x59, 0xe1, 0x67, 0x8e, 0x55, 0x87, 0x9b, 0x18, 0x56, 0x52, + 0x09, 0xe6, 0x23, 0xb9, 0xc9, 0xc9, 0xf5, 0xfc, 0x69, 0x1d, 0xcd, 0xa2, + 0x91, 0xe3, 0x50, 0xa2, 0x79, 0x64, 0x03, 0x2f, 0xfd, 0x38, 0xec, 0x71, + 0xdb, 0xed, 0xa7, 0xbc, 0x45, 0x22, 0x7f, 0x15, 0x91, 0x04, 0x3c, 0xe9, + 0x2c, 0x2a, 0x55, 0x13, 0x62, 0x58, 0x33, 0x63, 0x3a, 0x4d, 0x67, 0xa7, + 0x96, 0x47, 0x96, 0xb2, 0xa6, 0x3c, 0xb2, 0x36, 0xc9, 0xd3, 0x18, 0xd8, + 0xea, 0xc6, 0x51, 0x2d, 0xaa, 0xd5, 0x6d, 0xa4, 0xa9, 0xac, 0x32, 0xc5, + 0x0c, 0xf2, 0x54, 0x29, 0x4f, 0x3a, 0x6d, 0x19, 0xc7, 0x51, 0xff, 0x00, + 0x7d, 0xf4, 0xf3, 0x83, 0xea, 0xa5, 0xb0, 0x42, 0x25, 0xa4, 0x8a, 0x9a, + 0x82, 0x49, 0xa6, 0x65, 0x4a, 0x95, 0x8c, 0x39, 0x8e, 0x23, 0xec, 0x48, + 0xdc, 0x91, 0xb7, 0xb6, 0x96, 0x4c, 0x4c, 0x15, 0x12, 0x7c, 0xc3, 0x6f, + 0x29, 0x57, 0xe5, 0x4d, 0xd8, 0x92, 0x3b, 0x0d, 0x77, 0x71, 0xa9, 0x69, + 0x53, 0xe4, 0x60, 0xa6, 0x8e, 0x06, 0x95, 0x46, 0x65, 0x78, 0xc6, 0xeb, + 0xd3, 0x3e, 0xd8, 0x07, 0x19, 0xf5, 0x3a, 0x00, 0x66, 0x83, 0xab, 0x6a, + 0xea, 0xe6, 0x49, 0xab, 0x2e, 0x17, 0x96, 0xf0, 0x6a, 0x7c, 0xd1, 0x45, + 0x1b, 0x79, 0x80, 0x3b, 0x82, 0xde, 0xff, 0x00, 0x6d, 0x2d, 0x86, 0x4a, + 0x68, 0x22, 0x96, 0x78, 0xe1, 0x79, 0xcb, 0x00, 0xaa, 0xd2, 0x80, 0x47, + 0x36, 0x3b, 0x69, 0xa5, 0x45, 0xbe, 0x8a, 0x92, 0xdc, 0xf5, 0x4c, 0xaf, + 0x20, 0x50, 0xab, 0x17, 0x3a, 0xed, 0x81, 0xdc, 0x8f, 0x43, 0xdb, 0x50, + 0x53, 0x1f, 0x98, 0xa8, 0x35, 0x95, 0xe2, 0x38, 0x29, 0x97, 0xc8, 0x39, + 0x13, 0x00, 0x11, 0xd8, 0x0f, 0xc6, 0xa0, 0x6a, 0x07, 0x34, 0x90, 0x23, + 0x50, 0xc3, 0x0b, 0xf2, 0xa3, 0xc8, 0x39, 0x9f, 0x19, 0x00, 0x8f, 0x4f, + 0xfb, 0xf4, 0xd1, 0x31, 0x40, 0xb0, 0xc8, 0x20, 0xf1, 0x02, 0x43, 0x93, + 0xcc, 0x54, 0xee, 0xc3, 0x4b, 0x6b, 0xeb, 0x5a, 0x79, 0x84, 0x31, 0x07, + 0x48, 0xf9, 0x89, 0x0b, 0xcc, 0x73, 0x8f, 0xf2, 0xd4, 0xad, 0x1c, 0xd1, + 0x22, 0x91, 0x84, 0xc9, 0xca, 0x03, 0x92, 0x70, 0x46, 0x7a, 0xe7, 0x50, + 0x60, 0x65, 0x53, 0xc7, 0x0a, 0x88, 0xd2, 0x00, 0x0f, 0x31, 0x06, 0x59, + 0x18, 0x1e, 0x6f, 0x4c, 0x7a, 0x68, 0x1a, 0xaa, 0xd6, 0xe5, 0x68, 0x95, + 0x23, 0x04, 0x0c, 0x73, 0x05, 0xc8, 0xd7, 0x35, 0xd2, 0xb3, 0xc7, 0x12, + 0x31, 0xf3, 0x31, 0x00, 0x9e, 0x60, 0x77, 0xc7, 0xf7, 0xd0, 0x29, 0x04, + 0x22, 0xb2, 0x40, 0xc2, 0x52, 0x63, 0xe8, 0x5b, 0x61, 0x9d, 0x2c, 0x84, + 0x90, 0x55, 0x2a, 0x23, 0x09, 0xa7, 0x63, 0xd8, 0xaa, 0x46, 0x30, 0x75, + 0x0c, 0x73, 0xc5, 0x1c, 0x92, 0xba, 0x29, 0x54, 0x39, 0x61, 0x9f, 0x5d, + 0x14, 0x65, 0xa5, 0xa6, 0x4e, 0x6a, 0x94, 0x66, 0x69, 0x73, 0xc9, 0xe5, + 0xc6, 0x4f, 0xa0, 0xd4, 0x74, 0x34, 0x93, 0x5c, 0xaa, 0x9e, 0x38, 0x41, + 0x41, 0x18, 0x0c, 0xf1, 0xb0, 0xc1, 0x00, 0xf6, 0xd5, 0x49, 0xa4, 0xad, + 0x82, 0xe7, 0x1c, 0x6a, 0xe4, 0xcf, 0xd1, 0xd5, 0x49, 0x55, 0x12, 0x32, + 0xe5, 0xb3, 0x91, 0x8e, 0x83, 0x6d, 0x3b, 0xe1, 0xde, 0x1c, 0xbc, 0x5c, + 0xe0, 0x6a, 0xb5, 0x10, 0xd2, 0x53, 0x09, 0x39, 0x3c, 0x6a, 0x89, 0x02, + 0x26, 0x7d, 0x89, 0xdd, 0xbe, 0xc0, 0x1d, 0x3d, 0xb0, 0x70, 0xd5, 0xca, + 0xd2, 0xf4, 0xb7, 0xb6, 0xb3, 0x25, 0x4d, 0x1c, 0x45, 0x64, 0xe5, 0x91, + 0x03, 0xa4, 0x9e, 0xc4, 0x67, 0x45, 0xdf, 0xae, 0x54, 0x1c, 0x45, 0xc6, + 0x12, 0xd5, 0xc4, 0xb0, 0x5a, 0xa9, 0x9c, 0x89, 0x24, 0x49, 0x5f, 0x96, + 0x35, 0x7c, 0x00, 0xd8, 0x18, 0xeb, 0xfe, 0x9a, 0xcd, 0x93, 0x54, 0xaa, + 0xa1, 0xd9, 0xcf, 0xcb, 0xac, 0x57, 0x50, 0xe4, 0x9a, 0x5f, 0x86, 0x16, + 0xf3, 0xe1, 0x4d, 0x72, 0xba, 0x99, 0xd1, 0x94, 0xb0, 0x92, 0x05, 0xf2, + 0x6d, 0xd4, 0x02, 0x7a, 0x77, 0xed, 0xa6, 0x74, 0x1f, 0x0d, 0x78, 0x7d, + 0xee, 0x34, 0xd5, 0x74, 0xf7, 0x4b, 0x8d, 0x55, 0x34, 0x88, 0x3f, 0x92, + 0xfb, 0x3b, 0x82, 0x32, 0x14, 0x1c, 0xec, 0x0e, 0xdb, 0xe3, 0x56, 0xfe, + 0x16, 0xbf, 0x70, 0xb5, 0x25, 0xa5, 0xe9, 0x2b, 0x6a, 0xad, 0xd3, 0xc3, + 0x12, 0x2a, 0x8f, 0x02, 0x42, 0x43, 0x9e, 0xcd, 0x82, 0x3e, 0xbd, 0xce, + 0xfe, 0xc3, 0x57, 0xbb, 0x05, 0x77, 0x0a, 0x47, 0x6d, 0x94, 0xda, 0xea, + 0xe9, 0xa0, 0xf0, 0x51, 0x25, 0xa9, 0x91, 0x9b, 0x1e, 0x18, 0x60, 0x70, + 0x0b, 0x7e, 0x0e, 0xda, 0xe6, 0xfc, 0x3a, 0xb9, 0xbb, 0x79, 0x69, 0x19, + 0xbe, 0x7c, 0x8f, 0xfb, 0xcc, 0xf6, 0x86, 0xeb, 0x5d, 0xc1, 0x96, 0xd6, + 0xb2, 0xd1, 0x5a, 0x85, 0xa2, 0x16, 0x91, 0x8b, 0x18, 0xe2, 0xcb, 0x36, + 0x7f, 0xab, 0x9f, 0xd7, 0x6d, 0x36, 0xb4, 0x71, 0xdc, 0xb4, 0xb6, 0xf5, + 0x86, 0xae, 0xe3, 0x1a, 0x73, 0x1c, 0xc1, 0x2b, 0xb7, 0x9a, 0x45, 0x3d, + 0x9b, 0xdc, 0x7f, 0x96, 0x9d, 0xdf, 0x6f, 0x56, 0x2b, 0xa5, 0xba, 0xa2, + 0x95, 0x6a, 0xad, 0xd3, 0xa7, 0x86, 0x79, 0xa5, 0x9a, 0x50, 0x30, 0x7d, + 0x37, 0x1f, 0xbe, 0xb1, 0x7b, 0x8d, 0xb2, 0xed, 0x2c, 0x32, 0x7c, 0x9c, + 0x74, 0xf7, 0x5a, 0x26, 0xcb, 0x2c, 0x51, 0x37, 0x34, 0x91, 0x2e, 0x3a, + 0xff, 0x00, 0xd7, 0x57, 0x9b, 0x0e, 0x5d, 0xb4, 0xa7, 0x7f, 0xf6, 0x23, + 0x24, 0xa7, 0xea, 0x56, 0x6b, 0xd7, 0x3e, 0x2d, 0x9e, 0xa2, 0xdf, 0xe0, + 0x0a, 0xc8, 0xda, 0x26, 0x05, 0x64, 0xca, 0x87, 0x2f, 0xfa, 0xf4, 0xd5, + 0x2a, 0xed, 0x0c, 0x33, 0x54, 0x43, 0x83, 0xf2, 0xf0, 0x31, 0x1e, 0x33, + 0x67, 0x65, 0x4e, 0xbf, 0xae, 0x91, 0x70, 0xec, 0xb1, 0x41, 0xc2, 0x38, + 0x86, 0x36, 0x9e, 0x56, 0x25, 0xe3, 0x32, 0x3f, 0xd0, 0x17, 0x66, 0x5c, + 0xe3, 0x1d, 0xc6, 0xdd, 0x76, 0xd2, 0xda, 0xaa, 0x9a, 0x8b, 0xbd, 0x05, + 0x44, 0xe6, 0xb2, 0x8a, 0x0a, 0x78, 0x17, 0x95, 0x95, 0xe7, 0x0a, 0x5b, + 0xff, 0x00, 0x88, 0xfd, 0xb5, 0xcc, 0x78, 0x35, 0x19, 0x66, 0xb7, 0xc9, + 0xb4, 0x26, 0xa6, 0xfb, 0x1b, 0xde, 0x78, 0xe2, 0x82, 0x0b, 0xc8, 0x86, + 0x82, 0x88, 0x55, 0x51, 0x53, 0xa2, 0xa6, 0x0c, 0xe4, 0x07, 0x20, 0x63, + 0x9b, 0x38, 0xce, 0xfa, 0xd1, 0x3e, 0x1c, 0x71, 0xfd, 0x8a, 0xf0, 0x82, + 0xdb, 0x4d, 0x4b, 0xfc, 0x3e, 0xbf, 0x97, 0x22, 0x26, 0x3c, 0xdc, 0xe4, + 0x76, 0x56, 0xdb, 0x3a, 0xc7, 0xed, 0x2d, 0xc2, 0xd4, 0x09, 0x29, 0x96, + 0xd8, 0xd7, 0x9a, 0x9c, 0x8d, 0x84, 0xf8, 0xa7, 0x55, 0xc7, 0xa8, 0x1b, + 0x9d, 0xff, 0x00, 0xbe, 0xb4, 0xbe, 0x09, 0x3c, 0x33, 0x74, 0x86, 0x2a, + 0x9a, 0x6b, 0x5d, 0x1d, 0x2d, 0x64, 0x78, 0x25, 0x15, 0x07, 0x3a, 0x9f, + 0x5c, 0xeb, 0xa7, 0x87, 0x0c, 0x31, 0x4a, 0xe3, 0x15, 0x63, 0x21, 0x2d, + 0xa2, 0x7e, 0x28, 0x8e, 0xe5, 0xc5, 0x1c, 0x5f, 0x6e, 0xa6, 0xb5, 0xd3, + 0x93, 0x53, 0x6d, 0xb7, 0xc4, 0x31, 0x33, 0x72, 0xc6, 0x11, 0x54, 0x67, + 0x27, 0x7d, 0x89, 0x23, 0x57, 0x2e, 0x20, 0xe2, 0x0b, 0x77, 0x0f, 0x70, + 0xfd, 0x3d, 0x0c, 0xf5, 0x46, 0x09, 0x2a, 0x19, 0x11, 0xe4, 0x84, 0x11, + 0xcb, 0xd8, 0xe0, 0x7a, 0x76, 0xfb, 0x0d, 0x0d, 0x5d, 0x2d, 0x55, 0x15, + 0xae, 0x29, 0x2d, 0xf0, 0x4e, 0x9e, 0x2c, 0x71, 0x89, 0x66, 0xa7, 0x5e, + 0x69, 0x47, 0x97, 0xb0, 0xd5, 0x16, 0xe1, 0x79, 0xe1, 0x0b, 0x4d, 0xfa, + 0x14, 0xe2, 0x7b, 0xb4, 0xb5, 0xb2, 0x73, 0xf3, 0xd4, 0x52, 0xcf, 0x91, + 0x27, 0x7c, 0x0f, 0x2f, 0xbf, 0x6f, 0xdb, 0x5d, 0x79, 0x79, 0xb3, 0xa7, + 0x2f, 0x25, 0x66, 0x3d, 0x78, 0x8e, 0x4a, 0x5e, 0x21, 0xae, 0x81, 0xd5, + 0xd7, 0xc3, 0x99, 0x94, 0x12, 0x36, 0x23, 0x27, 0x1f, 0xb0, 0xd7, 0x70, + 0x03, 0xcb, 0x93, 0xdf, 0xb6, 0xb5, 0xcf, 0x8b, 0x5c, 0x05, 0x1d, 0xea, + 0x55, 0xe2, 0xce, 0x0f, 0x6a, 0x6a, 0x9a, 0x49, 0x23, 0x5f, 0x16, 0x92, + 0x39, 0x4f, 0x88, 0x08, 0x00, 0x64, 0x29, 0xea, 0x71, 0x81, 0x81, 0xbe, + 0xda, 0xad, 0xf0, 0xd7, 0xc2, 0xbe, 0x2d, 0xbc, 0xf8, 0x73, 0x4d, 0x6e, + 0x9a, 0xdb, 0x42, 0xcc, 0xb9, 0x9a, 0xa5, 0x08, 0x23, 0x7d, 0xf0, 0xbd, + 0x4e, 0xde, 0xb8, 0x1a, 0x4a, 0x95, 0xba, 0x39, 0xd2, 0xc5, 0x26, 0xf8, + 0x14, 0x70, 0x05, 0x82, 0xe1, 0xc4, 0x5c, 0x45, 0x1d, 0x2d, 0x15, 0x0c, + 0xd5, 0x29, 0x09, 0x12, 0x4d, 0xc8, 0x36, 0x54, 0xf5, 0x3f, 0x73, 0xad, + 0xd6, 0x9e, 0xd8, 0x96, 0x79, 0xde, 0xe5, 0x55, 0x49, 0x1c, 0xb2, 0x52, + 0xa7, 0x96, 0x09, 0xd7, 0x99, 0x79, 0x8f, 0x42, 0x46, 0x7e, 0xfa, 0xbb, + 0x70, 0x57, 0x08, 0xd9, 0x78, 0x2e, 0xcb, 0x15, 0x1d, 0xba, 0x27, 0x79, + 0x1c, 0x8f, 0x1a, 0xa9, 0x90, 0x19, 0x25, 0x6f, 0x56, 0xf6, 0xf6, 0xed, + 0xaa, 0xef, 0x1f, 0xde, 0x2d, 0xe2, 0xad, 0xa9, 0xe0, 0x90, 0x97, 0x4d, + 0xa5, 0x0a, 0x36, 0x2c, 0x3a, 0xfe, 0xfa, 0x1c, 0xf3, 0x96, 0x3c, 0x6e, + 0x9d, 0x36, 0x1c, 0xf1, 0xa8, 0x46, 0xd9, 0x99, 0x71, 0x6d, 0x25, 0xba, + 0xe5, 0x57, 0x25, 0x7d, 0xca, 0x95, 0x00, 0x5c, 0xb3, 0x38, 0x24, 0x01, + 0xeb, 0xb0, 0xd6, 0x7f, 0x76, 0x97, 0x87, 0xaa, 0xea, 0x45, 0x1d, 0x9e, + 0x92, 0x6e, 0x42, 0x30, 0xf3, 0x4a, 0xc5, 0x53, 0xdc, 0x81, 0xe9, 0xad, + 0x1f, 0x8c, 0x2d, 0xb3, 0xdd, 0x2c, 0x2e, 0xd4, 0xde, 0x43, 0x34, 0x80, + 0x04, 0xc1, 0x62, 0xc3, 0x7c, 0xf4, 0xe9, 0xf9, 0xd6, 0x37, 0xc4, 0x2e, + 0x96, 0xfb, 0x83, 0xdb, 0x23, 0xe4, 0x11, 0xc6, 0xc1, 0x26, 0x90, 0x36, + 0x72, 0xdd, 0xf1, 0xfa, 0x63, 0xef, 0x9d, 0x63, 0xd2, 0xc3, 0x2c, 0xe1, + 0xbf, 0x23, 0x62, 0x60, 0x7c, 0xb9, 0xd9, 0x28, 0x00, 0xf0, 0x9a, 0xa6, + 0x6e, 0x40, 0x0a, 0x99, 0xd1, 0x0a, 0xa9, 0x1e, 0xed, 0x9d, 0x05, 0x1f, + 0x0d, 0xd3, 0x47, 0x08, 0x8e, 0x98, 0xb4, 0x91, 0x1c, 0xee, 0xe7, 0x25, + 0x94, 0xee, 0x0e, 0x75, 0x71, 0x86, 0x5a, 0x3a, 0x7b, 0x4b, 0x45, 0x30, + 0x24, 0x39, 0x00, 0xc7, 0x8e, 0xa3, 0x1a, 0xa3, 0x52, 0xde, 0xa4, 0xa7, + 0xbb, 0x56, 0x52, 0xc4, 0x85, 0x69, 0x62, 0x97, 0x08, 0x8c, 0x73, 0x81, + 0xed, 0xae, 0x94, 0x61, 0x51, 0xa1, 0x84, 0xc6, 0x2a, 0xdb, 0x74, 0x52, + 0x34, 0x55, 0x06, 0x58, 0x93, 0x2a, 0xb1, 0x3f, 0x55, 0x3e, 0xc7, 0x55, + 0xcb, 0x8d, 0xce, 0xa2, 0x49, 0xd6, 0x26, 0x91, 0xd4, 0xc9, 0x83, 0x82, + 0x7d, 0x75, 0x76, 0x8c, 0xd0, 0x5c, 0x84, 0x80, 0xb7, 0x84, 0x1c, 0x61, + 0xb0, 0x39, 0x89, 0x3f, 0x6d, 0x4b, 0x6c, 0xf8, 0x71, 0x6b, 0xae, 0xf8, + 0x8d, 0x4f, 0xc2, 0xf4, 0x57, 0x89, 0xbc, 0x27, 0x1e, 0x2c, 0xd5, 0x95, + 0x09, 0x83, 0x12, 0x84, 0x2e, 0xe3, 0x04, 0xf5, 0x18, 0xc6, 0x33, 0xd7, + 0xbe, 0x8d, 0x85, 0x13, 0x3e, 0x93, 0x0a, 0x0f, 0x88, 0x76, 0x03, 0xbf, + 0x7d, 0x4f, 0x02, 0x2b, 0xc0, 0xac, 0x98, 0xc1, 0x03, 0x5c, 0xdd, 0xed, + 0xd3, 0xd4, 0x5c, 0xea, 0x29, 0x52, 0x4f, 0xf7, 0x78, 0xa6, 0x60, 0x24, + 0x3b, 0xe4, 0x02, 0x40, 0xfb, 0xed, 0xa9, 0xa1, 0x85, 0x29, 0x63, 0x31, + 0xa9, 0x2e, 0xa0, 0xec, 0x71, 0x8d, 0x0d, 0x12, 0x71, 0x0a, 0x4a, 0x41, + 0x25, 0x30, 0x63, 0x2c, 0x6c, 0xe8, 0xbb, 0x28, 0x3d, 0x73, 0xd0, 0x7d, + 0xf4, 0xce, 0xdf, 0x5d, 0x4f, 0x68, 0x00, 0x13, 0x3c, 0x15, 0x41, 0xbc, + 0xcc, 0x4e, 0xc0, 0xe0, 0xe3, 0x3e, 0xde, 0xda, 0x06, 0xd9, 0x70, 0xf0, + 0x23, 0x92, 0x15, 0xa7, 0x89, 0xe2, 0x95, 0xd7, 0xc4, 0x56, 0x1b, 0x9e, + 0x52, 0x0e, 0x41, 0xed, 0xd3, 0x4d, 0x2f, 0x37, 0x1a, 0x4b, 0x8f, 0x2b, + 0x55, 0xc4, 0xa5, 0xd1, 0x3c, 0x35, 0x7c, 0x79, 0xf9, 0x47, 0x40, 0x4f, + 0x7c, 0x0d, 0x25, 0xc7, 0xfd, 0xcb, 0x82, 0x51, 0x6d, 0xb5, 0xd6, 0x9b, + 0xb7, 0x10, 0xdb, 0x2e, 0xd0, 0xc4, 0xaf, 0x52, 0x41, 0x8a, 0xa0, 0x83, + 0xb3, 0xe1, 0x00, 0xc9, 0x1e, 0x9d, 0x0e, 0xa0, 0x98, 0xbd, 0x0d, 0xa6, + 0xe9, 0x49, 0x09, 0x65, 0x9e, 0xdf, 0x5a, 0x8f, 0x4e, 0x73, 0x95, 0x72, + 0xe7, 0x2a, 0x07, 0xa6, 0xdd, 0x74, 0xb7, 0x83, 0xee, 0x1e, 0x35, 0x3c, + 0xdf, 0x22, 0x16, 0x39, 0xed, 0xa8, 0x65, 0x0a, 0xc3, 0x66, 0x0a, 0x30, + 0x0f, 0xef, 0xa3, 0x2e, 0xf2, 0xc7, 0x4f, 0x75, 0xaf, 0x28, 0xea, 0x62, + 0x8e, 0x5a, 0x5a, 0xa6, 0x03, 0xe9, 0x72, 0x46, 0x3f, 0x38, 0xc8, 0xc1, + 0xd7, 0x47, 0x0f, 0xd0, 0xeb, 0x61, 0xfa, 0x20, 0x5a, 0xf5, 0x32, 0xf1, + 0x2d, 0xae, 0xac, 0x4c, 0x4b, 0xc8, 0x65, 0x89, 0x8c, 0x87, 0x02, 0x26, + 0x0c, 0x7f, 0x4c, 0xf6, 0xd7, 0xeb, 0x51, 0x92, 0x3b, 0xad, 0x7d, 0x2c, + 0xb4, 0xc0, 0x4b, 0x1f, 0x33, 0xa2, 0x73, 0x64, 0xb1, 0x27, 0xaf, 0xe3, + 0x44, 0x5c, 0x26, 0xb6, 0x8b, 0x64, 0x74, 0xef, 0x1c, 0x32, 0x4b, 0x0c, + 0xb2, 0x31, 0x95, 0x81, 0x39, 0x2e, 0x49, 0x05, 0xbe, 0xe3, 0x03, 0xbe, + 0x87, 0xbc, 0xcf, 0x53, 0x55, 0x73, 0xb5, 0x5c, 0xa8, 0xd3, 0xc2, 0xae, + 0xa8, 0x85, 0x4c, 0xa1, 0x4e, 0x39, 0x59, 0x47, 0x9b, 0x56, 0x37, 0x78, + 0x3a, 0x49, 0x4c, 0xd5, 0x69, 0x55, 0x31, 0x12, 0xf9, 0xc2, 0xb8, 0x71, + 0xf4, 0x8f, 0x61, 0xe9, 0xef, 0xdf, 0x44, 0x5e, 0xd6, 0x1b, 0x55, 0xfe, + 0x3a, 0xb1, 0x00, 0x9a, 0x9e, 0x78, 0x73, 0x4e, 0x84, 0xf9, 0x47, 0x62, + 0x71, 0xae, 0x78, 0xba, 0x2a, 0x2a, 0xc8, 0xed, 0xd5, 0xc9, 0x34, 0x69, + 0x55, 0x53, 0x2f, 0x2c, 0xab, 0xd0, 0x64, 0x1f, 0xaf, 0x1e, 0x9b, 0x6f, + 0xf7, 0xd0, 0xf7, 0x46, 0x79, 0xe5, 0x89, 0x6a, 0x66, 0x1c, 0xf4, 0x8a, + 0xc8, 0x54, 0x0d, 0x86, 0x48, 0x23, 0x07, 0xdf, 0xae, 0x80, 0xb4, 0x75, + 0x4b, 0xce, 0xed, 0x8a, 0xfa, 0xc9, 0x8b, 0xb6, 0x5a, 0x34, 0xce, 0x54, + 0x2f, 0x6d, 0xb5, 0x30, 0x64, 0xab, 0xb7, 0x24, 0x40, 0x78, 0x8c, 0x93, + 0x34, 0x9b, 0x0f, 0xa7, 0xae, 0x73, 0xfa, 0xea, 0x0a, 0x68, 0x96, 0x48, + 0x92, 0x44, 0x99, 0x54, 0x3f, 0xfc, 0x42, 0xc7, 0x04, 0x2e, 0x40, 0xdb, + 0xdb, 0x5f, 0x60, 0xad, 0x6a, 0x39, 0xe4, 0xf9, 0x44, 0x0f, 0x02, 0xc5, + 0xcc, 0x18, 0xaf, 0x28, 0xf3, 0x13, 0xe6, 0x03, 0xbf, 0x7d, 0x40, 0x8f, + 0xb1, 0x4a, 0xa6, 0x65, 0x54, 0x81, 0x23, 0x89, 0x37, 0x77, 0xc7, 0x99, + 0xbd, 0x4e, 0xbe, 0x32, 0x40, 0x0c, 0x8c, 0xbc, 0xc5, 0x7e, 0xac, 0x0e, + 0xa7, 0x3d, 0xc9, 0xed, 0xa1, 0x67, 0x50, 0x70, 0xb1, 0x33, 0x3c, 0x60, + 0x82, 0x09, 0xed, 0xae, 0xe2, 0x6c, 0x4e, 0x59, 0xc0, 0x0f, 0xb6, 0x0f, + 0x6c, 0xfa, 0xe8, 0x4b, 0x25, 0x74, 0x75, 0x91, 0x11, 0x5b, 0x9d, 0xd7, + 0x0c, 0xac, 0xdd, 0x7d, 0xb1, 0xa8, 0xf3, 0x5f, 0x5d, 0x70, 0x5a, 0x58, + 0x55, 0xe5, 0xab, 0x76, 0x21, 0x63, 0x5d, 0xce, 0x74, 0x3d, 0x65, 0x4b, + 0x53, 0xd5, 0xf8, 0xce, 0xa6, 0x47, 0xe5, 0xd8, 0x83, 0xb6, 0x7d, 0xf5, + 0xf7, 0x86, 0xae, 0x95, 0x14, 0xd7, 0x46, 0x9d, 0x27, 0x6a, 0x4a, 0xb7, + 0x23, 0xe5, 0xe4, 0x0e, 0x31, 0xcd, 0x9d, 0xc6, 0x71, 0xb1, 0x3a, 0x10, + 0x33, 0xe7, 0x8c, 0x29, 0x7b, 0x2f, 0x7c, 0x39, 0xc0, 0x4c, 0x1a, 0xdb, + 0xc4, 0x86, 0xe5, 0x4d, 0x70, 0x73, 0x3a, 0xac, 0x90, 0x8d, 0xfc, 0x3e, + 0xdb, 0x83, 0xd0, 0xab, 0x63, 0xf4, 0xd2, 0xa4, 0x8e, 0x6a, 0xaf, 0x88, + 0x57, 0x08, 0x3a, 0xcb, 0x55, 0x2b, 0x73, 0x12, 0x37, 0xc8, 0x03, 0x1a, + 0xe2, 0x5b, 0xa5, 0x55, 0x35, 0x5d, 0x75, 0xc3, 0x15, 0x14, 0xb7, 0x29, + 0x4f, 0x37, 0x82, 0xbb, 0x01, 0x9d, 0xd8, 0xfa, 0x0d, 0xfb, 0x63, 0x5f, + 0x78, 0x3f, 0x88, 0x3e, 0x43, 0x88, 0x23, 0xe2, 0x23, 0x49, 0x1d, 0x5c, + 0xa0, 0xb1, 0x71, 0x2f, 0x46, 0xe6, 0x03, 0x39, 0x03, 0xa1, 0xdb, 0x3a, + 0x46, 0x59, 0x5b, 0x38, 0xd9, 0x72, 0xca, 0x6f, 0x93, 0x42, 0xac, 0x92, + 0xba, 0xcd, 0x65, 0x9e, 0xd6, 0x64, 0x91, 0x59, 0xa0, 0x1e, 0x33, 0x74, + 0xcf, 0x72, 0x3d, 0xfa, 0x6b, 0x2c, 0xb9, 0x55, 0x86, 0xa8, 0xf1, 0xa2, + 0x8d, 0xa3, 0x47, 0xc3, 0x60, 0x9c, 0x63, 0x3d, 0x75, 0xa9, 0xf1, 0x6f, + 0x19, 0xd9, 0xea, 0xed, 0x50, 0xd4, 0xd9, 0x96, 0xad, 0x6b, 0x6a, 0x0e, + 0x25, 0x8e, 0xa1, 0xb9, 0xd6, 0x9f, 0xae, 0x79, 0x4e, 0x37, 0x27, 0xb1, + 0xd6, 0x43, 0x7f, 0xa8, 0xa5, 0x15, 0x8a, 0xa3, 0x69, 0x79, 0xb0, 0xd8, + 0x1b, 0x03, 0xdb, 0x3f, 0x7f, 0x5d, 0x2a, 0x9d, 0xee, 0x62, 0xb6, 0x96, + 0xba, 0xbb, 0x6b, 0x52, 0xaa, 0x2b, 0xc7, 0x24, 0x53, 0x90, 0x09, 0x46, + 0xe8, 0x41, 0x00, 0x86, 0xcf, 0x7c, 0xe7, 0x57, 0x7a, 0x4e, 0x1f, 0xb9, + 0x57, 0xf0, 0x4d, 0x24, 0x56, 0xc0, 0x90, 0xab, 0xb2, 0xb4, 0xb0, 0xf4, + 0x69, 0x64, 0xc9, 0xc3, 0x13, 0xfd, 0x5b, 0x74, 0xf4, 0x1a, 0x4b, 0xc4, + 0x75, 0x90, 0x49, 0x6e, 0xb7, 0x45, 0xf2, 0x75, 0x91, 0x5c, 0x69, 0xd7, + 0x13, 0x89, 0x36, 0x55, 0x42, 0xbe, 0x51, 0xef, 0xb6, 0x0f, 0xd8, 0x8d, + 0x1f, 0x65, 0xe2, 0x2a, 0xd9, 0x6a, 0x22, 0xad, 0x7a, 0xd6, 0x2b, 0x00, + 0x08, 0xc8, 0x48, 0x20, 0xa0, 0xec, 0x06, 0xda, 0xe6, 0xad, 0xc9, 0xbb, + 0x42, 0xd2, 0x57, 0xc8, 0xa9, 0xad, 0x97, 0x84, 0xbb, 0xc1, 0x6e, 0xf9, + 0x59, 0x3e, 0x6a, 0xa1, 0x7f, 0x92, 0x24, 0x1c, 0xbc, 0xde, 0xfa, 0x60, + 0x9c, 0x15, 0xc6, 0xd4, 0xb5, 0x22, 0xba, 0x8e, 0x23, 0x0c, 0xd1, 0xe5, + 0x87, 0xcb, 0x4c, 0x39, 0x87, 0xb6, 0x36, 0xdb, 0x45, 0x7c, 0x53, 0xb8, + 0x51, 0x56, 0xd3, 0x43, 0x74, 0xb7, 0xd5, 0xab, 0xba, 0x1e, 0x5e, 0x50, + 0x71, 0x2a, 0x12, 0xa3, 0xbf, 0xa6, 0x47, 0xe3, 0xf7, 0xd4, 0xfc, 0x01, + 0xf1, 0x17, 0xf8, 0x75, 0x9a, 0x9e, 0xdf, 0x7a, 0x54, 0x92, 0x30, 0x4b, + 0x19, 0x17, 0xeb, 0x52, 0x77, 0xdf, 0xd7, 0x3a, 0x67, 0xd5, 0x59, 0x36, + 0xc7, 0xf4, 0x0b, 0xc7, 0x75, 0x33, 0x7f, 0xe8, 0x1b, 0x7c, 0x0b, 0x48, + 0xb6, 0xea, 0x88, 0x1b, 0x9e, 0xb6, 0x34, 0x3b, 0x9c, 0x82, 0x01, 0xc7, + 0xf7, 0xfb, 0x8d, 0x67, 0x96, 0x88, 0x8b, 0xba, 0x21, 0x84, 0x4a, 0x59, + 0xb1, 0x82, 0x76, 0x24, 0xed, 0xad, 0x42, 0xb6, 0xb6, 0xd3, 0xc5, 0x6d, + 0x55, 0x47, 0x14, 0xae, 0x6a, 0x6b, 0x26, 0x39, 0x2a, 0x0b, 0x10, 0xa3, + 0xa0, 0xfc, 0x0c, 0x0d, 0x41, 0x27, 0x0a, 0xd3, 0x5a, 0x28, 0x8d, 0x1d, + 0x24, 0x86, 0x3a, 0x92, 0xb9, 0xf1, 0x25, 0x05, 0x5b, 0x20, 0x74, 0xdf, + 0xa0, 0xed, 0xa4, 0xe4, 0xd5, 0x42, 0x0d, 0x2f, 0x61, 0x49, 0xf0, 0x33, + 0x36, 0xeb, 0x3a, 0xdb, 0x95, 0xad, 0x51, 0x0a, 0x0a, 0xe9, 0x11, 0x01, + 0xf1, 0x10, 0x18, 0xf3, 0x8d, 0xf6, 0x18, 0xc8, 0x27, 0xd7, 0x54, 0xcb, + 0x5d, 0xee, 0xe5, 0x1f, 0x15, 0xa8, 0x48, 0x29, 0x62, 0x11, 0x31, 0x59, + 0x84, 0x3e, 0x50, 0x18, 0x67, 0x24, 0x2f, 0xa6, 0xd8, 0xeb, 0xdf, 0x42, + 0x53, 0xf1, 0x15, 0x42, 0xdc, 0xe9, 0x6d, 0xd7, 0x98, 0xde, 0xa2, 0x88, + 0xcb, 0xe1, 0x1e, 0x71, 0xba, 0x12, 0x71, 0xb1, 0xd1, 0x9c, 0x55, 0xc2, + 0x15, 0x10, 0xc5, 0x51, 0x78, 0x86, 0xa1, 0x63, 0x59, 0x6a, 0x3c, 0x2a, + 0x68, 0xc3, 0x79, 0xe4, 0x52, 0x7a, 0xff, 0x00, 0x6f, 0xd3, 0x4f, 0x96, + 0x6d, 0xd2, 0xda, 0xd5, 0x58, 0x26, 0xa4, 0xb7, 0x1a, 0x99, 0xa9, 0x4d, + 0xb1, 0xdc, 0xa8, 0x68, 0xc7, 0x20, 0x04, 0x0c, 0x8d, 0x86, 0xdf, 0x8d, + 0x53, 0xf8, 0xcb, 0xe1, 0x95, 0x0d, 0xe0, 0x1a, 0xd9, 0xaa, 0x62, 0x82, + 0x45, 0x89, 0x9e, 0x01, 0xcb, 0xcc, 0xe1, 0x80, 0x52, 0x03, 0xb0, 0xce, + 0x17, 0xd7, 0xb0, 0x3a, 0xb2, 0xf0, 0x35, 0xb1, 0xae, 0xb7, 0x8a, 0xfa, + 0x5a, 0xfb, 0x83, 0x47, 0x4f, 0xcc, 0x7e, 0x5d, 0x42, 0x85, 0x20, 0xe7, + 0xfe, 0x63, 0xbf, 0xe3, 0x56, 0x1a, 0xab, 0x5d, 0x65, 0xbe, 0xad, 0x05, + 0x6d, 0x23, 0x4f, 0x40, 0xaa, 0x73, 0x32, 0xb0, 0xe4, 0x60, 0x08, 0xc0, + 0x65, 0x1d, 0x88, 0xdf, 0x1e, 0xda, 0xdd, 0x2c, 0x92, 0x8b, 0xb8, 0xfa, + 0x1f, 0x14, 0xe2, 0xdb, 0x64, 0x1f, 0x02, 0x6d, 0xf5, 0x94, 0xb6, 0x39, + 0xe2, 0x92, 0x9a, 0x96, 0x8a, 0xa6, 0x96, 0x51, 0x0b, 0x2c, 0x1b, 0xc1, + 0x56, 0xa1, 0x47, 0xf3, 0x8b, 0xff, 0x00, 0x5b, 0x13, 0x91, 0xb6, 0x02, + 0xf4, 0xc1, 0xd6, 0x93, 0x1f, 0x2c, 0xf3, 0x2c, 0x09, 0x51, 0x0a, 0xc9, + 0x0e, 0x0c, 0x91, 0x23, 0x73, 0x11, 0x9d, 0xc1, 0x3d, 0x3a, 0xe9, 0x2d, + 0x3a, 0x45, 0x05, 0xbe, 0x3a, 0xaa, 0x78, 0x21, 0x8e, 0x49, 0x10, 0x78, + 0x66, 0x30, 0x04, 0x7e, 0x1e, 0x41, 0xd8, 0x7f, 0x49, 0xff, 0x00, 0x4d, + 0x35, 0x88, 0x40, 0x8c, 0x95, 0x2a, 0x86, 0x42, 0x00, 0x0e, 0xfc, 0xb8, + 0x61, 0x8e, 0x85, 0xbd, 0x86, 0xff, 0x00, 0xae, 0xab, 0x16, 0x69, 0x4a, + 0x5e, 0x46, 0xb5, 0x2e, 0x06, 0x53, 0xc9, 0xe1, 0xc6, 0x0b, 0xc6, 0xce, + 0x73, 0x8e, 0x55, 0x19, 0x24, 0x74, 0xce, 0xab, 0x75, 0xfc, 0x15, 0x6e, + 0xa9, 0xa9, 0x96, 0x7a, 0x87, 0x91, 0xfc, 0x46, 0x27, 0x94, 0x01, 0xdf, + 0xaf, 0x6d, 0x58, 0x62, 0x95, 0x5e, 0x36, 0xa8, 0xf1, 0xd5, 0xd4, 0x8f, + 0x21, 0x1b, 0x00, 0x3e, 0xfa, 0x1f, 0x9a, 0x69, 0xf2, 0x2a, 0x13, 0x95, + 0x41, 0xdc, 0xab, 0xe4, 0x1f, 0x6e, 0x9f, 0xbf, 0xb6, 0xb4, 0x67, 0xc3, + 0x8b, 0x2a, 0x4a, 0x6a, 0xca, 0xc8, 0x93, 0x5c, 0x95, 0x39, 0xf8, 0x3e, + 0x3a, 0x4b, 0x6d, 0xc9, 0xa0, 0x91, 0x9e, 0xa4, 0xd3, 0xca, 0xb6, 0xf5, + 0x6d, 0x96, 0x1f, 0x29, 0x23, 0x1f, 0xf3, 0x6d, 0x9c, 0xeb, 0xc7, 0xdc, + 0x43, 0x62, 0xab, 0xe7, 0xa8, 0x84, 0x41, 0x21, 0x97, 0x99, 0x94, 0xaf, + 0x2e, 0xfc, 0xc3, 0xb7, 0xed, 0xaf, 0x77, 0xca, 0x95, 0x02, 0xa9, 0xa7, + 0x82, 0x68, 0xc4, 0x0c, 0x9e, 0x60, 0xc3, 0x3e, 0x60, 0x46, 0xff, 0x00, + 0xa6, 0x75, 0x87, 0xfc, 0x49, 0xe3, 0xa8, 0x24, 0xbb, 0x56, 0xc7, 0x45, + 0x47, 0x4d, 0x1c, 0x48, 0x8e, 0xa2, 0x52, 0x3c, 0xf2, 0x49, 0xd3, 0x9b, + 0x1e, 0xdd, 0x89, 0xd6, 0x6d, 0x54, 0xfe, 0x24, 0x9c, 0x7f, 0xe0, 0xcd, + 0x9f, 0x6a, 0x4a, 0xcf, 0x2f, 0x5b, 0xae, 0x97, 0x3a, 0x54, 0xf9, 0x67, + 0x93, 0x23, 0x3c, 0xbc, 0x8e, 0x33, 0xbf, 0xa6, 0xb8, 0xa5, 0xa5, 0x34, + 0xb3, 0xbc, 0x8a, 0x9f, 0xcd, 0x99, 0xc8, 0x63, 0x9f, 0xa0, 0x13, 0xd7, + 0xfe, 0x9a, 0xb8, 0x52, 0x59, 0xd2, 0xb6, 0xbc, 0xd7, 0x54, 0xc2, 0x4c, + 0x4b, 0xbc, 0xac, 0xc7, 0xeb, 0x7e, 0xd8, 0x1f, 0xae, 0x84, 0xe2, 0x16, + 0x4a, 0x6a, 0xb4, 0x0b, 0x4c, 0x73, 0xca, 0x0f, 0x9b, 0xa3, 0x7b, 0xea, + 0xe1, 0x97, 0x7c, 0xb6, 0xc4, 0x5c, 0x64, 0x7c, 0x9e, 0xd6, 0x28, 0xea, + 0xed, 0x95, 0x14, 0x22, 0x49, 0x69, 0x84, 0x45, 0xdc, 0x63, 0x3c, 0xc5, + 0x4f, 0x31, 0x20, 0x7e, 0x40, 0xfc, 0xeb, 0xef, 0x1b, 0x5e, 0x45, 0xf7, + 0x88, 0xab, 0x6f, 0x53, 0x40, 0xb4, 0xf3, 0xd5, 0xc6, 0xbc, 0xc0, 0x28, + 0x5e, 0x76, 0x00, 0x02, 0xc5, 0x47, 0x4c, 0xe0, 0x6d, 0xed, 0xab, 0x67, + 0xc2, 0xeb, 0xa4, 0x94, 0xa6, 0xe7, 0xc4, 0x35, 0x53, 0x28, 0x92, 0x9a, + 0x94, 0xd3, 0xd3, 0xd3, 0x2c, 0x63, 0x05, 0x1b, 0x63, 0xe6, 0x3b, 0x2f, + 0xb7, 0xb9, 0xce, 0xb3, 0xc7, 0xb5, 0xde, 0xe4, 0xab, 0x68, 0x24, 0xa8, + 0xf1, 0xa9, 0x0c, 0xd9, 0x4e, 0x67, 0x1f, 0x56, 0xfe, 0xbe, 0x99, 0x23, + 0x4e, 0x8c, 0xd3, 0x93, 0x8b, 0xf4, 0x35, 0x31, 0xaf, 0xc9, 0x5d, 0x29, + 0x78, 0x3f, 0xe6, 0x40, 0xa4, 0x92, 0x8a, 0x49, 0x15, 0x32, 0x79, 0x0b, + 0xc6, 0xcc, 0x33, 0x90, 0x33, 0xcc, 0x3f, 0xb6, 0xab, 0xd5, 0xd0, 0x3c, + 0x10, 0x09, 0x26, 0x60, 0x99, 0x19, 0x03, 0xae, 0xfa, 0x79, 0x6a, 0x92, + 0xa2, 0xd7, 0x72, 0x6a, 0x1a, 0xc5, 0x3c, 0x92, 0x31, 0xe5, 0xcf, 0x4c, + 0xeb, 0xe7, 0x19, 0xa0, 0xae, 0x14, 0xb4, 0xf4, 0xa8, 0x8a, 0xc6, 0x4e, + 0x56, 0x23, 0xaf, 0xa6, 0x95, 0x1c, 0x8f, 0xe4, 0x49, 0xf4, 0x0c, 0xa6, + 0x55, 0x69, 0x26, 0x67, 0x5e, 0x63, 0xf4, 0xab, 0x6d, 0xf6, 0xd3, 0xfa, + 0x51, 0x1a, 0x2f, 0x89, 0x50, 0x39, 0xc3, 0x79, 0x95, 0x71, 0xd4, 0x1d, + 0x7e, 0xaa, 0xe1, 0x69, 0x6d, 0xf4, 0x80, 0xcb, 0x22, 0x78, 0xc1, 0xfc, + 0xb8, 0x18, 0xcf, 0x5d, 0x08, 0xbe, 0x24, 0x8e, 0x90, 0xbc, 0x6c, 0xb2, + 0x0d, 0x97, 0x1d, 0x3f, 0x5d, 0x33, 0xe4, 0x53, 0x57, 0x12, 0xdf, 0x28, + 0xb4, 0xf0, 0xf4, 0x94, 0x13, 0x19, 0x3c, 0x68, 0xca, 0x96, 0x25, 0x51, + 0x14, 0xec, 0x17, 0x07, 0xaf, 0xae, 0x74, 0x75, 0x6d, 0x03, 0x57, 0x45, + 0x5b, 0x54, 0x58, 0xe2, 0xa6, 0x89, 0x5c, 0x05, 0x5e, 0x9c, 0x88, 0x39, + 0xb3, 0xe9, 0xb9, 0x1a, 0x4b, 0x65, 0x49, 0x61, 0xaa, 0xa3, 0x6e, 0x61, + 0xcf, 0x14, 0xca, 0x18, 0x0e, 0x99, 0x27, 0xd7, 0x57, 0x35, 0xc4, 0x13, + 0x5d, 0x28, 0xe7, 0x40, 0x3c, 0x0a, 0x79, 0xd4, 0x64, 0xe3, 0x98, 0x92, + 0xb8, 0xfb, 0x75, 0x3a, 0x76, 0x9f, 0xa6, 0x6d, 0xd1, 0xcf, 0x72, 0x6b, + 0xf4, 0x53, 0x78, 0x96, 0x70, 0xb6, 0x1a, 0x48, 0x51, 0xb9, 0x52, 0xa9, + 0xe3, 0x9c, 0xc6, 0x06, 0xd9, 0x20, 0xab, 0x7e, 0xe3, 0x4c, 0xa8, 0xf0, + 0xb5, 0x16, 0xe7, 0xa6, 0x01, 0x3c, 0x02, 0x32, 0xec, 0x70, 0x3a, 0x64, + 0x8f, 0xdb, 0x4b, 0x67, 0x0c, 0x28, 0x78, 0x6e, 0x29, 0xd5, 0xe4, 0x09, + 0x3d, 0x44, 0xc5, 0x33, 0xb2, 0xa0, 0x61, 0x8c, 0x1f, 0xc6, 0x3b, 0x68, + 0xc9, 0xe6, 0x49, 0x29, 0x93, 0xe5, 0x61, 0x68, 0x64, 0x9e, 0x62, 0xdc, + 0x85, 0x89, 0xc6, 0x4e, 0x4e, 0xfd, 0xc6, 0x35, 0xa0, 0xd7, 0x0e, 0xc1, + 0x69, 0x61, 0x96, 0xe5, 0x7b, 0x86, 0x9a, 0x47, 0x1f, 0x2e, 0xb2, 0x12, + 0xa4, 0x0d, 0x94, 0x13, 0x9d, 0xb4, 0x5f, 0x11, 0xd2, 0x53, 0xc5, 0x7d, + 0x16, 0xda, 0x66, 0x73, 0x1f, 0x22, 0xb4, 0x92, 0x36, 0xf8, 0xdb, 0x6f, + 0xfc, 0x6a, 0x5b, 0x4d, 0x5a, 0xd0, 0x71, 0x07, 0x8a, 0xcd, 0x94, 0x73, + 0xe4, 0x21, 0x76, 0x39, 0xdc, 0x0c, 0x6a, 0x6b, 0xd2, 0x54, 0x41, 0x5a, + 0x2a, 0x4c, 0x7c, 0xa6, 0xb0, 0x99, 0x39, 0xc3, 0x67, 0x94, 0xff, 0x00, + 0xe3, 0x3b, 0x68, 0x46, 0x24, 0x2c, 0x8a, 0x8e, 0x59, 0x88, 0x39, 0x64, + 0xe4, 0x63, 0xc8, 0xca, 0x7e, 0x9c, 0x76, 0xd7, 0x10, 0x3a, 0xa8, 0x9a, + 0x22, 0x87, 0x2c, 0xc0, 0x47, 0x83, 0xb0, 0xc6, 0x76, 0xf7, 0x1d, 0x74, + 0x6b, 0xf8, 0x2d, 0x0a, 0xd1, 0xcb, 0x2a, 0x81, 0x36, 0x4a, 0xc8, 0xc3, + 0x02, 0x3f, 0x71, 0xe8, 0x4e, 0x82, 0xf9, 0x79, 0x10, 0xc9, 0x07, 0x3a, + 0x48, 0xc8, 0xde, 0x46, 0x56, 0xce, 0xdd, 0xb5, 0x44, 0x44, 0x82, 0x28, + 0xd5, 0x9d, 0x64, 0x8f, 0xcf, 0x9c, 0x82, 0x3a, 0x69, 0x6d, 0x73, 0xc9, + 0x33, 0x98, 0xd5, 0xb0, 0xca, 0x4e, 0xfe, 0x9b, 0xed, 0xfb, 0x68, 0xdb, + 0xa8, 0x9e, 0x9c, 0xe2, 0x56, 0x1c, 0xdd, 0x48, 0xce, 0x96, 0x54, 0x4a, + 0x42, 0xc4, 0x85, 0x0f, 0x34, 0xad, 0x93, 0x9d, 0x86, 0x35, 0x0b, 0x25, + 0x96, 0x70, 0x5d, 0x28, 0x9a, 0x97, 0xc3, 0x66, 0x65, 0x65, 0x98, 0x92, + 0x72, 0x3e, 0xda, 0x02, 0xa6, 0x08, 0xed, 0xf5, 0xb2, 0x4b, 0x5c, 0xa8, + 0xc0, 0xf9, 0x57, 0x0b, 0x80, 0x17, 0xfe, 0x5f, 0x4d, 0x18, 0x55, 0x16, + 0x55, 0x45, 0x05, 0x50, 0xae, 0x0e, 0x0e, 0xea, 0x73, 0xd7, 0x45, 0x9b, + 0x19, 0xbb, 0x55, 0xa4, 0xd3, 0xcb, 0x27, 0xf0, 0xda, 0x75, 0xe6, 0xcb, + 0xff, 0x00, 0xee, 0x11, 0xd8, 0x69, 0x51, 0x9b, 0x94, 0xdc, 0x59, 0xc8, + 0xc9, 0xfe, 0xa3, 0x62, 0xf1, 0x25, 0x7d, 0x7d, 0x4c, 0x13, 0xd1, 0xc9, + 0x57, 0x94, 0x01, 0x15, 0x49, 0xe7, 0x3c, 0xaa, 0x31, 0x81, 0xd3, 0x6d, + 0xb1, 0xab, 0xbd, 0x8a, 0xd9, 0x67, 0xb8, 0x45, 0x14, 0x0b, 0x77, 0x36, + 0xea, 0xc7, 0x20, 0x3d, 0x25, 0x64, 0x4c, 0xa4, 0xb9, 0xea, 0x73, 0xd3, + 0x1a, 0xad, 0xcb, 0x73, 0x92, 0x9d, 0xdc, 0xdb, 0xff, 0x00, 0xdd, 0x83, + 0x80, 0x14, 0xa8, 0xf3, 0x22, 0x0e, 0x8a, 0x0f, 0x6e, 0xbf, 0x9d, 0x7e, + 0xa7, 0x79, 0x2b, 0x2b, 0x60, 0x85, 0xe6, 0xe7, 0xfe, 0x50, 0x2c, 0xcc, + 0x77, 0x2e, 0xcc, 0xa3, 0x7f, 0x5f, 0xdb, 0xa6, 0xb3, 0xe4, 0xed, 0xc8, + 0x43, 0x34, 0x6e, 0x20, 0xe0, 0x9b, 0xcd, 0x92, 0x9a, 0x8e, 0x68, 0x0d, + 0x3d, 0x5c, 0x53, 0xb3, 0x2a, 0x3a, 0x36, 0xcb, 0x82, 0x37, 0x39, 0xe8, + 0x7d, 0xbd, 0x06, 0x97, 0xd1, 0x59, 0xb8, 0x21, 0xaa, 0xa3, 0xfe, 0x2d, + 0x78, 0xaa, 0x17, 0x29, 0x58, 0x44, 0xf2, 0xd3, 0xd3, 0x8f, 0x06, 0x39, + 0x0b, 0x64, 0x9c, 0x9e, 0xa0, 0x0f, 0x4d, 0xbb, 0xe7, 0x7d, 0x36, 0xe3, + 0x98, 0x6d, 0x16, 0x1e, 0x0f, 0xb4, 0xc3, 0x6e, 0xbc, 0x9a, 0x9b, 0x88, + 0xcb, 0xd4, 0x88, 0x2b, 0x4c, 0x91, 0xc6, 0x40, 0xc3, 0x02, 0x9b, 0x80, + 0x49, 0x23, 0x70, 0x7d, 0x46, 0xfa, 0xa5, 0xd0, 0xcb, 0x35, 0x1f, 0x0a, + 0xd5, 0xf1, 0x19, 0xa6, 0xa5, 0x25, 0x26, 0x14, 0x50, 0x16, 0x07, 0x31, + 0xc8, 0xe0, 0xb7, 0x30, 0x19, 0xdc, 0x80, 0xac, 0x37, 0xdb, 0x71, 0xa1, + 0x4e, 0xda, 0x41, 0x17, 0x9a, 0x9b, 0x1f, 0x10, 0xf0, 0xf5, 0x75, 0x5d, + 0x3b, 0xdc, 0x29, 0x65, 0xa2, 0x58, 0x0c, 0xef, 0x24, 0xd3, 0xa9, 0x32, + 0x8c, 0x80, 0x15, 0x41, 0xdf, 0x9b, 0x71, 0xb0, 0xed, 0x9d, 0x01, 0x0d, + 0x86, 0xdd, 0x7c, 0x09, 0x4f, 0x6f, 0xba, 0xc1, 0x43, 0x79, 0x6f, 0x39, + 0xa7, 0xa8, 0xa8, 0x01, 0x1f, 0x62, 0x72, 0x18, 0xec, 0x35, 0x8e, 0x54, + 0xdc, 0x6a, 0x65, 0xac, 0x53, 0x56, 0xcf, 0x50, 0x39, 0xc1, 0x2a, 0x64, + 0x6c, 0xbf, 0xa0, 0xce, 0x75, 0xa0, 0xf0, 0xa5, 0xc7, 0x87, 0x63, 0xe2, + 0x2a, 0x1b, 0x3d, 0xda, 0x2a, 0xc8, 0x9a, 0x66, 0x22, 0xa2, 0xa1, 0x9f, + 0x9c, 0xc5, 0xe5, 0x25, 0x79, 0x32, 0x3e, 0x9c, 0x80, 0x33, 0xef, 0xa3, + 0x7a, 0x7e, 0x77, 0x5f, 0xa0, 0x06, 0x75, 0xf3, 0x9f, 0xe1, 0xe2, 0x9d, + 0x92, 0x9e, 0x27, 0xa3, 0x8b, 0x96, 0x49, 0xd4, 0x61, 0x64, 0x3d, 0x4e, + 0x4f, 0xf5, 0x1f, 0x4f, 0xb6, 0xa1, 0xa8, 0xe1, 0x4b, 0xe9, 0x34, 0x72, + 0x4d, 0x4b, 0x3c, 0x26, 0xa9, 0x99, 0x51, 0x66, 0x1c, 0xac, 0x40, 0xc7, + 0x9b, 0x97, 0xa8, 0x19, 0x23, 0x7f, 0xbe, 0x99, 0xf0, 0x2f, 0x0f, 0x1e, + 0x26, 0xe3, 0x43, 0x40, 0x2a, 0x9e, 0x9e, 0x3a, 0x58, 0x9e, 0xa3, 0xc6, + 0x76, 0x0d, 0xba, 0x83, 0xca, 0x77, 0xdb, 0x39, 0xc7, 0x5e, 0xc4, 0xe9, + 0x25, 0xff, 0x00, 0x8c, 0x38, 0x8a, 0xe5, 0x75, 0x79, 0x2b, 0xef, 0x73, + 0xd4, 0x54, 0xc1, 0x21, 0x11, 0xb2, 0xbe, 0x02, 0x80, 0x71, 0xb6, 0x3f, + 0xcb, 0x58, 0x96, 0x18, 0xf3, 0x40, 0x51, 0xa1, 0xda, 0xb8, 0x66, 0xdd, + 0xc3, 0xd6, 0x88, 0xea, 0x6b, 0x0b, 0xc9, 0x73, 0x38, 0x6e, 0x68, 0xd8, + 0xe2, 0x36, 0xc6, 0xd8, 0x00, 0x8d, 0xf7, 0xd0, 0x95, 0x97, 0x5a, 0xfa, + 0xee, 0x78, 0xc5, 0xda, 0x49, 0x5d, 0x5b, 0x1e, 0x15, 0x46, 0xdc, 0xd8, + 0xf4, 0x3a, 0x93, 0xe1, 0x2f, 0xc4, 0x1a, 0x48, 0xee, 0xf4, 0xf4, 0x7c, + 0x5d, 0x04, 0x55, 0x49, 0x2b, 0x11, 0x15, 0x7c, 0x99, 0x2f, 0x19, 0x6e, + 0xcf, 0x9c, 0xf3, 0x2f, 0xbf, 0x6d, 0x5d, 0xea, 0xbe, 0x1e, 0x56, 0x9b, + 0xb2, 0x5f, 0x38, 0x76, 0xa2, 0x95, 0xff, 0x00, 0xdf, 0xa4, 0x22, 0x19, + 0x10, 0x05, 0xe5, 0x0c, 0x70, 0x41, 0x07, 0x07, 0xa7, 0x4c, 0x74, 0x3e, + 0xda, 0x46, 0x5d, 0x23, 0x6e, 0xd1, 0x7f, 0x13, 0x7d, 0x18, 0xe2, 0xdb, + 0xa7, 0xaa, 0xe2, 0x78, 0x3c, 0x59, 0x4c, 0x30, 0x49, 0x2f, 0x34, 0xaa, + 0xbe, 0xa3, 0x39, 0x1f, 0xae, 0xae, 0x15, 0x74, 0xf4, 0x44, 0x81, 0x2b, + 0xca, 0xd0, 0xe0, 0x8e, 0x5e, 0x6e, 0xa5, 0xba, 0x9f, 0xbe, 0xb4, 0xb4, + 0xf8, 0x71, 0x47, 0x53, 0x09, 0x17, 0x49, 0x07, 0xce, 0xb3, 0x16, 0x9a, + 0xaa, 0x12, 0x54, 0x6e, 0x09, 0x01, 0x50, 0x92, 0x01, 0x1b, 0x7d, 0xc6, + 0x75, 0x8c, 0xdf, 0x66, 0xfe, 0x1f, 0x7a, 0xaa, 0xb3, 0xf8, 0xce, 0xe6, + 0x09, 0x0a, 0xf3, 0xba, 0x72, 0xe4, 0x82, 0x46, 0xc3, 0x27, 0x6d, 0x6b, + 0xc3, 0x8a, 0x4b, 0xec, 0xca, 0x78, 0xe8, 0xd9, 0xf8, 0x53, 0x86, 0xe8, + 0xff, 0x00, 0x88, 0x53, 0xf1, 0x03, 0xd7, 0xc8, 0xa5, 0x11, 0x79, 0x60, + 0x31, 0x82, 0x55, 0xb9, 0x40, 0x2c, 0x09, 0x27, 0xfb, 0x6a, 0xd9, 0x56, + 0x22, 0x92, 0x05, 0x85, 0x2b, 0x0a, 0xcd, 0xe5, 0x7f, 0x13, 0x3e, 0x63, + 0x83, 0xf4, 0x91, 0xd3, 0xee, 0x74, 0x8e, 0x9a, 0xa2, 0xa6, 0x9e, 0xc5, + 0x48, 0xf4, 0xc3, 0xc7, 0x0d, 0x4e, 0xbc, 0xf2, 0x0c, 0x01, 0x18, 0x00, + 0x0e, 0x53, 0x9e, 0x9d, 0xc6, 0xdd, 0x71, 0xa0, 0x66, 0xad, 0x09, 0x4d, + 0x05, 0x5d, 0x12, 0x24, 0x22, 0x49, 0x3c, 0x09, 0xd2, 0x38, 0x4f, 0x21, + 0xc6, 0xfd, 0xce, 0x4f, 0x4f, 0x6d, 0x56, 0x4c, 0x8a, 0x32, 0x69, 0x9b, + 0x1f, 0x6e, 0x8b, 0x4d, 0x3d, 0x42, 0xc1, 0x4d, 0x3c, 0x35, 0x46, 0x26, + 0x75, 0x5c, 0xa8, 0x24, 0x30, 0x39, 0xe8, 0xb8, 0x1f, 0xb6, 0xab, 0x17, + 0xbe, 0x20, 0x7b, 0x45, 0x4a, 0xf3, 0xd1, 0x54, 0x07, 0x48, 0x8b, 0x98, + 0xc9, 0x18, 0xf0, 0xc9, 0xdc, 0x92, 0x76, 0xfc, 0x13, 0xaa, 0x97, 0x12, + 0x71, 0x7c, 0x54, 0x97, 0xda, 0x85, 0x9a, 0xb5, 0x60, 0xa6, 0x8c, 0x73, + 0x49, 0x84, 0xc0, 0x5d, 0x8e, 0x10, 0x2f, 0xa9, 0xdb, 0x7f, 0x6d, 0x71, + 0x6a, 0xe2, 0x2a, 0xdb, 0xdf, 0x0c, 0xca, 0x05, 0xae, 0x25, 0x5d, 0xf0, + 0x6b, 0x1b, 0x06, 0x55, 0x3d, 0x0a, 0x9d, 0xb9, 0x57, 0x1d, 0x4f, 0xf7, + 0xd2, 0xe3, 0x39, 0x49, 0x5a, 0x66, 0x57, 0x94, 0xbc, 0xf0, 0xb7, 0x13, + 0x47, 0x74, 0x82, 0xa2, 0x6b, 0x64, 0x6f, 0xf2, 0x71, 0xc4, 0x64, 0xe5, + 0x09, 0x80, 0xa4, 0xe0, 0xf4, 0x27, 0x7e, 0xfd, 0x3a, 0xeb, 0xb3, 0x72, + 0xfe, 0x35, 0x04, 0x75, 0x14, 0x2b, 0x35, 0x25, 0x50, 0x3b, 0xcb, 0x2f, + 0x91, 0xa6, 0x0b, 0xb6, 0x15, 0x8f, 0x4c, 0xee, 0x7a, 0x74, 0xd2, 0x0f, + 0x87, 0x0f, 0x05, 0x3d, 0x9a, 0x68, 0x26, 0xa3, 0x99, 0xe5, 0xa7, 0x8d, + 0xc7, 0x89, 0x1b, 0x64, 0x54, 0x31, 0xe9, 0xe1, 0xa6, 0xc4, 0xf4, 0x03, + 0x27, 0x6d, 0x58, 0xe8, 0x6d, 0x51, 0xcd, 0x47, 0x47, 0x1d, 0x78, 0xf9, + 0xa9, 0xa5, 0x0d, 0x24, 0xe2, 0x70, 0x57, 0x95, 0x1b, 0x7f, 0x32, 0x13, + 0xb1, 0x04, 0x74, 0x1b, 0x6d, 0xab, 0x87, 0xc9, 0xe9, 0xd8, 0x71, 0x7b, + 0xe3, 0x64, 0x7c, 0x6f, 0x73, 0xbc, 0x43, 0xc0, 0xd5, 0x32, 0xc5, 0x32, + 0x41, 0x5b, 0x28, 0xe5, 0x89, 0x63, 0x42, 0x79, 0x54, 0x92, 0x33, 0x91, + 0xed, 0xaf, 0x3d, 0xd6, 0xda, 0x2b, 0x11, 0xd8, 0xcf, 0x32, 0x2a, 0x91, + 0x92, 0x73, 0xb8, 0xc9, 0xf4, 0xd7, 0xa2, 0xe8, 0xed, 0xa6, 0xe5, 0x43, + 0x72, 0xb6, 0x4d, 0x54, 0xbe, 0x0e, 0x4a, 0x53, 0xf8, 0x52, 0xf3, 0xaa, + 0x2f, 0x63, 0x8f, 0xf2, 0xdf, 0xa8, 0xd6, 0x5f, 0xf1, 0x13, 0x83, 0xef, + 0x5c, 0x3f, 0x6c, 0x8e, 0xe5, 0x03, 0x53, 0xdc, 0x8f, 0x89, 0xc8, 0xc8, + 0x33, 0x94, 0x63, 0xd0, 0x9c, 0xf5, 0xd0, 0x64, 0x59, 0x67, 0x97, 0x73, + 0xe9, 0x01, 0x97, 0x1b, 0x6e, 0xd1, 0x4b, 0xbc, 0xda, 0xd7, 0x87, 0xed, + 0x8b, 0x2c, 0xf2, 0xd3, 0xf3, 0xd4, 0x43, 0xce, 0xac, 0x47, 0x98, 0x03, + 0xd0, 0x6a, 0x99, 0x62, 0xb4, 0x52, 0xdd, 0xab, 0xe6, 0xae, 0xb8, 0xd6, + 0x47, 0x49, 0x6d, 0x80, 0x9f, 0x1a, 0x79, 0xb3, 0x86, 0x38, 0xd9, 0x54, + 0x0d, 0xd8, 0x9d, 0x69, 0x09, 0xf0, 0xe6, 0xf1, 0x74, 0x64, 0xbd, 0x71, + 0x75, 0xc5, 0x69, 0xa8, 0xe3, 0x52, 0x1d, 0x61, 0x1c, 0xe6, 0x35, 0x09, + 0x95, 0xce, 0xf8, 0xc1, 0xd8, 0x63, 0xae, 0xb3, 0x0b, 0xf0, 0x47, 0xbc, + 0x7c, 0x85, 0x28, 0x8d, 0xa9, 0xa9, 0xd8, 0x08, 0x80, 0x5f, 0x2f, 0xdf, + 0x5a, 0xa3, 0x92, 0x2f, 0xe8, 0x02, 0x8d, 0x1f, 0x62, 0x95, 0x22, 0xb7, + 0x4f, 0x0d, 0x37, 0x34, 0x71, 0x19, 0x0e, 0x41, 0x4e, 0x5f, 0x10, 0x03, + 0xe5, 0x38, 0xfb, 0x68, 0x27, 0x2b, 0x5f, 0x6b, 0x92, 0x02, 0xd9, 0x31, + 0x39, 0x6c, 0x7a, 0x64, 0x6c, 0x7f, 0xef, 0xd7, 0x5a, 0x65, 0xb6, 0x81, + 0x38, 0x9a, 0xd3, 0xf3, 0x30, 0x2c, 0x86, 0xb6, 0xdb, 0x96, 0xac, 0x61, + 0x1f, 0xf2, 0xcc, 0x1c, 0xbb, 0x60, 0x8c, 0xe0, 0xae, 0x0e, 0xd8, 0xdf, + 0x39, 0xed, 0xac, 0xf6, 0x4a, 0x58, 0xa8, 0xaf, 0x95, 0x34, 0xb2, 0x11, + 0x14, 0x55, 0x00, 0xf2, 0x73, 0x7a, 0xe7, 0xa7, 0xf7, 0xd3, 0x78, 0x9b, + 0xb4, 0x86, 0x45, 0x96, 0xbf, 0x83, 0x97, 0x2b, 0x6d, 0x65, 0xc1, 0x2d, + 0x97, 0xbb, 0x2d, 0x3d, 0xca, 0xaa, 0x1c, 0xad, 0x1b, 0xcb, 0x8f, 0x2a, + 0xf4, 0x2b, 0xfe, 0x7a, 0xb8, 0xfc, 0x45, 0xe1, 0x7b, 0x14, 0xfc, 0x49, + 0x4d, 0xc4, 0x36, 0xa8, 0xe2, 0x5f, 0x05, 0x0a, 0x49, 0x4f, 0x08, 0xc4, + 0x71, 0x48, 0x36, 0xc8, 0xf5, 0xef, 0xac, 0xd3, 0xe1, 0xbc, 0x17, 0x48, + 0x3e, 0x23, 0x5a, 0x45, 0xa5, 0x11, 0xaa, 0xfc, 0x7c, 0x44, 0x59, 0xb0, + 0xbd, 0x08, 0xc9, 0x3e, 0x98, 0xdf, 0x5e, 0x8d, 0xa0, 0xb1, 0xd2, 0xc5, + 0x05, 0x7c, 0x8f, 0xe0, 0xcb, 0xcf, 0x1c, 0xaf, 0x56, 0xd3, 0xb9, 0x52, + 0xd2, 0x16, 0x2c, 0x70, 0xbd, 0x87, 0x5d, 0x61, 0xd5, 0x62, 0x6a, 0x54, + 0x9f, 0x62, 0xe7, 0xc9, 0x91, 0x5f, 0xf8, 0x5b, 0x9f, 0xe1, 0xdd, 0x67, + 0x10, 0xc9, 0xce, 0xcd, 0x1d, 0x42, 0x45, 0x14, 0x7b, 0x80, 0xa3, 0xa1, + 0x63, 0xef, 0x9c, 0xe3, 0x1a, 0xca, 0xeb, 0xa5, 0x14, 0xf9, 0x96, 0x1d, + 0xa4, 0x3e, 0x54, 0x3e, 0x9e, 0xfa, 0xf4, 0xdf, 0xc4, 0x2b, 0xd5, 0x8e, + 0x4b, 0x6d, 0x07, 0x0f, 0xbd, 0x3d, 0x14, 0xb6, 0xf9, 0x62, 0xf1, 0x43, + 0x42, 0x85, 0x63, 0x84, 0x93, 0x85, 0xc0, 0x19, 0x24, 0xe1, 0xb5, 0xe7, + 0x2b, 0xe5, 0xa4, 0x43, 0x57, 0x5f, 0x2b, 0x11, 0x24, 0x14, 0x93, 0x18, + 0xd0, 0xaf, 0x4d, 0xf2, 0x41, 0x07, 0xec, 0x3a, 0x69, 0xda, 0x75, 0xb3, + 0xc4, 0x28, 0xb2, 0xb6, 0x6a, 0x6a, 0x14, 0xb1, 0x8a, 0x46, 0x0b, 0x19, + 0x04, 0x0c, 0xff, 0x00, 0x56, 0x7a, 0xeb, 0x40, 0x59, 0xa5, 0x7b, 0x24, + 0x95, 0x0f, 0xcc, 0xdc, 0xd4, 0x3e, 0x21, 0x23, 0x66, 0x2c, 0x48, 0xe6, + 0xfc, 0x6a, 0x91, 0x80, 0xf1, 0x24, 0x81, 0x64, 0xf0, 0xd9, 0x8b, 0x06, + 0x2b, 0x80, 0xd8, 0xeb, 0x8f, 0x5d, 0x5e, 0x29, 0xea, 0x05, 0x57, 0x0e, + 0xc9, 0x3b, 0x05, 0x52, 0x68, 0x9e, 0x9d, 0x49, 0x6e, 0xfc, 0xe1, 0x87, + 0xfd, 0xfb, 0x6b, 0xad, 0x86, 0x06, 0xfd, 0x23, 0x05, 0xb5, 0x54, 0xc9, + 0x43, 0x71, 0xb4, 0x37, 0xca, 0xfc, 0xc2, 0xc1, 0x40, 0xf3, 0x00, 0x4e, + 0xec, 0xae, 0x58, 0x30, 0x23, 0xed, 0xcc, 0x73, 0xed, 0xa5, 0xf4, 0x54, + 0xeb, 0x27, 0x0b, 0xd4, 0x5c, 0xd2, 0x4f, 0xf7, 0xea, 0x7a, 0xc0, 0x4a, + 0x2f, 0x55, 0x89, 0x80, 0x2b, 0xfd, 0xb4, 0x55, 0xb6, 0x79, 0x57, 0x88, + 0xe2, 0xb6, 0x1e, 0x46, 0x67, 0xa1, 0x8e, 0x9a, 0x07, 0xe7, 0xdd, 0x1f, + 0xc3, 0xe6, 0x0c, 0x3d, 0xb7, 0x6e, 0xfd, 0xf5, 0x37, 0x09, 0x23, 0x35, + 0xaa, 0xfd, 0x6d, 0x9a, 0x37, 0x87, 0x34, 0xc9, 0x32, 0xf3, 0x8d, 0xa5, + 0x74, 0x7c, 0x10, 0x0f, 0x7c, 0xe7, 0x44, 0xfb, 0x35, 0x3e, 0xc0, 0x6b, + 0x8f, 0x35, 0xc2, 0x2a, 0xb0, 0xfc, 0xc6, 0x67, 0xe7, 0x56, 0xfe, 0xfb, + 0x7e, 0x75, 0x63, 0xb9, 0x24, 0x4f, 0x05, 0x14, 0x53, 0x2e, 0x11, 0x23, + 0xf1, 0x15, 0xd8, 0xe4, 0x85, 0xc1, 0x1b, 0x0f, 0x4e, 0x9a, 0xaf, 0xcd, + 0x49, 0x32, 0x43, 0x4b, 0x05, 0x45, 0x30, 0xa7, 0x78, 0xdf, 0x9c, 0x96, + 0xf2, 0xb1, 0x0d, 0x92, 0x3f, 0x1a, 0x71, 0x73, 0x0c, 0x6d, 0x74, 0x41, + 0xb1, 0x20, 0x8d, 0x08, 0x2e, 0xa7, 0xb7, 0x61, 0xa1, 0x34, 0x44, 0x55, + 0x58, 0x11, 0x62, 0x80, 0x2a, 0x00, 0xbc, 0xb9, 0xc9, 0xf5, 0xf5, 0xc7, + 0xa6, 0xa2, 0xa7, 0x56, 0x69, 0x53, 0x1b, 0x76, 0x27, 0x53, 0x73, 0x24, + 0xb4, 0x6a, 0xaf, 0x1a, 0x18, 0x8a, 0xf2, 0x63, 0x97, 0x24, 0x10, 0x71, + 0x9d, 0x7e, 0x82, 0x1a, 0x98, 0x26, 0x6a, 0x49, 0x31, 0x21, 0xe4, 0x2c, + 0x92, 0x8f, 0xa5, 0xd4, 0x77, 0x1a, 0xa2, 0x88, 0x2e, 0x93, 0x3f, 0x8e, + 0xf1, 0xab, 0x73, 0x78, 0x60, 0x17, 0xdb, 0x76, 0x27, 0xb6, 0x96, 0xcd, + 0x11, 0x59, 0x7c, 0x39, 0x06, 0x46, 0x39, 0xc1, 0xf4, 0x3e, 0xda, 0x77, + 0x08, 0x58, 0xae, 0x2e, 0x93, 0xd3, 0x99, 0xa3, 0xc2, 0xbb, 0x0e, 0x6c, + 0x13, 0xb6, 0x7a, 0xe9, 0x05, 0xd8, 0xf3, 0x54, 0x89, 0xa3, 0xe6, 0x08, + 0xa4, 0x31, 0x07, 0xaf, 0x2e, 0x48, 0xc6, 0xa1, 0x66, 0x87, 0xf0, 0xb3, + 0xe1, 0xed, 0x57, 0x1d, 0x5c, 0x18, 0xd2, 0xd5, 0x2d, 0x34, 0x74, 0x50, + 0xc6, 0xd3, 0x4a, 0xc0, 0x9c, 0xf3, 0xb1, 0xd8, 0x7b, 0xe3, 0x27, 0xf1, + 0xad, 0x6b, 0xfd, 0xa3, 0x2c, 0x14, 0x16, 0x5f, 0x87, 0xb6, 0x4a, 0x7a, + 0x0a, 0x54, 0x8a, 0x2a, 0x49, 0x45, 0x3a, 0x30, 0xfa, 0xb0, 0x63, 0x27, + 0x7f, 0x5c, 0xf2, 0xe7, 0x56, 0x1f, 0xf6, 0x75, 0xb5, 0x7f, 0x0c, 0xe0, + 0x9a, 0x5a, 0xca, 0x6e, 0x59, 0x69, 0xeb, 0xe1, 0x13, 0xbb, 0xa9, 0xc9, + 0x2f, 0xb8, 0x0a, 0x7e, 0xc0, 0x63, 0xf3, 0xa5, 0x3c, 0x65, 0xc0, 0x3c, + 0x61, 0xc7, 0x7c, 0x41, 0x5b, 0x70, 0xbd, 0x56, 0x43, 0x41, 0x6c, 0x81, + 0x5d, 0x2d, 0xb4, 0x60, 0x97, 0x7c, 0xff, 0x00, 0x4b, 0x30, 0x1b, 0x2e, + 0x4f, 0x53, 0x92, 0x7d, 0xb4, 0xa8, 0xc7, 0x6c, 0x5c, 0xbd, 0xb3, 0x9b, + 0x38, 0x2e, 0x68, 0xc0, 0xf8, 0x4f, 0x83, 0xae, 0xdc, 0x61, 0x70, 0x6a, + 0x2b, 0x3d, 0x3a, 0x4b, 0x2a, 0xc6, 0xd2, 0x3b, 0x33, 0xf2, 0xaa, 0x28, + 0xc0, 0x3c, 0xc7, 0xb1, 0xc9, 0x18, 0xfb, 0xea, 0x1b, 0xcf, 0x0e, 0xdc, + 0x78, 0x7a, 0x7f, 0x91, 0xbb, 0xd1, 0xd4, 0x51, 0xd4, 0x15, 0x0c, 0x12, + 0x45, 0xc7, 0x32, 0xee, 0x32, 0x3d, 0xb6, 0x3a, 0xf6, 0x17, 0xc3, 0xde, + 0x18, 0xa4, 0xe1, 0x4e, 0x16, 0x86, 0xd3, 0x4d, 0x1a, 0x34, 0xe2, 0x3c, + 0xcd, 0x37, 0x42, 0xed, 0xd7, 0xf4, 0xdf, 0x03, 0x59, 0x17, 0xfb, 0x4c, + 0xd9, 0x2a, 0x9a, 0xef, 0x6f, 0xbe, 0x63, 0xfd, 0xdd, 0xe9, 0xc5, 0x3b, + 0x80, 0x33, 0xc8, 0xe0, 0x92, 0x37, 0xf7, 0xe6, 0xfd, 0xb4, 0x9c, 0xb0, + 0xdb, 0x14, 0xcc, 0xf9, 0x31, 0xd2, 0x30, 0x6a, 0x88, 0xfc, 0x4e, 0x58, + 0x23, 0xfa, 0x9b, 0x73, 0xf6, 0xd3, 0x1b, 0xfd, 0xc2, 0x08, 0xbe, 0x16, + 0x4b, 0x60, 0x68, 0xa4, 0x79, 0x0d, 0xcc, 0x56, 0x2b, 0x96, 0xd8, 0x2f, + 0x86, 0x50, 0x29, 0xf7, 0xd6, 0x91, 0xc1, 0xdc, 0x22, 0xf7, 0xdf, 0x87, + 0x15, 0xf1, 0x5b, 0xad, 0x1f, 0x3d, 0x75, 0xa9, 0xae, 0x44, 0x86, 0x53, + 0x85, 0x58, 0x15, 0x14, 0x64, 0xb3, 0x1e, 0x80, 0x86, 0xe8, 0x3e, 0xf8, + 0xdb, 0x55, 0xcb, 0x47, 0xc3, 0xeb, 0x97, 0x12, 0xde, 0xeb, 0x78, 0x66, + 0x26, 0x8a, 0x29, 0xe0, 0x49, 0x8c, 0x85, 0xf7, 0x55, 0xe4, 0x38, 0x03, + 0x3e, 0xe7, 0x03, 0x3e, 0xfa, 0x4e, 0x37, 0xe5, 0x60, 0x24, 0x62, 0xf6, + 0xfc, 0xcf, 0x72, 0x46, 0xe5, 0x3c, 0xb0, 0x9c, 0xf5, 0xfc, 0x69, 0xb5, + 0xa1, 0x26, 0x6e, 0x28, 0x49, 0x23, 0x38, 0xf0, 0xc6, 0x7f, 0x04, 0x63, + 0xfc, 0xc6, 0xa3, 0xae, 0xb3, 0xd4, 0xf0, 0xed, 0xda, 0xb6, 0xd1, 0x72, + 0xa7, 0x68, 0x6a, 0xe9, 0xe4, 0x2a, 0xc0, 0x8d, 0x9b, 0x7e, 0xa0, 0xfa, + 0x77, 0x1a, 0xd0, 0x7e, 0x18, 0xfc, 0x3e, 0xba, 0xf1, 0x05, 0xc1, 0x27, + 0x86, 0x9c, 0xac, 0x4e, 0x57, 0xce, 0x0e, 0x47, 0x2e, 0xdb, 0x93, 0xdb, + 0xd7, 0x1a, 0xd1, 0x9b, 0x22, 0x8c, 0x2d, 0x91, 0xa2, 0xdb, 0xf0, 0xe9, + 0x6a, 0x65, 0xa1, 0xe2, 0x69, 0x12, 0x37, 0x4a, 0xb7, 0xb7, 0x83, 0x1b, + 0x03, 0x96, 0x74, 0x0c, 0x32, 0xa0, 0x6d, 0xd8, 0x75, 0xd6, 0x7d, 0x4b, + 0xc3, 0x57, 0x66, 0xb5, 0xcd, 0x75, 0x4b, 0x75, 0x4c, 0x74, 0x71, 0xbf, + 0xfc, 0x5f, 0x05, 0x82, 0x05, 0xed, 0xb9, 0x1e, 0xfa, 0xd6, 0xef, 0xe6, + 0xdd, 0xc1, 0xd7, 0x81, 0x65, 0xb4, 0xb1, 0x92, 0xe2, 0x22, 0x06, 0x5a, + 0x85, 0xcf, 0x90, 0x64, 0x6d, 0xef, 0x9c, 0x74, 0xd7, 0x1c, 0x4f, 0x54, + 0x78, 0xae, 0xd8, 0x54, 0x54, 0x57, 0xc3, 0x3d, 0x1c, 0x3f, 0xfe, 0x3a, + 0x4b, 0xfc, 0x83, 0x1a, 0x8f, 0xf0, 0x6c, 0x33, 0x9c, 0x6f, 0xae, 0x3e, + 0x3d, 0x46, 0xce, 0x7a, 0xb6, 0x2a, 0x8c, 0x9e, 0xa5, 0xa7, 0xf0, 0xa9, + 0xe2, 0x2f, 0xb5, 0x3e, 0x54, 0x0c, 0x0c, 0x82, 0x4e, 0xfb, 0xeb, 0xd2, + 0x56, 0xbb, 0x85, 0xf3, 0xff, 0x00, 0x4f, 0x58, 0x55, 0xea, 0x26, 0x8e, + 0x96, 0x6a, 0x28, 0x52, 0x61, 0x1a, 0x8f, 0x11, 0xb2, 0xa3, 0x05, 0x7e, + 0xfa, 0xf3, 0x7a, 0xe6, 0x40, 0x91, 0x92, 0x10, 0xf8, 0xb9, 0x3e, 0xc3, + 0x04, 0x1d, 0x7a, 0x37, 0xe1, 0xe7, 0x11, 0x40, 0x96, 0x98, 0xa2, 0xa6, + 0x11, 0x2b, 0x2c, 0x31, 0xaa, 0x34, 0xa7, 0x03, 0xc3, 0x5d, 0xca, 0xfd, + 0xfb, 0xea, 0x6b, 0x1c, 0x54, 0xa2, 0x9b, 0xa2, 0xf1, 0xe4, 0x49, 0xf2, + 0x5a, 0x2a, 0xe9, 0x2a, 0xad, 0xf4, 0x4e, 0x63, 0x9a, 0x69, 0xa4, 0x46, + 0xfe, 0x4b, 0x4a, 0xd9, 0x0a, 0x3f, 0xab, 0x9b, 0x03, 0x73, 0xdf, 0x18, + 0xce, 0x47, 0x5d, 0x79, 0xeb, 0x8e, 0xef, 0xd5, 0xfc, 0x59, 0xc5, 0x4e, + 0x22, 0xa7, 0x65, 0x8a, 0x91, 0x1a, 0x00, 0xef, 0x19, 0x8d, 0xf6, 0x62, + 0x72, 0xc0, 0xf4, 0x27, 0xd3, 0xb6, 0xb6, 0x4e, 0x3c, 0xa2, 0xbe, 0x7f, + 0xe9, 0xa8, 0xae, 0xb4, 0x33, 0x3f, 0x38, 0x98, 0x4c, 0xbe, 0x0e, 0x23, + 0xe4, 0x42, 0x7a, 0xb2, 0x0c, 0xf3, 0x11, 0x91, 0xdf, 0x4c, 0x78, 0x22, + 0xc1, 0x41, 0x15, 0x6d, 0x35, 0x6c, 0xa2, 0x3a, 0xeb, 0x93, 0xc2, 0x64, + 0x9a, 0xa7, 0x1e, 0x45, 0x7c, 0x82, 0x0e, 0x0e, 0xe4, 0xef, 0xb1, 0xf4, + 0x1a, 0x76, 0x15, 0x2c, 0x72, 0xb6, 0xbb, 0x34, 0xed, 0xba, 0x47, 0xff, + 0xd9 +}; + +void jpeg_get_video_info(VideoDecodeInfo *info) +{ + info->profile = GST_VAAPI_PROFILE_JPEG_BASELINE; + info->width = JPEG_CLIP_WIDTH; + info->height = JPEG_CLIP_HEIGHT; + info->data = jpeg_clip; + info->data_size = JPEG_CLIP_DATA_SIZE; +} diff --git a/tests/test-jpeg.h b/tests/test-jpeg.h new file mode 100644 index 0000000..8fdbcfe --- /dev/null +++ b/tests/test-jpeg.h @@ -0,0 +1,30 @@ +/* + * test-jpeg.h - JPEG test data + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#ifndef TEST_JPEG_H +#define TEST_JPEG_H + +#include +#include "test-decode.h" + +void jpeg_get_video_info(VideoDecodeInfo *info); + +#endif /* TEST_JPEG_H */ diff --git a/tests/test-mpeg2.c b/tests/test-mpeg2.c new file mode 100644 index 0000000..3e75143 --- /dev/null +++ b/tests/test-mpeg2.c @@ -0,0 +1,1649 @@ +/* + * test-mpeg2.c - MPEG-2 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#include "test-mpeg2.h" + +#define MPEG2_CLIP_WIDTH 320 +#define MPEG2_CLIP_HEIGHT 240 +#define MPEG2_CLIP_DATA_SIZE 19311 + +/* Data dump of a 320x240 MPEG-2 video clip (mpeg2.m2v), it has a single frame */ +static const guchar mpeg2_clip[MPEG2_CLIP_DATA_SIZE] = { + 0x00, 0x00, 0x01, 0xb3, 0x14, 0x00, 0xf0, 0x12, 0x07, 0x53, 0x23, 0x80, + 0x00, 0x00, 0x01, 0xb5, 0x14, 0x8a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xb5, 0x2b, 0x02, 0x02, 0x02, 0x05, 0x02, 0x07, 0x80, 0x00, 0x00, + 0x01, 0xb8, 0x00, 0x08, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, + 0xff, 0xf8, 0x00, 0x00, 0x01, 0xb5, 0x8f, 0xff, 0xf7, 0x5d, 0x80, 0x00, + 0x00, 0x01, 0x01, 0x43, 0xf8, 0x90, 0x03, 0xee, 0x36, 0xd4, 0x92, 0x85, + 0x86, 0x37, 0x48, 0x01, 0xb3, 0xf7, 0x9a, 0x1d, 0x5c, 0x38, 0xb1, 0x95, + 0xb9, 0x42, 0x43, 0xb2, 0xc2, 0x51, 0x24, 0x31, 0xb2, 0xed, 0x20, 0x73, + 0xd9, 0x08, 0xcc, 0x5b, 0xe2, 0x39, 0xbc, 0xdb, 0x12, 0xb7, 0x8c, 0x31, + 0xbf, 0x6c, 0x00, 0xc3, 0xeb, 0xc3, 0xd0, 0x6c, 0x3e, 0x16, 0xde, 0xa8, + 0x89, 0xf3, 0xc1, 0x17, 0xda, 0x5a, 0x4f, 0xca, 0xb0, 0x6b, 0x7c, 0x07, + 0xbb, 0x6c, 0x95, 0x8f, 0x74, 0x35, 0xaa, 0x45, 0x65, 0xb4, 0x35, 0xbf, + 0xd4, 0x22, 0xab, 0xfe, 0x80, 0x07, 0x7c, 0xed, 0x7a, 0x97, 0x2b, 0xaf, + 0x2f, 0x72, 0x64, 0x81, 0x86, 0x0f, 0x6f, 0x9a, 0x7b, 0x02, 0x10, 0x07, + 0x76, 0x2f, 0x01, 0x30, 0x01, 0x2d, 0x21, 0x37, 0x89, 0xbc, 0x74, 0x00, + 0xf4, 0xc3, 0x6b, 0xa4, 0x1f, 0x65, 0xa7, 0xb6, 0xff, 0x6d, 0x9f, 0x6f, + 0x6f, 0x77, 0xa8, 0x5b, 0xa7, 0x95, 0x90, 0x2e, 0x2b, 0x71, 0xec, 0x35, + 0xf4, 0x96, 0x92, 0x33, 0xa9, 0x92, 0x48, 0xdf, 0xcf, 0x50, 0x39, 0x13, + 0xd1, 0xbd, 0x25, 0x4f, 0xbe, 0x5b, 0x10, 0x25, 0x6e, 0x14, 0xdc, 0x5e, + 0xe0, 0x7b, 0x7a, 0x3d, 0x04, 0x2f, 0xf2, 0xb8, 0x84, 0x38, 0xdd, 0x16, + 0x94, 0xdb, 0x46, 0xfd, 0xdf, 0x3a, 0x00, 0x7a, 0xf9, 0x49, 0x45, 0xb7, + 0x52, 0xe9, 0x03, 0x9a, 0x4a, 0x40, 0xf8, 0x14, 0xdc, 0xa7, 0x4d, 0xf7, + 0xbc, 0x25, 0x04, 0xa0, 0x04, 0x2a, 0x81, 0x6d, 0xda, 0x36, 0x67, 0x1b, + 0xb8, 0x48, 0x96, 0xb7, 0x49, 0xea, 0xd9, 0x1c, 0x8d, 0xf8, 0xfb, 0x80, + 0x07, 0x50, 0x9c, 0x13, 0x43, 0xae, 0x94, 0x07, 0x36, 0xff, 0x8b, 0x00, + 0x1c, 0x8a, 0x35, 0x00, 0x20, 0x49, 0x40, 0xdb, 0x74, 0x05, 0x82, 0x10, + 0x03, 0xcd, 0x28, 0x29, 0x06, 0x56, 0xf1, 0x2f, 0xc0, 0x03, 0xd1, 0x22, + 0x26, 0xd0, 0x08, 0x0a, 0x03, 0x4d, 0x27, 0x37, 0x5d, 0x2f, 0x36, 0xb7, + 0xe9, 0xef, 0x7a, 0x00, 0xd0, 0x83, 0xe5, 0x14, 0x65, 0x8a, 0x62, 0xd9, + 0xe2, 0x31, 0xb8, 0x3e, 0xef, 0x15, 0xbd, 0xdc, 0xb8, 0xf4, 0xa3, 0x4a, + 0xb9, 0x36, 0x1c, 0xde, 0xe7, 0x41, 0x08, 0x01, 0xb8, 0x79, 0xe0, 0x11, + 0x4a, 0xbe, 0x07, 0xca, 0xdf, 0x2d, 0xea, 0x5d, 0x11, 0x99, 0xb0, 0x2c, + 0x3a, 0x6e, 0x41, 0xaa, 0x5b, 0x23, 0xf2, 0xb5, 0x5a, 0x41, 0xcd, 0xd8, + 0x42, 0xad, 0xf7, 0x78, 0xc8, 0x2d, 0xdc, 0x51, 0x70, 0x72, 0xcc, 0xd8, + 0xb4, 0x75, 0x85, 0x43, 0x94, 0x25, 0xbd, 0x5e, 0xf9, 0x3c, 0x49, 0xbc, + 0xe5, 0xa3, 0x2b, 0xb8, 0x49, 0x0a, 0x26, 0xd2, 0xa7, 0xea, 0x8d, 0xfd, + 0xb1, 0xf7, 0xdd, 0x22, 0x8b, 0xef, 0xce, 0x5a, 0x51, 0x66, 0x64, 0x33, + 0x8a, 0x85, 0x53, 0xc0, 0x7b, 0x51, 0x22, 0x34, 0xe8, 0xd7, 0xd0, 0x09, + 0x8f, 0x5a, 0x53, 0xb8, 0x54, 0x1b, 0x4b, 0x2c, 0xbb, 0xaa, 0x18, 0xd5, + 0x69, 0x6d, 0xd2, 0xfa, 0xba, 0x5b, 0x7c, 0x67, 0xc9, 0x37, 0x51, 0x02, + 0x37, 0x8a, 0x6a, 0xec, 0x2b, 0x03, 0x94, 0xe4, 0x1e, 0xad, 0xce, 0x96, + 0x95, 0x84, 0x34, 0x5a, 0x38, 0x63, 0x58, 0x90, 0x44, 0x0e, 0xa1, 0x35, + 0xf4, 0xa0, 0xf3, 0xe1, 0x55, 0x0a, 0x46, 0x12, 0x5b, 0x93, 0x2c, 0x0c, + 0x95, 0x51, 0x62, 0x94, 0x34, 0x34, 0x2d, 0xaa, 0x36, 0x8d, 0xf3, 0xbb, + 0x0e, 0xe3, 0x37, 0x54, 0x02, 0x32, 0x83, 0x29, 0xd0, 0xea, 0xce, 0x7e, + 0x95, 0x3c, 0x26, 0x9a, 0xd0, 0xcb, 0x9c, 0xba, 0xa8, 0x49, 0x8e, 0x2d, + 0x68, 0x4d, 0x65, 0xa9, 0xaa, 0x05, 0xb2, 0x8c, 0x37, 0xe9, 0x5e, 0xfc, + 0x00, 0x7a, 0xe7, 0x4e, 0x1e, 0xa3, 0xe5, 0x9b, 0xb9, 0x42, 0x52, 0xc3, + 0xe3, 0x3f, 0x3f, 0x39, 0x86, 0x59, 0xb8, 0x80, 0x2a, 0xa9, 0x65, 0x3d, + 0xa9, 0xd4, 0xfb, 0xf4, 0xf9, 0x65, 0x1e, 0xa9, 0x62, 0x6c, 0x18, 0x30, + 0xf8, 0xdb, 0x5f, 0xb7, 0x8e, 0xde, 0xe7, 0x1b, 0xe2, 0x84, 0xc0, 0x86, + 0xe3, 0x71, 0x37, 0x0a, 0x0b, 0x29, 0xbc, 0xe4, 0x33, 0x31, 0xbd, 0x1c, + 0xf3, 0x40, 0x1e, 0xee, 0x3b, 0x4c, 0x5f, 0xd0, 0x21, 0x00, 0x36, 0x96, + 0x3c, 0x7b, 0x76, 0xbd, 0xe9, 0xb5, 0xfd, 0x74, 0x81, 0xb6, 0xba, 0xdc, + 0x25, 0x14, 0xde, 0x6f, 0xda, 0x80, 0x1f, 0xa4, 0xf3, 0x08, 0x0b, 0x38, + 0x68, 0x6b, 0x75, 0x48, 0xdc, 0x52, 0x27, 0x1e, 0xf6, 0xa8, 0x0a, 0xaf, + 0x91, 0xb9, 0x68, 0x48, 0x67, 0x8b, 0x70, 0xf7, 0xc7, 0x96, 0x3a, 0x5f, + 0x59, 0x22, 0x59, 0xe2, 0xdc, 0xd7, 0x0c, 0xb9, 0x40, 0x07, 0xad, 0xf0, + 0x7e, 0x82, 0x74, 0x8c, 0x01, 0x6a, 0xe9, 0x63, 0x75, 0xcf, 0x59, 0x43, + 0xa1, 0x92, 0x04, 0x37, 0x86, 0xe2, 0xa5, 0x74, 0x50, 0x90, 0x1c, 0x43, + 0x3c, 0x6d, 0xf0, 0x18, 0xdb, 0xf6, 0xce, 0x24, 0x28, 0x29, 0xb9, 0xb4, + 0xac, 0xc0, 0x29, 0xbd, 0x2d, 0xab, 0xb6, 0xa3, 0x6a, 0xdf, 0xa6, 0x8e, + 0x73, 0xc5, 0xbb, 0x99, 0x90, 0x04, 0x66, 0x17, 0xea, 0xa7, 0xb7, 0xa5, + 0xe4, 0xa7, 0x6e, 0x69, 0x41, 0xbf, 0x9a, 0x60, 0xf3, 0xe0, 0xc6, 0x41, + 0x74, 0x02, 0xbe, 0x38, 0x7e, 0x50, 0x4a, 0xff, 0xd9, 0x2d, 0x0d, 0x29, + 0x7c, 0x1b, 0xaa, 0x27, 0x5c, 0x00, 0xdb, 0xfa, 0x20, 0x5b, 0xe2, 0x52, + 0xe5, 0x8f, 0x11, 0xa6, 0xd8, 0x58, 0x6a, 0x52, 0x15, 0x6d, 0x0b, 0xb5, + 0x40, 0xb6, 0x4d, 0xf0, 0x35, 0xb3, 0x76, 0xfa, 0xfe, 0x4b, 0xd0, 0x08, + 0x31, 0xb4, 0x40, 0x1a, 0xab, 0x62, 0x80, 0x84, 0x01, 0x35, 0xe0, 0x9b, + 0xff, 0xb2, 0x12, 0x19, 0x53, 0x94, 0x96, 0xd2, 0xdd, 0xbb, 0x0a, 0x66, + 0xd0, 0x1a, 0x36, 0x21, 0x40, 0x85, 0xff, 0x1b, 0x8f, 0x9e, 0xa6, 0x2a, + 0xb7, 0x75, 0xe3, 0x09, 0x0d, 0xb4, 0x18, 0xd4, 0xdd, 0xaf, 0x0e, 0x70, + 0xba, 0x4a, 0x56, 0xe5, 0x11, 0x4f, 0x95, 0x28, 0x0a, 0xa8, 0xc6, 0xf4, + 0x77, 0xf3, 0x79, 0x52, 0x4b, 0x4a, 0x5a, 0xb7, 0x3e, 0x7e, 0x6d, 0x24, + 0x23, 0x44, 0x2d, 0x5b, 0xc2, 0x2d, 0x76, 0x6d, 0xa4, 0x3a, 0xdd, 0x61, + 0x30, 0x00, 0xfe, 0x61, 0x26, 0x46, 0xfa, 0x10, 0x03, 0xf2, 0x2e, 0x00, + 0x16, 0xfd, 0xb1, 0xfe, 0xdb, 0x32, 0x95, 0xa5, 0x08, 0xaf, 0x9c, 0xc1, + 0xc5, 0x28, 0x6b, 0x7a, 0x80, 0x02, 0xd1, 0x16, 0xfb, 0xbc, 0x56, 0xe0, + 0x5e, 0x8f, 0x75, 0x0d, 0x81, 0xac, 0x13, 0x21, 0xa4, 0x8a, 0x48, 0x63, + 0x62, 0x42, 0xe3, 0x7e, 0xc1, 0xe0, 0x0f, 0xf9, 0x00, 0x72, 0x28, 0x4d, + 0x14, 0xfb, 0x92, 0x1d, 0x8e, 0xb6, 0xa6, 0x58, 0x5d, 0xf4, 0xac, 0x7e, + 0x40, 0x15, 0x80, 0x19, 0x7b, 0x3d, 0xf3, 0x65, 0xc2, 0xa7, 0x2e, 0xc3, + 0xee, 0xc5, 0x28, 0xe6, 0x4f, 0xf8, 0xbf, 0x6f, 0x97, 0x0b, 0xe3, 0xae, + 0xf5, 0x4a, 0x2f, 0x69, 0x61, 0x63, 0x5b, 0xb6, 0x46, 0x00, 0x63, 0x74, + 0x4a, 0xdc, 0xd7, 0xe5, 0x4c, 0x42, 0xdb, 0x1d, 0xe3, 0x7b, 0xa4, 0xd7, + 0x8d, 0x28, 0x32, 0x35, 0x99, 0x75, 0x4b, 0x78, 0x64, 0x0c, 0x8d, 0xfc, + 0xa0, 0x00, 0x9c, 0x59, 0x10, 0x89, 0x79, 0x77, 0xc8, 0xa7, 0x95, 0x0d, + 0xc7, 0x96, 0x51, 0x87, 0xc5, 0xad, 0x84, 0x01, 0x1b, 0xaf, 0xdc, 0x40, + 0xa1, 0x79, 0xce, 0x52, 0xe5, 0x93, 0x1e, 0x56, 0x55, 0x01, 0xec, 0xf5, + 0x6f, 0xd0, 0xa4, 0x6f, 0xe8, 0x01, 0xef, 0xc4, 0xde, 0x49, 0xef, 0x5b, + 0x36, 0x6c, 0x3a, 0xa5, 0x2e, 0x56, 0xee, 0xdd, 0x98, 0x62, 0x5a, 0x15, + 0xb4, 0xb4, 0x6e, 0xfd, 0x44, 0x21, 0x96, 0x31, 0xba, 0x1f, 0x62, 0x20, + 0x0f, 0x98, 0x00, 0x00, 0x01, 0x02, 0x43, 0xf8, 0x37, 0x13, 0x05, 0xdd, + 0xbe, 0xa9, 0x4b, 0x6c, 0xa2, 0xbc, 0xc5, 0x6e, 0x6c, 0x21, 0x12, 0x23, + 0x77, 0x3e, 0x68, 0x05, 0xa2, 0xdf, 0x8e, 0xcf, 0x02, 0xe1, 0x60, 0x73, + 0x79, 0x09, 0x08, 0x0e, 0x74, 0x25, 0x49, 0x1b, 0xcc, 0x42, 0xca, 0x21, + 0xb7, 0x90, 0xdf, 0x40, 0x10, 0xff, 0xe7, 0x1d, 0x2e, 0x92, 0x59, 0x94, + 0x80, 0x94, 0xbf, 0x16, 0xe7, 0xdc, 0x34, 0xb6, 0xd7, 0xb0, 0xd9, 0x2d, + 0x50, 0x81, 0xc5, 0x35, 0x0f, 0x6a, 0x6f, 0xd4, 0xea, 0xfd, 0x5e, 0xa0, + 0x03, 0x0a, 0xad, 0xc9, 0xee, 0x5f, 0x8e, 0x78, 0xb2, 0xc0, 0xc0, 0xe2, + 0xbd, 0x4a, 0x46, 0xd5, 0xed, 0x27, 0x2e, 0xe1, 0xea, 0x13, 0x76, 0xd1, + 0xc1, 0x65, 0x90, 0x99, 0xb6, 0x00, 0x1a, 0x24, 0x9e, 0x12, 0x87, 0xc8, + 0x14, 0x96, 0x10, 0xda, 0x60, 0x74, 0xd0, 0x2d, 0x85, 0x30, 0xaa, 0xdf, + 0x15, 0xff, 0x9c, 0x02, 0xaa, 0x36, 0xdb, 0x2d, 0xdb, 0x9b, 0xa0, 0x10, + 0xc4, 0x94, 0x87, 0x1b, 0x3e, 0x02, 0x17, 0xfc, 0x6b, 0x88, 0x70, 0xf4, + 0x21, 0x37, 0x7c, 0x5c, 0x9c, 0xba, 0xda, 0xac, 0x13, 0x59, 0x1f, 0x1b, + 0xca, 0x2b, 0x30, 0x5e, 0xe3, 0xa2, 0x78, 0xd0, 0xe2, 0x43, 0x7b, 0x87, + 0x53, 0x70, 0xbc, 0xa1, 0xb0, 0xf8, 0x12, 0xde, 0x44, 0x01, 0xf8, 0xaa, + 0x94, 0xf9, 0x43, 0x71, 0x51, 0xb4, 0x3f, 0x20, 0x9e, 0x6c, 0x49, 0x03, + 0x75, 0x76, 0x86, 0x42, 0x96, 0x95, 0x2b, 0x5a, 0x07, 0xb6, 0xfc, 0x97, + 0x8d, 0xfa, 0x7f, 0xa3, 0xcd, 0x91, 0xe6, 0x78, 0xc2, 0xc2, 0x5b, 0x77, + 0x7b, 0x48, 0xf6, 0x3d, 0x03, 0x21, 0xbd, 0x62, 0x58, 0x16, 0xb1, 0xbc, + 0xdc, 0xe7, 0xce, 0x77, 0x2b, 0xf4, 0x05, 0x7d, 0x29, 0x30, 0x69, 0xf2, + 0x37, 0x55, 0xd8, 0x00, 0x73, 0x3b, 0x89, 0x02, 0xad, 0x2c, 0x84, 0x3d, + 0xb0, 0x43, 0x25, 0x6c, 0x2c, 0x4a, 0xab, 0xe8, 0xde, 0x7d, 0xe3, 0x40, + 0x1d, 0x3f, 0xb7, 0x89, 0x90, 0x35, 0x1d, 0x76, 0xa8, 0xd2, 0x6c, 0x2d, + 0x28, 0x5b, 0x78, 0xb7, 0xf3, 0x7e, 0x57, 0xcc, 0x22, 0x49, 0xdd, 0x2a, + 0xa0, 0xd2, 0x83, 0x29, 0x6d, 0xf6, 0x3d, 0xbe, 0x73, 0x1c, 0x80, 0x10, + 0x45, 0x25, 0xa9, 0x5e, 0xad, 0xe0, 0xc5, 0xf2, 0x00, 0x70, 0x27, 0x84, + 0xd8, 0xa7, 0xee, 0xee, 0x59, 0x9b, 0x83, 0x40, 0x79, 0x22, 0xb5, 0x38, + 0x0c, 0xc5, 0x6e, 0x8c, 0xa0, 0x16, 0x87, 0x90, 0xa3, 0x6f, 0xed, 0x2f, + 0x0f, 0xf3, 0x59, 0x20, 0x13, 0x0f, 0x2d, 0x4e, 0x0a, 0x30, 0x39, 0x84, + 0xd3, 0x69, 0x8b, 0x92, 0x04, 0x17, 0x8e, 0x81, 0x1b, 0x15, 0x6e, 0x8e, + 0x29, 0xb8, 0x9c, 0x39, 0x53, 0x12, 0x5a, 0x51, 0x65, 0x42, 0xa4, 0x2b, + 0xd2, 0x9c, 0xdb, 0x38, 0x9e, 0x7a, 0x8b, 0x42, 0x4b, 0x2c, 0x30, 0xe4, + 0x6e, 0x88, 0x53, 0x7a, 0x27, 0xc6, 0xf0, 0xe8, 0x21, 0x00, 0x45, 0x28, + 0x92, 0xb5, 0x46, 0x1e, 0x7b, 0x64, 0x32, 0x6c, 0x9e, 0x31, 0x15, 0x15, + 0xb7, 0xe1, 0x68, 0x52, 0x80, 0x8a, 0xd1, 0xcd, 0xa2, 0x6d, 0xe6, 0x3f, + 0x65, 0xaa, 0x33, 0x0a, 0xc9, 0x12, 0x05, 0xa8, 0xd0, 0x86, 0x6c, 0x37, + 0xc6, 0xd8, 0x85, 0x94, 0x07, 0x36, 0x7e, 0xad, 0xeb, 0x92, 0x45, 0x2d, + 0xb6, 0x69, 0x99, 0xb8, 0x50, 0x16, 0xdc, 0x30, 0x43, 0x00, 0x77, 0x3a, + 0x80, 0x0c, 0x59, 0x1c, 0xd9, 0xcf, 0xc6, 0xd6, 0xf4, 0x11, 0xb0, 0x00, + 0xf4, 0x5e, 0x15, 0xe2, 0x91, 0x07, 0xb7, 0xad, 0xc9, 0x99, 0xed, 0x53, + 0x03, 0x22, 0xea, 0xcb, 0x40, 0x44, 0x3c, 0x73, 0x78, 0x31, 0x91, 0xbd, + 0x75, 0x04, 0x2f, 0xf7, 0xde, 0xc9, 0x20, 0x73, 0x61, 0x69, 0xcd, 0x82, + 0x90, 0x7c, 0x90, 0x86, 0xdd, 0x32, 0x25, 0x75, 0xd9, 0x03, 0x10, 0xec, + 0xb7, 0xc0, 0x73, 0x74, 0x76, 0x65, 0xce, 0x6c, 0xd0, 0x83, 0x65, 0x90, + 0x34, 0x7b, 0x70, 0xdc, 0x1d, 0xe6, 0x70, 0x46, 0x4c, 0xe0, 0xaf, 0x1a, + 0xdd, 0xcd, 0x04, 0x20, 0x08, 0xda, 0x62, 0x04, 0xaa, 0xcf, 0x45, 0x52, + 0x4b, 0x68, 0x37, 0x21, 0x21, 0xb6, 0xda, 0x01, 0x52, 0xe1, 0x0a, 0x96, + 0xdf, 0x21, 0x7c, 0x8f, 0xf5, 0x8d, 0x6f, 0x60, 0x85, 0xfe, 0x0e, 0x11, + 0x08, 0x66, 0xd2, 0x11, 0x4b, 0x58, 0x6c, 0xa9, 0x55, 0xbd, 0x08, 0xb9, + 0x48, 0xbd, 0xd3, 0x82, 0x90, 0xc8, 0x07, 0xb6, 0x81, 0xad, 0xe7, 0x37, + 0xd0, 0xa5, 0x18, 0x07, 0x36, 0x5e, 0x4a, 0x76, 0x72, 0x42, 0xbe, 0x44, + 0xb6, 0xd6, 0x8a, 0x8c, 0xbc, 0xda, 0xf7, 0x3a, 0xe6, 0x50, 0xbc, 0xa9, + 0xe8, 0x74, 0xa4, 0xb6, 0x89, 0xf8, 0xad, 0x03, 0x5b, 0xa3, 0x98, 0x96, + 0x69, 0x25, 0x5a, 0xc2, 0x3a, 0x8a, 0xc3, 0x70, 0xa1, 0xf1, 0x1e, 0x9b, + 0x21, 0xc1, 0x95, 0xae, 0xae, 0x27, 0x79, 0x4b, 0x09, 0x11, 0xba, 0xe4, + 0x6c, 0x00, 0xb3, 0xaf, 0x32, 0x6d, 0x1c, 0x41, 0xf3, 0x96, 0x58, 0x01, + 0xfb, 0x73, 0x3a, 0xc4, 0x90, 0x96, 0x48, 0x60, 0xf9, 0x63, 0x7e, 0x28, + 0x8b, 0x28, 0x9e, 0xa6, 0x1b, 0x03, 0x15, 0x64, 0x41, 0xad, 0xec, 0xbe, + 0x5d, 0xaf, 0x15, 0x9a, 0xfc, 0x81, 0xb7, 0x0e, 0xa9, 0xea, 0xd9, 0xba, + 0xcb, 0x61, 0xa5, 0xd0, 0xc5, 0x1c, 0xde, 0x87, 0xcf, 0x8f, 0xed, 0x11, + 0x98, 0x2f, 0x29, 0x69, 0x70, 0x02, 0xb7, 0xe4, 0x85, 0xcf, 0x05, 0xa3, + 0x1a, 0xf2, 0x17, 0x11, 0x93, 0x7d, 0xb0, 0x06, 0x7b, 0x99, 0xa4, 0x7e, + 0xa9, 0x03, 0x99, 0x2a, 0x79, 0xc7, 0x3f, 0x52, 0xde, 0x29, 0x94, 0xa5, + 0x8a, 0x4b, 0x8d, 0xe3, 0xdf, 0xf9, 0x6f, 0xba, 0x80, 0x3d, 0x15, 0xfe, + 0x00, 0x7d, 0x9e, 0xfc, 0x7b, 0x91, 0x93, 0x62, 0xe9, 0x3f, 0x9c, 0xcf, + 0x27, 0x07, 0xdb, 0x46, 0x16, 0x5a, 0xc6, 0xe2, 0x8b, 0xfb, 0xe8, 0x02, + 0x37, 0x88, 0x77, 0xc4, 0x1c, 0x95, 0x64, 0xaf, 0xde, 0x6c, 0xf2, 0x85, + 0x41, 0xc5, 0xb2, 0xb6, 0x57, 0xcb, 0x28, 0xf4, 0x89, 0x19, 0xd1, 0x96, + 0x50, 0xa6, 0xfc, 0xf7, 0xfc, 0x53, 0xfd, 0xc8, 0xf9, 0x9c, 0x3e, 0x06, + 0x27, 0x39, 0x78, 0xd4, 0x01, 0x5c, 0xa8, 0xa7, 0x0e, 0x6f, 0xd4, 0x42, + 0x01, 0x0b, 0xfc, 0xfe, 0x04, 0xb8, 0x84, 0xf9, 0x6c, 0xf0, 0x2c, 0xa6, + 0xc9, 0xfd, 0xdb, 0xfe, 0xfa, 0x72, 0xb6, 0x84, 0x38, 0xd4, 0x7f, 0xa8, + 0xea, 0xda, 0x44, 0xe0, 0x01, 0x9f, 0xb8, 0xbd, 0x72, 0x86, 0x99, 0x52, + 0x42, 0x14, 0x6e, 0xbd, 0x86, 0xee, 0x12, 0xe4, 0x6e, 0xbd, 0x86, 0xee, + 0x12, 0xe4, 0x6e, 0x90, 0x07, 0xbe, 0xfd, 0xf3, 0xcc, 0x86, 0x3e, 0xd4, + 0x92, 0x01, 0x87, 0x64, 0x5f, 0x16, 0xe9, 0x09, 0xef, 0x9d, 0x7d, 0xb6, + 0xbf, 0x68, 0xd5, 0x6d, 0x6d, 0xe0, 0x80, 0x14, 0x68, 0x20, 0x80, 0xaf, + 0xde, 0x73, 0xce, 0x50, 0xc9, 0xc4, 0x3b, 0x68, 0xcf, 0x46, 0xdd, 0x4b, + 0x3d, 0xb5, 0x54, 0xdb, 0x1b, 0xe7, 0x00, 0x3d, 0xfa, 0x40, 0x07, 0x8f, + 0xc7, 0x11, 0xf1, 0x5e, 0x55, 0x5a, 0xe7, 0x47, 0x47, 0xe4, 0x9e, 0x6a, + 0x88, 0x10, 0xdf, 0x17, 0x11, 0xf1, 0x84, 0x6b, 0xd0, 0x05, 0x84, 0xe9, + 0x3f, 0x44, 0xe9, 0x62, 0x5c, 0x1a, 0xdf, 0x4e, 0x00, 0x78, 0x00, 0xbb, + 0xb1, 0x3d, 0x63, 0x9f, 0xc6, 0x3e, 0x9a, 0xb2, 0xed, 0x19, 0xb1, 0xb1, + 0x00, 0x39, 0x00, 0x71, 0xf2, 0x00, 0xe0, 0x01, 0x97, 0x4e, 0xce, 0xf9, + 0xcd, 0xc8, 0x31, 0xf6, 0xea, 0x24, 0x31, 0xa0, 0xe8, 0xdc, 0xd4, 0xac, + 0x2e, 0xc6, 0x00, 0x00, 0x01, 0x03, 0x43, 0xf9, 0x6d, 0x84, 0xef, 0x3a, + 0x09, 0x80, 0x07, 0x34, 0x90, 0xde, 0x07, 0x7f, 0x39, 0x63, 0x7b, 0xb7, + 0x1b, 0xc6, 0xf3, 0x32, 0xc0, 0x8d, 0xe0, 0xbb, 0x14, 0x2a, 0x56, 0xf2, + 0x02, 0xdc, 0x4f, 0xe5, 0xf3, 0x3c, 0x7c, 0xdc, 0x5a, 0x1c, 0x7a, 0x37, + 0x04, 0xa6, 0x48, 0xad, 0xe3, 0xa1, 0x6d, 0xd7, 0x6d, 0x55, 0x38, 0x32, + 0x35, 0x87, 0xed, 0x02, 0x9b, 0x47, 0x21, 0xeb, 0x93, 0xd6, 0x56, 0xae, + 0x97, 0x24, 0x9b, 0xe2, 0x35, 0xb3, 0x83, 0x99, 0x46, 0xdd, 0xf0, 0x00, + 0xec, 0x80, 0x58, 0x51, 0xb0, 0x0a, 0x56, 0x5f, 0x6b, 0x05, 0x70, 0x2b, + 0x22, 0x00, 0x8f, 0x82, 0xc9, 0x76, 0xd2, 0x5b, 0x50, 0xe8, 0x64, 0x8b, + 0x42, 0x5b, 0x15, 0x0e, 0xad, 0x9c, 0x39, 0xae, 0x0d, 0x6d, 0xf1, 0x73, + 0x12, 0xdf, 0x4b, 0x0e, 0x09, 0x6f, 0x46, 0xec, 0x00, 0x3d, 0x8f, 0xe0, + 0xa0, 0xb5, 0x59, 0xe0, 0xde, 0x6e, 0xfe, 0x4d, 0x00, 0x18, 0x37, 0xd0, + 0x7b, 0x04, 0x2f, 0xf0, 0x7f, 0xb9, 0x94, 0x00, 0x68, 0x9e, 0xa9, 0x1b, + 0x40, 0x1c, 0xc0, 0x3d, 0x90, 0xd6, 0xec, 0x10, 0x9c, 0xe9, 0x44, 0x35, + 0x6e, 0x57, 0xb3, 0xed, 0xe7, 0x5d, 0xb1, 0xc0, 0x3d, 0x0e, 0xbd, 0x59, + 0xe8, 0x85, 0xaf, 0x83, 0x72, 0xb7, 0x1d, 0x9d, 0xbb, 0xcb, 0x8a, 0x1a, + 0x6c, 0x3f, 0x10, 0xf1, 0x8a, 0xb5, 0xae, 0x15, 0x8f, 0x17, 0xcf, 0x2f, + 0x2c, 0x31, 0x66, 0x15, 0x1b, 0x48, 0x54, 0x29, 0xb7, 0x71, 0x75, 0xbe, + 0xbb, 0x9f, 0xbd, 0x8a, 0x99, 0x29, 0xc3, 0x9f, 0x90, 0xaa, 0x36, 0x9d, + 0x47, 0xb7, 0xb2, 0xe7, 0x1d, 0xf3, 0x1d, 0x90, 0xf3, 0xcd, 0xe6, 0x5b, + 0x43, 0x46, 0x0d, 0x6f, 0x9a, 0x13, 0x76, 0x90, 0xed, 0xa1, 0xf6, 0xb7, + 0xbe, 0x70, 0x21, 0x7f, 0xbb, 0xb9, 0x88, 0x01, 0x0b, 0x73, 0x6a, 0x24, + 0x5a, 0xd3, 0x96, 0xe4, 0x02, 0x9b, 0xf4, 0xda, 0xe9, 0xb6, 0x94, 0x12, + 0x73, 0x57, 0xef, 0xaf, 0x77, 0x16, 0xf1, 0x14, 0x70, 0x6b, 0x71, 0x30, + 0x53, 0x88, 0x97, 0xb7, 0x76, 0x60, 0x23, 0xff, 0xea, 0xbe, 0x18, 0xea, + 0x12, 0x10, 0xda, 0x7d, 0xb8, 0xc7, 0xce, 0x73, 0xb4, 0x87, 0x16, 0x1d, + 0xb2, 0xaa, 0x90, 0xda, 0x5e, 0xe5, 0xd1, 0xad, 0x8e, 0x8e, 0xb7, 0xd5, + 0xbe, 0x60, 0x03, 0x39, 0x82, 0x34, 0xce, 0xe4, 0x83, 0x9f, 0x46, 0x0f, + 0x6f, 0x35, 0x7f, 0x2f, 0x97, 0x21, 0x45, 0x5f, 0x35, 0x81, 0xd6, 0x40, + 0xea, 0x58, 0x69, 0x0d, 0xbd, 0xe0, 0x03, 0xae, 0x60, 0xb8, 0x6f, 0x0f, + 0xd0, 0xdf, 0x2a, 0x5e, 0x6a, 0x87, 0x1a, 0x65, 0x3c, 0xe6, 0xe6, 0xff, + 0xf2, 0x00, 0x38, 0xf6, 0xc1, 0x5d, 0x85, 0xd8, 0xfb, 0xa8, 0xe2, 0xd6, + 0x07, 0x84, 0x1e, 0x18, 0xdb, 0xe4, 0x34, 0xbc, 0x6e, 0xb7, 0x42, 0x7e, + 0xcb, 0x9e, 0x0d, 0xf8, 0xc9, 0x22, 0x65, 0x94, 0x2e, 0xd4, 0x58, 0xa7, + 0x0d, 0x6b, 0xcd, 0x84, 0x67, 0xc7, 0xd9, 0x42, 0x0b, 0x2b, 0xd4, 0x63, + 0x67, 0x72, 0x48, 0x89, 0x28, 0xd4, 0x76, 0xbe, 0x2d, 0x94, 0xaa, 0x7a, + 0x8c, 0x6c, 0xb5, 0x05, 0x5c, 0x84, 0xa2, 0x90, 0x29, 0xb7, 0x6f, 0x4e, + 0x0d, 0x6c, 0x4a, 0x6c, 0xc0, 0x29, 0xb9, 0x20, 0x13, 0x69, 0x22, 0x48, + 0xdd, 0x42, 0x6e, 0xd8, 0x57, 0x8b, 0x74, 0x7f, 0xe6, 0x09, 0x23, 0x4e, + 0x1c, 0xfb, 0x03, 0x3b, 0xf3, 0xb1, 0xc8, 0x4d, 0x1a, 0xd9, 0x4b, 0xe5, + 0xb6, 0x46, 0xe1, 0x80, 0x84, 0x00, 0xc0, 0x7b, 0x7e, 0x78, 0x5e, 0x51, + 0x7c, 0x45, 0x8d, 0xec, 0x3d, 0xf0, 0xcd, 0x7d, 0x28, 0x02, 0x35, 0x88, + 0xdb, 0x3b, 0x7d, 0x13, 0x36, 0xf7, 0x02, 0x43, 0xf3, 0x35, 0x27, 0x85, + 0x6f, 0x6e, 0x45, 0x80, 0x07, 0x0f, 0xe6, 0x96, 0x13, 0x82, 0x7c, 0xec, + 0x40, 0x82, 0xc0, 0xe6, 0xe4, 0xea, 0xf9, 0x73, 0x94, 0x00, 0x67, 0x00, + 0xa6, 0xc9, 0xda, 0x41, 0x7f, 0x06, 0x7a, 0xeb, 0x7f, 0x34, 0xf7, 0x94, + 0x5f, 0x1c, 0x3c, 0x13, 0x3f, 0xe8, 0xa8, 0xde, 0xaf, 0xeb, 0x97, 0xfd, + 0xd6, 0xed, 0xb4, 0x21, 0x6c, 0x24, 0xb7, 0x43, 0xee, 0xe9, 0x7b, 0xcc, + 0xb4, 0x26, 0x79, 0xcb, 0x65, 0xf4, 0x1c, 0xd4, 0x80, 0x3a, 0xde, 0x54, + 0x0c, 0x20, 0xe7, 0xc3, 0xae, 0xe4, 0xa0, 0x53, 0x73, 0x3b, 0x0c, 0x74, + 0x9c, 0xca, 0x17, 0x6b, 0x57, 0x09, 0xf0, 0xe9, 0xe7, 0x3c, 0x6d, 0x6f, + 0x88, 0x26, 0x82, 0x17, 0xfc, 0x6e, 0x4f, 0x04, 0xa5, 0x56, 0xe9, 0x1b, + 0x37, 0x6c, 0xc6, 0xbc, 0x88, 0xfe, 0xc4, 0x4d, 0x7a, 0xc9, 0x50, 0x3a, + 0xc9, 0x29, 0x9b, 0x14, 0x28, 0x60, 0x4b, 0x75, 0x3f, 0xbd, 0x3f, 0x9f, + 0x39, 0xe6, 0x1b, 0x8a, 0xa7, 0x4b, 0x10, 0x65, 0x52, 0x82, 0xe0, 0xd6, + 0xf4, 0x26, 0x51, 0x78, 0x1d, 0x5b, 0x95, 0x0d, 0x53, 0x2b, 0x7e, 0x2f, + 0xe8, 0xf9, 0x9d, 0x47, 0xf6, 0x58, 0xe9, 0x30, 0xe2, 0xc3, 0xe1, 0x6d, + 0xdc, 0x50, 0x03, 0xdb, 0xcc, 0x94, 0x00, 0x5d, 0xe0, 0x07, 0xb6, 0x2f, + 0x97, 0xef, 0xc6, 0x3a, 0xc2, 0xc0, 0x99, 0xe7, 0x65, 0x89, 0x1b, 0x4e, + 0x59, 0x1f, 0xe7, 0xae, 0xc0, 0x1e, 0x61, 0x92, 0x5f, 0x55, 0xaa, 0x51, + 0xcc, 0xf6, 0x4e, 0x32, 0x56, 0x76, 0x99, 0x2b, 0x6e, 0xe8, 0x5c, 0xc9, + 0xe2, 0xa8, 0x78, 0x4b, 0x76, 0x85, 0xf3, 0x34, 0x5c, 0x52, 0x8e, 0xa5, + 0xed, 0x4a, 0x87, 0x9e, 0x3e, 0x90, 0x9b, 0xcf, 0xec, 0x57, 0x4b, 0x60, + 0x5a, 0xc9, 0x69, 0x0c, 0x63, 0x7a, 0x01, 0x26, 0x88, 0xb9, 0x32, 0x82, + 0x48, 0x02, 0x1b, 0x2c, 0xbe, 0x95, 0xb9, 0x2f, 0xe1, 0x4b, 0x6c, 0x4e, + 0x03, 0xdb, 0xc7, 0xce, 0xcf, 0x67, 0xf1, 0x1f, 0x83, 0xca, 0xb6, 0x20, + 0x06, 0xcd, 0xb8, 0xd9, 0xcb, 0x94, 0xb0, 0xa1, 0x88, 0xdc, 0xf9, 0x2c, + 0x4a, 0xb6, 0x85, 0x14, 0x42, 0x6c, 0xbb, 0x0d, 0x48, 0xd6, 0x51, 0x8f, + 0x21, 0x4a, 0xd4, 0x74, 0x6f, 0xdf, 0x89, 0x76, 0xf2, 0xe7, 0xcd, 0x32, + 0xc4, 0x4b, 0x52, 0xca, 0x5c, 0x08, 0x2c, 0x6b, 0x76, 0x88, 0xa4, 0x41, + 0x62, 0xed, 0x96, 0x71, 0xb0, 0xa4, 0x37, 0x2d, 0x91, 0x60, 0x69, 0x6d, + 0xee, 0x00, 0x18, 0x6f, 0x20, 0x0d, 0x48, 0xff, 0xd7, 0x2c, 0xb5, 0x4b, + 0x27, 0xf3, 0x91, 0xf3, 0x6a, 0x20, 0x04, 0xc5, 0x95, 0x10, 0x36, 0x0f, + 0x6f, 0x4c, 0x00, 0xc0, 0x57, 0x3e, 0xc0, 0x16, 0xcd, 0xba, 0x30, 0xcc, + 0x28, 0xed, 0xa7, 0xcf, 0x35, 0x94, 0xe0, 0xb6, 0x39, 0xdc, 0xb1, 0x25, + 0x09, 0x42, 0xd1, 0x8d, 0x7c, 0x87, 0x20, 0x53, 0x7b, 0xc0, 0x1b, 0x5d, + 0x00, 0x7f, 0xc3, 0xdf, 0xc6, 0xa1, 0x68, 0x61, 0x3c, 0xdb, 0x65, 0xf1, + 0x2d, 0xbd, 0xc3, 0x7c, 0x6c, 0x01, 0xa0, 0x9e, 0xd3, 0x9d, 0xd9, 0xd8, + 0xeb, 0x73, 0x5f, 0x76, 0xdd, 0x41, 0xe1, 0x6d, 0xcf, 0x00, 0x64, 0x44, + 0xea, 0x6c, 0x36, 0xdb, 0x40, 0x95, 0x2e, 0x9b, 0x42, 0x5b, 0x32, 0x36, + 0xba, 0x8b, 0x9b, 0x8e, 0xb4, 0x78, 0x6d, 0x87, 0x1e, 0xda, 0x08, 0xb3, + 0x75, 0x64, 0x6f, 0xeb, 0x3f, 0xcf, 0x7e, 0x85, 0x77, 0x8f, 0xcd, 0x55, + 0x87, 0x48, 0x75, 0x4a, 0x48, 0x6e, 0x00, 0xb0, 0x06, 0xe0, 0x07, 0xdc, + 0xd2, 0x33, 0xa7, 0x38, 0x54, 0x92, 0x1b, 0xa9, 0x5c, 0xa5, 0x64, 0x31, + 0x07, 0x37, 0x88, 0x00, 0x36, 0x20, 0x88, 0xa5, 0x8b, 0x90, 0xfc, 0xe2, + 0xcb, 0x24, 0x55, 0x01, 0xec, 0x6e, 0x37, 0xcf, 0xcf, 0xf0, 0x55, 0x99, + 0xf1, 0xe7, 0x4f, 0x77, 0x7b, 0x22, 0xc1, 0xab, 0x4f, 0x83, 0x23, 0x3f, + 0x8e, 0x37, 0x5c, 0x81, 0xf0, 0xea, 0x95, 0x0b, 0xad, 0x5c, 0x65, 0x41, + 0xad, 0xc0, 0x02, 0xe1, 0x53, 0xfc, 0x2a, 0x6b, 0xe8, 0x6d, 0xd7, 0x86, + 0xa1, 0x4d, 0xdc, 0x23, 0x00, 0x3c, 0xe8, 0x01, 0xb8, 0x03, 0x8f, 0x3e, + 0xfd, 0xf9, 0xda, 0x51, 0xb3, 0x99, 0xce, 0xd8, 0x71, 0x43, 0x46, 0x64, + 0x6f, 0x82, 0x11, 0x25, 0x11, 0xb9, 0x74, 0x0f, 0x1d, 0x46, 0x37, 0xb1, + 0x00, 0x68, 0x44, 0xa0, 0x0e, 0xc4, 0x60, 0x9f, 0x9e, 0xcc, 0x5b, 0x35, + 0xff, 0x9d, 0xd4, 0x37, 0x00, 0xc2, 0x7e, 0x14, 0x38, 0xa3, 0xe8, 0x5b, + 0x6f, 0xe4, 0x41, 0xb2, 0x46, 0x84, 0x8f, 0x49, 0x11, 0x80, 0x00, 0x00, + 0x01, 0x04, 0x43, 0xf9, 0x8e, 0xd8, 0xe7, 0x69, 0x90, 0x2f, 0x79, 0x44, + 0x6c, 0xf5, 0xf4, 0x47, 0x79, 0x4e, 0x1e, 0xb2, 0x59, 0x54, 0x21, 0x18, + 0x3d, 0xd3, 0x49, 0x98, 0x1a, 0x07, 0x35, 0x22, 0x72, 0x71, 0xd1, 0x70, + 0xe2, 0xd5, 0x75, 0x0a, 0x50, 0xd6, 0xf3, 0x52, 0xc6, 0xf1, 0xd1, 0xbc, + 0xba, 0xa0, 0x16, 0x17, 0xea, 0x39, 0xb4, 0x7c, 0xd3, 0x0d, 0x92, 0x8f, + 0x92, 0x27, 0x8b, 0x58, 0x28, 0x9f, 0xbc, 0xcd, 0xba, 0x52, 0x87, 0x5c, + 0x52, 0xdb, 0x41, 0x13, 0xb9, 0xcc, 0x42, 0x74, 0xa3, 0xeb, 0x86, 0x6d, + 0x55, 0x3a, 0xd6, 0x71, 0xf2, 0x2a, 0x33, 0xa3, 0x9b, 0xf2, 0xde, 0xee, + 0xd7, 0x3e, 0x15, 0x95, 0x81, 0x1f, 0x8d, 0xe4, 0x44, 0xba, 0x14, 0x7c, + 0xb2, 0xb7, 0xb1, 0x10, 0xab, 0x32, 0xdf, 0x09, 0x15, 0x5b, 0xb3, 0xda, + 0xfd, 0x79, 0x12, 0xb9, 0x28, 0x45, 0x92, 0x42, 0x13, 0x72, 0xcb, 0x16, + 0x12, 0x58, 0x54, 0x46, 0xfc, 0x88, 0x03, 0xf4, 0xb4, 0x9f, 0x54, 0x05, + 0x51, 0x7c, 0x9d, 0xe2, 0xa8, 0x58, 0x59, 0x6c, 0xa2, 0x93, 0xda, 0x1b, + 0xa8, 0x13, 0xb2, 0xc5, 0x6f, 0x47, 0x25, 0x15, 0xce, 0x5c, 0xa0, 0x94, + 0x01, 0x19, 0x6d, 0x04, 0xbf, 0xfd, 0x56, 0xf1, 0xd0, 0x0c, 0x15, 0x6f, + 0xa3, 0x77, 0x0f, 0x56, 0xd0, 0xe6, 0xe8, 0xb3, 0xcf, 0xac, 0xd4, 0xf5, + 0x29, 0xba, 0x1b, 0xf8, 0x39, 0xb0, 0xcc, 0x9f, 0x3a, 0xe9, 0xa4, 0x26, + 0xee, 0xbf, 0x3f, 0x09, 0x08, 0x6d, 0x34, 0xb9, 0x5a, 0x1b, 0xe4, 0xb7, + 0x53, 0xd8, 0x10, 0xbf, 0xdf, 0x98, 0x4b, 0xd8, 0xb3, 0xc5, 0xa8, 0xef, + 0x3c, 0xae, 0xc5, 0x08, 0x59, 0x49, 0x32, 0x8c, 0x6e, 0x74, 0x2e, 0xd2, + 0x4b, 0x21, 0xac, 0x37, 0xf5, 0x69, 0xf9, 0x52, 0x5c, 0x88, 0x4b, 0x6c, + 0x4f, 0xa0, 0x16, 0xf3, 0xe7, 0x68, 0x04, 0x1b, 0x8b, 0xe2, 0x91, 0x09, + 0x0c, 0xb9, 0x00, 0x0d, 0xf0, 0x5c, 0x04, 0xcf, 0xfd, 0x5a, 0x49, 0x67, + 0xe1, 0x31, 0xfc, 0x19, 0xb4, 0x30, 0xd7, 0x1b, 0x3d, 0x14, 0xef, 0x14, + 0xac, 0xc6, 0x23, 0x41, 0xe0, 0x73, 0x7e, 0x53, 0x78, 0xdf, 0xb7, 0x3f, + 0x1c, 0x73, 0x20, 0x6a, 0xe6, 0x72, 0x60, 0xe2, 0x62, 0xa5, 0xf5, 0x6d, + 0xbf, 0x6c, 0x84, 0x7f, 0xad, 0x4e, 0x2c, 0x80, 0x4e, 0xf3, 0x32, 0xe6, + 0xc3, 0xe9, 0x49, 0x06, 0xb6, 0x69, 0xc6, 0x4f, 0x8e, 0x04, 0x3d, 0xf3, + 0x29, 0x36, 0x5e, 0x73, 0x7c, 0xcc, 0x96, 0x2a, 0x15, 0x51, 0x67, 0x85, + 0x8d, 0x89, 0xfa, 0x7c, 0x84, 0x39, 0x80, 0x5b, 0x3b, 0x52, 0x54, 0x6f, + 0x57, 0x69, 0xb9, 0xb6, 0x37, 0xf4, 0x70, 0x07, 0x22, 0xe7, 0xc7, 0xdb, + 0x78, 0x7b, 0xc2, 0x73, 0x2c, 0xb1, 0x17, 0xf1, 0x1b, 0xe7, 0x3f, 0x7e, + 0xb7, 0xfc, 0x47, 0x9e, 0x41, 0x17, 0x28, 0xed, 0x3a, 0xc6, 0xf7, 0xbf, + 0xe7, 0x82, 0x0f, 0xf6, 0x4a, 0x2e, 0x00, 0x41, 0xba, 0xb7, 0x28, 0x5b, + 0x7b, 0xad, 0xda, 0x4e, 0xb7, 0x25, 0x0c, 0xb5, 0x0a, 0x6e, 0x5c, 0x8b, + 0xb2, 0xc6, 0xe1, 0xe3, 0x10, 0x5c, 0xb2, 0x04, 0x2b, 0x7f, 0x9e, 0x2d, + 0xf3, 0xf3, 0x03, 0x87, 0x86, 0x96, 0xdd, 0x61, 0x38, 0xed, 0x77, 0xcc, + 0x35, 0x60, 0xfb, 0x64, 0xa6, 0x0d, 0x1f, 0x69, 0x6d, 0x39, 0xb4, 0x01, + 0xb0, 0x9f, 0xf7, 0x2f, 0xd0, 0x9d, 0x7f, 0x0a, 0xeb, 0x69, 0xe0, 0x4c, + 0xa8, 0xdd, 0x27, 0x15, 0x9d, 0xed, 0x0b, 0x57, 0xea, 0x96, 0x03, 0x26, + 0xd2, 0x2b, 0xa2, 0x90, 0xf6, 0x36, 0xf0, 0x0c, 0x4b, 0x00, 0x06, 0x72, + 0xb7, 0xa6, 0x02, 0x17, 0xf8, 0x91, 0x63, 0xa4, 0x80, 0x3d, 0x37, 0xdf, + 0x78, 0x33, 0x21, 0xe4, 0xd5, 0x2a, 0x20, 0x4b, 0x7d, 0x7b, 0xe6, 0x02, + 0x0f, 0xf5, 0x80, 0x2c, 0xfe, 0x66, 0x89, 0xe2, 0x69, 0x59, 0x9b, 0xef, + 0xed, 0xe7, 0x27, 0x91, 0xf6, 0x93, 0xf6, 0x54, 0xa0, 0x11, 0x4b, 0x5b, + 0xe5, 0x30, 0x10, 0xbf, 0xea, 0xbe, 0xd8, 0x37, 0xf5, 0x62, 0x6d, 0xbe, + 0x0d, 0xd8, 0xfa, 0x7f, 0xb8, 0x00, 0x77, 0xef, 0x9e, 0x69, 0x47, 0xa3, + 0xb8, 0xf3, 0xc8, 0x32, 0x87, 0xe9, 0x52, 0x2b, 0x73, 0xce, 0x6e, 0x26, + 0x45, 0x08, 0x2d, 0xb8, 0xf2, 0xa2, 0x23, 0x7e, 0xbf, 0x1f, 0x9b, 0x73, + 0x53, 0x60, 0x4c, 0x29, 0x46, 0x52, 0xdb, 0xa4, 0x00, 0xa4, 0x8b, 0x9f, + 0x7e, 0x05, 0x88, 0x9a, 0xe9, 0x46, 0x51, 0x5f, 0x4f, 0x73, 0x37, 0xcc, + 0xf9, 0xfa, 0x85, 0xa9, 0xe3, 0x9b, 0xe7, 0x22, 0xe0, 0x01, 0xf6, 0x8a, + 0x8f, 0xd0, 0x9b, 0x78, 0xc4, 0x2c, 0x04, 0x68, 0x53, 0x7b, 0x5a, 0xa4, + 0x52, 0x0e, 0x4d, 0x30, 0x05, 0x7c, 0xae, 0x9e, 0x1d, 0x60, 0xd0, 0xb6, + 0xf2, 0x72, 0x82, 0x17, 0xfd, 0x57, 0x5c, 0x81, 0xb7, 0x4c, 0x29, 0xb0, + 0x85, 0xec, 0x2b, 0xc6, 0x46, 0xf3, 0x80, 0x14, 0xf0, 0xf0, 0x07, 0x3f, + 0x4e, 0x7d, 0xb1, 0xd0, 0x27, 0x7a, 0x7e, 0x2b, 0xa5, 0x2e, 0x15, 0x29, + 0xd5, 0xb2, 0xfc, 0x3e, 0x00, 0x3a, 0xf7, 0xbb, 0x64, 0x41, 0xdd, 0x3a, + 0x2e, 0x21, 0xc7, 0x16, 0xaa, 0x17, 0x55, 0xbe, 0xac, 0x00, 0xab, 0xa7, + 0x7c, 0x80, 0x57, 0xbd, 0xbf, 0x68, 0x11, 0xf9, 0xd0, 0xfc, 0x29, 0x00, + 0x8a, 0x34, 0x92, 0xdf, 0x37, 0x00, 0x75, 0xed, 0xee, 0x00, 0xfb, 0xdb, + 0x33, 0xa8, 0x47, 0xed, 0xf6, 0x2e, 0x87, 0x1d, 0x31, 0xce, 0x88, 0x54, + 0x29, 0xbd, 0x47, 0x3e, 0x0b, 0x15, 0x33, 0x4c, 0x09, 0x2e, 0xa5, 0xbe, + 0x2d, 0xbe, 0x6a, 0xc2, 0xd0, 0x25, 0xbf, 0x9b, 0x57, 0x66, 0xf0, 0x63, + 0xb2, 0x05, 0x0f, 0x0b, 0x6d, 0x2f, 0x2e, 0xd0, 0x29, 0xb6, 0x88, 0xdd, + 0xeb, 0x80, 0x09, 0xec, 0x2c, 0x07, 0xb6, 0x4f, 0x16, 0x8e, 0x12, 0x08, + 0x3f, 0xd8, 0x00, 0xfb, 0x39, 0x4a, 0x3d, 0x60, 0x8e, 0x64, 0xd7, 0x14, + 0xb0, 0xed, 0x2e, 0x5b, 0x43, 0x28, 0xe6, 0xdc, 0xc5, 0x80, 0x53, 0x4c, + 0x94, 0xb4, 0x6f, 0x29, 0x1b, 0x9b, 0x7e, 0xa4, 0xe3, 0x32, 0xd4, 0x8b, + 0x78, 0x8f, 0x4e, 0x4d, 0x01, 0xc2, 0x98, 0x6a, 0x0d, 0x2c, 0xf0, 0xc5, + 0x6f, 0x68, 0x22, 0xf6, 0x23, 0xe9, 0x05, 0x5e, 0xf2, 0x8e, 0xab, 0xd6, + 0xba, 0x2c, 0x0f, 0x85, 0x4b, 0x0a, 0x94, 0x28, 0x7b, 0x69, 0x00, 0x5e, + 0x4f, 0x00, 0x6a, 0x00, 0xe3, 0xdb, 0xb1, 0x79, 0xb4, 0x73, 0x85, 0x93, + 0xd7, 0x8e, 0x7b, 0x3f, 0x2a, 0x6c, 0x40, 0x1c, 0x51, 0x8d, 0xfa, 0x34, + 0x01, 0x0f, 0xdf, 0x5f, 0x44, 0x89, 0xcc, 0x90, 0xbb, 0x43, 0xde, 0xf2, + 0xc7, 0xdf, 0x5a, 0xd4, 0x2c, 0xae, 0x34, 0xbf, 0x06, 0xd9, 0xe5, 0xbb, + 0x4b, 0x6f, 0xf2, 0x77, 0x29, 0xc4, 0x85, 0xb6, 0x7e, 0xe2, 0xd8, 0x8d, + 0xfa, 0xc8, 0x00, 0x9c, 0x01, 0xc8, 0xbd, 0xd8, 0x1d, 0x1d, 0x90, 0x98, + 0x12, 0xd9, 0x40, 0x08, 0x7f, 0xfa, 0x46, 0x11, 0x49, 0xe2, 0x64, 0x2a, + 0x79, 0x98, 0xb4, 0xab, 0x4a, 0x8d, 0x98, 0x9e, 0x25, 0xb4, 0xf6, 0x5d, + 0xba, 0x55, 0x3d, 0xbf, 0x9b, 0x80, 0x3b, 0xf8, 0x70, 0x02, 0xf2, 0x30, + 0x03, 0xbb, 0xde, 0xad, 0xa5, 0x66, 0x80, 0x1e, 0x4e, 0x26, 0xbb, 0x50, + 0xba, 0x7e, 0xd4, 0x48, 0x58, 0x4b, 0x79, 0xa2, 0x27, 0x0f, 0xf7, 0xeb, + 0x48, 0xfd, 0x5a, 0x32, 0xc4, 0xeb, 0x72, 0x2c, 0x38, 0xed, 0xb5, 0x61, + 0x0a, 0x37, 0xe9, 0x7f, 0x9d, 0xbf, 0x5f, 0xef, 0xb8, 0xbd, 0xf5, 0xed, + 0xf6, 0xc8, 0x15, 0x87, 0x48, 0x14, 0xdf, 0x9f, 0x80, 0x1e, 0xf5, 0xa0, + 0x05, 0x14, 0x8d, 0xec, 0x2c, 0xe2, 0xe3, 0xed, 0xc1, 0x0e, 0x79, 0x47, + 0x13, 0x0b, 0xa9, 0xe0, 0x5a, 0xb4, 0x8b, 0xa4, 0xe3, 0x4e, 0x0a, 0x4b, + 0x63, 0x3e, 0x7f, 0x0a, 0x4a, 0xa7, 0x37, 0xcd, 0xfb, 0xb9, 0xc2, 0xdd, + 0xc6, 0xeb, 0xec, 0x1b, 0x92, 0x59, 0xfb, 0x39, 0xbe, 0x96, 0x00, 0xfc, + 0x5e, 0x09, 0xf7, 0x13, 0x38, 0xe8, 0x6a, 0x68, 0x05, 0x44, 0xcc, 0x7d, + 0x01, 0x5e, 0xd2, 0x8e, 0x1a, 0xad, 0xf3, 0x5f, 0xee, 0x7b, 0x7d, 0x44, + 0x5d, 0x15, 0x62, 0x25, 0x9b, 0xa1, 0x86, 0x14, 0x6f, 0x89, 0x41, 0x25, + 0x56, 0xfb, 0x57, 0xf0, 0x8b, 0x84, 0x5f, 0xbf, 0x7b, 0xc6, 0x8c, 0x47, + 0x64, 0x87, 0x3a, 0x21, 0x54, 0x7d, 0x3d, 0xb8, 0x7b, 0x78, 0x05, 0xa4, + 0xc9, 0xa1, 0x91, 0x1a, 0x1f, 0xa4, 0xfa, 0x52, 0xb7, 0xe4, 0x88, 0x00, + 0x15, 0x0a, 0x16, 0x96, 0xac, 0x55, 0x7d, 0x7e, 0x99, 0x86, 0xd2, 0xce, + 0xb0, 0x6d, 0x09, 0x6f, 0x19, 0xe7, 0x3d, 0xac, 0x8e, 0x7e, 0xd5, 0x36, + 0x9f, 0x86, 0xd5, 0x0b, 0x6f, 0x60, 0x00, 0xe8, 0x8b, 0x08, 0xc8, 0xfd, + 0x99, 0xa5, 0x96, 0xeb, 0x26, 0x45, 0x0b, 0xaa, 0x73, 0x7c, 0x9f, 0xda, + 0xd0, 0x06, 0xdf, 0x42, 0x27, 0x62, 0xc0, 0x45, 0xe6, 0xfb, 0x56, 0x0c, + 0x26, 0x4b, 0x0a, 0x2d, 0xa7, 0x93, 0x27, 0x42, 0x16, 0x0f, 0x53, 0x69, + 0xd0, 0x69, 0xc5, 0xb7, 0x3d, 0xb2, 0x4c, 0x58, 0xdf, 0x24, 0x01, 0xf9, + 0x3b, 0xa1, 0x04, 0x6e, 0xc4, 0xfc, 0x6a, 0x5b, 0x3c, 0xe3, 0xb7, 0x83, + 0x43, 0xe0, 0x65, 0xb0, 0xab, 0x65, 0x46, 0xfd, 0x38, 0x00, 0x8c, 0x8a, + 0x08, 0x3f, 0xcc, 0x00, 0xfc, 0x8e, 0xf0, 0x0b, 0x34, 0x11, 0xc0, 0x13, + 0x8f, 0x20, 0x31, 0x0a, 0x53, 0xb4, 0x7e, 0x9f, 0xe8, 0xde, 0x0f, 0xfb, + 0xcd, 0x00, 0x4a, 0x47, 0xd7, 0x79, 0x41, 0xf8, 0x01, 0x66, 0x49, 0x6e, + 0xd3, 0xc0, 0x72, 0x19, 0x09, 0x2d, 0xef, 0xdd, 0x1d, 0x04, 0xbe, 0x19, + 0x80, 0x2b, 0xc7, 0x07, 0x6a, 0x0e, 0x45, 0x43, 0x9b, 0xd6, 0xe3, 0x6f, + 0x39, 0x15, 0x60, 0xca, 0x6c, 0xab, 0x47, 0x37, 0x6c, 0xa6, 0xd6, 0x00, + 0x00, 0x01, 0x05, 0x43, 0xf9, 0x7d, 0x74, 0xbc, 0x58, 0xed, 0x01, 0x5e, + 0xd0, 0x82, 0x99, 0x05, 0xde, 0x29, 0x32, 0x84, 0xea, 0x9f, 0x46, 0x37, + 0x4e, 0x3e, 0x5b, 0x4c, 0xb6, 0x0e, 0x68, 0x2b, 0xdd, 0xc6, 0x95, 0x92, + 0xc5, 0x4d, 0xf0, 0x6e, 0x02, 0x9b, 0xc7, 0xc5, 0xd3, 0xa3, 0x7c, 0xf1, + 0x6e, 0xbb, 0x25, 0x90, 0x22, 0x69, 0xb2, 0x21, 0x46, 0xb3, 0x0b, 0xe7, + 0x9a, 0xfd, 0x76, 0x5a, 0xa6, 0xcf, 0x38, 0x8e, 0x9b, 0xa7, 0x19, 0x50, + 0xc8, 0xdd, 0x93, 0x43, 0x9e, 0x1e, 0xed, 0xb1, 0x66, 0x07, 0x2a, 0xa5, + 0x6d, 0xbb, 0x45, 0xba, 0x7d, 0x44, 0xce, 0x3b, 0xd2, 0xe5, 0x9d, 0x47, + 0xd7, 0x75, 0x77, 0x89, 0x15, 0x0f, 0x02, 0x75, 0xb9, 0x4d, 0x27, 0x45, + 0x3d, 0xb7, 0x2e, 0xa8, 0x1c, 0xdf, 0x96, 0xda, 0x6d, 0x88, 0xde, 0xcd, + 0xdc, 0x80, 0x1f, 0xf2, 0xfc, 0x92, 0x41, 0xf5, 0xf1, 0x02, 0xe0, 0xda, + 0x84, 0x36, 0xf2, 0xdc, 0x97, 0xc7, 0x04, 0x8b, 0x1b, 0x03, 0x9d, 0x05, + 0x7b, 0xf4, 0x6d, 0x9e, 0x18, 0x85, 0xb4, 0x5a, 0x38, 0x86, 0xdc, 0xd4, + 0xa9, 0x1b, 0xeb, 0x67, 0x37, 0xfd, 0xd6, 0x3b, 0xb7, 0xe4, 0x2c, 0xcc, + 0xd7, 0x98, 0x8f, 0xb2, 0x15, 0x0b, 0x44, 0x54, 0x6f, 0x1a, 0x08, 0x60, + 0x0d, 0x55, 0xbb, 0x02, 0x2a, 0xe5, 0xf2, 0xf4, 0x36, 0xd4, 0x6e, 0x56, + 0xc3, 0x1d, 0x29, 0x2f, 0x25, 0x6f, 0x42, 0x50, 0xea, 0xa4, 0x36, 0xd8, + 0x7b, 0x7b, 0xc4, 0x82, 0x17, 0xfa, 0xd7, 0xe4, 0x40, 0xb4, 0x46, 0xb4, + 0x8d, 0xd6, 0xf5, 0xa6, 0xbe, 0xd1, 0x85, 0x41, 0xed, 0xe8, 0x2a, 0xe5, + 0xe7, 0x49, 0x76, 0xda, 0xde, 0x66, 0x54, 0x73, 0xac, 0xbe, 0x3a, 0x89, + 0xe2, 0x39, 0xae, 0x87, 0x69, 0xed, 0x27, 0x37, 0xb4, 0x45, 0x00, 0x3e, + 0x84, 0x5e, 0x57, 0x01, 0x20, 0x00, 0xf9, 0x99, 0x38, 0x9e, 0x0a, 0x5c, + 0x21, 0x37, 0x9b, 0x81, 0xcd, 0xdb, 0xe9, 0xf3, 0xfd, 0xc7, 0x1e, 0x72, + 0x51, 0xb2, 0x58, 0xdc, 0x22, 0x63, 0x72, 0x8d, 0xac, 0xce, 0x6f, 0xd2, + 0x11, 0xb8, 0x04, 0x1f, 0xed, 0xc1, 0x1d, 0xca, 0x13, 0xe7, 0xbb, 0x56, + 0x0c, 0x19, 0x31, 0xaf, 0xc5, 0x00, 0x74, 0xf2, 0x31, 0x88, 0x1b, 0x37, + 0xbf, 0x3b, 0x76, 0x1e, 0x03, 0x88, 0x52, 0xa3, 0x72, 0xf9, 0x40, 0x07, + 0x3b, 0xf1, 0x99, 0x60, 0x4c, 0x32, 0xdb, 0x28, 0x4a, 0xa9, 0x2e, 0x35, + 0x9c, 0x60, 0x20, 0x80, 0x9f, 0x5e, 0xd2, 0xcf, 0x1e, 0x05, 0xc5, 0xf0, + 0xbc, 0x92, 0x1b, 0x53, 0xdb, 0xaa, 0xad, 0x45, 0x21, 0xab, 0x7b, 0xf7, + 0x99, 0xcf, 0x1b, 0x0c, 0xca, 0x39, 0x3d, 0xb5, 0xd3, 0x28, 0xca, 0x76, + 0xd2, 0xe9, 0x66, 0x36, 0x57, 0x99, 0xf1, 0xcd, 0xbe, 0x55, 0x3f, 0x69, + 0x66, 0xc1, 0xaa, 0x3e, 0x01, 0xcd, 0xe8, 0xfa, 0x7e, 0x80, 0x33, 0xc2, + 0x7c, 0xf3, 0x0a, 0xe1, 0xd6, 0x63, 0xa8, 0x0a, 0xe4, 0xb6, 0x94, 0x10, + 0x18, 0xd9, 0x79, 0xdb, 0xf4, 0xa2, 0x75, 0xf4, 0x2a, 0x7c, 0x9b, 0x84, + 0x38, 0x8a, 0xda, 0x35, 0xe7, 0xe4, 0xca, 0x4a, 0x6f, 0x85, 0xd0, 0x21, + 0x7f, 0xd3, 0xd7, 0x77, 0xc2, 0x18, 0xb7, 0xc2, 0xd6, 0xfa, 0xef, 0xd2, + 0xcf, 0xf8, 0x8d, 0x45, 0x01, 0x14, 0xb2, 0xc8, 0x34, 0x63, 0x7c, 0x75, + 0x17, 0x72, 0x12, 0xa2, 0x92, 0x0e, 0x6e, 0x8d, 0x90, 0x5f, 0x3a, 0xed, + 0x30, 0x2a, 0x3e, 0x36, 0x1a, 0x1d, 0x1b, 0x7e, 0x40, 0xc7, 0x56, 0xfa, + 0x46, 0xee, 0xd8, 0x08, 0x20, 0x27, 0x40, 0x1c, 0x79, 0x4a, 0x17, 0xd6, + 0x3e, 0xda, 0x17, 0x36, 0x55, 0xa1, 0x4d, 0xec, 0x85, 0xcd, 0xf7, 0x17, + 0xbc, 0x10, 0x2d, 0x2f, 0x6d, 0x0f, 0xc7, 0x9a, 0xf1, 0x87, 0x06, 0x50, + 0x96, 0xf0, 0xfd, 0x02, 0x10, 0x06, 0x8a, 0xe8, 0x41, 0x0b, 0x63, 0xf7, + 0x3c, 0x26, 0xd6, 0xf7, 0x3f, 0xcd, 0x84, 0x7d, 0x12, 0x84, 0x3b, 0x57, + 0xc4, 0x7f, 0xab, 0x71, 0x4c, 0x00, 0xab, 0x76, 0x5f, 0x57, 0xa5, 0xcf, + 0x16, 0xe4, 0xb8, 0x40, 0xd7, 0x80, 0x0c, 0x6a, 0xb7, 0xe7, 0xb5, 0xd5, + 0xd7, 0x8e, 0x28, 0xc4, 0x57, 0xc9, 0x4e, 0xb4, 0xba, 0x5d, 0x6f, 0xa0, + 0xe6, 0x0b, 0xff, 0x8a, 0x17, 0x79, 0xf2, 0x59, 0x2c, 0x37, 0x3a, 0xe6, + 0xba, 0x18, 0x7c, 0x2e, 0x01, 0xed, 0xe5, 0xba, 0xe4, 0x00, 0xe3, 0xa1, + 0x7d, 0x3e, 0xd8, 0x3c, 0xed, 0xb2, 0x85, 0x18, 0x5b, 0x7a, 0x3c, 0x73, + 0xc1, 0x03, 0xf3, 0x39, 0xe2, 0xd9, 0x88, 0x71, 0x3b, 0xbe, 0x3c, 0xe9, + 0x67, 0xc0, 0xe2, 0xe0, 0x14, 0xd9, 0x77, 0x41, 0x08, 0x01, 0xab, 0xe2, + 0x10, 0x9b, 0x91, 0xe0, 0x67, 0x89, 0x72, 0xb7, 0xe4, 0x7e, 0x3a, 0x00, + 0xb3, 0x5d, 0x85, 0xd9, 0x6c, 0x52, 0x8b, 0xbe, 0xb0, 0x08, 0x6e, 0x98, + 0x03, 0xed, 0x78, 0x03, 0xf1, 0x66, 0x3b, 0x8c, 0x83, 0x97, 0x30, 0x9a, + 0x5a, 0x40, 0xe9, 0x6c, 0x3e, 0x86, 0xb7, 0xe9, 0x10, 0x40, 0xfd, 0x40, + 0x07, 0x3d, 0xf0, 0x00, 0xf3, 0x8f, 0x61, 0x5a, 0xec, 0x85, 0xf2, 0xff, + 0x24, 0x29, 0xc6, 0x87, 0x7e, 0x83, 0x24, 0x6d, 0x60, 0x04, 0xa0, 0x0e, + 0x7d, 0xfa, 0x17, 0xb8, 0xf9, 0xe5, 0x92, 0x4c, 0x97, 0xcd, 0xf9, 0x13, + 0x6d, 0x32, 0x1c, 0xdd, 0x9f, 0x27, 0xad, 0x50, 0xb6, 0xea, 0x16, 0x7c, + 0xb5, 0x5b, 0xfc, 0xda, 0x00, 0xf3, 0xe3, 0xbe, 0x39, 0xf2, 0xe1, 0xef, + 0xe4, 0xb5, 0xcc, 0x78, 0x01, 0xf3, 0x88, 0x3b, 0xe5, 0x09, 0xf2, 0x42, + 0xac, 0x4b, 0x54, 0x7d, 0xad, 0xd4, 0xe2, 0xec, 0x15, 0xb8, 0x64, 0x08, + 0xb9, 0xb4, 0xf1, 0x9e, 0x10, 0x2d, 0xbe, 0xb6, 0x00, 0x8f, 0xa8, 0x00, + 0xc0, 0x01, 0x16, 0xef, 0x3c, 0xf2, 0x85, 0xf9, 0x63, 0xc4, 0x8b, 0x72, + 0x53, 0x43, 0xcb, 0x5c, 0x52, 0x4b, 0x6e, 0x04, 0x0f, 0xd3, 0x00, 0xb3, + 0x28, 0xbe, 0xdf, 0x75, 0xf2, 0x1d, 0x15, 0x6c, 0x8d, 0xbb, 0xe5, 0xba, + 0xb7, 0xd6, 0x42, 0x98, 0xee, 0x79, 0x6c, 0xb6, 0x37, 0xf8, 0xdd, 0xd8, + 0x00, 0x26, 0x5a, 0x09, 0x80, 0x06, 0xe9, 0x67, 0xab, 0x7d, 0x14, 0x10, + 0x3f, 0x38, 0x8c, 0x08, 0x3f, 0xae, 0x00, 0xf3, 0x04, 0x08, 0x23, 0xf0, + 0x84, 0xd3, 0x3e, 0x5f, 0xb2, 0x10, 0x38, 0x42, 0x7d, 0x85, 0x86, 0xb8, + 0x6b, 0x7e, 0xaa, 0x00, 0x27, 0x00, 0x7e, 0x2c, 0x01, 0xc8, 0x03, 0xb7, + 0x82, 0x10, 0x03, 0x3f, 0x6a, 0x4c, 0xeb, 0xae, 0xa9, 0x50, 0xcb, 0x4d, + 0xda, 0x81, 0x2d, 0xed, 0xb0, 0x3a, 0xd5, 0x6e, 0x9d, 0x2e, 0xb6, 0xda, + 0x5d, 0xa8, 0xde, 0x62, 0x28, 0x9e, 0x48, 0xbf, 0x71, 0x62, 0xc4, 0xf7, + 0xa0, 0x3d, 0xde, 0x5e, 0xfb, 0x74, 0x74, 0x85, 0x0e, 0x92, 0x23, 0x74, + 0xdb, 0x2e, 0x16, 0xc7, 0x22, 0x36, 0xcd, 0xab, 0x61, 0xd3, 0xcb, 0x69, + 0x21, 0xa7, 0x54, 0x83, 0xd5, 0x95, 0xb1, 0xe0, 0x21, 0x00, 0x35, 0xd6, + 0xc0, 0xe8, 0x00, 0x6f, 0x65, 0x9e, 0xb9, 0x24, 0x66, 0xc3, 0x70, 0x53, + 0xa8, 0x03, 0x0f, 0x7f, 0xaf, 0x5b, 0x1c, 0x5c, 0x57, 0xd2, 0x03, 0xec, + 0x93, 0x24, 0x2e, 0xa8, 0xe3, 0x83, 0x1b, 0xe6, 0xe6, 0x91, 0x1e, 0x44, + 0xfb, 0x80, 0x5a, 0xf1, 0x24, 0xd7, 0x16, 0xfa, 0xf9, 0x03, 0x89, 0x96, + 0x19, 0xb3, 0x03, 0x0a, 0x19, 0x1b, 0xed, 0x0a, 0x1d, 0x69, 0x21, 0xbf, + 0x18, 0xbd, 0xc0, 0x06, 0x8f, 0xf8, 0x7c, 0xa1, 0xab, 0x3e, 0x28, 0xa4, + 0x04, 0xb0, 0x03, 0x31, 0x47, 0x8e, 0x6f, 0x2e, 0x50, 0x03, 0xea, 0x92, + 0x78, 0xd2, 0xc9, 0x4d, 0xc9, 0x00, 0xc6, 0xa3, 0x7e, 0x9b, 0xfe, 0x2b, + 0x3b, 0xeb, 0x8b, 0xbd, 0xc1, 0xd7, 0x31, 0xcf, 0xd8, 0x62, 0x15, 0x2a, + 0x1c, 0x7b, 0x75, 0xb2, 0x76, 0x45, 0x17, 0xed, 0xbf, 0xee, 0x2e, 0x96, + 0x99, 0x8f, 0xd2, 0xe2, 0x42, 0xc7, 0x0d, 0x6e, 0x01, 0x13, 0x1c, 0x00, + 0xa4, 0x4f, 0xb7, 0x6e, 0xd8, 0x38, 0x02, 0x9d, 0xe1, 0x66, 0xd3, 0xd5, + 0x20, 0xd6, 0xfa, 0x8c, 0x17, 0x80, 0x0f, 0x38, 0x9f, 0x8c, 0xa9, 0x15, + 0x4d, 0xc9, 0x25, 0x1a, 0x31, 0x54, 0xa6, 0xf3, 0x9e, 0x9c, 0xcd, 0x58, + 0xa3, 0x91, 0x51, 0x28, 0x5b, 0x72, 0xd2, 0xe5, 0x95, 0xbc, 0x00, 0x0e, + 0x7e, 0xef, 0x23, 0x47, 0xe3, 0xf5, 0xce, 0x2a, 0x13, 0xc3, 0xd5, 0x14, + 0x04, 0x45, 0x29, 0x29, 0xbe, 0x72, 0x00, 0xf7, 0x0d, 0x17, 0xed, 0xc7, + 0x7c, 0x00, 0xaa, 0x4e, 0x35, 0xea, 0xf2, 0xc7, 0x42, 0xa9, 0x47, 0x9e, + 0xde, 0xf3, 0x3a, 0x7f, 0x3b, 0xcb, 0xd3, 0x06, 0x5c, 0x26, 0x96, 0xa3, + 0x0b, 0x43, 0xda, 0xae, 0xa7, 0xbf, 0x31, 0x34, 0xc4, 0x1b, 0x38, 0xbc, + 0x42, 0xae, 0xd0, 0xc5, 0x6e, 0xbd, 0xbb, 0xb2, 0xe1, 0xb4, 0x34, 0xc4, + 0x56, 0xa5, 0xa8, 0x8a, 0xdf, 0x40, 0x8d, 0x39, 0xfe, 0xf1, 0xcc, 0x94, + 0x68, 0x79, 0x99, 0xdd, 0x8e, 0x8a, 0x5a, 0xab, 0xa8, 0xd5, 0x29, 0xb9, + 0xc0, 0x0e, 0x05, 0x80, 0x19, 0x73, 0x3a, 0x31, 0x00, 0x25, 0x8f, 0xda, + 0x4c, 0x94, 0x38, 0xed, 0xf5, 0x6e, 0x48, 0x8e, 0x9f, 0xf1, 0xcb, 0xb7, + 0xad, 0xb4, 0x05, 0x7c, 0xc2, 0x60, 0xdf, 0x06, 0xf9, 0x71, 0xa0, 0x02, + 0x6d, 0x15, 0xaf, 0xb2, 0x0c, 0x86, 0xf1, 0xb2, 0xdf, 0x46, 0xc7, 0xb7, + 0x9a, 0x2c, 0xcb, 0xe9, 0x30, 0xa8, 0xa0, 0x53, 0x25, 0x31, 0xf5, 0x51, + 0x80, 0x00, 0x00, 0x01, 0x06, 0x43, 0xf8, 0xce, 0x95, 0xb6, 0x28, 0x43, + 0x6a, 0xca, 0xf1, 0x3b, 0x30, 0xc4, 0x1c, 0x79, 0x7e, 0x81, 0x8d, 0x9b, + 0x67, 0x9f, 0x09, 0x81, 0x4d, 0xd8, 0x13, 0x08, 0x2e, 0x3f, 0xc5, 0x5b, + 0xc6, 0x45, 0x6f, 0x08, 0x73, 0x68, 0x2b, 0x2b, 0xa4, 0xcc, 0xf1, 0xa3, + 0x47, 0x35, 0x3d, 0x3a, 0x3b, 0xad, 0x4b, 0x24, 0x1b, 0x55, 0xb6, 0x5d, + 0x00, 0xb2, 0xda, 0xb0, 0x31, 0x25, 0x2d, 0xb9, 0xe4, 0xdc, 0x6c, 0x49, + 0x92, 0x44, 0x65, 0x92, 0x45, 0xad, 0xf7, 0xb4, 0x10, 0xbf, 0xc8, 0x67, + 0xa3, 0x07, 0xf6, 0x40, 0x10, 0x23, 0x97, 0x58, 0x1b, 0x23, 0xbc, 0xd6, + 0xc0, 0x08, 0xd1, 0xba, 0xcf, 0x04, 0x2f, 0xf1, 0x36, 0x12, 0x9b, 0xc0, + 0x7b, 0x60, 0x21, 0x80, 0x53, 0xa0, 0x5a, 0x3b, 0x32, 0x97, 0xe1, 0x4b, + 0x6e, 0x95, 0x58, 0x50, 0x00, 0xd5, 0xac, 0xf6, 0xf6, 0x91, 0x64, 0x23, + 0x76, 0x9b, 0x9e, 0x2a, 0x8a, 0xd5, 0xa8, 0x01, 0xee, 0x3b, 0x24, 0xf5, + 0xa7, 0x85, 0x37, 0xab, 0xea, 0xdc, 0x76, 0xba, 0xa8, 0x4c, 0xaa, 0x93, + 0xc4, 0x63, 0x78, 0xc4, 0xbb, 0xce, 0x52, 0x87, 0x52, 0xa4, 0x54, 0x09, + 0x6d, 0x00, 0x4a, 0xe5, 0xf5, 0x46, 0xb1, 0xad, 0xfa, 0xd8, 0x1c, 0x68, + 0x16, 0xde, 0x33, 0x01, 0x08, 0x02, 0xbb, 0x76, 0x6a, 0xf8, 0xe4, 0x01, + 0xf3, 0x7a, 0x23, 0x29, 0x3b, 0x81, 0x66, 0xba, 0x86, 0xce, 0x5c, 0x74, + 0x3c, 0xf0, 0xc6, 0xf9, 0xe7, 0x40, 0x84, 0x00, 0xce, 0x10, 0x58, 0x5e, + 0xcd, 0xc5, 0xa3, 0x8b, 0x4a, 0x31, 0x87, 0x01, 0x8c, 0x9b, 0x48, 0x4d, + 0x67, 0xc6, 0xfa, 0xc7, 0x48, 0xd5, 0xd2, 0xa4, 0x6d, 0x52, 0x99, 0x24, + 0xbe, 0xa8, 0x8d, 0xd7, 0x12, 0xe7, 0xff, 0x5c, 0xee, 0x2e, 0x69, 0xf7, + 0xc9, 0x7c, 0xff, 0x63, 0x0a, 0x1e, 0xc9, 0x93, 0x75, 0x22, 0x7c, 0xd7, + 0x1e, 0x80, 0x12, 0x4b, 0xbc, 0xdd, 0xa7, 0x7e, 0x8e, 0x28, 0xf3, 0xca, + 0x6c, 0xef, 0xbe, 0x77, 0x99, 0x28, 0x51, 0x93, 0x64, 0x90, 0x05, 0x45, + 0x97, 0x02, 0x9b, 0xb0, 0x4e, 0x00, 0x34, 0x73, 0xfc, 0x94, 0xe5, 0xa8, + 0xe0, 0x17, 0xb5, 0x0e, 0x5b, 0x2b, 0xec, 0xa7, 0x9d, 0x31, 0xdd, 0x87, + 0xc3, 0xc7, 0xea, 0x7a, 0xb6, 0xa7, 0xab, 0x7a, 0x64, 0xd3, 0x63, 0x79, + 0x72, 0x80, 0x1b, 0xde, 0x72, 0xcc, 0x87, 0xad, 0xcd, 0xe5, 0x66, 0x05, + 0xdc, 0x90, 0x86, 0xde, 0x9d, 0xdb, 0x7d, 0x85, 0x09, 0x36, 0x4a, 0x04, + 0xdc, 0xe7, 0x79, 0x76, 0xda, 0x79, 0xfa, 0xf2, 0xe7, 0xa2, 0xb7, 0x0b, + 0x8b, 0x7e, 0xbb, 0x5d, 0xda, 0x2c, 0xa6, 0xe4, 0x20, 0x3d, 0xe5, 0x24, + 0x2e, 0xaa, 0x01, 0x07, 0x8c, 0x69, 0xa8, 0x2f, 0x45, 0x53, 0x29, 0xd4, + 0x3a, 0x8a, 0x7b, 0xc8, 0x45, 0x07, 0xd0, 0xa2, 0x9b, 0x43, 0x9a, 0x69, + 0x73, 0x1b, 0xaa, 0x55, 0x8a, 0x80, 0x11, 0x28, 0x0b, 0x9b, 0x4c, 0x03, + 0x2f, 0x88, 0x9e, 0x38, 0x57, 0x83, 0x63, 0xdf, 0xca, 0xc2, 0x5d, 0x95, + 0xba, 0xbc, 0x82, 0x10, 0x05, 0x3e, 0x44, 0x00, 0x87, 0x2e, 0x7a, 0x29, + 0x71, 0xa1, 0xbb, 0x9b, 0xc9, 0xd8, 0x7d, 0xc7, 0xe5, 0x08, 0xbe, 0x52, + 0xca, 0xdc, 0xc8, 0xbf, 0x4b, 0xef, 0x89, 0x06, 0xd2, 0xa7, 0x2b, 0x14, + 0x24, 0xa8, 0xde, 0xc7, 0x6c, 0x8e, 0x15, 0x24, 0x2c, 0x27, 0x05, 0x80, + 0x0c, 0x4e, 0x6c, 0x1d, 0xed, 0xe7, 0x8f, 0x3c, 0x81, 0x0b, 0xc4, 0xb4, + 0x0a, 0x56, 0x4d, 0x34, 0x3a, 0x56, 0xfc, 0x87, 0xe3, 0xdd, 0x4c, 0xe6, + 0xc3, 0xf3, 0x0d, 0xb8, 0x90, 0xb2, 0x91, 0x5b, 0xef, 0x8e, 0x78, 0xa0, + 0x40, 0xfd, 0x31, 0x60, 0x0f, 0x3b, 0xd7, 0x28, 0x0f, 0x77, 0x97, 0x72, + 0x36, 0x96, 0x57, 0x92, 0xb7, 0xc6, 0x5d, 0xef, 0x99, 0xaf, 0x7f, 0x0f, + 0x2c, 0xbc, 0xfc, 0x29, 0xdb, 0x49, 0xa5, 0xb5, 0x5e, 0xd9, 0x9f, 0xf2, + 0x38, 0x8e, 0x39, 0xb2, 0x06, 0x3b, 0x9e, 0x66, 0x68, 0xe0, 0xd1, 0xa1, + 0x2c, 0x17, 0xb5, 0xbc, 0xb1, 0xb2, 0x37, 0xfd, 0x08, 0xfb, 0x71, 0xdb, + 0xf7, 0xe0, 0x5c, 0xb1, 0x01, 0x14, 0x01, 0x39, 0x2e, 0x59, 0x65, 0xf1, + 0x66, 0xff, 0x60, 0xb7, 0x67, 0xc7, 0xbd, 0xcc, 0x4a, 0x08, 0x80, 0x09, + 0xb6, 0x24, 0xb5, 0x42, 0x46, 0xb7, 0xce, 0x00, 0x09, 0xb6, 0x80, 0x2d, + 0x00, 0x75, 0xef, 0xaf, 0xa1, 0x86, 0x88, 0x73, 0xec, 0x4a, 0x14, 0x3a, + 0x84, 0x37, 0xd0, 0xfd, 0xb2, 0xf6, 0xee, 0x6c, 0x4a, 0x02, 0xad, 0x2b, + 0x14, 0x20, 0x73, 0x74, 0x94, 0x03, 0x46, 0xec, 0x0c, 0x6f, 0xd4, 0xdd, + 0x27, 0xda, 0x6b, 0x3e, 0x53, 0x35, 0xb0, 0xe0, 0x05, 0x36, 0xb5, 0xd2, + 0x93, 0xa5, 0x24, 0xb5, 0xc6, 0x51, 0xbb, 0x9d, 0x5b, 0x0e, 0x01, 0x89, + 0x09, 0x2d, 0x44, 0x86, 0x56, 0xa7, 0x0a, 0x67, 0x19, 0x37, 0xbc, 0x9a, + 0xd7, 0x4a, 0x5b, 0x62, 0x9f, 0x9c, 0x6d, 0x54, 0x3a, 0x56, 0x6c, 0xdb, + 0xe2, 0xf0, 0x08, 0x40, 0x13, 0x15, 0xab, 0x00, 0x9f, 0x61, 0x25, 0xb3, + 0x00, 0xe0, 0x9c, 0x84, 0xb6, 0xdc, 0xab, 0x76, 0x40, 0xa5, 0xcb, 0xb2, + 0x10, 0x9a, 0x20, 0x75, 0xb0, 0x94, 0xc1, 0xd6, 0xb7, 0xdb, 0x77, 0xe6, + 0x21, 0x2d, 0xbe, 0x20, 0x00, 0xaf, 0x8a, 0x00, 0x4d, 0x04, 0x7d, 0x39, + 0x9b, 0x0e, 0xaa, 0xf7, 0x3a, 0xf9, 0x58, 0x30, 0x3a, 0x6d, 0x54, 0x29, + 0xbe, 0x99, 0xf0, 0xf7, 0x7b, 0xb8, 0xde, 0x70, 0xa2, 0x8b, 0x2e, 0x85, + 0x37, 0x75, 0xcf, 0xa4, 0x0d, 0xd7, 0x4a, 0x19, 0x6c, 0x8b, 0x15, 0xb8, + 0xee, 0xa7, 0xb7, 0x20, 0x03, 0xe6, 0xc2, 0xd4, 0xe2, 0xd6, 0xff, 0x23, + 0x73, 0x2a, 0x9f, 0xe0, 0xb1, 0xbe, 0x90, 0x2b, 0x8d, 0xe7, 0xad, 0xdd, + 0xcd, 0xa0, 0x2a, 0xda, 0xb1, 0x02, 0x0a, 0xa7, 0x04, 0x2d, 0x6f, 0xa4, + 0x80, 0x21, 0xfb, 0x80, 0x58, 0x29, 0xce, 0xaf, 0xc8, 0x54, 0x36, 0xad, + 0x1a, 0xdb, 0x88, 0xbf, 0x5d, 0x12, 0x00, 0xf7, 0x67, 0x31, 0x3f, 0x59, + 0x32, 0x01, 0x03, 0x6b, 0x72, 0x89, 0x70, 0x05, 0xbc, 0xc4, 0xf5, 0x87, + 0xb6, 0x3c, 0xcf, 0x3d, 0x84, 0xb8, 0xdf, 0x24, 0x01, 0xcf, 0x1b, 0xf5, + 0xeb, 0x70, 0x8d, 0xe7, 0x40, 0x05, 0x35, 0x2c, 0xaf, 0x74, 0x3a, 0x24, + 0xb4, 0x7b, 0x79, 0x72, 0x2f, 0x00, 0x06, 0x9f, 0x51, 0x46, 0xe3, 0xa5, + 0x28, 0x39, 0x1d, 0x6b, 0xed, 0x52, 0xcf, 0x48, 0x5c, 0x6f, 0x42, 0x00, + 0xfa, 0x8a, 0xfe, 0x77, 0x66, 0x73, 0x65, 0x96, 0x13, 0x24, 0xab, 0x4b, + 0x1f, 0x03, 0x0f, 0x6f, 0x2a, 0x08, 0x00, 0x5b, 0xf5, 0xe3, 0x91, 0x35, + 0xfd, 0x7b, 0x29, 0xd2, 0xe5, 0xda, 0x04, 0x15, 0x9b, 0x2c, 0x0c, 0x28, + 0x63, 0x77, 0x5a, 0x95, 0x6b, 0x69, 0xb4, 0x38, 0xda, 0x4b, 0x6f, 0x18, + 0x03, 0x97, 0x67, 0xc8, 0x97, 0x71, 0xc7, 0xb2, 0x1c, 0x5c, 0x73, 0x89, + 0xa8, 0x34, 0xb6, 0xf9, 0x29, 0x1f, 0x8e, 0x40, 0x1d, 0x5f, 0xa3, 0xed, + 0xc3, 0xae, 0x5d, 0x9c, 0x3b, 0x26, 0xc8, 0x7c, 0x3c, 0xc2, 0xdb, 0xe8, + 0x40, 0x05, 0x9e, 0xfd, 0x88, 0xfe, 0x40, 0x0a, 0xf3, 0xe2, 0x55, 0xe2, + 0x93, 0xb8, 0xe2, 0x07, 0xbd, 0xf3, 0x4c, 0x45, 0xa1, 0x0d, 0xe7, 0x6f, + 0x45, 0x4e, 0x84, 0x6c, 0x15, 0xaf, 0x7e, 0x57, 0x64, 0x44, 0xd8, 0xf9, + 0xa5, 0x6e, 0x5f, 0x52, 0xdb, 0x93, 0x97, 0x5f, 0x28, 0x96, 0xc1, 0x95, + 0x62, 0x2b, 0x48, 0xb8, 0x1c, 0x55, 0x60, 0x00, 0x00, 0x01, 0x07, 0x43, + 0xf9, 0xef, 0xbc, 0xbd, 0xf1, 0x2e, 0xf8, 0x28, 0xda, 0x7b, 0x6b, 0xe9, + 0xf8, 0x44, 0xed, 0xfc, 0xf3, 0xe1, 0x2d, 0x92, 0x40, 0xa6, 0xf6, 0xa0, + 0x0f, 0xc5, 0x69, 0x17, 0xdb, 0x08, 0xe2, 0x62, 0x0d, 0x41, 0x5b, 0xd5, + 0x93, 0x9b, 0x03, 0xaf, 0xe7, 0x16, 0x20, 0x4b, 0x5c, 0x08, 0x1f, 0x9e, + 0x44, 0xe0, 0x01, 0x87, 0xff, 0xdf, 0xe2, 0x0a, 0xdb, 0x0a, 0xf3, 0xdb, + 0xc6, 0xba, 0xcd, 0x87, 0x00, 0x4f, 0xc0, 0x49, 0x54, 0xa0, 0xc6, 0xf2, + 0xec, 0xb9, 0x6b, 0x78, 0xef, 0x94, 0x3e, 0x56, 0xfe, 0x39, 0x92, 0x3b, + 0x12, 0x4f, 0x09, 0x1b, 0x66, 0x82, 0x17, 0xfc, 0xcd, 0x6c, 0xfc, 0xca, + 0x55, 0xb0, 0x25, 0xbd, 0x28, 0x98, 0x4f, 0x17, 0xb4, 0xb0, 0xa7, 0xbb, + 0x10, 0x30, 0xf5, 0xb2, 0xdf, 0x4a, 0xdc, 0x96, 0x1b, 0x91, 0xb0, 0xd8, + 0xb1, 0xbb, 0xc4, 0x69, 0x3f, 0xe7, 0x93, 0x00, 0x06, 0x90, 0xb4, 0x08, + 0x6f, 0x99, 0x4f, 0xd4, 0x21, 0x15, 0x00, 0xa8, 0xdf, 0x53, 0x13, 0x6b, + 0xf2, 0xcc, 0x50, 0x11, 0x66, 0x2a, 0x8d, 0x3e, 0xc0, 0x29, 0xbe, 0x64, + 0xf2, 0xab, 0xa9, 0x2a, 0xc6, 0xde, 0xc2, 0xca, 0x21, 0xab, 0x69, 0x43, + 0xeb, 0x7e, 0xc0, 0x52, 0x91, 0xf6, 0xe9, 0x9a, 0x03, 0xca, 0x61, 0x55, + 0xbd, 0x30, 0x9d, 0x04, 0x1f, 0xeb, 0x22, 0x0a, 0xa0, 0x15, 0x8e, 0x88, + 0x64, 0x35, 0x40, 0x21, 0x30, 0xb0, 0xb2, 0x9b, 0xc2, 0xcf, 0xc9, 0xab, + 0xe1, 0x36, 0xb7, 0xd3, 0xa3, 0x9e, 0x00, 0xff, 0xb7, 0xc3, 0xc3, 0x2c, + 0x77, 0x2e, 0x31, 0x22, 0x9c, 0x66, 0x9f, 0xe2, 0xb2, 0x36, 0xce, 0x2b, + 0x6c, 0x80, 0x03, 0x36, 0xb3, 0x9b, 0xbc, 0x8e, 0x47, 0xe9, 0xc0, 0x0f, + 0x40, 0x1a, 0x64, 0xf6, 0x75, 0xa1, 0xe7, 0xf0, 0x2e, 0x5e, 0xf3, 0x4e, + 0x54, 0xb1, 0x56, 0xa1, 0x47, 0x14, 0xad, 0xf1, 0xaf, 0xfb, 0xf8, 0x14, + 0x67, 0x13, 0x75, 0x28, 0x09, 0x40, 0x0f, 0xbc, 0xaf, 0x39, 0x07, 0x15, + 0x12, 0x4d, 0xa3, 0xcb, 0x18, 0xde, 0xfb, 0xe0, 0xc1, 0x5e, 0xd9, 0xd3, + 0xf6, 0x86, 0x43, 0x70, 0xf1, 0x84, 0xc2, 0x9b, 0xca, 0xce, 0x5e, 0x00, + 0xe8, 0x50, 0x8e, 0x44, 0xbf, 0x27, 0xea, 0x4a, 0x2f, 0xcf, 0xbc, 0x83, + 0x40, 0x71, 0xc6, 0xc8, 0x64, 0xa0, 0x2a, 0x88, 0x5b, 0x72, 0x24, 0xb8, + 0xe5, 0xf5, 0x91, 0xaa, 0x07, 0xc8, 0xdf, 0x8e, 0xe3, 0x2b, 0x85, 0xbe, + 0xdc, 0x1e, 0x92, 0x6c, 0x83, 0x42, 0x80, 0xb6, 0xe8, 0x80, 0x34, 0xf8, + 0x9d, 0xf2, 0xf5, 0xf3, 0x79, 0x6a, 0x6d, 0x2e, 0xad, 0x03, 0x9b, 0x97, + 0x92, 0x7b, 0x3b, 0xaf, 0x30, 0x08, 0x67, 0x7e, 0x7b, 0x02, 0xe1, 0xb2, + 0xd9, 0xe1, 0x1b, 0x36, 0x6c, 0xc9, 0x69, 0x41, 0x76, 0x92, 0x9b, 0xbe, + 0xd6, 0xde, 0xd4, 0x8d, 0xfb, 0x2e, 0x1c, 0x00, 0x6e, 0x2b, 0xcb, 0xac, + 0x41, 0xa9, 0xb1, 0xd6, 0xca, 0x36, 0xd2, 0xcf, 0x2d, 0x91, 0x2c, 0xd7, + 0xa9, 0x61, 0x13, 0x99, 0x7d, 0x43, 0x1b, 0x86, 0x46, 0x80, 0x16, 0xf7, + 0x75, 0x02, 0x2b, 0xf6, 0x44, 0x1f, 0x5b, 0xd4, 0x13, 0x45, 0x3e, 0xdc, + 0x09, 0xb8, 0xaa, 0x10, 0x74, 0x89, 0x59, 0xb7, 0x58, 0x04, 0xea, 0xda, + 0x77, 0x63, 0xf3, 0x26, 0xe8, 0x64, 0x27, 0xb9, 0xda, 0x50, 0xd3, 0xb6, + 0xc3, 0xe0, 0x50, 0xd6, 0xeb, 0x79, 0x80, 0x1d, 0x80, 0x59, 0x2d, 0x1a, + 0x51, 0x3e, 0x7c, 0x73, 0x74, 0x34, 0x3a, 0xba, 0xd4, 0xb0, 0x21, 0xb9, + 0x50, 0xcf, 0x7b, 0xb5, 0x7c, 0x33, 0x6e, 0x6c, 0x01, 0x10, 0xdb, 0x60, + 0x51, 0x8c, 0xee, 0xd2, 0x7c, 0xfb, 0x97, 0x00, 0x45, 0xe6, 0xe5, 0x38, + 0x08, 0x54, 0x0e, 0x2c, 0x09, 0x6b, 0x6d, 0x87, 0x36, 0xd4, 0xbb, 0x57, + 0xd6, 0x52, 0x9b, 0xaa, 0xe5, 0xe1, 0xc2, 0xf7, 0x02, 0xcc, 0xdd, 0x4b, + 0x02, 0xcc, 0x1a, 0xdc, 0xf1, 0x33, 0x78, 0xdc, 0xcc, 0x41, 0xcf, 0x8f, + 0xf2, 0xb0, 0xbf, 0x16, 0x5e, 0x26, 0x10, 0x66, 0x3f, 0x03, 0x0f, 0xb5, + 0x4b, 0x2a, 0x9e, 0x31, 0xa5, 0xba, 0x1b, 0x7e, 0xb1, 0x61, 0x9a, 0x16, + 0x08, 0x5f, 0xf0, 0xbb, 0x84, 0x34, 0x29, 0xb5, 0xd9, 0x05, 0xd7, 0x62, + 0x06, 0xa1, 0x3a, 0xe4, 0x21, 0x2e, 0x36, 0x7e, 0xd1, 0xdc, 0x73, 0xc7, + 0x3a, 0x80, 0x4d, 0xc5, 0x26, 0x69, 0xf4, 0xf3, 0xa5, 0x95, 0xb7, 0xe5, + 0xbb, 0xc5, 0x72, 0x51, 0xa5, 0xc4, 0xee, 0xb8, 0x02, 0x23, 0x1e, 0x70, + 0x5c, 0x66, 0xd0, 0xdf, 0x89, 0x16, 0x68, 0xaa, 0x21, 0x22, 0x84, 0x8a, + 0xb8, 0x6a, 0x8f, 0x0c, 0x6a, 0xce, 0xd3, 0x0f, 0x1a, 0xb2, 0x2d, 0x6f, + 0x4e, 0x2b, 0x34, 0x01, 0xe0, 0xb8, 0xe7, 0xb8, 0x22, 0xed, 0x76, 0xc2, + 0xd4, 0x72, 0xcb, 0x03, 0x1b, 0xc5, 0x7c, 0x75, 0xce, 0xf4, 0x7e, 0xd0, + 0xa2, 0xca, 0xa5, 0xc2, 0xa8, 0xe8, 0xca, 0xb7, 0x9b, 0x43, 0xae, 0x12, + 0x1b, 0xfa, 0xe7, 0xfb, 0xb0, 0x41, 0xfc, 0xf2, 0x38, 0x03, 0xec, 0xe3, + 0x6c, 0x1d, 0x2b, 0xf8, 0xaf, 0x2d, 0x42, 0x30, 0x94, 0xdf, 0xb3, 0x9d, + 0xaa, 0xaa, 0xdf, 0xcf, 0x3d, 0x9b, 0xdb, 0xec, 0x8a, 0x02, 0x2d, 0x38, + 0x7b, 0x7e, 0xb4, 0x00, 0x6d, 0x01, 0x07, 0xf6, 0x3f, 0x84, 0x77, 0xe0, + 0x25, 0x00, 0x25, 0xec, 0xd9, 0x00, 0x47, 0x06, 0xb5, 0x40, 0xf6, 0xa8, + 0x1e, 0xdf, 0xd9, 0x78, 0x03, 0x2d, 0xa1, 0xc5, 0x56, 0xe4, 0xe0, 0x19, + 0xc4, 0x66, 0xe0, 0x0c, 0x5a, 0xdb, 0xb6, 0xed, 0xea, 0xe2, 0x99, 0x1b, + 0x99, 0xc7, 0xe1, 0xb9, 0x62, 0x2c, 0x96, 0x49, 0xb6, 0x0d, 0x8b, 0x1b, + 0x8f, 0xf6, 0xd0, 0x03, 0xcf, 0x77, 0xe4, 0x99, 0x4f, 0x9b, 0x2c, 0x59, + 0xb2, 0xc0, 0xa6, 0x50, 0xaa, 0xd1, 0x2a, 0x37, 0xeb, 0x05, 0x02, 0x17, + 0xfb, 0xa6, 0xcf, 0x41, 0xad, 0xea, 0x25, 0x36, 0x54, 0x6f, 0xce, 0xdf, + 0xcf, 0x69, 0xae, 0x14, 0xe5, 0xc5, 0x39, 0xe2, 0xe0, 0xb7, 0x38, 0xd2, + 0xbf, 0x15, 0x2c, 0xda, 0x75, 0xb0, 0x69, 0x71, 0xbe, 0xde, 0x20, 0x10, + 0x80, 0x2f, 0xdd, 0xf3, 0xd6, 0x22, 0xb6, 0x3c, 0x5f, 0x37, 0x16, 0x42, + 0x65, 0x29, 0xb8, 0x5b, 0x78, 0x09, 0x97, 0xa0, 0x4d, 0x00, 0x34, 0x6d, + 0xbd, 0xc4, 0x14, 0x2f, 0x41, 0x30, 0x01, 0x26, 0x94, 0xde, 0x2c, 0x8d, + 0xd0, 0x05, 0x62, 0x3d, 0x95, 0xda, 0x1b, 0x39, 0xe3, 0x69, 0x70, 0xe3, + 0x8b, 0x29, 0xbd, 0x58, 0x80, 0x0a, 0x75, 0xcf, 0x2c, 0x26, 0x6b, 0x96, + 0x90, 0x95, 0xa7, 0x8d, 0x97, 0x87, 0xca, 0x00, 0x34, 0x2f, 0xd1, 0x2b, + 0x10, 0x99, 0x54, 0x84, 0xdf, 0x3c, 0x01, 0xb8, 0x9c, 0xf2, 0xae, 0x97, + 0x1d, 0x16, 0xd7, 0xcc, 0x40, 0x1c, 0xc5, 0xba, 0x70, 0xf6, 0xf3, 0x7c, + 0x7f, 0x2d, 0xf9, 0xf8, 0x13, 0x7d, 0xa5, 0x01, 0xe3, 0xf1, 0xe8, 0x56, + 0x54, 0x45, 0x5c, 0x2d, 0x1a, 0xcf, 0x8d, 0x22, 0x00, 0x3a, 0xfb, 0xe5, + 0x15, 0xd8, 0xbc, 0x2a, 0xcb, 0xaf, 0x4b, 0x32, 0xf0, 0xf8, 0x6c, 0x83, + 0x4e, 0x1a, 0xde, 0x4c, 0x10, 0x00, 0xb0, 0x48, 0x01, 0xb0, 0x05, 0xb7, + 0xdf, 0x38, 0xd8, 0xb5, 0x09, 0xd8, 0x4d, 0xba, 0x93, 0x15, 0x5b, 0xe7, + 0xf3, 0xd9, 0xfc, 0x98, 0x6d, 0x90, 0x71, 0xc3, 0x4e, 0x18, 0x1a, 0x48, + 0x6c, 0x77, 0x2d, 0x8a, 0xad, 0xfb, 0x80, 0x07, 0x4b, 0xc7, 0x66, 0xf0, + 0xfc, 0x0c, 0xb3, 0x1e, 0x51, 0x44, 0x8a, 0xde, 0x64, 0x00, 0xb3, 0xdf, + 0x8f, 0x61, 0x78, 0x6f, 0x1d, 0xe4, 0x2d, 0x2c, 0xd8, 0x53, 0xcc, 0x0e, + 0xb5, 0xbe, 0x32, 0xff, 0x69, 0x40, 0x1e, 0x57, 0x3b, 0x1d, 0x4a, 0xbb, + 0x26, 0xe3, 0xcf, 0xee, 0x87, 0xe2, 0x4a, 0x74, 0x30, 0xe4, 0x6e, 0x50, + 0x00, 0x9f, 0x8c, 0x7a, 0x0a, 0xe9, 0xc3, 0x00, 0x2d, 0x7c, 0xc9, 0x6d, + 0xfc, 0x5b, 0x2d, 0x92, 0x51, 0xaa, 0x53, 0x7d, 0x01, 0x93, 0x55, 0x20, + 0x1b, 0x6e, 0xae, 0x64, 0xa4, 0xc8, 0xdf, 0xa6, 0xe0, 0x8b, 0xf6, 0x23, + 0x7d, 0x3d, 0xba, 0xf6, 0x78, 0xbf, 0x25, 0xf2, 0xdd, 0xa8, 0xbb, 0xa3, + 0x64, 0x5a, 0x52, 0xa4, 0x29, 0xa8, 0xfb, 0x00, 0x3b, 0x7e, 0x76, 0x41, + 0xef, 0xd9, 0xcf, 0x92, 0xcf, 0x37, 0x87, 0x2f, 0x94, 0x87, 0x59, 0x14, + 0x62, 0xb7, 0x91, 0x82, 0x7e, 0xae, 0xc3, 0x7e, 0x66, 0x4c, 0x2f, 0x05, + 0x3a, 0x19, 0x34, 0xad, 0xa6, 0x94, 0x70, 0xc6, 0xf5, 0x60, 0x09, 0x67, + 0x42, 0xdf, 0xb1, 0xdf, 0x3a, 0xa1, 0xd4, 0x6d, 0x44, 0x90, 0xba, 0x3c, + 0x73, 0x59, 0x6d, 0xd0, 0x13, 0x5b, 0xec, 0xfb, 0x08, 0xe9, 0xd9, 0xdd, + 0x10, 0x00, 0xf4, 0x5e, 0x5b, 0x2e, 0x3f, 0x45, 0xc0, 0x45, 0x00, 0x6d, + 0xb4, 0xd2, 0x6a, 0x9e, 0x50, 0xf6, 0xf2, 0x1f, 0x40, 0x07, 0xe2, 0xfa, + 0x4c, 0x00, 0x3e, 0x14, 0xe9, 0x25, 0x9e, 0xce, 0xc2, 0x91, 0xd0, 0x37, + 0xd6, 0x8f, 0x6e, 0x6f, 0xf5, 0xf9, 0xcf, 0x0e, 0xf3, 0x88, 0x04, 0x3b, + 0x9c, 0xd2, 0x61, 0xb1, 0x52, 0x98, 0xa5, 0x29, 0xfe, 0x8d, 0xb8, 0x00, + 0x4e, 0xe7, 0x0b, 0xda, 0x65, 0x45, 0xb8, 0x1d, 0x0d, 0x54, 0x55, 0x21, + 0x2b, 0x38, 0xc3, 0x00, 0x00, 0x00, 0x01, 0x08, 0x43, 0xf3, 0xc0, 0x0f, + 0xbd, 0x85, 0x00, 0x3b, 0xfb, 0x8a, 0xeb, 0x9e, 0x5c, 0x74, 0x97, 0xca, + 0x4d, 0xd3, 0x21, 0x32, 0x45, 0x52, 0xbd, 0x20, 0xe6, 0xfb, 0x10, 0x20, + 0x01, 0x6b, 0xaf, 0xd7, 0xa9, 0xcf, 0xd1, 0xd7, 0x6f, 0xee, 0x72, 0x65, + 0xdc, 0x86, 0x87, 0x4a, 0xa5, 0x15, 0xe2, 0xdf, 0x0a, 0x7d, 0xf3, 0xb2, + 0x44, 0x1c, 0x51, 0x48, 0xde, 0x82, 0x6d, 0x7c, 0x6e, 0x51, 0xf5, 0xbc, + 0xa2, 0xa5, 0x2d, 0xbe, 0x71, 0x1e, 0xdf, 0x61, 0x7d, 0x2a, 0xc3, 0xe6, + 0xaf, 0x56, 0x13, 0xd6, 0x1d, 0xf9, 0x88, 0x77, 0x8c, 0x6d, 0x54, 0x0c, + 0x20, 0x26, 0xff, 0xdd, 0x80, 0x02, 0xd2, 0x43, 0x6a, 0xd5, 0x73, 0xb5, + 0xef, 0x50, 0xa9, 0x13, 0x50, 0x23, 0x56, 0x95, 0x42, 0x47, 0x35, 0xdf, + 0x34, 0x50, 0x03, 0x7f, 0xb7, 0xd8, 0x4b, 0x9e, 0xa3, 0x2a, 0x89, 0xc0, + 0xba, 0x55, 0xbb, 0x4a, 0x0b, 0x2d, 0xb9, 0x6d, 0x5b, 0x2b, 0x03, 0x29, + 0x24, 0x0e, 0x6f, 0xd2, 0x80, 0x3b, 0x50, 0x05, 0x7f, 0xcf, 0x8d, 0xc3, + 0x87, 0x76, 0xfd, 0x93, 0x89, 0x60, 0x23, 0xff, 0xed, 0xfd, 0x46, 0xf8, + 0x80, 0xb3, 0x40, 0x1e, 0x09, 0xf8, 0xb4, 0x2e, 0x68, 0x8d, 0x14, 0xfb, + 0x01, 0x28, 0x01, 0x75, 0xc4, 0x86, 0xfd, 0xa9, 0xbd, 0xf9, 0x80, 0x3b, + 0xef, 0x9b, 0x68, 0xeb, 0x7b, 0x73, 0xf7, 0x38, 0x48, 0x5a, 0x07, 0x5b, + 0x0e, 0x38, 0x75, 0x6f, 0xca, 0x42, 0xaf, 0x3f, 0xce, 0xbf, 0xef, 0xb6, + 0x86, 0x71, 0x2d, 0x11, 0xed, 0x31, 0xc3, 0x49, 0xae, 0xe1, 0x57, 0x42, + 0x54, 0x63, 0x68, 0x4c, 0x90, 0x0b, 0x62, 0xd2, 0xdb, 0xf1, 0x6e, 0xa4, + 0xfb, 0x25, 0x8d, 0xf7, 0xd7, 0x72, 0xf7, 0x38, 0x01, 0xef, 0x74, 0x5b, + 0xb0, 0x65, 0xe0, 0x57, 0xcf, 0x7d, 0xee, 0x45, 0x3c, 0x08, 0x40, 0x08, + 0x13, 0x1b, 0xe4, 0xc0, 0x0f, 0xd4, 0x01, 0x18, 0x03, 0xef, 0xa7, 0x28, + 0x17, 0x5f, 0x6f, 0x19, 0x07, 0x1f, 0x29, 0x70, 0x2a, 0xa3, 0x7e, 0x94, + 0x00, 0x5b, 0x98, 0x23, 0x9e, 0x70, 0x50, 0x9e, 0x60, 0xc0, 0xfe, 0x37, + 0x62, 0x43, 0xec, 0x2c, 0x30, 0x2d, 0xbc, 0x1e, 0x85, 0x51, 0x06, 0x3f, + 0x98, 0xa1, 0x97, 0xf4, 0xad, 0x89, 0x86, 0x1f, 0xea, 0x31, 0xbf, 0xcf, + 0x40, 0x0f, 0xe6, 0x70, 0xfd, 0xb2, 0x51, 0xf4, 0xdb, 0x64, 0x8d, 0xc9, + 0xf7, 0xec, 0x00, 0xf1, 0xd6, 0xed, 0x81, 0xb1, 0x68, 0xc8, 0xdd, 0xe1, + 0x58, 0x00, 0x65, 0xe6, 0xf2, 0xf2, 0x9e, 0x4c, 0x96, 0xac, 0xf0, 0x6f, + 0x9f, 0x09, 0x9d, 0x09, 0xf8, 0x5a, 0x90, 0x25, 0xda, 0x1d, 0x29, 0xf0, + 0x6b, 0x75, 0x82, 0x1f, 0xfd, 0x4d, 0x84, 0x2a, 0xc2, 0x1a, 0xad, 0xe1, + 0xf9, 0x2f, 0xb8, 0xf4, 0x0a, 0xd7, 0x64, 0x56, 0x5e, 0x6d, 0xcc, 0x7f, + 0x25, 0x86, 0xcb, 0x76, 0x44, 0x90, 0x2a, 0x01, 0xed, 0xde, 0x7e, 0xa0, + 0xb7, 0xdf, 0x4a, 0x38, 0x29, 0x98, 0x4d, 0x37, 0xad, 0x76, 0xcf, 0x16, + 0xeb, 0x90, 0xb2, 0x9b, 0x5c, 0x1a, 0xdf, 0x8e, 0xe5, 0x5c, 0x6d, 0xa8, + 0x14, 0xb2, 0x7a, 0xd2, 0xdb, 0xd6, 0xc7, 0xcf, 0x9a, 0x92, 0xd0, 0xbd, + 0x76, 0xec, 0xd0, 0xa8, 0xb5, 0x4a, 0x0c, 0xaa, 0xd8, 0xbb, 0x80, 0x16, + 0x53, 0x37, 0x65, 0x0b, 0xa3, 0x42, 0xda, 0x02, 0x1f, 0xfd, 0x66, 0x3e, + 0x50, 0xab, 0x72, 0x12, 0x49, 0x05, 0xb6, 0xf9, 0xf9, 0x8d, 0xd7, 0x00, + 0x29, 0x6f, 0x4c, 0xd2, 0x78, 0xb1, 0x49, 0x02, 0x56, 0xbf, 0x0a, 0xb0, + 0x24, 0x63, 0x59, 0xde, 0xcf, 0x2b, 0x2b, 0xd4, 0x00, 0x53, 0x04, 0x41, + 0x4e, 0xb6, 0x82, 0x3f, 0xfe, 0x64, 0xa0, 0x51, 0xed, 0x97, 0x6d, 0xcd, + 0xdd, 0x93, 0x46, 0x95, 0x9c, 0x19, 0x36, 0x8d, 0xa5, 0x9a, 0x51, 0x61, + 0x2d, 0xd8, 0xee, 0x00, 0x1e, 0xbb, 0xaa, 0xf7, 0x0f, 0xae, 0x97, 0x33, + 0x5e, 0xf0, 0xc3, 0xd6, 0x15, 0x09, 0x2d, 0xd0, 0xdd, 0xc3, 0x9b, 0xaf, + 0xac, 0xa4, 0x5c, 0xba, 0x96, 0x45, 0x59, 0xba, 0x31, 0xba, 0x1c, 0xbe, + 0x6f, 0x9e, 0xdc, 0x00, 0x85, 0xdb, 0x0d, 0x42, 0x8e, 0x09, 0x6a, 0x74, + 0x9f, 0xf2, 0xfc, 0xe5, 0xd6, 0x86, 0xa7, 0x46, 0x50, 0xf0, 0x11, 0x9e, + 0x5b, 0x0a, 0xaf, 0xfb, 0xf5, 0x24, 0x09, 0x8f, 0xb2, 0x10, 0xe8, 0xca, + 0xd0, 0xda, 0x9e, 0xd8, 0xc4, 0xf9, 0xef, 0xa4, 0x08, 0x5d, 0x29, 0x14, + 0x2a, 0x36, 0xfb, 0x40, 0x2b, 0x17, 0xc7, 0x21, 0xe1, 0x16, 0x64, 0x73, + 0xe0, 0x5e, 0xfe, 0xa0, 0x59, 0x4d, 0x57, 0x69, 0xf6, 0x13, 0x9c, 0x72, + 0x81, 0x69, 0x13, 0x40, 0xea, 0xd4, 0x67, 0x37, 0xdb, 0x1e, 0xed, 0xd0, + 0x4a, 0xff, 0x9c, 0xca, 0x58, 0x40, 0xef, 0x05, 0x6b, 0x64, 0xde, 0x8a, + 0xbc, 0xc7, 0xd9, 0x14, 0x08, 0xdb, 0x9e, 0xf2, 0x4a, 0x30, 0x07, 0x33, + 0x88, 0x96, 0x85, 0x37, 0x87, 0xc8, 0x68, 0x8f, 0x6c, 0x7e, 0x84, 0xdb, + 0x68, 0x7a, 0x04, 0x23, 0x7d, 0x02, 0x82, 0x10, 0x03, 0x89, 0xf6, 0xc9, + 0x94, 0x12, 0x3f, 0xf7, 0x1d, 0x39, 0x77, 0x8e, 0x19, 0xb2, 0x90, 0xdb, + 0xe6, 0x8f, 0x90, 0x57, 0xd7, 0xae, 0x65, 0x0a, 0xc1, 0x56, 0x1a, 0xa7, + 0x9f, 0x06, 0xc0, 0xb6, 0x88, 0x53, 0x71, 0xd0, 0x30, 0x53, 0x7e, 0xe9, + 0xe9, 0xd1, 0x1c, 0x5e, 0x3b, 0xc7, 0x83, 0x16, 0xdf, 0x46, 0xf7, 0x9f, + 0xc8, 0x08, 0x3f, 0x95, 0xcf, 0xf8, 0x4a, 0x50, 0x49, 0xff, 0xde, 0x2c, + 0x80, 0x96, 0x00, 0x65, 0x12, 0x5b, 0xe0, 0x62, 0xac, 0x77, 0x9e, 0xdc, + 0x83, 0x12, 0x4a, 0x54, 0xf0, 0x6f, 0xb7, 0x7b, 0xc0, 0x41, 0xfc, 0x40, + 0x01, 0x16, 0x20, 0x04, 0x37, 0x99, 0x28, 0x59, 0x8b, 0x69, 0x29, 0xad, + 0x4e, 0x24, 0xb6, 0x14, 0xba, 0xdf, 0xec, 0x25, 0x41, 0xbe, 0x8a, 0xde, + 0x30, 0x01, 0xf3, 0xc1, 0x04, 0x06, 0x40, 0x1f, 0xfc, 0x8a, 0x77, 0x8d, + 0xe1, 0xf5, 0x60, 0x08, 0xaa, 0x07, 0xc0, 0xa6, 0xf5, 0x90, 0xaa, 0x00, + 0x2e, 0x6f, 0xcb, 0xe0, 0x0f, 0x90, 0x10, 0x00, 0xeb, 0x8e, 0x3e, 0xba, + 0x09, 0x7f, 0xf7, 0x49, 0xce, 0xa3, 0x0e, 0xb4, 0x9b, 0xe3, 0x0e, 0x6d, + 0x4e, 0xad, 0xbc, 0x29, 0x5b, 0xf0, 0x00, 0x0c, 0x3d, 0xba, 0x7f, 0xdb, + 0x8c, 0xf8, 0xce, 0x20, 0xfd, 0xe7, 0x7c, 0xa6, 0x2d, 0x0d, 0x39, 0xac, + 0xff, 0x0a, 0xe1, 0xfd, 0x57, 0xd7, 0xe4, 0x91, 0x77, 0x5f, 0xb9, 0x61, + 0xb6, 0xda, 0x87, 0xa0, 0xe0, 0x96, 0xe0, 0x89, 0xf2, 0xe4, 0xd8, 0xb5, + 0x00, 0x95, 0x1c, 0xad, 0xab, 0xce, 0x80, 0x3b, 0x00, 0x32, 0xc1, 0x5b, + 0x2c, 0x04, 0x6f, 0xfa, 0x7f, 0x91, 0x98, 0x34, 0x9a, 0x6d, 0x89, 0x02, + 0xdb, 0xcf, 0x44, 0x76, 0xda, 0x42, 0x46, 0xe5, 0xb0, 0x39, 0x5b, 0xfd, + 0x1f, 0xf7, 0xea, 0x82, 0x07, 0xe7, 0xf1, 0x08, 0x9e, 0xd7, 0x06, 0x79, + 0x79, 0xce, 0x57, 0xbc, 0x1c, 0x1d, 0x83, 0x2d, 0x6e, 0xf8, 0x03, 0x2e, + 0x78, 0x00, 0x4d, 0xce, 0x6f, 0x9d, 0x0c, 0x80, 0x3d, 0x0b, 0x0c, 0x87, + 0xb7, 0x8d, 0x04, 0x00, 0x2a, 0x73, 0xc0, 0x1b, 0x39, 0xef, 0xf9, 0x17, + 0x69, 0x6b, 0x99, 0xca, 0xd3, 0x62, 0xd3, 0x6c, 0x50, 0x96, 0xf9, 0xd8, + 0xae, 0x35, 0xdf, 0x13, 0x20, 0x8b, 0x85, 0xa6, 0x4c, 0x45, 0x8b, 0x36, + 0xae, 0x97, 0x7c, 0x5b, 0x67, 0xd8, 0x6b, 0xf7, 0x69, 0x08, 0xa6, 0xea, + 0xe4, 0xbb, 0xb6, 0xd0, 0x29, 0xbf, 0xa5, 0x80, 0x17, 0x7d, 0x4d, 0xf7, + 0xbb, 0xf3, 0xc3, 0xb9, 0x8a, 0x86, 0xa0, 0xc9, 0x85, 0x17, 0x10, 0xf3, + 0xc3, 0x15, 0xbc, 0x68, 0x03, 0x22, 0x37, 0x5d, 0x7b, 0x0a, 0x70, 0x05, + 0xbe, 0xd6, 0x93, 0x79, 0x78, 0xdd, 0x32, 0x40, 0xf1, 0xc5, 0x2b, 0x64, + 0x00, 0x71, 0xf6, 0xe6, 0x7b, 0xc5, 0x78, 0x9d, 0xb0, 0x9b, 0x77, 0x6a, + 0xdd, 0x58, 0x92, 0x14, 0x10, 0x34, 0xb6, 0xe6, 0x00, 0x36, 0x23, 0x70, + 0x66, 0x2d, 0xef, 0x6f, 0xed, 0xdc, 0x21, 0xd9, 0x0f, 0xa5, 0x86, 0xb2, + 0x7e, 0xd7, 0xf3, 0xbb, 0xb7, 0xc5, 0xb7, 0x7d, 0x37, 0x6d, 0xad, 0xf5, + 0xba, 0x00, 0x39, 0xde, 0x65, 0xdd, 0xe7, 0x30, 0x10, 0xc0, 0x18, 0x50, + 0xa7, 0x18, 0x92, 0xe6, 0xed, 0x1a, 0xef, 0xd5, 0x8d, 0x90, 0x01, 0xe7, + 0x64, 0x77, 0x89, 0xc5, 0xf6, 0x32, 0xd0, 0xff, 0x67, 0x47, 0x48, 0x90, + 0x83, 0x4d, 0xd8, 0x4b, 0xad, 0xe6, 0xc5, 0x3a, 0x74, 0x22, 0x4e, 0x84, + 0x70, 0x34, 0xd9, 0xc6, 0x7e, 0xf6, 0xd3, 0x82, 0x9a, 0xe7, 0xed, 0x79, + 0x8f, 0x5e, 0x72, 0xa2, 0xb8, 0xcd, 0x28, 0x98, 0x1c, 0x3a, 0x94, 0x06, + 0xdb, 0x48, 0xda, 0xd6, 0xfb, 0xa4, 0x4e, 0x05, 0x70, 0x46, 0xda, 0xef, + 0x7a, 0xfc, 0x53, 0x04, 0xf2, 0xf9, 0x0e, 0x98, 0x52, 0x87, 0xc8, 0x3e, + 0xd6, 0x6f, 0x60, 0x07, 0xa4, 0x71, 0x3d, 0xe6, 0xbf, 0x8c, 0x53, 0x03, + 0xac, 0xb1, 0x46, 0x14, 0x54, 0x1d, 0x06, 0xb7, 0x20, 0x00, 0xf7, 0xa7, + 0x77, 0xb1, 0xd3, 0x99, 0x8a, 0x82, 0xf4, 0x80, 0xbe, 0x72, 0xca, 0x38, + 0xa3, 0xe1, 0xde, 0xad, 0x97, 0xd9, 0xe2, 0xfd, 0xf9, 0x90, 0xc9, 0x46, + 0xa9, 0xb5, 0x10, 0xc8, 0x04, 0x1e, 0xa3, 0x98, 0xf1, 0x66, 0xdf, 0xa3, + 0x00, 0x58, 0xef, 0x97, 0x59, 0xcf, 0xd7, 0xdd, 0xfb, 0x4e, 0x99, 0x6a, + 0x80, 0xe3, 0x0f, 0x38, 0x61, 0x4d, 0xc0, 0xae, 0xeb, 0x32, 0xb8, 0x43, + 0xa1, 0x45, 0x16, 0x91, 0x0b, 0x0a, 0x6c, 0xde, 0xcb, 0x4c, 0x20, 0x4c, + 0x39, 0x74, 0xa8, 0x56, 0x8e, 0xf0, 0x02, 0xdb, 0xa7, 0xf1, 0x9c, 0xc7, + 0x50, 0x0b, 0x7b, 0xda, 0x74, 0x2e, 0xa2, 0xc7, 0x43, 0xd9, 0xc6, 0x6d, + 0xf9, 0xf3, 0x74, 0xcc, 0x36, 0x62, 0x8d, 0xa6, 0x1e, 0x8a, 0x58, 0x6b, + 0x27, 0x79, 0x5f, 0x83, 0x69, 0xe1, 0x65, 0x56, 0xee, 0x7c, 0xba, 0x8b, + 0xd9, 0x72, 0x00, 0x45, 0x98, 0x61, 0x67, 0x31, 0x7d, 0xe0, 0x57, 0xbd, + 0x58, 0x13, 0xb0, 0xeb, 0x3d, 0x51, 0x15, 0x86, 0x55, 0x80, 0x00, 0x00, + 0x01, 0x09, 0x43, 0xf1, 0xf9, 0x49, 0xf9, 0x85, 0x04, 0xad, 0x6e, 0xaf, + 0x32, 0x6e, 0x16, 0xdf, 0x2a, 0x77, 0x52, 0x11, 0xf8, 0xb7, 0x60, 0xe5, + 0x32, 0xc8, 0x58, 0xc2, 0xca, 0x4a, 0xa1, 0x2d, 0xf6, 0xba, 0x47, 0x22, + 0x00, 0x2d, 0x00, 0x7d, 0xbb, 0xbc, 0xdd, 0x4b, 0x49, 0xdd, 0x88, 0xe6, + 0x07, 0x2e, 0x07, 0xc3, 0xa5, 0x1a, 0x8d, 0xe5, 0xb8, 0xa6, 0xf3, 0x55, + 0x5b, 0xc0, 0xf7, 0x49, 0xde, 0xf0, 0x42, 0x36, 0x4b, 0xe0, 0xb6, 0x2b, + 0x6f, 0x73, 0xf4, 0x51, 0x1c, 0x01, 0xe7, 0xdb, 0x9a, 0x13, 0x7b, 0xf9, + 0x15, 0x1c, 0x4f, 0x04, 0x80, 0x03, 0xdd, 0x2f, 0x8a, 0x15, 0x0e, 0xa7, + 0xb7, 0xa8, 0x16, 0x45, 0xf6, 0xfa, 0x11, 0x4d, 0xf8, 0x82, 0xcc, 0x36, + 0xe6, 0xbf, 0x2f, 0x95, 0x55, 0x86, 0x7e, 0xad, 0x3d, 0x4b, 0x90, 0x21, + 0xba, 0x22, 0x7b, 0xa0, 0x0f, 0xbe, 0x9f, 0x77, 0x73, 0xc5, 0x8f, 0x7f, + 0x2f, 0x7d, 0x9b, 0x1f, 0xb1, 0xfa, 0xfd, 0x44, 0x43, 0xca, 0x8e, 0x0b, + 0x56, 0xe7, 0x75, 0xf2, 0xa3, 0x02, 0xab, 0x2d, 0x44, 0x6f, 0xd8, 0x73, + 0xae, 0x23, 0x7f, 0x04, 0xee, 0x3e, 0x00, 0x0a, 0x5d, 0xcf, 0x4b, 0x38, + 0xc9, 0x03, 0xc0, 0x4b, 0x0a, 0x43, 0x0a, 0xad, 0xf0, 0x40, 0x03, 0xb8, + 0xe7, 0xf9, 0xfb, 0x58, 0x7a, 0x6d, 0xd9, 0x9b, 0x57, 0x07, 0x15, 0x8a, + 0x6d, 0x0a, 0x46, 0xfd, 0x0f, 0xf4, 0x16, 0x00, 0x6b, 0xc7, 0xff, 0xb1, + 0x51, 0xf2, 0x9f, 0x78, 0xcd, 0x00, 0xb7, 0x6e, 0x53, 0xa9, 0x34, 0x3e, + 0x9b, 0x0e, 0x1b, 0x1b, 0xf2, 0x63, 0xe4, 0x11, 0x82, 0xa4, 0x80, 0x94, + 0x00, 0x66, 0x52, 0x51, 0x25, 0x9e, 0x16, 0xab, 0x3d, 0x23, 0x48, 0x0e, + 0x35, 0xbf, 0xae, 0x08, 0xfa, 0xb8, 0x10, 0x3f, 0x2c, 0x4e, 0x8b, 0xe3, + 0xbb, 0x40, 0x8e, 0x3e, 0x38, 0xeb, 0x88, 0xf9, 0xb0, 0xf0, 0xf7, 0xed, + 0xab, 0x14, 0x32, 0x14, 0xdf, 0x50, 0xf9, 0xf8, 0xc0, 0x02, 0x8e, 0x1c, + 0xe8, 0xb0, 0x11, 0xff, 0xee, 0xdb, 0x69, 0x60, 0x3c, 0x58, 0x52, 0x12, + 0x5b, 0xf2, 0xfe, 0x80, 0x53, 0x5b, 0xf4, 0x38, 0x03, 0xc7, 0xc0, 0x04, + 0xff, 0xe1, 0x7f, 0xdf, 0xb4, 0xc8, 0x08, 0xc0, 0x0a, 0xb4, 0x0c, 0xa6, + 0x07, 0x50, 0x1c, 0xd1, 0x88, 0x58, 0xd1, 0xb5, 0xb9, 0x75, 0x1d, 0xd3, + 0xf5, 0x7c, 0x21, 0x49, 0x4e, 0x1f, 0x5b, 0x38, 0x5b, 0xae, 0xcf, 0x04, + 0x3d, 0xbf, 0xce, 0x9f, 0x71, 0x0f, 0x00, 0x2e, 0xfb, 0xbb, 0x1d, 0x65, + 0x01, 0xe6, 0xbc, 0x46, 0xbb, 0x60, 0xca, 0x58, 0x45, 0x25, 0xb7, 0xce, + 0x3a, 0xe8, 0x02, 0xbe, 0xdc, 0x4f, 0x2c, 0x62, 0xc3, 0x15, 0xbf, 0x5c, + 0x00, 0x30, 0x17, 0xa0, 0x80, 0x05, 0x59, 0xef, 0xff, 0x16, 0x22, 0x4f, + 0xd7, 0x5c, 0x3d, 0xc8, 0x66, 0xd4, 0x27, 0x9d, 0x4d, 0x8b, 0x50, 0x68, + 0xd6, 0xfc, 0xd0, 0xfa, 0xf1, 0x7f, 0x24, 0x67, 0x71, 0x21, 0xd9, 0x5e, + 0x4f, 0xec, 0xc9, 0x93, 0x21, 0x74, 0x3c, 0x74, 0x6e, 0x82, 0x6f, 0x3b, + 0xa8, 0x43, 0xad, 0xa2, 0x96, 0xb5, 0xbc, 0x8f, 0xeb, 0x1c, 0x22, 0x47, + 0x64, 0xf5, 0x3e, 0xda, 0xa3, 0x4b, 0x6b, 0x08, 0xce, 0x00, 0x33, 0xf7, + 0x9b, 0x25, 0x0c, 0xaf, 0x32, 0x19, 0x46, 0xb7, 0xa7, 0x42, 0x01, 0xaf, + 0x7c, 0xb8, 0x03, 0xde, 0x79, 0x93, 0x80, 0xa2, 0xb2, 0x0c, 0x81, 0xa5, + 0xd6, 0xc1, 0xf7, 0x37, 0x0a, 0x44, 0x3d, 0x4a, 0x87, 0x86, 0x00, 0xd5, + 0x96, 0x4b, 0xae, 0x46, 0x4a, 0x52, 0xb7, 0xd0, 0xec, 0x5e, 0x11, 0xb8, + 0x7e, 0xbf, 0xac, 0x2c, 0xad, 0xe7, 0x1f, 0x93, 0x8b, 0x76, 0xa3, 0x8f, + 0x8a, 0x51, 0x94, 0xb4, 0x2b, 0x0f, 0x8d, 0xc0, 0xe6, 0x68, 0x19, 0xca, + 0x9e, 0x25, 0x29, 0x29, 0xb0, 0xf1, 0x28, 0xa1, 0x6e, 0xb7, 0x72, 0x06, + 0x45, 0x58, 0x9e, 0x10, 0x68, 0x4b, 0x52, 0x46, 0xcc, 0x7b, 0xb6, 0xe2, + 0x50, 0xab, 0x0a, 0x02, 0xeb, 0x5d, 0x87, 0x2d, 0xf5, 0x6d, 0xcf, 0xa0, + 0x5b, 0x7d, 0x61, 0x6b, 0xcd, 0xe2, 0xd9, 0x2f, 0x83, 0xf0, 0xaa, 0x10, + 0x31, 0xb7, 0xe4, 0xc8, 0x47, 0x94, 0xde, 0x02, 0xb5, 0xfb, 0x2e, 0x5b, + 0x16, 0x9d, 0xa0, 0x5b, 0x69, 0x23, 0x7e, 0x7b, 0x23, 0x75, 0xbb, 0x29, + 0xd0, 0xbf, 0x7f, 0x3b, 0x4b, 0x0c, 0x30, 0xda, 0x7b, 0x61, 0xd9, 0x39, + 0x14, 0x23, 0x70, 0xc8, 0x55, 0x31, 0xd4, 0xc7, 0x1c, 0x4c, 0x51, 0x81, + 0x67, 0xb7, 0xa0, 0x32, 0xb7, 0xa2, 0x8a, 0x8d, 0xea, 0xf6, 0xcb, 0xe5, + 0x78, 0xd8, 0xa7, 0xd2, 0xd5, 0xd2, 0x1c, 0x58, 0xe1, 0xed, 0xb7, 0x87, + 0xf9, 0x11, 0x95, 0x50, 0x72, 0x6e, 0x17, 0xa3, 0x09, 0x88, 0x31, 0xb9, + 0x76, 0x1b, 0xf3, 0x9b, 0x54, 0x05, 0x77, 0x8d, 0xc2, 0xe1, 0x30, 0x71, + 0xfe, 0xad, 0xd2, 0x17, 0x40, 0x0e, 0x05, 0xbe, 0x97, 0x46, 0x9a, 0x6b, + 0xb3, 0x32, 0x94, 0x04, 0x50, 0xf2, 0xef, 0x8c, 0x29, 0x93, 0x6e, 0xde, + 0x5c, 0xc2, 0x7f, 0x34, 0x9d, 0x81, 0x92, 0x72, 0xfc, 0x9b, 0x47, 0x0d, + 0x28, 0xf0, 0x98, 0xce, 0x45, 0x7c, 0xe8, 0x00, 0xfe, 0x1a, 0x19, 0x49, + 0xce, 0xe4, 0xc4, 0xd8, 0x1b, 0x64, 0xcb, 0x4a, 0x0d, 0x62, 0xe7, 0xef, + 0x59, 0xef, 0xbb, 0x25, 0x1c, 0x82, 0xf4, 0xc9, 0x29, 0xe3, 0x92, 0x92, + 0x1b, 0x1c, 0x33, 0xe1, 0xfd, 0xdb, 0x40, 0x47, 0xe6, 0xe5, 0x51, 0x83, + 0x0d, 0x18, 0x10, 0xd4, 0xd2, 0x73, 0x74, 0x08, 0x96, 0x71, 0x45, 0xe4, + 0xd4, 0x1c, 0x4f, 0x3f, 0x21, 0xd7, 0xc5, 0xb1, 0xdd, 0xa0, 0x0e, 0xbe, + 0x9d, 0x63, 0xed, 0x0d, 0xb3, 0xcf, 0x75, 0x29, 0xe3, 0xf7, 0x6c, 0xf4, + 0xb5, 0x97, 0x94, 0xb9, 0x66, 0x1b, 0xe2, 0x05, 0x1c, 0xdd, 0x5e, 0x45, + 0xc7, 0x6f, 0xe6, 0x4a, 0x59, 0x53, 0x75, 0x4c, 0x1e, 0x70, 0x4d, 0x61, + 0xa6, 0x95, 0x1b, 0xf1, 0x9e, 0xf2, 0x89, 0x99, 0x32, 0xca, 0x39, 0x43, + 0x4e, 0x6f, 0xd3, 0x1f, 0xde, 0xb4, 0x10, 0x3f, 0x2f, 0xee, 0xe2, 0x37, + 0xb7, 0xbc, 0xa5, 0xe6, 0xf5, 0x9d, 0xfb, 0x6b, 0xf5, 0xf9, 0x4f, 0x85, + 0xe5, 0x92, 0x2d, 0x09, 0x2d, 0xbe, 0x46, 0x6c, 0x9b, 0x23, 0xcb, 0x19, + 0x85, 0x86, 0x96, 0x88, 0xa5, 0x37, 0xbf, 0xff, 0x3b, 0x8c, 0x00, 0x79, + 0x77, 0xe3, 0xa1, 0x14, 0xf0, 0x0b, 0x45, 0xba, 0xd5, 0x79, 0xa6, 0xc9, + 0x61, 0x45, 0xda, 0x07, 0xb6, 0x67, 0xa4, 0x6c, 0x39, 0x45, 0x8d, 0xfd, + 0xc4, 0x00, 0xb0, 0x01, 0xf8, 0x8f, 0x6b, 0xcf, 0x9b, 0xaa, 0x5b, 0x16, + 0x21, 0x52, 0x7e, 0xc6, 0xc1, 0x90, 0xf1, 0xad, 0xf9, 0x59, 0x1d, 0xf1, + 0xf6, 0xf8, 0xf8, 0xf6, 0x99, 0x49, 0x86, 0xee, 0x75, 0xc6, 0x61, 0xb7, + 0x2d, 0x5a, 0xbb, 0x0f, 0xda, 0x79, 0xf5, 0xbb, 0xc2, 0xa0, 0x92, 0x7e, + 0xbf, 0x90, 0x0b, 0x61, 0x44, 0xed, 0x26, 0xe5, 0x91, 0xd9, 0x52, 0x69, + 0x95, 0x0b, 0x2e, 0x84, 0x56, 0xc9, 0xd8, 0xae, 0x45, 0x2e, 0x0a, 0x7c, + 0xb4, 0x9b, 0x15, 0x20, 0xfa, 0x6d, 0x2c, 0x28, 0xe6, 0xd2, 0x15, 0x1b, + 0x4d, 0xa5, 0x14, 0xdf, 0x3f, 0x9f, 0x3d, 0x89, 0xba, 0x87, 0x41, 0xaa, + 0x56, 0x0d, 0x56, 0xdf, 0x95, 0xf3, 0xdf, 0x2b, 0xf3, 0x68, 0xc7, 0x60, + 0xc9, 0x4b, 0x38, 0xaa, 0x71, 0x4d, 0x9f, 0xa9, 0x39, 0xdc, 0x5c, 0x29, + 0x7f, 0x57, 0x52, 0xdd, 0x42, 0x9b, 0xa5, 0x9d, 0x3f, 0x7e, 0x2c, 0xb7, + 0x61, 0x41, 0xd0, 0xa8, 0x54, 0x54, 0x0d, 0x38, 0x29, 0xa1, 0xb5, 0xab, + 0x4f, 0x6f, 0x3f, 0xd3, 0x89, 0xd7, 0x55, 0xe4, 0xed, 0xe7, 0x69, 0x35, + 0x06, 0x59, 0x22, 0x97, 0x4b, 0xfd, 0xb2, 0x74, 0x21, 0xf2, 0x45, 0x7d, + 0x50, 0xa3, 0xea, 0xa0, 0xf6, 0xe8, 0xfd, 0x44, 0x65, 0xe8, 0x07, 0x2f, + 0x55, 0xa6, 0xae, 0x52, 0xb1, 0x0a, 0x46, 0xe1, 0x3d, 0xdc, 0x60, 0xbf, + 0x38, 0x6c, 0x28, 0xf3, 0x0a, 0x85, 0x94, 0x3e, 0x56, 0x43, 0x19, 0xb7, + 0xaa, 0xf3, 0x79, 0xcc, 0x9c, 0x61, 0x94, 0xab, 0x62, 0x0c, 0x0a, 0x6d, + 0x80, 0x64, 0x59, 0x1b, 0x88, 0xe7, 0xec, 0x3c, 0x9d, 0x9c, 0xd7, 0xda, + 0xba, 0x8a, 0x34, 0x6b, 0x73, 0x5d, 0xd9, 0x07, 0xbd, 0xbc, 0xb8, 0xa2, + 0xee, 0x63, 0xae, 0x07, 0x5a, 0x85, 0x1e, 0x87, 0xd1, 0x8c, 0x80, 0x07, + 0xd1, 0xde, 0xd3, 0x9c, 0x2c, 0xb5, 0x58, 0x34, 0xb2, 0xe4, 0x0a, 0x8c, + 0xda, 0x63, 0x7d, 0xd1, 0x22, 0xc8, 0x9a, 0xec, 0xd3, 0x0d, 0x01, 0xc7, + 0x2f, 0xe4, 0xe8, 0x1f, 0x28, 0xcd, 0x81, 0x03, 0x55, 0xba, 0x93, 0xfe, + 0xff, 0x6b, 0xce, 0xcd, 0xef, 0x64, 0xd9, 0x8f, 0x9b, 0x2e, 0xdb, 0x38, + 0xc3, 0xe2, 0x0e, 0x29, 0xb8, 0x3f, 0x7e, 0x48, 0xc2, 0x3b, 0xd9, 0xb2, + 0xd3, 0xea, 0xef, 0x26, 0xe4, 0xae, 0x42, 0x8a, 0xa7, 0xdf, 0x02, 0x9b, + 0x3f, 0x26, 0x7c, 0xf4, 0x23, 0x5e, 0x3a, 0x4e, 0x21, 0xa9, 0x6c, 0xb4, + 0x62, 0x4a, 0x1a, 0xc0, 0xd6, 0x8c, 0x4b, 0x95, 0xbc, 0x4f, 0xde, 0x5c, + 0xec, 0x82, 0xde, 0xe2, 0xe9, 0x8e, 0x9c, 0xad, 0xa9, 0x87, 0xd2, 0x1b, + 0x5b, 0xee, 0x88, 0x92, 0xc8, 0x78, 0xd3, 0x88, 0x4d, 0xdf, 0x13, 0x3a, + 0xff, 0x7c, 0xe5, 0x76, 0x65, 0x4a, 0x1e, 0x9e, 0x56, 0x22, 0xd0, 0x21, + 0x07, 0x8f, 0x6f, 0x3b, 0xb6, 0x39, 0xef, 0xf2, 0x33, 0xc7, 0x24, 0xd4, + 0x38, 0x2d, 0x93, 0x69, 0x2a, 0xca, 0xda, 0x71, 0x6c, 0x7b, 0xf5, 0x42, + 0x92, 0x0f, 0x85, 0x46, 0xd9, 0xfc, 0xe7, 0x9f, 0x7e, 0x46, 0x0e, 0x48, + 0x5d, 0x64, 0x7e, 0xdf, 0x9c, 0x97, 0x8d, 0x94, 0x62, 0x1b, 0x84, 0xb4, + 0xa7, 0x05, 0x36, 0x98, 0xfb, 0xa2, 0x5d, 0x73, 0x85, 0xa3, 0x69, 0xea, + 0x50, 0x71, 0xd5, 0x88, 0xcd, 0xb4, 0x23, 0x3a, 0xf1, 0x96, 0x1b, 0xb2, + 0x04, 0x0e, 0x87, 0xfa, 0xb6, 0x67, 0xe4, 0xd7, 0x3a, 0x79, 0x50, 0xc3, + 0x12, 0x97, 0xbe, 0x07, 0x33, 0xba, 0x51, 0x1d, 0x24, 0x7d, 0x1d, 0xaf, + 0xd4, 0x2c, 0xe6, 0xe6, 0xcc, 0x9e, 0x7a, 0xb4, 0x26, 0xca, 0x7a, 0x50, + 0x1e, 0xb3, 0x8d, 0x6c, 0x00, 0x00, 0x01, 0x0a, 0x43, 0xf9, 0x00, 0x03, + 0xbf, 0xe0, 0xb1, 0x5c, 0x93, 0xba, 0x30, 0x72, 0x79, 0xf1, 0x4d, 0x53, + 0xac, 0x3e, 0x58, 0x53, 0x6f, 0xf9, 0x99, 0xc9, 0x1e, 0xf5, 0x2c, 0x80, + 0x4f, 0x96, 0xd8, 0xba, 0x81, 0x8a, 0x39, 0xbd, 0x28, 0x03, 0x87, 0xb8, + 0x8c, 0x29, 0xd6, 0xe4, 0x09, 0xdf, 0x3b, 0xaf, 0xa5, 0xa1, 0xf1, 0x55, + 0x21, 0xc3, 0x1b, 0xce, 0x08, 0xcf, 0x21, 0x4b, 0x2f, 0x8c, 0x6f, 0x1b, + 0x70, 0x9e, 0x4f, 0x8e, 0x50, 0x9c, 0xb1, 0x15, 0xbc, 0x74, 0x1c, 0xde, + 0xd0, 0xee, 0xf1, 0xd3, 0x20, 0x66, 0x61, 0x44, 0xda, 0x15, 0x21, 0x55, + 0xbd, 0x68, 0x03, 0xc7, 0xf1, 0xd7, 0x98, 0xbd, 0x4a, 0x7d, 0x97, 0x97, + 0xbe, 0xee, 0x97, 0x22, 0x42, 0xa8, 0xc8, 0x14, 0xde, 0x14, 0x9b, 0xce, + 0xad, 0x6b, 0x76, 0x51, 0x69, 0x90, 0x28, 0xa3, 0xda, 0x21, 0x52, 0x52, + 0x5b, 0x46, 0x1f, 0x15, 0xbf, 0xa0, 0x7b, 0x25, 0x11, 0xdf, 0x61, 0x20, + 0x13, 0xfe, 0x22, 0x14, 0x58, 0x70, 0xd2, 0xdb, 0xca, 0xda, 0x01, 0x53, + 0xdd, 0xb6, 0x20, 0xc2, 0xe7, 0x8b, 0x71, 0x04, 0x3a, 0x0a, 0xe6, 0x6e, + 0xec, 0x0d, 0x59, 0x12, 0x4f, 0x14, 0xad, 0xba, 0x02, 0x17, 0xfd, 0x3b, + 0x69, 0x2e, 0x92, 0x58, 0x2a, 0xd8, 0xa4, 0x26, 0xac, 0x2b, 0x15, 0xbf, + 0xb6, 0x80, 0x3b, 0x00, 0x5f, 0xec, 0x00, 0x5f, 0xfc, 0x8f, 0xe2, 0x74, + 0xa8, 0x4f, 0xc1, 0x62, 0x35, 0x61, 0x97, 0x13, 0x72, 0x9e, 0x10, 0xdf, + 0x6e, 0x11, 0xff, 0xe7, 0xa0, 0x06, 0x6f, 0xe5, 0xeb, 0xa3, 0x39, 0x79, + 0x97, 0x64, 0xa8, 0x9c, 0x5c, 0x59, 0x07, 0xb7, 0xe4, 0xfe, 0xf9, 0x00, + 0x35, 0xf6, 0x9c, 0xf9, 0xa4, 0x2e, 0x90, 0x3a, 0x49, 0x3b, 0xe4, 0x71, + 0x46, 0xd2, 0xa4, 0x3d, 0xbd, 0x0f, 0xfb, 0xed, 0x9f, 0x04, 0x70, 0x0a, + 0xfe, 0x05, 0x6d, 0x2f, 0xf2, 0x41, 0x5f, 0xc6, 0x61, 0x84, 0x0c, 0xcf, + 0xc2, 0x55, 0xb8, 0x78, 0x63, 0x67, 0xd3, 0xcc, 0xdf, 0x3b, 0x6a, 0x0f, + 0x74, 0x58, 0x81, 0x6d, 0xae, 0x5b, 0xa5, 0xd5, 0x0a, 0x6f, 0x9e, 0x2b, + 0x9a, 0x00, 0xf8, 0x8d, 0x9c, 0x65, 0x5b, 0x57, 0x79, 0x47, 0x48, 0x5d, + 0x55, 0x1a, 0x4a, 0x6f, 0x00, 0x2d, 0x61, 0x91, 0x47, 0x42, 0xc7, 0x48, + 0x51, 0xed, 0xea, 0xf5, 0xdc, 0x00, 0x3a, 0xec, 0x8a, 0x44, 0xec, 0x9f, + 0x00, 0x05, 0x3d, 0x90, 0x33, 0xbe, 0x6e, 0x69, 0xf0, 0x38, 0xb3, 0x2a, + 0x78, 0x94, 0xde, 0x0b, 0xfd, 0x40, 0x2d, 0xd7, 0xeb, 0x90, 0x35, 0x2e, + 0xd5, 0x83, 0x08, 0x4d, 0x35, 0x76, 0x54, 0xb0, 0x30, 0x29, 0xb0, 0xb0, + 0xb6, 0xfa, 0x36, 0xd7, 0xc8, 0xf9, 0x7d, 0x0a, 0xa0, 0x6d, 0xae, 0x27, + 0x10, 0x04, 0xdc, 0x40, 0x85, 0xb1, 0x5b, 0x81, 0xd6, 0x00, 0x19, 0x59, + 0x9a, 0xf0, 0x9b, 0x04, 0xcb, 0x81, 0x87, 0x05, 0xb6, 0x5f, 0xa7, 0x40, + 0x16, 0x08, 0x13, 0xcc, 0x81, 0x31, 0x0c, 0x84, 0xba, 0xdb, 0x4b, 0xe6, + 0xb2, 0x90, 0xd9, 0xd8, 0x39, 0xba, 0x78, 0x80, 0x07, 0xc2, 0x1d, 0x32, + 0xbe, 0x06, 0xcd, 0x47, 0x86, 0x0c, 0x94, 0x69, 0xe1, 0x8d, 0xbb, 0xdc, + 0xd0, 0x03, 0x9a, 0x40, 0x2a, 0xa5, 0x86, 0xe2, 0x26, 0xcf, 0x0d, 0x96, + 0x51, 0xc1, 0x8d, 0x92, 0xd7, 0xfd, 0x76, 0x0a, 0xc7, 0x28, 0xcc, 0x0f, + 0xe7, 0x22, 0x3e, 0x87, 0x43, 0xf4, 0x60, 0x62, 0x16, 0x5b, 0x6b, 0x22, + 0x6d, 0xf6, 0x23, 0x47, 0x62, 0x5a, 0xb6, 0xd8, 0x2b, 0xa8, 0xe9, 0xb7, + 0x76, 0x97, 0x4d, 0xd5, 0xb6, 0x90, 0xdb, 0x3f, 0xd4, 0x25, 0xb6, 0xd4, + 0xb6, 0xef, 0x32, 0x47, 0x45, 0x2c, 0xa3, 0xb3, 0xbd, 0x2b, 0x68, 0x1f, + 0x0a, 0x66, 0xe3, 0x00, 0x0f, 0xa1, 0x39, 0xf4, 0x6a, 0x20, 0x7e, 0x4a, + 0xa8, 0x70, 0xd5, 0x0d, 0x6b, 0x26, 0x5f, 0xbb, 0xf3, 0x64, 0xa1, 0x8b, + 0x5d, 0xbb, 0x2c, 0x08, 0x92, 0x17, 0xe0, 0xd4, 0xb9, 0xcb, 0xce, 0xf7, + 0x14, 0x24, 0x81, 0x66, 0x42, 0x13, 0x77, 0x40, 0x32, 0xa0, 0x5b, 0x7a, + 0x50, 0x0c, 0xcd, 0x24, 0xd6, 0xcb, 0xb5, 0x63, 0x9d, 0x28, 0x61, 0xb9, + 0xdb, 0xb0, 0xc8, 0x83, 0x07, 0x1e, 0x16, 0xdd, 0xb7, 0xe0, 0x00, 0x92, + 0xbd, 0xd2, 0x3a, 0xcf, 0xd0, 0x09, 0x2d, 0xa8, 0x7c, 0x58, 0x89, 0x14, + 0x22, 0xa3, 0x73, 0xfb, 0xb7, 0xdc, 0x40, 0x99, 0x2d, 0x01, 0x54, 0x9a, + 0x85, 0x1c, 0x37, 0x29, 0xc3, 0x4e, 0x6f, 0x57, 0xd7, 0x90, 0x8f, 0x81, + 0x62, 0x5d, 0xcb, 0xac, 0x01, 0x27, 0x90, 0xbc, 0xa9, 0x03, 0xd6, 0x02, + 0x27, 0xfe, 0x5b, 0x22, 0xf8, 0x28, 0xf6, 0xdd, 0xba, 0x23, 0x7c, 0xad, + 0xef, 0x7d, 0x9e, 0x27, 0x8c, 0xb9, 0x07, 0xee, 0xd7, 0x73, 0xbc, 0xef, + 0xe8, 0xe8, 0xa5, 0x7a, 0x37, 0x93, 0xd3, 0x45, 0x66, 0x27, 0x28, 0x19, + 0x6e, 0x6f, 0x9c, 0x18, 0x32, 0xd6, 0xd9, 0x78, 0x82, 0x81, 0x0b, 0xfe, + 0xab, 0xa0, 0xc2, 0xe5, 0x2a, 0xd2, 0x11, 0x5e, 0x25, 0xb6, 0x9c, 0xe5, + 0xef, 0x15, 0xaa, 0xe7, 0x02, 0x40, 0x01, 0x9b, 0xbb, 0x5f, 0xa1, 0x45, + 0x1c, 0x16, 0xc3, 0x4a, 0x23, 0x71, 0xdb, 0xbd, 0xbd, 0x79, 0x96, 0xd2, + 0x63, 0xb2, 0x3e, 0x2c, 0xb2, 0xd3, 0x51, 0x26, 0xf8, 0xb7, 0x4c, 0x49, + 0x31, 0xca, 0x65, 0x29, 0x10, 0xe4, 0xb1, 0x47, 0x35, 0x3f, 0x5e, 0x9f, + 0xc9, 0x75, 0x21, 0x72, 0xfe, 0xa2, 0xae, 0x12, 0xa8, 0xc6, 0xeb, 0xba, + 0xce, 0xc5, 0xde, 0x7a, 0xb4, 0x11, 0xbf, 0xf3, 0x75, 0xcf, 0x92, 0xcc, + 0xc0, 0xe8, 0x54, 0xab, 0x0b, 0x69, 0x67, 0x0f, 0xad, 0xd1, 0x9d, 0xed, + 0x17, 0x97, 0xbe, 0x86, 0xdc, 0x29, 0x4a, 0xbf, 0xaa, 0x36, 0x1c, 0x53, + 0x59, 0xed, 0xf1, 0x1c, 0xf7, 0xef, 0x1d, 0xc9, 0x40, 0x73, 0xb7, 0x56, + 0x3a, 0x64, 0x18, 0x16, 0x59, 0x61, 0x8d, 0x9c, 0x51, 0x05, 0xdd, 0x4a, + 0x27, 0x98, 0x34, 0x3a, 0xf2, 0xa9, 0x91, 0x0a, 0x2b, 0x00, 0xb6, 0x5d, + 0xef, 0x51, 0x5d, 0x62, 0x14, 0x4e, 0x92, 0xd2, 0xb1, 0xc7, 0xda, 0x58, + 0xe5, 0x0c, 0x66, 0xca, 0x16, 0x73, 0x7d, 0x22, 0x27, 0x09, 0x9a, 0x27, + 0xdf, 0x4d, 0x28, 0xb9, 0xba, 0xa8, 0x64, 0x2c, 0xe2, 0x8a, 0x88, 0x53, + 0x5b, 0xf5, 0xe2, 0x68, 0x18, 0x15, 0x24, 0xfd, 0x43, 0x6e, 0xd4, 0x43, + 0xb7, 0x16, 0x0e, 0x29, 0x5b, 0x17, 0x5b, 0x78, 0x78, 0x19, 0xe5, 0x3f, + 0x75, 0xcb, 0xbb, 0x46, 0x28, 0xd8, 0x73, 0x65, 0x8e, 0x77, 0x22, 0xb7, + 0x4d, 0x86, 0x0d, 0xbb, 0x6a, 0x98, 0x30, 0x60, 0x4b, 0x26, 0x1b, 0xb3, + 0xe1, 0xfa, 0x2b, 0xf2, 0x26, 0xa9, 0x52, 0xec, 0xda, 0x76, 0x49, 0x10, + 0x86, 0x31, 0xb4, 0xdf, 0x67, 0xfb, 0xbd, 0xf3, 0x5f, 0xaa, 0x52, 0x47, + 0xd9, 0x09, 0x67, 0x34, 0xde, 0x54, 0x4c, 0xb7, 0x28, 0x4e, 0x43, 0xc0, + 0x7c, 0xd6, 0x71, 0xa4, 0xe9, 0x76, 0xc8, 0xa7, 0x93, 0x6c, 0x98, 0xb4, + 0xb1, 0xb0, 0x74, 0x69, 0x6d, 0x02, 0x5b, 0xbb, 0xd8, 0x52, 0x71, 0xaf, + 0xbc, 0xc5, 0x50, 0xec, 0x94, 0xa8, 0x8a, 0x94, 0xb9, 0x3c, 0x5b, 0x95, + 0xc8, 0xb7, 0x0a, 0x7d, 0x97, 0x31, 0x0e, 0xb2, 0x3a, 0xa9, 0x91, 0x4b, + 0x29, 0x61, 0x5e, 0xac, 0xc4, 0xfa, 0x2a, 0x41, 0x83, 0x2e, 0x9a, 0x92, + 0x0e, 0x1e, 0x48, 0x6d, 0xdf, 0x63, 0x5f, 0x7b, 0xe6, 0xeb, 0xf7, 0x4f, + 0x9f, 0x89, 0x46, 0x42, 0x8b, 0x96, 0x8c, 0x60, 0xf6, 0x84, 0xb2, 0x9c, + 0xde, 0x5d, 0xdd, 0xf9, 0x85, 0xad, 0x9f, 0xa8, 0xa7, 0x59, 0xfa, 0x0c, + 0x1a, 0x16, 0xd7, 0xf3, 0xf3, 0xc7, 0x1c, 0xc9, 0x3a, 0xe0, 0x6d, 0xb5, + 0xd8, 0xb0, 0xe0, 0xc4, 0x6a, 0xba, 0x92, 0x45, 0x3e, 0x9e, 0x62, 0x42, + 0xfc, 0x4f, 0x6c, 0x1c, 0x3e, 0xf2, 0x65, 0x48, 0x75, 0x42, 0xe8, 0xd8, + 0x54, 0x61, 0x8d, 0x39, 0xbf, 0x5b, 0xf3, 0xce, 0x77, 0xf0, 0x27, 0x20, + 0x91, 0x68, 0x4c, 0xfc, 0xde, 0x52, 0x4e, 0x20, 0x66, 0x6c, 0x1b, 0x4a, + 0xa7, 0xc1, 0x8d, 0xcf, 0x13, 0xa2, 0x80, 0x0f, 0xdd, 0x82, 0xe6, 0x17, + 0x16, 0xe4, 0x18, 0x71, 0xa7, 0x28, 0x63, 0x73, 0x1d, 0x2b, 0x8a, 0x2c, + 0xa3, 0xcd, 0x7c, 0x85, 0x2c, 0x6e, 0x87, 0xb3, 0x8d, 0xcd, 0xba, 0xa3, + 0xe4, 0xa6, 0xe2, 0x50, 0xa6, 0x50, 0xa6, 0xdb, 0x75, 0x6d, 0x6e, 0xbf, + 0xc7, 0x96, 0x3b, 0x83, 0x90, 0xa7, 0x22, 0x19, 0x31, 0x14, 0x6a, 0x35, + 0x4e, 0xf3, 0x10, 0x29, 0xce, 0xb7, 0x6d, 0x3c, 0x3e, 0xf6, 0xb6, 0x0c, + 0x19, 0x69, 0xed, 0x5e, 0xdc, 0x11, 0xc6, 0x24, 0x09, 0x99, 0x6a, 0x16, + 0x16, 0x18, 0xda, 0x66, 0xaf, 0x9d, 0x36, 0x8d, 0x43, 0xc9, 0x8a, 0xc4, + 0x65, 0x68, 0x68, 0x16, 0xdf, 0x2b, 0xa7, 0x4e, 0xaf, 0x4f, 0xb2, 0x53, + 0x8a, 0xb6, 0xa5, 0xa4, 0x82, 0xe1, 0x2d, 0xac, 0xe3, 0xbc, 0xe3, 0x92, + 0xe6, 0x28, 0x0f, 0x10, 0xe1, 0x9e, 0x8d, 0x83, 0xab, 0xae, 0x32, 0x49, + 0x11, 0x20, 0xd0, 0x82, 0x9a, 0xcf, 0x8d, 0x7c, 0x73, 0x8d, 0xb6, 0xa8, + 0x10, 0x7d, 0x01, 0xab, 0x07, 0x30, 0x7d, 0x6d, 0xe6, 0x6b, 0x9d, 0xb6, + 0xbe, 0x8c, 0x08, 0x6a, 0x16, 0x72, 0xb2, 0x94, 0x04, 0x64, 0x85, 0xc0, + 0x92, 0xda, 0xae, 0x5d, 0xc6, 0x62, 0x71, 0xa1, 0x36, 0x86, 0x36, 0x0c, + 0xdd, 0xc9, 0x2b, 0xc2, 0xa0, 0x67, 0x84, 0x64, 0xc3, 0x00, 0x00, 0x00, + 0x01, 0x0b, 0x43, 0xf9, 0x16, 0xdf, 0x37, 0xad, 0x9e, 0xa7, 0x46, 0xde, + 0xf0, 0xfc, 0xc2, 0xef, 0x8b, 0x71, 0xd3, 0xcf, 0x16, 0x92, 0x8a, 0x6f, + 0x57, 0xc8, 0x21, 0x7f, 0xc8, 0x16, 0xb5, 0xbc, 0xb8, 0x52, 0xda, 0x43, + 0x6f, 0x16, 0x37, 0x5b, 0xd7, 0x0f, 0x0a, 0x1e, 0x1a, 0xd2, 0x53, 0x39, + 0xa0, 0x5b, 0x6c, 0x9f, 0x8b, 0x72, 0x7a, 0xca, 0xdc, 0xa9, 0x25, 0xc9, + 0x00, 0x20, 0x43, 0xa8, 0x09, 0x69, 0xed, 0x3a, 0x1f, 0x23, 0x4d, 0x2d, + 0xbe, 0x59, 0x84, 0x04, 0x99, 0x40, 0x47, 0x0c, 0x85, 0x85, 0x97, 0x49, + 0x2d, 0xda, 0x04, 0x3f, 0xfa, 0xb4, 0x92, 0xdc, 0x48, 0x08, 0x40, 0x0e, + 0x4e, 0x2b, 0xd7, 0x6d, 0x25, 0x95, 0x09, 0x4d, 0xe9, 0x39, 0xcb, 0xc9, + 0xb8, 0x43, 0xb1, 0xb1, 0xa3, 0x09, 0x0c, 0x8e, 0x46, 0xfa, 0x72, 0x10, + 0x76, 0x66, 0xdf, 0x0d, 0xb2, 0x2b, 0x68, 0x00, 0x6c, 0x28, 0x00, 0xf9, + 0xe4, 0x45, 0x35, 0x6a, 0x62, 0xd2, 0x21, 0x19, 0xe0, 0x66, 0x80, 0x47, + 0x69, 0xc1, 0x2a, 0x8c, 0x45, 0xc8, 0x2f, 0x2e, 0x2d, 0x38, 0xa5, 0x1b, + 0x83, 0x61, 0x55, 0xbd, 0x29, 0x17, 0xef, 0x84, 0x4f, 0x9b, 0xc3, 0xa0, + 0xf8, 0x6b, 0x84, 0xf5, 0x5f, 0xd1, 0x6e, 0xf3, 0xa1, 0xf9, 0x64, 0x9b, + 0x32, 0x14, 0x75, 0x52, 0xeb, 0x79, 0xf1, 0xe4, 0xe3, 0x0a, 0xa1, 0x54, + 0xb2, 0x89, 0x5e, 0x8d, 0x56, 0x1a, 0xdf, 0x82, 0xed, 0xfb, 0xc7, 0x41, + 0xe6, 0x58, 0x96, 0x1a, 0xae, 0x0b, 0x1c, 0x35, 0x0a, 0x18, 0xde, 0x64, + 0x5f, 0x39, 0xc7, 0xbe, 0x47, 0x66, 0xc3, 0xe6, 0xd5, 0x88, 0x51, 0xd4, + 0xf0, 0xca, 0xde, 0x88, 0x01, 0x87, 0xc7, 0x3d, 0x7f, 0x5d, 0xf3, 0xcf, + 0x2f, 0xe4, 0x99, 0x4c, 0x78, 0xa7, 0x65, 0x80, 0x16, 0x66, 0x2d, 0x57, + 0xa0, 0xca, 0x12, 0xdc, 0x3a, 0x2f, 0xa1, 0x1e, 0x5b, 0xcf, 0x57, 0x4e, + 0xdd, 0x4d, 0x89, 0x2d, 0x91, 0x70, 0xfa, 0xb2, 0x54, 0xa7, 0x96, 0xdd, + 0xb7, 0x12, 0x6c, 0x84, 0x30, 0x2d, 0xb7, 0xa5, 0x37, 0x9d, 0xf9, 0x78, + 0xeb, 0x64, 0xa1, 0x1b, 0x29, 0x5a, 0x80, 0x2b, 0x6c, 0x93, 0xf3, 0xce, + 0x61, 0x61, 0x85, 0xd9, 0x09, 0x2d, 0x8c, 0x57, 0x19, 0xf0, 0x29, 0xd3, + 0x24, 0x1b, 0x4f, 0xda, 0xfd, 0xa3, 0x49, 0xb6, 0xd5, 0xad, 0xa3, 0x87, + 0xe8, 0x9c, 0xe7, 0x78, 0x88, 0x00, 0x28, 0xce, 0x24, 0xbb, 0x54, 0xe1, + 0xb4, 0xe2, 0x13, 0x2b, 0x16, 0xd6, 0x8a, 0xdd, 0xc4, 0x6e, 0x35, 0xd8, + 0x9e, 0x7b, 0x46, 0xe9, 0xb8, 0xec, 0xc9, 0x2a, 0xad, 0xa8, 0x83, 0x6b, + 0x74, 0xfe, 0x6b, 0x80, 0x1c, 0xfc, 0x58, 0xee, 0xdf, 0x06, 0xe6, 0x3f, + 0x87, 0xf3, 0xc6, 0x44, 0x89, 0x29, 0x32, 0xa2, 0x4a, 0x59, 0xd5, 0x0f, + 0x6f, 0x31, 0x27, 0x96, 0xee, 0xa0, 0x52, 0x17, 0x5b, 0x50, 0x73, 0xf7, + 0x6e, 0x14, 0x03, 0xdd, 0x96, 0x14, 0x30, 0xea, 0xa3, 0x5b, 0x7d, 0xaa, + 0x95, 0xb7, 0xa3, 0x5b, 0xe9, 0x7f, 0x8d, 0x14, 0x26, 0x9a, 0xbe, 0x30, + 0xb9, 0x06, 0x96, 0xdb, 0xb6, 0x93, 0xba, 0xe9, 0xda, 0x09, 0x7f, 0xf5, + 0xed, 0xa8, 0xa7, 0x0e, 0x56, 0xf2, 0x7b, 0x60, 0x81, 0x0e, 0x96, 0xd0, + 0xd5, 0xbe, 0x28, 0xde, 0xfb, 0xea, 0xe7, 0x39, 0xe2, 0x78, 0x7e, 0x50, + 0xd9, 0xbf, 0x33, 0x49, 0xf6, 0x1c, 0x7b, 0xd6, 0x5c, 0xb9, 0x4a, 0x0a, + 0x66, 0xb7, 0x9d, 0x80, 0x53, 0x6d, 0x00, 0x29, 0xb2, 0xb6, 0xa2, 0xb9, + 0x04, 0x1f, 0xec, 0x7e, 0xf6, 0xed, 0x51, 0xc8, 0xe2, 0xa2, 0x8d, 0x2e, + 0xc5, 0x18, 0x59, 0xc9, 0x5b, 0xa5, 0x2c, 0xfb, 0x65, 0x9a, 0x19, 0x71, + 0x08, 0xe9, 0x6d, 0x90, 0x27, 0x92, 0xe2, 0xb5, 0x1f, 0xde, 0x60, 0x91, + 0x1d, 0x3d, 0xf7, 0x02, 0xc5, 0x74, 0x24, 0x53, 0xec, 0x38, 0xed, 0xa5, + 0xfa, 0x36, 0xc9, 0xba, 0x47, 0xc7, 0xde, 0x94, 0x32, 0xf1, 0x82, 0x77, + 0x9b, 0x14, 0x36, 0x06, 0x00, 0x8e, 0x37, 0x63, 0x7a, 0x0d, 0xf9, 0xde, + 0x67, 0x1d, 0x5f, 0x82, 0xb6, 0x9c, 0x98, 0x4e, 0x7c, 0xd4, 0x2d, 0x50, + 0xa3, 0x88, 0x6a, 0xdb, 0x78, 0xea, 0x77, 0xbf, 0x97, 0xbe, 0x81, 0x10, + 0x3b, 0x6c, 0xbf, 0xb1, 0xdb, 0x06, 0x78, 0x04, 0xb4, 0x12, 0x08, 0x40, + 0x0d, 0xb4, 0xd9, 0x60, 0x62, 0x3a, 0xd2, 0xd5, 0x61, 0xd4, 0xa2, 0x86, + 0x9e, 0xdc, 0xec, 0xa0, 0x06, 0x9d, 0xf3, 0xa9, 0x06, 0xa8, 0x04, 0xb5, + 0x7c, 0x07, 0xd3, 0xa0, 0x53, 0x03, 0x1a, 0x46, 0xb6, 0x08, 0xd3, 0x87, + 0x88, 0xdb, 0x82, 0xf9, 0x90, 0xac, 0xfc, 0xae, 0x19, 0x9c, 0x13, 0x57, + 0xc5, 0xba, 0x3b, 0x08, 0x3d, 0x42, 0x7c, 0x01, 0x56, 0x6c, 0x42, 0x9b, + 0xe7, 0x46, 0x87, 0xd8, 0x90, 0x30, 0xca, 0x02, 0xe6, 0xfa, 0xc1, 0x16, + 0xc0, 0x06, 0x64, 0x4e, 0xcd, 0x72, 0x14, 0xbb, 0xca, 0xae, 0x4d, 0x92, + 0xa1, 0xe8, 0x96, 0xc0, 0xa6, 0x74, 0xa6, 0x9c, 0xab, 0x4a, 0x6f, 0x33, + 0x9d, 0x39, 0xef, 0xa0, 0xeb, 0x42, 0xf6, 0x45, 0x1c, 0x77, 0xab, 0x76, + 0x1d, 0xef, 0xe4, 0x56, 0x2a, 0x16, 0x93, 0x12, 0x48, 0x65, 0x2d, 0x46, + 0x36, 0x5f, 0x90, 0x43, 0xff, 0x87, 0x59, 0xab, 0x12, 0xe4, 0x2a, 0x4d, + 0x2e, 0x55, 0x85, 0x21, 0xda, 0x16, 0xd8, 0x1f, 0xbc, 0x13, 0x9d, 0x92, + 0xec, 0x1b, 0x99, 0x72, 0x9d, 0x9a, 0x35, 0x4b, 0x3a, 0x05, 0x36, 0x67, + 0x36, 0x97, 0x4a, 0x46, 0xfd, 0x07, 0x3e, 0xe0, 0x16, 0x3e, 0xf1, 0x26, + 0x01, 0x2e, 0xf3, 0xa1, 0xd5, 0xd2, 0xc2, 0xce, 0xa3, 0x06, 0xfa, 0xb7, + 0x0e, 0x0b, 0xe0, 0x4f, 0x59, 0x93, 0x62, 0x17, 0x67, 0x73, 0x26, 0x62, + 0x6a, 0x06, 0x8d, 0xbe, 0x0c, 0x3b, 0xb8, 0x2f, 0x87, 0x64, 0xa3, 0x91, + 0xdc, 0xcd, 0x54, 0x28, 0x79, 0x0d, 0x83, 0xde, 0x62, 0x47, 0xa5, 0x38, + 0x9b, 0x2a, 0x98, 0x32, 0x9c, 0x8d, 0x11, 0xab, 0x46, 0xb6, 0xcf, 0xb2, + 0x72, 0x86, 0x6c, 0xa5, 0xfe, 0xd1, 0x12, 0xc2, 0xa3, 0x40, 0x0b, 0x6e, + 0x99, 0x71, 0x03, 0x26, 0x86, 0xa2, 0x56, 0x77, 0xdf, 0x37, 0xec, 0x5d, + 0x1d, 0x24, 0x51, 0x8d, 0x8b, 0xaf, 0xc1, 0x69, 0x07, 0xaa, 0x0c, 0x18, + 0xc4, 0x6a, 0xad, 0xd5, 0xe7, 0xc3, 0x8c, 0x7c, 0xcd, 0x2d, 0x69, 0x86, + 0x0f, 0x3e, 0x14, 0xa8, 0x4b, 0x6d, 0xa2, 0x77, 0xce, 0xd8, 0xeb, 0xd8, + 0x0f, 0x16, 0xd9, 0x2c, 0x88, 0x51, 0xed, 0xc2, 0x8f, 0x36, 0xc3, 0x10, + 0x75, 0x56, 0xec, 0xe7, 0x2f, 0x17, 0x7c, 0xaa, 0x4a, 0x02, 0x22, 0xd1, + 0x0f, 0x62, 0x14, 0xc5, 0x2e, 0x37, 0x7e, 0xc9, 0xc4, 0xb8, 0x90, 0x2f, + 0xd4, 0x05, 0xed, 0x9c, 0xc3, 0x76, 0xd5, 0x08, 0x4b, 0x1b, 0xaa, 0xe9, + 0xe5, 0x8b, 0x54, 0xa4, 0x6e, 0x7e, 0xd7, 0x64, 0x0e, 0x94, 0xe2, 0xcb, + 0xa5, 0x14, 0x35, 0xa0, 0x61, 0x4d, 0xaa, 0x96, 0x5b, 0x6a, 0xb9, 0xb7, + 0xf6, 0x19, 0x30, 0xb2, 0xea, 0xad, 0x6c, 0x5b, 0xcb, 0x8c, 0xcf, 0x2b, + 0x14, 0xea, 0xa8, 0x5c, 0x52, 0xce, 0x6e, 0x98, 0xae, 0xd0, 0xdb, 0x2d, + 0x19, 0x25, 0x42, 0xc8, 0x6d, 0xcc, 0xfc, 0xf5, 0x96, 0xee, 0xd1, 0xe3, + 0x68, 0x53, 0x38, 0xd9, 0x9c, 0xde, 0xff, 0xc4, 0xe6, 0xc3, 0x68, 0x59, + 0xed, 0x88, 0x57, 0x3b, 0x95, 0x77, 0x3c, 0x06, 0x23, 0x54, 0x25, 0xdc, + 0xf2, 0xe5, 0xe7, 0x8e, 0x1f, 0x94, 0x39, 0xf2, 0x53, 0x9b, 0xe8, 0x00, + 0x81, 0xfa, 0xa0, 0x0f, 0xbe, 0x40, 0x1e, 0xfd, 0xb8, 0x8e, 0x16, 0xe3, + 0x4d, 0x97, 0xae, 0x05, 0xee, 0x43, 0x2c, 0x7e, 0x5b, 0x03, 0xe5, 0x38, + 0x7b, 0x54, 0x65, 0x1b, 0xf9, 0xe9, 0x13, 0x1e, 0x91, 0x47, 0x14, 0x79, + 0x74, 0xa6, 0x4b, 0xd5, 0xc1, 0x56, 0xaa, 0x84, 0x54, 0x59, 0x11, 0x61, + 0x45, 0x0c, 0x6f, 0xba, 0x02, 0x07, 0xe7, 0x80, 0x59, 0x9f, 0xda, 0xe1, + 0x19, 0x34, 0x38, 0xde, 0x5f, 0x61, 0x97, 0x65, 0xc8, 0x62, 0xda, 0x3c, + 0xb4, 0x8d, 0xec, 0x7e, 0x08, 0xa4, 0x70, 0x06, 0xbf, 0xf8, 0xfa, 0xfe, + 0xe8, 0x76, 0x4b, 0x86, 0xc8, 0x4c, 0xcc, 0x83, 0x1b, 0xcd, 0x22, 0x73, + 0x1d, 0xcb, 0x9f, 0x96, 0x51, 0xd2, 0x37, 0x08, 0x87, 0x99, 0xb9, 0xb3, + 0xd1, 0xbf, 0x92, 0x02, 0x07, 0xe6, 0x7d, 0xa0, 0x03, 0x3f, 0xe3, 0xf8, + 0xf8, 0xf9, 0xca, 0x95, 0x1d, 0xe6, 0x85, 0xe3, 0x9f, 0x0b, 0x85, 0x50, + 0xc5, 0x6f, 0xd0, 0x00, 0x05, 0x20, 0x0e, 0x44, 0xfd, 0x40, 0x1f, 0xf7, + 0xaf, 0xeb, 0x40, 0x8e, 0xb8, 0xc2, 0xec, 0x31, 0x57, 0x74, 0x29, 0xbb, + 0xe0, 0x0c, 0x39, 0xdf, 0x8e, 0xe5, 0xde, 0x10, 0x22, 0xc0, 0x2e, 0x36, + 0x92, 0x25, 0xd1, 0x3f, 0x05, 0x50, 0x92, 0x88, 0x48, 0xd6, 0x20, 0x5f, + 0x06, 0x39, 0xf7, 0x28, 0x4e, 0x36, 0x5c, 0x24, 0xc9, 0x6b, 0x00, 0x00, + 0x00, 0x01, 0x0c, 0x43, 0xd4, 0x08, 0x1f, 0xa2, 0x01, 0x61, 0x14, 0x5e, + 0x67, 0xf0, 0x4e, 0xcf, 0xd6, 0xf2, 0xfe, 0x71, 0x0c, 0xe2, 0x54, 0xda, + 0xb6, 0x8c, 0x0a, 0xad, 0xd1, 0x00, 0x63, 0x8f, 0x22, 0x88, 0x22, 0xbb, + 0xbb, 0x4e, 0x04, 0x50, 0x0f, 0xb9, 0x5f, 0x25, 0x0f, 0xfd, 0xf9, 0xe4, + 0x28, 0x25, 0xbe, 0xad, 0xa2, 0xdc, 0x00, 0xd0, 0x00, 0x45, 0x9c, 0x50, + 0xc0, 0xe8, 0x6e, 0xbe, 0xad, 0x32, 0xfe, 0xe5, 0x26, 0xc2, 0x86, 0x54, + 0x63, 0xc8, 0x82, 0x7f, 0xc8, 0x03, 0xd0, 0xfb, 0x6f, 0xec, 0x10, 0x80, + 0x2a, 0xbf, 0xcc, 0x02, 0x27, 0x75, 0x2c, 0x0d, 0x3d, 0xbc, 0x2a, 0x93, + 0x65, 0x28, 0x02, 0x23, 0xdb, 0x8b, 0x74, 0xc2, 0xe9, 0x09, 0xbf, 0xc9, + 0x70, 0x10, 0x80, 0x1e, 0x47, 0xa4, 0x0d, 0xab, 0x52, 0x0e, 0x3a, 0x8d, + 0xa1, 0x6c, 0x2e, 0x2c, 0x59, 0xb4, 0x36, 0xda, 0x53, 0x0c, 0xfc, 0x57, + 0x00, 0x0c, 0x24, 0x39, 0x9c, 0xb7, 0x8d, 0xf4, 0x2d, 0xb7, 0x85, 0xda, + 0xdc, 0x0d, 0xf2, 0xb9, 0x03, 0x12, 0x42, 0x44, 0x6f, 0x75, 0xb2, 0xf6, + 0xfe, 0xcd, 0x0a, 0x0f, 0x35, 0xbc, 0xe6, 0x97, 0x8a, 0x42, 0xa6, 0x52, + 0x5a, 0x37, 0xd3, 0x04, 0xbf, 0xf3, 0x6b, 0xac, 0x0d, 0xf3, 0xdd, 0xd9, + 0x26, 0x1e, 0x36, 0x5a, 0x54, 0x3c, 0x6b, 0x4c, 0x2e, 0xa1, 0x29, 0x59, + 0x46, 0xf7, 0x7d, 0xbe, 0x35, 0xcf, 0xfe, 0xbb, 0x45, 0xe9, 0xd2, 0xeb, + 0x89, 0xfc, 0xef, 0x7c, 0xbe, 0x58, 0x6c, 0xa9, 0xe7, 0x13, 0x33, 0x32, + 0x18, 0x7c, 0x0b, 0x6f, 0x9d, 0x4e, 0x32, 0xe7, 0x19, 0x96, 0x0f, 0xb9, + 0x0e, 0xa6, 0x42, 0xce, 0x5a, 0x5d, 0x6a, 0x28, 0x88, 0xe7, 0x4f, 0x2b, + 0x90, 0x73, 0xed, 0x98, 0xaf, 0x53, 0xcb, 0x44, 0x08, 0x6b, 0x30, 0x38, + 0x5e, 0x6c, 0x88, 0x02, 0xb9, 0x57, 0xd6, 0x37, 0x9c, 0x98, 0x61, 0x49, + 0x46, 0xa6, 0x52, 0x99, 0x99, 0x23, 0x7d, 0x90, 0x05, 0x84, 0x52, 0x38, + 0xaf, 0xa8, 0x94, 0xf6, 0x2c, 0x11, 0x00, 0x17, 0x08, 0x98, 0xe3, 0x66, + 0xf2, 0x62, 0xc5, 0xf2, 0x0c, 0xa1, 0x4d, 0xf2, 0x27, 0x49, 0x38, 0x73, + 0x8b, 0x1e, 0x54, 0x87, 0x81, 0x4d, 0xd1, 0xca, 0x00, 0x64, 0xe7, 0x29, + 0x0a, 0x94, 0xdc, 0xc5, 0x9e, 0x51, 0xf5, 0x42, 0x0d, 0x75, 0x84, 0x30, + 0xc6, 0xf4, 0xf2, 0x2e, 0x54, 0xf4, 0x56, 0xe9, 0x90, 0xaa, 0x49, 0x6c, + 0x9e, 0xe0, 0x2d, 0xb3, 0xd4, 0x14, 0xf8, 0x00, 0x31, 0x88, 0xdd, 0xf2, + 0x3b, 0xaf, 0x3a, 0x59, 0x0d, 0xb2, 0x55, 0xfa, 0x1b, 0x62, 0xd0, 0xb2, + 0x43, 0x22, 0x64, 0x64, 0x39, 0xbe, 0x54, 0x4e, 0xf3, 0x11, 0x43, 0x0f, + 0x48, 0xbe, 0xad, 0xa3, 0xad, 0xd1, 0x53, 0xf2, 0xa0, 0x53, 0x71, 0xac, + 0x3a, 0xa8, 0x4a, 0x94, 0xdd, 0x17, 0xec, 0x58, 0x6a, 0x06, 0x29, 0x4a, + 0x39, 0xa1, 0x4e, 0x8c, 0xe3, 0x68, 0xa0, 0x16, 0xf1, 0xc6, 0xcd, 0x09, + 0x2e, 0x4a, 0xbe, 0xad, 0xfa, 0x64, 0x01, 0xb8, 0x9a, 0x00, 0xeb, 0xee, + 0x00, 0xe7, 0x7d, 0xfc, 0xa4, 0x28, 0xcc, 0x00, 0x3d, 0x17, 0xc3, 0x9d, + 0x07, 0x95, 0x84, 0xed, 0xb8, 0xb4, 0x07, 0x8b, 0x6b, 0x7e, 0x71, 0xdf, + 0xcb, 0xf2, 0x10, 0x8a, 0x6f, 0xd3, 0x20, 0x0a, 0x14, 0x10, 0x40, 0x4c, + 0x8f, 0xdd, 0xf3, 0xa0, 0x11, 0x73, 0xb9, 0xb0, 0x05, 0x4a, 0xb4, 0x34, + 0x62, 0xb7, 0x36, 0x6c, 0xe3, 0x7c, 0xb2, 0xe0, 0x6a, 0xee, 0xc0, 0x86, + 0x98, 0x5e, 0xe4, 0x25, 0xb7, 0xf2, 0x89, 0x08, 0x3e, 0xf4, 0x55, 0x40, + 0x47, 0xff, 0xd8, 0x27, 0x5d, 0xce, 0x48, 0x08, 0xff, 0xfb, 0xf8, 0x99, + 0xa5, 0x04, 0x94, 0x5b, 0x74, 0x2e, 0x80, 0x1f, 0x00, 0x1b, 0x23, 0xe5, + 0x02, 0x64, 0x76, 0x76, 0xa5, 0x94, 0x4c, 0xcd, 0x2e, 0x12, 0x9b, 0x37, + 0x34, 0x0c, 0x11, 0x4e, 0x0c, 0xbd, 0x0a, 0x17, 0x2e, 0x20, 0xdf, 0xd6, + 0xe6, 0x6d, 0x01, 0x1d, 0x48, 0xdd, 0x4b, 0x00, 0x0f, 0x05, 0x0a, 0xe1, + 0x36, 0x06, 0x42, 0x2c, 0x7c, 0xc0, 0xc1, 0x9e, 0x72, 0x16, 0x18, 0xde, + 0xb0, 0xc6, 0xf6, 0xcf, 0x6f, 0xce, 0x7b, 0x26, 0x4d, 0x4d, 0x7d, 0x18, + 0x55, 0x33, 0x65, 0xbb, 0x14, 0x08, 0x7d, 0xb5, 0xb8, 0xcb, 0x5d, 0xc7, + 0x1b, 0x60, 0xec, 0x99, 0x2c, 0x0e, 0x1e, 0x03, 0x36, 0xeb, 0x48, 0xff, + 0x62, 0x05, 0xb8, 0x58, 0xd4, 0x15, 0x3c, 0xb6, 0xd3, 0xa0, 0xd9, 0xa9, + 0xe2, 0xad, 0x97, 0x90, 0x42, 0xff, 0x5d, 0xbc, 0x20, 0x5e, 0x24, 0x2e, + 0xfa, 0x12, 0x98, 0x87, 0xb5, 0x53, 0x9b, 0x41, 0x22, 0xf4, 0x5f, 0x7c, + 0xef, 0x96, 0xd8, 0x32, 0x4e, 0x9c, 0x62, 0x8d, 0xfd, 0xac, 0x29, 0xbd, + 0x29, 0x19, 0xd3, 0xeb, 0xfd, 0xee, 0xd1, 0x7b, 0x75, 0x64, 0x7c, 0x5c, + 0xd9, 0x92, 0x4a, 0xba, 0x9e, 0x70, 0x9a, 0x90, 0x39, 0xb8, 0x2b, 0x09, + 0xf9, 0x64, 0x09, 0xb1, 0x70, 0xe1, 0xa7, 0x44, 0x3c, 0x21, 0xae, 0x74, + 0xd7, 0x08, 0xce, 0x67, 0x36, 0xd4, 0x3b, 0x69, 0x91, 0xd2, 0x58, 0x7a, + 0xc2, 0x83, 0x94, 0xb6, 0x89, 0x1b, 0x3a, 0x54, 0x56, 0xf4, 0xdc, 0xf6, + 0x15, 0xaf, 0xa2, 0xb2, 0x40, 0x09, 0x6c, 0x31, 0x16, 0xa1, 0xc3, 0xce, + 0x39, 0xb0, 0xe5, 0x79, 0x3d, 0xf5, 0xf2, 0x2f, 0xe9, 0x23, 0xa2, 0xa5, + 0x3c, 0x29, 0xbb, 0x3c, 0xdd, 0x14, 0x2f, 0x71, 0x0b, 0x3b, 0x3c, 0xae, + 0x38, 0xfa, 0x12, 0x35, 0x02, 0x5b, 0x3a, 0xce, 0xd3, 0x8e, 0x8b, 0x02, + 0x43, 0xb0, 0x3e, 0x0f, 0x2a, 0xfa, 0xb4, 0xc8, 0x53, 0x6d, 0xb5, 0x6b, + 0x6d, 0xce, 0xae, 0x5d, 0x18, 0x7c, 0x2d, 0x42, 0x9a, 0xfd, 0xd8, 0xfb, + 0x37, 0x28, 0x4d, 0xa5, 0x9c, 0x15, 0xea, 0xdc, 0x8e, 0xb2, 0xe7, 0x50, + 0xe8, 0x3e, 0x86, 0x8c, 0x21, 0x04, 0xb5, 0xb7, 0x11, 0xf0, 0xb1, 0xc7, + 0x0f, 0x30, 0xf2, 0xda, 0x6b, 0x68, 0xde, 0xcc, 0xf3, 0x72, 0xee, 0xbe, + 0x8e, 0xc2, 0xce, 0x90, 0x90, 0xdc, 0xd1, 0x40, 0x61, 0xd6, 0xdb, 0xb4, + 0xe0, 0xc1, 0xc8, 0xcc, 0x08, 0x60, 0x0b, 0x99, 0xa3, 0x4e, 0xab, 0xa3, + 0x1b, 0x1b, 0xdf, 0xe7, 0x61, 0xc0, 0x3c, 0x33, 0x2c, 0x09, 0x0d, 0x62, + 0x56, 0x2b, 0x76, 0x75, 0x72, 0xda, 0x99, 0x96, 0x8d, 0xb6, 0x16, 0xd8, + 0xf2, 0x9b, 0xce, 0x92, 0x0f, 0x6d, 0x8e, 0x7d, 0xc7, 0x9b, 0x32, 0x0d, + 0x2f, 0x10, 0xb8, 0xa5, 0x9c, 0xce, 0x26, 0x00, 0x1f, 0xfb, 0x48, 0x81, + 0xa6, 0xdc, 0xb9, 0xb3, 0xd4, 0xe6, 0x89, 0x52, 0x94, 0xd9, 0x66, 0xcc, + 0x79, 0x4d, 0xd3, 0x99, 0x67, 0x05, 0xa4, 0x0b, 0x53, 0xdb, 0xd4, 0x80, + 0x37, 0x14, 0xef, 0xaf, 0x5b, 0xc3, 0xbd, 0xf9, 0xca, 0x96, 0xbb, 0x1f, + 0xbc, 0x2d, 0x93, 0x5d, 0x77, 0x28, 0x6a, 0x96, 0xde, 0x9f, 0xe4, 0x47, + 0xbf, 0xfc, 0x01, 0x8f, 0x5f, 0x0e, 0x76, 0xaa, 0x19, 0x86, 0xbd, 0xff, + 0xb1, 0xbe, 0x90, 0xb6, 0xc1, 0x05, 0xf1, 0xbf, 0x1f, 0x1c, 0x00, 0x56, + 0xf9, 0x2e, 0x69, 0x3a, 0xf3, 0xd1, 0x99, 0xa5, 0x87, 0xa8, 0x79, 0x92, + 0x16, 0x10, 0xdc, 0xbd, 0x07, 0x00, 0xe4, 0x84, 0xde, 0x68, 0x89, 0xe5, + 0x57, 0x42, 0x9b, 0xe9, 0x80, 0x14, 0xfc, 0x8a, 0x77, 0x28, 0x2a, 0x3a, + 0x87, 0x4f, 0x37, 0x17, 0x71, 0x12, 0x1b, 0x0e, 0xf5, 0x6e, 0xc8, 0x01, + 0x3f, 0xce, 0x7c, 0x90, 0x26, 0xfb, 0x75, 0xfb, 0xf2, 0x79, 0x92, 0x9b, + 0x13, 0xf0, 0xb6, 0x0f, 0x5b, 0x5b, 0xd9, 0x80, 0x3c, 0xff, 0xe7, 0xc9, + 0x07, 0x7a, 0x9d, 0xc9, 0x40, 0x27, 0x2e, 0x66, 0xdb, 0x51, 0x74, 0xe1, + 0xd5, 0x50, 0xe8, 0xad, 0xee, 0xfe, 0x3f, 0xa2, 0x9e, 0x2c, 0x5e, 0x76, + 0xf7, 0xc0, 0x1e, 0x73, 0x39, 0xc7, 0xc8, 0x90, 0x38, 0x3a, 0xad, 0x44, + 0x38, 0x31, 0xbc, 0xde, 0xc4, 0x0a, 0xb8, 0x55, 0x2c, 0x34, 0xe8, 0x8d, + 0xca, 0xe7, 0x70, 0x88, 0x58, 0x5b, 0x7f, 0x34, 0x00, 0x78, 0x23, 0x90, + 0x03, 0x5e, 0xfd, 0xe7, 0xce, 0x5a, 0x4d, 0xe6, 0xbf, 0x76, 0xed, 0xa6, + 0x17, 0x87, 0x7a, 0x1c, 0xdd, 0xd0, 0x04, 0xd8, 0x29, 0xfb, 0x5f, 0xc6, + 0xec, 0x85, 0x2f, 0x96, 0xd5, 0xf2, 0x0b, 0xc0, 0xc6, 0xbb, 0xe8, 0x47, + 0x70, 0x03, 0xa2, 0x27, 0xba, 0xc1, 0x38, 0xaa, 0x66, 0x13, 0x95, 0x64, + 0xb1, 0x69, 0x41, 0x10, 0xb6, 0xf8, 0xb7, 0xb8, 0x8a, 0x46, 0xaf, 0x93, + 0xe3, 0x61, 0xf3, 0x97, 0x73, 0x1e, 0x67, 0x9c, 0x3a, 0xc5, 0x68, 0x7b, + 0xb8, 0xe9, 0x54, 0xa1, 0xb4, 0x04, 0x4d, 0xcd, 0x33, 0x31, 0x16, 0x46, + 0xfe, 0xd4, 0x00, 0xe9, 0xdc, 0x7c, 0x08, 0x7e, 0xe4, 0xbb, 0x52, 0x07, + 0xea, 0x54, 0x92, 0x0d, 0x6f, 0x0f, 0x7b, 0xc7, 0x6f, 0x4e, 0xeb, 0x50, + 0x11, 0xff, 0xef, 0x74, 0xcc, 0x43, 0xce, 0xaa, 0xdc, 0x91, 0x41, 0xc2, + 0xc8, 0xb3, 0x71, 0x00, 0x8c, 0x9d, 0xed, 0xc9, 0x10, 0xea, 0x6a, 0xe4, + 0x5a, 0x18, 0xdc, 0x20, 0x0a, 0x3a, 0xf6, 0x7f, 0x0e, 0xa2, 0x5c, 0x3b, + 0x76, 0xcc, 0xab, 0x2c, 0x4a, 0x50, 0x6f, 0x83, 0x79, 0xfc, 0x8a, 0x9e, + 0x4e, 0x8e, 0x74, 0xa1, 0x35, 0x5b, 0x33, 0x11, 0x12, 0x37, 0xd7, 0x00, + 0x40, 0xff, 0x79, 0xa2, 0x1d, 0x5d, 0x5d, 0x2a, 0xd9, 0x5e, 0xe3, 0x0d, + 0xa1, 0x6d, 0xf6, 0x00, 0x05, 0xdf, 0x34, 0x01, 0xb8, 0x03, 0xce, 0x6f, + 0x7d, 0x82, 0x47, 0xfe, 0x38, 0xda, 0x62, 0x1f, 0x0b, 0x81, 0xad, 0xf0, + 0xbe, 0xbe, 0xff, 0x22, 0x44, 0xed, 0xdf, 0x83, 0x16, 0xd8, 0xe7, 0x66, + 0xa1, 0x86, 0xdf, 0xca, 0x25, 0x28, 0xf8, 0xdf, 0x5c, 0x9f, 0x5e, 0xff, + 0xe2, 0xb7, 0xae, 0xf9, 0xe6, 0x8d, 0x2a, 0xd5, 0x36, 0x40, 0xc6, 0xf6, + 0x36, 0xbf, 0x97, 0xc3, 0x6e, 0x96, 0x4a, 0x6d, 0xa0, 0x7d, 0x8a, 0x4a, + 0x60, 0x00, 0x00, 0x01, 0x0d, 0x43, 0xf7, 0xdd, 0x8a, 0x78, 0x80, 0x06, + 0xc0, 0x0d, 0x05, 0x73, 0x52, 0x25, 0x20, 0x02, 0x10, 0x03, 0xf7, 0x2b, + 0x8d, 0x50, 0xea, 0x6d, 0xa5, 0x95, 0x43, 0x65, 0x6f, 0x4c, 0x00, 0xf8, + 0x5b, 0x80, 0x1b, 0x77, 0xcf, 0xcd, 0xdc, 0xa3, 0xe7, 0x9f, 0x0b, 0x24, + 0x3a, 0xfe, 0xa5, 0x29, 0x43, 0x1a, 0x10, 0x34, 0x89, 0xcd, 0xde, 0x5f, + 0xc5, 0xa7, 0x77, 0x37, 0xc9, 0x21, 0x8a, 0x61, 0xc1, 0x2d, 0xf3, 0xe0, + 0x07, 0xc0, 0x0d, 0x78, 0xe7, 0xe4, 0x88, 0xff, 0x6f, 0x68, 0x85, 0xf9, + 0x3e, 0x6d, 0x96, 0x6e, 0x2a, 0x40, 0xe9, 0x21, 0x77, 0xc1, 0xbc, 0x34, + 0xfc, 0x56, 0xe7, 0x96, 0x64, 0xb2, 0xac, 0xa5, 0x8e, 0x52, 0x82, 0x02, + 0x5b, 0xf8, 0x7d, 0xcb, 0xe7, 0x95, 0x60, 0x62, 0x4b, 0x2c, 0x21, 0x56, + 0xd9, 0x06, 0xd6, 0xfa, 0xb0, 0x02, 0x1c, 0x80, 0x09, 0x1c, 0x28, 0x89, + 0xf5, 0x10, 0xf8, 0x1d, 0x67, 0x7c, 0xf6, 0xee, 0xa4, 0x35, 0xda, 0x5e, + 0x54, 0x1c, 0xa3, 0x61, 0x4d, 0x98, 0x10, 0x3f, 0x4b, 0xf9, 0xa0, 0x0f, + 0xfe, 0x33, 0x3d, 0x88, 0xf9, 0x46, 0x49, 0xdb, 0xf2, 0x24, 0xe3, 0x4b, + 0xb8, 0xaa, 0xd9, 0xc2, 0xe2, 0x94, 0xde, 0x7b, 0xe1, 0xcd, 0xf1, 0x80, + 0x1c, 0x8a, 0xec, 0x01, 0x0f, 0xf0, 0x43, 0xb5, 0xd8, 0x1b, 0x39, 0x9d, + 0x87, 0x28, 0x0a, 0xa8, 0xdf, 0x46, 0xfb, 0x7f, 0x7e, 0x77, 0xfe, 0x40, + 0x31, 0xf4, 0x63, 0xae, 0x3b, 0xf3, 0x77, 0xc1, 0x0a, 0x40, 0xb6, 0xfa, + 0x37, 0xf7, 0xe7, 0xbf, 0xa8, 0x03, 0x71, 0x62, 0x44, 0xe8, 0x62, 0x6b, + 0xd4, 0x39, 0x3f, 0x08, 0x98, 0x32, 0x48, 0xdf, 0x3f, 0xfe, 0x0b, 0x00, + 0x10, 0x67, 0x57, 0x66, 0x0c, 0xa5, 0xe1, 0x65, 0x9e, 0xd3, 0x23, 0xba, + 0xe5, 0xf6, 0xda, 0x02, 0x29, 0x0b, 0x6b, 0xdb, 0x31, 0xf4, 0xbf, 0x06, + 0xfe, 0x5f, 0xdf, 0xbe, 0xfd, 0xb2, 0x75, 0xd6, 0xd4, 0x2d, 0x65, 0x88, + 0x89, 0xe8, 0xde, 0x08, 0x00, 0xf5, 0xe2, 0x3d, 0x9c, 0xfe, 0x79, 0xc9, + 0x13, 0xf0, 0xee, 0xe0, 0xea, 0x03, 0x56, 0xfa, 0x3f, 0xd5, 0xc0, 0x82, + 0x02, 0x7e, 0xdc, 0x9a, 0x5c, 0x39, 0x49, 0xf9, 0x21, 0xdb, 0x25, 0x2e, + 0x0d, 0x6f, 0x8d, 0x75, 0x67, 0x44, 0x0e, 0x6a, 0x84, 0x3d, 0x72, 0x98, + 0x38, 0xe1, 0xc3, 0x5b, 0x93, 0x78, 0x82, 0x66, 0xbb, 0x89, 0x83, 0xe2, + 0x5c, 0x6c, 0x2c, 0x34, 0xa8, 0xda, 0x11, 0x45, 0xe0, 0x87, 0x53, 0x2b, + 0x8e, 0x53, 0x35, 0x15, 0x2a, 0x1c, 0x1a, 0x90, 0xe6, 0xa3, 0xfb, 0xb6, + 0xed, 0xb6, 0x00, 0x46, 0x5d, 0x28, 0x28, 0x31, 0xbd, 0x8e, 0x77, 0x78, + 0xa2, 0xf5, 0xd8, 0x17, 0x69, 0xcd, 0xe0, 0x3e, 0xd2, 0xfd, 0x51, 0x20, + 0x5e, 0xcd, 0xca, 0xa8, 0x71, 0x68, 0xde, 0x97, 0xee, 0xb6, 0x92, 0x14, + 0x5b, 0x76, 0xce, 0x9d, 0xc0, 0x9d, 0x57, 0x00, 0xaa, 0xa0, 0xd8, 0x31, + 0xbc, 0xe0, 0xa9, 0x38, 0xe1, 0xda, 0x50, 0x48, 0xc8, 0xad, 0xf4, 0x0e, + 0x45, 0xe6, 0xfd, 0x26, 0xc7, 0xe1, 0x55, 0x1e, 0xb5, 0xd9, 0xa1, 0xd4, + 0x3c, 0x7c, 0x94, 0xa3, 0xda, 0x00, 0x27, 0xf9, 0xf6, 0xfa, 0x8a, 0x23, + 0x77, 0x5f, 0x14, 0x11, 0x00, 0x13, 0xae, 0xc8, 0x84, 0x7e, 0xf8, 0x8e, + 0x81, 0x1b, 0xc6, 0xae, 0xc8, 0x34, 0xa2, 0x8b, 0x6a, 0x44, 0x18, 0xda, + 0x13, 0x65, 0x6f, 0xe6, 0xe0, 0x38, 0xdb, 0x23, 0x6d, 0xd2, 0xe0, 0x16, + 0xd9, 0x3d, 0xdd, 0x08, 0x12, 0x3b, 0x68, 0x69, 0xb6, 0x8f, 0x2d, 0xb7, + 0xda, 0xaf, 0xb4, 0xc0, 0x82, 0xc6, 0x34, 0x51, 0xa4, 0xa6, 0x34, 0xaa, + 0xde, 0xde, 0xcc, 0x32, 0xcb, 0x35, 0x06, 0xd8, 0x55, 0x42, 0xd4, 0x7b, + 0x75, 0xbe, 0x94, 0x02, 0xdf, 0x99, 0x5e, 0xfc, 0x0c, 0x8e, 0xda, 0x52, + 0xd0, 0xc5, 0xb1, 0xb9, 0xe4, 0x68, 0xff, 0x97, 0xdd, 0x2c, 0xe5, 0x5d, + 0xdf, 0x27, 0x2c, 0xc2, 0xce, 0x3e, 0xb6, 0xbe, 0xb9, 0xbe, 0xde, 0xd8, + 0xee, 0x02, 0x6c, 0xc9, 0x0a, 0x83, 0x21, 0x50, 0x73, 0x73, 0xd3, 0x64, + 0x96, 0x46, 0x76, 0xa5, 0x6f, 0xde, 0xdb, 0xa4, 0x7f, 0x8f, 0x67, 0x6d, + 0xa3, 0xd2, 0xb8, 0x47, 0x75, 0xca, 0x02, 0x27, 0x48, 0x88, 0xdc, 0xdc, + 0xc9, 0x74, 0x5a, 0x84, 0x7e, 0x04, 0xf6, 0x28, 0x5d, 0xc1, 0xb0, 0xe9, + 0x69, 0x96, 0x84, 0x94, 0xc9, 0xec, 0x08, 0x5f, 0xe3, 0xc7, 0x3d, 0x6e, + 0xd3, 0xca, 0xd0, 0x33, 0x1f, 0x80, 0x03, 0x57, 0x4d, 0x8a, 0x13, 0x2b, + 0x55, 0x2c, 0xe3, 0x9e, 0xa9, 0x0f, 0x8d, 0xf6, 0xd5, 0x5a, 0xb4, 0xb9, + 0xc3, 0xa9, 0xc1, 0x0d, 0xea, 0x48, 0x6a, 0x92, 0x5b, 0xd5, 0x81, 0xf3, + 0x49, 0x2d, 0xd1, 0x51, 0xe0, 0x07, 0x06, 0xe2, 0x01, 0x08, 0x40, 0x17, + 0x28, 0xf3, 0xb6, 0xad, 0x24, 0xb2, 0xc3, 0x48, 0xfe, 0x7a, 0x58, 0x0a, + 0xdd, 0xd7, 0x25, 0x78, 0xe2, 0xab, 0x68, 0x11, 0xcb, 0xc5, 0x73, 0x56, + 0x3c, 0xc5, 0x49, 0x1d, 0xdf, 0x6f, 0xdb, 0x03, 0x52, 0xdd, 0x90, 0xa9, + 0x47, 0x4b, 0x5a, 0xb7, 0x61, 0x02, 0xfd, 0x1d, 0xde, 0x84, 0x95, 0x9b, + 0xd6, 0x5b, 0x4a, 0x42, 0xd1, 0x17, 0xc5, 0xae, 0x94, 0xda, 0xc6, 0xeb, + 0x9c, 0xc1, 0x74, 0x54, 0xcc, 0x2c, 0x62, 0xef, 0x12, 0xc2, 0xcf, 0x19, + 0x46, 0x9e, 0x1a, 0xcb, 0x0d, 0xe3, 0xe4, 0x46, 0x98, 0x78, 0xe1, 0x4e, + 0xb3, 0x74, 0x69, 0x34, 0xaa, 0xa8, 0xc7, 0x9e, 0x70, 0x89, 0x9e, 0xd3, + 0x9b, 0x46, 0xd5, 0x82, 0x7a, 0xb9, 0xe6, 0x30, 0xe0, 0xca, 0xd8, 0xdc, + 0x67, 0x0e, 0xce, 0x27, 0x8e, 0x45, 0x7f, 0xa2, 0xd2, 0x9a, 0x0e, 0x6a, + 0x3e, 0x37, 0xae, 0x13, 0xb6, 0xdf, 0x2c, 0xc8, 0x33, 0xf1, 0x9b, 0x4b, + 0xa1, 0x6c, 0x65, 0x33, 0x87, 0xc4, 0x81, 0x17, 0xb7, 0xe9, 0xe7, 0x0d, + 0x90, 0x61, 0x25, 0xab, 0x7d, 0xcd, 0x49, 0x29, 0x43, 0x25, 0x3b, 0x0b, + 0x83, 0x8f, 0x24, 0x35, 0x7c, 0x4d, 0xd7, 0xee, 0x94, 0x36, 0xc9, 0xae, + 0x86, 0x95, 0x4b, 0xa5, 0x9e, 0x30, 0x35, 0x6b, 0x45, 0x6b, 0x6e, 0xe7, + 0x5d, 0xd8, 0x03, 0x9b, 0x4e, 0x5b, 0xb2, 0xd3, 0x90, 0x86, 0xd5, 0xed, + 0x91, 0x40, 0xea, 0xa3, 0x9b, 0x35, 0x48, 0x92, 0xc0, 0x82, 0xda, 0xf9, + 0xf9, 0xd3, 0xc0, 0x22, 0xf5, 0x3d, 0x86, 0xb6, 0xe5, 0xc5, 0xb8, 0x68, + 0x52, 0x1a, 0x74, 0x39, 0x97, 0x9e, 0x88, 0x3e, 0xd9, 0xbc, 0xc5, 0x29, + 0x2e, 0x49, 0x4c, 0xcb, 0x42, 0x62, 0x95, 0x68, 0x53, 0x73, 0xfa, 0x97, + 0x8e, 0xe4, 0xdf, 0x49, 0x14, 0x34, 0x31, 0xba, 0x3f, 0x4e, 0xb0, 0x01, + 0xc8, 0x9c, 0x27, 0xe9, 0x65, 0x07, 0xf4, 0x56, 0x13, 0xa8, 0x0a, 0xdf, + 0x43, 0x4e, 0x0b, 0x68, 0x1a, 0x53, 0x73, 0xf0, 0x06, 0x35, 0x6f, 0xa3, + 0x7f, 0x47, 0x00, 0x5a, 0x01, 0x67, 0xdc, 0x8a, 0xef, 0x8d, 0x10, 0xf3, + 0xa4, 0xb8, 0x41, 0x73, 0xe7, 0x98, 0xd3, 0xa6, 0x15, 0x61, 0x43, 0xea, + 0xb7, 0x98, 0x12, 0xe0, 0x01, 0x0f, 0xb0, 0x8e, 0x5f, 0xe1, 0x38, 0x93, + 0x09, 0x46, 0x36, 0x0f, 0x6c, 0x98, 0x47, 0xd8, 0xfd, 0xc1, 0xf6, 0xbb, + 0x0c, 0x33, 0x4a, 0x1e, 0x32, 0x8e, 0x39, 0xbb, 0x80, 0x0f, 0x28, 0xb0, + 0x06, 0x20, 0x0f, 0xf8, 0xe2, 0x71, 0xb0, 0x75, 0xd2, 0x75, 0xd7, 0x24, + 0x0f, 0xa5, 0xc2, 0xa1, 0x51, 0xb9, 0xf2, 0xf9, 0x49, 0x29, 0x29, 0xbc, + 0x5c, 0x86, 0x61, 0x4d, 0xfb, 0x01, 0x5c, 0x00, 0x19, 0x77, 0xdf, 0x29, + 0x81, 0xa6, 0xb9, 0xf2, 0x4c, 0x5f, 0x16, 0xf9, 0x5c, 0x81, 0xdd, 0x6d, + 0xf1, 0x5c, 0xca, 0x43, 0xb2, 0x29, 0x29, 0xbe, 0x9e, 0x00, 0xd8, 0x58, + 0x20, 0x80, 0xb7, 0x06, 0x91, 0xc9, 0xd0, 0x67, 0x13, 0x6f, 0x16, 0x3a, + 0xc2, 0x6d, 0x01, 0xc8, 0xf4, 0x28, 0x6b, 0x7c, 0xaf, 0x8b, 0x75, 0xdf, + 0x17, 0x9c, 0x09, 0xb9, 0xcf, 0x95, 0x40, 0x11, 0x5d, 0xb0, 0xa8, 0xd8, + 0xec, 0x3f, 0x00, 0x06, 0x4a, 0xd9, 0x50, 0xd6, 0xfd, 0x57, 0xbc, 0xde, + 0xb9, 0xc7, 0xae, 0x06, 0x6c, 0x55, 0xcb, 0x02, 0x2c, 0x2d, 0xbe, 0x82, + 0x00, 0xec, 0x50, 0x01, 0xd3, 0xbb, 0x27, 0x9a, 0x3e, 0xf6, 0xf1, 0x3b, + 0xa1, 0xf9, 0x4a, 0xc3, 0xa2, 0xc9, 0x32, 0x14, 0x3d, 0xbc, 0xe7, 0xc6, + 0xf3, 0xfe, 0x82, 0x9d, 0xcb, 0xdc, 0x59, 0x30, 0xcd, 0xdb, 0xae, 0x1e, + 0x9e, 0x45, 0xc0, 0xf8, 0x30, 0x9a, 0xdd, 0xbf, 0xf6, 0x75, 0xf5, 0xbc, + 0x0a, 0xe3, 0x32, 0x1d, 0x26, 0xdb, 0x15, 0xc8, 0x7a, 0xac, 0x1b, 0x42, + 0x9b, 0xcc, 0xb8, 0xa7, 0x27, 0x80, 0x1e, 0xd9, 0x86, 0xc6, 0xf8, 0x7f, + 0x5f, 0x8e, 0x5f, 0xc0, 0xa1, 0x3b, 0x47, 0x57, 0x6b, 0xb2, 0xec, 0x83, + 0x8f, 0x80, 0x72, 0x36, 0xe0, 0x05, 0xe0, 0x0f, 0x2e, 0x91, 0xfc, 0x9e, + 0xeb, 0x95, 0x51, 0xfb, 0x62, 0xdc, 0xcb, 0x69, 0x90, 0xbd, 0x18, 0xad, + 0x8b, 0x8d, 0x70, 0x02, 0x69, 0xc7, 0x02, 0xdd, 0x40, 0x7b, 0x16, 0x2a, + 0xc4, 0x32, 0x1e, 0x50, 0xc0, 0xa8, 0xde, 0xa8, 0x00, 0xab, 0x6f, 0xf7, + 0xb1, 0x7d, 0x8a, 0x96, 0x8f, 0x86, 0xf3, 0xce, 0xe9, 0x65, 0x5a, 0x85, + 0xd5, 0x28, 0x96, 0xda, 0xda, 0x9b, 0x61, 0x4c, 0xee, 0x96, 0xdf, 0x9d, + 0xe8, 0xd0, 0x02, 0x87, 0x6a, 0xf7, 0x46, 0xae, 0xe8, 0xbd, 0xde, 0x70, + 0xb1, 0x9e, 0x5f, 0xa8, 0xbe, 0x2d, 0xe3, 0xdf, 0x79, 0xfe, 0xce, 0x11, + 0xc1, 0x92, 0xd7, 0xa2, 0x78, 0xa9, 0xde, 0x2d, 0xf4, 0x37, 0x89, 0x80, + 0x82, 0x02, 0xbb, 0xce, 0xc7, 0x58, 0x4c, 0xb2, 0x3d, 0x33, 0x24, 0xa1, + 0x11, 0x0a, 0x81, 0x4c, 0xbf, 0xdd, 0x84, 0x4f, 0x7e, 0xf4, 0x5b, 0xe2, + 0x2c, 0xb8, 0x66, 0x6d, 0x86, 0x60, 0xf0, 0x89, 0x1b, 0x1e, 0x83, 0xae, + 0x69, 0x0a, 0xb3, 0x85, 0x40, 0x2d, 0xbe, 0x98, 0xbe, 0xef, 0xc7, 0x2f, + 0x9f, 0x3d, 0xdd, 0xd3, 0xb8, 0xd9, 0x29, 0x86, 0x5b, 0xb4, 0x7e, 0x53, + 0x92, 0x28, 0xe6, 0xf2, 0xdf, 0x4e, 0x34, 0x01, 0xac, 0xf8, 0x9f, 0x99, + 0xfb, 0xdd, 0xd4, 0x95, 0x6e, 0xd2, 0xc9, 0xa7, 0xa0, 0xd6, 0xe7, 0x11, + 0x26, 0xfd, 0xc8, 0xc2, 0x05, 0xfb, 0x60, 0x6e, 0x65, 0x7e, 0x5b, 0xbb, + 0x20, 0x61, 0x69, 0x5b, 0x38, 0x03, 0x17, 0x71, 0xf4, 0xf7, 0xdc, 0x0f, + 0x87, 0xad, 0xce, 0x7a, 0x90, 0xd4, 0x0d, 0xc9, 0x62, 0xf8, 0xb7, 0x4f, + 0x12, 0xb9, 0xd9, 0xb2, 0x84, 0xa4, 0x58, 0x42, 0x69, 0x18, 0x05, 0x30, + 0x00, 0x00, 0x01, 0x0e, 0x43, 0xfa, 0xd0, 0x87, 0x4c, 0x11, 0xbc, 0xe4, + 0x90, 0xb2, 0xea, 0x14, 0x60, 0x5b, 0x78, 0x70, 0x02, 0x7e, 0x7a, 0x00, + 0x75, 0xd1, 0x02, 0xef, 0x35, 0x60, 0x22, 0x00, 0x26, 0x5b, 0x8f, 0xbb, + 0x80, 0x60, 0xc3, 0x14, 0xc3, 0xe1, 0x61, 0x81, 0x8d, 0xed, 0x7e, 0xa0, + 0x16, 0x00, 0x2d, 0x23, 0x5d, 0xe9, 0x2d, 0x2a, 0xae, 0x75, 0xa0, 0x66, + 0xcb, 0x2a, 0x16, 0x59, 0x29, 0xbb, 0x82, 0x78, 0xe7, 0x3d, 0xf8, 0x00, + 0xb2, 0x55, 0xab, 0x86, 0x3e, 0x1f, 0x1f, 0x4a, 0x91, 0x14, 0x69, 0x6d, + 0xf3, 0x59, 0x24, 0xd3, 0x2d, 0x21, 0x9c, 0xde, 0x45, 0x95, 0xf5, 0x27, + 0x82, 0xc6, 0xf5, 0x72, 0xed, 0x00, 0x2f, 0x79, 0x16, 0x41, 0x7c, 0xdf, + 0xdd, 0xef, 0x34, 0xcb, 0x84, 0x13, 0x09, 0xee, 0x8b, 0x92, 0xcb, 0x5d, + 0xe4, 0xa8, 0x72, 0xb7, 0xbf, 0xb5, 0xdb, 0xc4, 0x55, 0x83, 0x2e, 0xab, + 0xd6, 0x50, 0x11, 0x01, 0xed, 0xc5, 0xb6, 0x80, 0x5b, 0x65, 0xb4, 0xb4, + 0x59, 0x9b, 0x91, 0x14, 0x9b, 0x4b, 0xb4, 0xf2, 0xdb, 0xad, 0x9b, 0xb5, + 0xf2, 0x05, 0x98, 0x52, 0x4b, 0xfa, 0x18, 0x59, 0xde, 0xad, 0xb3, 0xa7, + 0x9a, 0x18, 0xa4, 0x86, 0xf4, 0x23, 0x7d, 0x0c, 0x5c, 0x2d, 0x03, 0x29, + 0x71, 0x65, 0x18, 0x43, 0x6f, 0x2c, 0x00, 0xb7, 0xe7, 0xcb, 0x24, 0xcc, + 0x71, 0x63, 0x4a, 0x1a, 0xde, 0x96, 0x48, 0xbb, 0x2e, 0x51, 0xb5, 0x21, + 0x85, 0xca, 0x49, 0x6c, 0x79, 0x2e, 0xba, 0x47, 0x5b, 0x07, 0x87, 0xd8, + 0x50, 0x61, 0x43, 0xeb, 0x68, 0xfe, 0x77, 0x87, 0x67, 0x94, 0xf0, 0xa7, + 0xd4, 0xac, 0xae, 0xdc, 0x85, 0x4f, 0x56, 0xfc, 0x08, 0x03, 0x59, 0x00, + 0x1e, 0x6f, 0xff, 0x79, 0xe2, 0x04, 0x08, 0x22, 0x67, 0x2b, 0x40, 0x4b, + 0x69, 0xbc, 0xac, 0x41, 0xd0, 0x3e, 0xb7, 0xe3, 0x8f, 0xaf, 0x0f, 0x22, + 0x66, 0x9a, 0x65, 0x83, 0x53, 0x2a, 0x12, 0x4a, 0x6f, 0xe8, 0x24, 0xc7, + 0x67, 0x7e, 0x56, 0xed, 0x43, 0xab, 0xdc, 0x1c, 0xa4, 0x30, 0xe8, 0xdf, + 0x9c, 0xc0, 0x14, 0x13, 0xc0, 0x16, 0x0a, 0xb7, 0x9e, 0xf6, 0xd1, 0xaa, + 0x23, 0x2d, 0xd3, 0x0e, 0xb4, 0x38, 0x64, 0x81, 0x2d, 0xc8, 0xe8, 0x01, + 0x66, 0xc9, 0x7c, 0x57, 0xc4, 0xf6, 0xe6, 0x52, 0x75, 0x02, 0xdb, 0xfc, + 0xdb, 0xf0, 0x23, 0x05, 0xab, 0xd0, 0x32, 0x1c, 0x69, 0xde, 0x0c, 0x04, + 0xd0, 0x0b, 0x5f, 0x35, 0x60, 0x0a, 0x83, 0xa1, 0x94, 0x2c, 0xb3, 0xa3, + 0x7b, 0x5f, 0xae, 0xe8, 0x94, 0xe3, 0x16, 0x0d, 0x2e, 0x42, 0xd2, 0x86, + 0x41, 0x8d, 0xc7, 0x71, 0x3f, 0xe3, 0xbe, 0x0d, 0xa5, 0x8c, 0x2a, 0xc9, + 0x43, 0x1b, 0x47, 0x2d, 0xe3, 0x2d, 0x94, 0x30, 0x2d, 0xb3, 0x95, 0x4f, + 0x6f, 0x73, 0xf3, 0x5f, 0xf7, 0x22, 0x0a, 0xee, 0x65, 0x3b, 0x03, 0xf9, + 0x17, 0x7a, 0xd4, 0xa3, 0x13, 0x39, 0xb1, 0x55, 0x47, 0x16, 0xdc, 0xc1, + 0x55, 0xff, 0x41, 0x1d, 0x70, 0x4f, 0x09, 0xd8, 0x28, 0x53, 0x9c, 0x48, + 0x89, 0x14, 0x32, 0x37, 0xbb, 0x11, 0x1c, 0x00, 0xe5, 0xff, 0xfe, 0x32, + 0x4a, 0x52, 0x9b, 0xc7, 0xdb, 0xda, 0x89, 0x36, 0xe0, 0xd3, 0x62, 0x55, + 0xb3, 0x46, 0xa0, 0xda, 0x31, 0xbe, 0x6e, 0x47, 0xf6, 0x76, 0xe6, 0x6e, + 0x65, 0xc3, 0x91, 0x75, 0x0d, 0x44, 0x08, 0x6d, 0x31, 0x34, 0xc2, 0xe0, + 0x04, 0x55, 0xad, 0x47, 0x90, 0x9b, 0xed, 0x09, 0x15, 0x08, 0xdc, 0xfc, + 0xd9, 0x9c, 0xf9, 0x97, 0x2c, 0xe7, 0xbc, 0x97, 0x75, 0xd1, 0xc9, 0x61, + 0x6a, 0x85, 0xd6, 0xf2, 0xd5, 0x04, 0x0b, 0xa6, 0x37, 0xa5, 0x76, 0x52, + 0x2f, 0x6e, 0x16, 0xe9, 0xe9, 0x4b, 0x40, 0xb6, 0xcc, 0x2d, 0x7e, 0xc4, + 0x61, 0x4f, 0x7d, 0xa0, 0x93, 0xff, 0x85, 0x81, 0xca, 0x16, 0xd9, 0x3a, + 0x1b, 0xb9, 0x64, 0x0a, 0xab, 0x63, 0x67, 0x90, 0xe6, 0xfc, 0xc3, 0xa5, + 0x17, 0x12, 0x10, 0xd0, 0x90, 0xde, 0x84, 0xd3, 0x79, 0x0e, 0xc0, 0xb9, + 0x46, 0x8c, 0x64, 0x00, 0x7f, 0x27, 0x5f, 0x3a, 0x57, 0x86, 0x8f, 0x6a, + 0x37, 0x2e, 0xf5, 0x29, 0x41, 0x11, 0x10, 0xe2, 0x9b, 0x59, 0x67, 0x92, + 0x56, 0xb3, 0xa2, 0x5f, 0x56, 0xfd, 0x4c, 0xda, 0x47, 0xf3, 0x87, 0x82, + 0x38, 0x01, 0xc5, 0xcb, 0x76, 0x80, 0x8a, 0xc3, 0x7c, 0x22, 0xb6, 0xaf, + 0x70, 0x42, 0x00, 0x8d, 0x7b, 0xac, 0x0a, 0x00, 0xa8, 0xce, 0xaa, 0x84, + 0xa9, 0x97, 0xd0, 0xb8, 0xd9, 0xf4, 0x10, 0xbf, 0xc4, 0x02, 0xaa, 0x58, + 0x24, 0xff, 0xde, 0x79, 0x96, 0x12, 0x92, 0xd2, 0x53, 0x77, 0x72, 0xd7, + 0x60, 0x9b, 0x3d, 0x3d, 0xb7, 0x5e, 0x9e, 0x0f, 0xb8, 0x00, 0x30, 0x56, + 0xe8, 0x80, 0x85, 0xff, 0x53, 0x40, 0xe6, 0xef, 0x80, 0x85, 0xff, 0x53, + 0x40, 0xe2, 0x43, 0x7e, 0x50, 0xa0, 0x07, 0xd7, 0x39, 0xa8, 0x13, 0xa2, + 0x6e, 0x3a, 0xf8, 0x99, 0x97, 0x03, 0x06, 0xd6, 0xeb, 0x60, 0x7e, 0xe3, + 0xad, 0xa1, 0x92, 0x81, 0x9b, 0x20, 0x5d, 0xc5, 0x02, 0x9b, 0x9e, 0x5f, + 0x1b, 0xd4, 0xce, 0x22, 0x17, 0x65, 0x00, 0x3d, 0xef, 0xe6, 0x49, 0x60, + 0x65, 0xb2, 0x2f, 0x8a, 0x63, 0x5f, 0x96, 0xd0, 0xfb, 0x43, 0x0b, 0xee, + 0xa6, 0x6a, 0x9c, 0x58, 0xd0, 0xd3, 0x9b, 0x73, 0x9b, 0xb0, 0xf0, 0x39, + 0xbc, 0xe2, 0x4c, 0xfb, 0x91, 0x84, 0x57, 0x48, 0x11, 0x6d, 0xba, 0x1b, + 0x43, 0xc3, 0xda, 0x77, 0x60, 0x89, 0xed, 0x74, 0xf0, 0x1e, 0xf5, 0xce, + 0x07, 0x00, 0x89, 0x06, 0xd3, 0xbc, 0x1b, 0xa2, 0x21, 0x3f, 0xe2, 0x7a, + 0x2b, 0xc3, 0x21, 0x72, 0x9c, 0xd5, 0xbf, 0x00, 0x2a, 0x13, 0xc6, 0xad, + 0x18, 0xaa, 0x61, 0x84, 0x34, 0x28, 0x94, 0xd0, 0xda, 0xd2, 0xdb, 0xc7, + 0xcc, 0x59, 0x72, 0x18, 0x30, 0x68, 0xca, 0x12, 0x8d, 0x5b, 0x83, 0xe6, + 0xe8, 0xc0, 0xca, 0x64, 0x08, 0x2d, 0x15, 0xb6, 0xee, 0xe3, 0xb8, 0x20, + 0xcd, 0xa1, 0x98, 0xb5, 0x03, 0x69, 0x34, 0x35, 0xb1, 0x3f, 0x26, 0xe4, + 0xa5, 0x85, 0x5b, 0x28, 0x0d, 0x58, 0x60, 0x73, 0x76, 0x6a, 0x9b, 0x69, + 0x09, 0xb9, 0x12, 0x63, 0x9d, 0x10, 0x87, 0x4e, 0xf5, 0x6d, 0x99, 0x27, + 0xb3, 0xf2, 0xa3, 0x73, 0xe2, 0xe4, 0xcd, 0x84, 0x35, 0x91, 0x91, 0xf1, + 0x83, 0x9b, 0xba, 0x47, 0xce, 0x31, 0xfe, 0x74, 0x74, 0x4b, 0xb2, 0x25, + 0x38, 0x71, 0xea, 0xdc, 0xc5, 0xb3, 0xdc, 0x0c, 0x41, 0xf4, 0x3a, 0x48, + 0x54, 0x3e, 0x9e, 0x36, 0xd6, 0xe9, 0x5a, 0x6c, 0x75, 0x50, 0x95, 0x83, + 0x7d, 0x5b, 0x6f, 0xde, 0x9b, 0x1c, 0x20, 0x56, 0x40, 0x1e, 0x3d, 0xf8, + 0xff, 0xcb, 0xa1, 0xde, 0x2a, 0xd9, 0xe4, 0x36, 0x65, 0x2f, 0xc2, 0xb7, + 0x87, 0x03, 0x8c, 0x00, 0x18, 0x37, 0x85, 0xe2, 0xbc, 0xfa, 0xe9, 0xcf, + 0xe3, 0x81, 0x98, 0x6d, 0x43, 0x31, 0x10, 0x79, 0x0d, 0xbe, 0x89, 0xf7, + 0xf9, 0x23, 0x7b, 0x91, 0xb1, 0xef, 0xe6, 0x3e, 0x17, 0x45, 0x73, 0x9b, + 0x09, 0xb2, 0x51, 0xd4, 0x61, 0x2d, 0xbc, 0x3f, 0xc7, 0x52, 0x2e, 0xee, + 0x8f, 0xba, 0x56, 0x64, 0x91, 0x0a, 0x38, 0x07, 0xb6, 0xd5, 0x6d, 0xcf, + 0x33, 0xe7, 0xdb, 0xdb, 0x65, 0x43, 0xae, 0x65, 0x0e, 0xdb, 0x6c, 0xa9, + 0x4e, 0xd3, 0x8a, 0x28, 0x63, 0x73, 0x5a, 0x4e, 0x29, 0x42, 0x56, 0x36, + 0x4d, 0xfb, 0xa0, 0x06, 0x3e, 0xd0, 0x8d, 0xf5, 0x76, 0xa7, 0x32, 0x95, + 0x09, 0xd5, 0xee, 0xdc, 0x57, 0x80, 0xac, 0x34, 0x63, 0x0f, 0xf8, 0x03, + 0x51, 0x1f, 0x3d, 0x3b, 0x9e, 0x74, 0x53, 0xec, 0x0f, 0x9c, 0x08, 0xde, + 0x03, 0xc9, 0xf6, 0x16, 0xb1, 0x54, 0xa4, 0x3c, 0x39, 0x8e, 0x7c, 0x8a, + 0x00, 0x45, 0xef, 0x1e, 0x47, 0xe2, 0xf1, 0x88, 0xee, 0x2e, 0x51, 0x77, + 0x9f, 0x2c, 0x7e, 0x97, 0xb5, 0x35, 0x24, 0xb4, 0x60, 0xc5, 0x6f, 0x25, + 0x9c, 0x5f, 0x62, 0x2f, 0xdf, 0xab, 0xe7, 0x64, 0x01, 0x26, 0x3c, 0x8d, + 0x97, 0x5e, 0xe9, 0x56, 0xd3, 0x4c, 0xe4, 0xac, 0xa8, 0x3a, 0xdc, 0x56, + 0x29, 0x65, 0x94, 0x34, 0x6c, 0x3d, 0xaa, 0x94, 0xdf, 0xb3, 0x13, 0xf0, + 0x23, 0x3e, 0xb7, 0x9e, 0x33, 0xb7, 0x6a, 0x21, 0xaf, 0x14, 0xf7, 0x6f, + 0x96, 0x18, 0xa7, 0x4b, 0x12, 0x01, 0x03, 0xaa, 0x36, 0x7f, 0xe8, 0x91, + 0x0e, 0x11, 0x5c, 0x25, 0xfc, 0xb8, 0xeb, 0xc3, 0xf8, 0xce, 0xde, 0xee, + 0x0a, 0xfc, 0xc3, 0xe5, 0x19, 0xad, 0xf1, 0x8e, 0x30, 0x02, 0xde, 0x05, + 0x23, 0x8c, 0x81, 0x9b, 0x20, 0xc2, 0xbf, 0x43, 0xfc, 0x1b, 0xe9, 0x7f, + 0x04, 0x57, 0x80, 0x3d, 0xeb, 0x81, 0x73, 0x45, 0x67, 0xea, 0x3a, 0x75, + 0xbd, 0xcd, 0xcc, 0x85, 0x50, 0x31, 0xe5, 0x4b, 0x95, 0x8e, 0xec, 0xc4, + 0x92, 0x40, 0x9b, 0x16, 0xb6, 0x74, 0x07, 0xed, 0xf4, 0x72, 0x3c, 0x50, + 0xa5, 0xdb, 0x69, 0x5f, 0x9d, 0x97, 0x23, 0xf5, 0xcb, 0x16, 0x7e, 0xcb, + 0xa8, 0x71, 0xcc, 0xa0, 0x0b, 0x7e, 0x1f, 0x2f, 0x4f, 0x8f, 0x83, 0xf2, + 0xe3, 0xdd, 0xae, 0xcd, 0x94, 0xaa, 0x36, 0x0c, 0xb0, 0x7a, 0x37, 0x50, + 0x8b, 0x9d, 0x00, 0x31, 0xea, 0x91, 0xb4, 0x5c, 0x95, 0x30, 0x3b, 0x3e, + 0x9f, 0x57, 0xbb, 0x98, 0x5a, 0x2f, 0x95, 0x87, 0xa8, 0x4a, 0x58, 0x8d, + 0xe5, 0x00, 0x1a, 0x11, 0xbd, 0xb0, 0x57, 0x5c, 0x4c, 0xeb, 0x21, 0x77, + 0xcb, 0x80, 0xc8, 0x34, 0xb4, 0x1b, 0x5b, 0x91, 0xf5, 0x65, 0x52, 0x15, + 0x29, 0x9d, 0xa5, 0xd6, 0xfe, 0xac, 0x47, 0x12, 0x08, 0x5f, 0xdc, 0xf3, + 0x7c, 0x8a, 0xa9, 0xbc, 0x75, 0xb6, 0xa5, 0x8b, 0x68, 0xd0, 0xd4, 0x6e, + 0x37, 0xb7, 0x02, 0x38, 0xe8, 0xcd, 0x74, 0x44, 0x9e, 0x5b, 0x14, 0xf8, + 0xad, 0xe8, 0xc0, 0x15, 0x09, 0xe4, 0x00, 0xac, 0x56, 0x11, 0xc8, 0x95, + 0xe7, 0x4a, 0x01, 0x63, 0x89, 0xcf, 0x7e, 0xb8, 0x11, 0x00, 0x10, 0x6c, + 0x3c, 0xcc, 0x2f, 0xd5, 0xbd, 0x00, 0x01, 0x8f, 0xb7, 0x5e, 0xe2, 0xdd, + 0xd0, 0x93, 0x76, 0xc0, 0x09, 0x97, 0x9e, 0x39, 0xf2, 0x7a, 0x96, 0xe0, + 0x20, 0x30, 0x31, 0xb9, 0xc5, 0x87, 0x49, 0x2c, 0x09, 0x09, 0x8d, 0x3c, + 0x93, 0x12, 0x84, 0xb7, 0xf2, 0x0f, 0x79, 0x3e, 0xb7, 0xe3, 0x1d, 0x64, + 0x0d, 0xd5, 0x32, 0xf8, 0x58, 0xde, 0x97, 0xb1, 0x64, 0x07, 0x5a, 0xe9, + 0x98, 0x12, 0x61, 0xb6, 0xd3, 0xdb, 0xea, 0xa0, 0x05, 0xe2, 0x63, 0xb3, + 0xbb, 0xe7, 0x12, 0x19, 0x9a, 0xec, 0xc7, 0xe8, 0x18, 0x94, 0xfb, 0xe4, + 0xe9, 0x4e, 0xba, 0x91, 0x42, 0x1b, 0xe0, 0xc2, 0x83, 0xa6, 0x6a, 0xe0, + 0xfc, 0x0e, 0xdf, 0xd5, 0x3d, 0xbb, 0x37, 0xf2, 0x5e, 0x2b, 0x1b, 0x92, + 0x6b, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x43, 0xfd, 0x0a, 0x00, 0xf4, 0x58, + 0xaf, 0xbf, 0xbf, 0x02, 0x2d, 0x72, 0xa2, 0x9b, 0x98, 0xeb, 0x6b, 0xe4, + 0xc3, 0x96, 0xc9, 0x0b, 0x46, 0xf4, 0x06, 0xf1, 0xd7, 0x0b, 0xa5, 0x14, + 0x5c, 0xcb, 0xb2, 0x19, 0x4e, 0xa7, 0x97, 0x5b, 0x9b, 0xc3, 0x80, 0x0f, + 0x9f, 0xab, 0x9a, 0xa3, 0x1d, 0xa9, 0x53, 0x2d, 0xc4, 0x52, 0xea, 0x14, + 0xa3, 0x56, 0x37, 0x20, 0x52, 0xe7, 0x31, 0xcf, 0xd3, 0x51, 0x03, 0xf7, + 0xbe, 0x13, 0x2e, 0xd0, 0xc2, 0xc7, 0x51, 0xed, 0xf2, 0x99, 0x52, 0xac, + 0xf0, 0x2d, 0xb8, 0x60, 0xfb, 0x5b, 0xf5, 0x02, 0xaa, 0x6f, 0x36, 0x65, + 0x88, 0x50, 0x74, 0x42, 0x86, 0x9c, 0x1a, 0x81, 0xad, 0xe4, 0x00, 0x1e, + 0x4e, 0xfe, 0x3e, 0xf9, 0x32, 0x45, 0x29, 0x03, 0xae, 0xf9, 0x5d, 0x96, + 0x18, 0x58, 0xf8, 0xbe, 0x0d, 0xe1, 0xc0, 0x17, 0x6f, 0x04, 0x6e, 0x78, + 0x32, 0xe5, 0x5b, 0x53, 0x74, 0x53, 0xcb, 0xc9, 0xa1, 0xf4, 0x39, 0xf2, + 0x17, 0x6c, 0x6d, 0x9f, 0x02, 0xbb, 0xcf, 0xa7, 0xd6, 0xc1, 0x7c, 0x82, + 0x30, 0x02, 0x55, 0x0f, 0x0e, 0x85, 0x00, 0x90, 0xe5, 0xb6, 0x2f, 0x83, + 0x67, 0x31, 0x66, 0x92, 0x55, 0xb9, 0xb0, 0x3a, 0x2b, 0x7f, 0x41, 0xff, + 0x40, 0x03, 0xfe, 0x85, 0xf0, 0xf3, 0x28, 0x23, 0xff, 0xef, 0x0f, 0x0f, + 0xd3, 0x62, 0x8f, 0xa1, 0xa5, 0xb0, 0x14, 0xb8, 0x2a, 0x71, 0xc8, 0x98, + 0x01, 0x2e, 0x6c, 0xd5, 0x74, 0xe3, 0x30, 0xaf, 0x5b, 0x4e, 0x0d, 0x46, + 0xe3, 0xf1, 0x7b, 0xff, 0xd2, 0x29, 0xb5, 0xd0, 0xb3, 0x37, 0xc9, 0xdb, + 0xbc, 0xee, 0x39, 0xe5, 0xee, 0x01, 0x8b, 0x61, 0x34, 0x29, 0xbd, 0x0f, + 0xdf, 0xbd, 0xd8, 0xb8, 0xea, 0x1d, 0x9f, 0x8c, 0xf3, 0xde, 0x7c, 0xa9, + 0xa7, 0x87, 0x45, 0x2c, 0xc3, 0x94, 0x63, 0x6a, 0x64, 0xd5, 0xa8, 0xda, + 0xa4, 0xdc, 0x02, 0xdb, 0xe3, 0xf5, 0xf0, 0xe0, 0x04, 0x80, 0x06, 0xaf, + 0xaf, 0x50, 0x26, 0xf1, 0xbc, 0x4a, 0xe5, 0x85, 0x93, 0x6d, 0x54, 0x50, + 0xb6, 0xfc, 0xff, 0xf5, 0xcc, 0xcb, 0x0c, 0x37, 0xc6, 0x4a, 0xdf, 0xa5, + 0x48, 0xb9, 0xc5, 0x22, 0x7c, 0xf7, 0x95, 0x16, 0xc9, 0xb3, 0x31, 0x0d, + 0xb4, 0xf3, 0xec, 0xb1, 0x56, 0x24, 0x29, 0x5b, 0xe4, 0x80, 0x0d, 0xfe, + 0x01, 0x04, 0x06, 0x7f, 0xb3, 0x39, 0x15, 0xc8, 0xc0, 0xe2, 0x0b, 0x97, + 0xcc, 0xb0, 0x20, 0x29, 0xb0, 0x32, 0x66, 0x3b, 0x25, 0x0a, 0x7b, 0x64, + 0xf9, 0xe5, 0x24, 0x4f, 0x16, 0xfc, 0x30, 0xbd, 0xc0, 0x07, 0x9f, 0xfd, + 0xe7, 0x3c, 0xd4, 0x6a, 0x49, 0x64, 0x32, 0x37, 0x91, 0x22, 0xf7, 0xc1, + 0x17, 0x34, 0x40, 0x8e, 0xea, 0x17, 0x25, 0xe7, 0x16, 0xf3, 0xd6, 0x6c, + 0x35, 0x3c, 0xae, 0x1e, 0xb0, 0xa3, 0x9b, 0xe9, 0xc0, 0x05, 0x70, 0x57, + 0x0f, 0xdf, 0x8f, 0xe4, 0x01, 0xe6, 0x87, 0x1a, 0x5d, 0x94, 0xc9, 0xbe, + 0x5b, 0x96, 0x5b, 0x2c, 0x6f, 0x94, 0x49, 0xf8, 0xf8, 0x9a, 0xa1, 0x73, + 0x9c, 0x36, 0xda, 0x1a, 0x5c, 0x25, 0x37, 0x6e, 0x5a, 0x9f, 0x9a, 0x15, + 0x56, 0x94, 0xcc, 0xfb, 0x1b, 0x0e, 0x96, 0x00, 0x5b, 0x4d, 0xc0, 0x15, + 0xaa, 0x43, 0xc3, 0x21, 0xed, 0x88, 0xae, 0x05, 0x77, 0x00, 0x06, 0x7a, + 0xaa, 0x48, 0x46, 0xfa, 0xaf, 0xbd, 0xd9, 0xfc, 0x12, 0x46, 0xd3, 0x34, + 0x30, 0x0c, 0xf9, 0xfb, 0x66, 0xc0, 0xf3, 0xa6, 0x48, 0x6c, 0x94, 0xa3, + 0xea, 0x37, 0xcd, 0x36, 0xf9, 0xbf, 0x05, 0xe5, 0x08, 0x84, 0x02, 0xb5, + 0xb4, 0x96, 0xdc, 0xc8, 0xbe, 0x87, 0x10, 0xd9, 0xc3, 0x9b, 0xfa, 0x6f, + 0xc0, 0xbf, 0x70, 0x02, 0x3f, 0x69, 0xbd, 0x08, 0xed, 0x41, 0x10, 0x01, + 0x30, 0x51, 0xaa, 0x80, 0x91, 0xff, 0x92, 0xfe, 0xe0, 0xe5, 0xaa, 0xdb, + 0x3f, 0xff, 0x34, 0x01, 0xf6, 0x91, 0x08, 0xc2, 0x62, 0x9f, 0x69, 0xbc, + 0x71, 0xbf, 0x9d, 0x26, 0xd2, 0xad, 0x85, 0x41, 0xad, 0xe4, 0x3b, 0xf8, + 0x04, 0x1f, 0xd9, 0x00, 0x12, 0x00, 0x5b, 0x68, 0x64, 0x36, 0x3c, 0xca, + 0x38, 0x3f, 0xc8, 0xe4, 0xa5, 0xf8, 0x37, 0xe8, 0x2f, 0x91, 0x3b, 0xcf, + 0xb8, 0xb8, 0x06, 0x60, 0xc7, 0x5e, 0xdd, 0xa8, 0x93, 0x53, 0x15, 0x23, + 0xee, 0x20, 0xc2, 0x1b, 0x79, 0xef, 0x90, 0x52, 0x5d, 0xa0, 0x03, 0x46, + 0xca, 0x95, 0x16, 0x7a, 0xb7, 0xf1, 0x30, 0x07, 0x74, 0x10, 0x40, 0x5c, + 0x4f, 0xf7, 0xda, 0x20, 0xf5, 0xcf, 0x7e, 0x9c, 0x1f, 0x6c, 0x2a, 0x9b, + 0x62, 0xac, 0x92, 0xa0, 0xc1, 0xed, 0xf2, 0x8e, 0x13, 0x8b, 0xb7, 0x6f, + 0x81, 0x8b, 0x3c, 0x5b, 0xf4, 0xf9, 0x10, 0x48, 0x20, 0x80, 0xe7, 0xd3, + 0x3e, 0x5d, 0x9c, 0xe9, 0x76, 0xde, 0x36, 0xbf, 0x4d, 0xab, 0x7c, 0xe9, + 0x4b, 0x9a, 0x7a, 0xa5, 0x3d, 0x5b, 0xf3, 0x5f, 0xcc, 0x20, 0x76, 0xf7, + 0x49, 0x7c, 0x26, 0x6d, 0x1f, 0x06, 0x6b, 0x75, 0x17, 0xde, 0x9b, 0xe8, + 0x3e, 0x05, 0xb6, 0xaa, 0xa7, 0xb7, 0xc4, 0xe3, 0x83, 0x76, 0x65, 0x40, + 0x08, 0xee, 0x2b, 0x7b, 0xf8, 0x08, 0x40, 0x15, 0xa2, 0xce, 0x90, 0xf0, + 0x43, 0x00, 0x68, 0x14, 0x79, 0x3e, 0x58, 0x49, 0x6f, 0x17, 0x26, 0xf9, + 0xe1, 0x6a, 0x3b, 0xf3, 0x6b, 0xac, 0xf0, 0xa0, 0x6d, 0xbd, 0xc6, 0x4b, + 0xd0, 0x81, 0x32, 0x5a, 0x11, 0x1d, 0xc6, 0x85, 0x02, 0x27, 0xfd, 0x6a, + 0xfa, 0x48, 0xde, 0xb5, 0x0f, 0x6f, 0x41, 0x49, 0xe0, 0x73, 0x74, 0x71, + 0x9c, 0xce, 0xdd, 0xf8, 0xa1, 0x7e, 0xdb, 0xef, 0xc8, 0x4d, 0x59, 0xb3, + 0x56, 0xc1, 0xc9, 0x2c, 0xad, 0x81, 0xe6, 0x68, 0xbf, 0x7f, 0x6d, 0x81, + 0x59, 0xf3, 0x5d, 0xbc, 0x51, 0xc1, 0xc6, 0x58, 0x78, 0x49, 0x4c, 0xfd, + 0x3a, 0xd1, 0x5c, 0x77, 0x65, 0x83, 0x03, 0xbf, 0x92, 0xcd, 0xb0, 0xf3, + 0xf7, 0x39, 0x59, 0x00, 0x46, 0x5a, 0xb6, 0xbd, 0xc7, 0x89, 0xeb, 0xef, + 0xca, 0xe5, 0x5a, 0x56, 0xe0, 0x87, 0x88, 0xc7, 0xe4, 0x3c, 0x02, 0x57, + 0x6e, 0xfa, 0x16, 0xda, 0xb7, 0x54, 0x6f, 0x9b, 0x43, 0xde, 0x2a, 0xf8, + 0xc3, 0x62, 0x14, 0x12, 0x91, 0xbd, 0x35, 0xda, 0x44, 0x30, 0xcd, 0xf4, + 0xd7, 0xd2, 0xbd, 0x2a, 0x92, 0xdb, 0x83, 0xdc, 0xb9, 0x5d, 0x73, 0x9a, + 0x3e, 0x58, 0xf7, 0xdd, 0x88, 0x4c, 0x38, 0xb1, 0x81, 0x55, 0xba, 0x76, + 0x00, 0x1b, 0x07, 0x27, 0x8e, 0xf9, 0xd4, 0x1a, 0x73, 0x65, 0x5b, 0xa0, + 0xf5, 0x6f, 0x90, 0x58, 0xa3, 0x0b, 0xf5, 0x83, 0x82, 0xd4, 0x84, 0xc7, + 0x7f, 0x39, 0x0b, 0xf5, 0x80, 0x7c, 0x6b, 0xea, 0x67, 0x56, 0xcb, 0x68, + 0x61, 0xb8, 0x97, 0x4a, 0x1c, 0xa3, 0xce, 0x68, 0xf7, 0x57, 0xd8, 0xf8, + 0x81, 0xa9, 0x9a, 0x51, 0x0d, 0x19, 0x1c, 0xc1, 0xe8, 0xde, 0x19, 0x08, + 0x19, 0x14, 0xb0, 0x98, 0x9b, 0xe8, 0x39, 0xb9, 0xcf, 0x2b, 0x70, 0x95, + 0x28, 0xc0, 0xa0, 0xd6, 0xed, 0x2b, 0xde, 0xf9, 0x66, 0x21, 0xe0, 0x88, + 0x00, 0x95, 0x54, 0x2a, 0x61, 0xed, 0xc0, 0x2b, 0x08, 0x13, 0x3d, 0x75, + 0x2c, 0x24, 0xc6, 0x9a, 0xca, 0x14, 0x07, 0x37, 0xf6, 0x90, 0x02, 0x5f, + 0x20, 0x02, 0xd0, 0x06, 0xd3, 0xd9, 0xdb, 0x68, 0x0f, 0x7b, 0x27, 0xf0, + 0xfc, 0xe2, 0x4a, 0xb7, 0xf7, 0x76, 0x67, 0x85, 0xb1, 0xbd, 0x4f, 0x6f, + 0xd0, 0x40, 0x03, 0x9e, 0x78, 0x9b, 0xba, 0xa3, 0x41, 0x0b, 0xfd, 0x67, + 0x3a, 0x78, 0x4e, 0x6c, 0x5b, 0x7c, 0x63, 0x7d, 0x7b, 0xeb, 0x01, 0x07, + 0xf9, 0x7f, 0xff, 0x57, 0xeb, 0xac, 0x02, 0x7c, 0xec, 0xde, 0x1f, 0x83, + 0x0e, 0x5c, 0xd9, 0x24, 0x81, 0x8d, 0xf3, 0x90, 0x02, 0x3f, 0xf0, 0x81, + 0x00, 0x0d, 0xb3, 0xe3, 0xec, 0xfe, 0x51, 0x4c, 0x7f, 0x3d, 0x75, 0x90, + 0x9f, 0xce, 0xca, 0x86, 0x9b, 0x69, 0x85, 0xaa, 0x54, 0x34, 0x73, 0x46, + 0xda, 0xba, 0x57, 0x81, 0x88, 0xde, 0x5e, 0xae, 0x2a, 0x92, 0x9b, 0xf8, + 0x90, 0x02, 0x12, 0x33, 0xc0, 0x1d, 0x80, 0x36, 0x7c, 0x17, 0x2c, 0x1b, + 0x25, 0xeb, 0x9b, 0x24, 0xfd, 0xc2, 0xb4, 0x6c, 0xc1, 0xcd, 0xc9, 0xfa, + 0xf5, 0xbf, 0x04, 0x5e, 0x05, 0xf5, 0xcc, 0x3a, 0xa6, 0xe4, 0x78, 0x75, + 0x18, 0x3e, 0x58, 0xdf, 0xba, 0x3e, 0x5f, 0x48, 0xbf, 0x7f, 0x71, 0x7d, + 0xdd, 0x1b, 0x4b, 0xe7, 0x9b, 0xa6, 0x0c, 0xfd, 0x69, 0xd2, 0x05, 0x37, + 0xe6, 0xbf, 0xee, 0x02, 0x08, 0x16, 0x0b, 0xff, 0x74, 0x81, 0x5b, 0xc0, + 0xa3, 0x2f, 0x86, 0xdb, 0x6c, 0x21, 0xd6, 0xe7, 0xa8, 0xed, 0xb0, 0x96, + 0x3d, 0xb0, 0xdf, 0xc5, 0xad, 0xfc, 0x61, 0xe0, 0x63, 0x32, 0x90, 0xed, + 0x6d, 0x7e, 0xdb, 0xa0, 0x0c, 0x1d, 0xf7, 0x16, 0xb2, 0x06, 0x4f, 0xe8, + 0x92, 0xb2, 0xd0, 0xc2, 0x07, 0x19, 0x8b, 0xeb, 0x5b, 0xec, 0x80, 0x0b, + 0x5d, 0xef, 0xcf, 0xd8, 0x01, 0xcd, 0x17, 0x2a, 0x93, 0x60, 0x87, 0x11, + 0xcc, 0xe9, 0xd6, 0xa7, 0xe2, 0xcd, 0x7f, 0x12, 0x52, 0x86, 0x8c, 0xd6, + 0xf1, 0x20, 0x05, 0xa2, 0x27, 0xb8, 0x02, 0xa1, 0x64, 0x1d, 0xd3, 0x83, + 0x93, 0xe0, 0x5e, 0xe5, 0xca, 0x34, 0x3b, 0x69, 0x25, 0x2b, 0x67, 0x3f, + 0x25, 0x4f, 0x11, 0xed, 0x16, 0x0d, 0x24, 0x37, 0xf1, 0x28, 0x08, 0x5f, + 0xef, 0x38, 0x8b, 0xe3, 0x2d, 0xa4, 0xa8, 0xdd, 0xdf, 0x28, 0x00, 0xee, + 0x8a, 0xc0, 0x4c, 0x00, 0x3a, 0xa9, 0xea, 0xdc, 0xfe, 0xf1, 0xf4, 0x5e, + 0x72, 0xe7, 0xca, 0x36, 0x57, 0x2e, 0x6c, 0xb0, 0x22, 0x95, 0x5b, 0xed, + 0x40, 0x04, 0xa2, 0xa8, 0x01, 0x79, 0x1b, 0x31, 0xcf, 0x01, 0x13, 0xec, + 0x48, 0xa3, 0x29, 0x6a, 0x32, 0xb6, 0x8e, 0xa4, 0x0d, 0x7d, 0x21, 0x58, + 0xca, 0x94, 0x5b, 0x7b, 0xf9, 0x76, 0xfb, 0xc0, 0x06, 0x25, 0x06, 0x5b, + 0x3e, 0x84, 0xe9, 0xc4, 0x18, 0x4d, 0x59, 0xab, 0x42, 0x92, 0x37, 0x80, + 0x00, 0x77, 0xf0, 0x2f, 0x3d, 0xc5, 0xf5, 0xc3, 0xf8, 0xd8, 0xb2, 0xe4, + 0x7b, 0xf2, 0x6a, 0x51, 0x95, 0x06, 0x5f, 0x16, 0xfa, 0xc7, 0xd3, 0xbd, + 0xe0, 0x8b, 0xec, 0x27, 0xe6, 0x0e, 0x0e, 0xb9, 0xde, 0x57, 0x39, 0x69, + 0x51, 0x2d, 0xa5, 0x14, 0xd8, 0xa5, 0xc0, 0x06, 0x40, 0x0f, 0x1f, 0xf1, + 0x40, 0x2c, 0xc2, 0xd3, 0x2b, 0xb8, 0x7a, 0xe7, 0x9d, 0xbe, 0x7a, 0x36, + 0x16, 0x43, 0xad, 0xe3, 0xf5, 0x7c, 0xf5, 0x66, 0xc0, 0xca, 0xb9, 0x02, + 0xdb, 0x29, 0x4e, 0x46, 0xfe, 0x72, 0xe7, 0x4d, 0x00, 0xb3, 0x2c, 0xf0, + 0xef, 0x61, 0xa0, 0x97, 0xff, 0xb6, 0x2a, 0x05, 0xb7, 0xea, 0x88, 0x21, + 0xd8, 0x2b, 0xdb, 0x9e, 0x08, 0x0a, 0x02, 0x5d, 0xe6, 0xb8, 0xf9, 0x0a, + 0xa5, 0x0c, 0x2c, 0x7b, 0x7e, 0x5a, 0x9a, 0x01, 0x5c, 0xe2, 0x60, 0x04, + 0x22, 0xf7, 0x24, 0x21, 0xa4, 0x6f, 0xd3, 0xe0, 0x0f, 0x81, 0x0b, 0xfd, + 0x33, 0x9b, 0x6b, 0xc6, 0xc4, 0x90, 0x99, 0x92, 0x87, 0x86, 0x5b, 0xb5, + 0x59, 0x65, 0x20, 0x13, 0xac, 0xb0, 0x34, 0x3c, 0xf9, 0x5a, 0xf2, 0xcd, + 0x4a, 0xad, 0xf4, 0x12, 0x7c, 0x11, 0x7b, 0xcb, 0x8e, 0xb2, 0x9a, 0xeb, + 0x21, 0xa9, 0x12, 0x87, 0xe2, 0xee, 0xcb, 0x55, 0x15, 0x46, 0xb7, 0xe6, + 0x71, 0x1e, 0xcf, 0xf8, 0x00, 0x71, 0xd7, 0xb6, 0x3d, 0x60, 0xd0, 0x42, + 0x00, 0x69, 0x69, 0x48, 0x51, 0x61, 0xf6, 0xac, 0x85, 0x1e, 0x5b, 0x7d, + 0xcf, 0xe4, 0x89, 0xc0, 0x03, 0x0e, 0xe3, 0x9f, 0xb2, 0x29, 0xab, 0xc0, + 0x01, 0xec, 0x27, 0xe6, 0xeb, 0xcf, 0x44, 0xb0, 0xb8, 0x91, 0x1b, 0xd7, + 0xfd, 0xfd, 0xde, 0x00, 0xdf, 0xe6, 0x13, 0xd7, 0xf5, 0x09, 0xde, 0x46, + 0xd3, 0x2d, 0x2f, 0x7f, 0x6a, 0x64, 0x50, 0xe3, 0x8b, 0x6e, 0x9b, 0x2f, + 0x2f, 0xc3, 0x28, 0x00, 0xd0, 0xf5, 0x6e, 0x8a, 0x54, 0x95, 0x58, 0x00, + 0x00, 0x01, 0xb7 +}; + +void mpeg2_get_video_info(VideoDecodeInfo *info) +{ + info->profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE; + info->width = MPEG2_CLIP_WIDTH; + info->height = MPEG2_CLIP_HEIGHT; + info->data = mpeg2_clip; + info->data_size = MPEG2_CLIP_DATA_SIZE; +} diff --git a/tests/test-mpeg2.h b/tests/test-mpeg2.h new file mode 100644 index 0000000..c43154d --- /dev/null +++ b/tests/test-mpeg2.h @@ -0,0 +1,30 @@ +/* + * test-mpeg2.h - MPEG-2 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#ifndef TEST_MPEG2_H +#define TEST_MPEG2_H + +#include +#include "test-decode.h" + +void mpeg2_get_video_info(VideoDecodeInfo *info); + +#endif /* TEST_MPEG2_H */ diff --git a/tests/test-subpicture-data.c b/tests/test-subpicture-data.c new file mode 100644 index 0000000..02f2188 --- /dev/null +++ b/tests/test-subpicture-data.c @@ -0,0 +1,1430 @@ +/* + * test-subpicture-data.c - subpicture data + * + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "test-subpicture-data.h" + +#define SUBPICTURE_WIDTH 184 +#define SUBPICTURE_HEIGHT 38 +#define SUBPICTURE_DATA_SIZE 27968 + +/* Raw RGBA data */ +static const guint32 text[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x09000000, 0x63000000, 0x08000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x44000000, 0x88000000, 0x88000000, 0x88000000, 0x88000000, + 0x88000000, 0x88000000, 0x88000000, 0x88000000, 0x88000000, + 0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x44000000, 0x88000000, + 0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x69000000, 0xff0000b4, 0x65000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0x80000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, + 0xff0000b6, 0x9c000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x3c000000, 0xbb000000, + 0xff0000ff, 0xdd000000, 0xbb000000, 0xbb000000, 0xbb000000, + 0xbb000000, 0xdd000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x08000000, 0x61000000, + 0x60000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x1f000000, 0x5c000000, 0x78000000, 0x60000000, + 0x27000000, 0x00000000, 0x00000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x88000000, 0x88000000, 0x88000000, + 0x0f000000, 0x00000000, 0x00000000, 0x42000000, 0x78000000, + 0x78000000, 0x41000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x1f000000, 0x5c000000, 0x78000000, + 0x60000000, 0x27000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x1f000000, 0x5c000000, 0x78000000, 0x60000000, + 0x27000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x42000000, 0x78000000, 0x78000000, 0x41000000, + 0x00000000, 0x00000000, 0x00000000, 0x44000000, 0x88000000, + 0x88000000, 0x45000000, 0x3d000000, 0x73000000, 0x6c000000, + 0x37000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000, + 0xc4000000, 0xff0000ff, 0xe2000000, 0x88000000, 0x88000000, + 0x88000000, 0x53000000, 0x88000000, 0x88000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x41000000, + 0x78000000, 0x78000000, 0x46000000, 0x01000000, 0x00000000, + 0x00000000, 0x44000000, 0x88000000, 0x88000000, 0x49000000, + 0x55000000, 0x78000000, 0x4a000000, 0x02000000, 0x02000000, + 0x4f000000, 0x78000000, 0x4d000000, 0x01000000, 0x00000000, + 0x00000000, 0x44000000, 0x88000000, 0x88000000, 0x45000000, + 0x3e000000, 0x77000000, 0x78000000, 0x43000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x42000000, 0x78000000, 0x78000000, 0x41000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1f000000, + 0x5c000000, 0x78000000, 0x60000000, 0x27000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x80000000, + 0x77000000, 0x9e000000, 0x00000000, 0x00000000, 0x9000000a, + 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0, + 0xc8000036, 0x35000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff00009c, 0x1c000000, + 0x10000000, 0xc900001f, 0xff0000ad, 0xff0000e7, 0xff0000e7, + 0xff0000ad, 0xc900001f, 0x13000000, 0x00000000, 0x00000000, + 0x9000000a, 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, + 0xf50000a0, 0xc8000036, 0x35000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x9000000a, + 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0, + 0xc8000036, 0x35000000, 0x00000000, 0x10000000, 0xc900001f, + 0xff0000ad, 0xff0000e7, 0xff0000e7, 0xff0000ad, 0xc900001f, + 0x13000000, 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xee000011, 0xff0000a3, 0xff0000e5, 0xff0000ca, 0xfc000072, + 0x94000010, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff00009c, + 0x9b000000, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x10000000, 0xc900001f, 0xff0000ad, 0xfe0000e7, + 0xff0000e7, 0xff0000af, 0xc600001f, 0x11000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xff0000ff, 0xf700001f, 0xff0000b6, + 0xff0000eb, 0xf80000ac, 0xbb00001a, 0xc8000022, 0xff0000b3, + 0xff0000e6, 0xf900008a, 0xad000017, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xff0000ff, 0xf300001b, 0xff0000ad, + 0xfe0000e3, 0xff0000e9, 0xff0000ad, 0xc100001d, 0x0f000000, + 0x00000000, 0x00000000, 0x10000000, 0xc900001f, 0xff0000ad, + 0xff0000e7, 0xff0000e7, 0xff0000ad, 0xc900001f, 0x13000000, + 0x00000000, 0x00000000, 0x9000000a, 0xfd000076, 0xff0000b6, + 0xff0000ef, 0xfe0000dc, 0xf50000a0, 0xc8000036, 0x35000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xe2000000, 0x88000000, + 0x88000000, 0xc4000000, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x43000000, 0xff000078, 0xf8000096, + 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff, + 0x8d000000, 0x3c000000, 0xbb000000, 0xff0000ff, 0xdd000000, + 0xbb000000, 0xbb000000, 0xbb000000, 0x57000000, 0xbc00001a, + 0xff0000e4, 0xf5000098, 0xc8000033, 0xd1000033, 0xf900009a, + 0xff0000e4, 0xbe00001a, 0x00000000, 0x43000000, 0xff000078, + 0xf8000096, 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, + 0xff0000ff, 0x8d000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x43000000, 0xff000078, 0xf8000096, + 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff, + 0x8d000000, 0x00000000, 0xbc00001a, 0xff0000e4, 0xf5000098, + 0xc8000033, 0xd1000033, 0xf900009a, 0xff0000e4, 0xbe00001a, + 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, 0xff0000b1, + 0xea000077, 0xbd00001d, 0xda000042, 0xfd0000bc, 0xfa000074, + 0x36000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, + 0xdd000000, 0xbb000000, 0xbb000000, 0xbb000000, 0x81000000, + 0xbb000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0xb700001a, 0xff0000e6, 0xf500008e, 0xc9000031, 0xd000002c, + 0xf8000087, 0xff0000dd, 0xb1000014, 0x00000000, 0x3c000000, + 0xbb000000, 0xff0000ff, 0xff0000a9, 0xd4000054, 0xc5000024, + 0xfc0000a8, 0xfa0000b4, 0xff0000a7, 0xd5000054, 0xc4000024, + 0xfc0000aa, 0xfc000088, 0x3e000000, 0x00000000, 0x3c000000, + 0xbb000000, 0xff0000ff, 0xff0000cf, 0xf2000087, 0xc600002d, + 0xd1000033, 0xf900009a, 0xff0000e1, 0xb6000017, 0x00000000, + 0x00000000, 0xbc00001a, 0xff0000e4, 0xf5000098, 0xc8000033, + 0xd1000033, 0xf900009a, 0xff0000e4, 0xbe00001a, 0x00000000, + 0x43000000, 0xff000078, 0xf8000096, 0xbe00002c, 0xb9000011, + 0xe5000051, 0xfa0000cf, 0xff0000ff, 0x8d000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000, + 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x2e000000, 0xff00009c, 0xf8000092, + 0x7e000000, 0x4c000000, 0x1a000000, 0x30000000, 0xfa000096, + 0xff00009b, 0x37000000, 0x75000000, 0xfe0000e4, 0xc5000025, + 0x4c000000, 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000, + 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000, + 0x2e000000, 0xff00009c, 0xf8000092, 0x7e000000, 0x4c000000, + 0x1a000000, 0x30000000, 0xfa000096, 0xff00009b, 0x37000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xf5000078, 0x5e000000, + 0x3c000000, 0x0f000000, 0xcd00004b, 0xfe0000c1, 0x89000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x2e000000, 0xff00009b, + 0xf900009e, 0x82000000, 0x47000000, 0x19000000, 0x25000000, + 0xf700008e, 0xfe000086, 0x25000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xee000060, 0x56000000, 0x2a000000, 0xb9000036, + 0xff0000ff, 0xe9000060, 0x55000000, 0x2a000000, 0xba000038, + 0xff0000ca, 0x91000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xf7000084, 0x70000000, 0x44000000, 0x17000000, + 0x30000000, 0xfb000096, 0xff000098, 0x32000000, 0x2e000000, + 0xff00009c, 0xf8000092, 0x7e000000, 0x4c000000, 0x1a000000, + 0x30000000, 0xfa000096, 0xff00009b, 0x37000000, 0x75000000, + 0xfe0000e4, 0xc5000025, 0x4c000000, 0x16000000, 0x09000000, + 0xcd000040, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xdd000000, 0xbb000000, 0xbb000000, 0xdd000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005, + 0x48000000, 0x44000000, 0x88000000, 0x9e000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x5d000000, 0xff0000da, 0xd0000049, 0x49000000, + 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9, + 0x96000000, 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, + 0x82000005, 0x48000000, 0x44000000, 0x88000000, 0x9e000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005, + 0x48000000, 0x44000000, 0x88000000, 0x9e000000, 0x5d000000, + 0xff0000da, 0xd0000049, 0x49000000, 0x00000000, 0x00000000, + 0x00000000, 0xbe00004b, 0xfe0000d9, 0x96000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xd1000028, 0x3c000000, 0x00000000, + 0x00000000, 0x90000011, 0xff0000fc, 0xaf000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x5d000000, 0xff0000da, 0xeb000034, + 0xad000000, 0x88000000, 0x88000000, 0x88000000, 0xde00002f, + 0xff0000cb, 0x7b000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xcd000020, 0x30000000, 0x00000000, 0x84000005, 0xff0000ff, + 0xcd000020, 0x30000000, 0x00000000, 0x85000006, 0xff0000fc, + 0xb1000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xd300002c, 0x42000000, 0x00000000, 0x00000000, 0x00000000, + 0xbe00004b, 0xfe0000d8, 0x95000000, 0x5d000000, 0xff0000da, + 0xd0000049, 0x49000000, 0x00000000, 0x00000000, 0x00000000, + 0xbe00004b, 0xfe0000d9, 0x96000000, 0x49000000, 0xf70000a8, + 0xfb0000cb, 0xea000055, 0x82000005, 0x48000000, 0x44000000, + 0x88000000, 0x9e000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x3c000000, 0x77000000, + 0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2, + 0xf200005c, 0x72000001, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x78000000, 0xff0000f6, 0xc0000012, 0x25000000, 0x00000000, + 0x00000000, 0x00000000, 0x92000013, 0xff0000f6, 0xb4000000, + 0x00000000, 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, + 0xfb0000c2, 0xf200005c, 0x72000001, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2, + 0xf200005c, 0x72000001, 0x00000000, 0x78000000, 0xff0000f6, + 0xc0000012, 0x25000000, 0x00000000, 0x00000000, 0x00000000, + 0x92000013, 0xff0000f6, 0xb4000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x14000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xbf000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x7a000000, 0xff0000f6, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ee, + 0xa8000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x10000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x10000000, 0x00000000, 0x80000000, 0xff0000ff, 0xbf000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x16000000, 0x00000000, 0x00000000, 0x00000000, 0x92000013, + 0xff0000f6, 0xb3000000, 0x78000000, 0xff0000f6, 0xc0000012, + 0x25000000, 0x00000000, 0x00000000, 0x00000000, 0x92000013, + 0xff0000f6, 0xb4000000, 0x00000000, 0x8f000007, 0xf900007e, + 0xfc0000dd, 0xff0000f2, 0xfb0000c2, 0xf200005c, 0x72000001, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000, + 0x88000000, 0x44000000, 0x00000000, 0x44000000, 0x88000000, + 0x65000000, 0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc, + 0xfb000098, 0x40000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x5d000000, + 0xff0000da, 0xdc00004a, 0x09000000, 0x00000000, 0x00000000, + 0x00000000, 0xbe00004b, 0xfe0000d9, 0xb1000000, 0x44000000, + 0x88000000, 0x65000000, 0x84000000, 0xc8000014, 0xf4000059, + 0xfc0000cc, 0xfb000098, 0x40000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x44000000, 0x88000000, + 0x65000000, 0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc, + 0xfb000098, 0x40000000, 0x5d000000, 0xff0000da, 0xdc00004a, + 0x09000000, 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, + 0xfe0000d9, 0xb1000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x69000000, 0xff0000d9, 0xe8000028, 0xbb000000, 0xbb000000, + 0xbb000000, 0xbb000000, 0xda000000, 0xff000000, 0xc1000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xd6000036, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d8, + 0xb1000000, 0x5d000000, 0xff0000da, 0xdc00004a, 0x09000000, + 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9, + 0xb1000000, 0x44000000, 0x88000000, 0x65000000, 0x84000000, + 0xc8000014, 0xf4000059, 0xfc0000cc, 0xfb000098, 0x40000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0x80000000, 0x00000000, 0x80000000, 0xff0000ff, 0xba00003a, + 0x00000000, 0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2, + 0x9d000000, 0x00000000, 0x7f000000, 0xff0000fd, 0xc0000002, + 0x00000000, 0x43000000, 0x88000000, 0x71000000, 0xff00009b, + 0xfb000095, 0x39000000, 0x00000000, 0x00000000, 0x18000000, + 0xf9000096, 0xff00009b, 0x85000000, 0x80000000, 0xff0000ff, + 0xba00003a, 0x00000000, 0x00000000, 0x0b000000, 0xc1000027, + 0xff0000e2, 0x9d000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xba00003a, + 0x00000000, 0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2, + 0x9d000000, 0x2b000000, 0xff00009b, 0xfb000095, 0x39000000, + 0x00000000, 0x00000000, 0x18000000, 0xf9000096, 0xff00009b, + 0x85000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x7f000000, 0xff0000fd, + 0xc0000002, 0x00000000, 0x43000000, 0x88000000, 0x46000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x2b000000, + 0xff000097, 0xf4000080, 0x1b000000, 0x00000000, 0x00000000, + 0x08000000, 0xe0000059, 0xff0000b5, 0x55000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xf9000089, 0x28000000, 0x00000000, + 0x00000000, 0x18000000, 0xf9000096, 0xff000097, 0x83000000, + 0x2b000000, 0xff00009b, 0xfb000095, 0x39000000, 0x00000000, + 0x00000000, 0x18000000, 0xf9000096, 0xff00009b, 0x85000000, + 0x80000000, 0xff0000ff, 0xba00003a, 0x00000000, 0x00000000, + 0x0b000000, 0xc1000027, 0xff0000e2, 0x9d000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000, + 0xc4000000, 0xff0000ff, 0xe2000000, 0x88000000, 0x88000000, + 0x88000000, 0x88000000, 0xc4000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a, + 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, 0x95000000, + 0x00000000, 0x66000000, 0xff0000c1, 0xee000050, 0x8e00000d, + 0xe400005a, 0xfe0000c7, 0x66000000, 0xb800001a, 0xff0000e4, + 0xf8000099, 0xac000033, 0xac000033, 0xf5000099, 0xff0000e4, + 0xcc00001a, 0x4e000000, 0x80000000, 0xff0000ff, 0xfc0000c5, + 0xcf00004a, 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, + 0x95000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a, + 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, 0x95000000, + 0x00000000, 0xb800001a, 0xff0000e4, 0xf8000099, 0xac000033, + 0xac000033, 0xf5000099, 0xff0000e4, 0xcc00001a, 0x4e000000, + 0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, + 0x00000000, 0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000, + 0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x66000000, 0xff0000c1, 0xee000050, + 0x8e00000d, 0xe400005a, 0xfe0000c7, 0xaa000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0xad000015, + 0xff0000d3, 0xf200007f, 0xaa00002d, 0x9d00001d, 0xe6000061, + 0xff0000e9, 0xe9000025, 0x60000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x44000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x44000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000bc, 0xf5000088, 0xa900002d, 0xac000033, + 0xf5000099, 0xff0000e1, 0xc9000017, 0x4c000000, 0x00000000, + 0xb800001a, 0xff0000e4, 0xf8000099, 0xac000033, 0xac000033, + 0xf5000099, 0xff0000e4, 0xcc00001a, 0x4e000000, 0x80000000, + 0xff0000ff, 0xfc0000c5, 0xcf00004a, 0x91000010, 0xab00002c, + 0xfa00009d, 0xff000074, 0x95000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xc0000000, 0x00000000, + 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0, + 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, 0x00000000, + 0x15000000, 0xee000046, 0xff0000bd, 0xff0000ef, 0xfd0000be, + 0xeb00003f, 0x6f000000, 0x13000000, 0xcd00001f, 0xff0000ae, + 0xff0000e8, 0xff0000e8, 0xff0000ae, 0xd900001f, 0x7d000000, + 0x0d000000, 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, + 0xff0000f0, 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0, + 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, 0x00000000, + 0x13000000, 0xcd00001f, 0xff0000ae, 0xff0000e8, 0xff0000e8, + 0xff0000ae, 0xd900001f, 0x7d000000, 0x0d000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x15000000, 0xee000046, 0xff0000bd, 0xff0000ef, + 0xfd0000be, 0xeb00003f, 0xbc000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x0e000000, 0xc0000018, + 0xff0000a4, 0xff0000e1, 0xff0000e5, 0xfc00009b, 0xec000042, + 0x8d000000, 0x13000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xf8000012, 0xff0000a6, 0xff0000e2, 0xff0000e9, 0xff0000ad, + 0xd100001d, 0x78000000, 0x0c000000, 0x00000000, 0x13000000, + 0xcd00001f, 0xff0000ae, 0xff0000e8, 0xff0000e8, 0xff0000ae, + 0xd900001f, 0x7d000000, 0x0d000000, 0x36000000, 0xd300003b, + 0xfb0000aa, 0xff0000e1, 0xff0000f0, 0xff0000b6, 0xfc000076, + 0xae000008, 0x3a000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, + 0xbb000000, 0xbb000000, 0xbb000000, 0xbb000000, 0xbb000000, + 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000, + 0x00000000, 0x4a000000, 0x96000000, 0xb2000000, 0xa8000000, + 0x6e000000, 0x3b000000, 0x04000000, 0x00000000, 0x00000000, + 0x0f000000, 0x78000000, 0xaa000000, 0xaa000000, 0x68000000, + 0x20000000, 0x00000000, 0x00000000, 0x47000000, 0xa5000000, + 0xb4000000, 0x94000000, 0x57000000, 0x10000000, 0x00000000, + 0x00000000, 0x00000000, 0x4a000000, 0x96000000, 0xb2000000, + 0xa8000000, 0x6e000000, 0x3b000000, 0x04000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x4a000000, 0x96000000, 0xb2000000, 0xa8000000, + 0x6e000000, 0x3b000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x47000000, 0xa5000000, 0xb4000000, 0x94000000, + 0x57000000, 0x10000000, 0x00000000, 0x3c000000, 0x77000000, + 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x3c000000, + 0x77000000, 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x0f000000, 0x78000000, 0xaa000000, 0xaa000000, + 0x68000000, 0x54000000, 0x77000000, 0xbb000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x3b000000, + 0x9f000000, 0xb0000000, 0x9e000000, 0x51000000, 0x21000000, + 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000, + 0x9e000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000, + 0x9e000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x43000000, 0x9d000000, 0xb3000000, 0x95000000, 0x57000000, + 0x0f000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x47000000, 0xa5000000, 0xb4000000, 0x94000000, 0x57000000, + 0x10000000, 0x00000000, 0x00000000, 0x00000000, 0x4a000000, + 0x96000000, 0xb2000000, 0xa8000000, 0x6e000000, 0x3b000000, + 0x04000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x3c000000, 0x77000000, + 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x09000000, 0x63000000, 0x08000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000, + 0x88000000, 0x88000000, 0x44000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x69000000, 0xff0000b4, 0x65000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000, + 0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000, + 0x88000000, 0x88000000, 0x44000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x6a000000, 0xff0000b6, 0x9c000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x08000000, + 0x61000000, 0x60000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x3c000000, 0xbb000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x88000000, 0x88000000, 0x88000000, + 0x0f000000, 0x00000000, 0x00000000, 0x41000000, 0x78000000, + 0x78000000, 0x46000000, 0x01000000, 0x00000000, 0x00000000, + 0x44000000, 0x88000000, 0x88000000, 0x45000000, 0x3d000000, + 0x73000000, 0x6c000000, 0x37000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x41000000, + 0x78000000, 0x78000000, 0x46000000, 0x01000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x38000000, 0x6e000000, 0x79000000, 0x43000000, 0x00000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000, + 0x44000000, 0x38000000, 0x75000000, 0x86000000, 0x88000000, + 0x44000000, 0x00000000, 0x00000000, 0x42000000, 0x78000000, + 0x78000000, 0x41000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x1f000000, 0x5c000000, 0x78000000, + 0x60000000, 0x27000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x42000000, 0x78000000, 0x78000000, + 0x41000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x1f000000, 0x5c000000, 0x78000000, 0x60000000, + 0x27000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x1f000000, 0x5c000000, 0x78000000, 0x60000000, 0x27000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000, + 0x44000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000, + 0x45000000, 0x3d000000, 0x73000000, 0x6c000000, 0x37000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x43000000, 0x79000000, 0x6f000000, 0x38000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x44000000, + 0x88000000, 0x88000000, 0x44000000, 0x00000000, 0x00000000, + 0x44000000, 0x88000000, 0x88000000, 0x44000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x43000000, 0x79000000, + 0x6f000000, 0x38000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x02000000, 0x46000000, + 0x76000000, 0x65000000, 0x27000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff00009c, 0x1c000000, + 0x10000000, 0xc900001f, 0xff0000ad, 0xfe0000e7, 0xff0000e7, + 0xff0000af, 0xc600001f, 0x11000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0xee000011, 0xff0000a3, 0xff0000e5, + 0xff0000ca, 0xfc000072, 0x94000010, 0x00000000, 0x00000000, + 0x00000000, 0x10000000, 0xc900001f, 0xff0000ad, 0xfe0000e7, + 0xff0000e7, 0xff0000af, 0xc600001f, 0x11000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xf7000011, 0xff0000a2, + 0xfe0000e0, 0xff0000e9, 0xff0000ad, 0xc100001d, 0x0f000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0xef000014, + 0xff0000a3, 0xff0000dd, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x10000000, 0xc900001f, 0xff0000ad, 0xff0000e7, 0xff0000e7, + 0xff0000ad, 0xc900001f, 0x13000000, 0x00000000, 0x00000000, + 0x9000000a, 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, + 0xf50000a0, 0xc8000036, 0x35000000, 0x00000000, 0x10000000, + 0xc900001f, 0xff0000ad, 0xff0000e7, 0xff0000e7, 0xff0000ad, + 0xc900001f, 0x13000000, 0x00000000, 0x00000000, 0x9000000a, + 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0, + 0xc8000036, 0x35000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x9000000a, 0xfd000076, + 0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0, 0xc8000036, + 0x35000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0xee000011, + 0xff0000a3, 0xff0000e5, 0xff0000ca, 0xfc000072, 0x94000010, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0xc900001e, + 0xff0000ad, 0xff0000e9, 0xfe0000e0, 0xff0000a2, 0xed000011, + 0xff0000ff, 0xc0000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, 0x00000000, + 0x10000000, 0xc900001e, 0xff0000ad, 0xff0000e9, 0xfe0000e0, + 0xff0000a2, 0xed000011, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x36000000, 0xdd000045, 0xff0000bf, 0xff0000ef, + 0xff0000b9, 0xfc000063, 0x7e00000b, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, 0xdd000000, + 0xbb000000, 0xbb000000, 0xbb000000, 0x57000000, 0xb700001a, + 0xff0000e6, 0xf500008e, 0xc9000031, 0xd000002c, 0xf8000087, + 0xff0000dd, 0xb1000014, 0x00000000, 0x3c000000, 0xbb000000, + 0xff0000ff, 0xff0000b1, 0xea000077, 0xbd00001d, 0xda000042, + 0xfd0000bc, 0xfa000074, 0x36000000, 0x00000000, 0x00000000, + 0xb700001a, 0xff0000e6, 0xf500008e, 0xc9000031, 0xd000002c, + 0xf8000087, 0xff0000dd, 0xb1000014, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xff0000bd, 0xf200008c, 0xc500002f, + 0xd1000033, 0xf900009a, 0xff0000e1, 0xb6000017, 0x00000000, + 0x3c000000, 0xbb000000, 0xff0000ff, 0xff0000b8, 0xe0000067, + 0xb8000015, 0xf000005c, 0xff0000ff, 0xc0000000, 0xbc00001a, + 0xff0000e4, 0xf5000098, 0xc8000033, 0xd1000033, 0xf900009a, + 0xff0000e4, 0xbe00001a, 0x00000000, 0x43000000, 0xff000078, + 0xf8000096, 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, + 0xff0000ff, 0x8d000000, 0x00000000, 0xbc00001a, 0xff0000e4, + 0xf5000098, 0xc8000033, 0xd1000033, 0xf900009a, 0xff0000e4, + 0xbe00001a, 0x00000000, 0x43000000, 0xff000078, 0xf8000096, + 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff, + 0x8d000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x43000000, 0xff000078, 0xf8000096, 0xbe00002c, + 0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff, 0x8d000000, + 0x3c000000, 0xbb000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x3c000000, 0xbb000000, 0xff0000ff, 0xff0000b1, 0xea000077, + 0xbd00001d, 0xda000042, 0xfd0000bc, 0xfa000074, 0x36000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xb7000019, 0xff0000e2, 0xf5000098, + 0xc8000033, 0xd100002f, 0xf800008c, 0xff0000bc, 0xff0000ff, + 0xc0000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x3c000000, 0xbb000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0xb7000019, + 0xff0000e2, 0xf5000098, 0xc8000033, 0xd100002f, 0xf800008c, + 0xff0000bc, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xf2000076, 0xbe000014, 0xd7000031, + 0xfe0000b1, 0xff00008e, 0x33000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x2e000000, 0xff00009b, 0xf900009e, + 0x82000000, 0x47000000, 0x19000000, 0x25000000, 0xf700008e, + 0xfe000086, 0x25000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xf5000078, 0x5e000000, 0x3c000000, 0x0f000000, 0xcd00004b, + 0xfe0000c1, 0x89000000, 0x00000000, 0x2e000000, 0xff00009b, + 0xf900009e, 0x82000000, 0x47000000, 0x19000000, 0x25000000, + 0xf700008e, 0xfe000086, 0x25000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xf900008a, 0x68000000, 0x46000000, 0x18000000, + 0x30000000, 0xfb000096, 0xff000098, 0x32000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xf0000068, 0x5d000000, 0x34000000, + 0x42000000, 0x90000000, 0xb4000000, 0xff00009c, 0xf8000092, + 0x7e000000, 0x4c000000, 0x1a000000, 0x30000000, 0xfa000096, + 0xff00009b, 0x37000000, 0x75000000, 0xfe0000e4, 0xc5000025, + 0x4c000000, 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, + 0xc0000000, 0x2e000000, 0xff00009c, 0xf8000092, 0x7e000000, + 0x4c000000, 0x1a000000, 0x30000000, 0xfa000096, 0xff00009b, + 0x37000000, 0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000, + 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000, 0x16000000, + 0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xf5000078, 0x5e000000, 0x3c000000, + 0x0f000000, 0xcd00004b, 0xfe0000c1, 0x89000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x2a000000, 0xff00009a, 0xf9000092, 0x7d000000, 0x4c000000, + 0x1a000000, 0x26000000, 0xf600008b, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x2a000000, 0xff00009a, 0xf9000092, + 0x7d000000, 0x4c000000, 0x1a000000, 0x26000000, 0xf600008b, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x3c000000, + 0x77000000, 0x9b000000, 0x3b000000, 0x0a000000, 0xaf000027, + 0xff0000e4, 0x8f000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x5d000000, 0xff0000da, 0xeb000034, 0xad000000, + 0x88000000, 0x88000000, 0x88000000, 0xde00002f, 0xff0000cb, + 0x7b000000, 0x00000000, 0x80000000, 0xff0000ff, 0xd1000028, + 0x3c000000, 0x00000000, 0x00000000, 0x90000011, 0xff0000fc, + 0xaf000000, 0x00000000, 0x5d000000, 0xff0000da, 0xeb000034, + 0xad000000, 0x88000000, 0x88000000, 0x88000000, 0xde00002f, + 0xff0000cb, 0x7b000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xd7000036, 0x45000000, 0x00000000, 0x00000000, 0x00000000, + 0xbe00004b, 0xfe0000d8, 0x95000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xcb000019, 0x34000000, 0x00000000, 0x00000000, + 0x00000000, 0x5d000000, 0xff0000da, 0xd0000049, 0x49000000, + 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9, + 0x96000000, 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, + 0x82000005, 0x48000000, 0x44000000, 0x88000000, 0x9e000000, + 0x5d000000, 0xff0000da, 0xd0000049, 0x49000000, 0x00000000, + 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9, 0x96000000, + 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005, + 0x48000000, 0x44000000, 0x88000000, 0x9e000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x49000000, + 0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005, 0x48000000, + 0x44000000, 0x88000000, 0x9e000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xd1000028, 0x3c000000, 0x00000000, 0x00000000, + 0x90000011, 0xff0000fc, 0xaf000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5b000000, + 0xff0000da, 0xd0000049, 0x49000000, 0x00000000, 0x00000000, + 0x00000000, 0xb0000037, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x5b000000, 0xff0000da, 0xd0000049, 0x49000000, + 0x00000000, 0x00000000, 0x00000000, 0xb0000037, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x2d000000, + 0x60000000, 0x81000000, 0x88000000, 0xc4000000, 0xff0000f6, + 0xb3000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x7a000000, 0xff0000f6, 0xff0000ff, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ee, 0xa8000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x14000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xbf000000, + 0x00000000, 0x7a000000, 0xff0000f6, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ee, + 0xa8000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000001, + 0x1b000000, 0x00000000, 0x00000000, 0x00000000, 0x92000013, + 0xff0000f6, 0xb3000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x0d000000, 0x00000000, 0x00000000, 0x00000000, + 0x78000000, 0xff0000f6, 0xc0000012, 0x25000000, 0x00000000, + 0x00000000, 0x00000000, 0x92000013, 0xff0000f6, 0xb4000000, + 0x00000000, 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, + 0xfb0000c2, 0xf200005c, 0x72000001, 0x00000000, 0x78000000, + 0xff0000f6, 0xc0000012, 0x25000000, 0x00000000, 0x00000000, + 0x00000000, 0x92000013, 0xff0000f6, 0xb4000000, 0x00000000, + 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2, + 0xf200005c, 0x72000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8f000007, + 0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2, 0xf200005c, + 0x72000001, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x14000000, 0x00000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xbf000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x78000000, 0xff0000f6, + 0xc0000012, 0x25000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000001, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x78000000, 0xff0000f6, 0xc0000012, 0x25000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000001, 0xff0000ff, 0xc0000000, + 0x00000000, 0x01000000, 0xa1000010, 0xfe00007f, 0xfe0000c1, + 0xff0000f9, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xbd000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x69000000, + 0xff0000d9, 0xe8000028, 0xbb000000, 0xbb000000, 0xbb000000, + 0xbb000000, 0xda000000, 0xff000000, 0xc1000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x69000000, 0xff0000d9, 0xe8000028, 0xbb000000, 0xbb000000, + 0xbb000000, 0xbb000000, 0xda000000, 0xff000000, 0xc1000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xd300002b, 0x01000000, + 0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d8, + 0xb1000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5d000000, + 0xff0000da, 0xdc00004a, 0x09000000, 0x00000000, 0x00000000, + 0x00000000, 0xbe00004b, 0xfe0000d9, 0xb1000000, 0x44000000, + 0x88000000, 0x65000000, 0x84000000, 0xc8000014, 0xf4000059, + 0xfc0000cc, 0xfb000098, 0x40000000, 0x5d000000, 0xff0000da, + 0xdc00004a, 0x09000000, 0x00000000, 0x00000000, 0x00000000, + 0xbe00004b, 0xfe0000d9, 0xb1000000, 0x44000000, 0x88000000, + 0x65000000, 0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc, + 0xfb000098, 0x40000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x65000000, + 0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc, 0xfb000098, + 0x40000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x5b000000, 0xff0000da, 0xdc000049, + 0x09000000, 0x00000000, 0x00000000, 0x00000000, 0xa700002c, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x7e000000, + 0xff0000fc, 0xc7000011, 0x00000000, 0x00000000, 0x00000000, + 0xa500002a, 0xff0000ff, 0xc0000000, 0x00000000, 0x5b000000, + 0xff0000da, 0xdc000049, 0x09000000, 0x00000000, 0x00000000, + 0x00000000, 0xa700002c, 0xff0000ff, 0xc0000000, 0x00000000, + 0x48000000, 0xff000083, 0xfb0000a8, 0xc7000038, 0xb500000a, + 0xba000000, 0xdd000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x7f000000, 0xff0000fd, 0xc0000002, + 0x00000000, 0x43000000, 0x88000000, 0x71000000, 0xff000097, + 0xf4000080, 0x1b000000, 0x00000000, 0x00000000, 0x08000000, + 0xe0000059, 0xff0000b5, 0x55000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x2b000000, + 0xff000097, 0xf4000080, 0x1b000000, 0x00000000, 0x00000000, + 0x08000000, 0xe0000059, 0xff0000b5, 0x55000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xf7000083, 0x1f000000, 0x00000000, + 0x00000000, 0x18000000, 0xf9000096, 0xff000097, 0x83000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x2b000000, 0xff00009b, + 0xfb000095, 0x39000000, 0x00000000, 0x00000000, 0x18000000, + 0xf9000096, 0xff00009b, 0x85000000, 0x80000000, 0xff0000ff, + 0xba00003a, 0x00000000, 0x00000000, 0x0b000000, 0xc1000027, + 0xff0000e2, 0x9d000000, 0x2b000000, 0xff00009b, 0xfb000095, + 0x39000000, 0x00000000, 0x00000000, 0x18000000, 0xf9000096, + 0xff00009b, 0x85000000, 0x80000000, 0xff0000ff, 0xba00003a, + 0x00000000, 0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2, + 0x9d000000, 0x00000000, 0x44000000, 0x88000000, 0x45000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xba00003a, 0x00000000, + 0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2, 0x9d000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, + 0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x2a000000, 0xff000099, 0xfb000092, 0x38000000, + 0x00000000, 0x00000000, 0x0b000000, 0xf0000084, 0xff0000ff, + 0xc0000000, 0x00000000, 0x00000000, 0x67000000, 0xfe0000c2, + 0xdf000048, 0x09000000, 0x00000000, 0x07000000, 0xec00007a, + 0xff0000ff, 0xc0000000, 0x00000000, 0x2a000000, 0xff000099, + 0xfb000092, 0x38000000, 0x00000000, 0x00000000, 0x0b000000, + 0xf0000084, 0xff0000ff, 0xc0000000, 0x00000000, 0x76000000, + 0xff0000e1, 0xbd000026, 0x54000000, 0x1c000000, 0x05000000, + 0x98000015, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, + 0x44000000, 0x88000000, 0x88000000, 0x44000000, 0x00000000, + 0x00000000, 0x66000000, 0xff0000c1, 0xee000050, 0x8e00000d, + 0xe400005a, 0xfe0000c7, 0x66000000, 0xad000015, 0xff0000d3, + 0xf200007f, 0xaa00002d, 0x9d00001d, 0xe6000061, 0xff0000e9, + 0xe9000025, 0x60000000, 0x44000000, 0xc4000000, 0xff0000ff, + 0xe2000000, 0x44000000, 0x00000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0xad000015, + 0xff0000d3, 0xf200007f, 0xaa00002d, 0x9d00001d, 0xe6000061, + 0xff0000e9, 0xe9000025, 0x60000000, 0x44000000, 0xc4000000, + 0xff0000ff, 0xff0000cc, 0xf3000083, 0xa900002b, 0xac000033, + 0xf5000099, 0xff0000e1, 0xc9000017, 0x4c000000, 0x44000000, + 0xc4000000, 0xff0000ff, 0xe2000000, 0x88000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0xb800001a, 0xff0000e4, + 0xf8000099, 0xac000033, 0xac000033, 0xf5000099, 0xff0000e4, + 0xcc00001a, 0x4e000000, 0x80000000, 0xff0000ff, 0xfc0000c5, + 0xcf00004a, 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, + 0x95000000, 0x00000000, 0xb800001a, 0xff0000e4, 0xf8000099, + 0xac000033, 0xac000033, 0xf5000099, 0xff0000e4, 0xcc00001a, + 0x4e000000, 0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a, + 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, 0x95000000, + 0x00000000, 0x8e000009, 0xff0000e8, 0x72000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a, 0x91000010, + 0xab00002c, 0xfa00009d, 0xff000074, 0x95000000, 0x44000000, + 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, 0x44000000, + 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, + 0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xb8000019, 0xff0000e2, 0xf7000097, 0xab000032, + 0xa900002b, 0xef000083, 0xff0000cc, 0xff0000ff, 0xe2000000, + 0x44000000, 0x00000000, 0x30000000, 0xf9000076, 0xfd0000ba, + 0xc4000041, 0x9c00001c, 0xe9000076, 0xff0000b0, 0xff0000ff, + 0xe2000000, 0x44000000, 0x00000000, 0xb8000019, 0xff0000e2, + 0xf7000097, 0xab000032, 0xa900002b, 0xef000083, 0xff0000cc, + 0xff0000ff, 0xe2000000, 0x44000000, 0x47000000, 0xfd000086, + 0xfd0000af, 0xbd000038, 0x8f00000e, 0xc000003c, 0xfe0000b5, + 0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, 0x00000000, + 0x15000000, 0xee000046, 0xff0000bd, 0xff0000ef, 0xfd0000be, + 0xeb00003f, 0x6f000000, 0x0e000000, 0xc0000018, 0xff0000a4, + 0xff0000e1, 0xff0000e5, 0xfc00009b, 0xec000042, 0x8d000000, + 0x13000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0xff0000ff, + 0x80000000, 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x0e000000, 0xc0000018, + 0xff0000a4, 0xff0000e1, 0xff0000e5, 0xfc00009b, 0xec000042, + 0x8d000000, 0x13000000, 0x80000000, 0xff0000ff, 0xff0000ff, + 0xfa00001a, 0xff0000ad, 0xff0000e4, 0xff0000e9, 0xff0000ad, + 0xd100001d, 0x78000000, 0x0c000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x13000000, 0xcd00001f, 0xff0000ae, + 0xff0000e8, 0xff0000e8, 0xff0000ae, 0xd900001f, 0x7d000000, + 0x0d000000, 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, + 0xff0000f0, 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, + 0x00000000, 0x13000000, 0xcd00001f, 0xff0000ae, 0xff0000e8, + 0xff0000e8, 0xff0000ae, 0xd900001f, 0x7d000000, 0x0d000000, + 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0, + 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, 0x00000000, + 0xba00002b, 0xff0000ba, 0x9f000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x36000000, + 0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0, 0xff0000b6, + 0xfc000076, 0xae000008, 0x3a000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0x80000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, 0x80000000, + 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0f000000, 0xc300001e, 0xff0000ae, 0xff0000e9, 0xfe0000e5, + 0xff0000ae, 0xf600001a, 0xff0000ff, 0xff0000ff, 0x80000000, + 0x00000000, 0x00000000, 0x96000011, 0xfd000075, 0xff0000cc, + 0xff0000e6, 0xff0000a4, 0xf2000011, 0xff0000ff, 0xff0000ff, + 0x80000000, 0x00000000, 0x0f000000, 0xc300001e, 0xff0000ae, + 0xff0000e9, 0xfe0000e5, 0xff0000ae, 0xf600001a, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x9b000011, 0xfc000082, + 0xff0000cb, 0xff0000f2, 0xff0000ca, 0xfe000048, 0xff0000ff, + 0xff0000ff, 0x80000000, 0x00000000, 0x80000000, 0xff0000ff, + 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000, + 0x0f000000, 0x78000000, 0xaa000000, 0xaa000000, 0x68000000, + 0x20000000, 0x00000000, 0x00000000, 0x3b000000, 0x9f000000, + 0xb0000000, 0x9e000000, 0x51000000, 0x21000000, 0x00000000, + 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000, 0x9e000000, + 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x3b000000, + 0x9f000000, 0xb0000000, 0x9e000000, 0x51000000, 0x21000000, + 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, 0x9e000000, + 0x47000000, 0xa5000000, 0xb3000000, 0x95000000, 0x57000000, + 0x0f000000, 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, + 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x47000000, 0xa5000000, + 0xb4000000, 0x94000000, 0x57000000, 0x10000000, 0x00000000, + 0x00000000, 0x00000000, 0x4a000000, 0x96000000, 0xb2000000, + 0xa8000000, 0x6e000000, 0x3b000000, 0x04000000, 0x00000000, + 0x00000000, 0x00000000, 0x47000000, 0xa5000000, 0xb4000000, + 0x94000000, 0x57000000, 0x10000000, 0x00000000, 0x00000000, + 0x00000000, 0x4a000000, 0x96000000, 0xb2000000, 0xa8000000, + 0x6e000000, 0x3b000000, 0x04000000, 0x13000000, 0xf600007d, + 0xf900006e, 0x66000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4a000000, 0x96000000, 0xb2000000, 0xa8000000, 0x6e000000, + 0x3b000000, 0x04000000, 0x3c000000, 0x77000000, 0xbb000000, + 0xbb000000, 0x9e000000, 0x3c000000, 0x77000000, 0xbb000000, + 0xbb000000, 0x9e000000, 0x00000000, 0x3c000000, 0x77000000, + 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x47000000, 0xa5000000, 0xb5000000, 0x94000000, + 0x7f000000, 0x7e000000, 0xbb000000, 0x9e000000, 0x00000000, + 0x00000000, 0x00000000, 0x3d000000, 0x8d000000, 0xaa000000, + 0x93000000, 0x7b000000, 0x7c000000, 0xbb000000, 0x9e000000, + 0x00000000, 0x00000000, 0x00000000, 0x47000000, 0xa5000000, + 0xb5000000, 0x94000000, 0x7f000000, 0x7e000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x00000000, 0x35000000, 0x8d000000, + 0xaa000000, 0xa1000000, 0x8e000000, 0x8a000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x3c000000, 0x77000000, 0xbb000000, + 0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x6d000000, 0xff000097, 0x9c000002, + 0x37000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x06000000, 0x79000000, 0x4d000000, 0x01000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +void subpicture_get_info(VideoSubpictureInfo *info) +{ + info->width = SUBPICTURE_WIDTH; + info->height = SUBPICTURE_HEIGHT; + info->data = text; + info->data_size = SUBPICTURE_DATA_SIZE; +} diff --git a/tests/test-subpicture-data.h b/tests/test-subpicture-data.h new file mode 100644 index 0000000..cc37988 --- /dev/null +++ b/tests/test-subpicture-data.h @@ -0,0 +1,40 @@ +/* + * test-subpicture-data.h - subpicture data + * + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef TEST_SUBPICTURE_DATA +#define TEST_SUBPICTURE_DATA + +#include +#include "test-decode.h" + +typedef struct _VideoSubpictureInfo VideoSubpictureInfo; + +struct _VideoSubpictureInfo { + guint width; + guint height; + const guint32 *data; + guint data_size; +}; + +void subpicture_get_info(VideoSubpictureInfo *info); + +#endif /* TEST_SUBPICTURE_DATA*/ diff --git a/tests/test-subpicture.c b/tests/test-subpicture.c new file mode 100644 index 0000000..7a65fe3 --- /dev/null +++ b/tests/test-subpicture.c @@ -0,0 +1,229 @@ +/* + * test-subpicture.c - Test GstVaapiSubpicture + * + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include +#include +#include +#include +#include "output.h" +#include "test-mpeg2.h" +#include "test-subpicture-data.h" + +typedef void (*GetVideoInfoFunc)(VideoDecodeInfo *info); + +typedef struct _CodecDefs CodecDefs; +struct _CodecDefs { + const gchar *codec_str; + GetVideoInfoFunc get_video_info; +}; + +static const CodecDefs g_codec_defs[] = { +#define INIT_FUNCS(CODEC) { #CODEC, CODEC##_get_video_info } + INIT_FUNCS(mpeg2), +#undef INIT_FUNCS + { NULL, } +}; + +static const CodecDefs * +get_codec_defs(const gchar *codec_str) +{ + const CodecDefs *c; + for (c = g_codec_defs; c->codec_str; c++) + if (strcmp(codec_str, c->codec_str) == 0) + return c; + return NULL; +} + +static inline void pause(void) +{ + g_print("Press any key to continue...\n"); + getchar(); +} + +static gchar *g_codec_str; + +static GOptionEntry g_options[] = { + { "codec", 'c', + 0, + G_OPTION_ARG_STRING, &g_codec_str, + "codec to test", NULL }, + { NULL, } +}; + +static void +upload_image (guint8 *dst, const guint32 *src, guint size) +{ + guint i; + + for (i = 0; i < size; i += 4) { + dst[i ] = *src >> 24; + dst[i + 1] = *src >> 16; + dst[i + 2] = *src >> 8; + dst[i + 3] = *src++; + } +} + +int +main(int argc, char *argv[]) +{ + GstVaapiDisplay *display; + GstVaapiWindow *window; + GstVaapiDecoder *decoder = NULL; + GstCaps *decoder_caps; + GstStructure *structure; + GstVaapiDecoderStatus status; + const CodecDefs *codec; + GstBuffer *buffer; + GstVaapiSurfaceProxy *proxy; + GstVaapiSurface *surface; + VideoDecodeInfo info; + VideoSubpictureInfo subinfo; + GstVaapiImage *subtitle_image; + GstVaapiSubpicture *subpicture; + GstCaps *argbcaps; + GstVaapiRectangle sub_rect; + guint surf_width, surf_height; + + static const guint win_width = 640; + static const guint win_height = 480; + + if (!video_output_init(&argc, argv, g_options)) + g_error("failed to initialize video output subsystem"); + + if (!g_codec_str) + g_codec_str = g_strdup("mpeg2"); + + g_print("Test %s decode\n", g_codec_str); + codec = get_codec_defs(g_codec_str); + if (!codec) + g_error("no %s codec data found", g_codec_str); + + display = video_output_create_display(NULL); + if (!display) + g_error("could not create VA display"); + + window = video_output_create_window(display, win_width, win_height); + if (!window) + g_error("could not create window"); + + codec->get_video_info(&info); + decoder_caps = gst_vaapi_profile_get_caps(info.profile); + if (!decoder_caps) + g_error("could not create decoder caps"); + + structure = gst_caps_get_structure(decoder_caps, 0); + if (info.width > 0 && info.height > 0) + gst_structure_set( + structure, + "width", G_TYPE_INT, info.width, + "height", G_TYPE_INT, info.height, + NULL + ); + + decoder = gst_vaapi_decoder_mpeg2_new(display, decoder_caps); + if (!decoder) + g_error("could not create video decoder"); + gst_caps_unref(decoder_caps); + + buffer = gst_buffer_new(); + if (!buffer) + g_error("could not create encoded data buffer"); + gst_buffer_set_data(buffer, (guchar *)info.data, info.data_size); + + if (!gst_vaapi_decoder_put_buffer(decoder, buffer)) + g_error("could not send video data to the decoder"); + gst_buffer_unref(buffer); + + if (!gst_vaapi_decoder_put_buffer(decoder, NULL)) + g_error("could not send EOS to the decoder"); + + proxy = gst_vaapi_decoder_get_surface(decoder, &status); + if (!proxy) + g_error("could not get decoded surface (decoder status %d)", status); + + surface = gst_vaapi_surface_proxy_get_surface(proxy); + if (!surface) + g_error("could not get underlying surface"); + + gst_vaapi_surface_get_size(surface, &surf_width, &surf_height); + printf("surface size %dx%d\n", surf_width, surf_height); + + subpicture_get_info (&subinfo); + + /* Adding subpicture */ + argbcaps = gst_caps_new_simple ("video/x-raw-rgb", + "endianness", G_TYPE_INT, G_BIG_ENDIAN, + "bpp", G_TYPE_INT, 32, + "red_mask", G_TYPE_INT, 0xff000000, + "green_mask", G_TYPE_INT, 0x00ff0000, + "blue_mask", G_TYPE_INT, 0x0000ff00, + "alpha_mask", G_TYPE_INT, 0x000000ff, + "width", G_TYPE_INT, subinfo.width, + "height", G_TYPE_INT, subinfo.height, + NULL); + + buffer = gst_buffer_new_and_alloc (subinfo.data_size); + upload_image (GST_BUFFER_DATA (buffer), subinfo.data, subinfo.data_size); + gst_buffer_set_caps (buffer, argbcaps); + + subtitle_image = gst_vaapi_image_new (display, + GST_VAAPI_IMAGE_RGBA, subinfo.width, subinfo.height); + + if (!gst_vaapi_image_update_from_buffer (subtitle_image, buffer, NULL)) + g_error ("could not update VA image with subtitle data"); + + subpicture = gst_vaapi_subpicture_new (subtitle_image); + + /* We position it as a subtitle, centered at the bottom. */ + sub_rect.x = (surf_width - subinfo.width) / 2; + sub_rect.y = surf_height - subinfo.height - 10; + sub_rect.height = subinfo.height; + sub_rect.width = subinfo.width; + + if (!gst_vaapi_surface_associate_subpicture ( + surface, + subpicture, + NULL, + &sub_rect)) + g_error("could not associate subpicture"); + + gst_vaapi_window_show(window); + + if (!gst_vaapi_window_put_surface(window, + GST_VAAPI_SURFACE_PROXY_SURFACE(proxy), + NULL, + NULL, + GST_VAAPI_PICTURE_STRUCTURE_FRAME)) + g_error("could not render surface"); + + pause(); + + gst_buffer_unref(buffer); + g_object_unref(proxy); + g_object_unref(decoder); + g_object_unref(window); + g_object_unref(display); + g_free(g_codec_str); + video_output_exit(); + return 0; +} diff --git a/tests/test-surfaces.c b/tests/test-surfaces.c new file mode 100644 index 0000000..c236e5e --- /dev/null +++ b/tests/test-surfaces.c @@ -0,0 +1,132 @@ +/* + * test-surfaces.c - Test GstVaapiSurface and GstVaapiSurfacePool + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include "output.h" + +#define MAX_SURFACES 4 + +static void +gst_vaapi_object_destroy_cb(gpointer object, gpointer user_data) +{ + g_print("destroying GstVaapiObject %p\n", object); +} + +int +main(int argc, char *argv[]) +{ + GstVaapiDisplay *display; + GstVaapiSurface *surface; + GstVaapiID surface_id; + GstVaapiSurface *surfaces[MAX_SURFACES]; + GstVaapiVideoPool *pool; + GstCaps *caps; + gint i; + + static const GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + static const guint width = 320; + static const guint height = 240; + + if (!video_output_init(&argc, argv, NULL)) + g_error("failed to initialize video output subsystem"); + + display = video_output_create_display(NULL); + if (!display) + g_error("could not create Gst/VA display"); + + surface = gst_vaapi_surface_new(display, chroma_type, width, height); + if (!surface) + g_error("could not create Gst/VA surface"); + + /* This also tests for the GstVaapiParamSpecID */ + g_object_get(G_OBJECT(surface), "id", &surface_id, NULL); + if (surface_id != gst_vaapi_surface_get_id(surface)) + g_error("could not retrieve the native surface ID"); + g_print("created surface %" GST_VAAPI_ID_FORMAT "\n", + GST_VAAPI_ID_ARGS(surface_id)); + + g_object_unref(surface); + + caps = gst_caps_new_simple( + GST_VAAPI_SURFACE_CAPS_NAME, + "type", G_TYPE_STRING, "vaapi", + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + NULL + ); + if (!caps) + g_error("cound not create Gst/VA surface caps"); + + pool = gst_vaapi_surface_pool_new(display, caps); + if (!pool) + g_error("could not create Gst/VA surface pool"); + + for (i = 0; i < MAX_SURFACES; i++) { + surface = gst_vaapi_video_pool_get_object(pool); + if (!surface) + g_error("could not allocate Gst/VA surface from pool"); + g_print("created surface %" GST_VAAPI_ID_FORMAT " from pool\n", + GST_VAAPI_ID_ARGS(gst_vaapi_surface_get_id(surface))); + surfaces[i] = surface; + } + + /* Check the pool doesn't return the last free'd surface */ + surface = g_object_ref(surfaces[1]); + + for (i = 0; i < 2; i++) + gst_vaapi_video_pool_put_object(pool, surfaces[i]); + + for (i = 0; i < 2; i++) { + surfaces[i] = gst_vaapi_video_pool_get_object(pool); + if (!surfaces[i]) + g_error("could not re-allocate Gst/VA surface%d from pool", i); + g_print("created surface %" GST_VAAPI_ID_FORMAT " from pool (realloc)\n", + GST_VAAPI_ID_ARGS(gst_vaapi_surface_get_id(surfaces[i]))); + } + + if (surface == surfaces[0]) + g_error("Gst/VA pool doesn't queue free surfaces"); + + for (i = MAX_SURFACES - 1; i >= 0; i--) { + if (!surfaces[i]) + continue; + gst_vaapi_video_pool_put_object(pool, surfaces[i]); + surfaces[i] = NULL; + } + + g_signal_connect( + G_OBJECT(surface), + "destroy", + G_CALLBACK(gst_vaapi_object_destroy_cb), NULL + ); + + /* Unref in random order to check objects are correctly refcounted */ + g_print("unref display\n"); + g_object_unref(display); + gst_caps_unref(caps); + g_print("unref pool\n"); + g_object_unref(pool); + g_print("unref surface\n"); + g_object_unref(surface); + video_output_exit(); + return 0; +} diff --git a/tests/test-textures.c b/tests/test-textures.c new file mode 100644 index 0000000..7bf40fd --- /dev/null +++ b/tests/test-textures.c @@ -0,0 +1,192 @@ +/* + * test-textures.c - Test GstVaapiTexture + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include "image.h" + +static inline void pause(void) +{ + g_print("Press any key to continue...\n"); + getchar(); +} + +static inline guint gl_get_current_texture_2d(void) +{ + GLint texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture); + return (guint)texture; +} + +int +main(int argc, char *argv[]) +{ + GstVaapiDisplay *display; + GstVaapiWindow *window; + GstVaapiWindowGLX *glx_window; + GstVaapiSurface *surface; + GstVaapiImage *image; + GstVaapiTexture *textures[2]; + GstVaapiTexture *texture; + GLuint texture_id; + GstVaapiRectangle src_rect; + GstVaapiRectangle dst_rect; + guint flags = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + + static const GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + static const guint width = 320; + static const guint height = 240; + static const guint win_width = 640; + static const guint win_height = 480; + + gst_init(&argc, &argv); + + display = gst_vaapi_display_glx_new(NULL); + if (!display) + g_error("could not create VA display"); + + surface = gst_vaapi_surface_new(display, chroma_type, width, height); + if (!surface) + g_error("could not create VA surface"); + + image = image_generate(display, GST_VAAPI_IMAGE_NV12, width, height); + if (!image) + g_error("could not create VA image"); + if (!image_upload(image, surface)) + g_error("could not upload VA image to surface"); + + window = gst_vaapi_window_glx_new(display, win_width, win_height); + if (!window) + g_error("could not create window"); + glx_window = GST_VAAPI_WINDOW_GLX(window); + + gst_vaapi_window_show(window); + + if (!gst_vaapi_window_glx_make_current(glx_window)) + g_error("coult not bind GL context"); + + g_print("#\n"); + g_print("# Create texture with gst_vaapi_texture_new()\n"); + g_print("#\n"); + { + texture = gst_vaapi_texture_new( + display, + GL_TEXTURE_2D, + GL_RGBA, + width, + height + ); + if (!texture) + g_error("could not create VA texture"); + + textures[0] = texture; + texture_id = gst_vaapi_texture_get_id(texture); + + if (!gst_vaapi_texture_put_surface(texture, surface, flags)) + g_error("could not transfer VA surface to texture"); + + if (!gst_vaapi_window_glx_put_texture(glx_window, texture, NULL, NULL)) + g_error("could not render texture into the window"); + } + + g_print("#\n"); + g_print("# Create texture with gst_vaapi_texture_new_with_texture()\n"); + g_print("#\n"); + { + const GLenum target = GL_TEXTURE_2D; + const GLenum format = GL_BGRA; + + glEnable(target); + glGenTextures(1, &texture_id); + glBindTexture(target, texture_id); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D( + target, + 0, + GL_RGBA8, + width, height, + 0, + format, + GL_UNSIGNED_BYTE, + NULL + ); + glDisable(target); + + texture = gst_vaapi_texture_new_with_texture( + display, + texture_id, + target, + format + ); + if (!texture) + g_error("could not create VA texture"); + + if (texture_id != gst_vaapi_texture_get_id(texture)) + g_error("invalid texture id"); + + if (gl_get_current_texture_2d() != texture_id) + g_error("gst_vaapi_texture_new_with_texture() altered texture bindings"); + + textures[1] = texture; + + if (!gst_vaapi_texture_put_surface(texture, surface, flags)) + g_error("could not transfer VA surface to texture"); + + if (gl_get_current_texture_2d() != texture_id) + g_error("gst_vaapi_texture_put_surface() altered texture bindings"); + + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = width; + src_rect.height = height; + + dst_rect.x = win_width/2; + dst_rect.y = win_height/2; + dst_rect.width = win_width/2; + dst_rect.height = win_height/2; + + if (!gst_vaapi_window_glx_put_texture(glx_window, texture, + &src_rect, &dst_rect)) + g_error("could not render texture into the window"); + + if (gl_get_current_texture_2d() != texture_id) + g_error("gst_vaapi_window_glx_put_texture() altered texture bindings"); + } + + gst_vaapi_window_glx_swap_buffers(glx_window); + pause(); + + g_object_unref(textures[0]); + g_object_unref(textures[1]); + glDeleteTextures(1, &texture_id); + + g_object_unref(window); + g_object_unref(display); + gst_deinit(); + return 0; +} diff --git a/tests/test-vc1.c b/tests/test-vc1.c new file mode 100644 index 0000000..60170f1 --- /dev/null +++ b/tests/test-vc1.c @@ -0,0 +1,1778 @@ +/* + * test-vc1.c - VC-1 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#include "test-vc1.h" + +#define VC1_CLIP_WIDTH 293 +#define VC1_CLIP_HEIGHT 240 +#define VC1_CLIP_DATA_SIZE 20864 + +/* Data dump of a 320x240 VC-1 video clip (vc1.raw), it has a single frame */ +static const guchar vc1_clip[VC1_CLIP_DATA_SIZE] = { + 0x00, 0x00, 0x01, 0x0f, 0xca, 0x00, 0x09, 0xf0, 0x77, 0x0a, 0x09, 0x20, + 0x1d, 0xff, 0x0a, 0x0b, 0x80, 0x84, 0x80, 0x00, 0x00, 0x01, 0x0e, 0x4c, + 0x10, 0x80, 0x00, 0x00, 0x01, 0x0d, 0xc1, 0xd8, 0xd4, 0x47, 0xd0, 0xaa, + 0xc4, 0x45, 0xaa, 0xb8, 0x01, 0xdf, 0x4c, 0xc1, 0x3a, 0xfa, 0x13, 0x67, + 0x6a, 0xed, 0x2c, 0x67, 0xbc, 0xef, 0xdc, 0x69, 0x99, 0xf8, 0x53, 0x97, + 0x01, 0xdc, 0xbe, 0xd8, 0x3b, 0xa2, 0x96, 0xe8, 0xa1, 0x94, 0x02, 0x57, + 0x82, 0x82, 0xd6, 0x14, 0xc7, 0x61, 0x5a, 0x00, 0x22, 0x81, 0x73, 0x33, + 0x20, 0x00, 0xa0, 0x09, 0xc0, 0x50, 0xfa, 0x06, 0xce, 0x35, 0x91, 0x8d, + 0x19, 0x0f, 0x07, 0x1e, 0x84, 0x5b, 0x3a, 0x29, 0x03, 0xad, 0x8f, 0x8a, + 0xd2, 0x22, 0xf0, 0xfc, 0x28, 0xd2, 0x95, 0x4a, 0xfe, 0x74, 0x4b, 0x23, + 0xe7, 0xd4, 0x12, 0x1f, 0x37, 0x01, 0x88, 0xf8, 0xa4, 0x09, 0x76, 0x51, + 0xae, 0xf4, 0x23, 0x6d, 0x29, 0x8c, 0x54, 0xaa, 0x2c, 0x68, 0x10, 0x7e, + 0x71, 0xbf, 0x10, 0xb4, 0x77, 0x97, 0x8b, 0xa1, 0x54, 0xd1, 0xda, 0xb5, + 0x5f, 0x61, 0xf0, 0x64, 0x64, 0x29, 0x25, 0x7d, 0x42, 0xe0, 0xff, 0x2a, + 0x83, 0x29, 0x61, 0xfc, 0xee, 0xe5, 0x11, 0x04, 0xc0, 0x43, 0xc0, 0xc4, + 0x0e, 0x18, 0x43, 0xb6, 0x08, 0x55, 0xa0, 0x22, 0xf4, 0x58, 0x01, 0xc6, + 0x43, 0x0d, 0xba, 0x04, 0x3e, 0x8e, 0x5f, 0xc1, 0x11, 0x56, 0xef, 0xd7, + 0x78, 0xe2, 0xd2, 0xdb, 0x84, 0x16, 0x76, 0xc6, 0x92, 0x15, 0xf6, 0xc2, + 0x76, 0x2f, 0xd2, 0xef, 0x46, 0x02, 0x60, 0x24, 0xda, 0x16, 0x48, 0x95, + 0xc4, 0x87, 0x81, 0xa7, 0xdd, 0xd7, 0x77, 0x56, 0xb7, 0xb5, 0x28, 0x9d, + 0x6b, 0x7b, 0xd6, 0x8b, 0x80, 0x42, 0x28, 0xb0, 0x28, 0x82, 0x50, 0x04, + 0x65, 0x1a, 0xc3, 0x79, 0x74, 0x6c, 0x3e, 0x9e, 0x69, 0x0e, 0xc1, 0xed, + 0x8d, 0xe9, 0xf0, 0xf4, 0xf8, 0xde, 0xc1, 0x62, 0x1d, 0x1f, 0x4a, 0x5d, + 0x02, 0x11, 0xfa, 0xd8, 0x10, 0xb8, 0xa0, 0xc5, 0xf5, 0x85, 0xd1, 0x19, + 0x14, 0x06, 0x21, 0x5b, 0xa5, 0x37, 0xcd, 0xf2, 0xbc, 0x3b, 0x7f, 0xe3, + 0x1c, 0x62, 0x51, 0x4b, 0x09, 0x2e, 0x48, 0x1f, 0x4e, 0x19, 0xe4, 0x90, + 0x22, 0x81, 0xf4, 0xf7, 0x16, 0x4f, 0xe5, 0x97, 0x12, 0x9b, 0x92, 0x6e, + 0xcc, 0x61, 0xd6, 0x4a, 0x59, 0x66, 0x7d, 0xc2, 0x1d, 0x33, 0x7e, 0x62, + 0x29, 0x81, 0x80, 0xb7, 0xa4, 0xcb, 0xc4, 0xc3, 0x9b, 0x1d, 0x2b, 0x00, + 0xc9, 0x78, 0x82, 0xef, 0xd7, 0xa5, 0xad, 0x08, 0x18, 0x7c, 0x97, 0x61, + 0x3e, 0xaf, 0x4e, 0x21, 0xd6, 0x5a, 0x35, 0xd6, 0xf9, 0xdf, 0x89, 0xe9, + 0x09, 0x99, 0x3e, 0x53, 0x81, 0x80, 0x21, 0xd9, 0x44, 0x7f, 0xb9, 0xe7, + 0x7d, 0x1d, 0xa6, 0xd4, 0xb6, 0x60, 0x71, 0xa3, 0x87, 0x13, 0x40, 0x7a, + 0x50, 0xac, 0x02, 0x87, 0xe3, 0x7a, 0xab, 0xce, 0x11, 0xed, 0x51, 0x97, + 0xc5, 0xf0, 0x33, 0xf5, 0x3b, 0x7e, 0x05, 0xda, 0x4d, 0x29, 0x23, 0xa7, + 0xca, 0x43, 0x0e, 0x72, 0xf0, 0x96, 0xe9, 0x95, 0x4a, 0x32, 0xb0, 0xc4, + 0xe5, 0x65, 0x73, 0xc3, 0x30, 0xea, 0xfb, 0x93, 0x04, 0x64, 0x48, 0x48, + 0x20, 0x1a, 0x8c, 0xde, 0xb0, 0x24, 0x7d, 0xd6, 0xe9, 0x5b, 0xb9, 0x0b, + 0x18, 0xb9, 0xc4, 0x4a, 0x81, 0xaa, 0xfb, 0x6b, 0x2f, 0xe6, 0x77, 0x00, + 0x17, 0xa8, 0x1f, 0x7f, 0x8b, 0xcd, 0xaf, 0xb5, 0xc1, 0x26, 0x99, 0x3f, + 0x74, 0xd9, 0x69, 0x4c, 0x4c, 0xe5, 0x8a, 0x51, 0x3b, 0x47, 0x18, 0x33, + 0x1a, 0xc5, 0xc3, 0xe1, 0xeb, 0xc7, 0x80, 0xa4, 0xb3, 0x5f, 0x22, 0x64, + 0xcc, 0x97, 0xcb, 0xdb, 0xe5, 0xc9, 0x09, 0x89, 0x65, 0xfd, 0x61, 0x76, + 0xc3, 0xf7, 0xfe, 0x7d, 0xe1, 0x70, 0x07, 0x9a, 0x17, 0x95, 0x08, 0x4d, + 0xec, 0xfb, 0x38, 0x61, 0x06, 0x1e, 0x96, 0x91, 0x19, 0x42, 0x88, 0xf1, + 0x45, 0x04, 0x69, 0x63, 0x1c, 0x99, 0xf8, 0x26, 0xf4, 0xfc, 0xf0, 0xeb, + 0x48, 0x06, 0x9d, 0xef, 0x46, 0x72, 0x41, 0xa9, 0xa5, 0xb8, 0x4a, 0xf0, + 0xd3, 0x82, 0x65, 0x88, 0x98, 0x40, 0x97, 0x4a, 0x95, 0x10, 0x52, 0xca, + 0x47, 0xec, 0x14, 0x75, 0x86, 0xd5, 0x7d, 0xf7, 0xda, 0xa5, 0x09, 0xc6, + 0x50, 0x02, 0x8f, 0xd7, 0x51, 0x42, 0x43, 0x60, 0x27, 0x67, 0xa0, 0xd6, + 0xd8, 0xcf, 0x58, 0xc5, 0x13, 0x27, 0xa2, 0x4e, 0x4f, 0xc3, 0xc2, 0x50, + 0xcb, 0x8d, 0x00, 0x53, 0x87, 0x5a, 0x6b, 0x4d, 0xb4, 0x07, 0x0b, 0x40, + 0xb3, 0xba, 0xc3, 0x14, 0xb8, 0x75, 0xda, 0x84, 0x50, 0x96, 0x12, 0xc6, + 0xd1, 0x00, 0xa5, 0xa3, 0x4c, 0x11, 0x45, 0x02, 0xc7, 0x2f, 0xe2, 0x8f, + 0xb7, 0xe9, 0xff, 0xe2, 0x48, 0x8b, 0x28, 0x1c, 0x38, 0x8c, 0x41, 0xc9, + 0xd0, 0xfa, 0x13, 0x4f, 0xfd, 0x6b, 0x72, 0xa5, 0x0e, 0xd7, 0x2f, 0x2b, + 0xee, 0x37, 0xe6, 0xb0, 0x41, 0x4d, 0x45, 0x83, 0x88, 0x6d, 0x14, 0x6d, + 0xa6, 0xb1, 0x59, 0x7d, 0x7e, 0xa7, 0x8d, 0x48, 0xc3, 0x4c, 0x80, 0x91, + 0xf0, 0x4d, 0xfc, 0xaf, 0xe6, 0xae, 0x9a, 0x24, 0xca, 0x73, 0xc4, 0x13, + 0xf8, 0x28, 0xd2, 0xbf, 0xdf, 0xc4, 0xd0, 0x4e, 0xf4, 0x3e, 0x2c, 0x60, + 0x6a, 0xd4, 0x6e, 0x44, 0x8a, 0xae, 0x09, 0x37, 0xb1, 0x98, 0xaf, 0x69, + 0xf0, 0xee, 0x6f, 0x0a, 0x55, 0x6d, 0x12, 0x7c, 0xf0, 0x08, 0x78, 0xd2, + 0x98, 0x7c, 0xdf, 0xd7, 0xa0, 0x0d, 0xf3, 0x52, 0x65, 0xf6, 0xb9, 0xfe, + 0xf3, 0x73, 0x4c, 0xe2, 0x3a, 0x27, 0x64, 0x00, 0x28, 0x54, 0x2d, 0x4a, + 0x59, 0x42, 0x43, 0xea, 0x26, 0xeb, 0x13, 0x2a, 0x5a, 0x9a, 0x35, 0xe9, + 0xe3, 0xe0, 0x3d, 0x84, 0xf0, 0x12, 0xbe, 0x84, 0x3f, 0x1c, 0xe6, 0x06, + 0xab, 0x30, 0x0d, 0xa3, 0xba, 0xe4, 0x24, 0xe0, 0x6f, 0x5c, 0xab, 0x43, + 0x9a, 0xf6, 0xf4, 0xd9, 0x74, 0x7e, 0x2c, 0x63, 0xf3, 0xd2, 0x17, 0x0b, + 0x57, 0xda, 0x1d, 0xd0, 0x47, 0x52, 0xc7, 0xc9, 0xb8, 0x14, 0x12, 0x23, + 0xc1, 0x23, 0x9b, 0x78, 0x51, 0x81, 0x7b, 0x66, 0x48, 0xbb, 0xc8, 0x7a, + 0x67, 0x84, 0x0a, 0xff, 0x82, 0xe9, 0x7e, 0xea, 0x5f, 0x5b, 0x94, 0xd6, + 0x24, 0x48, 0x3b, 0xa6, 0x25, 0x29, 0xd1, 0x92, 0x12, 0x9a, 0x5f, 0x84, + 0x3e, 0xb4, 0xe4, 0x3f, 0x15, 0xad, 0xe9, 0xec, 0xbc, 0x10, 0x7d, 0xc9, + 0xcd, 0xeb, 0x71, 0xd3, 0x79, 0x1a, 0xc2, 0xf5, 0x0d, 0x31, 0xac, 0x6a, + 0xac, 0xbc, 0x7f, 0x67, 0x43, 0x78, 0xc5, 0x23, 0x97, 0x56, 0x88, 0x3c, + 0xb0, 0x8e, 0x2c, 0x8a, 0x2b, 0x63, 0xfe, 0xb2, 0xaa, 0xb1, 0x71, 0x72, + 0x74, 0x41, 0xc3, 0x78, 0x0c, 0x5f, 0x92, 0x8d, 0x64, 0xe0, 0xf8, 0xde, + 0x09, 0x8f, 0xcd, 0x39, 0x45, 0x5a, 0x5d, 0x12, 0x6b, 0x26, 0xad, 0xfe, + 0xc0, 0x51, 0x1e, 0x00, 0xe9, 0x36, 0xf1, 0xb6, 0x74, 0x7b, 0x67, 0x6e, + 0xe2, 0xe4, 0xf4, 0x8e, 0x40, 0x87, 0xc6, 0x14, 0xcc, 0xa8, 0x25, 0x37, + 0x72, 0x0c, 0xc0, 0xf4, 0xff, 0xf4, 0x7d, 0xdc, 0xa8, 0xda, 0x68, 0xa5, + 0xbf, 0x04, 0xa3, 0x2c, 0x9f, 0xc7, 0x0a, 0x7c, 0x37, 0x86, 0xe7, 0x76, + 0x4e, 0x50, 0x79, 0xa5, 0xd1, 0x5f, 0x2e, 0x6f, 0x9a, 0x5c, 0x75, 0x73, + 0xd3, 0x7a, 0x10, 0x69, 0x45, 0xf1, 0x99, 0xca, 0x04, 0x24, 0x0a, 0x76, + 0xf5, 0xb9, 0xf7, 0xca, 0xf3, 0xfe, 0xde, 0x28, 0x70, 0x47, 0x3c, 0x35, + 0x17, 0x70, 0x21, 0x42, 0x32, 0x81, 0xfb, 0x3d, 0xc8, 0xf0, 0x35, 0xfe, + 0xe7, 0xee, 0x1b, 0x1e, 0xdd, 0xce, 0x19, 0xa2, 0x95, 0x95, 0x43, 0x2f, + 0xb2, 0x26, 0xcc, 0xbb, 0xb7, 0x8b, 0x8b, 0xff, 0x1c, 0xeb, 0x82, 0xa9, + 0x4f, 0x25, 0x58, 0xfa, 0x41, 0x22, 0x4a, 0xcb, 0x38, 0xc4, 0xff, 0x12, + 0x0d, 0xf7, 0x3b, 0xed, 0x0c, 0x7e, 0x29, 0xd3, 0x19, 0xe2, 0x2c, 0xff, + 0x8e, 0xbf, 0xe1, 0x1b, 0xc9, 0x6f, 0xac, 0x51, 0x97, 0x49, 0x68, 0x4d, + 0x20, 0x27, 0x3f, 0x11, 0xfe, 0x1e, 0x7f, 0xef, 0xda, 0x76, 0xba, 0xba, + 0xf2, 0xdb, 0x60, 0x36, 0x9a, 0xa3, 0x28, 0x89, 0xc8, 0x64, 0xb0, 0x90, + 0x79, 0xcb, 0x9d, 0x45, 0xcc, 0xdd, 0x6d, 0xf0, 0xd5, 0xb5, 0x8a, 0x64, + 0x51, 0x96, 0xcb, 0x12, 0x70, 0x0a, 0xca, 0x69, 0x34, 0x20, 0x43, 0x31, + 0x3c, 0xba, 0xb2, 0x80, 0xe1, 0xb2, 0x65, 0x79, 0x6f, 0x4e, 0x6e, 0x92, + 0x4b, 0xbf, 0x80, 0x2a, 0xb7, 0x97, 0x7f, 0xc9, 0xf5, 0xbc, 0xef, 0x1e, + 0x7f, 0xc9, 0xb6, 0x3d, 0x86, 0x4c, 0x89, 0x62, 0xac, 0x2b, 0xd0, 0x26, + 0x9d, 0xab, 0xeb, 0xfb, 0x5d, 0x4b, 0x6c, 0xe5, 0x58, 0x29, 0xb3, 0x4a, + 0x09, 0xed, 0x17, 0xf1, 0x00, 0xbb, 0x5c, 0x17, 0xc4, 0x56, 0x3b, 0xfc, + 0x13, 0x08, 0xc5, 0xcf, 0xc4, 0x14, 0x5f, 0xe2, 0xf8, 0xa5, 0xe2, 0xde, + 0x2f, 0x85, 0xde, 0xf7, 0xf7, 0x4d, 0xcd, 0x7b, 0xf2, 0xb6, 0x8b, 0x72, + 0x03, 0x6b, 0x2c, 0x7f, 0xde, 0x40, 0xf4, 0x76, 0x52, 0x2b, 0x61, 0x2d, + 0x72, 0xa2, 0x21, 0x0c, 0x1b, 0x44, 0x6c, 0x40, 0x04, 0xbc, 0x5e, 0xff, + 0xcb, 0xb6, 0x65, 0x99, 0xc6, 0xdb, 0xf7, 0x6f, 0xbc, 0x75, 0xd6, 0xcb, + 0x79, 0x6d, 0xd6, 0x94, 0xbd, 0xb7, 0x47, 0x89, 0xc6, 0xf6, 0xf0, 0xab, + 0x67, 0x60, 0x37, 0x32, 0x7d, 0x0f, 0x31, 0x08, 0xe2, 0x4e, 0x11, 0x0d, + 0x64, 0x1e, 0x66, 0xc6, 0xc6, 0xc5, 0x34, 0x56, 0xf8, 0xbf, 0x12, 0x83, + 0x7a, 0x75, 0xe0, 0x67, 0xae, 0x7b, 0x7e, 0xfb, 0xb6, 0x33, 0x38, 0xaa, + 0xea, 0x98, 0x9b, 0xfd, 0x36, 0x0d, 0x7e, 0x0f, 0xd4, 0xf9, 0x56, 0x6a, + 0xd5, 0x40, 0xb4, 0x38, 0xae, 0x6a, 0x7a, 0xc5, 0x40, 0x2c, 0x87, 0x72, + 0x80, 0x3e, 0x20, 0xf3, 0x48, 0xed, 0xbd, 0xb8, 0x13, 0xdf, 0xb7, 0xae, + 0x6a, 0xe6, 0x62, 0x6e, 0x73, 0x4c, 0xf0, 0x06, 0xba, 0x6c, 0xb2, 0xed, + 0xb6, 0x83, 0x32, 0x77, 0x63, 0xff, 0x84, 0x7e, 0xca, 0x91, 0xd7, 0x14, + 0xc7, 0xae, 0x12, 0x91, 0x49, 0xb6, 0x32, 0x92, 0x97, 0x5e, 0x39, 0x5a, + 0x71, 0x86, 0xdc, 0x92, 0xbb, 0x47, 0x8c, 0x3e, 0x24, 0xfc, 0x05, 0xf2, + 0x38, 0x7b, 0xdd, 0x4c, 0xec, 0x52, 0x8f, 0x80, 0x57, 0xd1, 0x52, 0x6b, + 0x0a, 0xb9, 0x81, 0xfd, 0x6b, 0xd2, 0x43, 0x58, 0x2c, 0x2a, 0xb8, 0x3d, + 0x66, 0xb0, 0x61, 0x9b, 0x3e, 0x7a, 0xc9, 0x38, 0x62, 0xc8, 0x6b, 0x4f, + 0xa0, 0xe3, 0xed, 0x13, 0x7b, 0xd6, 0x7c, 0xbb, 0x35, 0xaf, 0x81, 0xed, + 0x88, 0x91, 0x35, 0x2a, 0x5c, 0x5f, 0x47, 0xa7, 0x2f, 0x6f, 0xf5, 0x23, + 0x38, 0x20, 0x87, 0x5f, 0x65, 0x81, 0xfa, 0x44, 0x88, 0xd4, 0x96, 0x5e, + 0xc2, 0x84, 0xca, 0x39, 0x20, 0x28, 0x93, 0x94, 0x06, 0x4f, 0xc5, 0x41, + 0xff, 0x4e, 0x9d, 0xe6, 0xdb, 0x29, 0x50, 0xaf, 0x46, 0x49, 0x00, 0x24, + 0x04, 0xf2, 0xcd, 0x13, 0x84, 0x82, 0xa3, 0xc9, 0x21, 0x36, 0x26, 0x6f, + 0xad, 0xff, 0xb7, 0x6f, 0xf2, 0x6e, 0x15, 0x83, 0xa8, 0xb5, 0x2e, 0x89, + 0xfb, 0xca, 0xfe, 0xfa, 0x80, 0x2d, 0xc7, 0x43, 0xfe, 0xbe, 0xd5, 0x1b, + 0x8a, 0x4d, 0x08, 0xed, 0x55, 0x2c, 0x83, 0xc1, 0xe5, 0x7b, 0xc5, 0x1b, + 0x5d, 0xdd, 0xb7, 0x53, 0xf1, 0x3b, 0xd7, 0x7d, 0xed, 0xe6, 0x11, 0xbe, + 0x75, 0xb5, 0xb4, 0x22, 0x42, 0x53, 0x10, 0x81, 0x34, 0x7b, 0x81, 0x3c, + 0x94, 0x13, 0xc7, 0x2c, 0xed, 0xa1, 0xa3, 0x0a, 0x15, 0x7a, 0xb0, 0x26, + 0x69, 0xe0, 0x45, 0x19, 0xb1, 0x9c, 0x88, 0x9d, 0xe1, 0x61, 0x20, 0xee, + 0x3f, 0xe6, 0xa3, 0x8c, 0x61, 0x85, 0xa7, 0x28, 0xd2, 0x09, 0x7b, 0x69, + 0xb0, 0x95, 0x37, 0xd8, 0x96, 0x3c, 0xcc, 0x2c, 0x90, 0x83, 0x28, 0x8c, + 0x8b, 0x3b, 0xfe, 0xb7, 0xb5, 0x19, 0x15, 0x5e, 0xcf, 0x5f, 0xaf, 0x8c, + 0x76, 0x95, 0x02, 0x97, 0xe9, 0xac, 0x02, 0xb2, 0xee, 0x82, 0xe7, 0x16, + 0xca, 0x5b, 0x08, 0x22, 0xc6, 0x4e, 0xd2, 0xab, 0x10, 0x0f, 0x68, 0x5c, + 0xc2, 0x3d, 0x16, 0xf8, 0x74, 0x11, 0xd6, 0x4c, 0x65, 0xe1, 0x26, 0x9a, + 0x2d, 0xb0, 0x20, 0x66, 0xd2, 0xed, 0x60, 0xf4, 0xd1, 0xc2, 0x7d, 0x44, + 0xd7, 0xbd, 0x45, 0x36, 0x7b, 0xdc, 0xef, 0x87, 0xba, 0xbe, 0x16, 0x40, + 0x13, 0xa3, 0x3a, 0x6e, 0x12, 0xc0, 0xa3, 0xe2, 0x01, 0xfa, 0xde, 0xe5, + 0x75, 0xb9, 0x8a, 0x12, 0x19, 0x44, 0x8a, 0x12, 0xc9, 0x51, 0x84, 0xa5, + 0xcb, 0xc0, 0xec, 0xee, 0xd3, 0xaf, 0x34, 0xa4, 0x91, 0x34, 0x52, 0x01, + 0xeb, 0x00, 0x8e, 0x62, 0x71, 0x6f, 0x32, 0x80, 0x3e, 0xdc, 0x17, 0x3b, + 0x7d, 0x4b, 0x50, 0x4e, 0x81, 0x90, 0x98, 0xde, 0x4c, 0xc6, 0x90, 0x09, + 0x6e, 0xbb, 0x4e, 0x1f, 0x87, 0x0b, 0x2e, 0x1f, 0xed, 0x42, 0x0e, 0x2d, + 0x04, 0x24, 0xb0, 0x40, 0xc3, 0xde, 0x12, 0x24, 0x15, 0x2a, 0x68, 0x09, + 0xf8, 0xf8, 0x71, 0xf1, 0x85, 0x16, 0x12, 0xa4, 0x58, 0xc1, 0xa6, 0x19, + 0x1a, 0x68, 0x9d, 0xa1, 0x94, 0x32, 0x08, 0x11, 0x51, 0x14, 0xb1, 0xa4, + 0x24, 0x0c, 0xdd, 0x2c, 0x04, 0x20, 0x19, 0x72, 0x35, 0x60, 0xda, 0x79, + 0x84, 0x11, 0x05, 0xf0, 0xe6, 0x52, 0xf8, 0x9f, 0x3a, 0xd0, 0x9e, 0xe1, + 0xe4, 0x50, 0x99, 0x8c, 0xb4, 0xba, 0x33, 0xc7, 0xc0, 0x33, 0x00, 0x76, + 0x0e, 0x10, 0x19, 0x31, 0x23, 0x8d, 0x34, 0x96, 0xdf, 0xd8, 0x6b, 0x24, + 0x65, 0x3f, 0x4d, 0x1c, 0x95, 0x5a, 0x79, 0xc2, 0xe5, 0xb2, 0x36, 0xc5, + 0xa6, 0x8b, 0x28, 0x03, 0x95, 0xda, 0x51, 0xa3, 0x96, 0x00, 0xf9, 0xe0, + 0xbc, 0x7e, 0xc5, 0xab, 0x8a, 0x64, 0xa5, 0x7c, 0xf3, 0x65, 0x98, 0xc1, + 0x92, 0x4b, 0x9f, 0xa6, 0x87, 0x8a, 0x35, 0xa5, 0x35, 0x14, 0x93, 0x26, + 0x05, 0xfe, 0xec, 0x4b, 0xdc, 0xea, 0xd6, 0xb6, 0x54, 0x23, 0x2c, 0x24, + 0x72, 0xfe, 0x71, 0x90, 0x31, 0xfd, 0x00, 0x84, 0xc2, 0xc8, 0x63, 0x8a, + 0x88, 0xcb, 0x27, 0xf0, 0x7e, 0x05, 0x1e, 0xf3, 0xb4, 0xfa, 0x7e, 0xe1, + 0x77, 0x67, 0xe3, 0xa6, 0x28, 0x11, 0x48, 0xe3, 0xbd, 0x00, 0x25, 0x7b, + 0x30, 0xcb, 0xec, 0x27, 0xc1, 0x61, 0x28, 0x1c, 0x56, 0x66, 0x12, 0x10, + 0xba, 0x08, 0x03, 0x91, 0x43, 0xd3, 0x6d, 0x2a, 0xcd, 0x2a, 0x58, 0x64, + 0x68, 0x24, 0x4f, 0xc7, 0x47, 0xf1, 0x7c, 0x69, 0x9a, 0x14, 0x64, 0x5e, + 0x53, 0xbd, 0x74, 0x85, 0xa9, 0x29, 0xa6, 0x7e, 0xae, 0x39, 0x35, 0x40, + 0x8c, 0xe5, 0x59, 0x30, 0x5c, 0x7f, 0x46, 0xa1, 0x37, 0x29, 0x04, 0x07, + 0xc5, 0xf1, 0xcf, 0x30, 0x0f, 0x89, 0x87, 0x31, 0x4f, 0x33, 0xa2, 0x04, + 0xb2, 0x9b, 0x30, 0x55, 0x14, 0xb1, 0x82, 0xac, 0x3e, 0xb8, 0x1a, 0xb9, + 0xca, 0xa5, 0xe9, 0x4b, 0x28, 0x77, 0x3a, 0x63, 0xe8, 0xad, 0xbe, 0x98, + 0xd2, 0x2d, 0x32, 0xc6, 0x30, 0x82, 0x0e, 0xc1, 0x8f, 0xb9, 0x70, 0x13, + 0xca, 0x42, 0xd8, 0x07, 0x0f, 0x23, 0xd9, 0x5a, 0xed, 0x92, 0x9b, 0x38, + 0xc5, 0xa0, 0x65, 0xb1, 0x08, 0x90, 0xcb, 0x61, 0x2c, 0x05, 0x1f, 0xa6, + 0x2a, 0x55, 0x24, 0x2f, 0x40, 0xc2, 0x4f, 0x5c, 0xb3, 0xcc, 0xd5, 0xfb, + 0x57, 0xda, 0x92, 0x08, 0xed, 0x0e, 0x56, 0x4e, 0x55, 0x6d, 0xfc, 0xc3, + 0x66, 0x95, 0x9c, 0x81, 0x27, 0xe5, 0x6c, 0x9d, 0x42, 0x94, 0x38, 0x68, + 0x48, 0x22, 0x58, 0x48, 0x86, 0xfa, 0x83, 0x66, 0xb6, 0xbd, 0xca, 0x0d, + 0x0c, 0x72, 0x68, 0xd6, 0x07, 0xe4, 0xcc, 0x84, 0x76, 0x85, 0x0f, 0x9c, + 0x7a, 0x2d, 0x6a, 0xed, 0x3e, 0x34, 0xda, 0x2b, 0xf2, 0xf4, 0x67, 0xa6, + 0x00, 0xd1, 0x64, 0x5e, 0x45, 0x12, 0x82, 0x2d, 0x95, 0x2f, 0xac, 0x58, + 0xf9, 0xea, 0x65, 0x4b, 0x27, 0xdb, 0x3d, 0xdd, 0x8d, 0x8a, 0x5e, 0xda, + 0xb5, 0xd6, 0x05, 0x88, 0x64, 0x1c, 0x84, 0x7f, 0x69, 0x12, 0x11, 0x2f, + 0x80, 0x7d, 0x12, 0xbb, 0xaa, 0x50, 0x71, 0x9b, 0x4c, 0xba, 0xdf, 0xaa, + 0x5e, 0xf6, 0x34, 0x1f, 0xef, 0xa5, 0x4f, 0xfa, 0x95, 0x34, 0xef, 0x84, + 0xed, 0xd9, 0x2f, 0x1c, 0xcd, 0xc6, 0x5e, 0x90, 0xfb, 0x13, 0xf3, 0xf0, + 0xfa, 0x3f, 0x7f, 0x77, 0xca, 0x76, 0x12, 0x9a, 0x3c, 0x92, 0x86, 0xed, + 0xcb, 0xe0, 0x22, 0x84, 0x86, 0x5d, 0x02, 0xf2, 0xfa, 0x37, 0x83, 0x64, + 0xad, 0x1f, 0x0d, 0xdb, 0x95, 0x8f, 0x3d, 0x70, 0xbe, 0xff, 0xfb, 0x5d, + 0xfd, 0xbe, 0x1b, 0x92, 0xcc, 0xb6, 0x95, 0xef, 0x63, 0x8a, 0x72, 0xc8, + 0x4e, 0x88, 0xf9, 0xa3, 0xb9, 0x07, 0x9c, 0xb3, 0x3f, 0xad, 0xca, 0x84, + 0xb2, 0x06, 0x42, 0x28, 0xb7, 0xc4, 0xf1, 0x07, 0x9c, 0xcf, 0x8e, 0xe7, + 0xd9, 0xc9, 0xa8, 0xf8, 0x9e, 0x1b, 0x96, 0x48, 0xf6, 0xa9, 0x55, 0x5d, + 0x6d, 0xff, 0xff, 0xed, 0x49, 0xc8, 0x82, 0x8e, 0x33, 0x09, 0x78, 0x68, + 0x44, 0x2c, 0xd9, 0xbf, 0xd4, 0x22, 0x03, 0xad, 0x38, 0x01, 0x7b, 0xeb, + 0x1b, 0x8b, 0x6c, 0x94, 0xda, 0x81, 0x6e, 0xd8, 0x6a, 0x26, 0x02, 0x28, + 0xa3, 0x2f, 0xa8, 0x0f, 0xef, 0x0d, 0xbc, 0xb9, 0xa2, 0x57, 0xb2, 0x72, + 0x28, 0x81, 0x9b, 0x5d, 0x54, 0x86, 0x7b, 0xf9, 0xed, 0x13, 0xe1, 0x8c, + 0xa4, 0x32, 0x35, 0xe4, 0x8e, 0x01, 0xe1, 0xdd, 0x71, 0xc5, 0xfe, 0x50, + 0x53, 0xdf, 0xef, 0x6b, 0x69, 0x81, 0x35, 0x5a, 0x65, 0x16, 0x87, 0xce, + 0x42, 0x86, 0x32, 0xd4, 0x48, 0x97, 0x3f, 0x10, 0x39, 0xa3, 0xf6, 0x03, + 0xc1, 0xb2, 0xe7, 0xe3, 0xed, 0xae, 0x92, 0x06, 0xca, 0xd0, 0xd0, 0x96, + 0x51, 0xd2, 0x4b, 0x9f, 0xef, 0x5a, 0xdc, 0x66, 0x2b, 0x56, 0xa3, 0x5f, + 0xe3, 0x4b, 0x67, 0x39, 0x09, 0x6f, 0x27, 0x68, 0xd0, 0x75, 0x66, 0xf3, + 0x5c, 0x7c, 0x99, 0x97, 0xbe, 0x95, 0xb7, 0x22, 0xde, 0x54, 0x77, 0x8e, + 0x97, 0x05, 0x21, 0xa4, 0x00, 0x9a, 0x1d, 0xcc, 0xf5, 0x5e, 0xc6, 0xcf, + 0x48, 0x84, 0xab, 0x80, 0xe4, 0x3d, 0x25, 0xc0, 0x88, 0xc7, 0x62, 0xce, + 0x40, 0x32, 0x45, 0xc4, 0x89, 0x44, 0x64, 0xeb, 0x20, 0xe7, 0xba, 0x5a, + 0x97, 0xe7, 0xb1, 0x1a, 0xa6, 0xeb, 0xe2, 0x4f, 0x30, 0x03, 0x60, 0xc2, + 0x84, 0xcc, 0xf0, 0x0a, 0xa8, 0xb0, 0x97, 0x22, 0x48, 0x78, 0x40, 0x46, + 0x9f, 0xc4, 0x83, 0xfe, 0x62, 0x7b, 0xfe, 0xbb, 0xfb, 0x3d, 0x36, 0x2a, + 0xf5, 0xde, 0xb3, 0xbd, 0xf9, 0x4f, 0xcb, 0x1e, 0xbf, 0xcd, 0xe0, 0xef, + 0x3f, 0x34, 0x9b, 0xf3, 0x96, 0xd1, 0x30, 0x84, 0x69, 0x8d, 0x00, 0xf3, + 0x77, 0x1e, 0x06, 0x66, 0x09, 0x3d, 0xd2, 0xeb, 0x76, 0x2f, 0x96, 0xba, + 0x56, 0x73, 0x18, 0x6b, 0x5b, 0x89, 0xef, 0x1e, 0x9f, 0x4e, 0x5c, 0x62, + 0x73, 0xa5, 0x71, 0x7f, 0xa6, 0xb6, 0x27, 0x05, 0x89, 0xa6, 0x34, 0x6f, + 0xb8, 0x6a, 0x5c, 0xb3, 0x72, 0xe7, 0xc1, 0x2a, 0x9e, 0xc1, 0x3f, 0xbf, + 0x7f, 0x71, 0x7f, 0x6f, 0x3b, 0xfd, 0xf7, 0xbf, 0xb1, 0xfd, 0xaa, 0xdf, + 0x4b, 0x7f, 0x73, 0x6d, 0x7a, 0x2e, 0x2f, 0x95, 0xb6, 0xe6, 0xe5, 0xbc, + 0x18, 0x58, 0xcc, 0x4c, 0x3b, 0x49, 0x10, 0x88, 0x3e, 0x20, 0xe6, 0xfe, + 0x33, 0x5c, 0xc2, 0xc7, 0x6e, 0xbe, 0x7a, 0xbb, 0xaa, 0xd6, 0xd7, 0x13, + 0x81, 0xfb, 0xfd, 0xfe, 0x76, 0xfa, 0x26, 0xb9, 0x01, 0x87, 0x3d, 0x8f, + 0x5d, 0xe2, 0xa1, 0xc6, 0xa9, 0x2a, 0x26, 0xf7, 0x8f, 0x04, 0x23, 0x0c, + 0xd5, 0x49, 0x36, 0x72, 0x25, 0x74, 0x12, 0x66, 0xee, 0x7b, 0xe6, 0x2f, + 0xbf, 0x1f, 0xdf, 0xcc, 0xd2, 0x7d, 0xfd, 0xd5, 0x0b, 0x2d, 0xf7, 0xe3, + 0x37, 0x5b, 0xf7, 0xe3, 0xf7, 0xe5, 0x09, 0xfe, 0x7b, 0xca, 0xc7, 0x68, + 0xa7, 0xcb, 0x9d, 0xec, 0x38, 0xe4, 0x5e, 0xec, 0x02, 0x87, 0xd4, 0xc3, + 0xd9, 0x51, 0x5f, 0x3b, 0xef, 0xed, 0x78, 0x14, 0xe9, 0xde, 0xb7, 0xff, + 0x4f, 0x6d, 0x5d, 0x1c, 0x36, 0xed, 0xe5, 0x57, 0xe5, 0xd8, 0x39, 0x87, + 0x8b, 0x8e, 0xc7, 0x57, 0x97, 0xdd, 0x8a, 0x76, 0x40, 0xba, 0x23, 0xee, + 0x4d, 0x7c, 0x65, 0x72, 0xc8, 0x9d, 0x2f, 0xee, 0x36, 0xd4, 0xfb, 0xd6, + 0xff, 0x49, 0x7a, 0x7f, 0x93, 0xfa, 0x7b, 0x3f, 0x5a, 0x79, 0xf9, 0x85, + 0xd6, 0xeb, 0x7b, 0xf5, 0xd1, 0x64, 0x2e, 0x72, 0xf0, 0x98, 0x36, 0x03, + 0xed, 0xfe, 0xc0, 0x4e, 0x06, 0xec, 0x09, 0x8b, 0x83, 0x8d, 0x7f, 0x7b, + 0xa6, 0x75, 0xd7, 0x6e, 0xf3, 0xa8, 0xdb, 0xd2, 0xb6, 0x5b, 0xf8, 0xc5, + 0xe3, 0x86, 0xd1, 0x5a, 0xf9, 0xe7, 0x4e, 0x7a, 0x69, 0xb1, 0x65, 0xc3, + 0xc9, 0xb0, 0xfb, 0xbd, 0xea, 0xb7, 0x05, 0xd2, 0x73, 0x9a, 0x39, 0xdc, + 0xde, 0x2a, 0xef, 0xdf, 0x8c, 0xc3, 0xcd, 0xdf, 0x85, 0xf4, 0x89, 0xae, + 0xbc, 0xeb, 0xbf, 0xe7, 0xad, 0xe6, 0x9c, 0x6a, 0x60, 0xef, 0x5a, 0xff, + 0x4e, 0x95, 0xa6, 0x96, 0x2f, 0x3f, 0x97, 0x2c, 0x4d, 0x96, 0xd6, 0xe7, + 0xf4, 0x11, 0xe9, 0x5d, 0x5e, 0x28, 0x9c, 0x75, 0x55, 0xcc, 0xef, 0x65, + 0x6a, 0x2b, 0x29, 0xb7, 0xff, 0x43, 0x9d, 0xcb, 0x91, 0x60, 0x58, 0x50, + 0x79, 0xef, 0xb4, 0xd8, 0x7a, 0x1d, 0x94, 0x2a, 0xe4, 0x54, 0x74, 0x4c, + 0xe5, 0x8c, 0xeb, 0xfb, 0x13, 0xfd, 0x4a, 0xc3, 0xee, 0x3f, 0x71, 0x33, + 0xf9, 0xba, 0xa5, 0x17, 0xde, 0xcf, 0x45, 0x28, 0x75, 0xfe, 0xb8, 0x35, + 0xa5, 0x79, 0x9b, 0x54, 0x37, 0xc8, 0xa7, 0x8b, 0x0d, 0x56, 0x92, 0x3f, + 0xd8, 0xc8, 0x68, 0xf4, 0xe2, 0x1c, 0xbc, 0x4a, 0x5a, 0x9d, 0xea, 0x85, + 0x57, 0xa1, 0x45, 0x58, 0xb9, 0xc8, 0x23, 0x7a, 0xc5, 0xfe, 0x2f, 0xbd, + 0x9d, 0xe9, 0xbf, 0x19, 0x2a, 0x14, 0x0d, 0x78, 0xa4, 0x01, 0x03, 0x0e, + 0x97, 0x91, 0x0c, 0x5c, 0x6b, 0x9d, 0x29, 0x50, 0x5e, 0xfc, 0x18, 0x51, + 0x91, 0x9b, 0x03, 0x41, 0x1c, 0xb9, 0xe4, 0x42, 0x59, 0xcf, 0x3b, 0xd6, + 0xe9, 0xe3, 0x19, 0xc0, 0x82, 0x28, 0x60, 0x3f, 0x1e, 0x32, 0xe0, 0x05, + 0xca, 0x07, 0x5c, 0x8e, 0x37, 0xb0, 0xcb, 0x0d, 0xf1, 0x21, 0x91, 0x96, + 0x41, 0xb4, 0x67, 0x56, 0xab, 0x7d, 0x75, 0x02, 0x86, 0x83, 0xbf, 0x39, + 0x7b, 0x9d, 0x0c, 0x7c, 0xb0, 0x7d, 0x38, 0x4f, 0x9c, 0xf2, 0xe6, 0x52, + 0xdd, 0x2f, 0xc4, 0x3d, 0x75, 0x5e, 0xbb, 0x53, 0x7a, 0x4f, 0xa6, 0xf5, + 0x3a, 0xdb, 0xa1, 0xc0, 0x02, 0x62, 0xf2, 0xe6, 0x90, 0xca, 0x92, 0x3e, + 0x9c, 0x9f, 0x72, 0x0b, 0x7f, 0x63, 0xa7, 0x5f, 0x07, 0x2a, 0x62, 0xa9, + 0xe6, 0x22, 0x25, 0xb7, 0x96, 0xad, 0x51, 0x0b, 0xc6, 0x47, 0x9d, 0x76, + 0xbc, 0x1f, 0x83, 0x2c, 0x65, 0xd9, 0x15, 0xfb, 0x7c, 0x85, 0x6a, 0xd6, + 0xa6, 0xc8, 0x04, 0x5c, 0x25, 0xa1, 0x96, 0x91, 0xfa, 0x31, 0xaf, 0xd2, + 0x0d, 0xdd, 0x7f, 0x8a, 0x09, 0x4f, 0xd9, 0x38, 0x3f, 0xb6, 0x1e, 0x52, + 0xf3, 0x8a, 0x27, 0x25, 0xe2, 0x93, 0x08, 0x7c, 0x69, 0xa4, 0x39, 0xd6, + 0x59, 0x07, 0x0c, 0xd2, 0x91, 0x9c, 0xf3, 0x04, 0xf7, 0x7b, 0x99, 0x72, + 0x2c, 0x73, 0x7b, 0x6d, 0xe7, 0x7b, 0x1a, 0x8b, 0x71, 0x8e, 0x8c, 0xf2, + 0xea, 0x3a, 0x52, 0xee, 0x44, 0x91, 0xf8, 0x26, 0xfc, 0xc2, 0xde, 0x9b, + 0xd9, 0x6c, 0x3c, 0xc4, 0xaf, 0x75, 0x64, 0x3c, 0xa4, 0x27, 0xdc, 0xf8, + 0x5f, 0x91, 0x28, 0x87, 0xaa, 0xce, 0xea, 0x6e, 0x5c, 0xa2, 0x00, 0x04, + 0xcb, 0x4c, 0xe5, 0x99, 0xca, 0x00, 0x27, 0x34, 0x72, 0x5e, 0x0b, 0x4e, + 0x03, 0xbd, 0x7d, 0x10, 0x11, 0x90, 0xca, 0x8c, 0xbf, 0x04, 0xbe, 0xb2, + 0x5b, 0x65, 0xf1, 0x22, 0x83, 0xd1, 0x84, 0x3d, 0x16, 0x26, 0x30, 0xf1, + 0x03, 0xe6, 0x64, 0xa8, 0xc8, 0x20, 0x3c, 0x3b, 0x01, 0x72, 0xbc, 0xea, + 0xaa, 0x94, 0xf2, 0x80, 0x1d, 0x93, 0xc3, 0x3c, 0xbf, 0x4f, 0xce, 0x48, + 0x8f, 0xb5, 0x38, 0x83, 0x5c, 0x4d, 0x7f, 0xd6, 0x68, 0x70, 0x0c, 0x90, + 0x8c, 0x5d, 0x2b, 0xc2, 0x60, 0x51, 0xad, 0xfb, 0xfb, 0x22, 0x97, 0x02, + 0xe6, 0xda, 0x4c, 0x7c, 0x46, 0xfe, 0x36, 0xec, 0x8b, 0x9a, 0x09, 0x48, + 0x7d, 0x13, 0x2e, 0xd7, 0x1b, 0x3f, 0xcb, 0xe9, 0xa5, 0x90, 0xc4, 0x30, + 0x0c, 0x92, 0x23, 0x22, 0x89, 0x91, 0x62, 0x73, 0xb0, 0x8f, 0x55, 0xd2, + 0x9e, 0x1c, 0x3a, 0x22, 0x57, 0x87, 0xd9, 0x6e, 0x47, 0x93, 0xdd, 0xfd, + 0x53, 0xa0, 0x5e, 0x40, 0x92, 0x04, 0x54, 0x57, 0x3a, 0x69, 0x45, 0x7f, + 0xe7, 0x8d, 0x03, 0x8b, 0xff, 0xe2, 0x76, 0x13, 0xc1, 0x22, 0x2d, 0xf3, + 0xa9, 0x8b, 0xb9, 0x63, 0x33, 0x56, 0xa3, 0x9f, 0x02, 0xf5, 0x3d, 0x6c, + 0x89, 0xe3, 0xc9, 0x88, 0xc3, 0xa3, 0xf0, 0x5e, 0x05, 0xcd, 0x22, 0xeb, + 0xe1, 0x0c, 0x36, 0x2c, 0xb6, 0x7b, 0x40, 0x30, 0xf3, 0xab, 0x2f, 0xe0, + 0x4f, 0x03, 0x97, 0x2b, 0xd9, 0xfe, 0xfe, 0x23, 0xa7, 0x9f, 0x05, 0xdc, + 0x66, 0x82, 0xd2, 0x54, 0x6d, 0x87, 0xfa, 0x0c, 0x8e, 0x48, 0x25, 0xde, + 0xb0, 0x13, 0x77, 0x71, 0x55, 0x1e, 0x89, 0x63, 0x8d, 0xdb, 0x8a, 0x1c, + 0x31, 0x0d, 0xa2, 0xfa, 0xa0, 0x5c, 0x50, 0x34, 0x11, 0x22, 0x61, 0x1e, + 0xe0, 0x55, 0xfe, 0xd7, 0x5a, 0x5c, 0x91, 0x2b, 0xaf, 0x65, 0x91, 0x8c, + 0xe7, 0x1c, 0x34, 0x88, 0x22, 0x63, 0x2c, 0x56, 0x70, 0x4e, 0x15, 0x02, + 0x9b, 0x52, 0xff, 0x22, 0x14, 0xff, 0xb3, 0x05, 0x6e, 0xb7, 0xb6, 0x41, + 0x11, 0x21, 0x44, 0xe4, 0xf6, 0x90, 0xf0, 0x4d, 0x79, 0xf3, 0x34, 0x32, + 0xf2, 0x33, 0xb4, 0x94, 0x69, 0x49, 0xeb, 0xd3, 0x43, 0x7b, 0x07, 0x60, + 0xd1, 0xdc, 0x81, 0x43, 0x1a, 0x68, 0x1c, 0x9f, 0x64, 0xe3, 0x1c, 0x8d, + 0xaf, 0x40, 0x52, 0xd5, 0x28, 0x26, 0x69, 0x9c, 0x9a, 0x26, 0x80, 0x4e, + 0xc8, 0x12, 0x24, 0xeb, 0x56, 0x54, 0xe9, 0xb5, 0x2a, 0x0c, 0x44, 0xd2, + 0xd2, 0xe7, 0x56, 0xab, 0x97, 0x16, 0xac, 0x18, 0x41, 0x28, 0x4e, 0x11, + 0x46, 0x03, 0x2c, 0x79, 0x8c, 0x3f, 0xcf, 0x77, 0x96, 0x84, 0xc9, 0x03, + 0x26, 0xee, 0x7d, 0x3e, 0x15, 0xb6, 0x6b, 0x1d, 0x90, 0xdd, 0x87, 0x29, + 0x88, 0x06, 0x69, 0x19, 0x8c, 0x27, 0xef, 0x9d, 0x1a, 0x9f, 0xca, 0x12, + 0xff, 0x70, 0xee, 0x16, 0x10, 0x71, 0x95, 0x2a, 0x19, 0x79, 0x54, 0x3e, + 0x8b, 0xa7, 0x49, 0xc4, 0xe8, 0x4f, 0x2a, 0xac, 0xe0, 0x04, 0x66, 0x28, + 0xcf, 0x2a, 0x87, 0x64, 0x3e, 0x5d, 0x04, 0x3e, 0xc4, 0x89, 0x06, 0xc9, + 0x64, 0x98, 0xa0, 0xe7, 0x07, 0x6f, 0x05, 0xb4, 0xfb, 0x66, 0x9e, 0x33, + 0xb3, 0xbc, 0xe3, 0x10, 0x86, 0xa4, 0x10, 0xc9, 0xfd, 0x89, 0x97, 0x13, + 0x9e, 0x74, 0x49, 0x61, 0x29, 0xca, 0x9b, 0x98, 0x1a, 0x10, 0x84, 0x89, + 0xac, 0x02, 0xa3, 0xbf, 0xf2, 0x5f, 0xff, 0x8a, 0xfc, 0xf9, 0xab, 0xd6, + 0x90, 0xe5, 0xe0, 0x58, 0x2f, 0xd1, 0xde, 0x44, 0xc0, 0x5a, 0x67, 0x52, + 0x63, 0x28, 0x0a, 0x04, 0x63, 0xcf, 0xc1, 0x21, 0x38, 0xe9, 0x8b, 0xaf, + 0x2e, 0x4e, 0x40, 0x81, 0xa0, 0x9a, 0x1b, 0x69, 0x3f, 0x67, 0x07, 0x28, + 0x8c, 0x24, 0x24, 0x68, 0x63, 0x12, 0xee, 0xce, 0xdf, 0x8b, 0xeb, 0x4d, + 0x45, 0x07, 0xe7, 0xea, 0x49, 0xbb, 0xd1, 0x36, 0x6e, 0xdd, 0xd7, 0xe0, + 0xaf, 0x12, 0xf4, 0x08, 0x48, 0x9b, 0xd4, 0x26, 0x19, 0x6a, 0x5e, 0x7b, + 0xce, 0xd7, 0xde, 0xdd, 0x6a, 0x1f, 0xc1, 0x9b, 0xbd, 0x13, 0xb6, 0x1d, + 0x84, 0x15, 0x93, 0x3c, 0xf4, 0xf0, 0x06, 0xfa, 0xcd, 0xce, 0x89, 0x78, + 0x76, 0xe7, 0x23, 0x72, 0xe7, 0xf1, 0x3e, 0x27, 0x86, 0x54, 0x75, 0xec, + 0xef, 0x9e, 0x7b, 0xf2, 0x75, 0x57, 0x46, 0xc4, 0x2b, 0xf0, 0x55, 0x6c, + 0x95, 0x71, 0xc4, 0xf7, 0xd6, 0x32, 0xee, 0xd9, 0xa5, 0x8c, 0x6d, 0xce, + 0x40, 0x25, 0xc9, 0x01, 0x80, 0x7d, 0x75, 0xbf, 0x8a, 0xeb, 0xbc, 0x48, + 0xe7, 0xa7, 0x2e, 0x58, 0x06, 0x2c, 0xd5, 0xee, 0x20, 0x90, 0x22, 0xa8, + 0x4a, 0x41, 0x1e, 0xe7, 0x62, 0x9b, 0x13, 0x28, 0x02, 0x4d, 0xd6, 0xd0, + 0xb1, 0x80, 0x96, 0x39, 0xa3, 0x4c, 0xa4, 0x7b, 0x83, 0xf7, 0x78, 0x9f, + 0xbe, 0x0a, 0xf9, 0x98, 0xcb, 0x17, 0x7d, 0x46, 0xe4, 0x10, 0xbd, 0xa6, + 0x89, 0xca, 0x00, 0x98, 0xd0, 0x2f, 0xaa, 0x84, 0x09, 0xc2, 0xac, 0xc5, + 0xd6, 0xe9, 0x91, 0x1b, 0x5e, 0x49, 0x52, 0x73, 0x15, 0xf5, 0x6b, 0xf0, + 0xdb, 0xd4, 0x32, 0x8d, 0x34, 0xb8, 0x5c, 0x25, 0xe4, 0x21, 0x7a, 0x7c, + 0x44, 0x2e, 0x54, 0xe3, 0x5d, 0xf2, 0x59, 0xfd, 0x63, 0x6b, 0xb6, 0x2f, + 0x3b, 0xdb, 0xb3, 0x39, 0x94, 0xe5, 0x26, 0x26, 0x79, 0x5a, 0x0c, 0x26, + 0x12, 0xfc, 0x41, 0x57, 0x89, 0x63, 0x11, 0x0b, 0xc6, 0x46, 0x57, 0xa3, + 0xb2, 0xa5, 0x2a, 0x5d, 0xf6, 0xfd, 0x7c, 0x73, 0xe2, 0xaf, 0x6f, 0x5b, + 0xa4, 0xb3, 0x05, 0x1c, 0x7d, 0xc1, 0x89, 0xfa, 0xcd, 0x03, 0x29, 0xa0, + 0x25, 0x18, 0xcd, 0xe1, 0xf1, 0xee, 0x5a, 0x21, 0xbf, 0x4a, 0xb8, 0x4c, + 0x9c, 0x87, 0x21, 0x09, 0x19, 0xe4, 0xa5, 0xe2, 0x03, 0x50, 0x31, 0x34, + 0x7c, 0x49, 0xbf, 0xe6, 0x56, 0x6c, 0xb6, 0xdf, 0x4e, 0xa6, 0x34, 0xd9, + 0xd8, 0x90, 0x50, 0x26, 0x54, 0x11, 0x14, 0x08, 0x28, 0x1f, 0x05, 0x1b, + 0xa6, 0x5d, 0x39, 0x42, 0x77, 0xb6, 0xc7, 0xc4, 0xfa, 0xb1, 0x43, 0x0a, + 0x93, 0x86, 0xf9, 0xe0, 0xfe, 0xa9, 0x65, 0x99, 0xfe, 0xeb, 0x93, 0xe3, + 0x61, 0xb2, 0x2b, 0x6c, 0xde, 0xd6, 0xc6, 0x02, 0xc5, 0xc1, 0x91, 0x53, + 0x5e, 0xf4, 0xcb, 0xf9, 0x70, 0x03, 0xb0, 0xde, 0x85, 0x18, 0xc6, 0x4b, + 0xd0, 0xe2, 0x7a, 0x6a, 0x28, 0xc3, 0xec, 0x45, 0xc4, 0xf1, 0x91, 0x4a, + 0x44, 0x4c, 0x78, 0xe3, 0xa4, 0x47, 0xd8, 0x6a, 0x9a, 0xc8, 0x21, 0x67, + 0x10, 0x11, 0x35, 0x36, 0x42, 0xa2, 0xde, 0x4d, 0xb0, 0xc3, 0xb2, 0x5d, + 0x44, 0x27, 0x18, 0xbc, 0xd5, 0xbf, 0xd4, 0x9d, 0xe4, 0xb5, 0x50, 0x88, + 0x3a, 0xf8, 0x30, 0x8f, 0x64, 0xed, 0xbb, 0x28, 0x9e, 0x78, 0x9e, 0x41, + 0x6d, 0x98, 0x2f, 0x6c, 0x1c, 0xe9, 0xe0, 0x51, 0x93, 0x2a, 0xd2, 0xa7, + 0xdc, 0xcc, 0x91, 0x70, 0x40, 0xc9, 0x99, 0x82, 0x10, 0xec, 0xa9, 0xf9, + 0xde, 0x9d, 0x5b, 0xd6, 0x9d, 0xb7, 0xb5, 0xb3, 0xe8, 0x33, 0x31, 0x0e, + 0x49, 0x79, 0x25, 0x65, 0x51, 0x99, 0x28, 0x01, 0x3f, 0xad, 0x50, 0x9e, + 0x5f, 0x5c, 0x0c, 0x73, 0x42, 0xac, 0x53, 0xb7, 0x71, 0x87, 0x5d, 0x3b, + 0x53, 0x03, 0x30, 0x06, 0x7c, 0x66, 0xfa, 0x34, 0xfe, 0xa9, 0x41, 0xbf, + 0xba, 0x85, 0xf6, 0xa8, 0xe4, 0xbb, 0x95, 0xf2, 0xce, 0x59, 0x01, 0x32, + 0x50, 0x92, 0x13, 0xf8, 0xa9, 0x42, 0xad, 0x36, 0x27, 0x84, 0xd8, 0x5c, + 0xe8, 0x84, 0xa4, 0x0a, 0x43, 0xc4, 0x7d, 0xdb, 0x8a, 0x8e, 0xdb, 0x4f, + 0x34, 0xb8, 0x29, 0x1f, 0x4e, 0xa0, 0xc8, 0xa8, 0x88, 0xbf, 0xda, 0x86, + 0xcf, 0xc5, 0xac, 0xed, 0x0e, 0x37, 0x26, 0xa4, 0xba, 0x6e, 0x40, 0xc3, + 0x3a, 0x1f, 0x12, 0x44, 0xa4, 0xb0, 0x27, 0x28, 0x34, 0xe7, 0x7b, 0x2f, + 0x87, 0xe7, 0x86, 0xfe, 0xce, 0x04, 0x38, 0xd3, 0x18, 0x99, 0x30, 0x29, + 0xd6, 0x42, 0xce, 0xba, 0x73, 0xd8, 0x35, 0x6f, 0x43, 0x6a, 0x82, 0x5b, + 0x51, 0x12, 0x0e, 0xd4, 0x61, 0x48, 0xb9, 0x4a, 0xfb, 0x34, 0x95, 0x71, + 0x4c, 0xb8, 0x9a, 0xa7, 0x6e, 0xc6, 0x81, 0x38, 0xa4, 0x57, 0x83, 0xca, + 0x64, 0x19, 0xb4, 0x90, 0x91, 0x32, 0xac, 0x9b, 0x79, 0xce, 0x42, 0x01, + 0xf0, 0x66, 0x7f, 0x38, 0xa5, 0xad, 0x44, 0x43, 0x1f, 0xca, 0x0f, 0x59, + 0xbe, 0x8f, 0x9d, 0xff, 0x16, 0xc9, 0xb6, 0xb7, 0x37, 0xa4, 0x46, 0x54, + 0x62, 0xac, 0x03, 0x2a, 0xac, 0x07, 0x39, 0xf1, 0xc9, 0xcd, 0x9b, 0xd7, + 0x6b, 0x47, 0x13, 0x25, 0xb0, 0x68, 0x24, 0x1e, 0xb0, 0xb8, 0xec, 0x19, + 0xa7, 0x2e, 0xaf, 0x0e, 0xb2, 0x1b, 0xd1, 0x63, 0x56, 0x83, 0xce, 0x19, + 0xe9, 0xcb, 0x14, 0x0b, 0x19, 0x4f, 0xc3, 0x61, 0x55, 0x8d, 0xfe, 0x94, + 0x86, 0x4a, 0x0d, 0x78, 0xbb, 0x1b, 0x8a, 0x8d, 0x3d, 0xe4, 0xbe, 0x0e, + 0xf4, 0xa0, 0x97, 0x91, 0x02, 0xfe, 0x7d, 0xf4, 0xda, 0x44, 0x07, 0x79, + 0xc8, 0xa2, 0x4d, 0x24, 0x50, 0x39, 0x3f, 0x9c, 0x0f, 0x33, 0xba, 0x96, + 0x0b, 0xf9, 0x2b, 0xb7, 0x87, 0xc5, 0x74, 0x69, 0xba, 0xb6, 0xe2, 0x67, + 0x2d, 0xe0, 0xcc, 0x00, 0x0d, 0x5b, 0x64, 0x77, 0xb8, 0x4d, 0x1a, 0x23, + 0x2f, 0xd3, 0xf6, 0x47, 0x76, 0xff, 0x6d, 0x74, 0xde, 0x84, 0x36, 0xc3, + 0x7b, 0x62, 0x8c, 0x2f, 0xc4, 0x54, 0x15, 0x16, 0xc7, 0xd8, 0x10, 0xd7, + 0xa6, 0x0e, 0xd9, 0xa3, 0x1a, 0x41, 0x19, 0x76, 0x44, 0xa5, 0xda, 0x9e, + 0x6b, 0x0a, 0xaf, 0xea, 0x27, 0x29, 0x3f, 0xaf, 0x01, 0xb7, 0xb0, 0x31, + 0xff, 0x9e, 0x15, 0x21, 0x3d, 0xec, 0x3e, 0x24, 0x8a, 0x38, 0x63, 0x94, + 0x3c, 0x08, 0x39, 0xd9, 0x44, 0x99, 0x28, 0x64, 0x6b, 0x09, 0xcd, 0xe8, + 0xf8, 0x99, 0xb1, 0x33, 0x6d, 0xd6, 0xa4, 0xa5, 0xd2, 0x3c, 0x09, 0x39, + 0x38, 0x8b, 0x23, 0x14, 0x64, 0xb6, 0x01, 0xa2, 0x7e, 0x2c, 0xbe, 0xd5, + 0x24, 0xe5, 0xd8, 0x19, 0xce, 0xc8, 0x77, 0x8c, 0xec, 0x6c, 0x8a, 0x38, + 0x2d, 0x8b, 0xa8, 0x42, 0x2d, 0xb1, 0x34, 0x28, 0x9c, 0x85, 0x19, 0x78, + 0x40, 0x0a, 0xee, 0xff, 0xfa, 0xa3, 0xd9, 0xa2, 0x26, 0x55, 0xdb, 0x8f, + 0xa0, 0xc5, 0xd7, 0xa1, 0x07, 0x67, 0x87, 0x0f, 0x4e, 0x31, 0x09, 0x74, + 0x2a, 0xd2, 0xf3, 0xfb, 0xf3, 0x8c, 0x51, 0x65, 0x27, 0x74, 0x67, 0x2c, + 0x64, 0x7e, 0x6e, 0x32, 0xce, 0x12, 0x0b, 0x1b, 0xb6, 0xa2, 0xda, 0xb4, + 0xc2, 0xf4, 0xaa, 0xfe, 0x3a, 0x47, 0x52, 0x9c, 0x91, 0x43, 0x1f, 0xe7, + 0xee, 0x71, 0x8e, 0xa2, 0x3e, 0xbd, 0xf3, 0x2e, 0xbd, 0xbc, 0xae, 0x76, + 0x7f, 0x15, 0x3d, 0x41, 0xc1, 0xf3, 0xed, 0xc2, 0xdb, 0x3a, 0xcd, 0x2d, + 0xf4, 0xd4, 0x5e, 0x10, 0x02, 0x84, 0xd1, 0x23, 0x5d, 0xac, 0x86, 0x4c, + 0x7d, 0x17, 0xd3, 0xbc, 0x7f, 0xec, 0x42, 0xa9, 0x74, 0x01, 0x01, 0xa3, + 0x8e, 0x20, 0x8c, 0x26, 0x66, 0x4e, 0x03, 0xf5, 0x07, 0xac, 0x2b, 0xaf, + 0x5a, 0xd2, 0xbf, 0xef, 0x74, 0xf1, 0x5c, 0xb1, 0xa7, 0x48, 0x1a, 0x48, + 0x0c, 0x69, 0xc6, 0x32, 0xc0, 0x70, 0x80, 0x77, 0x9a, 0x4c, 0x6f, 0xd7, + 0x22, 0xd8, 0xcd, 0x42, 0x3f, 0xae, 0xf9, 0x01, 0x08, 0x06, 0x9c, 0xca, + 0xc8, 0x3d, 0x63, 0x2b, 0x54, 0x7e, 0x76, 0xc1, 0x2c, 0xe0, 0xf5, 0x50, + 0x54, 0x51, 0x1b, 0xcb, 0x77, 0x36, 0xed, 0x30, 0x2e, 0x63, 0xad, 0x34, + 0x38, 0x9a, 0xd6, 0x9b, 0x0c, 0xcd, 0x2c, 0x91, 0x7f, 0x19, 0xfc, 0x4d, + 0x58, 0xac, 0x47, 0xdd, 0x17, 0xf3, 0xb8, 0xa0, 0x10, 0x3f, 0x16, 0xad, + 0x9b, 0x06, 0xc9, 0x97, 0x7b, 0x3f, 0x40, 0xb0, 0x0d, 0x1d, 0x85, 0xcb, + 0x12, 0x79, 0x61, 0x8e, 0x31, 0x20, 0x51, 0x9e, 0x59, 0x97, 0x87, 0x6d, + 0xfa, 0x4a, 0x43, 0x70, 0x8f, 0x75, 0x9f, 0x31, 0x75, 0xd9, 0xa6, 0x84, + 0x9b, 0x40, 0xaf, 0x62, 0xa1, 0x7b, 0x4a, 0x6e, 0x72, 0xdc, 0xd0, 0xa0, + 0x04, 0x35, 0x94, 0xd5, 0xa7, 0x3e, 0xc6, 0xd3, 0x73, 0x7b, 0xfd, 0x5b, + 0x64, 0x1d, 0x94, 0x48, 0x69, 0x8a, 0x89, 0xd8, 0x50, 0x22, 0x30, 0x94, + 0xfb, 0x5f, 0xaa, 0x53, 0x0b, 0xb9, 0x53, 0xe4, 0xbe, 0x0a, 0x27, 0x97, + 0x77, 0x53, 0x0d, 0xc5, 0xde, 0x64, 0x7f, 0x73, 0x77, 0x23, 0x5a, 0x47, + 0xb0, 0xda, 0x7c, 0x3e, 0x00, 0xd4, 0x4f, 0x80, 0x3c, 0xd8, 0x7f, 0x4d, + 0x76, 0x56, 0x8f, 0x55, 0xdd, 0x6d, 0x63, 0xde, 0xeb, 0xa3, 0x8e, 0x44, + 0xcf, 0xcc, 0x9e, 0xe7, 0x42, 0x94, 0x7b, 0xb9, 0x1d, 0x7d, 0x15, 0xb3, + 0x0a, 0x9e, 0xe8, 0xd5, 0x8f, 0x2e, 0xe4, 0xa6, 0x79, 0x55, 0x82, 0xff, + 0xfe, 0x79, 0x3a, 0x3d, 0xa7, 0x02, 0x04, 0x8d, 0x65, 0x6e, 0xab, 0x9c, + 0x62, 0xd8, 0x6f, 0x7e, 0xab, 0x21, 0x70, 0x12, 0x88, 0x76, 0x68, 0x5b, + 0xe2, 0x4b, 0xc6, 0x69, 0x0d, 0x5f, 0xf8, 0x21, 0x92, 0xe5, 0x49, 0xef, + 0xe6, 0x79, 0x9d, 0xcf, 0x6d, 0x5a, 0x7d, 0xbf, 0x08, 0x61, 0x62, 0xbd, + 0x87, 0x75, 0x8e, 0x36, 0x1c, 0x0a, 0x13, 0x94, 0x9c, 0x03, 0x01, 0x2e, + 0x47, 0xd8, 0x93, 0x13, 0xab, 0xab, 0x8d, 0xfe, 0x4d, 0xb3, 0x4e, 0x0a, + 0x18, 0x67, 0x84, 0x38, 0x21, 0x11, 0xb0, 0x58, 0x7c, 0x78, 0x23, 0xaf, + 0xbc, 0x58, 0xf7, 0x3b, 0xeb, 0x69, 0x59, 0xc9, 0x1a, 0x03, 0xe6, 0x00, + 0x43, 0xc0, 0x15, 0x56, 0x9b, 0x19, 0xb3, 0xbc, 0xdb, 0xeb, 0xec, 0xca, + 0xb8, 0x6a, 0x18, 0x7c, 0x59, 0xba, 0xa4, 0xc6, 0x84, 0x91, 0x12, 0x4b, + 0x41, 0xf2, 0xbc, 0x5a, 0x52, 0x29, 0x99, 0x0c, 0x5e, 0xb0, 0x9f, 0x0c, + 0xd4, 0xc5, 0x6e, 0xed, 0xf9, 0xb0, 0xc1, 0xc1, 0x7d, 0xae, 0x67, 0x4c, + 0xc0, 0x55, 0xf4, 0xed, 0x03, 0xad, 0xc5, 0xb4, 0x83, 0xfe, 0xec, 0x16, + 0x70, 0x08, 0xdd, 0x5c, 0x45, 0xb4, 0xb7, 0x99, 0x9b, 0xec, 0xa0, 0x06, + 0x42, 0x44, 0xd0, 0x9f, 0xda, 0x05, 0xb7, 0xef, 0x7c, 0xd5, 0xa3, 0x0f, + 0x4c, 0x36, 0xf7, 0x92, 0x98, 0xc4, 0x64, 0x89, 0xa7, 0x2a, 0x39, 0x41, + 0xa1, 0x28, 0xcb, 0xc4, 0xc1, 0x77, 0xda, 0x49, 0xf7, 0xfa, 0xb3, 0x72, + 0x93, 0xa0, 0xad, 0x09, 0x9b, 0xd9, 0x82, 0x44, 0xf6, 0x84, 0x9c, 0xbf, + 0xad, 0x73, 0xde, 0x15, 0x76, 0xee, 0x9c, 0x4f, 0xce, 0x5f, 0x5d, 0xf4, + 0x90, 0x51, 0xfc, 0xaf, 0xfc, 0x59, 0x2a, 0x70, 0x92, 0x66, 0xeb, 0xd3, + 0x04, 0x29, 0xc8, 0xc2, 0x49, 0x40, 0x9a, 0xac, 0xff, 0x94, 0x31, 0x42, + 0x81, 0x83, 0x17, 0x6f, 0x87, 0xdc, 0x62, 0xe7, 0x74, 0x50, 0xc9, 0xc6, + 0x83, 0xbf, 0x7a, 0xe0, 0xae, 0x11, 0xbd, 0x86, 0x0f, 0x02, 0xdc, 0x2a, + 0x58, 0xee, 0x50, 0x04, 0xcf, 0x28, 0x7d, 0xa0, 0xdf, 0xd8, 0x2b, 0xec, + 0xe3, 0x79, 0xff, 0xd9, 0x2b, 0xc3, 0x23, 0x3a, 0x4a, 0x19, 0x26, 0x69, + 0x7c, 0x5a, 0xcb, 0xf5, 0x66, 0x11, 0xdd, 0x7e, 0x4f, 0x99, 0xc6, 0xf2, + 0x6f, 0xf6, 0xe5, 0x3f, 0x60, 0x46, 0xfe, 0x52, 0x26, 0xab, 0x3a, 0xcc, + 0x48, 0xbf, 0xdf, 0xcc, 0xaf, 0x67, 0xc5, 0x02, 0x99, 0x93, 0x43, 0x0b, + 0x11, 0x31, 0xda, 0x9c, 0xa6, 0x64, 0xb9, 0x4b, 0xed, 0x05, 0x56, 0xf8, + 0x75, 0xdf, 0xbc, 0x7d, 0xfd, 0xee, 0x69, 0x59, 0xfb, 0x68, 0x7e, 0xfd, + 0x94, 0xd3, 0x46, 0x1d, 0xa2, 0x61, 0x59, 0x8c, 0x7b, 0x05, 0x58, 0x07, + 0x8a, 0xfe, 0x37, 0x7b, 0xbc, 0x9c, 0x40, 0x04, 0x4d, 0x08, 0x31, 0xca, + 0x3c, 0xb9, 0x74, 0x67, 0x46, 0xbc, 0xc9, 0x79, 0x78, 0x4e, 0x60, 0xbf, + 0xf8, 0x92, 0x51, 0xa4, 0xda, 0x35, 0xfd, 0xe8, 0x89, 0x4b, 0xe0, 0xc8, + 0x9c, 0xb2, 0xbe, 0xb9, 0x3c, 0x26, 0x4b, 0x6a, 0x8a, 0xfa, 0xa8, 0x5c, + 0xd3, 0x0b, 0x9a, 0x86, 0xd9, 0x5a, 0xa1, 0x2b, 0x13, 0x2d, 0xf1, 0xe9, + 0xde, 0x99, 0x78, 0x0d, 0xc9, 0xae, 0x6d, 0x4e, 0x8e, 0x3c, 0x25, 0x2d, + 0x1f, 0xb1, 0x04, 0x69, 0x86, 0x4b, 0x23, 0xc3, 0x70, 0x8c, 0x5d, 0x08, + 0xc0, 0x3b, 0x8f, 0x88, 0x8f, 0x82, 0x42, 0x20, 0xef, 0xf8, 0xbb, 0x92, + 0x06, 0x8b, 0x19, 0x3e, 0xc6, 0x34, 0xa5, 0x95, 0x90, 0xf0, 0x16, 0xac, + 0xee, 0x4b, 0xed, 0x7c, 0xb6, 0x83, 0x2a, 0x67, 0x14, 0x8d, 0xec, 0x4c, + 0xe5, 0x6e, 0x96, 0x92, 0xa6, 0x05, 0x2a, 0xb1, 0x57, 0xb8, 0x7c, 0x31, + 0xc7, 0x56, 0xf4, 0xf3, 0xc9, 0x06, 0x3f, 0x51, 0x8e, 0x93, 0x45, 0xe6, + 0x22, 0xed, 0x44, 0x71, 0xff, 0x61, 0x38, 0x7f, 0xc4, 0x57, 0xff, 0x3c, + 0x04, 0x1a, 0xa1, 0xc8, 0x80, 0xb0, 0x97, 0x30, 0x2b, 0x17, 0xe5, 0x67, + 0xa2, 0x54, 0x38, 0xdc, 0x5e, 0x48, 0x27, 0xe8, 0x08, 0xd7, 0xfd, 0xef, + 0x99, 0x34, 0xb1, 0x40, 0x06, 0x14, 0x49, 0x43, 0x2b, 0x18, 0xbe, 0x5a, + 0x1d, 0xc1, 0x8e, 0xcf, 0x0a, 0xca, 0xf0, 0x13, 0x5b, 0x8b, 0x3f, 0xe8, + 0x3c, 0xa0, 0x84, 0x46, 0x09, 0x69, 0x14, 0x70, 0x1f, 0x06, 0x61, 0x3d, + 0xd3, 0x25, 0x24, 0x5f, 0x37, 0x0b, 0x36, 0xea, 0xbd, 0xce, 0xd9, 0xb5, + 0x0f, 0x21, 0x84, 0x25, 0xb4, 0x8b, 0x34, 0xe5, 0x41, 0xa7, 0x58, 0x47, + 0xcc, 0x97, 0x91, 0x1e, 0xcc, 0x63, 0x88, 0x8b, 0x84, 0xb9, 0xf7, 0x0c, + 0x59, 0xb4, 0x28, 0x8a, 0xa8, 0xcc, 0xa9, 0xc4, 0x9a, 0xb6, 0x2e, 0xca, + 0x0d, 0x8c, 0x52, 0x08, 0x9b, 0xd7, 0xee, 0x2a, 0x1b, 0x0e, 0xde, 0x81, + 0x38, 0x62, 0x97, 0x43, 0xe3, 0xd2, 0x20, 0x5a, 0x30, 0x92, 0xe9, 0x1f, + 0x14, 0x99, 0x69, 0x8c, 0xa1, 0x13, 0xc8, 0x48, 0x4e, 0xf5, 0x73, 0x3a, + 0xf4, 0xa1, 0xfb, 0xf4, 0x7c, 0xfb, 0x3f, 0x2d, 0xe6, 0x2d, 0x78, 0x10, + 0x03, 0x70, 0x7c, 0xc1, 0x90, 0x96, 0x4f, 0x09, 0x04, 0xfd, 0x03, 0x55, + 0xf7, 0x1a, 0x58, 0x5f, 0x6a, 0x26, 0x25, 0x80, 0xc6, 0x9f, 0xf7, 0x1b, + 0x45, 0x06, 0xdc, 0xcd, 0xf4, 0x65, 0x4b, 0xfb, 0xbe, 0xd7, 0x45, 0x19, + 0x1d, 0x41, 0x90, 0x82, 0x39, 0x14, 0x83, 0x35, 0x9c, 0xf3, 0xd7, 0x9f, + 0x9a, 0x70, 0x43, 0x03, 0x90, 0xde, 0x6d, 0x84, 0xb0, 0xe9, 0x55, 0x68, + 0xfb, 0xcd, 0xfb, 0x3c, 0x9b, 0x44, 0xb0, 0x22, 0x8b, 0x97, 0x79, 0x83, + 0xe9, 0xee, 0x5b, 0x59, 0xab, 0x8a, 0x69, 0x85, 0x37, 0x57, 0x11, 0x8f, + 0x97, 0x21, 0x80, 0xa1, 0x2c, 0x89, 0xc9, 0xed, 0x6c, 0xce, 0x4d, 0xb5, + 0xe2, 0xb7, 0xd2, 0xc4, 0xa2, 0x70, 0xe1, 0xb4, 0x45, 0x78, 0x2f, 0x0e, + 0x63, 0x06, 0x33, 0xc7, 0x9d, 0x1a, 0x52, 0x13, 0xdf, 0xda, 0xdb, 0xe8, + 0x57, 0x49, 0x1d, 0x81, 0xac, 0x71, 0x8c, 0x64, 0x90, 0x29, 0x19, 0xd1, + 0x33, 0xf9, 0xc0, 0xce, 0x13, 0xf2, 0x59, 0x16, 0xf0, 0xea, 0x6a, 0x75, + 0x78, 0x07, 0x75, 0xf0, 0xf9, 0x0a, 0x66, 0x52, 0x48, 0xd0, 0x4e, 0xd0, + 0x6b, 0x89, 0xd6, 0x9b, 0xef, 0x7e, 0xef, 0x23, 0x29, 0x0a, 0x4c, 0x28, + 0xe4, 0xc8, 0x1f, 0x15, 0x13, 0x3a, 0xca, 0x98, 0x20, 0x7f, 0xe2, 0x9d, + 0x2a, 0xe6, 0x1c, 0x77, 0xa5, 0x06, 0xe3, 0x19, 0xce, 0x7f, 0x38, 0xcf, + 0x5e, 0xd1, 0xef, 0xf8, 0x81, 0x20, 0xfa, 0x98, 0x45, 0x9f, 0x2b, 0x27, + 0xe0, 0x73, 0x8c, 0xe1, 0x01, 0x2c, 0x05, 0x0a, 0xa7, 0x19, 0xd9, 0xe5, + 0xf6, 0x06, 0xd4, 0x02, 0xdb, 0xee, 0x38, 0x41, 0x35, 0x02, 0x48, 0xa4, + 0x72, 0x0a, 0xa2, 0x6c, 0x6a, 0x8a, 0x18, 0x08, 0x4b, 0x26, 0x44, 0xa4, + 0x0a, 0x1e, 0x20, 0xcf, 0xfc, 0xa8, 0x72, 0x37, 0xe6, 0xe4, 0xea, 0xb4, + 0x4c, 0xe9, 0xe5, 0x6e, 0x1c, 0x57, 0x83, 0x2f, 0x44, 0x50, 0xc0, 0x3c, + 0x37, 0x07, 0x38, 0xbd, 0x6a, 0xc7, 0x88, 0x90, 0x0b, 0x7d, 0xe9, 0x20, + 0x2a, 0xbc, 0x73, 0xad, 0x07, 0x60, 0x52, 0x9a, 0x47, 0x2f, 0xe2, 0xc6, + 0x9a, 0xc0, 0x0d, 0x37, 0x12, 0x60, 0x99, 0x51, 0xfc, 0x5e, 0xdf, 0xc0, + 0x23, 0x7f, 0x47, 0xa2, 0x5c, 0xa6, 0x2f, 0xa5, 0x62, 0x13, 0xc6, 0x3b, + 0x61, 0xf1, 0x52, 0xe1, 0x90, 0x9b, 0xba, 0x4a, 0x67, 0x02, 0x3f, 0xfd, + 0x8d, 0xfe, 0xd7, 0xe1, 0xed, 0xd6, 0x26, 0x3a, 0xd9, 0x48, 0x3c, 0x00, + 0x11, 0x36, 0x33, 0x18, 0x6c, 0x9e, 0x57, 0x89, 0xe5, 0x44, 0xfe, 0xae, + 0x69, 0xd9, 0x4c, 0x22, 0x1f, 0x18, 0xe9, 0x07, 0xf8, 0xbf, 0x42, 0x8c, + 0x0b, 0xf1, 0xb5, 0x6c, 0x95, 0x2f, 0xcb, 0x0c, 0x85, 0x90, 0xc0, 0xfa, + 0x98, 0xcb, 0x32, 0xd8, 0xfb, 0x1a, 0x57, 0x49, 0xf5, 0xea, 0x9b, 0x27, + 0x3d, 0xf6, 0x11, 0xf5, 0xfc, 0xa9, 0x7f, 0xca, 0xe3, 0xf5, 0xb3, 0x50, + 0xd5, 0x78, 0xcf, 0x28, 0x99, 0x82, 0x11, 0x96, 0x46, 0x51, 0x00, 0x25, + 0x56, 0x4e, 0xf6, 0xa6, 0x59, 0xd3, 0x97, 0xdf, 0x0c, 0x1f, 0x4e, 0xa6, + 0x69, 0x50, 0x2f, 0xad, 0xe4, 0x84, 0x8b, 0x82, 0xc6, 0x45, 0x2f, 0xb8, + 0x07, 0x9a, 0x5c, 0x1e, 0xa8, 0xe7, 0x9a, 0xcc, 0xff, 0xf4, 0x89, 0x30, + 0xa7, 0x52, 0x9b, 0x99, 0x65, 0x28, 0xda, 0xef, 0x4f, 0x5a, 0x8c, 0x27, + 0x36, 0x4a, 0x06, 0x5d, 0xc0, 0x5c, 0x79, 0x96, 0xbf, 0x2d, 0xd6, 0xcb, + 0xa4, 0xcc, 0xc7, 0x15, 0xa0, 0x93, 0xb0, 0x2f, 0xa1, 0x19, 0x5f, 0x6e, + 0x66, 0x94, 0xe7, 0x37, 0x74, 0xf8, 0x22, 0x57, 0xed, 0xca, 0x0f, 0x0d, + 0x31, 0x54, 0xe2, 0x5b, 0xc6, 0xb1, 0x3d, 0x97, 0xb5, 0xdb, 0xaa, 0x5d, + 0x60, 0x0f, 0x08, 0x22, 0x1e, 0x2d, 0x80, 0x99, 0x92, 0x1a, 0x4d, 0x2d, + 0x90, 0x41, 0x38, 0x40, 0x0d, 0x07, 0xe0, 0xbc, 0x0c, 0x76, 0x58, 0x61, + 0xb2, 0xd1, 0x4b, 0x97, 0x68, 0x12, 0x3f, 0x6a, 0x4f, 0xc3, 0xf9, 0x1f, + 0xc8, 0x58, 0x39, 0x7b, 0xbc, 0x7f, 0x5a, 0xf9, 0xc4, 0x1a, 0x14, 0x88, + 0x27, 0x1d, 0xc6, 0xf6, 0x66, 0x95, 0x87, 0xcb, 0x99, 0xee, 0x50, 0x8d, + 0x56, 0xff, 0x90, 0x0b, 0xb4, 0x94, 0x77, 0xcb, 0x06, 0x63, 0x7a, 0x65, + 0xf1, 0xfc, 0x35, 0x59, 0x68, 0xee, 0x50, 0x25, 0xf2, 0x5c, 0xff, 0x28, + 0x9e, 0xd1, 0xd5, 0xea, 0x84, 0x14, 0x90, 0x28, 0xfc, 0x5f, 0xa0, 0x3e, + 0xc8, 0xee, 0x61, 0xeb, 0x05, 0x9c, 0x6e, 0x44, 0x58, 0x78, 0xfc, 0xfe, + 0x0c, 0xb5, 0x01, 0xf9, 0xab, 0xf3, 0xbf, 0xcd, 0x6f, 0x8e, 0x31, 0xdc, + 0x4a, 0xb4, 0x12, 0xe9, 0x8a, 0x15, 0x90, 0x62, 0x4d, 0xc1, 0xef, 0xbf, + 0x53, 0xeb, 0x8f, 0x90, 0x1d, 0x17, 0xbf, 0xc7, 0xa3, 0x0c, 0x35, 0x26, + 0x76, 0x9b, 0xa4, 0x56, 0xf0, 0xfc, 0x41, 0xe0, 0x96, 0x02, 0x75, 0x9b, + 0x0f, 0xfe, 0x1a, 0x9c, 0x10, 0x79, 0xa5, 0xfa, 0x2c, 0x5b, 0x6f, 0xfa, + 0xf3, 0x16, 0xea, 0xca, 0xed, 0xb5, 0xe9, 0xd3, 0x73, 0xf0, 0x41, 0x29, + 0x98, 0x4a, 0x00, 0x10, 0x03, 0xe8, 0x02, 0x6f, 0x15, 0xf8, 0x42, 0x65, + 0xb6, 0x8b, 0xf7, 0x12, 0x96, 0x55, 0xf6, 0x0e, 0x38, 0xaa, 0xc7, 0x6f, + 0x70, 0x7b, 0x40, 0x0f, 0xce, 0x02, 0xa7, 0xe3, 0xba, 0x8f, 0xff, 0xaa, + 0x76, 0x7e, 0x3c, 0xc9, 0x43, 0x98, 0x59, 0xa5, 0x4c, 0x68, 0x99, 0x03, + 0x01, 0x45, 0x11, 0x0d, 0x04, 0x60, 0xfa, 0x9d, 0xa9, 0xf7, 0xfd, 0x9e, + 0x3b, 0xac, 0xc6, 0xf9, 0xdd, 0xd2, 0x8c, 0x9b, 0x13, 0x58, 0x83, 0xcc, + 0x69, 0x6e, 0x63, 0x58, 0x79, 0x80, 0x10, 0xc6, 0x61, 0x21, 0xe0, 0x61, + 0x42, 0xac, 0x07, 0x95, 0xfd, 0xbd, 0xb7, 0xa8, 0x17, 0xed, 0x71, 0xc2, + 0x58, 0xf3, 0x36, 0x5e, 0x4e, 0x09, 0xe0, 0x3f, 0x6e, 0x1d, 0x28, 0x7c, + 0x4b, 0x9d, 0x1f, 0xd7, 0x84, 0x27, 0x29, 0xd3, 0x1f, 0xcf, 0x0a, 0xfc, + 0xdb, 0x3a, 0xde, 0xda, 0xd1, 0x3a, 0x50, 0x4a, 0x5a, 0x82, 0x80, 0x48, + 0xd1, 0x38, 0x49, 0x9d, 0x88, 0xb7, 0x39, 0x16, 0xa7, 0xb7, 0xbb, 0xdf, + 0x82, 0xfa, 0xa4, 0x08, 0xca, 0x13, 0x20, 0xe4, 0xcc, 0x69, 0x10, 0x89, + 0x85, 0xdc, 0xfe, 0xca, 0xd5, 0xbb, 0x1c, 0x75, 0x71, 0x94, 0x70, 0xce, + 0x46, 0x58, 0x33, 0x92, 0x5d, 0x61, 0x29, 0xe4, 0xa1, 0xaf, 0xed, 0x8e, + 0x35, 0x89, 0xa7, 0x45, 0x82, 0x33, 0x85, 0xa5, 0x36, 0x9f, 0x70, 0xbd, + 0xf4, 0x63, 0x5d, 0xc2, 0x3c, 0xd8, 0xea, 0x53, 0x7b, 0x6a, 0xf0, 0xa9, + 0x19, 0xbb, 0x9b, 0x1d, 0xf5, 0xaf, 0x4e, 0x71, 0xf4, 0xae, 0x44, 0x12, + 0x18, 0x71, 0x03, 0x4d, 0x9d, 0x04, 0x89, 0x47, 0xc4, 0x02, 0x69, 0xb9, + 0x6b, 0x79, 0x76, 0x29, 0x6f, 0xe6, 0x9b, 0x40, 0xe8, 0x4b, 0x94, 0x84, + 0xd1, 0x90, 0x3d, 0xaf, 0xcf, 0x3e, 0xdb, 0xe5, 0xec, 0x5e, 0x2d, 0x7f, + 0x1a, 0x92, 0x32, 0x10, 0xcc, 0xcb, 0xb5, 0xf0, 0x13, 0x15, 0xb4, 0x2e, + 0xec, 0x11, 0x65, 0x90, 0x42, 0x1b, 0xb5, 0x20, 0xa7, 0x7c, 0x92, 0xd1, + 0x33, 0x9d, 0xea, 0xa8, 0x46, 0xca, 0x2a, 0x60, 0x3d, 0xcf, 0x5d, 0x8f, + 0xa5, 0x25, 0x42, 0xe5, 0xff, 0x2a, 0x0b, 0x60, 0xcf, 0xfd, 0x8c, 0xb7, + 0xd9, 0x83, 0xa2, 0xc9, 0x6f, 0xc2, 0x5a, 0x30, 0xc2, 0xd8, 0x41, 0xd7, + 0x9a, 0xbe, 0x1b, 0xfe, 0x3c, 0xa3, 0x0f, 0x2d, 0x02, 0xe0, 0x4a, 0x66, + 0x92, 0x2d, 0xb4, 0x11, 0x48, 0xcb, 0xed, 0x04, 0xd9, 0xd1, 0x5b, 0xe3, + 0x7f, 0x9f, 0x99, 0x3b, 0x92, 0x95, 0x51, 0x64, 0x3a, 0x5d, 0x94, 0xce, + 0xfb, 0x73, 0xf1, 0xde, 0x2b, 0xf0, 0xcf, 0xb2, 0x00, 0x44, 0xe4, 0x92, + 0xbd, 0x3f, 0x5b, 0xa5, 0x1f, 0x97, 0xeb, 0x84, 0x52, 0x18, 0xd5, 0xad, + 0x79, 0x2d, 0x47, 0xfd, 0x24, 0xa3, 0x43, 0x2d, 0x0f, 0xa2, 0x9a, 0xd0, + 0xe5, 0x70, 0x23, 0x04, 0x82, 0x3d, 0x84, 0xab, 0x22, 0xf8, 0x82, 0x90, + 0x48, 0x56, 0x50, 0xb7, 0x9a, 0x41, 0x2d, 0xfc, 0x6f, 0x25, 0x0b, 0x86, + 0x01, 0x8b, 0x35, 0x18, 0xc4, 0xa4, 0x68, 0x78, 0x3a, 0x99, 0xd4, 0xa0, + 0xd3, 0xa3, 0x23, 0xf5, 0xde, 0x69, 0xba, 0x22, 0x60, 0x89, 0x56, 0x51, + 0x87, 0xe9, 0xea, 0x48, 0xbc, 0xdf, 0xe2, 0x9e, 0x7b, 0xfc, 0x88, 0x6b, + 0x6a, 0xe9, 0x65, 0xb8, 0x9c, 0xe9, 0x72, 0x28, 0xc9, 0xe9, 0x89, 0x11, + 0xf1, 0x2a, 0xd1, 0x4f, 0x7e, 0xf9, 0x5e, 0x07, 0x4f, 0xee, 0xdc, 0x82, + 0x4a, 0x53, 0x30, 0xf9, 0x96, 0x85, 0x1f, 0x99, 0xac, 0xd9, 0xfa, 0x44, + 0xa4, 0xe5, 0x4f, 0x16, 0xe7, 0x9c, 0x42, 0x11, 0x2d, 0x95, 0x2c, 0xbf, + 0x00, 0x17, 0x9e, 0x98, 0xc9, 0x9e, 0x77, 0x85, 0xe2, 0x0b, 0x29, 0xb7, + 0xa2, 0x4f, 0x04, 0xc9, 0x2d, 0xa3, 0x04, 0x8f, 0x82, 0x5e, 0x16, 0x58, + 0x33, 0x00, 0x21, 0x34, 0x72, 0xe4, 0x2a, 0xd9, 0x44, 0x7a, 0x63, 0xfc, + 0xf5, 0xa5, 0x80, 0x7f, 0x9e, 0xb6, 0xb9, 0xa5, 0xe3, 0xb4, 0x99, 0x1f, + 0x4d, 0x61, 0x1e, 0xcd, 0xa6, 0x37, 0x9f, 0x38, 0x8c, 0xfa, 0x28, 0xa5, + 0x81, 0x18, 0xe4, 0xbb, 0x29, 0xcf, 0x1c, 0x74, 0xd7, 0x69, 0xa7, 0xd9, + 0xed, 0x4c, 0x10, 0x93, 0xf3, 0x47, 0x81, 0xe7, 0x90, 0x32, 0x6d, 0xc4, + 0x74, 0x2a, 0xcd, 0x2f, 0x04, 0xd2, 0x00, 0xcc, 0x20, 0x7e, 0x71, 0xab, + 0x73, 0xf4, 0xda, 0xd9, 0xe2, 0xf7, 0x2c, 0xf4, 0x86, 0x42, 0x85, 0x13, + 0x47, 0x25, 0x2e, 0xe0, 0x65, 0x6f, 0x5a, 0x22, 0xbc, 0x1c, 0xf1, 0x8f, + 0x87, 0xff, 0xda, 0x99, 0x50, 0x54, 0xa4, 0x48, 0x47, 0x0f, 0xf6, 0x2d, + 0xdf, 0x99, 0xc9, 0xb4, 0xb4, 0x67, 0x8c, 0x06, 0x3e, 0x80, 0xf9, 0x9a, + 0x03, 0x25, 0x97, 0x84, 0x04, 0x93, 0x97, 0xa5, 0x52, 0xc4, 0x43, 0x0e, + 0x91, 0x45, 0x0c, 0x06, 0xf5, 0x15, 0x89, 0x47, 0x15, 0xba, 0xaa, 0x03, + 0x90, 0xf1, 0x43, 0x8a, 0x33, 0xc6, 0xc7, 0x19, 0x21, 0x47, 0x00, 0xac, + 0x89, 0xec, 0xa9, 0xb6, 0xb8, 0x34, 0x7b, 0xf2, 0x51, 0xd3, 0xf9, 0xf4, + 0x18, 0x19, 0x87, 0xd0, 0x07, 0x54, 0x70, 0xf9, 0x79, 0x74, 0x51, 0xee, + 0x41, 0x0d, 0xfa, 0xed, 0x8f, 0x0e, 0x2f, 0xf7, 0xd4, 0x8b, 0xc3, 0xb5, + 0x72, 0x26, 0x5c, 0xe5, 0xbe, 0x9c, 0x3e, 0x01, 0x04, 0xfc, 0x6d, 0x7b, + 0xc2, 0x4f, 0xfe, 0x2c, 0x5e, 0xea, 0xf1, 0x64, 0x31, 0xc5, 0x31, 0x31, + 0x42, 0x7d, 0x98, 0x80, 0x64, 0x42, 0x47, 0xc4, 0x45, 0xed, 0xfc, 0xf2, + 0x9f, 0x45, 0xad, 0xda, 0xaf, 0x51, 0x61, 0x97, 0x45, 0x68, 0x31, 0xc9, + 0xa1, 0x46, 0x5e, 0x03, 0xa9, 0xaa, 0x05, 0x14, 0x51, 0x61, 0xe9, 0xbd, + 0x58, 0x6c, 0x6d, 0x09, 0xd2, 0x48, 0x65, 0x7d, 0x79, 0xd9, 0xc9, 0x1e, + 0xca, 0xa5, 0xdc, 0xa7, 0x86, 0x77, 0xd6, 0x41, 0x45, 0x0f, 0x88, 0x7e, + 0xb1, 0xa5, 0xfa, 0xdd, 0xaa, 0x2d, 0xa8, 0x89, 0xa1, 0x32, 0x3b, 0x0b, + 0xe0, 0x0a, 0xf5, 0x72, 0x29, 0x9c, 0x03, 0xce, 0x00, 0x42, 0x46, 0x06, + 0x79, 0xbc, 0xd2, 0xfd, 0x23, 0x08, 0x00, 0x7c, 0xad, 0x65, 0xc5, 0x69, + 0x51, 0xa8, 0xcc, 0x68, 0x45, 0x7b, 0xc4, 0x72, 0xdc, 0xf0, 0x43, 0xd0, + 0xa3, 0x24, 0x94, 0x4f, 0xd3, 0x03, 0x53, 0xf9, 0x47, 0xf2, 0xcd, 0x79, + 0xa7, 0x4b, 0x7c, 0xbb, 0x69, 0x00, 0x51, 0xaf, 0x4e, 0x11, 0xf1, 0x3e, + 0x80, 0xaa, 0x8d, 0x57, 0x2f, 0xc9, 0x6a, 0xff, 0x3d, 0xbc, 0xdb, 0xad, + 0xea, 0x75, 0xfb, 0xdb, 0x70, 0x64, 0xd1, 0x1b, 0xed, 0x4a, 0x55, 0x01, + 0xe0, 0x6d, 0x99, 0x6f, 0x17, 0x56, 0x2d, 0x1e, 0x17, 0x47, 0x26, 0x1d, + 0x50, 0xcf, 0x00, 0xdc, 0xb2, 0x28, 0x2a, 0x9f, 0xd7, 0xf7, 0x2e, 0xb6, + 0xb9, 0xe3, 0x91, 0xca, 0x9e, 0x58, 0xdb, 0x64, 0x4a, 0x42, 0x31, 0xfa, + 0x8a, 0xba, 0x7c, 0xa5, 0x8a, 0x76, 0xce, 0xdc, 0x47, 0xe3, 0xf8, 0xeb, + 0x3a, 0xdc, 0x90, 0xb1, 0xc4, 0x28, 0x1c, 0xaa, 0x08, 0x51, 0xfb, 0x74, + 0x76, 0xbd, 0x83, 0x75, 0x3e, 0xef, 0x2d, 0xb3, 0x21, 0x60, 0x04, 0xa2, + 0xf8, 0x05, 0x14, 0x72, 0xa8, 0x61, 0x20, 0xe5, 0x26, 0x77, 0x71, 0x70, + 0x4f, 0x8a, 0xfa, 0x3b, 0x88, 0x7b, 0x59, 0x65, 0x10, 0xdd, 0xa2, 0x22, + 0x55, 0x58, 0x28, 0xfc, 0xb5, 0xe9, 0x91, 0x7a, 0xf2, 0x35, 0x08, 0x50, + 0x9a, 0x5f, 0xd2, 0xda, 0xb6, 0x5b, 0xda, 0xb9, 0x14, 0x83, 0xb2, 0x5f, + 0xee, 0x73, 0x0f, 0xa8, 0x6c, 0xb3, 0xe2, 0x4a, 0x47, 0xc1, 0x3d, 0xf5, + 0x44, 0x8d, 0x50, 0xfa, 0xa2, 0x3e, 0x85, 0xf0, 0x1f, 0x7d, 0x49, 0x47, + 0xc5, 0x43, 0x7f, 0x40, 0xa5, 0xe2, 0x09, 0x03, 0xae, 0x98, 0x4b, 0xd3, + 0x07, 0xb9, 0x1e, 0x05, 0x7c, 0xf1, 0xb1, 0xe7, 0x26, 0xd6, 0xc9, 0xc9, + 0x0f, 0x06, 0xd6, 0x9d, 0xfc, 0x2a, 0xdb, 0x7f, 0x43, 0x39, 0x61, 0x69, + 0x32, 0xe7, 0x98, 0xdb, 0xde, 0x51, 0xd7, 0x21, 0xd1, 0x2a, 0x84, 0x9d, + 0x16, 0x32, 0xa1, 0x4e, 0x70, 0x41, 0x23, 0x97, 0x2f, 0xa2, 0x4f, 0x4e, + 0xb4, 0x97, 0xae, 0x5e, 0x6f, 0x05, 0x03, 0x7a, 0x23, 0x40, 0x3c, 0x2d, + 0x42, 0xa5, 0x95, 0x6c, 0x40, 0xec, 0x65, 0x30, 0x72, 0x8e, 0x11, 0x0c, + 0x49, 0xa0, 0x9b, 0x28, 0xcf, 0x9f, 0xca, 0x67, 0x7b, 0xa0, 0x68, 0x16, + 0xf1, 0x31, 0xe3, 0x6f, 0xc2, 0xb6, 0xee, 0xf3, 0xd6, 0xb6, 0x68, 0x19, + 0x86, 0x97, 0xc5, 0x22, 0x57, 0xa8, 0x1b, 0xe4, 0x78, 0xd7, 0x1d, 0xf9, + 0xe8, 0xcf, 0x15, 0x9b, 0x73, 0x48, 0xc2, 0xd5, 0x50, 0xd1, 0x6d, 0x3d, + 0xf8, 0xfd, 0xdb, 0x57, 0x90, 0x60, 0xdf, 0x30, 0xdd, 0x85, 0x47, 0xc6, + 0xa3, 0x5e, 0x19, 0xef, 0x8c, 0xd9, 0x29, 0xe2, 0x46, 0x59, 0xb1, 0x72, + 0x9d, 0x59, 0xbf, 0x72, 0xae, 0x37, 0x1c, 0xc4, 0x87, 0xc5, 0x23, 0x15, + 0xc3, 0xc2, 0xcb, 0xe1, 0x1a, 0x52, 0x48, 0x21, 0xf7, 0x20, 0xd8, 0xb9, + 0xdf, 0xbd, 0xd5, 0x4e, 0x45, 0x50, 0x29, 0x16, 0xe4, 0xc8, 0x4d, 0xf1, + 0x8a, 0x34, 0x61, 0x0e, 0x50, 0xca, 0x22, 0x7e, 0x22, 0x31, 0xd9, 0xc5, + 0x67, 0xa6, 0x83, 0x1a, 0x5c, 0x91, 0x0c, 0xf2, 0xdf, 0x19, 0x9d, 0x00, + 0x95, 0x0f, 0x72, 0xba, 0xa2, 0xd9, 0xff, 0x1f, 0xc7, 0x45, 0xbc, 0xcc, + 0x49, 0x90, 0xc9, 0x78, 0xc1, 0x8e, 0x98, 0x51, 0x10, 0x34, 0xf6, 0xc9, + 0x64, 0xd5, 0x55, 0x14, 0xc5, 0xc5, 0x71, 0x2e, 0x51, 0x79, 0xbe, 0xaa, + 0xff, 0xa6, 0xb3, 0x8d, 0x62, 0x34, 0x49, 0x63, 0xa3, 0x51, 0xd0, 0x91, + 0x23, 0x29, 0x11, 0xe2, 0x85, 0xdc, 0xd2, 0x61, 0x57, 0x25, 0x76, 0x2b, + 0x42, 0x08, 0x69, 0xac, 0x57, 0xa4, 0x35, 0x34, 0x4b, 0xd5, 0x86, 0xf0, + 0x35, 0x9d, 0xb9, 0x17, 0x98, 0xbe, 0x69, 0x70, 0xd9, 0xcd, 0x0f, 0xe5, + 0xe5, 0xaf, 0x97, 0x1f, 0xa4, 0xc7, 0xd3, 0x8b, 0x22, 0x32, 0x78, 0x49, + 0x84, 0x64, 0xaa, 0xe7, 0xe9, 0x86, 0xd8, 0xb8, 0xad, 0xe9, 0xc5, 0x11, + 0xcb, 0xf3, 0xad, 0xb5, 0x14, 0xa5, 0xe2, 0xf1, 0x43, 0xb5, 0xdf, 0xd3, + 0x7e, 0xb7, 0x9e, 0x50, 0x68, 0xf6, 0xcb, 0x9e, 0x43, 0x4b, 0xf5, 0x19, + 0x0c, 0xa9, 0x1f, 0xd6, 0x14, 0x0e, 0xdc, 0xe0, 0x09, 0x64, 0xa5, 0xe6, + 0x02, 0x95, 0x71, 0x7c, 0xed, 0xb9, 0xb4, 0x87, 0x6c, 0x96, 0x50, 0xcc, + 0x13, 0xa1, 0x36, 0xee, 0xbf, 0x7e, 0xdc, 0x58, 0xf7, 0x7f, 0xd1, 0x04, + 0x13, 0x01, 0xa4, 0x6d, 0xb4, 0x9a, 0x1a, 0xd0, 0x9e, 0x4f, 0xe0, 0xe7, + 0xdc, 0x93, 0xb6, 0xfd, 0xd4, 0x54, 0xd8, 0xed, 0x0b, 0xeb, 0x38, 0x5b, + 0xfe, 0xde, 0xf9, 0x0e, 0x0f, 0xad, 0x17, 0x04, 0x84, 0x2c, 0x25, 0x0f, + 0x99, 0xd2, 0x10, 0xcb, 0x19, 0x1a, 0xcc, 0x59, 0x6f, 0xe8, 0x17, 0x6f, + 0xe5, 0x04, 0xb3, 0x40, 0x00, 0x02, 0x40, 0x77, 0x01, 0x1b, 0x6a, 0xb0, + 0x55, 0xf7, 0x29, 0x1c, 0x95, 0x64, 0x42, 0xdd, 0xbf, 0x21, 0x1d, 0xa9, + 0x43, 0x24, 0x8b, 0xfc, 0x52, 0xc0, 0xce, 0x58, 0x00, 0xf0, 0x1d, 0x19, + 0x7d, 0x2c, 0x52, 0xfe, 0x5f, 0x3d, 0x5e, 0x94, 0x05, 0x22, 0x72, 0x87, + 0x80, 0xb1, 0x4b, 0xb4, 0x94, 0xb2, 0x4d, 0x2f, 0x8e, 0x25, 0xbb, 0x22, + 0x6c, 0x35, 0x03, 0x4c, 0xcd, 0x16, 0x45, 0xf2, 0x64, 0x9f, 0x82, 0x08, + 0x78, 0x33, 0x8d, 0x1a, 0x20, 0x78, 0xbb, 0x99, 0xbf, 0xf8, 0x4e, 0x91, + 0x76, 0x5d, 0x26, 0x18, 0x5b, 0x0c, 0xf0, 0x42, 0x6a, 0xa0, 0x71, 0xfe, + 0xa7, 0xd2, 0x26, 0xd1, 0x69, 0x5e, 0x73, 0x42, 0x1d, 0xb0, 0x99, 0xd6, + 0x49, 0x03, 0xe2, 0x2e, 0x1d, 0xd1, 0x86, 0x6c, 0x95, 0xf5, 0x14, 0x13, + 0x56, 0xb5, 0x6e, 0x0a, 0xde, 0x8a, 0x28, 0x62, 0x37, 0x9d, 0x99, 0x29, + 0xd0, 0x86, 0x14, 0x26, 0x81, 0x6a, 0xa8, 0x07, 0xbb, 0x23, 0x58, 0x54, + 0xd7, 0x5a, 0x36, 0xef, 0xe7, 0xd8, 0x1b, 0x86, 0xba, 0x6e, 0x29, 0xe6, + 0x9c, 0x91, 0xb8, 0x19, 0xe7, 0xb3, 0x03, 0xba, 0x1a, 0x39, 0x64, 0x34, + 0x8f, 0x72, 0x0f, 0x2d, 0xff, 0x0d, 0x8a, 0xaf, 0x34, 0x4e, 0x31, 0xf6, + 0x64, 0xbb, 0x5c, 0x0c, 0x66, 0x87, 0xb4, 0xd0, 0x95, 0x37, 0x98, 0x14, + 0x48, 0x01, 0x10, 0x8d, 0x60, 0x1b, 0xd2, 0xc6, 0xe9, 0x02, 0xff, 0x3c, + 0x01, 0xcc, 0xa5, 0x95, 0xa3, 0x42, 0x4d, 0x59, 0x00, 0x33, 0x5d, 0x38, + 0xe7, 0x71, 0x79, 0xeb, 0xcc, 0x2b, 0xd3, 0x34, 0xb5, 0xd7, 0x61, 0xac, + 0x14, 0xb2, 0xec, 0x52, 0x1a, 0x0e, 0x97, 0x02, 0x49, 0xed, 0xfc, 0x06, + 0xbb, 0x7f, 0x6f, 0xfa, 0x23, 0xad, 0x6f, 0x96, 0x2e, 0xee, 0x03, 0x36, + 0x34, 0x08, 0x4f, 0x26, 0x4f, 0xcd, 0x3e, 0x28, 0x54, 0x97, 0xbd, 0xfb, + 0x31, 0x46, 0x1a, 0x6b, 0x9b, 0xcf, 0x2d, 0xca, 0x37, 0xab, 0x8f, 0xd6, + 0x30, 0xc5, 0x95, 0x6d, 0xfe, 0x6f, 0xc8, 0x1b, 0x70, 0x90, 0x25, 0xb1, + 0x92, 0x02, 0xb0, 0x9d, 0x81, 0x0e, 0x26, 0x51, 0x97, 0x60, 0xbe, 0x25, + 0x62, 0xae, 0x5c, 0xd6, 0xbd, 0xfc, 0xca, 0xad, 0x6a, 0x6a, 0xdb, 0x4b, + 0x19, 0x8a, 0x04, 0xce, 0x73, 0x73, 0x39, 0x22, 0x6b, 0x2f, 0x5f, 0x22, + 0x78, 0xd6, 0xd1, 0xcb, 0xa3, 0xf0, 0x48, 0x78, 0x80, 0xb9, 0x69, 0xe4, + 0x57, 0xdc, 0x0e, 0x47, 0x6a, 0x28, 0x94, 0x88, 0xca, 0xac, 0x83, 0x27, + 0xbb, 0x11, 0x74, 0x74, 0xc8, 0xce, 0x11, 0x01, 0xc0, 0x0e, 0x92, 0xaf, + 0x58, 0xf9, 0xd3, 0xae, 0xa5, 0xed, 0x81, 0x84, 0x69, 0xd5, 0xcb, 0xe3, + 0x65, 0xc9, 0x84, 0xbb, 0x5d, 0x89, 0xe3, 0x8f, 0x98, 0x04, 0xf7, 0x06, + 0x93, 0x9f, 0xd8, 0xb3, 0x61, 0xfe, 0xfa, 0xd2, 0x86, 0x39, 0x53, 0xed, + 0x58, 0x0b, 0x61, 0x88, 0x46, 0x8f, 0x8f, 0x1f, 0xdf, 0x1a, 0x7a, 0x77, + 0x06, 0x72, 0xc5, 0x6a, 0x88, 0x60, 0x2f, 0x4a, 0x60, 0xe4, 0xbe, 0xa0, + 0x59, 0x69, 0xb0, 0xc6, 0x49, 0x7a, 0x95, 0x03, 0x0e, 0xa9, 0x60, 0x22, + 0xa3, 0xd4, 0xc6, 0x54, 0x63, 0xdc, 0x1c, 0x5a, 0x8a, 0x25, 0x19, 0x4f, + 0xc4, 0x8d, 0xae, 0xba, 0x9b, 0x3e, 0xe1, 0xd2, 0x27, 0x1c, 0x68, 0x87, + 0x18, 0x06, 0x5f, 0x64, 0x25, 0xba, 0x67, 0x0e, 0xda, 0x9a, 0xb9, 0x97, + 0x9e, 0x52, 0x32, 0x44, 0x25, 0x9a, 0xa7, 0xa3, 0xae, 0xce, 0x19, 0x6d, + 0x33, 0x04, 0x63, 0x93, 0x14, 0x43, 0x8c, 0xaf, 0xa8, 0x4f, 0xa8, 0xe3, + 0x53, 0x6f, 0x77, 0x4b, 0xc6, 0xd9, 0x6c, 0x02, 0x8f, 0xd8, 0x17, 0x9d, + 0x52, 0x10, 0x2b, 0x4f, 0x92, 0x91, 0xd1, 0xa2, 0x94, 0x8f, 0xd5, 0xb9, + 0xd2, 0xf5, 0xd9, 0xec, 0x47, 0x4f, 0x27, 0x87, 0x21, 0x6d, 0x2c, 0x81, + 0x87, 0x07, 0xb5, 0x29, 0x26, 0x46, 0x7c, 0x47, 0x38, 0x97, 0x98, 0x13, + 0xa2, 0xaa, 0x47, 0x9d, 0x23, 0x3c, 0x9c, 0x2d, 0x80, 0x56, 0x10, 0xb9, + 0xbe, 0x78, 0xe8, 0x61, 0x17, 0x92, 0x8b, 0x88, 0x70, 0xf4, 0x31, 0xf0, + 0x0c, 0x07, 0xe7, 0xbd, 0x1c, 0x34, 0xe5, 0x8e, 0x8c, 0xe8, 0xd6, 0x4e, + 0x38, 0xef, 0x0b, 0x59, 0xf7, 0xc1, 0x5f, 0x0f, 0xa4, 0x21, 0x93, 0x90, + 0x27, 0x80, 0x21, 0x29, 0xe5, 0x7d, 0x12, 0xfd, 0x0e, 0x27, 0x0b, 0x42, + 0x8e, 0xcd, 0x12, 0x50, 0x96, 0x5b, 0x94, 0xa0, 0x3e, 0x29, 0xee, 0x1a, + 0x6f, 0xc5, 0x07, 0x9a, 0xef, 0xbc, 0x9e, 0x9e, 0x8b, 0x6f, 0x99, 0x96, + 0x78, 0x3b, 0x2c, 0xd2, 0xc5, 0x05, 0x91, 0x96, 0x5e, 0x39, 0x06, 0xb2, + 0x0f, 0x34, 0xa5, 0x98, 0x98, 0x67, 0xd9, 0x4e, 0x92, 0xb8, 0x46, 0xc0, + 0x7a, 0xf4, 0xf2, 0x90, 0x97, 0xcf, 0x33, 0x9e, 0x0b, 0xb7, 0xf3, 0xef, + 0xa5, 0xa5, 0xbf, 0x97, 0xf9, 0x04, 0x46, 0xea, 0x31, 0x21, 0x94, 0x61, + 0x19, 0x17, 0xd1, 0x9d, 0xe7, 0xfa, 0x3a, 0xaa, 0x52, 0x55, 0x46, 0x72, + 0x1b, 0x97, 0xd9, 0x6b, 0x5e, 0x3d, 0x15, 0x83, 0x55, 0x01, 0x95, 0x52, + 0x27, 0xd1, 0x0c, 0x41, 0x90, 0x67, 0x44, 0x7d, 0x4f, 0xd8, 0x7a, 0x3e, + 0x9f, 0xae, 0xc3, 0x00, 0x86, 0xc3, 0xc2, 0x06, 0xd8, 0x99, 0xb4, 0xfc, + 0x00, 0xbf, 0x8e, 0xa3, 0x0c, 0xf9, 0x14, 0x48, 0x2a, 0xb0, 0x5e, 0xf8, + 0xfe, 0x6b, 0x83, 0x13, 0xaa, 0x94, 0xd0, 0x62, 0x9b, 0xbb, 0xa7, 0x33, + 0x26, 0x18, 0xca, 0x60, 0x48, 0x0c, 0x5c, 0xe3, 0x13, 0x94, 0x24, 0xfe, + 0x00, 0xf3, 0x1f, 0xa2, 0x2f, 0xae, 0x49, 0x92, 0xe7, 0xf6, 0x49, 0x1e, + 0xf7, 0x57, 0x4c, 0xe5, 0x4c, 0x5f, 0x8c, 0xa3, 0xdc, 0x70, 0xbe, 0x5b, + 0x8c, 0x3c, 0xdb, 0xd3, 0x84, 0x02, 0x6e, 0xdc, 0xd5, 0x6a, 0xc9, 0xc2, + 0x5f, 0x95, 0x3a, 0x2d, 0x44, 0x87, 0x09, 0x52, 0x90, 0x41, 0x1f, 0xa8, + 0x93, 0x76, 0xae, 0x53, 0xd3, 0xef, 0x26, 0x15, 0x27, 0x38, 0x04, 0xc7, + 0xda, 0xed, 0xb1, 0x11, 0xe8, 0x2a, 0x67, 0x03, 0xd0, 0xfe, 0x5f, 0x85, + 0xfc, 0xa0, 0x6a, 0x73, 0x6e, 0xac, 0x15, 0x8d, 0xa2, 0xca, 0x5b, 0x32, + 0x52, 0xc1, 0x2e, 0xf4, 0xe6, 0x68, 0x99, 0xbd, 0xeb, 0x05, 0x4e, 0x8f, + 0xb7, 0x5c, 0xd1, 0x31, 0x5b, 0x17, 0x98, 0x81, 0xef, 0x69, 0x3d, 0x23, + 0x01, 0xc3, 0x34, 0xc7, 0x69, 0x39, 0x5e, 0xb3, 0x1e, 0x99, 0xa6, 0xbf, + 0x78, 0xee, 0x88, 0xe2, 0xdb, 0xd7, 0x4e, 0x17, 0xa0, 0x27, 0x0f, 0xe6, + 0x9f, 0x9f, 0x74, 0x0c, 0xa4, 0xd2, 0x47, 0xe3, 0xc1, 0xb5, 0xc9, 0x13, + 0xaa, 0x72, 0x22, 0xbb, 0x7d, 0xd6, 0xb8, 0x76, 0x6c, 0x5e, 0xd5, 0xf7, + 0x22, 0x69, 0x7c, 0x40, 0x4f, 0x64, 0xcd, 0x02, 0x43, 0x4a, 0x09, 0x1d, + 0x95, 0x90, 0x16, 0x3f, 0xaa, 0x4d, 0xdf, 0x5d, 0xea, 0x76, 0xb0, 0x52, + 0x92, 0xa1, 0xde, 0xd6, 0x2f, 0x66, 0x7d, 0x53, 0x65, 0xb4, 0xa6, 0x3e, + 0x0a, 0x85, 0x03, 0x56, 0x82, 0x6f, 0x17, 0xe6, 0xb6, 0xef, 0x0f, 0x4e, + 0x01, 0xc5, 0xba, 0x01, 0xdb, 0x23, 0x4c, 0x9f, 0x11, 0x59, 0x28, 0x71, + 0xc4, 0xf2, 0xeb, 0x00, 0xa9, 0x72, 0x7b, 0xd7, 0x02, 0x94, 0xd8, 0xaf, + 0xad, 0x16, 0x92, 0x51, 0xea, 0xe4, 0xb6, 0xf6, 0xe1, 0x80, 0xaf, 0x6b, + 0x0d, 0x2c, 0xbc, 0x6f, 0xb4, 0x0c, 0xa9, 0xd4, 0xf8, 0xb8, 0x19, 0xc5, + 0x69, 0x5d, 0x8f, 0xce, 0x4b, 0x98, 0x11, 0xae, 0x66, 0x19, 0x66, 0x6e, + 0xe5, 0x88, 0xc9, 0x23, 0xf5, 0xc6, 0x3d, 0x52, 0x4d, 0x5a, 0x6d, 0x5e, + 0xdc, 0x00, 0x21, 0x41, 0x53, 0xab, 0x97, 0x3d, 0xa3, 0xfb, 0xd9, 0xdf, + 0x90, 0x77, 0xeb, 0x4f, 0x8d, 0xec, 0xca, 0x17, 0xad, 0x65, 0xb9, 0x92, + 0x0c, 0x24, 0xd4, 0x80, 0x19, 0x78, 0x49, 0x7d, 0x9b, 0xcf, 0xdd, 0xaf, + 0xfd, 0xb8, 0xdd, 0x89, 0x4b, 0xe5, 0xb9, 0x99, 0x9b, 0x70, 0x24, 0xc5, + 0x86, 0x42, 0x92, 0x2c, 0x47, 0xd5, 0x1a, 0x50, 0x5d, 0x4d, 0xcf, 0xdc, + 0xb4, 0x19, 0x9a, 0xe2, 0x94, 0x5f, 0x1b, 0x19, 0x40, 0xd3, 0x5c, 0xe3, + 0x09, 0xe3, 0x7c, 0x15, 0x60, 0x49, 0xf7, 0xf9, 0xdb, 0x8e, 0x38, 0x69, + 0xfa, 0xa2, 0xe6, 0x18, 0x11, 0xc3, 0x57, 0xa0, 0xec, 0x1b, 0x43, 0x3a, + 0xb1, 0x5a, 0x6a, 0xcd, 0x5a, 0x2e, 0x59, 0x10, 0x8b, 0xc1, 0xfc, 0xbd, + 0x75, 0xc9, 0x5e, 0x5c, 0xe2, 0x28, 0xb8, 0x72, 0xbc, 0xb3, 0x8a, 0x5e, + 0x82, 0x32, 0x50, 0xa3, 0xe0, 0x77, 0xf6, 0xe0, 0x46, 0xbe, 0xda, 0x52, + 0xa5, 0x13, 0xa5, 0x99, 0xcd, 0xc3, 0x55, 0x31, 0x83, 0x10, 0x72, 0xa3, + 0x2d, 0x14, 0x49, 0xda, 0x57, 0x81, 0xd7, 0x7f, 0xbd, 0x29, 0x6d, 0xb8, + 0x21, 0xe4, 0x4b, 0x58, 0x99, 0x74, 0x84, 0xef, 0x77, 0xd6, 0x92, 0xe0, + 0x81, 0xe1, 0xc0, 0x3c, 0x10, 0x81, 0xf9, 0xa9, 0xaa, 0x63, 0x74, 0x98, + 0x91, 0xa8, 0x72, 0x16, 0xa6, 0xf3, 0xf9, 0x89, 0xe4, 0xe6, 0x48, 0xac, + 0x50, 0x65, 0x11, 0x4c, 0xef, 0xfe, 0xcf, 0x89, 0xd3, 0x9f, 0xc1, 0xfc, + 0xdc, 0xea, 0x75, 0x19, 0xc7, 0xd0, 0x12, 0xaf, 0x20, 0x64, 0x82, 0x08, + 0x8e, 0xc8, 0x0f, 0x15, 0x51, 0x7b, 0xe2, 0x6b, 0xb0, 0x1c, 0xcd, 0xad, + 0xd1, 0x77, 0x2d, 0xad, 0xa0, 0xec, 0x81, 0xa7, 0xa8, 0x28, 0xcd, 0xb1, + 0xcc, 0xa5, 0x43, 0xc4, 0x5b, 0xb8, 0x9c, 0x84, 0xa5, 0x2c, 0xac, 0xba, + 0xc0, 0x2a, 0x61, 0xc7, 0xf1, 0xb6, 0x57, 0x56, 0xe5, 0xca, 0x96, 0xbb, + 0xfb, 0x8e, 0x49, 0x3e, 0x50, 0x2f, 0x36, 0x73, 0x5b, 0x44, 0x5b, 0x36, + 0x9c, 0xa0, 0x90, 0xc6, 0x96, 0x4e, 0x73, 0x1f, 0x68, 0x47, 0x43, 0xd3, + 0x6b, 0x1f, 0x4d, 0x43, 0x1e, 0xbf, 0x1c, 0x28, 0xe9, 0xf5, 0x3d, 0xac, + 0x48, 0x4c, 0xd4, 0x6d, 0x32, 0x25, 0xf3, 0x71, 0x29, 0xe9, 0xf0, 0x08, + 0x2a, 0xd2, 0x75, 0xc1, 0xa6, 0x5f, 0x1f, 0xca, 0xbb, 0x76, 0x91, 0xdc, + 0xca, 0x13, 0x3b, 0x18, 0xd9, 0x66, 0x48, 0xb0, 0x29, 0x01, 0x39, 0xfd, + 0x35, 0x8b, 0xd7, 0xac, 0xeb, 0xe3, 0x92, 0x96, 0xef, 0xe1, 0x7e, 0xd7, + 0xd0, 0xe9, 0xd6, 0xcf, 0xd7, 0x28, 0x58, 0x0a, 0x20, 0xcc, 0xc1, 0x8a, + 0x45, 0x45, 0xe0, 0x71, 0xca, 0x66, 0x75, 0xb0, 0x97, 0x89, 0x13, 0x7b, + 0xa3, 0x27, 0x5d, 0xce, 0x36, 0x58, 0xf6, 0x0a, 0x66, 0xf5, 0x83, 0xc8, + 0xef, 0x6e, 0x6f, 0x98, 0x79, 0x52, 0xd7, 0xd4, 0xa3, 0x3f, 0xda, 0x70, + 0xe2, 0x41, 0x10, 0x55, 0x20, 0x71, 0xb0, 0xd8, 0xd9, 0x14, 0x19, 0xc6, + 0x76, 0x0d, 0x45, 0x78, 0xb5, 0x70, 0x88, 0x65, 0x5a, 0x6b, 0xeb, 0x2f, + 0x28, 0x38, 0xf9, 0xbc, 0x28, 0xbe, 0xca, 0x44, 0x86, 0x4e, 0xd4, 0x29, + 0xc6, 0x16, 0xca, 0x3e, 0xb7, 0x33, 0x58, 0x04, 0x33, 0x7c, 0xac, 0xb5, + 0x9f, 0xf9, 0xfd, 0x6d, 0xb9, 0xff, 0x5a, 0x35, 0xa6, 0xd8, 0xa5, 0x28, + 0x30, 0xf5, 0x16, 0x95, 0xa9, 0x14, 0x65, 0x97, 0x56, 0x01, 0x4d, 0xf8, + 0x71, 0xc9, 0x93, 0xad, 0xac, 0x97, 0x1d, 0xab, 0x70, 0x21, 0x2d, 0xf3, + 0x26, 0x16, 0x66, 0xcb, 0xa2, 0x67, 0x56, 0x09, 0xd9, 0x9d, 0x9c, 0xec, + 0x37, 0x4d, 0x71, 0xbd, 0xef, 0xaf, 0x22, 0x78, 0xd9, 0x4c, 0xdd, 0xab, + 0x9a, 0x12, 0x28, 0x7d, 0xb4, 0xd4, 0x9c, 0x01, 0xf2, 0x85, 0x2f, 0xbc, + 0x58, 0x77, 0x85, 0x32, 0xdf, 0x4e, 0x79, 0x41, 0x41, 0xda, 0x6e, 0x9f, + 0x60, 0x09, 0x82, 0xf4, 0x50, 0x15, 0x68, 0x0f, 0xfd, 0x0b, 0x5b, 0x09, + 0x33, 0x98, 0x9c, 0x92, 0x1d, 0xc1, 0x38, 0xbe, 0xdc, 0x17, 0xbe, 0x88, + 0xa8, 0xa6, 0x88, 0xa2, 0x0f, 0x81, 0xcd, 0xb6, 0xde, 0x42, 0xc7, 0x7d, + 0x53, 0xc6, 0xab, 0xd3, 0x94, 0x9d, 0x2e, 0x79, 0x2f, 0x0b, 0x76, 0x63, + 0x36, 0xa5, 0x85, 0x7f, 0x94, 0x07, 0x53, 0xe7, 0xa8, 0x6a, 0x0d, 0xb1, + 0xda, 0x1f, 0xad, 0xb6, 0x5b, 0x13, 0xe7, 0x21, 0xcc, 0xe7, 0x29, 0x09, + 0x48, 0x1a, 0x19, 0x7e, 0x22, 0x1b, 0x1b, 0xe5, 0xf2, 0x1a, 0x08, 0x25, + 0x30, 0xca, 0xf1, 0xd6, 0x97, 0x56, 0x3a, 0xa7, 0x3f, 0x0b, 0xce, 0xaf, + 0xfc, 0x50, 0x24, 0x34, 0xab, 0xf0, 0x9c, 0x91, 0x12, 0xc0, 0x4f, 0xd5, + 0xed, 0xa4, 0xf4, 0xe4, 0x36, 0x54, 0x49, 0xed, 0x36, 0x61, 0x6d, 0xa4, + 0x1e, 0x63, 0x24, 0x3c, 0x40, 0xb0, 0xb2, 0x44, 0xe3, 0x6d, 0xf2, 0xa6, + 0x96, 0x97, 0xe9, 0x97, 0xd4, 0x76, 0x80, 0x0c, 0x6d, 0xa8, 0xb1, 0x39, + 0x48, 0x48, 0x7c, 0x1b, 0x46, 0x9e, 0x94, 0x7a, 0xbf, 0xfd, 0xc6, 0xff, + 0x72, 0xf0, 0x4d, 0x4b, 0x22, 0x46, 0x32, 0x8e, 0x51, 0x23, 0xe7, 0xb2, + 0xe7, 0xa7, 0x05, 0x38, 0xb9, 0x25, 0xcc, 0xe2, 0xbf, 0x08, 0xff, 0x77, + 0xf9, 0xb6, 0x37, 0xcd, 0x29, 0x47, 0xc3, 0x10, 0xe4, 0xc9, 0xd5, 0xaa, + 0x41, 0xe8, 0x6c, 0x6d, 0x17, 0xa2, 0x8a, 0x08, 0xcc, 0xde, 0xa3, 0xcb, + 0xeb, 0x66, 0x86, 0x2c, 0x0b, 0xd3, 0xeb, 0xb3, 0x4b, 0x9e, 0x64, 0x70, + 0xf3, 0xa2, 0x8e, 0x30, 0x14, 0x32, 0x09, 0xea, 0xbd, 0x57, 0x4b, 0x6b, + 0x1e, 0xa3, 0x12, 0x01, 0xc2, 0x46, 0x65, 0x23, 0xe9, 0xac, 0x21, 0xb2, + 0xba, 0x60, 0xef, 0x6e, 0xa8, 0x32, 0x16, 0x1b, 0x69, 0x41, 0x23, 0x93, + 0xfb, 0x48, 0x7a, 0xb3, 0xe2, 0xab, 0x9b, 0x1a, 0x44, 0xce, 0x8a, 0x35, + 0xfc, 0x87, 0x3e, 0xe4, 0xa5, 0xec, 0xcf, 0x98, 0x04, 0x32, 0xc2, 0x32, + 0x4b, 0x48, 0x96, 0xed, 0x6a, 0xd1, 0xca, 0x3a, 0xf0, 0xb9, 0x32, 0x14, + 0xe3, 0x11, 0x23, 0x87, 0x09, 0x49, 0x59, 0x20, 0x6b, 0x3a, 0xb7, 0xc5, + 0xa7, 0xb3, 0x86, 0xd1, 0x87, 0x0d, 0xcf, 0x04, 0x92, 0x2a, 0x87, 0xa4, + 0x36, 0xc9, 0x03, 0x3f, 0x05, 0x2f, 0x39, 0xad, 0xfb, 0xbb, 0x25, 0x0c, + 0xbe, 0x23, 0xe4, 0x18, 0x1c, 0x24, 0x71, 0xd1, 0x6c, 0xba, 0x6a, 0xba, + 0xa6, 0xa7, 0x93, 0x08, 0x43, 0x92, 0x13, 0xfa, 0x02, 0xe0, 0x0e, 0xf6, + 0x26, 0x20, 0x11, 0x5c, 0x4f, 0x54, 0xc0, 0xb2, 0x0b, 0x5e, 0x79, 0x41, + 0xd9, 0x03, 0xd8, 0x4f, 0xb4, 0x60, 0xf7, 0x2c, 0xbd, 0xd8, 0xcd, 0xdd, + 0x19, 0xee, 0x46, 0x5f, 0x44, 0x2b, 0x57, 0x3f, 0xe3, 0x6b, 0x41, 0x4b, + 0x63, 0x19, 0x2b, 0x69, 0xb3, 0xe4, 0x14, 0xe0, 0xfc, 0x70, 0x6f, 0xc5, + 0x9e, 0xe2, 0x56, 0xfe, 0x62, 0xc7, 0x2b, 0x68, 0x43, 0x34, 0xb0, 0xf8, + 0x71, 0xd9, 0x0e, 0xbd, 0x20, 0x29, 0x83, 0xf1, 0xfe, 0xed, 0xec, 0xd5, + 0xeb, 0x12, 0xc9, 0x13, 0x9d, 0x1f, 0xb4, 0xce, 0x39, 0xd8, 0x15, 0xa9, + 0x6c, 0x24, 0x8d, 0x6f, 0xc5, 0x0a, 0x0c, 0xa2, 0x7e, 0x29, 0x67, 0xf1, + 0x3a, 0xf8, 0xd6, 0xd0, 0x3b, 0x28, 0x30, 0x94, 0x0c, 0x28, 0x77, 0x06, + 0x79, 0x3f, 0xfc, 0x67, 0xf2, 0x76, 0x8b, 0xb5, 0xc0, 0x4a, 0x1a, 0x79, + 0x9c, 0x04, 0xef, 0xc1, 0x61, 0x0e, 0xe9, 0xe0, 0xf3, 0x4a, 0x03, 0x00, + 0xf1, 0x4a, 0xa6, 0x66, 0x51, 0x53, 0x76, 0x35, 0x72, 0xc7, 0x59, 0x4b, + 0x34, 0x34, 0xc9, 0x1d, 0x91, 0x21, 0x1a, 0x5f, 0xb6, 0x81, 0x9e, 0x7a, + 0x62, 0x4a, 0xb8, 0x54, 0xb7, 0xdf, 0xe7, 0xd7, 0xb0, 0x5f, 0xa8, 0x1c, + 0x93, 0xae, 0x94, 0x3d, 0x82, 0x83, 0xe7, 0x9c, 0x50, 0x79, 0xa5, 0x03, + 0xf2, 0x3f, 0x19, 0xd7, 0x3f, 0x5f, 0x33, 0xf1, 0x5b, 0x65, 0x03, 0x4d, + 0x40, 0x88, 0x66, 0x67, 0x3f, 0x16, 0x8e, 0x7c, 0x4f, 0xd6, 0x15, 0xb3, + 0x1d, 0xed, 0x86, 0xc7, 0x2b, 0x82, 0x4e, 0x4e, 0xc1, 0x9b, 0x25, 0xc1, + 0xf5, 0x3f, 0x6e, 0xde, 0xbd, 0x23, 0x44, 0xa1, 0xb4, 0x84, 0xfb, 0x0a, + 0x95, 0x59, 0x57, 0x60, 0x73, 0x54, 0xcf, 0x4d, 0x2d, 0x5d, 0x8d, 0xc3, + 0xc8, 0x2a, 0x98, 0x7d, 0xb2, 0x59, 0x94, 0xe6, 0x90, 0x43, 0xed, 0xa2, + 0xc2, 0x13, 0x33, 0xf5, 0xee, 0x21, 0x72, 0x82, 0xaa, 0x33, 0xfc, 0x92, + 0x15, 0xc1, 0xf6, 0xef, 0x7d, 0xdf, 0x25, 0x8a, 0xbe, 0x36, 0xe8, 0x69, + 0x91, 0x42, 0x93, 0x4f, 0x1d, 0xc4, 0x92, 0xa5, 0xf3, 0xc1, 0x5d, 0x3d, + 0x1b, 0x36, 0xd7, 0xc4, 0x35, 0x7d, 0xe5, 0x02, 0x5b, 0xca, 0x8f, 0xcc, + 0x0c, 0x86, 0x7b, 0x20, 0xbc, 0xc2, 0xc1, 0x6f, 0x5a, 0x7c, 0xfe, 0x66, + 0x6d, 0xeb, 0x5e, 0xa5, 0xba, 0xbe, 0x26, 0xd3, 0xda, 0xe8, 0x51, 0x26, + 0x57, 0xac, 0xcf, 0x3f, 0x86, 0x1d, 0x38, 0x71, 0xa4, 0x35, 0x70, 0xe9, + 0x50, 0x02, 0x72, 0xc2, 0x22, 0x79, 0x78, 0xeb, 0x7d, 0xcf, 0xc7, 0x87, + 0xbc, 0x7e, 0xc7, 0x1c, 0x8d, 0x13, 0x44, 0xf3, 0xd0, 0x8a, 0x25, 0xf6, + 0xf7, 0x3c, 0xd9, 0x6f, 0xf2, 0x37, 0x9e, 0xad, 0x33, 0x43, 0x86, 0x40, + 0x4e, 0x90, 0x92, 0x33, 0x8c, 0x49, 0x90, 0x26, 0xf5, 0x25, 0x7d, 0xfe, + 0xf7, 0x16, 0x7e, 0x57, 0xef, 0xde, 0x6f, 0x2f, 0x93, 0xbe, 0x57, 0xda, + 0xae, 0x04, 0x35, 0x40, 0xcc, 0x4d, 0x72, 0x03, 0x2b, 0xb8, 0x1a, 0xfb, + 0xda, 0x1b, 0xb6, 0xff, 0x86, 0x6b, 0x76, 0xa6, 0xee, 0x71, 0xdd, 0xe8, + 0x10, 0xd8, 0x00, 0x94, 0x00, 0xa4, 0x6b, 0x00, 0x46, 0xd3, 0x8d, 0x16, + 0x64, 0x4c, 0x21, 0xd5, 0xc0, 0xca, 0x64, 0x44, 0xd2, 0xe6, 0xee, 0x4f, + 0xc4, 0xfa, 0x35, 0x45, 0x64, 0xc5, 0x51, 0xa8, 0x7c, 0x14, 0x77, 0xeb, + 0x97, 0x87, 0x0b, 0xae, 0x1d, 0x9c, 0x6e, 0x0d, 0xba, 0xb8, 0xa8, 0x8c, + 0xc8, 0x97, 0xd7, 0xb5, 0x43, 0xf3, 0x6b, 0x2d, 0x86, 0xdd, 0x01, 0xf6, + 0x07, 0xde, 0x7d, 0x7f, 0xb7, 0x3c, 0xe2, 0x30, 0x6b, 0x98, 0x99, 0xce, + 0xa6, 0xcb, 0x18, 0xa4, 0xa7, 0x3b, 0xc9, 0x62, 0xb9, 0x61, 0x3c, 0x87, + 0xe0, 0x7f, 0x85, 0x0f, 0xda, 0x1f, 0x83, 0x76, 0x6e, 0x9c, 0x53, 0x95, + 0x0c, 0x75, 0xe3, 0xc2, 0x90, 0x91, 0x96, 0x54, 0x87, 0x70, 0xcf, 0xb6, + 0x84, 0xe2, 0xbe, 0x31, 0xe5, 0x4a, 0x79, 0x00, 0x4a, 0x25, 0x06, 0x54, + 0x19, 0x39, 0x4d, 0x14, 0x28, 0xfd, 0x71, 0x91, 0xa2, 0x69, 0xee, 0x2b, + 0xa2, 0x88, 0x97, 0x37, 0x4f, 0x3e, 0xfa, 0xb7, 0x2a, 0x41, 0x55, 0x10, + 0xdf, 0xc4, 0x24, 0xfc, 0xde, 0xa9, 0x45, 0x74, 0xb5, 0xb9, 0xee, 0xef, + 0xd7, 0xb3, 0x8d, 0xc3, 0x41, 0x0c, 0xe8, 0x23, 0x5e, 0x41, 0x29, 0x83, + 0x23, 0x90, 0xc9, 0xf1, 0x54, 0x0e, 0xb8, 0xbf, 0x95, 0x5a, 0x28, 0x2c, + 0x5d, 0xd2, 0xd6, 0x50, 0x60, 0x5b, 0x1d, 0xbe, 0x64, 0x4d, 0x10, 0x28, + 0x92, 0x87, 0x88, 0x7d, 0x3f, 0x8d, 0xaf, 0xfc, 0x0f, 0x0c, 0x00, 0xa3, + 0x29, 0xd2, 0x10, 0x8b, 0xd9, 0x14, 0xb8, 0x3b, 0x81, 0x76, 0x64, 0xc2, + 0x97, 0xbe, 0x6f, 0x92, 0x61, 0x8b, 0xb7, 0x05, 0xbd, 0x3e, 0x6d, 0x54, + 0x50, 0x0c, 0x87, 0x95, 0x97, 0xf4, 0x49, 0x2d, 0x06, 0xac, 0xb8, 0xa9, + 0x31, 0xd3, 0x76, 0x92, 0x4a, 0xa3, 0xd9, 0x1f, 0xf4, 0x08, 0xd9, 0x29, + 0x49, 0xa9, 0xe3, 0x65, 0xee, 0x68, 0x60, 0x12, 0x97, 0xcc, 0xfc, 0xe1, + 0x5d, 0x26, 0xcc, 0xbe, 0xa8, 0x4e, 0xdd, 0x9a, 0x28, 0x21, 0xc3, 0x41, + 0x2f, 0x8a, 0x4e, 0x60, 0xb7, 0x03, 0x8c, 0x1f, 0x6f, 0x05, 0x5e, 0x99, + 0x73, 0x33, 0x43, 0xd2, 0xe7, 0x22, 0x75, 0xbc, 0x98, 0xe0, 0x34, 0x7e, + 0x2c, 0xb0, 0x0f, 0xa9, 0xee, 0xbc, 0x82, 0xa8, 0x1d, 0xa0, 0xd0, 0x95, + 0x5e, 0xa1, 0x33, 0x95, 0xf4, 0xdb, 0xe0, 0xf5, 0x3c, 0x1c, 0xa4, 0x5e, + 0x12, 0x08, 0x40, 0x7c, 0xc6, 0x12, 0x22, 0xb3, 0x6d, 0x81, 0xa2, 0x88, + 0xac, 0x97, 0x6f, 0x2a, 0xc9, 0xd6, 0xde, 0x6b, 0xb6, 0x02, 0x58, 0x18, + 0x40, 0xc7, 0x92, 0x06, 0x63, 0x26, 0x11, 0x98, 0xf1, 0x05, 0x50, 0x73, + 0x37, 0x4c, 0xcf, 0x8e, 0x77, 0xe6, 0x0f, 0x6e, 0x4f, 0x36, 0x5e, 0x7a, + 0x94, 0xd1, 0x13, 0xa5, 0xb1, 0x22, 0x0c, 0x20, 0xa1, 0x97, 0x8c, 0x7e, + 0xcb, 0xf9, 0xfa, 0x17, 0x4a, 0x4a, 0x40, 0x5e, 0xef, 0xe6, 0x48, 0x6c, + 0x3b, 0x18, 0xca, 0x2c, 0x67, 0x91, 0x09, 0x85, 0x6a, 0xcd, 0xdd, 0xdb, + 0xdb, 0x82, 0x07, 0xa7, 0x57, 0xa2, 0x42, 0x84, 0xf8, 0xe7, 0xd2, 0xbe, + 0x8b, 0x80, 0xe4, 0xda, 0x07, 0x4e, 0xcc, 0x11, 0xc9, 0xf6, 0x5f, 0x5e, + 0x22, 0xcd, 0xf3, 0x82, 0xa9, 0x6d, 0x7a, 0xc4, 0x26, 0x70, 0xec, 0x1d, + 0x6a, 0x79, 0x7f, 0x37, 0x28, 0x88, 0x1a, 0x53, 0x84, 0xf8, 0x00, 0xad, + 0x47, 0x7b, 0xfe, 0x19, 0xc9, 0xac, 0xab, 0x55, 0x76, 0xde, 0x4b, 0x6d, + 0x6f, 0x2e, 0x77, 0xca, 0xd7, 0x4e, 0x73, 0x18, 0xcd, 0xc3, 0x41, 0xac, + 0x39, 0x9a, 0x22, 0xac, 0xbf, 0xd2, 0xc0, 0xec, 0x4c, 0x54, 0xfb, 0xb9, + 0x76, 0x39, 0xd4, 0xcf, 0x63, 0xd6, 0xd6, 0x3c, 0xfe, 0x6f, 0xc0, 0x22, + 0xc0, 0x14, 0x36, 0xb8, 0x02, 0x19, 0x1e, 0x6a, 0x8b, 0xa3, 0x39, 0x78, + 0x1a, 0x82, 0x9e, 0x78, 0xf6, 0x58, 0xdb, 0x2e, 0x0a, 0x70, 0xc3, 0xa7, + 0x45, 0x41, 0x19, 0x8d, 0xca, 0x91, 0xed, 0x28, 0x12, 0x8c, 0xbb, 0x91, + 0xbd, 0xb3, 0xf0, 0x6a, 0xff, 0x79, 0x7f, 0xdf, 0xbc, 0x03, 0x6c, 0x4f, + 0x05, 0xe1, 0xaf, 0x39, 0x14, 0x37, 0x08, 0xbd, 0xd8, 0xa5, 0x3a, 0x0d, + 0xe2, 0x65, 0xdd, 0x9f, 0x80, 0x0c, 0xca, 0xd2, 0x19, 0x36, 0x1d, 0x84, + 0xfa, 0xa0, 0xa7, 0xb3, 0x26, 0x14, 0x4e, 0x53, 0xb5, 0x98, 0x15, 0x7b, + 0x53, 0x55, 0xc7, 0x55, 0x59, 0x65, 0xf7, 0xf9, 0xb5, 0x6b, 0x96, 0x59, + 0x7d, 0xb6, 0xf2, 0xab, 0x6f, 0x4e, 0x48, 0xa1, 0x30, 0x18, 0x01, 0x2a, + 0x3e, 0x20, 0x3a, 0xc6, 0x6d, 0x2a, 0x23, 0x0d, 0x17, 0x3d, 0x66, 0x30, + 0xe5, 0xe5, 0xac, 0x86, 0x84, 0x08, 0x01, 0x7a, 0xcc, 0xed, 0xf9, 0xfa, + 0x83, 0xcf, 0x09, 0x95, 0xdf, 0xf8, 0xed, 0x8c, 0x12, 0x7d, 0xf0, 0xcc, + 0x3e, 0x35, 0xfe, 0x10, 0x50, 0xed, 0x35, 0xcc, 0x8a, 0x13, 0x18, 0x67, + 0x22, 0x79, 0x04, 0xd8, 0x43, 0xd2, 0x38, 0xb3, 0xe8, 0x4c, 0x57, 0x6b, + 0xab, 0xfa, 0x95, 0x4e, 0x2c, 0x5e, 0x14, 0x0e, 0x7e, 0x06, 0xd6, 0x7d, + 0xcd, 0xe9, 0xb7, 0xbb, 0x8b, 0x76, 0x35, 0xe5, 0xf1, 0x87, 0x6c, 0x92, + 0x2c, 0x44, 0x8e, 0x59, 0xa3, 0x84, 0x27, 0x55, 0xaa, 0xe7, 0x8a, 0xda, + 0x3a, 0x08, 0xa3, 0x3c, 0x94, 0x69, 0x07, 0x98, 0xf9, 0x33, 0x0a, 0xe8, + 0xfe, 0xfd, 0x7e, 0x55, 0x0c, 0x5b, 0x81, 0xba, 0x56, 0xb4, 0x86, 0xd9, + 0xca, 0x80, 0xc8, 0x12, 0xe8, 0x83, 0x8d, 0x51, 0x04, 0xb9, 0xcf, 0xe8, + 0x0f, 0x34, 0x97, 0xe7, 0x3b, 0xab, 0xaf, 0x85, 0x7f, 0x6f, 0x38, 0x1e, + 0x7b, 0xd8, 0x54, 0x31, 0xa7, 0x82, 0x4f, 0x2c, 0xa0, 0xff, 0x18, 0x73, + 0x8f, 0xbc, 0x57, 0xfe, 0x8f, 0x7f, 0xe5, 0x34, 0xfa, 0x16, 0x59, 0xa5, + 0x36, 0x3c, 0x01, 0x22, 0x89, 0x33, 0x99, 0x73, 0x93, 0xf1, 0x6b, 0x99, + 0xe3, 0xaa, 0xab, 0xf0, 0x37, 0x21, 0x09, 0xb2, 0x5d, 0x5a, 0x61, 0x89, + 0xb9, 0x62, 0xaf, 0x90, 0x3f, 0x8a, 0x42, 0x9d, 0x6b, 0x41, 0x86, 0x00, + 0x51, 0x78, 0x28, 0x41, 0x37, 0x35, 0x84, 0x73, 0xc6, 0x1e, 0x42, 0x52, + 0x91, 0x4a, 0x93, 0xce, 0x78, 0x0a, 0x08, 0x51, 0xec, 0x92, 0x15, 0x48, + 0x58, 0xe4, 0x94, 0x48, 0xbb, 0x8b, 0xd7, 0xf6, 0x5b, 0xac, 0x69, 0x5f, + 0x9a, 0x9d, 0x6c, 0xd9, 0x8e, 0xef, 0xb0, 0x71, 0xf8, 0x1a, 0xc4, 0xa8, + 0x90, 0x93, 0xec, 0x1a, 0x66, 0xbd, 0x29, 0x0f, 0xa9, 0xce, 0xf1, 0x65, + 0xb2, 0xc7, 0xb4, 0x4a, 0x92, 0x3d, 0x94, 0xcb, 0xae, 0x15, 0xc8, 0x99, + 0x44, 0x6d, 0x82, 0x00, 0x89, 0x20, 0x96, 0x97, 0x38, 0xd0, 0x5b, 0x8e, + 0xfa, 0x6d, 0x6a, 0x40, 0xa0, 0x72, 0xb2, 0x92, 0x27, 0xb5, 0xbc, 0x34, + 0x50, 0xfa, 0x5f, 0x1a, 0xfa, 0xe5, 0xdd, 0x75, 0x76, 0xb7, 0x7c, 0x19, + 0xbb, 0xe2, 0x89, 0x31, 0xab, 0xc9, 0x59, 0x72, 0x19, 0x7f, 0x3e, 0x60, + 0x9c, 0x8d, 0x4d, 0xdf, 0x90, 0xea, 0xcb, 0x65, 0xca, 0x03, 0x96, 0x59, + 0x22, 0x32, 0x8c, 0xfc, 0x0c, 0x97, 0x1f, 0x39, 0x75, 0xff, 0xd1, 0x79, + 0x9b, 0xce, 0x89, 0xd2, 0xe5, 0x8d, 0x04, 0xf0, 0xe2, 0x59, 0x48, 0xd0, + 0xf9, 0xc3, 0xbe, 0xee, 0x58, 0x06, 0xb7, 0xe6, 0xd1, 0x80, 0x6b, 0x13, + 0xb4, 0x41, 0x11, 0x06, 0x51, 0x8c, 0x66, 0xf9, 0x7e, 0x34, 0x07, 0xc1, + 0x4f, 0xfe, 0x9b, 0x31, 0xdf, 0x1e, 0x62, 0x44, 0xe7, 0x26, 0xc6, 0xa2, + 0x28, 0x25, 0x22, 0x28, 0xf8, 0x8d, 0xad, 0x27, 0x0b, 0xc7, 0x78, 0x01, + 0x82, 0x8c, 0x15, 0xe7, 0x96, 0x55, 0x1c, 0x63, 0xf1, 0xcc, 0x5d, 0xba, + 0x89, 0xbf, 0x1a, 0xd9, 0x98, 0xaf, 0xa1, 0x87, 0x6c, 0x8c, 0x86, 0xf4, + 0x4f, 0xc7, 0xf3, 0x13, 0x7c, 0x94, 0x5d, 0x95, 0x46, 0xbf, 0xad, 0x0d, + 0x9d, 0x3c, 0xe8, 0x12, 0x88, 0x99, 0x92, 0x5a, 0x15, 0x62, 0x50, 0xdb, + 0x67, 0x7a, 0xf3, 0x53, 0x6d, 0x5a, 0xd2, 0x12, 0x2f, 0x2e, 0xd0, 0x50, + 0x22, 0x8c, 0x3f, 0x3b, 0x45, 0x54, 0x5c, 0x54, 0x35, 0xe7, 0xb3, 0x78, + 0xf5, 0x10, 0x53, 0x38, 0xd8, 0xa1, 0x5f, 0x28, 0xe4, 0xc1, 0xf0, 0x66, + 0x54, 0x56, 0xdb, 0xed, 0xff, 0xd3, 0x60, 0x08, 0x41, 0xb5, 0xa0, 0x41, + 0x8c, 0x51, 0x96, 0x60, 0x0e, 0x3a, 0x5a, 0xf0, 0x13, 0xbc, 0x49, 0xd5, + 0xf9, 0xd7, 0xcf, 0xcc, 0x04, 0x20, 0x97, 0x64, 0x1a, 0xe6, 0x36, 0x03, + 0xa1, 0x4b, 0xaf, 0x34, 0x1d, 0x06, 0x31, 0x80, 0x8c, 0x0a, 0x5c, 0xf0, + 0x93, 0x03, 0xde, 0xb3, 0xd9, 0xca, 0xda, 0x9e, 0xd8, 0x99, 0xce, 0x9b, + 0xef, 0x72, 0x29, 0x72, 0x79, 0xfc, 0x5f, 0x01, 0xd7, 0x36, 0x93, 0x03, + 0xda, 0xcf, 0xd3, 0x2f, 0xa0, 0xad, 0xb4, 0x3f, 0xc7, 0x30, 0x92, 0xf0, + 0x3b, 0x49, 0x5d, 0xa2, 0x5c, 0xd2, 0x39, 0x45, 0x2f, 0xe8, 0xad, 0xfc, + 0xa6, 0x3f, 0xed, 0x61, 0x3d, 0x0a, 0x24, 0x1c, 0x02, 0x78, 0x41, 0xda, + 0xff, 0x02, 0xaa, 0xcf, 0xb1, 0xf3, 0xa3, 0xae, 0x72, 0xff, 0xe2, 0x83, + 0xfa, 0x92, 0xf6, 0xe3, 0x45, 0x8a, 0xcb, 0x10, 0x74, 0x19, 0xdc, 0x97, + 0x8d, 0x02, 0x75, 0x17, 0x0b, 0x05, 0x2f, 0x59, 0x62, 0x48, 0x61, 0xca, + 0x18, 0x07, 0x65, 0x11, 0x8e, 0x63, 0xde, 0xd2, 0xaf, 0xb6, 0x66, 0xaf, + 0xd1, 0x1f, 0xaf, 0x63, 0xe4, 0xc3, 0x50, 0xf1, 0xd0, 0x04, 0xc6, 0x3b, + 0x66, 0xc9, 0xd6, 0x25, 0xe2, 0xe7, 0xfa, 0xdf, 0xca, 0x26, 0xde, 0x2f, + 0xdc, 0xf9, 0x33, 0x13, 0x72, 0xa8, 0x9e, 0x6c, 0x18, 0x09, 0xc1, 0x39, + 0x1a, 0x6e, 0x81, 0x80, 0x4f, 0x2c, 0xde, 0xb3, 0xae, 0xf2, 0xf6, 0xbe, + 0xa5, 0xed, 0x7d, 0x66, 0xac, 0xd0, 0x63, 0xba, 0x74, 0x9a, 0x4e, 0xe7, + 0x18, 0x71, 0x4d, 0xf0, 0xfb, 0x72, 0x49, 0x13, 0x72, 0x6b, 0x00, 0xf3, + 0x6e, 0xc8, 0x76, 0x3a, 0xf2, 0xba, 0x5b, 0xf8, 0xd8, 0x70, 0x8a, 0x1a, + 0x16, 0x7e, 0x43, 0x41, 0xde, 0x02, 0x50, 0x23, 0x70, 0xa5, 0x90, 0x2b, + 0x22, 0x97, 0xc1, 0xf2, 0xb9, 0xe9, 0xa9, 0x43, 0xb0, 0x43, 0xf9, 0x37, + 0x8c, 0x6a, 0x86, 0x49, 0x13, 0xca, 0x03, 0xc1, 0x32, 0x68, 0x1d, 0xd3, + 0x2e, 0x9b, 0x6f, 0x51, 0xb8, 0x46, 0x19, 0x51, 0x34, 0x64, 0xd0, 0x62, + 0x23, 0xf1, 0x7c, 0x46, 0x60, 0xdf, 0xca, 0xd6, 0x6a, 0xf3, 0x9e, 0x20, + 0x00, 0xd1, 0x94, 0xa8, 0x04, 0xb0, 0xf0, 0x41, 0xf3, 0xd6, 0xad, 0xb3, + 0x8a, 0x30, 0xb3, 0x4a, 0x53, 0x11, 0x8d, 0x1b, 0xd0, 0x0f, 0xc5, 0x97, + 0xd0, 0x20, 0x4f, 0x4b, 0x36, 0xe2, 0x06, 0x14, 0xd9, 0xa0, 0x18, 0x78, + 0x05, 0x02, 0x23, 0x09, 0xcf, 0xe3, 0xfa, 0x0a, 0x66, 0x71, 0xf6, 0xe0, + 0xf1, 0xc0, 0xc5, 0xa0, 0xa7, 0xff, 0xb5, 0xca, 0x89, 0x2d, 0x3c, 0x67, + 0x3f, 0x37, 0x80, 0xce, 0x59, 0x5f, 0x3f, 0xa8, 0x4b, 0xa6, 0xcd, 0x0a, + 0x65, 0x1a, 0x25, 0x13, 0x18, 0x5e, 0xb2, 0x7b, 0x9f, 0x35, 0xc6, 0xc6, + 0x45, 0x7b, 0x3b, 0x32, 0x8c, 0x04, 0xcc, 0x85, 0xe8, 0x68, 0xd2, 0x62, + 0xed, 0xe7, 0x57, 0x18, 0xad, 0xda, 0xe1, 0xd9, 0x89, 0x09, 0x1f, 0x06, + 0x79, 0x5e, 0x82, 0xcd, 0x80, 0x61, 0xb1, 0x0b, 0x8a, 0x24, 0x09, 0xc1, + 0xe9, 0x4a, 0xac, 0x8d, 0xe7, 0x55, 0xcc, 0x55, 0x07, 0x7d, 0xdb, 0xbd, + 0x8b, 0x29, 0x4e, 0x78, 0xfb, 0x46, 0x64, 0x94, 0xaf, 0xa1, 0x19, 0x6f, + 0xcd, 0xbe, 0x72, 0x60, 0xe3, 0x55, 0xe1, 0xa5, 0x61, 0x83, 0xbb, 0xce, + 0x8c, 0x62, 0xe3, 0x2e, 0x84, 0x1f, 0x3c, 0xdc, 0x03, 0xf4, 0x41, 0xab, + 0x68, 0x63, 0xe3, 0x94, 0x8e, 0x1c, 0xe4, 0x80, 0xc6, 0xfb, 0x10, 0xb9, + 0xaf, 0xee, 0xcd, 0xfe, 0xfa, 0x9c, 0x18, 0xd8, 0xbc, 0xd6, 0xe0, 0xa8, + 0xe1, 0xfe, 0x78, 0x82, 0x0e, 0xd7, 0x0e, 0x80, 0xc9, 0x1f, 0x11, 0x5e, + 0x57, 0x35, 0x41, 0xdb, 0x6c, 0x39, 0xdb, 0xda, 0xfc, 0xb3, 0x12, 0x26, + 0x05, 0x9a, 0x01, 0xd4, 0x86, 0x4e, 0x60, 0x6a, 0x69, 0x72, 0xf1, 0x15, + 0x9f, 0x63, 0xaf, 0x9b, 0xe7, 0x1c, 0xbc, 0x33, 0xde, 0x3b, 0x6a, 0x74, + 0x8a, 0x9e, 0x74, 0x5c, 0xa0, 0x64, 0xc3, 0x01, 0xf1, 0x04, 0xef, 0xaf, + 0x45, 0x52, 0x5b, 0xed, 0xb2, 0xf8, 0x80, 0xb9, 0xc6, 0x04, 0x40, 0x1e, + 0x0b, 0xd0, 0x0f, 0xcf, 0x73, 0x2a, 0x65, 0xd2, 0xee, 0xcc, 0xdb, 0xe6, + 0xe8, 0x84, 0xff, 0xda, 0xb1, 0x25, 0x3a, 0x14, 0x94, 0x67, 0x0e, 0x03, + 0xdc, 0x93, 0xfe, 0x50, 0x19, 0x60, 0x61, 0xa5, 0xf3, 0xd2, 0x2d, 0x8e, + 0x6b, 0xa2, 0xc5, 0x63, 0xa9, 0x99, 0x8e, 0xe7, 0x21, 0x5e, 0x08, 0x4c, + 0xe5, 0x22, 0x66, 0x88, 0xc0, 0x7c, 0x0e, 0x5d, 0x97, 0xb2, 0x15, 0x30, + 0xd5, 0xee, 0xd4, 0x25, 0x22, 0x82, 0x28, 0x64, 0xc9, 0x96, 0x12, 0x46, + 0x53, 0xcb, 0xa1, 0xb7, 0x38, 0xe2, 0x8e, 0x52, 0x5a, 0x03, 0x1e, 0xf4, + 0x4a, 0xb2, 0x8e, 0x77, 0xfa, 0x6b, 0xe6, 0x8c, 0x12, 0xc3, 0x4d, 0x12, + 0x87, 0xc1, 0x78, 0x29, 0xfa, 0x86, 0xd9, 0xe0, 0xbc, 0x10, 0x87, 0xc6, + 0x42, 0x13, 0x8d, 0x19, 0x0f, 0x02, 0x4f, 0x56, 0xac, 0xb3, 0xce, 0x6a, + 0x84, 0xb9, 0x39, 0x59, 0x26, 0x23, 0xe0, 0xcf, 0x72, 0x2e, 0xb9, 0xa2, + 0xda, 0x32, 0x18, 0x77, 0x12, 0xc9, 0xc1, 0x95, 0x80, 0x93, 0x93, 0xac, + 0x2d, 0xdf, 0x4c, 0xc2, 0x53, 0x0d, 0xa3, 0x2c, 0xac, 0x3e, 0xfe, 0x72, + 0xdb, 0xf6, 0x20, 0x80, 0x21, 0xbd, 0x98, 0x71, 0x5d, 0x21, 0xf3, 0x45, + 0x64, 0x71, 0x0b, 0xb0, 0x33, 0x40, 0xa3, 0x33, 0x57, 0xe5, 0x96, 0x87, + 0xc4, 0xec, 0x80, 0x90, 0x1d, 0xfb, 0x31, 0x73, 0x5d, 0x7f, 0x70, 0xb3, + 0x61, 0xa4, 0x8b, 0x3c, 0xc8, 0x44, 0x4d, 0x09, 0xb2, 0x32, 0x74, 0x3e, + 0xa0, 0xaf, 0xd7, 0x66, 0xe8, 0xd0, 0xb1, 0xc3, 0xa8, 0x81, 0xbc, 0x70, + 0xe8, 0x6e, 0x68, 0x89, 0x14, 0xaf, 0x8f, 0x4b, 0x60, 0xae, 0x6a, 0xcd, + 0xa8, 0xbc, 0xd7, 0xbd, 0x35, 0x15, 0xbc, 0xcb, 0x9c, 0x84, 0x27, 0x86, + 0x69, 0xe5, 0x09, 0x21, 0xf6, 0xa4, 0xd9, 0xaf, 0x33, 0x48, 0x84, 0x93, + 0x91, 0x24, 0x96, 0xe5, 0x4c, 0x78, 0xee, 0xec, 0x79, 0x5b, 0x0a, 0x3c, + 0xa8, 0x62, 0xe9, 0xa9, 0x68, 0x21, 0x2c, 0x6a, 0x48, 0x4a, 0x17, 0x19, + 0x60, 0x65, 0xa5, 0x0c, 0x97, 0xd4, 0xc9, 0xde, 0x56, 0xe9, 0xf0, 0xf7, + 0x56, 0x57, 0x6c, 0x8e, 0x3e, 0xf6, 0x52, 0xe1, 0x86, 0x42, 0x80, 0x01, + 0x80, 0xa1, 0x28, 0x64, 0x32, 0x8f, 0x80, 0xf3, 0x7d, 0xa2, 0x97, 0x84, + 0x82, 0xe7, 0x91, 0x41, 0x92, 0x08, 0xe6, 0x02, 0x69, 0x37, 0xfe, 0xcd, + 0xa2, 0x85, 0xfa, 0xb7, 0x64, 0xab, 0x78, 0x95, 0xb4, 0x85, 0x44, 0x28, + 0xa5, 0xe5, 0xb8, 0xc0, 0x11, 0xac, 0x21, 0x5a, 0xd3, 0x98, 0x5e, 0x8a, + 0x08, 0x60, 0x14, 0x0d, 0x53, 0xde, 0xce, 0x06, 0xd4, 0x37, 0xb1, 0x22, + 0xe2, 0x68, 0x34, 0xc7, 0xc5, 0xa3, 0xf5, 0x1b, 0xce, 0xed, 0x45, 0x24, + 0xd9, 0x4a, 0x08, 0xdd, 0x65, 0x07, 0x8b, 0xbf, 0x81, 0xda, 0x3b, 0x31, + 0xdc, 0xb1, 0x7b, 0x3d, 0x8a, 0xb4, 0x74, 0x6e, 0xc8, 0xd4, 0x46, 0xd9, + 0xb6, 0x97, 0x45, 0x3b, 0xa0, 0x24, 0x88, 0xc3, 0xc4, 0x1d, 0x58, 0xa5, + 0xa7, 0xf0, 0x7c, 0xae, 0xd6, 0x77, 0x47, 0x7c, 0xe2, 0xb0, 0x18, 0xef, + 0x2c, 0x35, 0x82, 0x8c, 0x89, 0x93, 0x76, 0x40, 0x52, 0xbc, 0xf1, 0xf9, + 0x7f, 0x77, 0x03, 0x74, 0xdc, 0x12, 0xfd, 0x74, 0x2e, 0x16, 0xe6, 0x19, + 0xd5, 0xe0, 0x8b, 0x06, 0x4b, 0x99, 0x1f, 0x68, 0x3c, 0xd1, 0xbe, 0xe8, + 0x9c, 0xf7, 0xb5, 0x9d, 0x17, 0x1f, 0xaf, 0x47, 0xc5, 0x38, 0x92, 0x2c, + 0x1b, 0x54, 0x6f, 0x2b, 0x1d, 0x09, 0xeb, 0x4d, 0x89, 0x8e, 0x32, 0xe7, + 0x59, 0x84, 0x91, 0xfd, 0x57, 0xd9, 0x79, 0x4f, 0x8a, 0xdb, 0xc3, 0x3a, + 0x09, 0xe0, 0x07, 0x36, 0xdd, 0x93, 0x94, 0x1e, 0x69, 0x6b, 0xe1, 0x31, + 0xae, 0x72, 0xed, 0x66, 0x80, 0x06, 0x1b, 0x4a, 0x45, 0xdc, 0xbc, 0xdc, + 0x93, 0x44, 0xce, 0xf4, 0x01, 0xdc, 0x08, 0x73, 0x02, 0x32, 0xa3, 0xf0, + 0x61, 0x9a, 0x50, 0x04, 0x3b, 0x28, 0xb3, 0x9a, 0xbf, 0xe7, 0x5c, 0x5a, + 0x99, 0x4b, 0xf7, 0xff, 0x3b, 0x76, 0x7b, 0x7a, 0xcc, 0xcd, 0x49, 0xdf, + 0x49, 0x48, 0xcc, 0x99, 0x34, 0x14, 0x07, 0xda, 0x06, 0xfb, 0x9d, 0x97, + 0xc4, 0xd9, 0x2e, 0x25, 0x34, 0x63, 0x0c, 0x97, 0xce, 0xfa, 0x3b, 0xcf, + 0x87, 0x18, 0xdd, 0xf7, 0x3f, 0x8b, 0xe1, 0x00, 0xcb, 0x61, 0x03, 0x2c, + 0x38, 0xbc, 0x31, 0xdc, 0x80, 0xc4, 0x3f, 0xd5, 0x8c, 0x64, 0xe1, 0x09, + 0x4e, 0x86, 0x59, 0xec, 0x85, 0x55, 0xf0, 0x3a, 0xa7, 0xae, 0xae, 0x02, + 0xd1, 0x9c, 0x00, 0xc9, 0x20, 0x3e, 0x3c, 0x3f, 0x6e, 0x2e, 0xd9, 0x64, + 0xb9, 0x0c, 0x82, 0x32, 0x81, 0xe7, 0x46, 0xf5, 0x72, 0xb5, 0x70, 0x5c, + 0x4c, 0xaf, 0xda, 0xfc, 0x29, 0x07, 0x12, 0x3b, 0x09, 0xde, 0xd3, 0x29, + 0x06, 0xa0, 0x66, 0x94, 0x72, 0xbe, 0xa0, 0x3f, 0xc3, 0xef, 0x4f, 0xf2, + 0x77, 0x21, 0x37, 0x58, 0xd9, 0x62, 0x25, 0x08, 0x41, 0xf4, 0x47, 0xc4, + 0xcb, 0xcb, 0xac, 0x63, 0x14, 0x12, 0xb6, 0xe8, 0xfa, 0xb7, 0x12, 0x6d, + 0x41, 0xd1, 0x1c, 0x8c, 0x3b, 0x3d, 0x10, 0x20, 0xcb, 0xcb, 0x9c, 0xab, + 0x1a, 0x27, 0xe1, 0x71, 0xce, 0x95, 0x67, 0x02, 0xe4, 0x8b, 0x90, 0xe2, + 0x13, 0xb3, 0xb3, 0x0d, 0x33, 0xb3, 0xb3, 0x96, 0x7e, 0xb3, 0xb6, 0x89, + 0x44, 0x94, 0x0a, 0x0c, 0xc0, 0xd6, 0xc3, 0xe9, 0x14, 0x19, 0x0a, 0xfb, + 0xd0, 0x9d, 0x0a, 0x39, 0x61, 0xbe, 0xbb, 0x5f, 0xa4, 0xd4, 0xf8, 0xc4, + 0x7c, 0x91, 0x18, 0xe8, 0x84, 0x46, 0x1f, 0x25, 0x29, 0x9c, 0xbb, 0xd4, + 0x41, 0x9e, 0xdb, 0x04, 0x3b, 0xef, 0x46, 0x72, 0xc6, 0xdb, 0x40, 0x25, + 0x92, 0x7c, 0x34, 0x68, 0x2b, 0x43, 0xbd, 0x4b, 0xfd, 0x8c, 0x51, 0xa2, + 0xcd, 0x91, 0x3e, 0x7b, 0xfe, 0x67, 0xb7, 0x93, 0x5b, 0x62, 0x43, 0x25, + 0x7f, 0xd2, 0x98, 0xd5, 0xfd, 0x63, 0x21, 0x2a, 0x18, 0x0d, 0x0a, 0x3d, + 0xc6, 0x78, 0xe5, 0xd2, 0x92, 0xb1, 0x2a, 0x11, 0xd0, 0x9b, 0xa0, 0x4a, + 0x54, 0x1a, 0x68, 0x04, 0xca, 0x18, 0x7a, 0xc0, 0x4b, 0xeb, 0x76, 0xc9, + 0x81, 0x8e, 0x32, 0xb4, 0x5b, 0x50, 0xa0, 0x94, 0xe6, 0x80, 0xc9, 0x19, + 0xf8, 0x26, 0x57, 0xef, 0xf7, 0x29, 0x71, 0x17, 0xfb, 0xeb, 0x85, 0xa8, + 0xa8, 0x41, 0x5b, 0x26, 0x48, 0x51, 0x83, 0x4c, 0x89, 0x1b, 0xa1, 0x8e, + 0x91, 0xf1, 0xe9, 0x8c, 0xff, 0xba, 0xee, 0xd7, 0x6b, 0x0f, 0xf5, 0x39, + 0x60, 0x69, 0xda, 0xbc, 0x76, 0xd8, 0x15, 0x79, 0x9a, 0x79, 0x59, 0x54, + 0xa5, 0x46, 0xb2, 0x65, 0x7e, 0x34, 0xd4, 0xc4, 0xf6, 0xc7, 0x98, 0x26, + 0x39, 0x9c, 0x30, 0x18, 0xc0, 0x04, 0xac, 0xba, 0xca, 0x5f, 0xcd, 0x7b, + 0x03, 0xd7, 0x0d, 0xa0, 0x71, 0xdd, 0x90, 0x86, 0x85, 0x5e, 0x44, 0xfc, + 0xe3, 0x41, 0xf7, 0xc2, 0xd6, 0x6b, 0xee, 0xa5, 0x6b, 0x2f, 0x72, 0x18, + 0xbb, 0xc8, 0x48, 0xa0, 0x26, 0x48, 0x9b, 0xca, 0xac, 0x6d, 0x73, 0x5a, + 0x5d, 0x3d, 0xef, 0x97, 0xdc, 0x83, 0x4d, 0x47, 0x40, 0xee, 0x60, 0x85, + 0x61, 0xf6, 0x23, 0x2c, 0x80, 0x7c, 0x45, 0x5b, 0x49, 0x91, 0x43, 0x0c, + 0x50, 0x6c, 0xa2, 0x19, 0x0c, 0x03, 0x1f, 0xe7, 0x85, 0x15, 0x7f, 0x75, + 0xb2, 0xf2, 0x64, 0x05, 0x1a, 0x28, 0xbc, 0xa9, 0x21, 0x97, 0x42, 0x86, + 0x5e, 0x10, 0x01, 0xb9, 0x3c, 0x91, 0xfb, 0x95, 0x32, 0xde, 0x1a, 0xdd, + 0x32, 0x09, 0x81, 0x94, 0x9d, 0xda, 0x12, 0xed, 0x5a, 0x53, 0x4a, 0xc8, + 0xa2, 0xeb, 0xa8, 0x41, 0xcd, 0xaf, 0xfc, 0xe3, 0xb5, 0x89, 0x53, 0x90, + 0x30, 0x22, 0x59, 0x0a, 0x00, 0xcb, 0x01, 0xf0, 0x49, 0xb3, 0x5b, 0x7f, + 0x61, 0xc3, 0xc8, 0xee, 0xd9, 0x6d, 0xc8, 0xe1, 0x01, 0xa6, 0xe7, 0x26, + 0x84, 0xe8, 0xc8, 0x9c, 0x20, 0x3e, 0x18, 0x2a, 0xb7, 0x15, 0xd6, 0x66, + 0xb1, 0x51, 0x09, 0x20, 0xc1, 0x1a, 0x8b, 0x2d, 0x01, 0xdc, 0xac, 0xf6, + 0x1f, 0x6a, 0x74, 0x58, 0x8f, 0x30, 0x61, 0x46, 0x0e, 0x04, 0x91, 0x73, + 0x29, 0x08, 0x51, 0x0f, 0x92, 0x6f, 0x03, 0xaa, 0x88, 0x1d, 0x95, 0x57, + 0x6e, 0xec, 0xc2, 0xf8, 0xae, 0x43, 0x50, 0x14, 0xa4, 0x18, 0x19, 0x50, + 0x19, 0x08, 0x7c, 0x78, 0xde, 0xe7, 0xb3, 0x5e, 0x5c, 0x17, 0xde, 0xc0, + 0x66, 0x90, 0xed, 0x65, 0xaa, 0x00, 0x4e, 0x85, 0x3c, 0x6c, 0x79, 0x20, + 0x0d, 0x0f, 0xaa, 0x95, 0xa8, 0x5e, 0xb7, 0x8f, 0xbf, 0x3c, 0x07, 0x12, + 0x11, 0x91, 0xbd, 0xa9, 0x1f, 0x31, 0xf3, 0xd7, 0x8a, 0x6c, 0xd2, 0xa9, + 0xbd, 0x7d, 0xd1, 0x63, 0x39, 0x63, 0x64, 0x85, 0xe1, 0x94, 0xba, 0xb1, + 0xb5, 0xc0, 0xf4, 0xe2, 0xf7, 0x7b, 0xab, 0xc3, 0x99, 0xee, 0x43, 0x23, + 0x18, 0x80, 0x18, 0x50, 0xc3, 0xc0, 0x8e, 0x42, 0xf9, 0xef, 0xe5, 0xad, + 0xe2, 0x6d, 0xd8, 0xb6, 0x2e, 0xde, 0x45, 0xa3, 0x21, 0x87, 0x97, 0x70, + 0x33, 0xcb, 0xfa, 0xe6, 0x45, 0x7b, 0x46, 0x89, 0xf9, 0xa1, 0x2b, 0x09, + 0x65, 0x28, 0x87, 0x9b, 0xb8, 0x79, 0x04, 0x69, 0x01, 0xda, 0xbd, 0x17, + 0x7c, 0x84, 0x94, 0x23, 0x4b, 0x0a, 0x57, 0xe3, 0xf3, 0xed, 0x5d, 0x27, + 0xcc, 0x12, 0xe4, 0x07, 0xd3, 0x01, 0x46, 0x49, 0x43, 0x26, 0xf4, 0x70, + 0x85, 0x6b, 0x65, 0x9f, 0xaa, 0xa4, 0x88, 0x66, 0x20, 0x88, 0x44, 0x03, + 0x4c, 0x32, 0xa0, 0xa2, 0x5c, 0x8f, 0xb4, 0x0d, 0x90, 0x1f, 0x39, 0x41, + 0xfb, 0x48, 0x5c, 0x04, 0x70, 0xd9, 0x47, 0xec, 0x43, 0xae, 0x77, 0x33, + 0x84, 0xda, 0x48, 0xa6, 0xbd, 0xed, 0x92, 0xca, 0x38, 0x60, 0x28, 0x80, + 0x18, 0xd1, 0xa1, 0xd9, 0x46, 0xc7, 0xae, 0x2e, 0xcf, 0xd6, 0x4f, 0xb3, + 0x3c, 0xb7, 0xd0, 0x01, 0x03, 0x31, 0x97, 0xda, 0xd5, 0xee, 0xd7, 0x26, + 0x06, 0x12, 0xa5, 0xe8, 0x2f, 0xdf, 0x80, 0x18, 0xe2, 0x59, 0x64, 0xe1, + 0x20, 0x10, 0xc8, 0x97, 0x92, 0x4b, 0xad, 0x54, 0x02, 0x12, 0xc3, 0xcd, + 0x8a, 0x33, 0xc7, 0xf4, 0xfd, 0x4d, 0xeb, 0x6d, 0x4c, 0xa3, 0x34, 0x00, + 0xf8, 0xa8, 0xc8, 0x21, 0x90, 0x43, 0x3f, 0xae, 0x7b, 0xaf, 0x37, 0x7a, + 0x72, 0xc3, 0x47, 0xce, 0xbb, 0xbf, 0xd0, 0x80, 0x6e, 0x00, 0xd6, 0x71, + 0x42, 0x92, 0x12, 0x9c, 0x62, 0x09, 0xc7, 0x3f, 0x62, 0x36, 0xd2, 0xfe, + 0xff, 0xba, 0xb5, 0x08, 0x27, 0x88, 0x26, 0x86, 0x3b, 0xd4, 0x34, 0x8c, + 0x08, 0xf8, 0x24, 0xb3, 0x46, 0x1b, 0x60, 0xf3, 0x86, 0x32, 0x90, 0x47, + 0xb6, 0x92, 0x1f, 0x8b, 0xb6, 0xa1, 0x7a, 0x4e, 0x67, 0x04, 0x86, 0x51, + 0xfa, 0x96, 0xb4, 0xba, 0xe3, 0xe3, 0x6a, 0x97, 0x0a, 0x02, 0x30, 0x0a, + 0xd5, 0x08, 0x35, 0x42, 0x67, 0x00, 0xac, 0xa0, 0xd6, 0x6a, 0xcc, 0x52, + 0xa3, 0xe5, 0xec, 0xb9, 0x9c, 0xcb, 0xce, 0x53, 0xca, 0x63, 0x97, 0x95, + 0x91, 0x16, 0x6c, 0x65, 0x16, 0xcb, 0x6c, 0x3c, 0xa0, 0xa3, 0x34, 0x42, + 0x29, 0x5e, 0x01, 0x5e, 0xf4, 0xd2, 0xe1, 0x32, 0x9e, 0x42, 0x12, 0x3f, + 0x72, 0x3a, 0x8d, 0xe8, 0xab, 0x8b, 0x0a, 0x86, 0x29, 0x99, 0x00, 0xe3, + 0x38, 0x9a, 0x34, 0x0c, 0xd0, 0xcb, 0x4a, 0x21, 0x11, 0xdc, 0x07, 0xad, + 0x53, 0xe5, 0xb2, 0x30, 0x69, 0x13, 0x92, 0xc9, 0x64, 0xb3, 0x00, 0x35, + 0x33, 0x4d, 0xc0, 0xca, 0x64, 0x3e, 0x08, 0x03, 0x3a, 0x38, 0xde, 0x0d, + 0xd2, 0x96, 0xb7, 0xb7, 0xab, 0xc4, 0x9a, 0x26, 0x74, 0x27, 0xe9, 0xf1, + 0x0a, 0xc3, 0x6f, 0x5a, 0x79, 0xd5, 0xf2, 0x92, 0xd5, 0x33, 0x30, 0x40, + 0x41, 0x06, 0x81, 0x8d, 0xe1, 0xde, 0x9c, 0x8a, 0xbd, 0xb4, 0xb5, 0xc5, + 0x82, 0x8b, 0xe3, 0xc3, 0xf3, 0x03, 0xd3, 0x84, 0xa2, 0xcc, 0x03, 0xed, + 0x67, 0xe6, 0x20, 0x32, 0x94, 0x92, 0x18, 0x0e, 0x44, 0x61, 0x52, 0xaf, + 0xb8, 0x51, 0x7c, 0xac, 0x20, 0x67, 0x2c, 0x3b, 0x90, 0xe1, 0x90, 0x99, + 0x43, 0x24, 0x3d, 0x3f, 0x68, 0xad, 0xda, 0x91, 0x3e, 0x30, 0xc5, 0x2f, + 0xf1, 0x50, 0x71, 0x45, 0xf0, 0x09, 0x4e, 0x34, 0xd2, 0x7d, 0x94, 0xb3, + 0xe9, 0xbd, 0x44, 0x0d, 0x34, 0x18, 0x4f, 0xc4, 0x5c, 0xc3, 0x04, 0x3c, + 0x9b, 0x08, 0xc5, 0x2d, 0x65, 0x23, 0x40, 0x64, 0xa5, 0xf4, 0x77, 0xfb, + 0xbf, 0xca, 0x23, 0x89, 0x8d, 0x03, 0x4b, 0x40, 0xf6, 0xb4, 0x49, 0x39, + 0x24, 0x7c, 0x4f, 0x79, 0xce, 0x13, 0x0b, 0x38, 0xc9, 0xbf, 0xc5, 0x94, + 0x64, 0x07, 0xd0, 0x2d, 0xed, 0xe0, 0x30, 0x14, 0x68, 0xfd, 0x3f, 0x08, + 0x42, 0x62, 0xa3, 0xd3, 0x1c, 0x88, 0x58, 0xe8, 0x8c, 0x9b, 0x22, 0x3c, + 0x41, 0xa6, 0xa5, 0x7d, 0x1d, 0xbf, 0xc0, 0xf9, 0xf9, 0xbe, 0x78, 0x67, + 0x0a, 0x2f, 0xbf, 0x39, 0xd4, 0xb2, 0x6f, 0x07, 0xcc, 0x09, 0xe5, 0x7d, + 0x54, 0xfc, 0xbb, 0x30, 0xc6, 0x22, 0x66, 0x84, 0xf2, 0xb4, 0x8c, 0xa1, + 0x74, 0xaf, 0x04, 0x8e, 0x73, 0x71, 0x1a, 0xf0, 0x67, 0xad, 0x8a, 0x18, + 0xd0, 0xf1, 0x63, 0x95, 0xf4, 0xc7, 0xc4, 0x7e, 0x75, 0xb6, 0x12, 0xd8, + 0xd4, 0xe7, 0x03, 0x11, 0xb2, 0x1e, 0x70, 0x8f, 0xb2, 0xbf, 0x18, 0x7b, + 0xf8, 0x98, 0x97, 0xe1, 0xe7, 0x08, 0x0c, 0x6f, 0x55, 0x19, 0x94, 0xfa, + 0xd5, 0x89, 0xb7, 0xdc, 0xf1, 0x2b, 0xc6, 0x4b, 0x32, 0x8c, 0x26, 0x26, + 0x96, 0x72, 0x4d, 0x55, 0x3d, 0xba, 0x6e, 0xbc, 0xb6, 0x98, 0xe1, 0x9c, + 0x6e, 0x18, 0x12, 0x84, 0xf1, 0x8d, 0x14, 0x0e, 0x5e, 0x01, 0xe2, 0x74, + 0xf7, 0x4a, 0x55, 0xff, 0xb7, 0x3c, 0xe7, 0xfe, 0xd2, 0x97, 0xce, 0xed, + 0xc6, 0xc6, 0xec, 0xfd, 0x89, 0xe9, 0x52, 0x26, 0x8b, 0x82, 0xfa, 0x44, + 0x8c, 0x21, 0xbc, 0xa5, 0x79, 0x76, 0x5b, 0xb7, 0x93, 0x70, 0x56, 0xe0, + 0x00, 0x48, 0x84, 0xee, 0x09, 0x17, 0x61, 0x46, 0x90, 0x44, 0x07, 0x32, + 0x9c, 0xc7, 0x71, 0x56, 0x64, 0x67, 0x46, 0x3e, 0xbf, 0x93, 0xdf, 0x4e, + 0xa6, 0x2c, 0x0a, 0x05, 0x0a, 0x6b, 0x15, 0x0f, 0xe9, 0x0d, 0xb6, 0xf0, + 0xce, 0x0a, 0x32, 0xa1, 0x59, 0x11, 0xe3, 0xa6, 0xac, 0xe1, 0xb4, 0xc4, + 0xbf, 0xcc, 0xac, 0x9d, 0xed, 0xe7, 0x34, 0x49, 0xf1, 0x26, 0xad, 0x58, + 0xdb, 0xf1, 0xb5, 0x00, 0xa1, 0x05, 0xed, 0xb2, 0xe0, 0xc2, 0x96, 0x82, + 0x05, 0xa4, 0x95, 0x59, 0x76, 0xbf, 0xe6, 0x96, 0xb8, 0xd0, 0x29, 0xe5, + 0xad, 0x2b, 0x7b, 0x73, 0xb3, 0x2d, 0x01, 0x20, 0x4d, 0x12, 0x72, 0xdc, + 0x92, 0x5d, 0x1c, 0x24, 0x2e, 0xb8, 0x33, 0x70, 0xe9, 0x41, 0x56, 0xaf, + 0x9f, 0xeb, 0x1a, 0xa5, 0xae, 0x1a, 0x74, 0x68, 0x04, 0x24, 0xc0, 0x01, + 0x38, 0x4e, 0xc8, 0xc9, 0x9f, 0x01, 0xc3, 0x39, 0xc3, 0xb5, 0x0c, 0xa3, + 0xe2, 0xaa, 0x6e, 0xf0, 0x69, 0x07, 0xda, 0x17, 0xbf, 0x6a, 0xcd, 0x92, + 0x26, 0x87, 0xd7, 0x87, 0xae, 0x0a, 0x3d, 0xf5, 0x87, 0xfc, 0x3b, 0x9c, + 0xb1, 0xf2, 0xe8, 0x90, 0x12, 0x92, 0x27, 0xb9, 0x40, 0xea, 0xc5, 0x63, + 0xab, 0xfe, 0xf3, 0xbe, 0x62, 0x07, 0xa2, 0x95, 0xf3, 0x47, 0x72, 0x1b, + 0xd9, 0xaf, 0xd2, 0x2c, 0x51, 0x28, 0x8c, 0x9f, 0xcc, 0xe4, 0xfb, 0x83, + 0x33, 0xdd, 0xba, 0xbe, 0xb4, 0xbb, 0x33, 0xf7, 0x4d, 0x8c, 0xe0, 0xb6, + 0x41, 0xc9, 0x13, 0xc3, 0x72, 0xad, 0xd1, 0xd1, 0xed, 0x58, 0x16, 0xf9, + 0xff, 0xde, 0xf5, 0x0b, 0xfb, 0x38, 0xbb, 0x1b, 0x8c, 0x1e, 0xdf, 0x9a, + 0x5f, 0xd5, 0x8d, 0xb9, 0x8c, 0x60, 0x1c, 0xbc, 0xc2, 0x58, 0x44, 0x23, + 0x94, 0x67, 0xf4, 0x1d, 0x27, 0x10, 0x46, 0xfb, 0x75, 0xa0, 0xc3, 0x22, + 0x6d, 0x45, 0xc1, 0x94, 0xa6, 0xc5, 0x08, 0x7e, 0x30, 0x56, 0x7d, 0xb6, + 0x59, 0xcd, 0x35, 0xfe, 0xcf, 0xfc, 0xf0, 0x1a, 0xe7, 0xb8, 0xf3, 0x04, + 0x0c, 0xa7, 0x05, 0x09, 0xe0, 0x15, 0x86, 0x4e, 0x56, 0xce, 0xff, 0x8b, + 0x6e, 0xed, 0x94, 0x26, 0x79, 0xa2, 0x12, 0xe4, 0x25, 0x38, 0x12, 0xce, + 0xe7, 0x92, 0xfa, 0x6a, 0xaa, 0xb6, 0xa8, 0x84, 0x71, 0xd9, 0x9b, 0x72, + 0xd9, 0x14, 0xb1, 0x66, 0x85, 0x09, 0x91, 0x29, 0xe5, 0xc9, 0x17, 0xa0, + 0x09, 0xfa, 0x20, 0xa5, 0xc3, 0x66, 0x2e, 0x3b, 0x53, 0x59, 0xd1, 0x0c, + 0x40, 0x5c, 0xd2, 0xf7, 0x95, 0x46, 0x53, 0x01, 0x10, 0x4e, 0x53, 0xfd, + 0x46, 0xb7, 0x82, 0x6b, 0xe8, 0xea, 0x52, 0xc6, 0x9b, 0xe5, 0xa5, 0x88, + 0x2a, 0xf0, 0x28, 0x23, 0x51, 0x99, 0x77, 0x00, 0x46, 0x77, 0x3c, 0x9a, + 0xfa, 0x51, 0x28, 0xad, 0x8d, 0x13, 0x0d, 0xe9, 0x41, 0x1a, 0x12, 0x43, + 0xee, 0x12, 0x28, 0xbb, 0x8e, 0xf6, 0x0e, 0x18, 0xc0, 0x57, 0x6f, 0x2d, + 0x28, 0x32, 0x33, 0xf2, 0xa4, 0x06, 0xf2, 0x7b, 0xa3, 0xf1, 0x6b, 0x06, + 0xcf, 0x23, 0x81, 0xe7, 0x90, 0xc5, 0xa8, 0xa9, 0x27, 0x64, 0x97, 0x44, + 0xba, 0x07, 0x1a, 0x52, 0xc9, 0xa2, 0x97, 0x56, 0x19, 0xca, 0x2a, 0x7e, + 0xd8, 0x92, 0x79, 0xbd, 0x7a, 0x0d, 0xf9, 0x61, 0x80, 0x9b, 0x83, 0x31, + 0xa6, 0xa6, 0xe8, 0x32, 0x38, 0x40, 0x99, 0x81, 0x75, 0xd5, 0xa5, 0xd8, + 0xbd, 0x0c, 0x71, 0xb8, 0x1c, 0xe5, 0x65, 0x99, 0x50, 0x09, 0x0c, 0xb3, + 0xe2, 0x7b, 0x5a, 0xbc, 0x1c, 0x0d, 0x21, 0xa9, 0xc8, 0x33, 0x01, 0x2c, + 0x64, 0x66, 0x6f, 0x49, 0xf4, 0xf8, 0xb7, 0x5a, 0x5f, 0xe8, 0x86, 0x10, + 0xcc, 0x01, 0x08, 0xc6, 0x9e, 0x8b, 0xc8, 0x91, 0x47, 0x72, 0x22, 0x55, + 0x83, 0xfb, 0xa5, 0xa7, 0x50, 0xd3, 0x4d, 0xcb, 0xd2, 0xa5, 0x96, 0x60, + 0x35, 0x1e, 0x52, 0x00, 0xa3, 0x39, 0x23, 0xf6, 0x4c, 0x6d, 0x4b, 0x14, + 0x96, 0xf9, 0xa9, 0x43, 0xd9, 0x80, 0x27, 0x6a, 0xf3, 0xa2, 0xcf, 0xc3, + 0x19, 0x19, 0x4f, 0x2a, 0x69, 0x72, 0x32, 0x95, 0x65, 0x3e, 0x9b, 0xfa, + 0x8e, 0x23, 0x36, 0x83, 0xb0, 0x71, 0xd4, 0x0d, 0x52, 0xaf, 0x99, 0x02, + 0xf9, 0x7b, 0x20, 0x8c, 0x82, 0x33, 0x8e, 0x5d, 0xb1, 0x34, 0x18, 0x1c, + 0x32, 0xad, 0x70, 0x4c, 0x88, 0x95, 0x1e, 0xc2, 0xf8, 0xda, 0x70, 0xe0, + 0xc8, 0x62, 0xfc, 0xdc, 0xc8, 0x96, 0x02, 0x83, 0x41, 0x56, 0xbf, 0xc5, + 0xfc, 0xba, 0xdc, 0x53, 0x94, 0x9c, 0x63, 0x38, 0x9c, 0x19, 0x29, 0x99, + 0xa4, 0x60, 0x12, 0xac, 0x53, 0x6b, 0xcc, 0xb1, 0xc3, 0xca, 0x50, 0x24, + 0x4f, 0x68, 0x12, 0x35, 0x53, 0x3b, 0xbe, 0xca, 0x08, 0x87, 0x79, 0x49, + 0x20, 0xd5, 0x60, 0xea, 0x68, 0xc4, 0x50, 0xcb, 0x29, 0x50, 0xf7, 0x02, + 0xfe, 0xba, 0x30, 0x35, 0x3e, 0x06, 0xf5, 0x86, 0x7c, 0x32, 0x22, 0x53, + 0x24, 0xa2, 0x82, 0x33, 0x19, 0x3e, 0xc8, 0x35, 0xbb, 0x30, 0xd2, 0x05, + 0x8b, 0x9f, 0xf0, 0x22, 0xdd, 0xa3, 0x22, 0x81, 0x48, 0x37, 0xda, 0x88, + 0x20, 0xae, 0x96, 0x5c, 0xa1, 0xbd, 0x18, 0x49, 0xe6, 0xe6, 0x6b, 0xdb, + 0xeb, 0x19, 0x06, 0x9c, 0xe8, 0x99, 0x11, 0x93, 0xc9, 0x7d, 0x42, 0xff, + 0xe3, 0xa3, 0x00, 0x82, 0x88, 0x1e, 0x94, 0x67, 0x47, 0xe2, 0xd6, 0x5a, + 0x64, 0xb2, 0x26, 0x40, 0xa1, 0xe9, 0xc2, 0x45, 0x33, 0x4a, 0x8a, 0x5f, + 0x61, 0x3c, 0x11, 0x2d, 0x23, 0xa6, 0x9c, 0xe4, 0x8a, 0x17, 0xa0, 0x4f, + 0xe2, 0xf8, 0xb8, 0xbc, 0xd1, 0x6a, 0x34, 0xa1, 0x94, 0x19, 0x32, 0x97, + 0x80, 0xd5, 0x67, 0x26, 0x01, 0xce, 0x95, 0x41, 0xcb, 0x42, 0x8e, 0x50, + 0x83, 0x0e, 0x70, 0x8d, 0xc0, 0x7a, 0xdc, 0x88, 0xa2, 0x48, 0x9c, 0xf2, + 0x52, 0xfb, 0x6c, 0x49, 0x62, 0xec, 0xcd, 0xe1, 0x39, 0x06, 0xfb, 0x09, + 0xf6, 0x8e, 0x84, 0x8e, 0xe9, 0x25, 0xb9, 0x39, 0x7e, 0x9c, 0xaf, 0x11, + 0x1b, 0x04, 0xf9, 0x7d, 0x9a, 0x1a, 0x4a, 0xab, 0x00, 0xdb, 0xba, 0x4a, + 0xe6, 0xd2, 0x6b, 0x9b, 0x85, 0xf2, 0xcc, 0x32, 0xab, 0xc7, 0x2d, 0x21, + 0x59, 0x3a, 0xb0, 0x27, 0xbf, 0xc5, 0xf2, 0x7b, 0x3f, 0x43, 0x6c, 0xab, + 0xbf, 0xd5, 0xe5, 0x2e, 0xcd, 0x4e, 0xbe, 0xe1, 0xc8, 0x3c, 0x96, 0x13, + 0xed, 0x14, 0xe8, 0xf8, 0x81, 0x7c, 0x49, 0x06, 0x5b, 0xd1, 0xca, 0x45, + 0x2f, 0x2a, 0x34, 0x2e, 0x03, 0xc5, 0x86, 0x64, 0x40, 0x8e, 0x1e, 0x80, + 0x0d, 0x42, 0x14, 0x80, 0x6f, 0xb4, 0xc9, 0xe4, 0xf6, 0xed, 0xda, 0xd4, + 0x45, 0x0d, 0x42, 0xc1, 0x76, 0xe2, 0xbb, 0xd1, 0x05, 0x66, 0x4a, 0xd4, + 0xd1, 0xca, 0x85, 0xc8, 0xcb, 0xfb, 0x84, 0xa5, 0xca, 0x98, 0x8f, 0xbf, + 0xcf, 0xc5, 0x71, 0x5f, 0xfe, 0xe6, 0x92, 0x56, 0x20, 0xa4, 0x34, 0x8a, + 0x35, 0x7a, 0xaa, 0xa2, 0xb5, 0x79, 0xe1, 0x24, 0xa9, 0xee, 0xc3, 0x2c, + 0x4d, 0x59, 0xa0, 0x41, 0xf5, 0x87, 0xa8, 0xa0, 0xeb, 0x02, 0xe9, 0xfd, + 0xdf, 0x77, 0xbb, 0x72, 0xc4, 0x17, 0x9e, 0xdb, 0xe1, 0x18, 0x70, 0xca, + 0x6a, 0x87, 0x24, 0x68, 0xb8, 0x80, 0x84, 0x94, 0xc1, 0xe7, 0xd5, 0x07, + 0xde, 0xd4, 0xdc, 0xce, 0x2a, 0xde, 0x74, 0xb8, 0xd9, 0xfd, 0x5a, 0x0f, + 0x91, 0x9a, 0x70, 0x8a, 0x34, 0x0a, 0xc9, 0x5f, 0x88, 0x28, 0xf9, 0x3a, + 0x79, 0xd6, 0xee, 0x4c, 0x82, 0xa4, 0x97, 0x24, 0x4a, 0x43, 0x2b, 0x25, + 0xf5, 0x55, 0xcb, 0x6f, 0x23, 0xb1, 0x2c, 0x9a, 0x43, 0xe6, 0x9e, 0xe1, + 0x70, 0x77, 0x07, 0x09, 0x14, 0x9c, 0x00, 0x5e, 0xb9, 0x22, 0x28, 0xd7, + 0xf9, 0x41, 0xe6, 0x13, 0xa6, 0x2b, 0x73, 0x5a, 0x4f, 0x6b, 0x98, 0x39, + 0xba, 0xf8, 0xa7, 0xfc, 0x07, 0x1d, 0xbf, 0x69, 0xcc, 0x00, 0xd1, 0x66, + 0xa6, 0x41, 0x00, 0x91, 0x41, 0x1e, 0xe0, 0x07, 0xcb, 0x16, 0xfe, 0xc6, + 0xe6, 0xd5, 0x54, 0xb4, 0x51, 0x4e, 0xf7, 0x2a, 0xb4, 0x86, 0xa0, 0x77, + 0xb8, 0x2b, 0xf2, 0x41, 0x2f, 0xb2, 0x03, 0xc0, 0x7a, 0x92, 0x7b, 0xcb, + 0xd5, 0x9a, 0x65, 0xd2, 0x37, 0x80, 0xbe, 0xdc, 0x4e, 0x0c, 0x3e, 0xaa, + 0x86, 0xef, 0x86, 0x01, 0xa8, 0x77, 0x36, 0xd7, 0xf2, 0xf5, 0xb9, 0xeb, + 0xd8, 0x6e, 0x5e, 0x12, 0x5d, 0xfc, 0xf7, 0x93, 0xb6, 0x91, 0xbc, 0x00, + 0x04, 0x67, 0x97, 0xf7, 0x37, 0xac, 0x3b, 0x81, 0xbe, 0xab, 0x3e, 0xfa, + 0x92, 0x67, 0xb1, 0x60, 0x4e, 0xf4, 0x64, 0x27, 0x08, 0x08, 0x32, 0x40, + 0x9a, 0x3e, 0x2c, 0x4c, 0x9a, 0x53, 0x45, 0xcc, 0xe1, 0xfa, 0x70, 0xda, + 0x8c, 0x00, 0x49, 0x6d, 0x0e, 0x4b, 0x22, 0xf6, 0x7f, 0xd1, 0x49, 0x37, + 0xa0, 0x28, 0x48, 0x5e, 0xa4, 0xc5, 0x76, 0xb8, 0x86, 0x1a, 0xa5, 0x34, + 0xe6, 0x0a, 0x25, 0x80, 0x48, 0x9f, 0x01, 0x25, 0xb3, 0xde, 0xf1, 0x0b, + 0xaf, 0x6b, 0x22, 0x1c, 0x60, 0x1c, 0xc9, 0xa3, 0x17, 0x96, 0x19, 0xb2, + 0x1b, 0xcb, 0xc2, 0x1d, 0xf6, 0x9f, 0xc2, 0x89, 0x99, 0xcd, 0x9b, 0x7f, + 0x67, 0x7e, 0x39, 0xdf, 0x37, 0x9b, 0xd3, 0xf3, 0x7f, 0xfe, 0xb8, 0x34, + 0xb0, 0xf0, 0x03, 0xbf, 0x33, 0x23, 0xa5, 0x01, 0x51, 0x28, 0x09, 0x90, + 0x89, 0x78, 0x4f, 0xd0, 0x1c, 0xf6, 0x61, 0xc6, 0xb4, 0xd4, 0x08, 0x9d, + 0x22, 0xcf, 0x08, 0xa4, 0x70, 0xc6, 0x79, 0x77, 0xa8, 0x15, 0xe9, 0x0d, + 0x74, 0x0a, 0xc6, 0x04, 0xb0, 0x6f, 0x39, 0x80, 0x43, 0xcc, 0xa8, 0xfc, + 0x5a, 0x32, 0xa0, 0x2a, 0xd6, 0x01, 0xb9, 0x41, 0xd1, 0xd8, 0x96, 0x5a, + 0x07, 0x25, 0xf4, 0x5c, 0x48, 0x1f, 0x0b, 0x38, 0x4c, 0x2e, 0x15, 0x23, + 0x32, 0xe2, 0xee, 0x7c, 0x7d, 0xf8, 0xa5, 0x89, 0xde, 0x89, 0x2f, 0xc7, + 0x4d, 0xba, 0x2f, 0xfe, 0x48, 0x95, 0x19, 0x4e, 0x06, 0x64, 0x4e, 0x54, + 0xfc, 0x0c, 0xf6, 0xc3, 0x5a, 0x17, 0xb0, 0x90, 0x9e, 0x52, 0x5c, 0xf2, + 0x51, 0xa4, 0x15, 0xc5, 0xf2, 0x98, 0xce, 0x50, 0xfc, 0xef, 0x86, 0x91, + 0x5b, 0x95, 0x23, 0x42, 0x48, 0xa3, 0x90, 0xea, 0xcb, 0x47, 0x98, 0xdf, + 0xf2, 0xcc, 0xfc, 0x5b, 0x0d, 0xdc, 0x8e, 0x78, 0x86, 0x58, 0xf2, 0xed, + 0xa0, 0x6a, 0xea, 0xe1, 0x51, 0xf1, 0x0c, 0xfb, 0x3a, 0x2c, 0x4e, 0x59, + 0xec, 0x82, 0x32, 0x65, 0x93, 0xc2, 0xd9, 0xa4, 0x32, 0x72, 0x41, 0x91, + 0x45, 0x23, 0x43, 0xc3, 0xab, 0x8a, 0xfb, 0xaf, 0x21, 0xc6, 0x42, 0x85, + 0x61, 0x24, 0xcb, 0x25, 0x09, 0xf4, 0xf6, 0x54, 0x1e, 0x45, 0xe1, 0x42, + 0x19, 0x49, 0x1c, 0x96, 0x11, 0x3c, 0x89, 0x2f, 0xf3, 0xa9, 0x48, 0x39, + 0x02, 0x14, 0x50, 0x26, 0x8f, 0x64, 0x33, 0x85, 0x4f, 0x35, 0x85, 0xe7, + 0xdd, 0x7f, 0x7d, 0xfb, 0xd9, 0xd4, 0x62, 0x06, 0x1a, 0x57, 0x10, 0xfe, + 0x12, 0xc6, 0x9e, 0x26, 0xb6, 0x5d, 0x41, 0xde, 0x66, 0x1e, 0xcf, 0x32, + 0x7b, 0x20, 0x4e, 0xec, 0xf1, 0x84, 0xb2, 0x28, 0x55, 0xd2, 0x4f, 0xcd, + 0x23, 0xff, 0xcb, 0xd4, 0x96, 0x6a, 0x16, 0xc9, 0x1a, 0xd8, 0x02, 0x59, + 0x7f, 0x06, 0x3e, 0x7d, 0xe1, 0x0f, 0x60, 0x79, 0xec, 0x1b, 0x41, 0x5f, + 0x99, 0xb9, 0x65, 0x5d, 0x82, 0xbe, 0x2f, 0x97, 0x8f, 0xd2, 0xef, 0x0e, + 0x32, 0xd7, 0xab, 0x65, 0xc5, 0xa1, 0x92, 0xf1, 0x74, 0x65, 0xf3, 0x00, + 0xb1, 0xab, 0x54, 0x7f, 0x26, 0x43, 0x2c, 0x4e, 0xba, 0x6d, 0x83, 0xb9, + 0x1a, 0x75, 0xec, 0x98, 0x6d, 0x1f, 0xa1, 0x37, 0xdb, 0xaa, 0x3e, 0xb4, + 0x1a, 0xef, 0xe9, 0x4a, 0x7a, 0x76, 0xe3, 0x66, 0x0c, 0x92, 0xf5, 0x06, + 0xcc, 0x39, 0x3d, 0x78, 0x84, 0x7a, 0x7e, 0xb0, 0x7d, 0xd5, 0xff, 0x20, + 0x07, 0x08, 0x68, 0x35, 0xbf, 0x04, 0xd8, 0xc6, 0x59, 0x67, 0xec, 0xa4, + 0x24, 0xfc, 0xce, 0x83, 0x4f, 0x44, 0x3e, 0xde, 0x86, 0xd4, 0x79, 0x9b, + 0xb0, 0xaf, 0x98, 0x4c, 0xf2, 0xa8, 0xe0, 0x1f, 0x47, 0x83, 0x85, 0x12, + 0xfb, 0x32, 0x01, 0x0a, 0x5a, 0xca, 0xc6, 0x92, 0x31, 0x8a, 0x45, 0x1a, + 0x3f, 0x57, 0x1f, 0xb8, 0x96, 0xe1, 0xfd, 0x20, 0xc8, 0x98, 0x54, 0x56, + 0x01, 0x27, 0x2a, 0x50, 0xcd, 0x0f, 0x9e, 0x36, 0xe2, 0x97, 0xae, 0x69, + 0x36, 0x86, 0x5e, 0x54, 0xcc, 0x68, 0x69, 0x73, 0x32, 0xdb, 0x56, 0xbf, + 0xfb, 0xa7, 0x66, 0x20, 0xd6, 0xcb, 0x06, 0x82, 0x07, 0x98, 0x46, 0x6f, + 0xb9, 0x61, 0xbe, 0x3d, 0x57, 0x3d, 0xed, 0x8f, 0x50, 0x2e, 0x56, 0x2f, + 0x37, 0x75, 0xed, 0x94, 0xc2, 0x72, 0x66, 0x91, 0x07, 0x95, 0xa5, 0x6d, + 0xf1, 0xb5, 0xaf, 0x8e, 0xd8, 0xcb, 0x20, 0x1a, 0x44, 0x09, 0xbc, 0xd0, + 0x13, 0x2c, 0x12, 0xb2, 0xa1, 0xf1, 0x3e, 0xda, 0x6b, 0x21, 0xad, 0x9d, + 0x53, 0x59, 0x33, 0x6e, 0x1a, 0x50, 0xb0, 0xc3, 0x19, 0x55, 0x31, 0x00, + 0x61, 0x7c, 0xa9, 0xe5, 0xf8, 0xb7, 0x7f, 0x2e, 0x8f, 0x9b, 0x6e, 0xd1, + 0x3a, 0x1c, 0x66, 0xd0, 0x65, 0xc3, 0x04, 0xe6, 0xe6, 0xf0, 0x98, 0x09, + 0x21, 0x95, 0xe2, 0x18, 0xa7, 0xb2, 0xbd, 0x90, 0x14, 0x05, 0x78, 0xcf, + 0x21, 0x65, 0xa1, 0x93, 0x47, 0x09, 0x15, 0xbe, 0x1f, 0x92, 0xf0, 0x15, + 0x32, 0x84, 0xd8, 0xe0, 0x22, 0x8c, 0xdc, 0xa3, 0x2f, 0x83, 0xf1, 0x43, + 0x14, 0x4c, 0x7e, 0xe1, 0xa0, 0x18, 0xef, 0x5f, 0xa2, 0x1b, 0xe6, 0x66, + 0x97, 0x2a, 0x3e, 0x2d, 0x7f, 0x80, 0x5a, 0x1b, 0xc7, 0x2e, 0x94, 0xdf, + 0x17, 0xe0, 0xfe, 0x8a, 0x77, 0x05, 0xc3, 0x3c, 0x33, 0x28, 0xc2, 0x90, + 0xc9, 0x66, 0x0a, 0x2a, 0x60, 0xa6, 0xec, 0x11, 0x9e, 0x54, 0xd2, 0x82, + 0x5f, 0xdc, 0x10, 0x88, 0x5b, 0x24, 0x6f, 0x4f, 0x69, 0x4a, 0xf5, 0xb8, + 0x5c, 0xac, 0xc6, 0xf7, 0x77, 0x35, 0x19, 0x81, 0x0a, 0x32, 0x0d, 0x92, + 0x11, 0xa3, 0xf1, 0xa2, 0xc8, 0x99, 0x4c, 0xb9, 0x43, 0x2d, 0x28, 0x4a, + 0xf5, 0x3e, 0x23, 0x36, 0x1d, 0xd1, 0xc3, 0x94, 0x87, 0xdc, 0x06, 0xfb, + 0x07, 0x78, 0x60, 0xed, 0x05, 0x2c, 0x9f, 0x65, 0x0f, 0xe5, 0x09, 0x53, + 0x9e, 0x84, 0x91, 0x66, 0x72, 0x4f, 0xc7, 0x1f, 0x05, 0xd6, 0x68, 0x7c, + 0x58, 0xd0, 0xcc, 0xd0, 0xec, 0xc2, 0x86, 0x98, 0x51, 0x7c, 0xa6, 0xa3, + 0x33, 0x56, 0xa1, 0x6f, 0xf1, 0xf8, 0x20, 0xcc, 0x48, 0xed, 0x46, 0xf2, + 0x69, 0x72, 0xf1, 0x72, 0x39, 0x69, 0x09, 0xde, 0x33, 0xf1, 0x54, 0x2b, + 0xcc, 0x4e, 0x3e, 0x52, 0x29, 0x11, 0xd8, 0x4f, 0x8f, 0x06, 0x60, 0xfd, + 0xdd, 0x5d, 0x34, 0xae, 0x37, 0xe6, 0x5c, 0x5e, 0x75, 0xc1, 0xd3, 0xbe, + 0x50, 0x24, 0xb6, 0xf7, 0x23, 0x87, 0xa5, 0xc3, 0x94, 0x12, 0xfc, 0x01, + 0xf7, 0xfb, 0xfb, 0x3b, 0xbe, 0x9e, 0xea, 0xce, 0x5e, 0x2e, 0xf5, 0xba, + 0x4f, 0x90, 0x5e, 0xa6, 0x8e, 0x4f, 0x4e, 0x84, 0x8d, 0x0f, 0x14, 0x61, + 0xf6, 0xe9, 0xd5, 0x5e, 0x6b, 0x35, 0x5b, 0xea, 0xba, 0xd0, 0x3b, 0xd4, + 0xb5, 0x33, 0x37, 0x63, 0xb7, 0x94, 0x98, 0x99, 0x4f, 0x2a, 0x7e, 0x3b, + 0x48, 0x1c, 0xeb, 0xb4, 0xa6, 0x9e, 0x76, 0x2b, 0xc2, 0x89, 0x3b, 0xf8, + 0x36, 0x55, 0xce, 0x57, 0x8d, 0xd0, 0x0b, 0xdd, 0x53, 0x34, 0xa0, 0x93, + 0x01, 0xb1, 0x80, 0x25, 0xa5, 0x51, 0xf1, 0x3d, 0x3e, 0xbc, 0xb3, 0x56, + 0x99, 0xb7, 0x12, 0xa1, 0x73, 0x23, 0x5f, 0x14, 0xf1, 0xb8, 0x83, 0x2e, + 0x73, 0x84, 0xf8, 0x82, 0xb4, 0x54, 0xcb, 0x4c, 0x6b, 0xdb, 0xf3, 0xf1, + 0x04, 0xad, 0x66, 0xb6, 0x7b, 0x9a, 0x25, 0x2c, 0x63, 0x80, 0xfb, 0x61, + 0x8c, 0x0d, 0x1e, 0xe0, 0x4e, 0xfe, 0x37, 0x63, 0x1e, 0x7a, 0x86, 0xfe, + 0xb7, 0x9d, 0x2b, 0x79, 0xd7, 0x9c, 0x0a, 0x0d, 0x35, 0x12, 0x40, 0x83, + 0x49, 0x55, 0x8c, 0x3d, 0x3a, 0xfb, 0x4a, 0x3e, 0xb6, 0xb6, 0xbb, 0xed, + 0x13, 0x6d, 0x2f, 0x9d, 0x95, 0x6e, 0xdc, 0xa9, 0x09, 0x9e, 0x7c, 0xfe, + 0x9c, 0xd5, 0xdd, 0x9d, 0xf3, 0x9e, 0xcf, 0xcb, 0xb9, 0x7e, 0xd7, 0x16, + 0xa2, 0x21, 0x08, 0x27, 0xa0, 0x8c, 0xb2, 0x20, 0x84, 0x6c, 0xee, 0xed, + 0xd3, 0x85, 0xee, 0x7c, 0x6d, 0xc1, 0x18, 0xf4, 0x55, 0x42, 0xa2, 0x29, + 0x55, 0x60, 0x27, 0xdb, 0xbd, 0x76, 0x26, 0x7a, 0x8f, 0x98, 0xcd, 0xa2, + 0xe9, 0xa9, 0x1e, 0xd0, 0x08, 0x4c, 0x26, 0xa8, 0x44, 0x61, 0x89, 0xab, + 0x01, 0xe1, 0xff, 0xb9, 0xbb, 0xc9, 0xc0, 0x14, 0xff, 0xfb, 0x38, 0xb7, + 0xcd, 0x04, 0xa1, 0xe5, 0x81, 0x38, 0xd8, 0x0a, 0x14, 0x6a, 0xd7, 0xe9, + 0x17, 0xb9, 0x25, 0xd0, 0xac, 0xff, 0x0b, 0xff, 0xb4, 0x60, 0xba, 0xbf, + 0x14, 0x9d, 0xee, 0x9b, 0xb3, 0x5c, 0x36, 0xe1, 0x1b, 0x07, 0x70, 0xec, + 0x25, 0x04, 0x03, 0x5e, 0x1d, 0x64, 0x4d, 0x3a, 0xb0, 0xdb, 0xab, 0x34, + 0xf4, 0xff, 0xbc, 0xb0, 0xda, 0x45, 0xa4, 0x96, 0x4f, 0xd8, 0x9b, 0x81, + 0x7f, 0xcd, 0x7e, 0xb6, 0xfb, 0x82, 0x4d, 0x88, 0x35, 0x25, 0x6c, 0x64, + 0x17, 0x97, 0x02, 0x29, 0x14, 0x92, 0x11, 0xf3, 0x2f, 0xf5, 0x69, 0x5c, + 0x40, 0x36, 0x9c, 0xf0, 0x29, 0xc3, 0x40, 0xb6, 0x58, 0x14, 0x27, 0x31, + 0x42, 0x0a, 0xcd, 0x12, 0x7b, 0x83, 0x82, 0x79, 0x2d, 0x7f, 0x1d, 0x07, + 0x43, 0x8e, 0x96, 0x8c, 0x98, 0xa0, 0xf3, 0xcf, 0x90, 0x4e, 0x1f, 0x77, + 0x4a, 0x95, 0xaf, 0x3e, 0x8d, 0x81, 0x9f, 0x79, 0x66, 0x73, 0x92, 0x43, + 0xb8, 0x07, 0x8b, 0xba, 0xc1, 0xaf, 0xbd, 0xee, 0x7f, 0x99, 0xbf, 0x1c, + 0xde, 0x07, 0xac, 0xb2, 0x24, 0x83, 0xb2, 0x38, 0x76, 0xca, 0xf0, 0xdc, + 0x5a, 0xf6, 0xf7, 0xfd, 0xdc, 0xb8, 0xc4, 0xf6, 0xc4, 0x50, 0xe3, 0x48, + 0x11, 0x4e, 0x64, 0xbd, 0xa7, 0x2e, 0x73, 0x94, 0xaa, 0xc3, 0xe2, 0x3d, + 0xec, 0x8f, 0xb7, 0xff, 0xe3, 0x30, 0xbe, 0x4e, 0x5d, 0x0d, 0xb1, 0xa1, + 0xe9, 0xfb, 0x29, 0x07, 0xd8, 0x37, 0xd1, 0xd7, 0xea, 0x2e, 0x3f, 0x5c, + 0x3a, 0xf0, 0xa9, 0x75, 0xd9, 0x5d, 0x54, 0xbf, 0x2f, 0x9e, 0x9d, 0x2b, + 0x73, 0x97, 0xe1, 0x88, 0x5c, 0xe2, 0xe2, 0xa2, 0xd8, 0xe4, 0xbc, 0xe4, + 0xa3, 0x0c, 0x30, 0x25, 0x77, 0x00, 0x88, 0xea, 0x97, 0x2b, 0xfe, 0xae, + 0xdd, 0xdd, 0x6a, 0x16, 0x26, 0x40, 0xa9, 0xc4, 0x03, 0x2d, 0x89, 0x82, + 0x06, 0x9a, 0x33, 0xbd, 0x3e, 0x20, 0x8e, 0xc5, 0x8b, 0x63, 0xda, 0xf5, + 0xed, 0xaf, 0x83, 0xfd, 0xd8, 0x65, 0x62, 0x0e, 0xd2, 0x72, 0xa3, 0x0a, + 0x1d, 0x90, 0xeb, 0x8e, 0xdd, 0xf7, 0x58, 0xdf, 0x8f, 0x65, 0xec, 0x3b, + 0x5c, 0x18, 0x8c, 0xb6, 0x22, 0x4a, 0x7d, 0x63, 0x90, 0xc0, 0x9c, 0x3c, + 0x9c, 0x65, 0x04, 0x7e, 0xc3, 0xe7, 0xa5, 0x12, 0x57, 0x96, 0x63, 0x31, + 0xeb, 0xe6, 0x29, 0x9e, 0xdc, 0xab, 0x30, 0x3b, 0x18, 0x58, 0x38, 0x28, + 0x20, 0x40, 0x3e, 0x01, 0x56, 0x41, 0xe2, 0xf2, 0x3f, 0x7b, 0xf3, 0x37, + 0x60, 0x53, 0x14, 0xd6, 0x75, 0xe8, 0xb1, 0xfe, 0xb7, 0x06, 0x1b, 0x7c, + 0x36, 0x36, 0xcc, 0x88, 0x94, 0xf5, 0x03, 0x89, 0x09, 0x42, 0x3e, 0x8b, + 0x8d, 0x58, 0xfd, 0x5c, 0xcd, 0x2f, 0xd9, 0x96, 0xcd, 0xd7, 0x3d, 0x9d, + 0x88, 0x13, 0x91, 0x16, 0x31, 0x38, 0xaf, 0x47, 0xb5, 0xbd, 0x88, 0x48, + 0xfd, 0x2f, 0x39, 0xa5, 0xe0, 0x59, 0x31, 0x52, 0x99, 0xbf, 0x23, 0x72, + 0x3b, 0xf5, 0xbb, 0xd7, 0xdd, 0xda, 0xa6, 0x26, 0x0d, 0x4c, 0x8d, 0x13, + 0x93, 0xda, 0x52, 0x43, 0x22, 0x02, 0xa1, 0x66, 0xb8, 0x71, 0x7c, 0xad, + 0x57, 0x9b, 0x65, 0x53, 0x2b, 0x32, 0xa7, 0x04, 0xd1, 0x0c, 0x8e, 0x34, + 0xf2, 0xcf, 0x88, 0x3c, 0xd2, 0xd1, 0x9f, 0x17, 0xfd, 0x4e, 0x2d, 0xb7, + 0x62, 0xac, 0x9d, 0xef, 0xb4, 0x96, 0x1b, 0x52, 0x94, 0x16, 0x69, 0xa6, + 0x65, 0xa4, 0xac, 0x04, 0x94, 0x4f, 0x89, 0xd3, 0x7d, 0xde, 0xe1, 0xba, + 0xd3, 0x2d, 0x8f, 0x05, 0x19, 0xa2, 0x89, 0x92, 0x3f, 0x10, 0xce, 0xb0, + 0xf9, 0x5e, 0xfb, 0x3c, 0xb6, 0x59, 0xe5, 0xab, 0xb0, 0x21, 0x7d, 0xb3, + 0x57, 0xf2, 0x82, 0xbf, 0x63, 0xce, 0x0c, 0x00, 0x16, 0x7e, 0xdb, 0x22, + 0x0c, 0xb1, 0xa4, 0x72, 0x49, 0x1f, 0xb4, 0x4f, 0x51, 0xb0, 0xe9, 0xba, + 0x69, 0xb7, 0x6a, 0xc8, 0xc4, 0x57, 0xfc, 0x94, 0xa1, 0xf4, 0x93, 0xd9, + 0x02, 0xe3, 0xde, 0xde, 0x7f, 0x6a, 0x19, 0x52, 0xa2, 0xd0, 0xc1, 0x87, + 0x40, 0xe3, 0x00, 0x52, 0xf6, 0x04, 0x85, 0x64, 0xc5, 0xd5, 0xa7, 0x98, + 0x36, 0xea, 0x7c, 0xce, 0x84, 0x32, 0x93, 0x1c, 0x95, 0x06, 0x38, 0x4b, + 0xe1, 0xa3, 0xf0, 0x22, 0x4f, 0x3e, 0xa4, 0x0c, 0x19, 0x2f, 0x70, 0x0b, + 0x50, 0x8a, 0x9a, 0x2d, 0x87, 0x5f, 0xc6, 0xa8, 0x6c, 0xa8, 0xd7, 0xa1, + 0x46, 0x02, 0xe8, 0x22, 0x4d, 0x01, 0x29, 0x19, 0x7c, 0xf2, 0xdf, 0xcd, + 0xdc, 0xbb, 0xce, 0x11, 0x93, 0x4a, 0xca, 0x95, 0x58, 0x24, 0x6d, 0x7f, + 0xf3, 0xd2, 0xdd, 0x16, 0xcb, 0x1f, 0x3c, 0xeb, 0xce, 0x8a, 0x24, 0x44, + 0xb4, 0xfb, 0x12, 0x46, 0x61, 0x12, 0x32, 0x91, 0xab, 0x27, 0x49, 0x3f, + 0x31, 0x13, 0xae, 0xba, 0x4f, 0x6f, 0x0a, 0x39, 0x7a, 0xc6, 0x9e, 0x43, + 0x1f, 0x34, 0x56, 0x00, 0xf1, 0xad, 0x68, 0x63, 0xa5, 0x51, 0x03, 0x09, + 0x38, 0xd9, 0x1e, 0xdf, 0xd8, 0x39, 0xd7, 0x07, 0x6c, 0x77, 0x51, 0xb8, + 0x6a, 0xf6, 0x82, 0x3b, 0x46, 0x58, 0xd5, 0x69, 0xd1, 0xf7, 0xf3, 0xef, + 0xb8, 0xf7, 0xb8, 0x7f, 0xc7, 0x7f, 0x8f, 0xeb, 0xb1, 0xe6, 0x3d, 0x1a, + 0xcb, 0x0a, 0xc7, 0x0d, 0x3a, 0xbe, 0xb3, 0x2d, 0x00, 0x52, 0x89, 0x85, + 0xf2, 0x08, 0x50, 0xad, 0xfc, 0x50, 0xa0, 0x25, 0x0f, 0x02, 0x78, 0x82, + 0x9f, 0xf2, 0x56, 0x86, 0x81, 0x9b, 0xb9, 0x9e, 0x49, 0x23, 0xe2, 0xd3, + 0x3b, 0x28, 0x9c, 0x32, 0x18, 0x07, 0xcf, 0x32, 0xbc, 0x2f, 0xe4, 0xa0, + 0xbc, 0x68, 0x08, 0x94, 0x01, 0xe1, 0x0f, 0x33, 0x43, 0x27, 0xf1, 0x68, + 0x8f, 0xb0, 0xcf, 0x3e, 0x27, 0x2d, 0xd4, 0xd3, 0x2f, 0x3e, 0x17, 0xa9, + 0x49, 0xa6, 0x08, 0x9a, 0x04, 0xd0, 0xc8, 0xa4, 0xb9, 0xd6, 0x98, 0xdd, + 0x37, 0xe2, 0x9c, 0xe7, 0x3c, 0x49, 0xc0, 0x58, 0xd4, 0x4e, 0x8e, 0x5f, + 0xc7, 0xf5, 0x7e, 0x6f, 0xcb, 0x3c, 0x28, 0x4b, 0x58, 0x78, 0x00, 0xa0, + 0x27, 0x94, 0x12, 0x87, 0x81, 0x67, 0x14, 0x10, 0x82, 0x89, 0xc9, 0xcc, + 0x4e, 0x85, 0xdd, 0x5a, 0xeb, 0x11, 0xc9, 0x08, 0x28, 0xa9, 0x86, 0x39, + 0x8c, 0x1b, 0x08, 0x16, 0xc7, 0xfb, 0xb4, 0xd3, 0x98, 0x9f, 0xd5, 0xe8, + 0x3e, 0x41, 0x30, 0x4b, 0x2c, 0x29, 0x02, 0x4f, 0x81, 0xbf, 0xd1, 0xeb, + 0x55, 0x7e, 0xc2, 0xcb, 0x84, 0xc1, 0x4f, 0x5c, 0xac, 0x59, 0x94, 0x94, + 0xb7, 0x86, 0x7f, 0x31, 0xf6, 0xb8, 0xd7, 0x0b, 0x22, 0x7c, 0x47, 0x6c, + 0xd0, 0xa8, 0xff, 0x6f, 0x82, 0x63, 0x17, 0x6c, 0xa8, 0x09, 0x48, 0x4b, + 0xc1, 0xab, 0x50, 0xda, 0xa3, 0xaf, 0xfa, 0xe4, 0x2f, 0x7c, 0x83, 0xa4, + 0x8e, 0xc0, 0xd5, 0xec, 0x70, 0xef, 0x24, 0x8e, 0xe1, 0x2f, 0x29, 0x64, + 0xef, 0x58, 0xc2, 0xea, 0xf1, 0xe1, 0xb3, 0xce, 0xa9, 0xd4, 0x62, 0x89, + 0x96, 0x42, 0x9c, 0xa6, 0x72, 0x21, 0x2c, 0xe0, 0xef, 0x9d, 0xbd, 0x6d, + 0x7f, 0xf8, 0xa7, 0x5e, 0x0f, 0xb2, 0xcb, 0x61, 0x24, 0x51, 0x80, 0x91, + 0x02, 0x54, 0x12, 0x33, 0xfa, 0x3b, 0x2a, 0x38, 0xb7, 0x97, 0xc0, 0x5b, + 0x42, 0x8d, 0xed, 0xf8, 0xc8, 0x93, 0x96, 0x0c, 0x14, 0x72, 0xa7, 0x3b, + 0xd6, 0xa3, 0xf7, 0xf9, 0xff, 0x79, 0xd9, 0x9b, 0x63, 0x83, 0xa4, 0x08, + 0x67, 0x13, 0x48, 0xa5, 0xe3, 0x9a, 0x13, 0xee, 0x21, 0xab, 0x97, 0x69, + 0xc3, 0xd0, 0xe8, 0x6b, 0x23, 0x44, 0x23, 0x7b, 0x47, 0x0e, 0x0a, 0x52, + 0x47, 0xed, 0x2e, 0xe2, 0x5c, 0x6e, 0x75, 0x68, 0xea, 0xf6, 0x02, 0x70, + 0xf4, 0x86, 0x32, 0xe7, 0x34, 0x32, 0x11, 0xc9, 0xca, 0x85, 0x64, 0x3d, + 0x2b, 0x5a, 0x80, 0x71, 0x0c, 0x09, 0x78, 0xa6, 0x11, 0xf1, 0x10, 0x4a, + 0xac, 0x11, 0x03, 0x32, 0x7c, 0xca, 0x80, 0xba, 0x99, 0x92, 0xb2, 0xdd, + 0x92, 0xfd, 0x33, 0xfb, 0x69, 0x6d, 0x45, 0x0b, 0x76, 0xb7, 0x03, 0x0c, + 0x84, 0xa6, 0x52, 0x89, 0x22, 0x85, 0xe9, 0xc2, 0x14, 0xe4, 0x4d, 0xa5, + 0x39, 0xe5, 0x05, 0x09, 0x81, 0x97, 0x0e, 0x52, 0x57, 0xc7, 0x3e, 0x8b, + 0xec, 0x3d, 0x3d, 0x41, 0xb9, 0x41, 0x23, 0xb2, 0x61, 0x91, 0x9c, 0x25, + 0x02, 0xe5, 0x1c, 0xa1, 0x3f, 0xb1, 0xab, 0x31, 0x45, 0xe8, 0x97, 0xdb, + 0x97, 0x9d, 0x19, 0x40, 0x86, 0x5a, 0x43, 0x09, 0x2b, 0xd1, 0x14, 0x3e, + 0x2e, 0x5f, 0xa6, 0xaa, 0x2c, 0x85, 0x10, 0x68, 0x20, 0x91, 0xf9, 0xc4, + 0xa7, 0x3f, 0x98, 0x37, 0xa7, 0xe7, 0x82, 0xff, 0x18, 0xb4, 0x38, 0x71, + 0x43, 0x00, 0x09, 0x59, 0x82, 0x4d, 0xad, 0xbf, 0x59, 0xe7, 0x71, 0x0b, + 0x09, 0x98, 0x34, 0xd8, 0xee, 0xe4, 0x19, 0x48, 0x37, 0x6a, 0x51, 0x95, + 0x60, 0x0a, 0xb4, 0x39, 0x05, 0xc3, 0x21, 0x94, 0x8a, 0x18, 0x0a, 0x11, + 0xa0, 0x04, 0x4c, 0xde, 0xad, 0xe3, 0x5c, 0xe3, 0x5e, 0x5b, 0xa3, 0xba, + 0x46, 0xbf, 0x63, 0xa1, 0x50, 0xf2, 0x0d, 0xe5, 0xd5, 0x4f, 0xc8, 0xf1, + 0x5c, 0xde, 0xa2, 0x83, 0xec, 0xcf, 0x3d, 0x5e, 0xfe, 0x56, 0xf3, 0xad, + 0xe5, 0x57, 0x92, 0xc9, 0xa5, 0x25, 0x4d, 0x97, 0x22, 0x11, 0x67, 0x62, + 0x4b, 0x46, 0x58, 0x97, 0xd0, 0x13, 0x6f, 0x7f, 0xa7, 0xe5, 0x62, 0xf3, + 0xc3, 0x00, 0x95, 0x48, 0x69, 0x25, 0x81, 0x7f, 0xc1, 0xee, 0xb0, 0x58, + 0x6d, 0x79, 0x9f, 0x53, 0x9e, 0xa8, 0xbb, 0x93, 0x90, 0xc2, 0x08, 0x0a, + 0x22, 0x53, 0xab, 0x53, 0x26, 0x7c, 0xbc, 0x26, 0x9f, 0xe2, 0xc8, 0x78, + 0x75, 0x3b, 0x08, 0x54, 0xf2, 0x86, 0x44, 0x63, 0x6c, 0x48, 0x9c, 0x67, + 0xee, 0x3e, 0x01, 0xf0, 0xb6, 0x6c, 0x8d, 0xf9, 0x22, 0xb8, 0xbe, 0xfe, + 0xb5, 0x7d, 0xda, 0x99, 0x7b, 0xa5, 0x3c, 0x60, 0x8d, 0x24, 0xb1, 0x40, + 0xf7, 0x26, 0x7e, 0x2b, 0x40, 0x4f, 0x67, 0x4d, 0x90, 0xe6, 0x43, 0x7c, + 0x53, 0x58, 0x2e, 0x09, 0x3d, 0x89, 0xff, 0xb7, 0x76, 0x5f, 0x8d, 0xf9, + 0x85, 0x92, 0xe1, 0xbb, 0x50, 0x3b, 0x5e, 0x50, 0x46, 0x7d, 0xa3, 0x1a, + 0x00, 0x7d, 0x85, 0xd1, 0xce, 0x62, 0x79, 0xf3, 0xaa, 0x93, 0x23, 0x39, + 0xb8, 0x2a, 0x09, 0x13, 0x94, 0x32, 0x7e, 0x2e, 0xbb, 0x7d, 0x05, 0x4d, + 0x25, 0x05, 0x53, 0xfd, 0x4d, 0xb8, 0x69, 0xe3, 0xb1, 0x6a, 0x8f, 0x44, + 0x20, 0x46, 0x4e, 0x7e, 0x07, 0x57, 0x7e, 0xe5, 0xad, 0xfb, 0xcf, 0x79, + 0xed, 0xd7, 0x09, 0x27, 0xaa, 0x0f, 0x5f, 0xd3, 0xd1, 0x0c, 0xc0, 0xc9, + 0x95, 0xa9, 0x63, 0x0e, 0xe0, 0x43, 0xa4, 0x77, 0x40, 0xfc, 0xda, 0xa7, + 0x7d, 0xb6, 0xd4, 0x35, 0xd9, 0x9e, 0x4f, 0x62, 0x45, 0x2b, 0x62, 0x84, + 0x86, 0xe7, 0x07, 0x70, 0xbb, 0xef, 0x7e, 0x0b, 0x7e, 0xe3, 0xa3, 0xc0, + 0x74, 0xc0, 0x1d, 0xf0, 0xe5, 0x18, 0x00, 0x08, 0x83, 0x40, 0xe5, 0xca, + 0x58, 0x4b, 0x7c, 0x36, 0x76, 0x29, 0x65, 0x05, 0x49, 0xf7, 0xdf, 0xe5, + 0x44, 0xe7, 0x71, 0x74, 0xe7, 0x83, 0x7b, 0x53, 0x0d, 0x3a, 0x78, 0xf2, + 0x40, 0x22, 0x11, 0x4b, 0x97, 0x88, 0xae, 0xec, 0xa7, 0x3f, 0x21, 0x5a, + 0x81, 0x9e, 0x9f, 0x4b, 0x7d, 0xb1, 0xa2, 0xa7, 0x08, 0x96, 0x70, 0x96, + 0xc6, 0xb1, 0x6a, 0x36, 0xe2, 0x15, 0x75, 0xb0, 0xca, 0x95, 0x7e, 0x45, + 0xc0, 0x45, 0xb2, 0xb4, 0x6b, 0xc3, 0x0c, 0x28, 0x25, 0x64, 0xfe, 0xa2, + 0x15, 0x03, 0x3f, 0xaa, 0xde, 0xf2, 0xb5, 0xed, 0xe4, 0x03, 0x38, 0x37, + 0xb2, 0x48, 0xa0, 0x8b, 0x60, 0x28, 0xcb, 0x2d, 0xa7, 0x84, 0x2e, 0x2d, + 0xe3, 0x0a, 0x37, 0x36, 0xca, 0x1a, 0xaa, 0x03, 0xb4, 0x2f, 0xe5, 0xad, + 0xf7, 0xc9, 0x0f, 0x8b, 0xab, 0x47, 0x66, 0xcb, 0x99, 0x83, 0x52, 0xc7, + 0xa0, 0x96, 0x2a, 0xc3, 0x17, 0xbf, 0xe0, 0x62, 0xde, 0xe2, 0x1d, 0x21, + 0x0b, 0x4f, 0x1d, 0x0c, 0x97, 0xda, 0x8b, 0xc2, 0x9e, 0xea, 0x1e, 0xd5, + 0x88, 0x1b, 0x4e, 0xec, 0xca, 0xd0, 0x08, 0x0d, 0x20, 0x65, 0x29, 0x48, + 0x7c, 0xc0, 0x9f, 0xce, 0x3a, 0xaf, 0xe2, 0x5b, 0xfd, 0xfc, 0xb7, 0x63, + 0xbd, 0x6c, 0x40, 0x10, 0xab, 0xda, 0x72, 0xce, 0x88, 0xca, 0x1f, 0x6d, + 0x49, 0x02, 0x76, 0x22, 0x5a, 0x27, 0xe2, 0x82, 0xa3, 0x9f, 0xdb, 0xdd, + 0xa6, 0xfc, 0x09, 0xd6, 0xce, 0xec, 0xde, 0xe9, 0x34, 0xe0, 0x76, 0xa3, + 0x33, 0x29, 0x83, 0x4d, 0xd0, 0x39, 0x04, 0x19, 0xdf, 0xb5, 0x4f, 0xd8, + 0x29, 0xe5, 0x21, 0xba, 0x63, 0x67, 0x73, 0x40, 0x13, 0xbc, 0x3d, 0x39, + 0x94, 0x21, 0x28, 0x43, 0x59, 0x13, 0xe2, 0x7b, 0xdc, 0xb8, 0x0e, 0x75, + 0xdd, 0x96, 0x7d, 0x63, 0x52, 0xd9, 0x9b, 0x8d, 0xb1, 0xa0, 0x8f, 0x81, + 0x7e, 0x5f, 0x67, 0xfe, 0xae, 0x20, 0x58, 0xb3, 0x54, 0xe1, 0x9c, 0x98, + 0x3b, 0xed, 0x13, 0x2c, 0x47, 0x91, 0x38, 0x05, 0x0c, 0x24, 0x20, 0x03, + 0xc7, 0x83, 0x2f, 0xde, 0x76, 0xd3, 0xa1, 0xfc, 0x83, 0x65, 0xc2, 0xae, + 0xc6, 0x7f, 0xda, 0x0d, 0x68, 0xa1, 0x03, 0xce, 0x54, 0x75, 0x97, 0xe1, + 0x46, 0x7c, 0xd7, 0x9b, 0x9e, 0x0f, 0xed, 0x17, 0xb1, 0xf9, 0x7a, 0x86, + 0xc5, 0x54, 0x8b, 0xd3, 0x92, 0xac, 0x91, 0x83, 0x1e, 0xa2, 0x81, 0xcc, + 0xe8, 0x94, 0x3e, 0xaf, 0x17, 0x33, 0x37, 0x2f, 0x2b, 0x1f, 0x88, 0x75, + 0x27, 0x84, 0xda, 0x89, 0x72, 0x10, 0x9a, 0x13, 0x03, 0x19, 0x9e, 0x69, + 0x1f, 0x03, 0x3a, 0xb4, 0x2b, 0xaf, 0x1c, 0xf4, 0x4e, 0xf4, 0x26, 0xc6, + 0x14, 0x02, 0xf4, 0x4c, 0x2d, 0x90, 0xe5, 0x8c, 0x95, 0x8f, 0xf5, 0xf9, + 0x1e, 0x38, 0x1f, 0xc7, 0x57, 0x45, 0xdd, 0xab, 0x14, 0x24, 0x1e, 0x16, + 0xf3, 0x1c, 0x7b, 0xeb, 0x60, 0x3e, 0xa9, 0x75, 0xe4, 0xbd, 0xe7, 0xa7, + 0x66, 0x72, 0x2e, 0xec, 0xa1, 0x6a, 0x9d, 0xc9, 0x3c, 0x79, 0xb4, 0x07, + 0x95, 0x48, 0x88, 0x21, 0xa1, 0xf5, 0x33, 0x26, 0x34, 0x54, 0xf3, 0xc5, + 0x44, 0x1a, 0x61, 0xea, 0x27, 0x82, 0x84, 0xe4, 0x7e, 0xa9, 0x06, 0x1e, + 0x49, 0xc7, 0x1a, 0x62, 0x8c, 0x84, 0x33, 0x79, 0xcd, 0xa5, 0xb3, 0xb9, + 0x4f, 0x1d, 0x1f, 0xab, 0x89, 0x3b, 0xbc, 0x08, 0x64, 0x78, 0x31, 0xd1, + 0x9d, 0x5e, 0x60, 0x8a, 0x08, 0xf7, 0x31, 0xe7, 0xb3, 0x88, 0x65, 0x73, + 0x01, 0x46, 0x02, 0x8c, 0xcc, 0xa4, 0x8a, 0x07, 0x2e, 0x59, 0x5f, 0x3c, + 0x16, 0xcc, 0xda, 0x51, 0x69, 0x04, 0x20, 0xd5, 0x14, 0x8c, 0x26, 0x34, + 0xbe, 0x39, 0x00, 0x8c, 0x60, 0xc6, 0x83, 0xd0, 0x93, 0x99, 0xf7, 0x29, + 0x81, 0x0c, 0x31, 0x21, 0x0f, 0x32, 0xc7, 0x00, 0x48, 0x25, 0x9f, 0xb3, + 0x84, 0x89, 0xe1, 0x3e, 0x90, 0xf8, 0x0d, 0x66, 0x4e, 0xed, 0xc5, 0x3e, + 0xd3, 0x14, 0xce, 0x55, 0x3e, 0xf6, 0x0d, 0xc5, 0x6d, 0xe3, 0xad, 0x68, + 0x8a, 0x07, 0x19, 0xf1, 0x8a, 0xca, 0x28, 0xf3, 0x6b, 0x54, 0x31, 0x97, + 0x8c, 0xf2, 0x90, 0xc2, 0x17, 0xef, 0x13, 0x63, 0x8d, 0xbd, 0x29, 0x8a, + 0x46, 0x48, 0x63, 0xe5, 0xa5, 0x65, 0xf8, 0x19, 0x92, 0xc5, 0x6d, 0x3a, + 0x95, 0xd9, 0xce, 0xdc, 0x03, 0x01, 0x9c, 0x28, 0x55, 0x32, 0x49, 0x24, + 0x0f, 0x39, 0x5d, 0x66, 0x55, 0xac, 0x5b, 0x4d, 0xc3, 0xa7, 0xe7, 0x70, + 0x9c, 0x57, 0x42, 0xbc, 0x95, 0xa6, 0xa2, 0xc0, 0xa2, 0x4f, 0x64, 0xef, + 0x38, 0x20, 0xce, 0x2a, 0x0b, 0xf1, 0x74, 0x7f, 0x6f, 0x94, 0xf7, 0xac, + 0xa0, 0xaf, 0xd3, 0x97, 0xbc, 0xb5, 0x8a, 0x81, 0x18, 0xd8, 0x74, 0x28, + 0x50, 0xf9, 0xfe, 0xdb, 0x69, 0x9a, 0xfc, 0xb5, 0x3a, 0xbc, 0xa2, 0x89, + 0x74, 0xb3, 0x92, 0xf0, 0x05, 0x5f, 0xde, 0xd1, 0x0b, 0xea, 0xc1, 0x23, + 0x31, 0x87, 0xed, 0x24, 0x67, 0x38, 0x00, 0x3f, 0x38, 0xde, 0xba, 0x70, + 0xbc, 0x57, 0x90, 0x30, 0xa0, 0x66, 0x32, 0x53, 0x43, 0xb2, 0x78, 0x50, + 0xf3, 0x28, 0x06, 0xf9, 0x94, 0xba, 0x7b, 0xbd, 0xf6, 0x7b, 0x6f, 0xfd, + 0xce, 0x5f, 0xae, 0xc3, 0x1c, 0x3f, 0x4b, 0x66, 0x25, 0xa2, 0x27, 0x49, + 0xe6, 0xed, 0x0a, 0x22, 0x84, 0xeb, 0x22, 0xf8, 0xf6, 0xb3, 0xf1, 0xdf, + 0x9b, 0xa7, 0x17, 0x07, 0x28, 0xd3, 0xc4, 0x93, 0x46, 0x41, 0x06, 0x19, + 0x39, 0x04, 0x7c, 0x41, 0x16, 0x66, 0xf0, 0x7b, 0x0a, 0x6e, 0x3b, 0xc7, + 0x3a, 0xc9, 0x3e, 0x3d, 0x5d, 0x2f, 0x4d, 0xdd, 0xea, 0x14, 0x0e, 0x50, + 0x22, 0x8e, 0x2e, 0x1f, 0x64, 0x4f, 0x0d, 0x58, 0x07, 0x37, 0x5d, 0x84, + 0x45, 0x69, 0xdc, 0x43, 0xa8, 0x18, 0xd3, 0x92, 0x32, 0x42, 0x68, 0x1a, + 0xb1, 0x4b, 0x16, 0x70, 0xab, 0x94, 0xa2, 0x89, 0xd6, 0xdc, 0xf7, 0x5f, + 0xe0, 0x0f, 0xf6, 0xd7, 0x3a, 0xe6, 0x1e, 0x46, 0xca, 0x30, 0xa9, 0xa1, + 0x90, 0x32, 0xa0, 0x5f, 0x88, 0x27, 0x41, 0x1f, 0xa8, 0x34, 0xd9, 0xe7, + 0x49, 0x27, 0x68, 0xba, 0x5b, 0x1d, 0x75, 0x13, 0xc9, 0x9c, 0x96, 0x4f, + 0xc1, 0x37, 0x39, 0xdf, 0xae, 0x4d, 0x6b, 0xe4, 0x84, 0x63, 0x11, 0xf1, + 0x50, 0x08, 0xf8, 0xc8, 0x50, 0xb1, 0xbe, 0xdf, 0x52, 0x69, 0x89, 0x8a, + 0x9d, 0xb9, 0x96, 0x30, 0x23, 0x22, 0x18, 0x43, 0x8a, 0xf4, 0xbb, 0x46, + 0xed, 0x72, 0x67, 0x08, 0x5c, 0x7a, 0x9f, 0xa8, 0x18, 0xf8, 0xc1, 0x21, + 0x34, 0x67, 0xe9, 0xfa, 0xad, 0xc8, 0x53, 0x18, 0x50, 0x12, 0xa1, 0x21, + 0x33, 0x92, 0xf0, 0x89, 0xf5, 0x65, 0xfc, 0xba, 0x8a, 0x18, 0xba, 0xba, + 0x66, 0x06, 0x3e, 0x64, 0x68, 0xb6, 0x83, 0xcf, 0x79, 0x75, 0xf9, 0x90, + 0x86, 0x4b, 0xc5, 0x5f, 0xff, 0x6c, 0xa3, 0xab, 0x8a, 0x43, 0x28, 0xf4, + 0x7d, 0x4e, 0x69, 0x13, 0x30, 0x32, 0xea, 0xf4, 0xea, 0xd8, 0xc7, 0xf4, + 0xcb, 0xff, 0x4b, 0xd3, 0x8a, 0x36, 0x0c, 0xf0, 0x1f, 0x01, 0x4c, 0xd7, + 0x41, 0x20, 0xc4, 0xde, 0xc7, 0xa5, 0x76, 0xf0, 0x65, 0xf3, 0x03, 0x10, + 0x8e, 0xda, 0x7f, 0xd9, 0x89, 0x47, 0xce, 0x11, 0x88, 0x45, 0x36, 0x9d, + 0x4c, 0x65, 0x5b, 0xea, 0xc5, 0xe5, 0x87, 0x75, 0x29, 0xd4, 0xff, 0x15, + 0x4f, 0x7a, 0x3c, 0x4d, 0x07, 0x62, 0x8e, 0xab, 0x73, 0x26, 0x50, 0x02, + 0xc6, 0x11, 0xf3, 0x34, 0x3b, 0x82, 0x52, 0xb1, 0xe1, 0x64, 0x9e, 0x9b, + 0xff, 0x10, 0x40, 0x08, 0x0e, 0x34, 0x01, 0x33, 0x82, 0x6f, 0x4b, 0x46, + 0x80, 0x42, 0xb2, 0xb1, 0x45, 0xdd, 0xed, 0x99, 0x39, 0x18, 0x28, 0xbc, + 0xa8, 0xe1, 0xf1, 0x90, 0x4b, 0xfa, 0xf2, 0x6a, 0x9c, 0xa2, 0x06, 0xdc, + 0xfe, 0x97, 0x20, 0x51, 0x24, 0xb8, 0x07, 0x1a, 0x1c, 0x7d, 0xa4, 0x7b, + 0x68, 0x93, 0x9e, 0x2e, 0x4c, 0x3b, 0xd9, 0xae, 0x77, 0x97, 0x40, 0xd2, + 0xd4, 0x92, 0x51, 0x39, 0x2a, 0x19, 0x10, 0x05, 0x91, 0xfc, 0x7f, 0x96, + 0x34, 0x80, 0x4b, 0x8c, 0x0c, 0x61, 0x46, 0x8f, 0xd1, 0xf7, 0x62, 0xad, + 0x6a, 0xfd, 0x78, 0xb9, 0x9d, 0x45, 0x8c, 0x95, 0x44, 0x21, 0xdc, 0x35, + 0xa9, 0x92, 0x31, 0xb5, 0x06, 0x1a, 0x79, 0x46, 0x16, 0x28, 0x51, 0x4b, + 0x48, 0x56, 0x68, 0x31, 0x45, 0x46, 0xcd, 0x05, 0x0a, 0x18, 0x7c, 0x9f, + 0x64, 0xec, 0xb6, 0x6a, 0xf4, 0xed, 0x0f, 0x86, 0xd0, 0x28, 0x24, 0x5e, + 0x86, 0x1c, 0xa5, 0x61, 0x03, 0x95, 0x39, 0x40, 0x17, 0xf9, 0x82, 0xd3, + 0xf8, 0xc5, 0x2a, 0x8c, 0xde, 0x73, 0xc3, 0x7a, 0x7b, 0x91, 0x61, 0x86, + 0x83, 0x09, 0xcf, 0xb0, 0x74, 0x3e, 0x7a, 0xc7, 0xe6, 0x76, 0x47, 0x2a, + 0xf4, 0x7c, 0xe7, 0x0c, 0xc2, 0x63, 0x64, 0xc6, 0x57, 0x80, 0x17, 0x08, + 0x14, 0x17, 0xe7, 0x21, 0xdb, 0x66, 0x54, 0x18, 0x88, 0x0b, 0x65, 0x42, + 0x97, 0x46, 0x7d, 0x91, 0x26, 0x5e, 0x59, 0x3c, 0x48, 0x06, 0xbc, 0x20, + 0x66, 0x89, 0x39, 0x64, 0xd6, 0x5a, 0x7a, 0x05, 0x10, 0x89, 0x44, 0x4a, + 0x73, 0x98, 0x3e, 0x9f, 0xb0, 0xc3, 0x3c, 0xea, 0x77, 0x95, 0xc6, 0xc5, + 0x5b, 0x08, 0x07, 0x2b, 0xaa, 0x63, 0x25, 0x4c, 0xf6, 0xa7, 0x08, 0xf9, + 0x42, 0x4c, 0xc7, 0xa9, 0xe9, 0x58, 0x0a, 0x9e, 0x4a, 0x0e, 0xf6, 0x2b, + 0xf5, 0x35, 0x20, 0x55, 0x65, 0x46, 0xda, 0x32, 0xdc, 0xb5, 0x29, 0x4a, + 0x79, 0x2a, 0x1e, 0x20, 0xa3, 0x3f, 0xfb, 0x5c, 0xf7, 0xce, 0x5f, 0x3b, + 0x96, 0xb9, 0x16, 0xf4, 0x6f, 0xe9, 0x5b, 0x63, 0x86, 0x85, 0xbe, 0x7f, + 0xe8, 0x3b, 0x30, 0xdb, 0xc0, 0xd4, 0xeb, 0xf8, 0xcd, 0x40, 0x4e, 0x72, + 0x1f, 0x37, 0x74, 0xb7, 0x28, 0x93, 0xe2, 0x0d, 0xdf, 0x5b, 0x9f, 0xa0, + 0x1b, 0x82, 0x13, 0x2d, 0x52, 0x3b, 0xdd, 0x17, 0x32, 0x93, 0x36, 0x82, + 0x5f, 0x68, 0x3c, 0x1d, 0xf3, 0x54, 0xcd, 0x2e, 0x24, 0x5f, 0xcb, 0x73, + 0x5e, 0xf1, 0x31, 0xf7, 0xb5, 0x3d, 0x6c, 0x43, 0x65, 0x2a, 0x8d, 0xf9, + 0x05, 0xb2, 0xa4, 0x67, 0x46, 0x50, 0x65, 0x8a, 0xb0, 0xcc, 0xbf, 0xea, + 0xa5, 0x46, 0xfd, 0x39, 0xb7, 0x75, 0xa8, 0x8f, 0xd3, 0x91, 0x5a, 0x79, + 0x98, 0x2b, 0x7b, 0xa3, 0x97, 0x49, 0xa1, 0x08, 0xb4, 0x62, 0x97, 0x58, + 0x13, 0x9b, 0xef, 0x5e, 0x7e, 0xfd, 0x23, 0xf7, 0x6f, 0xf2, 0xfc, 0x79, + 0x9f, 0x5a, 0x56, 0x33, 0x0d, 0x73, 0x67, 0x9a, 0x9b, 0xed, 0xc0, 0x30, + 0xe2, 0xa3, 0x5e, 0x12, 0x91, 0x3f, 0x68, 0x95, 0xbf, 0x77, 0xfd, 0xd4, + 0x4d, 0x8b, 0xd5, 0xf6, 0xb1, 0x4c, 0x95, 0xb7, 0x50, 0xba, 0xb5, 0xf1, + 0x06, 0x33, 0xd2, 0x9b, 0x32, 0x8b, 0xb9, 0x34, 0x4b, 0xe3, 0x4c, 0x91, + 0xdc, 0x27, 0xd7, 0xa9, 0x61, 0xe2, 0xfb, 0x41, 0xf7, 0xf6, 0xb9, 0x67, + 0x3d, 0x38, 0x5a, 0xc7, 0xf5, 0x62, 0xae, 0x9b, 0x86, 0x65, 0x29, 0xa8, + 0x90, 0x03, 0x3a, 0x27, 0x48, 0xe2, 0x63, 0x0c, 0xaf, 0xa8, 0x26, 0xfd, + 0x8f, 0xee, 0xb7, 0x22, 0xa9, 0x97, 0x6d, 0x8b, 0xe7, 0x56, 0x56, 0xec, + 0x50, 0x9d, 0x18, 0x20, 0x59, 0xc8, 0x4c, 0x9d, 0xe8, 0xfd, 0x86, 0x6e, + 0xb9, 0xfd, 0xa6, 0x95, 0x30, 0x02, 0xa9, 0x4b, 0xb0, 0x83, 0x51, 0x8f, + 0x6d, 0x00, 0x75, 0xd1, 0x37, 0x85, 0x47, 0xec, 0x75, 0xb3, 0xab, 0xb3, + 0xf4, 0xd3, 0x62, 0x2d, 0x95, 0x0f, 0xe6, 0xd6, 0xbb, 0x49, 0xc2, 0x08, + 0x77, 0x4b, 0x91, 0x18, 0xc2, 0xb3, 0x90, 0x99, 0x90, 0x81, 0x2b, 0xc9, + 0xba, 0x79, 0xe3, 0xca, 0x1b, 0x71, 0x5a, 0x6d, 0xbc, 0xd9, 0x98, 0x92, + 0xba, 0x7b, 0xe5, 0xeb, 0x9b, 0x29, 0xde, 0x6e, 0x85, 0x20, 0x10, 0x82, + 0xb0, 0x0a, 0x73, 0x3a, 0xd1, 0xf6, 0x58, 0x5a, 0xd7, 0xc6, 0xb6, 0x29, + 0x42, 0xca, 0x32, 0x3b, 0x04, 0xa2, 0xd4, 0x09, 0x93, 0xf6, 0xb9, 0x2a, + 0x12, 0xfb, 0x52, 0x22, 0xfc, 0xbe, 0x66, 0xb3, 0x71, 0xd1, 0xdc, 0xe6, + 0xf5, 0xd4, 0x09, 0xea, 0xd5, 0x57, 0x35, 0x1d, 0x00, 0x09, 0x44, 0xcc, + 0x94, 0x65, 0x4a, 0x52, 0xee, 0x44, 0xb5, 0x26, 0xe3, 0x8c, 0xef, 0x61, + 0x65, 0x73, 0x37, 0xed, 0x4b, 0x8c, 0xa4, 0x08, 0x32, 0x87, 0x21, 0xd1, + 0x26, 0xad, 0xbf, 0xb4, 0xf6, 0x4e, 0x57, 0x4e, 0x53, 0xa2, 0xed, 0x3c, + 0xdd, 0xda, 0x70, 0x93, 0xd3, 0x12, 0x9d, 0x69, 0x85, 0x02, 0x06, 0x3c, + 0x27, 0x27, 0x0b, 0xc9, 0x21, 0xe0, 0x7f, 0xf6, 0xb1, 0x38, 0xe9, 0xbd, + 0x22, 0x14, 0xd8, 0x83, 0x79, 0x36, 0x90, 0x08, 0x76, 0x50, 0xb0, 0xab, + 0xc6, 0xd6, 0x75, 0xe5, 0x32, 0x3f, 0xcf, 0xc7, 0x05, 0x7e, 0x98, 0x9b, + 0xe4, 0x1b, 0xda, 0x72, 0x06, 0xc2, 0x45, 0x5e, 0x9b, 0xf6, 0x6d, 0xcb, + 0xe7, 0x82, 0x8c, 0xc7, 0xff, 0x56, 0xdc, 0xb2, 0x2f, 0xee, 0x6d, 0xe0, + 0xd3, 0x5d, 0x87, 0xcc, 0x8a, 0xbc, 0xe3, 0xb5, 0xa3, 0xe9, 0xb2, 0x89, + 0x82, 0x60, 0xb7, 0x73, 0x74, 0xb0, 0xf0, 0x3b, 0x28, 0x20, 0xb0, 0x1e, + 0xe3, 0x3f, 0x8b, 0x7f, 0xf7, 0xf6, 0x43, 0x4d, 0x33, 0xb2, 0x02, 0x27, + 0x4d, 0x8d, 0x80, 0xfc, 0xd1, 0xe0, 0x24, 0xe7, 0x82, 0xdf, 0xe9, 0x1c, + 0x62, 0x34, 0xd2, 0x9b, 0xd1, 0x9a, 0x5f, 0x61, 0x6a, 0xd4, 0xd9, 0x8f, + 0x5c, 0x8e, 0xa3, 0x19, 0x6b, 0xd2, 0xda, 0x16, 0x54, 0xc4, 0xf8, 0xb1, + 0x95, 0x48, 0x3e, 0x26, 0x5c, 0x27, 0x1c, 0xf2, 0xd2, 0x0d, 0x36, 0x3f, + 0x69, 0x9e, 0x6d, 0x81, 0x86, 0x1f, 0x50, 0xcd, 0xa9, 0x76, 0x08, 0xe1, + 0xd3, 0xb0, 0xda, 0xfb, 0xd8, 0x5d, 0x93, 0xb1, 0x8e, 0x6d, 0x14, 0xed, + 0xdf, 0xf7, 0x57, 0xff, 0xff, 0x8c, 0x4d, 0x15, 0x36, 0x21, 0x87, 0x64, + 0xb0, 0x67, 0xe5, 0x89, 0x90, 0x9a, 0x26, 0x86, 0xa5, 0x2c, 0x20, 0xc3, + 0xcd, 0x4b, 0x7c, 0x6c, 0xc0, 0xfa, 0x40, 0xca, 0x08, 0x65, 0xa3, 0x40, + 0x31, 0x9a, 0x59, 0xfb, 0x46, 0xd7, 0xe7, 0xda, 0xa1, 0x46, 0x9b, 0x3c, + 0x05, 0x40, 0x11, 0x5e, 0x7e, 0xd5, 0x8e, 0x58, 0xaf, 0x43, 0x0c, 0x86, + 0x5f, 0x88, 0x37, 0x81, 0x4e, 0x7c, 0xea, 0xdf, 0x32, 0xde, 0x9d, 0x7f, + 0x43, 0x1c, 0x15, 0x96, 0x10, 0xe4, 0xe8, 0x50, 0xab, 0x6f, 0x37, 0x6a, + 0xf7, 0x6c, 0x68, 0x21, 0xda, 0x19, 0x5d, 0x2d, 0xc7, 0x9d, 0xcc, 0x88, + 0x18, 0x8c, 0xe3, 0x00, 0x68, 0x05, 0x1c, 0xa2, 0x6a, 0xc3, 0xaf, 0xbd, + 0xd1, 0xb3, 0xc5, 0xba, 0xa5, 0xb7, 0xc6, 0x91, 0xf3, 0x4f, 0x1c, 0xba, + 0x10, 0x23, 0x21, 0x2a, 0x4e, 0xd8, 0xf9, 0x72, 0xf1, 0x3a, 0x7b, 0xab, + 0x9c, 0x2d, 0xec, 0x6f, 0x2b, 0x15, 0xcb, 0x38, 0xa6, 0x60, 0x83, 0x5a, + 0x08, 0x9d, 0xed, 0x67, 0xb5, 0x27, 0x2b, 0xb9, 0x0b, 0xa0, 0x8f, 0xf6, + 0xfd, 0x68, 0x27, 0xe6, 0xbb, 0x6b, 0x53, 0x86, 0x30, 0x14, 0x1b, 0x89, + 0x51, 0x39, 0x5b, 0x38, 0x60, 0xce, 0x8d, 0x65, 0xc7, 0x81, 0xbd, 0x5e, + 0xd1, 0x08, 0xdd, 0x65, 0x15, 0x1d, 0xff, 0xfa, 0x86, 0x2d, 0x9c, 0x1d, + 0xf3, 0x01, 0xc3, 0xc3, 0x38, 0x6a, 0x9a, 0x65, 0x38, 0xc2, 0x82, 0x38, + 0xef, 0xe3, 0x70, 0xc2, 0xc9, 0xf3, 0xc3, 0x99, 0x75, 0x14, 0xa9, 0x85, + 0x21, 0x5a, 0xd2, 0xd0, 0xd0, 0x4a, 0x26, 0x31, 0xc7, 0x90, 0xee, 0x41, + 0x9a, 0x8f, 0xbf, 0x9d, 0xaf, 0x4b, 0x7b, 0x56, 0x23, 0x6e, 0xbf, 0x6b, + 0x87, 0x1a, 0x56, 0x91, 0xe5, 0xec, 0xf9, 0xbe, 0xe1, 0x51, 0xaf, 0x50, + 0xcb, 0xee, 0x4e, 0x33, 0xdf, 0xb3, 0xbe, 0x8e, 0xed, 0x7a, 0x47, 0x12, + 0x0e, 0x28, 0xa8, 0xe3, 0x41, 0xb0, 0xdb, 0x12, 0xaf, 0x10, 0x0e, 0x32, + 0x13, 0x99, 0xf9, 0xf0, 0xf5, 0x48, 0x61, 0xa2, 0xec, 0x3a, 0x8c, 0x5c, + 0xa8, 0xab, 0xef, 0x77, 0xea, 0xe2, 0x8a, 0xc8, 0xb3, 0x8d, 0xcf, 0x70, + 0xf0, 0x4d, 0x7e, 0x1c, 0xa2, 0x40, 0x6a, 0x28, 0x50, 0x3e, 0x29, 0x5f, + 0x76, 0x05, 0x99, 0x90, 0x18, 0xf8, 0x48, 0xa8, 0xb5, 0x77, 0xd9, 0xb8, + 0xd5, 0xba, 0x6a, 0x58, 0xdb, 0x83, 0x72, 0x62, 0xee, 0xfa, 0x70, 0x4b, + 0x97, 0x4b, 0x45, 0x00, 0x68, 0xc1, 0x23, 0xdc, 0x09, 0xd8, 0x3c, 0xca, + 0xb8, 0x73, 0xab, 0x6d, 0x6e, 0x27, 0x95, 0xcd, 0x42, 0x2f, 0x51, 0x2e, + 0x70, 0x65, 0x1a, 0x06, 0x67, 0x1b, 0x09, 0xf6, 0xf0, 0x02, 0x40, 0x59, + 0x3a, 0x77, 0x1b, 0x9d, 0x52, 0x3e, 0x46, 0xc7, 0x5a, 0x4e, 0xdc, 0xa6, + 0x6e, 0x3f, 0x6c, 0xdc, 0x82, 0x1b, 0x16, 0x66, 0x43, 0x23, 0x32, 0xab, + 0x27, 0x78, 0xb1, 0x5d, 0xad, 0x54, 0x48, 0x9a, 0x3e, 0x7b, 0x49, 0x60, + 0x6d, 0x2d, 0xd9, 0xbf, 0x29, 0xa1, 0xa7, 0xb7, 0x34, 0x09, 0x94, 0xa0, + 0x64, 0xbf, 0x04, 0xf7, 0x8f, 0x5b, 0x71, 0xfa, 0xa5, 0x9c, 0xdb, 0x43, + 0x1c, 0x0c, 0x66, 0x7b, 0x21, 0xd3, 0xe3, 0x69, 0x6e, 0xf8, 0x67, 0x04, + 0x3c, 0xb1, 0xa6, 0x7c, 0x57, 0xea, 0x83, 0x08, 0x45, 0x2e, 0x5d, 0x1a, + 0x8d, 0x02, 0xe4, 0xe5, 0xfc, 0x61, 0x50, 0x61, 0x13, 0x9b, 0x6e, 0x54, + 0x28, 0x0a, 0x09, 0xd7, 0x97, 0x2c, 0x72, 0x27, 0xb6, 0xa8, 0xe5, 0x43, + 0x27, 0x29, 0xcf, 0xc4, 0x05, 0x2b, 0x78, 0xed, 0x69, 0xe0, 0x20, 0x48, + 0x8c, 0x02, 0x5f, 0x40, 0x71, 0xfd, 0x39, 0xbe, 0x2f, 0xbb, 0xeb, 0xde, + 0xbd, 0xb4, 0x2f, 0x97, 0xa0, 0xcc, 0xdb, 0xed, 0x1c, 0x73, 0x5e, 0x70, + 0x32, 0xdf, 0x45, 0xcc, 0xf2, 0xbe, 0x80, 0xed, 0xf6, 0xce, 0x60, 0xeb, + 0x66, 0x4a, 0x4b, 0x17, 0x87, 0xf1, 0x8c, 0x46, 0x0b, 0x5a, 0x74, 0x13, + 0xcf, 0x51, 0x4c, 0xfa, 0x37, 0xb8, 0xe7, 0xf7, 0xf8, 0xbf, 0xb7, 0x0e, + 0xee, 0x74, 0xff, 0x3e, 0x35, 0x0c, 0x3e, 0x5b, 0x64, 0x82, 0x27, 0x63, + 0x27, 0x24, 0xa1, 0xf6, 0x0d, 0x99, 0xae, 0x3a, 0xe7, 0xe2, 0xf7, 0xdc, + 0x47, 0x45, 0x00, 0x93, 0x0d, 0x9b, 0x37, 0xba, 0xce, 0x1c, 0x80, 0x44, + 0x81, 0x4a, 0x28, 0x9a, 0xc1, 0xce, 0x2d, 0x49, 0xea, 0xe2, 0x73, 0xe7, + 0xb0, 0x4c, 0xe3, 0x0d, 0x4e, 0xf7, 0x9a, 0x5c, 0x1d, 0xa0, 0xa2, 0xf4, + 0x06, 0x12, 0x0f, 0x3d, 0x2d, 0x3f, 0xb7, 0xe5, 0xbf, 0xff, 0x60, 0x84, + 0x94, 0x7a, 0xef, 0xce, 0xd2, 0x15, 0x1a, 0x80, 0x75, 0x18, 0x28, 0xb0, + 0x9a, 0x08, 0x48, 0x43, 0x84, 0x6f, 0x83, 0xdb, 0xb0, 0xd0, 0x51, 0xf5, + 0x15, 0x19, 0xc2, 0xc2, 0x53, 0xf9, 0xbf, 0x93, 0x37, 0xfc, 0xcb, 0x3a, + 0x2f, 0x16, 0x6a, 0x54, 0x67, 0xa7, 0xa6, 0xe4, 0xd1, 0x25, 0xe0, 0x30, + 0x06, 0x13, 0x00, 0x0a, 0x2e, 0x11, 0xf1, 0x33, 0x9e, 0xb4, 0xe7, 0x1c, + 0xe3, 0x0c, 0x91, 0xfb, 0x52, 0x62, 0x46, 0xcd, 0xed, 0x77, 0x12, 0xff, + 0x15, 0x7b, 0xd7, 0x3b, 0x22, 0xcd, 0xd7, 0xf4, 0x0c, 0xe1, 0x85, 0x68, + 0x0a, 0x24, 0xd0, 0x07, 0x0e, 0xf5, 0x68, 0x5d, 0x55, 0xb5, 0xe3, 0x28, + 0x68, 0x23, 0x40, 0xec, 0x0d, 0x94, 0x8c, 0xa8, 0x09, 0x77, 0x16, 0xe5, + 0xab, 0xc5, 0xe8, 0x53, 0xe2, 0xc1, 0xce, 0x5c, 0xa9, 0x55, 0x10, 0xea, + 0x9b, 0x3e, 0x8a, 0x1d, 0xae, 0x60, 0x1d, 0x09, 0xc7, 0xf7, 0xf5, 0xca, + 0x92, 0x02, 0x5f, 0x35, 0x96, 0x74, 0x72, 0x85, 0x29, 0xf8, 0x04, 0x20, + 0x70, 0xf7, 0xb9, 0x34, 0x46, 0x3a, 0xb2, 0x92, 0x05, 0x1f, 0xa3, 0x05, + 0x5d, 0xb0, 0x10, 0x15, 0xbe, 0x01, 0x21, 0x03, 0x57, 0x46, 0xef, 0x43, + 0x80, 0x10, 0xc9, 0x78, 0xf2, 0x33, 0x39, 0xd3, 0xc0, 0x6a, 0x92, 0xd9, + 0x69, 0x22, 0xbf, 0xd9, 0xd1, 0xf4, 0xda, 0xb5, 0xe9, 0xe8, 0x65, 0x1a, + 0x60, 0x3b, 0x19, 0xbd, 0x44, 0xe8, 0x89, 0x77, 0x28, 0xb9, 0xbb, 0xcd, + 0x2d, 0xfb, 0x7b, 0xf0, 0x74, 0x32, 0xbf, 0x6f, 0x4c, 0x74, 0xf8, 0x0a, + 0x0f, 0x31, 0x24, 0x51, 0xfa, 0x01, 0x51, 0xe3, 0x8d, 0x4f, 0xfe, 0x08, + 0x8d, 0x02, 0xd8, 0x71, 0xa3, 0xfd, 0xc8, 0x19, 0x7b, 0xd1, 0x87, 0x6c, + 0x72, 0x73, 0x7f, 0x9e, 0x31, 0xb7, 0xbf, 0xc3, 0x6f, 0xcf, 0xd3, 0xd9, + 0x7a, 0x3a, 0x76, 0xc5, 0xe5, 0xb9, 0x7b, 0x20, 0x13, 0xa3, 0x2d, 0xa1, + 0x7a, 0xa2, 0x60, 0x49, 0xfd, 0xba, 0x2f, 0x2c, 0xb9, 0x48, 0x49, 0xfe, + 0x80, 0x8e, 0xc4, 0xd0, 0x96, 0x92, 0xf7, 0x0e, 0x4e, 0x6d, 0x8c, 0x32, + 0x1a, 0x3f, 0x14, 0xf8, 0x2d, 0x63, 0x44, 0x1d, 0x1d, 0xba, 0xc2, 0xcc, + 0xa6, 0x36, 0x8b, 0x48, 0xd5, 0xea, 0x8e, 0x87, 0xce, 0x0c, 0xfb, 0x46, + 0x0e, 0xb9, 0xa4, 0x68, 0x0c, 0x9f, 0xa6, 0xb3, 0xfd, 0x39, 0xad, 0x69, + 0x2e, 0x53, 0x48, 0x9c, 0x02, 0xac, 0x51, 0xd8, 0x19, 0x24, 0x82, 0x1e, + 0x24, 0x91, 0x52, 0x0f, 0xba, 0x53, 0x25, 0x07, 0x0e, 0x83, 0xe0, 0x09, + 0x72, 0xa2, 0x32, 0x2c, 0xee, 0x0e, 0x88, 0x5b, 0x42, 0x25, 0x3c, 0x69, + 0xb7, 0xc5, 0x9a, 0x07, 0xc0, 0x6b, 0x94, 0x28, 0x01, 0x39, 0x34, 0xd1, + 0xab, 0xf4, 0x32, 0x55, 0x82, 0x3c, 0x07, 0x2a, 0x11, 0x7a, 0x10, 0xc9, + 0x55, 0xaa, 0x84, 0x39, 0xd8, 0x3c, 0x4e, 0x09, 0x65, 0xe9, 0x03, 0x39, + 0xd0, 0xf1, 0x79, 0x70, 0x83, 0x07, 0x68, 0x72, 0x4f, 0x3f, 0x8e, 0x05, + 0xe1, 0x41, 0xe4, 0xf8, 0x1b, 0xc6, 0x13, 0xd4, 0x95, 0xed, 0xe5, 0x2f, + 0xab, 0x97, 0xaf, 0xa9, 0x6b, 0x59, 0x3c, 0x09, 0xe3, 0x3d, 0x26, 0xdb, + 0x04, 0x72, 0x19, 0x05, 0x28, 0x1f, 0x00, 0x67, 0x29, 0x2a, 0xe1, 0x7b, + 0xdb, 0x8b, 0xfb, 0x71, 0xde, 0x13, 0x5f, 0xe1, 0xb6, 0x91, 0x99, 0x90, + 0x99, 0x4a, 0xf8, 0xf0, 0x79, 0xe2, 0x2d, 0x76, 0x9b, 0x1e, 0x29, 0xed, + 0xf7, 0x8b, 0xa2, 0x1c, 0xf9, 0xec, 0xde, 0xf4, 0x35, 0x40, 0xca, 0x4c, + 0xf0, 0x30, 0x4a, 0xcb, 0x9f, 0x72, 0x0f, 0xfe, 0x06, 0xcd, 0x54, 0xb0, + 0x5d, 0x30, 0x59, 0xd6, 0x0d, 0x7e, 0x7e, 0x71, 0x45, 0xb6, 0xc3, 0xac, + 0x5b, 0x76, 0xa7, 0xc6, 0x67, 0x08, 0x2d, 0xd1, 0xa7, 0x32, 0x1a, 0x90, + 0x83, 0xc1, 0x55, 0x6a, 0xca, 0x9c, 0x8e, 0xb3, 0x7b, 0x8f, 0xc5, 0x05, + 0x4f, 0x91, 0xef, 0xee, 0xa5, 0x7d, 0xcd, 0xd6, 0xb0, 0xad, 0xc1, 0x94, + 0x98, 0x20, 0x04, 0x26, 0x54, 0xd6, 0x72, 0xb4, 0x28, 0xe4, 0xe4, 0xdf, + 0x43, 0x7e, 0xfd, 0x15, 0x17, 0x8d, 0xd9, 0xd4, 0x62, 0xa9, 0x62, 0x47, + 0x6d, 0x32, 0x26, 0x11, 0x41, 0x04, 0x6f, 0x50, 0x3c, 0xd2, 0x9a, 0xeb, + 0x76, 0x2e, 0x7e, 0xcf, 0xfe, 0xbc, 0xbd, 0xae, 0x5f, 0x23, 0x77, 0x86, + 0x9c, 0xf1, 0x99, 0xa7, 0x8c, 0xd9, 0x21, 0x58, 0x07, 0x9b, 0x3b, 0xfa, + 0xe4, 0xc1, 0x72, 0xd9, 0x01, 0xc5, 0xe5, 0xb8, 0xc0, 0xe8, 0xb9, 0x11, + 0x96, 0xcf, 0x39, 0x8c, 0x8a, 0x77, 0x3e, 0xd7, 0x8d, 0x27, 0xf1, 0x0b, + 0xfc, 0xa0, 0xa7, 0x7a, 0x61, 0x44, 0xcc, 0xfc, 0x15, 0xea, 0x0b, 0xf7, + 0x74, 0x9b, 0xa7, 0xda, 0x73, 0x9b, 0xec, 0x62, 0x43, 0x19, 0xbb, 0x16, + 0xba, 0x0d, 0x1e, 0xd6, 0xa1, 0x4c, 0xbd, 0x58, 0xac, 0xcf, 0x79, 0x9d, + 0xf2, 0xbd, 0xfa, 0x9c, 0xfd, 0x79, 0x81, 0x0c, 0x7d, 0xb8, 0xe9, 0xf9, + 0x99, 0x64, 0xee, 0xa9, 0xa4, 0xe9, 0xcc, 0x94, 0x09, 0x6c, 0x3d, 0x7e, + 0x59, 0x55, 0x80, 0x5e, 0xf1, 0xf5, 0xff, 0x5d, 0x74, 0xf2, 0xea, 0xe6, + 0xfa, 0xb1, 0x7a, 0x48, 0xeb, 0x72, 0x53, 0x18, 0x60, 0x14, 0xfb, 0x54, + 0x72, 0xab, 0x04, 0x13, 0xa7, 0x47, 0xfb, 0xbb, 0x21, 0x14, 0x3d, 0xd3, + 0x56, 0x53, 0x89, 0xa4, 0x6b, 0x02, 0x79, 0x83, 0x74, 0x85, 0x2e, 0x9c, + 0xbe, 0x03, 0xf4, 0x0b, 0xa2, 0xdc, 0xf2, 0xdb, 0x57, 0x2a, 0x25, 0x5b, + 0x63, 0x01, 0x67, 0x18, 0xc4, 0x1c, 0xa7, 0xfa, 0x99, 0xc2, 0x3d, 0x26, + 0xaf, 0x9b, 0x9f, 0x9f, 0x4c, 0x03, 0x73, 0xb9, 0xd7, 0x98, 0x22, 0x67, + 0x0e, 0x5c, 0x60, 0xc8, 0xf8, 0xc0, 0x54, 0x9b, 0xfb, 0x4c, 0xd9, 0x38, + 0xf8, 0xfc, 0x90, 0x78, 0x5b, 0xeb, 0xf0, 0xe9, 0x3f, 0xa5, 0x32, 0xc8, + 0x28, 0xc3, 0xf8, 0x6f, 0x63, 0x62, 0x59, 0x54, 0xf1, 0x81, 0xc9, 0xa1, + 0xf3, 0x97, 0xdf, 0x1f, 0xff, 0xfb, 0x75, 0xe3, 0xf2, 0xc3, 0x2d, 0x7c, + 0x6f, 0x41, 0xa1, 0xa0, 0x1d, 0xc8, 0x34, 0x44, 0xca, 0x15, 0x93, 0xde, + 0xda, 0xb9, 0x17, 0x93, 0x7f, 0x17, 0x5a, 0xfe, 0xe1, 0x3b, 0x94, 0x4c, + 0xd9, 0x54, 0x27, 0x08, 0x13, 0x9c, 0x04, 0x89, 0x65, 0x51, 0xee, 0x41, + 0xd7, 0x93, 0x1b, 0xef, 0x40, 0x6f, 0xac, 0xc5, 0x55, 0xe5, 0xad, 0x42, + 0xa2, 0x65, 0xf7, 0x7a, 0xc3, 0xae, 0x99, 0xc8, 0xd3, 0x44, 0x7d, 0x36, + 0x47, 0xaa, 0xe2, 0xd9, 0xe2, 0xa0, 0xcf, 0x34, 0xb7, 0xca, 0x0f, 0x2e, + 0x9f, 0xa5, 0x21, 0x07, 0xf6, 0x70, 0x32, 0x34, 0xf2, 0xcf, 0x19, 0x19, + 0xa2, 0x28, 0x4b, 0xea, 0x0f, 0x34, 0xbb, 0x4a, 0x27, 0x17, 0x35, 0xc7, + 0x27, 0x12, 0xda, 0xd7, 0x9d, 0xde, 0x30, 0x71, 0xda, 0x0c, 0x6a, 0xbe, + 0x72, 0x0c, 0x6b, 0x00, 0xa6, 0xb7, 0xc5, 0x3a, 0x43, 0xfb, 0x3b, 0xe4, + 0x20, 0x5a, 0x79, 0x10, 0xa9, 0x9e, 0xfc, 0x84, 0x48, 0xc6, 0x2b, 0xa0, + 0xa4, 0x5a, 0x90, 0x13, 0x9e, 0xf1, 0x5f, 0x0f, 0x97, 0x0e, 0x5e, 0x10, + 0xe2, 0x42, 0x1f, 0x22, 0x73, 0xe4, 0xe0, 0xa5, 0x2a, 0x0c, 0x7c, 0xae, + 0x95, 0x57, 0x95, 0xb1, 0x40, 0x76, 0xc7, 0x0d, 0xa2, 0xe0, 0x30, 0x62, + 0x77, 0x07, 0x07, 0x65, 0xd6, 0xef, 0x23, 0x8d, 0xac, 0x3c, 0xc9, 0x45, + 0xe5, 0x21, 0xe2, 0x1f, 0xee, 0x96, 0x60, 0xae, 0x6f, 0x51, 0x3f, 0x11, + 0x0c, 0xcd, 0x1a, 0x7b, 0x32, 0xa1, 0xda, 0xe3, 0x90, 0x05, 0x0a, 0xa9, + 0x27, 0xaf, 0xc8, 0x39, 0xbe, 0xe1, 0x7a, 0xf7, 0x94, 0x22, 0x1a, 0xd2, + 0xad, 0xc6, 0xa7, 0xb8, 0x77, 0x5b, 0x93, 0xe5, 0x4e, 0x50, 0x30, 0x8c, + 0x0e, 0x12, 0x0f, 0x34, 0xb6, 0x7b, 0xe0, 0xef, 0x3b, 0xbb, 0xb6, 0x92, + 0xe8, 0xfc, 0xd4, 0x1d, 0x67, 0x18, 0x8a, 0x50, 0x9a, 0x48, 0x81, 0x4f, + 0x2f, 0x54, 0x12, 0xbe, 0xdb, 0xd2, 0x67, 0xae, 0x1d, 0x2a, 0x5f, 0x8d, + 0x0f, 0x55, 0xbf, 0x40, 0x00, 0x00, 0x01, 0x0a +}; + +void vc1_get_video_info(VideoDecodeInfo *info) +{ + info->profile = GST_VAAPI_PROFILE_VC1_ADVANCED; + info->width = VC1_CLIP_WIDTH; + info->height = VC1_CLIP_HEIGHT; + info->data = vc1_clip; + info->data_size = VC1_CLIP_DATA_SIZE; +} diff --git a/tests/test-vc1.h b/tests/test-vc1.h new file mode 100644 index 0000000..1d78504 --- /dev/null +++ b/tests/test-vc1.h @@ -0,0 +1,30 @@ +/* + * test-vc1.h - VC-1 test data + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#ifndef TEST_VC1_H +#define TEST_VC1_H + +#include +#include "test-decode.h" + +void vc1_get_video_info(VideoDecodeInfo *info); + +#endif /* TEST_VC1_H */ diff --git a/tests/test-windows.c b/tests/test-windows.c new file mode 100644 index 0000000..6c24f8a --- /dev/null +++ b/tests/test-windows.c @@ -0,0 +1,235 @@ +/* + * test-windows.c - Test GstVaapiWindow + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA +*/ + +#include "config.h" +#include +#include +#if USE_DRM +# include +# include +#endif +#if USE_X11 +# include +# include +#endif +#if USE_WAYLAND +# include +# include +#endif +#include "image.h" + +static inline void +pause(void) +{ + g_print("Press any key to continue...\n"); + getchar(); +} + +static GstVaapiSurface * +create_test_surface(GstVaapiDisplay *display, guint width, guint height) +{ + GstVaapiImage *image = NULL; + GstVaapiSurface *surface; + guint i; + + static const GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420; + static const GstVaapiImageFormat image_formats[] = { + GST_VAAPI_IMAGE_NV12, + GST_VAAPI_IMAGE_YV12, + GST_VAAPI_IMAGE_I420, + GST_VAAPI_IMAGE_AYUV, + GST_VAAPI_IMAGE_ARGB, + GST_VAAPI_IMAGE_BGRA, + GST_VAAPI_IMAGE_RGBA, + GST_VAAPI_IMAGE_ABGR, + 0 + }; + + surface = gst_vaapi_surface_new(display, chroma_type, width, height); + if (!surface) + g_error("could not create Gst/VA surface"); + + for (i = 0; image_formats[i]; i++) { + const GstVaapiImageFormat format = image_formats[i]; + + image = image_generate(display, format, width, height); + if (!image) + break; + if (image_upload(image, surface)) + break; + } + if (!image) + g_error("could not create Gst/VA image"); + + if (!gst_vaapi_surface_sync(surface)) + g_error("could not complete image upload"); + + g_object_unref(image); + return surface; +} + +int +main(int argc, char *argv[]) +{ + GstVaapiDisplay *display; + GstVaapiWindow *window; + GstVaapiSurface *surface; + guint flags = GST_VAAPI_PICTURE_STRUCTURE_FRAME; + + static const guint width = 320; + static const guint height = 240; + static const guint win_width = 640; + static const guint win_height = 480; + + gst_init(&argc, &argv); + +#if USE_DRM + display = gst_vaapi_display_drm_new(NULL); + if (!display) + g_error("could not create Gst/VA (DRM) display"); + + surface = create_test_surface(display, width, height); + if (!surface) + g_error("could not create Gst/VA surface"); + + g_print("#\n"); + g_print("# Create window with gst_vaapi_window_drm_new()\n"); + g_print("#\n"); + { + window = gst_vaapi_window_drm_new(display, win_width, win_height); + if (!window) + g_error("could not create dummy window"); + + gst_vaapi_window_show(window); + + if (!gst_vaapi_window_put_surface(window, surface, NULL, NULL, flags)) + g_error("could not render surface"); + + pause(); + g_object_unref(window); + } + + g_object_unref(surface); + g_object_unref(display); +#endif + +#if USE_X11 + display = gst_vaapi_display_x11_new(NULL); + if (!display) + g_error("could not create Gst/VA display"); + + surface = create_test_surface(display, width, height); + if (!surface) + g_error("could not create Gst/VA surface"); + + g_print("#\n"); + g_print("# Create window with gst_vaapi_window_x11_new()\n"); + g_print("#\n"); + { + window = gst_vaapi_window_x11_new(display, win_width, win_height); + if (!window) + g_error("could not create window"); + + gst_vaapi_window_show(window); + + if (!gst_vaapi_window_put_surface(window, surface, NULL, NULL, flags)) + g_error("could not render surface"); + + pause(); + g_object_unref(window); + } + + g_print("#\n"); + g_print("# Create window with gst_vaapi_window_x11_new_with_xid()\n"); + g_print("#\n"); + { + Display * const dpy = gst_vaapi_display_x11_get_display(GST_VAAPI_DISPLAY_X11(display)); + Window rootwin, win; + int screen; + unsigned long white_pixel, black_pixel; + + screen = DefaultScreen(dpy); + rootwin = RootWindow(dpy, screen); + white_pixel = WhitePixel(dpy, screen); + black_pixel = BlackPixel(dpy, screen); + + win = XCreateSimpleWindow( + dpy, + rootwin, + 0, 0, win_width, win_height, + 0, black_pixel, + white_pixel + ); + if (!win) + g_error("could not create X window"); + + window = gst_vaapi_window_x11_new_with_xid(display, win, 0); + if (!window) + g_error("could not create window"); + + gst_vaapi_window_show(window); + + if (!gst_vaapi_window_put_surface(window, surface, NULL, NULL, flags)) + g_error("could not render surface"); + + pause(); + g_object_unref(window); + XUnmapWindow(dpy, win); + XDestroyWindow(dpy, win); + } + + g_object_unref(surface); + g_object_unref(display); +#endif + +#if USE_WAYLAND + display = gst_vaapi_display_wayland_new(NULL); + if (!display) + g_error("could not create Gst/VA (Wayland) display"); + + surface = create_test_surface(display, width, height); + if (!surface) + g_error("could not create Gst/VA surface"); + + g_print("#\n"); + g_print("# Create window with gst_vaapi_window_wayland_new()\n"); + g_print("#\n"); + { + window = gst_vaapi_window_wayland_new(display, win_width, win_height); + if (!window) + g_error("could not create window"); + + gst_vaapi_window_show(window); + + if (!gst_vaapi_window_put_surface(window, surface, NULL, NULL, flags)) + g_error("could not render surface"); + + pause(); + g_object_unref(window); + } + + g_object_unref(surface); + g_object_unref(display); +#endif + + gst_deinit(); + return 0; +} -- 2.7.4