├── README.md ├── build.sh ├── gst-metadata ├── CMakeLists.txt ├── README.md ├── build.sh ├── gst_buffer_info_meta.c ├── gst_buffer_info_meta.h ├── gst_buffer_info_meta.py └── how-to-write-metadata-gst-buffer.ipynb ├── how_to_make_gst_buffer_writable.ipynb └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 | ### Installation 2 | ```bash 3 | python3 -m venv venv 4 | source venv/bin/activate 5 | 6 | pip install --upgrade wheel pip setuptools 7 | pip install --upgrade --requirement requirements.txt 8 | 9 | ./build.sh 10 | ``` 11 | 12 | ### Hacks 13 | #### How to make Gst.Buffer writable 14 | #### How to write/read/delete metadata -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | cd gst-metadata 2 | ./build.sh -------------------------------------------------------------------------------- /gst-metadata/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | project (annotations_meta) 4 | set(CMAKE_BUILD_TYPE Release) 5 | 6 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 7 | add_library(gst_buffer_info_meta SHARED gst_buffer_info_meta.c) 8 | 9 | # Gstreamer linkage 10 | include(${CMAKE_ROOT}/Modules/FindPkgConfig.cmake) 11 | 12 | # Set CMAKE_C_FLAGS variable with info from pkg-util 13 | execute_process(COMMAND pkg-config --cflags gstreamer-1.0 14 | OUTPUT_VARIABLE CMAKE_C_FLAGS) 15 | string(REPLACE "\n" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) 16 | message("CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}") 17 | 18 | # Set CMAKE_EXE_LINKER_FLAGS variable with info from pkg-util 19 | 20 | execute_process(COMMAND pkg-config --libs gstreamer-1.0 21 | OUTPUT_VARIABLE CMAKE_EXE_LINKER_FLAGS) 22 | string(REPLACE "\n" "" CMAKE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) 23 | message("CMAKE_EXE_LINKER_FLAGS: ${CMAKE_EXE_LINKER_FLAGS}") 24 | 25 | set_target_properties(gst_buffer_info_meta 26 | PROPERTIES COMPILE_FLAGS ${CMAKE_C_FLAGS} 27 | LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) 28 | -------------------------------------------------------------------------------- /gst-metadata/README.md: -------------------------------------------------------------------------------- 1 | #### Example how to read/write/remove metadata from Gst.Buffer 2 | 3 | 4 | Run **how-to-write-metadata-gst-buffer.ipynb** to check write/get/remove metadata from Gst.Buffer 5 | 6 | * Detailed code explanation is [here]() 7 | -------------------------------------------------------------------------------- /gst-metadata/build.sh: -------------------------------------------------------------------------------- 1 | 2 | rm -rf build 3 | mkdir build 4 | cd build 5 | cmake .. 6 | make 7 | -------------------------------------------------------------------------------- /gst-metadata/gst_buffer_info_meta.c: -------------------------------------------------------------------------------- 1 | #include "gst_buffer_info_meta.h" 2 | 3 | #include "stdio.h" 4 | #include "stdlib.h" 5 | #include "string.h" 6 | 7 | static gboolean gst_buffer_info_meta_init(GstMeta *meta, gpointer params, GstBuffer *buffer); 8 | static gboolean gst_buffer_info_meta_transform(GstBuffer *transbuf, GstMeta *meta, GstBuffer *buffer, 9 | GQuark type, gpointer data); 10 | 11 | 12 | GstBufferInfo* empty(){ 13 | static GstBufferInfo info; 14 | info.description = ""; 15 | return &info; 16 | } 17 | 18 | 19 | // Register metadata type and returns Gtype 20 | // https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstMeta.html#gst-meta-api-type-register 21 | GType gst_buffer_info_meta_api_get_type(void) 22 | { 23 | static const gchar *tags[] = {NULL}; 24 | static volatile GType type; 25 | if (g_once_init_enter (&type)) { 26 | GType _type = gst_meta_api_type_register("GstBufferInfoMetaAPI", tags); 27 | g_once_init_leave(&type, _type); 28 | } 29 | return type; 30 | } 31 | 32 | // GstMetaInfo provides info for specific metadata implementation 33 | // https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstMeta.html#GstMetaInfo 34 | 35 | const GstMetaInfo *gst_buffer_info_meta_get_info(void) 36 | { 37 | static const GstMetaInfo *gst_buffer_info_meta_info = NULL; 38 | 39 | if (g_once_init_enter (&gst_buffer_info_meta_info)) { 40 | // Explanation of fields 41 | // https://gstreamer.freedesktop.org/documentation/design/meta.html#gstmeta1 42 | const GstMetaInfo *meta = gst_meta_register (GST_BUFFER_INFO_META_API_TYPE, /* api type */ 43 | "GstBufferInfoMeta", /* implementation type */ 44 | sizeof (GstBufferInfoMeta), /* size of the structure */ 45 | gst_buffer_info_meta_init, 46 | (GstMetaFreeFunction) NULL, 47 | gst_buffer_info_meta_transform); 48 | g_once_init_leave (&gst_buffer_info_meta_info, meta); 49 | } 50 | return gst_buffer_info_meta_info; 51 | } 52 | 53 | // Meta init function 54 | // 4-th field in GstMetaInfo 55 | static gboolean gst_buffer_info_meta_init(GstMeta *meta, gpointer params, GstBuffer *buffer) 56 | { 57 | GstBufferInfoMeta *gst_buffer_info_meta = (GstBufferInfoMeta*)meta; 58 | gst_buffer_info_meta->info.description = ""; 59 | return TRUE; 60 | } 61 | 62 | // Meta transform function 63 | // 5-th field in GstMetaInfo 64 | // https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstMeta.html#GstMetaTransformFunction 65 | static gboolean gst_buffer_info_meta_transform(GstBuffer *transbuf, GstMeta *meta, GstBuffer *buffer, 66 | GQuark type, gpointer data) 67 | { 68 | GstBufferInfoMeta *gst_buffer_info_meta = (GstBufferInfoMeta *)meta; 69 | gst_buffer_add_buffer_info_meta(transbuf, &(gst_buffer_info_meta->info)); 70 | return TRUE; 71 | } 72 | 73 | // Only for Python : return GstBufferInfo instead of GstBufferInfoMeta 74 | // To avoid GstMeta (C) map to Gst.Meta (Python) 75 | GstBufferInfo* gst_buffer_get_buffer_info_meta(GstBuffer* buffer) 76 | { 77 | // https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#gst-buffer-get-meta 78 | GstBufferInfoMeta* meta = (GstBufferInfoMeta*)gst_buffer_get_meta((buffer), GST_BUFFER_INFO_META_API_TYPE); 79 | 80 | if (meta == NULL) 81 | return empty(); 82 | else 83 | return &meta->info; 84 | } 85 | 86 | 87 | GstBufferInfoMeta* gst_buffer_add_buffer_info_meta( GstBuffer *buffer 88 | , GstBufferInfo* buffer_info ) 89 | { 90 | GstBufferInfoMeta *gst_buffer_info_meta = NULL; 91 | 92 | // check that gst_buffer valid 93 | g_return_val_if_fail(GST_IS_BUFFER(buffer), NULL); 94 | 95 | // check that gst_buffer writable 96 | if ( !gst_buffer_is_writable(buffer)) 97 | return gst_buffer_info_meta; 98 | 99 | // https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#gst-buffer-add-meta 100 | gst_buffer_info_meta = (GstBufferInfoMeta *) gst_buffer_add_meta (buffer, GST_BUFFER_INFO_META_INFO, NULL); 101 | 102 | // copy fields to buffer's meta 103 | if (buffer_info->description != NULL) 104 | { 105 | gst_buffer_info_meta->info.description = malloc(strlen(buffer_info->description) + 1); 106 | strcpy(gst_buffer_info_meta->info.description, buffer_info->description); 107 | } 108 | 109 | return gst_buffer_info_meta; 110 | } 111 | 112 | 113 | // Removes metadata (GstBufferInfo) from buffer 114 | gboolean gst_buffer_remove_buffer_info_meta(GstBuffer *buffer) 115 | { 116 | g_return_val_if_fail(GST_IS_BUFFER(buffer), NULL); 117 | 118 | GstBufferInfoMeta* meta = (GstBufferInfoMeta*)gst_buffer_get_meta((buffer), GST_BUFFER_INFO_META_API_TYPE); 119 | 120 | if (meta == NULL) 121 | return TRUE; 122 | 123 | if ( !gst_buffer_is_writable(buffer)) 124 | return FALSE; 125 | 126 | // https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#gst-buffer-remove-meta 127 | return gst_buffer_remove_meta(buffer, &meta->meta); 128 | } -------------------------------------------------------------------------------- /gst-metadata/gst_buffer_info_meta.h: -------------------------------------------------------------------------------- 1 | /* 2 | Meta implementation example 3 | https://github.com/EricssonResearch/openwebrtc-gst-plugins/tree/master/gst-libs/gst/sctp 4 | */ 5 | 6 | 7 | #ifndef __GST_BUFFER_INFO_META_H__ 8 | #define __GST_BUFFER_INFO_META_H__ 9 | 10 | #include 11 | 12 | 13 | G_BEGIN_DECLS 14 | 15 | typedef enum { 16 | GST_BUFFER_INFO_META_PARTIAL_RELIABILITY_NONE, 17 | GST_BUFFER_INFO_META_PARTIAL_RELIABILITY_TTL, 18 | GST_BUFFER_INFO_META_PARTIAL_RELIABILITY_BUF, 19 | GST_BUFFER_INFO_META_PARTIAL_RELIABILITY_RTX 20 | } GstBufferInfoMetaPartiallyReliability; 21 | 22 | // Api Type 23 | // 1-st field of GstMetaInfo 24 | #define GST_BUFFER_INFO_META_API_TYPE (gst_buffer_info_meta_api_get_type()) 25 | #define GST_BUFFER_INFO_META_INFO (gst_buffer_info_meta_get_info()) 26 | 27 | typedef struct _GstBufferInfoMeta GstBufferInfoMeta; 28 | typedef struct _GstBufferInfo GstBufferInfo ; 29 | 30 | struct _GstBufferInfo { 31 | gchar* description; 32 | }; 33 | 34 | 35 | struct _GstBufferInfoMeta { 36 | 37 | // Required as it is base structure for metadata 38 | // https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstMeta.html 39 | GstMeta meta; 40 | 41 | // Custom fields 42 | GstBufferInfo info; 43 | }; 44 | 45 | 46 | GType gst_buffer_info_meta_api_get_type(void); 47 | 48 | GST_EXPORT 49 | const GstMetaInfo * gst_buffer_info_meta_get_info(void); 50 | 51 | GST_EXPORT 52 | GstBufferInfoMeta* gst_buffer_add_buffer_info_meta(GstBuffer *buffer, GstBufferInfo*); 53 | 54 | GST_EXPORT 55 | gboolean gst_buffer_remove_buffer_info_meta(GstBuffer *buffer); 56 | 57 | GST_EXPORT 58 | GstBufferInfo* gst_buffer_get_buffer_info_meta(GstBuffer* b); 59 | 60 | G_END_DECLS 61 | 62 | #endif /* __GST_BUFFER_INFO_META_H__ */ -------------------------------------------------------------------------------- /gst-metadata/gst_buffer_info_meta.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy 2 | 3 | import gi 4 | gi.require_version('Gst', '1.0') 5 | from gi.repository import Gst, GObject 6 | 7 | import sys 8 | from ctypes import * 9 | 10 | 11 | # Metadata structure that describes GstBufferInfo (C) 12 | class GstBufferInfo(Structure): 13 | _fields_ = [("description", c_char_p)] 14 | 15 | # Pointer to GstBufferInfo structure 16 | GstBufferInfoPtr = POINTER(GstBufferInfo) 17 | 18 | # Load C-lib 19 | clib = CDLL("build/libgst_buffer_info_meta.so") 20 | 21 | # Map ctypes arguments to C-style arguments 22 | clib.gst_buffer_add_buffer_info_meta.argtypes = [c_void_p, GstBufferInfoPtr] 23 | clib.gst_buffer_add_buffer_info_meta.restype = c_void_p 24 | 25 | clib.gst_buffer_get_buffer_info_meta.argtypes = [c_void_p] 26 | clib.gst_buffer_get_buffer_info_meta.restype = GstBufferInfoPtr 27 | 28 | clib.gst_buffer_remove_buffer_info_meta.argtypes = [c_void_p] 29 | clib.gst_buffer_remove_buffer_info_meta.restype = c_bool 30 | 31 | 32 | def write_meta(buffer, description): 33 | """ 34 | Writes GstBufferInfo as metadata to Gst.Buffer 35 | 36 | :param name: buffer 37 | :type name: Gst.Buffer 38 | 39 | :param name: custom information to be written 40 | :type name: str 41 | """ 42 | meta = GstBufferInfo() 43 | meta.description = description.encode("utf-8") 44 | clib.gst_buffer_add_buffer_info_meta(hash(buffer), meta) 45 | 46 | 47 | def get_meta(buffer): 48 | """ 49 | Get GstBufferInfo from Gst.Buffer 50 | 51 | :param name: buffer 52 | :type name: Gst.Buffer 53 | 54 | :rtype: GstBufferInfo 55 | """ 56 | res = clib.gst_buffer_get_buffer_info_meta(hash(buffer)) 57 | return res.contents 58 | 59 | 60 | def remove_meta(buffer): 61 | """ 62 | Removes GstBufferInfo from Gst.Buffer 63 | 64 | :param name: buffer 65 | :type name: Gst.Buffer 66 | 67 | :rtype: bool 68 | """ 69 | return clib.gst_buffer_remove_buffer_info_meta(hash(buffer)) 70 | -------------------------------------------------------------------------------- /gst-metadata/how-to-write-metadata-gst-buffer.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### How to add metadata to Gst.Buffer" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import gi\n", 17 | "gi.require_version('Gst', '1.0')\n", 18 | "gi.require_version('GstBase', '1.0')\n", 19 | "from gi.repository import Gst, GObject, GstBase" 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "#### Import get/add methods from gst_buffer_info_meta.py\n", 27 | "There implemented direct C-calls from Python to work with Metadata*\n", 28 | "\n", 29 | "*Metadata described by GstBufferInfo Structure " 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 2, 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [ 38 | "from gst_buffer_info_meta import write_meta, remove_meta, get_meta" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": {}, 44 | "source": [ 45 | "#### Init Gstreamer variables" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": 3, 51 | "metadata": {}, 52 | "outputs": [ 53 | { 54 | "data": { 55 | "text/plain": [ 56 | "[]" 57 | ] 58 | }, 59 | "execution_count": 3, 60 | "metadata": {}, 61 | "output_type": "execute_result" 62 | } 63 | ], 64 | "source": [ 65 | "Gst.init(None)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "Create Gst.Buffer from string" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 4, 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "buffer = Gst.Buffer.new_wrapped(b\"lifestyletransfer\")" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "Check that there is no GstBufferInfo in buffer" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 5, 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "name": "stdout", 98 | "output_type": "stream", 99 | "text": [ 100 | "\n" 101 | ] 102 | } 103 | ], 104 | "source": [ 105 | "buffer_info_meta = get_meta(buffer)\n", 106 | "print(buffer_info_meta.description.decode(\"utf-8\"))" 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "metadata": {}, 112 | "source": [ 113 | "Add custom metadata (GstBufferInfo) with description field:\n", 114 | "\n", 115 | "- Turotial 'How to write metadata in Python Gstreamer plugin'" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 6, 121 | "metadata": {}, 122 | "outputs": [], 123 | "source": [ 124 | "write_meta(buffer, description=\"Turotial 'How to write metadata in Python Gstreamer plugin'\")" 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "metadata": {}, 130 | "source": [ 131 | "Check that there is a GstBufferInfo in buffer" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 7, 137 | "metadata": {}, 138 | "outputs": [ 139 | { 140 | "name": "stdout", 141 | "output_type": "stream", 142 | "text": [ 143 | "Turotial 'How to write metadata in Python Gstreamer plugin'\n" 144 | ] 145 | } 146 | ], 147 | "source": [ 148 | "buffer_info_meta = get_meta(buffer)\n", 149 | "print(buffer_info_meta.description.decode(\"utf-8\"))" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "Remove metadata (GstBufferInfo) from Gst.Buffer" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 8, 162 | "metadata": {}, 163 | "outputs": [ 164 | { 165 | "name": "stdout", 166 | "output_type": "stream", 167 | "text": [ 168 | "True\n" 169 | ] 170 | } 171 | ], 172 | "source": [ 173 | "is_ok = remove_meta(buffer)\n", 174 | "print(is_ok)" 175 | ] 176 | }, 177 | { 178 | "cell_type": "markdown", 179 | "metadata": {}, 180 | "source": [ 181 | "Check that there is no GstBufferInfo (Meta) in Gst.Buffer" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": 10, 187 | "metadata": {}, 188 | "outputs": [ 189 | { 190 | "name": "stdout", 191 | "output_type": "stream", 192 | "text": [ 193 | "\n" 194 | ] 195 | } 196 | ], 197 | "source": [ 198 | "buffer_info_meta = get_meta(buffer)\n", 199 | "print(buffer_info_meta.description.decode(\"utf-8\"))" 200 | ] 201 | } 202 | ], 203 | "metadata": { 204 | "kernelspec": { 205 | "display_name": "Python 3", 206 | "language": "python", 207 | "name": "python3" 208 | }, 209 | "language_info": { 210 | "codemirror_mode": { 211 | "name": "ipython", 212 | "version": 3 213 | }, 214 | "file_extension": ".py", 215 | "mimetype": "text/x-python", 216 | "name": "python", 217 | "nbconvert_exporter": "python", 218 | "pygments_lexer": "ipython3", 219 | "version": "3.6.9" 220 | } 221 | }, 222 | "nbformat": 4, 223 | "nbformat_minor": 2 224 | } 225 | -------------------------------------------------------------------------------- /how_to_make_gst_buffer_writable.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## How to make Gst.Buffer writable\n", 8 | "\n", 9 | "Explained: http://lifestyletransfer.com/how-to-make-gstreamer-buffer-writable-in-python/" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import gi\n", 19 | "gi.require_version('Gst', '1.0')\n", 20 | "gi.require_version('GstBase', '1.0')\n", 21 | "from gi.repository import Gst, GObject, GstBase" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 2, 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "data": { 31 | "text/plain": [ 32 | "[]" 33 | ] 34 | }, 35 | "execution_count": 2, 36 | "metadata": {}, 37 | "output_type": "execute_result" 38 | } 39 | ], 40 | "source": [ 41 | "Gst.init(None)" 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "metadata": {}, 47 | "source": [ 48 | "### Problem" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 3, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "buffer = Gst.Buffer.new_wrapped(b\"lifestyletransfer\")" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": 4, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "ret, map_info = buffer.map(Gst.MapFlags.READ | Gst.MapFlags.WRITE)" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 5, 72 | "metadata": {}, 73 | "outputs": [ 74 | { 75 | "data": { 76 | "text/plain": [ 77 | "b'lifestyletransfer'" 78 | ] 79 | }, 80 | "execution_count": 5, 81 | "metadata": {}, 82 | "output_type": "execute_result" 83 | } 84 | ], 85 | "source": [ 86 | "map_info.data" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 6, 92 | "metadata": {}, 93 | "outputs": [ 94 | { 95 | "ename": "TypeError", 96 | "evalue": "'bytes' object does not support item assignment", 97 | "output_type": "error", 98 | "traceback": [ 99 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 100 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 101 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmap_info\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"L\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 102 | "\u001b[0;31mTypeError\u001b[0m: 'bytes' object does not support item assignment" 103 | ] 104 | } 105 | ], 106 | "source": [ 107 | "map_info.data[0] = \"L\"" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "metadata": {}, 113 | "source": [ 114 | "### Solution" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": 16, 120 | "metadata": {}, 121 | "outputs": [], 122 | "source": [ 123 | "from ctypes import *\n", 124 | "from contextlib import contextmanager" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 17, 130 | "metadata": {}, 131 | "outputs": [], 132 | "source": [ 133 | "GST_PADDING = 4" 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": 19, 139 | "metadata": {}, 140 | "outputs": [], 141 | "source": [ 142 | "libgst = CDLL(\"libgstreamer-1.0.so.0\")" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": 20, 148 | "metadata": {}, 149 | "outputs": [], 150 | "source": [ 151 | "class GstMapInfo(Structure):\n", 152 | " _fields_ = [(\"memory\", c_void_p), # GstMemory *memory\n", 153 | " (\"flags\", c_int), # GstMapFlags flags\n", 154 | " (\"data\", POINTER(c_byte)), # guint8 *data\n", 155 | " (\"size\", c_size_t), # gsize size\n", 156 | " (\"maxsize\", c_size_t), # gsize maxsize\n", 157 | " (\"user_data\", c_void_p * 4), # gpointer user_data[4]\n", 158 | " (\"_gst_reserved\", c_void_p * GST_PADDING)]" 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": 21, 164 | "metadata": {}, 165 | "outputs": [], 166 | "source": [ 167 | "GST_MAP_INFO_POINTER = POINTER(GstMapInfo)" 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": 22, 173 | "metadata": {}, 174 | "outputs": [], 175 | "source": [ 176 | "# gst_buffer_map\n", 177 | "libgst.gst_buffer_map.argtypes = [c_void_p, GST_MAP_INFO_POINTER, c_int]\n", 178 | "libgst.gst_buffer_map.restype = c_bool\n", 179 | "\n", 180 | "# gst_buffer_unmap\n", 181 | "libgst.gst_buffer_unmap.argtypes = [c_void_p, GST_MAP_INFO_POINTER]\n", 182 | "libgst.gst_buffer_unmap.restype = None\n", 183 | "\n", 184 | "# gst_mini_object_is_writable\n", 185 | "libgst.gst_mini_object_is_writable.argtypes = [c_void_p]\n", 186 | "libgst.gst_mini_object_is_writable.restype = c_bool" 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "execution_count": 23, 192 | "metadata": {}, 193 | "outputs": [], 194 | "source": [ 195 | "@contextmanager\n", 196 | "def map_gst_buffer(pbuffer, flags):\n", 197 | " if pbuffer is None:\n", 198 | " raiseTypeError(\"Cannot pass NULL to _map_gst_buffer\")\n", 199 | "\n", 200 | " ptr = hash(pbuffer)\n", 201 | " if flags & Gst.MapFlags.WRITE and libgst.gst_mini_object_is_writable(ptr) == 0:\n", 202 | " raiseValueError(\"Writable array requested but buffer is not writeable\")\n", 203 | "\n", 204 | " mapping = GstMapInfo()\n", 205 | " success = libgst.gst_buffer_map(ptr, mapping, flags)\n", 206 | "\n", 207 | " if not success:\n", 208 | " raiseRuntimeError(\"Couldn't map buffer\")\n", 209 | "\n", 210 | " try:\n", 211 | " yield cast(mapping.data, POINTER(c_byte * mapping.size)).contents\n", 212 | " finally:\n", 213 | " libgst.gst_buffer_unmap(ptr, mapping)" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": 24, 219 | "metadata": {}, 220 | "outputs": [], 221 | "source": [ 222 | "buffer = Gst.Buffer.new_wrapped(b\"lifestyletransfer\")" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": 25, 228 | "metadata": {}, 229 | "outputs": [], 230 | "source": [ 231 | "with map_gst_buffer(buffer, Gst.MapFlags.READ | Gst.MapFlags.WRITE) as mapped:\n", 232 | " mapped[0] = ord('L')\n", 233 | " mapped[4] = ord('S')\n", 234 | " mapped[9] = ord('T')" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 26, 240 | "metadata": {}, 241 | "outputs": [ 242 | { 243 | "name": "stdout", 244 | "output_type": "stream", 245 | "text": [ 246 | "b'LifeStyleTransfer'\n" 247 | ] 248 | } 249 | ], 250 | "source": [ 251 | "ret, map_info = buffer.map(Gst.MapFlags.READ)\n", 252 | "print(map_info.data)" 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": null, 258 | "metadata": {}, 259 | "outputs": [], 260 | "source": [] 261 | } 262 | ], 263 | "metadata": { 264 | "kernelspec": { 265 | "display_name": "Python 3", 266 | "language": "python", 267 | "name": "python3" 268 | }, 269 | "language_info": { 270 | "codemirror_mode": { 271 | "name": "ipython", 272 | "version": 3 273 | }, 274 | "file_extension": ".py", 275 | "mimetype": "text/x-python", 276 | "name": "python", 277 | "nbconvert_exporter": "python", 278 | "pygments_lexer": "ipython3", 279 | "version": "3.6.9" 280 | } 281 | }, 282 | "nbformat": 4, 283 | "nbformat_minor": 2 284 | } 285 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | gstreamer-python @ git+https://github.com/jackersson/gstreamer-python.git#egg=gstreamer-python --------------------------------------------------------------------------------