Skip to content

LifeStyleTransfer

Art of Code. Ways to style life with Tech
Menu
  • Home
  • Tutorials
  • Content
  • Contact
April 24, 2018
HomeGstreamerHow to add metadata to Gstreamer buffer in Python?

How to add metadata to Gstreamer buffer in Python?

By taras.lishchenko Gstreamer, Hacks, Tutorials  15 Comments

    Gstreamer is flexible plugin based data streaming framework. One of the main advantange of plugins is that developer can pass not only data buffer, but custom metadata which can describe buffer and store any information about buffer. Next information is a simple guide with code templates on how to pass any data from one plugin to another.

    Here are some possible use of metadata for Computer Vision applications:

  • objects bounding boxes (list of [x, y, width, height])
  • objects classes (“person”, “car”, “cat”, “dog”, … )
  • objects confidences ([0, 1.0])
  • keypoints
  • etc.

Note: Metadata do not relies on buffer encoding, format.
To get more information about role of Metadata in Gstreamer read official docs

Problem

     It could be difficult (in some cases even impossible) to read/write metadata from gstreamer plugin implemented in Python. (Remember that Gst.Buffer isn’t writable? See “How to make Gst.Buffer writable”)

    There are some discussions from forums with problem description and with no solution:

    • Getting buffer metadata in plugin written in Python
    • How to shuttle Gst.Meta between Python and C

Solution

    Code is available here.

//
git clone https://github.com/jackersson/gst-python-hacks.git
cd gst-python-hacks
cd gst-metadata
./build

    Open how-to-write-metadata-gst-buffer.ipynb in notebook. Let’s go through each step and see how it works:

#1. Create new buffer

//
buffer = Gst.Buffer.new_wrapped(b"lifestyletransfer")

#2. Write custom meta with text field

//
write_meta(buffer, description="Turotial 'How to write metadata in Python Gstreamer plugin'")

#3. Check that meta exists

//
buffer_info_meta = get_meta(buffer)
print(buffer_info_meta.description.decode("utf-8"))
->
Turotial 'How to write metadata in Python Gstreamer plugin'

#4. Remove meta

//
is_ok = remove_meta(buffer)
print(is_ok)
->
True

Explanation

    There are specific requirements from official documentation for handling buffer’s metadata. All those requirements could be combined in C-code template (common for all custom metadata you might want to use).
    Have a look at simple example on how to use C-template to create your own Metadata.

#1. Define Metadata Structure

//
// Structure that holds "description" field to 
// store custom text data
struct GstBufferInfo {
    gchar* description;
};

// Custom structure to be passed between Gstreamer plugins
struct GstBufferInfoMeta {

    // Required as it is base structure for metadata
    // https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstMeta.html
    GstMeta meta;

    // Custom fields
    GstBufferInfo info;
};

#2. Register Metadata type.

    Gstreamer requires to register Metadata type so it could be used to work with it in Glib ecosystem. Next function registers GstBufferInfoMeta once and returns GType value if success.

Note: GType is a numerical value which represents the unique identifier of a registered type.

//
GType gst_buffer_info_meta_api_get_type(void)
{
    static const gchar *tags[] = {NULL};
    static volatile GType type;
    if (g_once_init_enter (&type)) {
        GType _type = gst_meta_api_type_register("GstBufferInfoMetaAPI", tags);
        g_once_init_leave(&type, _type);
    }
    return type;
}

#3. Impelement Metadata init function.

    In this function all metadata’s fields (if required) should be set to default values.

//
static gboolean gst_buffer_info_meta_init(GstMeta *meta, gpointer params, GstBuffer *buffer)
{
    GstBufferInfoMeta *gst_buffer_info_meta = (GstBufferInfoMeta*)meta;
    gst_buffer_info_meta->info.description = "";
    return TRUE;
}

#4. Implement meta transform.

    This is required by Gstreamer to be able to copy medatada from one buffer to another. This is useful in case when some plugin forward through pipeline not the same buffer, but the new one.

//
static gboolean gst_buffer_info_meta_transform(GstBuffer *transbuf, GstMeta *meta, 
                                               GstBuffer *buffer,
                                               GQuark type, gpointer data)
{
    GstBufferInfoMeta *gst_buffer_info_meta = (GstBufferInfoMeta *)meta;
    gst_buffer_add_buffer_info_meta(transbuf, &(gst_buffer_info_meta->info));
    return TRUE;
}

#5. Implement GstMetaInfo

    GstMetaInfo provides specific information about Metadata structure. In this we combine all previous steps get_g_type-, transform-, init- functions

//

const GstMetaInfo *gst_buffer_info_meta_get_info(void)
{
    static const GstMetaInfo *gst_buffer_info_meta_info = NULL;
 
    if (g_once_init_enter (&gst_buffer_info_meta_info)) {

        // Explanation of fields
        // https://gstreamer.freedesktop.org/documentation/design/meta.html#gstmeta1
        const GstMetaInfo *meta = gst_meta_register (GST_BUFFER_INFO_META_API_TYPE, /* api type */
            "GstBufferInfoMeta", /* implementation type */
            sizeof(GstBufferInfoMeta), /* size of the structure */
            gst_buffer_info_meta_init,
            (GstMetaFreeFunction) NULL,
            gst_buffer_info_meta_transform);
       g_once_init_leave (&gst_buffer_info_meta_info, meta);
    }
    return gst_buffer_info_meta_info;
}

    Now we can use GstBufferInfoMeta as Metadata object. To to read from GstBuffer use following command:

