From 9b5ef9a99480b454544c216de578b739f62ed29b Mon Sep 17 00:00:00 2001 From: HyungKyu Song Date: Sat, 16 Feb 2013 01:01:16 +0900 Subject: [PATCH] Tizen 2.0 Release --- AUTHORS | 14 + COPYING.LIB | 502 ++++ Makefile.am | 25 + NEWS | 131 ++ README | 88 + autogen.sh | 38 + configure.ac | 601 +++++ 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/Makefile.am | 4 + 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 | 385 ++++ 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 ++ 205 files changed, 59287 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING.LIB create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100755 autogen.sh create mode 100644 configure.ac 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/Makefile.am create mode 100644 gst-libs/gst/Makefile.am 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/Makefile.am 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 new file mode 100644 index 0000000..96d5fc7 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..a204514 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,25 @@ +ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} + +AUTOMAKE_OPTIONS = foreign + +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 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 new file mode 100644 index 0000000..2ad1dbe --- /dev/null +++ b/NEWS @@ -0,0 +1,131 @@ +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.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 new file mode 100644 index 0000000..3c1e078 --- /dev/null +++ b/README @@ -0,0 +1,88 @@ + + gstreamer-vaapi + VA-API support to GStreamer + + Copyright (C) 2010-2011 Splitted-Desktop Systems + Copyright (C) 2011-2012 Intel Corporation + Copyright (C) 2011 Collabora Ltd. + + +License +------- + +gstreamer-vaapi helper libraries and plugin elements are available +under the terms of the GNU Lesser General Public License v2.1+ + +Overview +-------- + +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 +------------ + +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 new file mode 100755 index 0000000..920e77e --- /dev/null +++ b/autogen.sh @@ -0,0 +1,38 @@ +#!/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 new file mode 100644 index 0000000..8ced37f --- /dev/null +++ b/configure.ac @@ -0,0 +1,601 @@ +# 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], [14]) +m4_define([gst_major_minor_version], + [gst_major_version.gst_minor_version]) +m4_define([gst_version], + [gst_major_version.gst_minor_version.gst_micro_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], [31]) +m4_define([gst_plugins_base_version], + [gst_plugins_base_major_version.gst_plugins_base_minor_version.gst_plugins_base_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]) + +# 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], + [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 + +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 +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"]) + +AC_ARG_ENABLE(wayland, + AC_HELP_STRING([--enable-wayland], + [enable Wayland output @<:@default=yes@:>@]), + [], [enable_wayland="yes"]) + +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]) +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]) +GST_PLUGINS_DIR=`$PKG_CONFIG gstreamer-$GST_MAJORMINOR --variable pluginsdir` +if test -z "$GST_PLUGINS_DIR"; then + echo "FAIL FAIL FAIL" + GST_PLUGINS_DIR="\$(libdir)/gstreamer-$GST_MAJORMINOR" +fi +AC_MSG_RESULT([$GST_PLUGINS_DIR]) +plugindir="$GST_PLUGINS_DIR" +AC_SUBST(plugindir) + +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_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) + +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 + 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/Makefile.am b/gst-libs/Makefile.am new file mode 100644 index 0000000..d5356a6 --- /dev/null +++ b/gst-libs/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = gst + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/gst-libs/gst/Makefile.am b/gst-libs/gst/Makefile.am new file mode 100644 index 0000000..06d14db --- /dev/null +++ b/gst-libs/gst/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = codecparsers vaapi + +# Extra clean files so that maintainer-clean removes *everything* +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 new file mode 100644 index 0000000..76ff704 --- /dev/null +++ b/gst-libs/gst/vaapi/Makefile.am @@ -0,0 +1,385 @@ +lib_LTLIBRARIES = libgstvaapi-@GST_MAJORMINOR@.la + +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 + +if USE_WAYLAND +lib_LTLIBRARIES += libgstvaapi-wayland-@GST_MAJORMINOR@.la +endif + +libgstvaapi_includedir = \ + $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/vaapi + +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* +MAINTAINERCLEANFILES = Makefile.in 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