//
GstBufferInfoMeta* meta = (GstBufferInfoMeta*)gst_buffer_get_meta((buffer), GST_BUFFER_INFO_META_API_TYPE);

    To write GstBufferInfoMeta to GstBuffer use next:

//
gst_buffer_info_meta = (GstBufferInfoMeta *) gst_buffer_add_meta (buffer, GST_BUFFER_INFO_META_INFO, NULL);

// copy fields to buffer's meta
if (buffer_info->description!=NULL)
{
    gst_buffer_info_meta->info.description = malloc(strlen(buffer_info->description) + 1);
    strcpy(gst_buffer_info_meta->info.description, buffer_info->description);
}

    Additionally, you can remove GstBufferInfoMeta from Buffer

//
GstBufferInfoMeta* meta = (GstBufferInfoMeta*)gst_buffer_get_meta((buffer), GST_BUFFER_INFO_META_API_TYPE);

// https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#gst-buffer-remove-meta
gboolean is_ok = gst_buffer_remove_meta(buffer, &meta->meta);

    So, for now C-template is implemented in next files:

//

gst_buffer_info_meta.c
gst_buffer_info_meta.h

    To use C-template from Python let compile it into shared *.so library (look at CMakeLists.txt):

//

./build.sh

    Library file libgst_buffer_info_meta.so is now located in build/ folder.

    Now we can call C-functions from shared library using ctypes and Python. Let use next step-by-step guide

#1. Load shared lib

    To load libgst_buffer_info_meta.so library use:

# 

clib = CDLL("build/libgst_buffer_info_meta.so")

#2. Define Python version GstBufferInfo Structure (with ctypes) that corresponds to C-version to GstBufferInfoMeta

# 

class GstBufferInfo(Structure):
    _fields_ = [("description", c_char_p)]

GstBufferInfoPtr = POINTER(GstBufferInfo)

 #3. Map c-arguments to ctypes-arguments in lib’s functions calls

# 

clib.gst_buffer_add_buffer_info_meta.argtypes = [c_void_p, GstBufferInfoPtr]
clib.gst_buffer_add_buffer_info_meta.restype = c_void_p

clib.gst_buffer_get_buffer_info_meta.argtypes = [c_void_p]
clib.gst_buffer_get_buffer_info_meta.restype = GstBufferInfoPtr

clib.gst_buffer_remove_buffer_info_meta.argtypes = [c_void_p]
clib.gst_buffer_remove_buffer_info_meta.restype = c_bool

#4. Wrap C-calls with Python functions that could be used in your code.

#

def write_meta(buffer, description):   
    meta = GstBufferInfo()
    meta.description = description.encode("utf-8")
    clib.gst_buffer_add_buffer_info_meta(hash(buffer), meta)

def get_meta(buffer):   
    res = clib.gst_buffer_get_buffer_info_meta(hash(buffer))
    return res.contents

def remove_meta(buffer):
    return clib.gst_buffer_remove_buffer_info_meta(hash(buffer))

    Previous functions are used in how-to-write-metadata-gst-buffer.ipynb. Now you can extend Metadata structure and use in your applications. Hope everything works as expected, if not – leave a comment 😉

    Additional readings:

  • How to design Metadata for Gstreamer

 

Tags:gstreamer, gstreamer metadata, gstreamer metadata python, gstreamer python, how to write metadata gstreamer, metadata

Related Posts

Top 5 Resources to learn Gstreamer

Top 5 Resources to learn Gstreamer

Gstreamer Plugin in Python Image Filter

How to write Gstreamer plugin with Python?

how-to-set-gstreamer-plugin-rank

How to set Gstreamer Plugin rank? (Hardware priority)

15 Comments
  1. mark

    clib = CDLL(“/home/pi/installs/gst-python-hacks/gst-metadata/build/libgst_buffer_info_meta.so”)
    gives me this error:
    Traceback (most recent call last):
    File “”, line 1, in
    File “/usr/lib/python3.5/ctypes/__init__.py”, line 347, in __init__
    self._handle = _dlopen(self._name, mode)
    OSError: /home/pi/installs/gst-python-hacks/gst-metadata/build/libgst_buffer_info_meta.so: undefined symbol: _gst_buffer_type

    June 26, 2019 Reply
    • taras.lishchenko

      Hi,

      Just tried same steps in tutorial but with Python 3.6. And everything worked.
      Check same on your PC in own virtual environment 😉

      If this won’t work, I’ll try to check it in Docker.

      June 26, 2019 Reply
      • mark

        False alarm got it to work, I had been trying to compile the head of gstreamer trunk with good, bad, ugly, omx, etc. with hardware acceleration for my raspberry pi and had some linking issues (putting it nicely) that once cleared up fixed my issue. Thank you for speedy response.

        June 27, 2019 Reply
  2. Toro

    would it be possible to extract metadata from a video stream via rtsp ? Or I would have to write it from a config file and label the metadata for each frame extracted from the video stream?

    August 8, 2019 Reply
    • taras.lishchenko

      Hi, Toro

      Thanks for question. Proposed method (for writing/reading metadata) in post works only inside single pipeline to pass data from one plugin to another. It won’t work for passing metadata from one pipeline to another, because streaming protocols doesn’t support some custom data transmission (except some of them I suppose).

      Using files for such a purpose would be a good choice.

      Best regards,
      Taras Lishchenko

      August 19, 2019 Reply
  3. Michael

    Hey taras, can I ask a question. Is it possible to obtain the timestamp of when the camera starts recording using gstreamer? or other offsets? I want to obtain the actual time at which each frame was captured.

    August 15, 2019 Reply
    • taras.lishchenko

      Hi, Michael

      Thanks for your question. There are two options:
      1 – Real-World time with timezone using python’s datetime. Due to this example, you can just create simple python plugin, like this and using datetime record timestamp for each incoming buffer.

      2 – Real-World time using gstreamer’s running-time. Fixate pipeline’s start time (with datetime lib) as ACTUAL_TIME=START_TIME and each frame increase this time gst_buffer.duration: ACTUAL_TIME += gst_buffer.duration. Or ACTUAL_TIME = START_TIME + gst_buffer.pts (look at for reference)

      Additional:
      – Getting buffers offset for live source: gst_buffer.pts / gst_buffer.duration

      Best regards,
      Taras Lishchenko

      August 19, 2019 Reply
  4. Michael

    hey taras, i want to ask if it was possible to obtain the timestamp of when the camera starts recording in gstreamer? how may i go about and find this?

    August 15, 2019 Reply
  5. ejl

    Big help specially in the python implementation of gstreamer.

    May 28, 2020 Reply
    • taras.lishchenko

      Thanks 😉

      May 30, 2020 Reply
  6. Aref

    Hi,

    I did as you instructed but I’m not getting anything on the receiver side. It just prints a blank line everytime. I just implemented a test class using GstBase.BaseTransform and in the do_transform_ip method I used write_meta and get_meta in sender and receiver, respectively.

    Could you please help me fix the issue?

    Thanks for the great instructions.

    September 23, 2020 Reply
    • taras.lishchenko

      Hey Aref,

      Can you share pipelines you are using for sender and receiver part? Make sure that you are not doing any buffer transfer through network protocol, in this case all metadata won’t be transfered.

      Best regards,
      Taras

      September 23, 2020 Reply
      • Aref

        Hi again,

        I am just using a simple test pipeline:

        gst-launch-1.0 videotestsrc ! send ! rec ! fakesink

        The problem is not with the transfer part beacuse I tried to get and print the buffer_info_meta in the same element (the one which created it) and again it did not have any data.

        What I did is:

        text = “Turotial ‘How to write metadata in Python Gstreamer plugin'”
        write_meta(buffer, description=text)
        print(text)
        buffer_info_meta = get_meta(buffer)
        print(buffer_info_meta.get().decode(“utf-8”))

        and the result is:
        Turotial ‘How to write metadata in Python Gstreamer plugin’

        Turotial ‘How to write metadata in Python Gstreamer plugin’

        Turotial ‘How to write metadata in Python Gstreamer plugin’
        .
        .
        .

        One of my colleagues encountered the same problem but we could not resolve it yet.
        I am trying to write this write_meta and get_meta function myself, first using C and then in Python using gi.repository.Gst.Meta and Gst.Buffer. I’ll share the result if I could fix the bug.

        Thanks.

        October 5, 2020 Reply
        • Aref

          between every
          Turotial ‘How to write metadata in Python Gstreamer plugin’
          comes a blank line. It is not visible in the comments.

          October 5, 2020 Reply
  7. blockere

    Apologies for the basic question, but I cannot get the linker to resolve the gst_meta_data dependencies.

    I’m trying this in a python 3.9 docker container, and installing the gstreamer dependencies per the instructions listed here: https://gstreamer.freedesktop.org/documentation/installing/on-linux.html?gi-language=python

    Perhaps it could be an issue with python3.9.
    Could you provide a link or steps to follow for the environment setup?

    Much appreciated

    November 18, 2020 Reply

Add a Comment

Cancel reply

Your email address will not be published. Required fields are marked *

Subscribe to be notified when new post is published

Check your inbox or spam folder to confirm your subscription.

Recent Posts

  • How to implement Video Crop Gstreamer plugin? (Caps negotiation)
  • How to set Gstreamer Plugin rank? (Hardware priority)
  • How to install Gstreamer VAAPI plugins on Ubuntu?
  • How to install Nvidia Gstreamer plugins (nvenc, nvdec) on Ubuntu?
  • How to use Gstreamer AppSrc in Python

Categories

  • Deep Learning
  • Gstreamer
  • Hacks
  • Performance
  • Python
  • Tensorflow
  • Top List
  • Tutorials
LifeStyleTransfer Copyright © 2025.
Theme by MyThemeShop. Back to Top ↑