Examples

The following is a list of examples and their purpose. These examples exist in C and Python3.

The standard installation path for examples is /usr/share/theimagingsource/tiscamera/examples.

It may be neccessary to install additional development packages when using pre-compiled tiscamera packages. See Dependencies.

Build Instructions

Instructions to build applications using tiscamera.

Show sample code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
LIBS:=$(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config gstreamer-1.0 --libs)
LIBS:=$(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config gstreamer-video-1.0 --libs)
LIBS+=$(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config gobject-introspection-1.0 --libs)
LIBS+=$(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config tcam --libs)

# to build within the source tree
# enable the following lines
# and source build directory ./env.sh
# LIBS+=-L./../../build/libs

CFLAGS:=$(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config gstreamer-1.0 --cflags)
CFLAGS:=$(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config gstreamer-video-1.0 --cflags)
CFLAGS+=$(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config gobject-introspection-1.0 --cflags)
CFLAGS+=$(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config tcam --cflags)

# CFLAGS+=-I../../libs/tcam-property/src
# CFLAGS+=-I../../src/gstreamer-1.0/tcamsrc

.PHONY: all clean

EXECS = 00-list-devices \
	01-list-properties \
	02-set-properties \
	03-live-stream \
	04-list-formats \
	05-set-format \
	06-softwaretrigger \
	07-appsink \
	08-save-stream \
	09-device-lost \
	10-metadata \
	11-json-state \
	12-tcam-properties \
	13-gstquery

all: $(EXECS)


$(EXECS): %: %.c
	$(CC) -g -DGST_DISABLE_DEPRECATED -Wall -Wextra -O0 $(CFLAGS) -o $@ $< $(LIBS)

clean:
	$(RM) *.o
	$(RM) $(EXECS)

Automatically handled by gobject introspection.

For custom installations set GI_TYPELIB_PATH to where the file Tcam-1.0.typelib is installed.

00 - list-devices

Shows what cameras there are and how to identify them.

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

/* This example will show you how to list information about the available devices */

#include <gst/gst.h>
#include <stdio.h> /* printf and putchar */


void print_device(GstDevice* device)
{

    GstStructure* struc = gst_device_get_properties(device);

    printf("\tmodel:\t%s\tserial:\t%s\ttype:\t%s\n",
           gst_structure_get_string(struc, "model"),
           gst_structure_get_string(struc, "serial"),
           gst_structure_get_string(struc, "type"));

    gst_structure_free(struc);

}


gboolean bus_function(GstBus* bus __attribute__((unused)), GstMessage* message, gpointer user_data __attribute__((unused)))
{
    GstDevice* device;

    switch (GST_MESSAGE_TYPE(message))
    {
        case GST_MESSAGE_DEVICE_ADDED:
        {
            gst_message_parse_device_added(message, &device);

            printf("NEW device\n");
            print_device(device);
            gst_object_unref(device);
            break;
        }
        case GST_MESSAGE_DEVICE_REMOVED:
        {
            // this can also be used as an alternative to device-lost signals
            gst_message_parse_device_removed(message, &device);
            printf("REMOVED Device\n");
            print_device(device);
            gst_object_unref(device);
            break;
        }
        /*
        // not used by tiscamera
        // requires gstreamer 1.16
        case GST_MESSAGE_DEVICE_CHANGED:
        */
        default:
        {
            break;
        }
    }

    // this means we want to continue
    // to listen to device events
    // to stop listening return G_SOURCE_REMOVE;
    return G_SOURCE_CONTINUE;
}


int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    // The device monitor listens to device activities for us
    GstDeviceMonitor* monitor = gst_device_monitor_new();
    // We are only interested in devices that are in the categories
    // Video and Source && tcam
    gst_device_monitor_add_filter(monitor, "Video/Source/tcam", NULL);

    //
    // static query
    // list all devices that are available right now
    //

    GList* devices = gst_device_monitor_get_devices(monitor);

    for (GList* elem = devices; elem; elem = elem->next)
    {
        GstDevice* device = (GstDevice*) elem->data;

        print_device(device);
    }

    g_list_free_full(devices, gst_object_unref);

    //
    // dynamic listing
    // notify us on all device changes (add/remove/changed)
    // all devices will appear once as ADDED
    //

    GstBus* bus = gst_device_monitor_get_bus(monitor);
    gst_bus_add_watch(bus, bus_function, NULL);
    gst_object_unref(bus);

    // actually start the dynamic monitoring
    gst_device_monitor_start(monitor);

    printf("Now listening to device changes. Disconnect your camera to see a remove event. Connect it to see a connect event. Press Ctrl-C to end.\n");

    // This is simply used to wait for events or the user to end this script
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(loop);
    g_main_loop_unref(loop);

    // has to be called when gst_device_monitor_start has been called
    gst_device_monitor_stop(monitor);

    // cleanup
    gst_object_unref(monitor);

    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env python3

#
# This example will show you how to list information about the available devices
#

import sys
import gi

gi.require_version("Gst", "1.0")
gi.require_version("GLib", "2.0")

from gi.repository import GLib, Gst


def print_device(device):
    """

    """

    # struc is a Gst.Structure
    struc = device.get_properties()

    print("\tmodel:\t{}\tserial:\t{}\ttype:\t{}".format(struc.get_string("model"),
                                                        struc.get_string("serial"),
                                                        struc.get_string("type")))


def bus_function(bus, message, user_data):
    """
    Callback for the GstBus watch
    """

    if message.type == Gst.MessageType.DEVICE_ADDED:
        device = message.parse_device_added()
        print("NEW Device")
        print_device(device)
    elif message.type == Gst.MessageType.DEVICE_REMOVED:
        device = message.parse_device_removed()
        print("REMOVED Device")
        print_device(device)

    return True


if __name__ == "__main__":

    Gst.init(sys.argv)  # init gstreamer

    # this line sets the gstreamer default logging level
    # it can be removed in normal applications
    # gstreamer logging can contain verry useful information
    # when debugging your application
    # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
    # for further details
    Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING)

    monitor = Gst.DeviceMonitor.new()

    monitor.add_filter("Video/Source/tcam")

    #
    # static query
    # list all devices that are available right now
    #

    for device in monitor.get_devices():

        print_device(device)

    #
    # dynamic listing
    # notify us on all device changes (add/remove/changed)
    # all devices will appear once as ADDED
    #

    bus = monitor.get_bus()
    bus.add_watch(GLib.PRIORITY_DEFAULT, bus_function, None)

    monitor.start()
    print("Now listening to device changes. Disconnect your camera to see a remove event. Connect it to see a connect event. Press Ctrl-C to end.\n")

    # This is simply used to wait for events or the user to end this script
    loop = GLib.MainLoop.new(None, False)
    loop.run()

    # has to be called when gst_device_monitor_start has been called
    monitor.stop()

01 - list-properties

Shows the properties of a camera and their settings (range, current value, etc.).

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360

/* This example will show you how to list the available properties */

#include "tcam-property-1.0.h" /* gobject introspection interface */

#include <gst/gst.h>
#include <stdio.h> /* printf and putchar */
#include <string.h>
#include <unistd.h>

void print_flags(TcamPropertyBase* prop)
{
    printf("Available: ");
    GError* err = NULL;
    gboolean av = tcam_property_base_is_available(prop, &err);
    if (av)
    {
        printf("yes");
    }
    else
    {
        printf("no");
    }

    printf("\tLocked: ");

    gboolean lo = tcam_property_base_is_locked(prop, &err);

    if (lo)
    {
        printf("yes");
    }
    else
    {
        printf("no");
    }
}


void list_properties(GstElement* source)
{

    GError* err = NULL;
    GSList* names =  tcam_property_provider_get_tcam_property_names(TCAM_PROPERTY_PROVIDER(source), &err);

    for (unsigned int i = 0; i < g_slist_length(names); ++i)
    {
        char* name = (char*)g_slist_nth(names, i)->data;

        TcamPropertyBase* base_property = tcam_property_provider_get_tcam_property(TCAM_PROPERTY_PROVIDER(source), name, &err);

        TcamPropertyType type = tcam_property_base_get_property_type(base_property);

        switch(type)
        {
            case TCAM_PROPERTY_TYPE_INTEGER:
            {
                TcamPropertyInteger* integer = TCAM_PROPERTY_INTEGER(base_property);

                gint64 def = tcam_property_integer_get_default(integer, &err);

                gint64 min;
                gint64 max;
                gint64 step;
                tcam_property_integer_get_range(integer, &min, &max, &step, &err);

                if (err)
                {
                    printf("%s\n", err->message);
                    g_error_free(err);
                    err = NULL;
                    break;
                }

                gint64 value = tcam_property_integer_get_value(integer, &err);

                if (err)
                {
                    printf("%s\n", err->message);
                    g_error_free(err);
                    err = NULL;
                    break;
                }

                const char* unit = "";
                const char* tmp_unit = tcam_property_integer_get_unit(integer);

                if (tmp_unit)
                {
                    unit = tmp_unit;
                }

                printf("%s\ttype: Integer\t"
                       "Display Name: \"%s\" "
                       "Category: %s\n"
                       "\t\t\tDescription: %s\n"
                       "\t\t\tUnit: %s\n"
                       "\t\t\tVisibility: %s\n"
                       "\t\t\tPresentation: %s\n\t\t\t",
                       name,
                       tcam_property_base_get_display_name(base_property),
                       tcam_property_base_get_category(base_property),
                       tcam_property_base_get_description(base_property),
                       unit,
                       g_enum_to_string(tcam_property_visibility_get_type() , tcam_property_base_get_visibility(base_property)),
                       g_enum_to_string(tcam_property_intrepresentation_get_type(), tcam_property_integer_get_representation(integer)));
                print_flags(base_property);
                printf("\n\n"
                       "\t\t\tDefault: %ld\n"
                       "\t\t\tValue: %ld"
                       "\n\n", def, value);

                break;

            }
            case TCAM_PROPERTY_TYPE_FLOAT:
            {
                TcamPropertyFloat* f = TCAM_PROPERTY_FLOAT(base_property);

                gdouble def = tcam_property_float_get_default(f, &err);
;
                gdouble min;
                gdouble max;
                gdouble step;
                tcam_property_float_get_range(f, &min, &max, &step, &err);

                if (err)
                {
                    printf("%s\n", err->message);
                    g_error_free(err);
                    err = NULL;
                    break;
                }

                gdouble value = tcam_property_float_get_value(f, &err);

                if (err)
                {
                    printf("%s\n", err->message);
                    g_error_free(err);
                    err = NULL;
                    break;
                }


                const char* unit = "";
                const char* tmp_unit = tcam_property_float_get_unit(f);

                if (tmp_unit)
                {
                    unit = tmp_unit;
                }

                printf("%s\ttype: Float\t"
                       "Display Name: \"%s\" "
                       "Category: %s\n"
                       "\t\t\tDescription: %s\n"
                       "\t\t\tUnit: %s\n"
                       "\t\t\tVisibility: %s\n"
                       "\t\t\tPresentation: %s\n\t\t\t",
                       name,
                       tcam_property_base_get_display_name(base_property),
                       tcam_property_base_get_category(base_property),
                       tcam_property_base_get_description(base_property),
                       unit,
                       g_enum_to_string(tcam_property_visibility_get_type() , tcam_property_base_get_visibility(base_property)),
                       g_enum_to_string(tcam_property_intrepresentation_get_type(), tcam_property_float_get_representation(f)));
                print_flags(base_property);
                printf("\n\n"
                       "\t\t\tDefault: %f\n"
                       "\t\t\tValue: %f"
                       "\n\n", def, value);

                break;
            }
            case TCAM_PROPERTY_TYPE_ENUMERATION:
            {
                TcamPropertyEnumeration* e = TCAM_PROPERTY_ENUMERATION(base_property);

                const char* value = tcam_property_enumeration_get_value(e, &err);

                if (err)
                {
                    printf("%s\n", err->message);
                    g_error_free(err);
                    err = NULL;
                    break;
                }

                const char* def = tcam_property_enumeration_get_default(e, &err);

                if (err)
                {
                    printf("%s\n", err->message);
                    g_error_free(err);
                    err = NULL;
                    break;
                }

                printf("%s\ttype: Enumeration\t"
                       "Display Name: \"%s\" "
                       "Category: %s\n"
                       "\t\t\tDescription: %s\n"
                       "\t\t\tVisibility: %s\n"
                       "\t\t\t",
                       name, tcam_property_base_get_display_name(base_property),
                       tcam_property_base_get_category(base_property),
                       tcam_property_base_get_description(base_property),
                       g_enum_to_string(tcam_property_visibility_get_type() , tcam_property_base_get_visibility(base_property)));
                print_flags(base_property);
                printf("\n\n"
                       "\t\t\tEntries:");

                GSList* enum_entries = tcam_property_enumeration_get_enum_entries(e, &err);

                if (err)
                {
                    printf("%s\n", err->message);
                    g_error_free(err);
                    break;
                }

                if (enum_entries)
                {
                    for (GSList* entry = enum_entries; entry != NULL; entry = entry->next)
                    {
                        printf(" %s", (const char*)entry->data);
                    }

                    g_slist_free_full(enum_entries, g_free);
                }
                printf("\n\t\t\tDefault: %s\n"
                       "\t\t\tValue: %s\n\n\n", def, value);

                break;
            }
            case TCAM_PROPERTY_TYPE_BOOLEAN:
            {
                TcamPropertyBoolean* b = TCAM_PROPERTY_BOOLEAN(base_property);
                gboolean value = tcam_property_boolean_get_value(b, &err);
                gboolean def = tcam_property_boolean_get_default(b, &err);

                if (err)
                {
                    printf("%s\n", err->message);
                    g_error_free(err);
                    err = NULL;
                    break;
                }

                const char* val_str = "false";
                const char* def_str = "false";

                if (value)
                {
                    val_str = "true";
                }

                if (def)
                {
                    def_str = "true";
                }

                printf("%s\ttype: Boolean\t"
                       "Display Name: \"%s\" "
                       "Category: %s\n"
                       "\t\t\tDescription: %s\n"
                       "\t\t\t",
                       name,
                       tcam_property_base_get_display_name(base_property),
                       tcam_property_base_get_category(base_property),
                       tcam_property_base_get_description(base_property)
                    );
                print_flags(base_property);
                printf("\n\n\t\t\tDefault: %s\n"
                       "\t\t\tValue: %s\n\n\n",
                       def_str, val_str);

                break;
            }
            case TCAM_PROPERTY_TYPE_COMMAND:
            {
                printf("%s\ttype: Command\t"
                       "Display Name: \"%s\" "
                       "Category: %s\n"
                       "\t\t\tDescription: %s\n"
                       "\t\t\t",
                       name,
                       tcam_property_base_get_display_name(base_property),
                       tcam_property_base_get_category(base_property),
                       tcam_property_base_get_description(base_property));
                print_flags(base_property);
                printf("\n\n\n");
                        break;
            }
            default:
            {
                break;
            }
            printf("\n\n\n");
        }
        g_object_unref(base_property);
    }
    g_slist_free_full(names, g_free);
}


int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    GError* err = NULL;

    // this is a placeholder definition
    // normally your pipeline would be defined here
    GstElement* pipeline = gst_parse_launch("tcambin name=source ! fakesink", &err);

    if (pipeline == NULL)
    {
        printf("Unable to create pipeline: %s\n", err->message);
        g_free(err);
        return 1;
    }

    /* get the tcambin to retrieve device information */
    GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline), "source");

    const char* serial = NULL; // set this if you do not want the first found device

    if (serial != NULL)
    {
        GValue val = {};
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);
    }

    // in the READY state the camera will always be initialized
    gst_element_set_state(pipeline, GST_STATE_READY);

    list_properties(source);

    // cleanup
    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(source);
    gst_object_unref(pipeline);

    return 0;
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#!/usr/bin/env python3

#
# This example will show you how to list available properties
#

import sys
import gi

gi.require_version("Tcam", "1.0")
gi.require_version("Gst", "1.0")
gi.require_version("GLib", "2.0")

from gi.repository import Tcam, Gst, GLib


def flag_strings(prop):
    """

    """

    ret = "Available: "

    if prop.is_available():
        ret += "yes"
    else:
        ret += "no"

    ret += "\tLocked: "

    if prop.is_locked():
        ret += "yes"
    else:
        ret += "no"

    return ret


def list_properties(camera):

    property_names = camera.get_tcam_property_names()

    for name in property_names:
        try:
            base = camera.get_tcam_property(name)

            if base.get_property_type() == Tcam.PropertyType.INTEGER:

                default = base.get_default()
                mini, maxi, step = base.get_range()

                unit = base.get_unit()
                if not unit:
                    unit = ""

                print(("{name}\ttype: Integer\tDisplay Name: \"{disp_name}\"\tCategory: {cat}\n"
                       "\t\t\tDescription: {desc}\n"
                       "\t\t\tUnit: {unit}\n"
                       "\t\t\tVisibility: {vis}\n"
                       "\t\t\tPresentation: {pres}\n"
                       "\t\t\t{flags}\n\n"
                       "\t\t\tMin: {mini}\t Max: {maxi}\tStep: {step}\n"
                       "\t\t\tDefault: {default}\n"
                       "\t\t\tValue: {val}\n\n").format(name=name,
                                                        disp_name=base.get_display_name(),
                                                        cat=base.get_category(),
                                                        desc=base.get_description(),
                                                        unit=unit,
                                                        vis=base.get_visibility(),
                                                        pres=base.get_representation(),
                                                        flags=flag_strings(base),
                                                        mini=mini,
                                                        maxi=maxi,
                                                        step=step,
                                                        default=default,
                                                        val=base.get_value()))
            elif base.get_property_type() == Tcam.PropertyType.FLOAT:

                default = base.get_default()
                mini, maxi, step = base.get_range()

                unit = base.get_unit()
                if not unit:
                    unit = ""

                print(("{name}\ttype: Float\tDisplay Name: \"{disp_name}\"\tCategory: {cat}\n"
                       "\t\t\tDescription: {desc}\n"
                       "\t\t\tUnit: {unit}\n"
                       "\t\t\tVisibility: {vis}\n"
                       "\t\t\tPresentation: {pres}\n"
                       "\t\t\t{flags}\n\n"
                       "\t\t\tMin: {mini}\t Max: {maxi}\tStep: {step}\n"
                       "\t\t\tDefault: {default}\n"
                       "\t\t\tValue: {val}\n\n").format(name=name,
                                                        disp_name=base.get_display_name(),
                                                        cat=base.get_category(),
                                                        desc=base.get_description(),
                                                        unit=unit,
                                                        vis=base.get_visibility(),
                                                        pres=base.get_representation(),
                                                        flags=flag_strings(base),
                                                        mini=mini,
                                                        maxi=maxi,
                                                        step=step,
                                                        default=default,
                                                        val=base.get_value()))
            elif base.get_property_type() == Tcam.PropertyType.ENUMERATION:
                print(("{name}\ttype: Enumeration\tDisplay Name: \"{disp_name}\"\tCategory: {cat}\n"
                       "\t\t\tDescription: {desc}\n"
                       "\t\t\tVisibility: {vis}\n"
                       "\t\t\t{flags}\n\n"
                       "\t\t\tEntries: {entries}\n"
                       "\t\t\tDefault: {default}\n"
                       "\t\t\tValue: {val}\n\n").format(name=name,
                                                        disp_name=base.get_display_name(),
                                                        cat=base.get_category(),
                                                        desc=base.get_description(),
                                                        vis=base.get_visibility(),
                                                        flags=flag_strings(base),
                                                        entries=base.get_enum_entries(),
                                                        default=base.get_default(),
                                                        val=base.get_value()))
            elif base.get_property_type() == Tcam.PropertyType.BOOLEAN:
                print(("{name}\ttype: Boolean\tDisplay Name: \"{disp_name}\"\tCategory: {cat}\n"
                       "\t\t\tDescription: {desc}\n"
                       "\t\t\tVisibility: {vis}\n"
                       "\t\t\t{flags}\n\n"
                       "\t\t\tDefault: {default}\n"
                       "\t\t\tValue: {val}\n\n").format(name=name,
                                                        disp_name=base.get_display_name(),
                                                        cat=base.get_category(),
                                                        desc=base.get_description(),
                                                        vis=base.get_visibility(),
                                                        flags=flag_strings(base),
                                                        default=base.get_default(),
                                                        val=base.get_value()))
            elif base.get_property_type() == Tcam.PropertyType.COMMAND:
                print(("{name}\ttype: Command\tDisplay Name: \"{disp_name}\"\tCategory: {cat}\n"
                       "\t\t\tDescription: {desc}\n"
                       "\t\t\tVisibility: {vis}\n"
                       "\t\t\t{flags}\n\n").format(name=name,
                                                   disp_name=base.get_display_name(),
                                                   cat=base.get_category(),
                                                   desc=base.get_description(),
                                                   vis=base.get_visibility(),
                                                   flags=flag_strings(base)))
        except GLib.Error as err:

            print("Error for {}: {}".format(name, err.message))


def block_until_playing(pipeline):

    while True:
        # wait 0.1 seconds for something to happen
        change_return, state, pending = pipeline.get_state(100000000)
        if change_return == Gst.StateChangeReturn.SUCCESS:
            return True
        elif change_return == Gst.StateChangeReturn.FAILURE:
            print("Failed to change state {} {} {}".format(change_return,
                                                           state,
                                                           pending))
            return False


def main():
    Gst.init(sys.argv)  # init gstreamer

    # this line sets the gstreamer default logging level
    # it can be removed in normal applications
    # gstreamer logging can contain verry useful information
    # when debugging your application
    # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
    # for further details
    Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING)

    pipeline = Gst.parse_launch("tcambin name=source ! fakesink")

    if not pipeline:
        print("Unable to create pipeline")
        return 1

    # set this to a specific camera serial if you
    # do not want to use the default camera
    serial = None

    # get the tcambin to retrieve a property list through it
    source = pipeline.get_by_name("source")

    # serial is defined, thus make the source open that device
    if serial is not None:
        source.set_property("serial", serial)

    # the pipeline/tcamsrc/tcambin element must
    # at least be in Gst.State.READY
    # for a device to be open.
    # with Gst.State.NULL
    # no properties will be returned
    pipeline.set_state(Gst.State.READY)

    list_properties(source)

    # This closes the device
    # All properties are now invalid
    # and have to be deleted
    pipeline.set_state(Gst.State.NULL)

    return 0


if __name__ == "__main__":
    sys.exit(main())

02 - set-properties

Shows how to set a specific property.

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

/* This example will show you how to set properties for a certain camera */

#include "tcam-property-1.0.h" /* gobject introspection interface */

#include <gst/gst.h>
#include <stdio.h> /* printf and putchar */


void print_enum_property(GstElement* source, const char* name)
{
    /* this is only a sample not all properties will be set here */

    GError* err = NULL;
    TcamPropertyBase* property_base = tcam_property_provider_get_tcam_property(TCAM_PROPERTY_PROVIDER(source),
                                                                               name,
                                                                               &err);

    if (err)
    {
        printf("Error while retrieving property: %s\n", err->message);
        g_error_free(err);
        err = NULL;
    }

    if (tcam_property_base_get_property_type(property_base) != TCAM_PROPERTY_TYPE_ENUMERATION)
    {
        printf("%s has wrong type. This should not happen.\n", name);
    }
    else
    {
        TcamPropertyEnumeration* property_enum = TCAM_PROPERTY_ENUMERATION(property_base);
        const char* value = tcam_property_enumeration_get_value(property_enum, &err);

        if (err)
        {
            printf("Error while retrieving property: %s\n", err->message);
            g_error_free(err);
            err = NULL;
        }
        else
        {
            printf("%s: %s\n", name, value);
        }
    }
    g_object_unref(property_base);
}


void set_enum_property(GstElement* source, const char* name, const char* value)
{
    GError* err = NULL;
    TcamPropertyBase* property_base = tcam_property_provider_get_tcam_property(TCAM_PROPERTY_PROVIDER(source),
                                                                               name,
                                                                               &err);

    if (err)
    {
        printf("Error while retrieving property: %s\n", err->message);
        g_error_free(err);
        err = NULL;
    }

    if (tcam_property_base_get_property_type(property_base) != TCAM_PROPERTY_TYPE_ENUMERATION)
    {
        printf("ExposureAuto has wrong type. This should not happen.\n");
    }
    else
    {
        TcamPropertyEnumeration* enum_property = TCAM_PROPERTY_ENUMERATION(property_base);

        tcam_property_enumeration_set_value(enum_property, value, &err);

        if (err)
        {
            printf("Error while setting property: %s\n", err->message);
            g_error_free(err);
            err = NULL;
        }
        else
        {
            printf("Set %s to %s\n", name, value);
        }
    }
    g_object_unref(property_base);
}



int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    GError* err = NULL;

    // this is a placeholder definition
    // normally your pipeline would be defined here
    GstElement* pipeline = gst_parse_launch("tcambin name=source  ! fakesink", &err);

    if (pipeline == NULL)
    {
        printf("Unable to create pipeline: %s\n", err->message);
        g_free(err);
        err = NULL;
        return 1;
    }

    /* create a tcambin to retrieve device information */
    GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline), "source");

    const char* serial = NULL;

    if (serial != NULL)
    {
        GValue val = {};
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);
    }

    gst_element_set_state(pipeline, GST_STATE_READY);

    /* Device is now in a state for interactions */

    /*
      We print the properties for a before/after comparison,
     */
    printf("Values before we change them:\n\n");

    print_enum_property(source, "ExposureAuto");
    print_enum_property(source, "GainAuto");

    /*
      We set the properties to other values
     */
    printf("\nChanging:\n\n");

    set_enum_property(source, "ExposureAuto", "Off");
    set_enum_property(source, "GainAuto", "Off");

    /* alternatively you can get/set directly on the TCAM_PROPERTY_PROVIDER */
    /* for this you need to know the type of the property you want to get/set */

    /* tcam_property_provider_set_tcam_enumeration(TCAM_PROPERTY_PROVIDER(source), "ExposureAuto", "Off", &err); */
    /* tcam_property_provider_set_tcam_integer(TCAM_PROPERTY_PROVIDER(source), "Brightness", 200, &err); */
    /* tcam_property_provider_set_tcam_float(TCAM_PROPERTY_PROVIDER(source), "ExposureTime", 30000.0, &err); */

    printf("\nValues after we changed them:\n\n");

    /*
      second print for the before/after comparison
     */
    print_enum_property(source, "ExposureAuto");
    print_enum_property(source, "GainAuto");

    /* cleanup, reset state */
    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(source);
    gst_object_unref(pipeline);

    return 0;
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
#!/usr/bin/env python3

#
# This example will show you how to set properties
#

import sys
import gi

gi.require_version("Tcam", "1.0")
gi.require_version("Gst", "1.0")
gi.require_version("GLib", "2.0")

from gi.repository import Tcam, Gst, GLib


def print_properties(camera):
    """
    Print selected properties
    """
    try:

        property_exposure_auto = camera.get_tcam_property("ExposureAuto")

        print(property_exposure_auto.get_value())

        value = camera.get_tcam_enumeration("ExposureAuto")

        print(f"Exposure Auto has value: {value}")

        value = camera.get_tcam_enumeration("GainAuto")

        print("Gain Auto has value: {}".format(value))

        value = camera.get_tcam_float("ExposureTime")

        print("ExposureTimer has value: {}".format(value))

    except GLib.Error as err:

        print(f"{err.message}")


def block_until_playing(pipeline):

    while True:
        # wait 0.1 seconds for something to happen
        change_return, state, pending = pipeline.get_state(100000000)
        if change_return == Gst.StateChangeReturn.SUCCESS:
            return True
        elif change_return == Gst.StateChangeReturn.FAILURE:
            print("Failed to change state {} {} {}".format(change_return,
                                                           state,
                                                           pending))
            return False


def main():

    Gst.init(sys.argv)

    # this line sets the gstreamer default logging level
    # it can be removed in normal applications
    # gstreamer logging can contain verry useful information
    # when debugging your application
    # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
    # for further details
    Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING)

    # Set this to a serial string for a specific camera
    serial = None

    camera = Gst.ElementFactory.make("tcambin")

    if serial:
        # This is gstreamer set_property
        camera.set_property("serial", serial)

    # in the READY state the camera will always be initialized
    camera.set_state(Gst.State.READY)

    # Print properties for a before/after comparison
    print_properties(camera)

    # Set properties
    try:
        camera.set_tcam_enumeration("ExposureAuto", "Off")
        camera.set_tcam_enumeration("GainAuto", "Off")

        camera.set_tcam_float("ExposureTime", 2000)

    except GLib.Error as err:
        # if setting properties fail, print the reason
        print(f"{err.message}")

    print_properties(camera)

    # cleanup, reset state
    camera.set_state(Gst.State.NULL)


if __name__ == "__main__":
    sys.exit(main())

03 - live-stream

Delivers live-image stream from the camera.

Show sample code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

/* This example will show you how to start a live stream from your camera */

#include <gst/gst.h>
#include <stdio.h> /* printf and putchar */


int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    const char* serial = NULL; // set this if you do not want the first found device

    GError* err = NULL;

    GstElement* pipeline =
        gst_parse_launch("tcambin name=source ! videoconvert ! ximagesink sync=false", &err);

    if (err)
    {
        printf("%s\n", err->message);
        g_error_free(err);
        err = NULL;
    }

    /* test for error */
    if (pipeline == NULL)
    {
        printf("Could not create pipeline. Cause: %s\n", err->message);
        return 1;
    }

    if (serial != NULL)
    {
        GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline), "source");
        GValue val = {};
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);

        gst_object_unref(source);
    }

    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    printf("Press enter to stop the stream.\n");
    getchar();

    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(pipeline);

    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/usr/bin/env python3

#
# This example will show you how to start a simply live stream
#

import time
import sys
import gi

gi.require_version("Gst", "1.0")

from gi.repository import Gst


def main():

    Gst.init(sys.argv)  # init gstreamer

    # this line sets the gstreamer default logging level
    # it can be removed in normal applications
    # gstreamer logging can contain verry useful information
    # when debugging your application
    # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
    # for further details
    Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING)

    serial = None

    pipeline = Gst.parse_launch("tcambin name=bin "
                                " ! videoconvert"
                                " ! ximagesink sync=false")

    # retrieve the bin element from the pipeline
    camera = pipeline.get_by_name("bin")

    # serial is defined, thus make the source open that device
    if serial is not None:
        camera.set_property("serial", serial)

    pipeline.set_state(Gst.State.PLAYING)

    print("Press Ctrl-C to stop.")

    # We wait with this thread until a
    # KeyboardInterrupt in the form of a Ctrl-C
    # arrives. This will cause the pipline
    # to be set to state NULL
    try:
        while True:
            time.sleep(1)
            pipeline.set_state(Gst.State.READY)
            pipeline.set_state(Gst.State.PLAYING)
    except KeyboardInterrupt:
        pass
    finally:
        pipeline.set_state(Gst.State.NULL)


if __name__ == "__main__":
    main()

04 - list-format

Lists what formats the camera offers.

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

/* This example will show you how to list the formats your device offers */

#include "tcam-property-1.0.h" /* gobject introspection interface */

#include <gst/gst.h>
#include <stdio.h> /* printf and putchar */


int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    // set this if you do not want the first found device
    char* serial = NULL;

    /* create a tcambin to retrieve device information */
    GstElement* source = gst_element_factory_make("tcambin", "source");

    if (serial != NULL)
    {
        GValue val = {};
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);
    }

    /* Setting the state to ready ensures that all resources
       are initialized and that we really get all format capabilities */
    gst_element_set_state(source, GST_STATE_READY);

    GstPad* pad = gst_element_get_static_pad(source, "src");

    GstCaps* caps = gst_pad_query_caps(pad, NULL);

    printf("================ %s\n", gst_caps_to_string(caps));

    for (unsigned int i = 0; i < gst_caps_get_size(caps); ++i)
    {
        GstStructure* structure = gst_caps_get_structure(caps, i);

        /*
          for a simple display the following line can be used
          printf("%s\n", gst_structure_to_string(structure));
        */

        const char* name = gst_structure_get_name(structure);

        // this is only required when dealing
        // with FPD/MiPi cameras on tegra systems
        // must not be freed
        GstCapsFeatures* features = gst_caps_get_features(caps, i);

        if (features)
        {
            if (gst_caps_features_contains(features, "memory:NVMM"))
            {
                // do something with this information
                printf("NVMM ");
            }
        }

        if (gst_structure_get_field_type(structure, "format") == G_TYPE_STRING)
        {
            const char* format = gst_structure_get_string(structure, "format");

            printf("%s %s - ", name, format);
        }
        else if (gst_structure_get_field_type(structure, "format") == GST_TYPE_LIST)
        {
            printf("%s { ", name);

            const GValue* val = gst_structure_get_value(structure, "format");

            for (unsigned int x = 0; x < gst_value_list_get_size(val); ++x)
            {
                const GValue* format = gst_value_list_get_value(val, x);

                printf("%s ", g_value_get_string(format));
            }


            printf("} - ");
        }
        else
        {
            printf("format handling not implemented for unexpected type: %s\n",
                   G_VALUE_TYPE_NAME(gst_structure_get_field_type(structure, "format")));
            continue;
        }

        GType width_type = gst_structure_get_field_type(structure, "width");

        if (width_type == GST_TYPE_INT_RANGE)
        {
            int width_min =
                gst_value_get_int_range_min(gst_structure_get_value(structure, "width"));
            int width_max =
                gst_value_get_int_range_max(gst_structure_get_value(structure, "width"));


            printf("width: [%d-%d]", width_min, width_max);
        }
        else
        {
            int width;
            gboolean ret = gst_structure_get_int(structure, "width", &width);

            if (!ret)
            {
                printf("Unable to query width\n");
                continue;
            }

            printf("%d", width);
        }

        printf(" X ");

        GType height_type = gst_structure_get_field_type(structure, "height");

        if (height_type == GST_TYPE_INT_RANGE)
        {
            int height_min =
                gst_value_get_int_range_min(gst_structure_get_value(structure, "height"));
            int height_max =
                gst_value_get_int_range_max(gst_structure_get_value(structure, "height"));


            printf("height: [%d-%d]", height_min, height_max);
        }
        else
        {
            int height;
            gboolean ret = gst_structure_get_int(structure, "height", &height);

            if (!ret)
            {
                printf("Unable to query height\n");
                continue;
            }

            printf("%d", height);
        }

        printf(" - ");

        const GValue* framerate = gst_structure_get_value(structure, "framerate");

        if (G_VALUE_TYPE(framerate) == GST_TYPE_LIST)
        {
            for (unsigned int x = 0; x < gst_value_list_get_size(framerate); ++x)
            {
                const GValue* val = gst_value_list_get_value(framerate, x);

                if (G_VALUE_TYPE(val) == GST_TYPE_FRACTION)
                {
                    int num = gst_value_get_fraction_numerator(val);
                    int den = gst_value_get_fraction_denominator(val);

                    printf("%d/%d ", num, den);
                }
                else
                {
                    printf(
                        "Handling of framerate handling not implemented for non fraction types.\n");
                    break;
                }
            }
        }
        else if (G_VALUE_TYPE(framerate) == GST_TYPE_FRACTION_RANGE)
        {
            const GValue* framerate_min = gst_value_get_fraction_range_min(framerate);
            const GValue* framerate_max = gst_value_get_fraction_range_max(framerate);

            printf("%d/%d - %d/%d",
                   gst_value_get_fraction_numerator(framerate_min),
                   gst_value_get_fraction_denominator(framerate_min),
                   gst_value_get_fraction_numerator(framerate_max),
                   gst_value_get_fraction_denominator(framerate_max));
        }
        else
        {
            printf("Unable to interpret framerate type\n");
            continue;
        }

        // we printed all information for a format decription
        // print a new line to keep everything user readable
        printf("\n");
    }

    gst_caps_unref(caps);
    gst_object_unref(pad);

    gst_element_set_state(source, GST_STATE_NULL);

    gst_object_unref(source);

    return 0;
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#!/usr/bin/env python3

#
# This example will show you how to retrieve the available gstreamer
# caps from tcamsrc and how to display print them to stdout.
#

import sys
import gi
import re

gi.require_version("Gst", "1.0")

from gi.repository import Gst


def print_formats(source):

    caps = source.get_static_pad("src").query_caps()

    for x in range(caps.get_size()):

        structure = caps.get_structure(x)

        # video/x-raw, video/x-bayer, etc.
        name = structure.get_name()

        # this is only required when dealing
        # with FPD/MiPi cameras on tegra systems
        features = caps.get_features(x)
        if features:
            if features.contains("memory:NVMM"):
                print("NVMM ")

        try:
            fmt = structure.get_value("format")

            if isinstance(fmt, str):
                print(f"{name} {fmt}", end="")
            elif isinstance(fmt, Gst.ValueList):

                print(f"{name} {{ ", end="")

                for y in range(Gst.ValueList.get_size(fmt)):

                    val = Gst.ValueList.get_value(fmt, y)

                    print(f"{val} ", end="")
                print("}", end="")
            else:
                print("==")
        except TypeError:  # Gst.ValueList

            # this means we have multiple formats that all
            # have the same width/height/framerate settings

            begin = structure.to_string().find("format=(string){")
            print(begin)
            substr = structure.to_string()[begin:]
            values = substr[substr.find("{")+1:substr.find("}")]

            print(f"{name} {{ ", end="")

            for fmt in values.split(","):

                print(f"{fmt} ", end="")

            print("}", end="")

        # the python gobject introspection wrapper
        # can pose problems in older version
        # the type Gst.IntRange
        # may not be available and thus cause a TypeError
        # in such a case we query the string description
        # of the Gst.Structure and extract the width/height
        try:
            if (structure.to_string().find("width=[") != -1
                    or structure.to_string().find("height=[") != -1):
                raise TypeError

            width = structure.get_value("width")
            height = structure.get_value("height")

            print(f" - {width}x{height} - ", end="")

        except TypeError:

            # width handling

            begin = structure.to_string().find("width=(int)[")
            substr = structure.to_string()[begin:]
            values = substr[substr.find("[")+1:substr.find("]")]
            v = re.findall(r'\d+', values)

            # assume first entry is smaller
            width_min = v[0]
            width_max = v[1]

            # height handling

            begin = structure.to_string().find("height=(int)[")
            substr = structure.to_string()[begin:]
            values = substr[substr.find("[")+1:substr.find("]")]
            v = re.findall(r'\d+', values)

            height_min = v[0]
            height_max = v[1]

            print(f" - {width_min}x{height_min} <=> {width_max}x{height_max} - ", end="")

        # the python gobject introspection wrapper
        # can pose problems in older version
        # the types Gst.Fraction and Gst.FractionRange
        # may not be available and thus cause a TypeError
        # in such a case we query the string description
        # of the Gst.Structure and extract the framerates
        try:
            framerates = structure.get_value("framerate")
        except TypeError:

            substr = structure.to_string()[structure.to_string().find("framerate="):]

            try:
                # try for frame rate lists
                field, values, remain = re.split("{|}", substr, maxsplit=3)
                rates = [x.strip() for x in values.split(",")]
                for r in rates:
                    print(f"{r} ", end="")
            except ValueError:  # we have a GstFractionRange

                values = substr[substr.find("[")+1:substr.find("]")]
                v = re.findall(r'\d+', values)
                fps_min_num = v[0]
                fps_min_den = v[1]
                fps_max_num = v[2]
                fps_max_den = v[3]
                # framerates are fractions thus one framerate euqals two values
                print(f"{fps_min_num}/ {fps_min_den} <=> {fps_max_num}/{fps_max_den}", end="")

            # printf line break
            print("")
            # we are done here
            continue

        if isinstance(framerates, Gst.ValueList):

            # Gst.ValueList.get_size may cause a warning:
            # DeprecationWarning: an integer is required (got type float).
            # Implicit conversion to integers using __int__ is deprecated,
            # and may be removed in a future version of Python.
            #
            # this is part of the GStreamer python wrapper
            # and not tiscamera
            size = Gst.ValueList.get_size(framerates)

            for y in range(size):

                val = Gst.ValueList.get_value(framerates, y)

                print("{} ".format(val), end="")

        elif isinstance(framerates, Gst.FractionRange):

            min_val = Gst.value_get_fraction_range_min(framerates)
            max_val = Gst.value_get_fraction_range_max(framerates)
            print(f"{min_val} <-> {max_val}")

        else:
            print(f"framerates not supported {isinstance(framerates)}")
            # we are finished
        print("")


def main():
    """
    main function
    initializes GstElement and starts GstCaps query
    """
    Gst.init(sys.argv)  # init gstreamer

    # this line sets the gstreamer default logging level
    # it can be removed in normal applications
    # gstreamer logging can contain verry useful information
    # when debugging your application
    # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
    # for further details
    Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING)

    source = Gst.ElementFactory.make("tcambin")

    # The tcambin wraps the tcamsrc and offers additional
    # formats by implicitly converting
    # source = Gst.ElementFactory.make("tcambin")

    serial = None

    if serial:
        source.set_property("serial", serial)

    source.set_state(Gst.State.READY)

    print_formats(source)

    source.set_state(Gst.State.NULL)


if __name__ == "__main__":
    main()

05 - set format

Sets the camera to a specific format.

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109

/*
  This example will show you how to start a live stream from your camera
  with a specific format
 */

#include "tcam-property-1.0.h" /* gobject introspection interface */

#include <gst/gst.h>
#include <stdio.h> /* printf and putchar */


int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    const char* serial = NULL; // set this if you do not want the first found device

    GError* err = NULL;
    const char* pipeline_desc =
        "tcambin name=source ! capsfilter name=filter ! videoconvert ! ximagesink";

    GstElement* pipeline = gst_parse_launch(pipeline_desc, &err);

    /* test for error */
    if (pipeline == NULL)
    {
        printf("Could not create pipeline. Cause: %s\n", err->message);
        return 1;
    }

    if (serial != NULL)
    {
        GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline), "source");
        GValue val = {};
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);

        gst_object_unref(source);
    }


    GstCaps* caps = gst_caps_new_empty();

    GstStructure* structure = gst_structure_from_string("video/x-raw", NULL);
    gst_structure_set(structure,
                      "format",
                      G_TYPE_STRING,
                      "BGRx",
                      "width",
                      G_TYPE_INT,
                      640,
                      "height",
                      G_TYPE_INT,
                      480,
                      "framerate",
                      GST_TYPE_FRACTION,
                      15,
                      1,
                      NULL);

    gst_caps_append_structure(caps, structure);

    GstElement* capsfilter = gst_bin_get_by_name(GST_BIN(pipeline), "filter");

    if (capsfilter == NULL)
    {
        printf("Could not retrieve capsfilter from pipeline.");
        return 1;
    }

    g_object_set(G_OBJECT(capsfilter), "caps", caps, NULL);
    gst_object_unref(capsfilter);
    gst_caps_unref(caps);

    /*
      to statically create caps you can reduce the whole procedure to
      GstCaps* caps = gst_caps_from_string("video/x-raw,format=BGRx,width=640,height=480,framerate=30/1");

      gst_parse_lauch allows you to use strings for caps descriptions.
      That means everything until now can be done with:

      GstElement* pipeline = gst_parse_launch("tcambin name=source ! video/x-raw,format=BGRx,width=640,height=480,framerate=30/1 ! videoconvert ! ximagesink", &err);

    */


    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    printf("Press enter to stop the stream.\n");
    getchar();

    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(pipeline);

    return 0;
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
#!/usr/bin/env python3

#
# This example will show you how to start a simply live stream
#

import time
import sys
import gi

gi.require_version("Gst", "1.0")

from gi.repository import Gst


def main():
    """
    """
    Gst.init(sys.argv)  # init gstreamer

    # this line sets the gstreamer default logging level
    # it can be removed in normal applications
    # gstreamer logging can contain verry useful information
    # when debugging your application
    # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
    # for further details
    Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING)

    serial = None

    pipeline = Gst.parse_launch("tcambin name=bin"
                                " ! capsfilter name=filter"
                                " ! videoconvert"
                                " ! ximagesink")

    # serial is defined, thus make the source open that device
    if serial:
        # retrieve the bin element from the pipeline
        camera = pipeline.get_by_name("bin")
        camera.set_property("serial", serial)

    caps = Gst.Caps.new_empty()

    structure = Gst.Structure.new_from_string("video/x-raw")
    structure.set_value("width", 640)
    structure.set_value("height", 480)

    try:
        fraction = Gst.Fraction(30, 1)
        structure.set_value("framerate", fraction)
    except TypeError:
        struc_string = structure.to_string()

        struc_string += ",framerate={}/{}".format(30, 1)
        structure.free()
        structure, end = structure.from_string(struc_string)

    caps.append_structure(structure)

    structure.free()
    # structure is not useable from here on

    capsfilter = pipeline.get_by_name("filter")

    if not capsfilter:
        print("Could not retrieve capsfilter from pipeline.")
        return 1

    capsfilter.set_property("caps", caps)

    # to statically create caps you can reduce the whole procedure to
    # caps = Gst.Caps.from_string("video/x-raw,format=BGRx,width=640,height=480,framerate=30/1");
    #
    # Gst.parse_lauch allows you to use strings for caps descriptions.
    # That means everything until now can be done with:
    #
    # pipeline = Gst.parse_launch("tcambin name=source"
    #                             " ! video/x-raw,format=BGRx,width=640,height=480,framerate=30/1"
    #                             " ! videoconvert ! ximagesink");

    pipeline.set_state(Gst.State.PLAYING)

    print("Press Ctrl-C to stop.")

    # We wait with this thread until a
    # KeyboardInterrupt in the form of a Ctrl-C
    # arrives. This will cause the pipline
    # to be set to state NULL
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        pass
    finally:
        pipeline.set_state(Gst.State.NULL)

    return 0


if __name__ == "__main__":
    sys.exit(main())

06 - softwaretrigger

Triggers single images - instead of a continuous image stream.

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107

/* This example will show you how to trigger images */

#include <gst/gst.h>
#include <stdio.h> /* printf */
#include <tcam-property-1.0.h>
#include <unistd.h> /* sleep  */


int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    const char* serial = NULL; // the serial number of the camera we want to use

    GError* err = NULL;

    GstElement* pipeline =
        gst_parse_launch("tcambin name=source ! video/x-raw,format=BGRx ! videoconvert ! ximagesink ", &err);

    /* test for error */
    if (pipeline == NULL)
    {
        printf("Could not create pipeline. Cause: %s\n", err->message);
        return 1;
    }

    GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline), "source");

    if (serial != NULL)
    {
        GValue val = {};
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);

        g_value_unset(&val);
    }

    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    /*
      This sleep exists only to ensure
      that a live image exists before trigger mode is activated.
      for all other purposes this can be removed.
     */
    sleep(2);

    tcam_property_provider_set_tcam_enumeration(TCAM_PROPERTY_PROVIDER(source), "TriggerMode", "On", &err);

    if (err)
    {
        printf("Error while setting trigger mode: %s\n", err->message);
        g_error_free(err);
        err = NULL;
    }

    while (0 == 0)
    {
        printf("Press 'q' then 'enter' to stop the stream.\n");
        printf("Press 'Enter' to trigger a new image.\n");

        char c = getchar();

        if (c == 'q')
        {
            break;
        }

        tcam_property_provider_set_tcam_command(TCAM_PROPERTY_PROVIDER(source), "TriggerSoftware", &err);
        if (err)
        {
            printf("!!! Could not trigger. !!!\n");
            printf("Error while setting trigger: %s\n", err->message);
            g_error_free(err);
            err = NULL;
        }
        else
        {
            printf("=== Triggered image. ===\n");
        }
    }

    /* deactivate trigger mode */
    /* this is simply to prevent confusion when the camera ist started without wanting to trigger */
    tcam_property_provider_set_tcam_enumeration(TCAM_PROPERTY_PROVIDER(source), "TriggerMode", "Off", &err);

    // this stops the pipeline and frees all resources
    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(source);
    /* the pipeline automatically handles all elements that have been added to it.
       thus they do not have to be cleaned up manually */
    gst_object_unref(pipeline);

    return 0;
}

07 - appsink

Receives images in an application instead of just showing them.

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

/*
  This example will show you how to receive data
  from gstreamer in your application
  and how to get the actual image data
*/

#include <gst/gst.h>
#include <gst/video/video.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


/*
  This function will be called in a separate thread when our appsink
  says there is data for us. user_data has to be defined
  when calling g_signal_connect. It can be used to pass objects etc.
  from your other function to the callback.

  user_data can point to additional data for your usage
            marked as unused to prevent compiler warnings
*/
static GstFlowReturn callback(GstElement* sink, void* user_data __attribute__((unused)))
{
    GstSample* sample = NULL;
    /* Retrieve the buffer */
    g_signal_emit_by_name(sink, "pull-sample", &sample, NULL);

    if (sample)
    {
        // we have a valid sample
        // do things with the image here
        static guint framecount = 0;
        int pixel_data = -1;

        GstBuffer* buffer = gst_sample_get_buffer(sample);
        GstMapInfo info; // contains the actual image
        if (gst_buffer_map(buffer, &info, GST_MAP_READ))
        {
            GstVideoInfo* video_info = gst_video_info_new();
            if (!gst_video_info_from_caps(video_info, gst_sample_get_caps(sample)))
            {
                // Could not parse video info (should not happen)
                g_warning("Failed to parse video info");
                return GST_FLOW_ERROR;
            }

            // pointer to the image data

            // unsigned char* data = info.data;

            // Get the pixel value of the center pixel

            // int stride = video_info->finfo->bits / 8;
            // unsigned int pixel_offset = video_info->width / 2 * stride
            //                             + video_info->width * video_info->height / 2 * stride;

            // this is only one pixel
            // when dealing with formats like BGRx
            // pixel_data will consist out of
            // pixel_offset   => B
            // pixel_offset+1 => G
            // pixel_offset+2 => R
            // pixel_offset+3 => x

            // pixel_data = info.data[pixel_offset];

            gst_buffer_unmap(buffer, &info);
            gst_video_info_free(video_info);
        }

        GstClockTime timestamp = GST_BUFFER_PTS(buffer);
        g_print("Captured frame %d, Pixel Value=%03d Timestamp=%" GST_TIME_FORMAT "            \r",
                framecount,
                pixel_data,
                GST_TIME_ARGS(timestamp));
        framecount++;


        // delete our reference so that gstreamer can handle the sample
        gst_sample_unref(sample);
    }
    return GST_FLOW_OK;
}


int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv);

    const char* serial = NULL; // the serial number of the camera we want to use

    const char* pipeline_str = "tcambin name=source ! videoconvert ! appsink name=sink";

    GError* err = NULL;
    GstElement* pipeline = gst_parse_launch(pipeline_str, &err);

    /* test for error */
    if (pipeline == NULL)
    {
        printf("Could not create pipeline. Cause: %s\n", err->message);
        return 1;
    }

    if (serial != NULL)
    {
        GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline), "source");

        GValue val = {};
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);
        gst_object_unref(source);
    }

    /* retrieve the appsink from the pipeline */
    GstElement* sink = gst_bin_get_by_name(GST_BIN(pipeline), "sink");

    // tell appsink to notify us when it receives an image
    g_object_set(G_OBJECT(sink), "emit-signals", TRUE, NULL);

    // tell appsink what function to call when it notifies us
    g_signal_connect(sink, "new-sample", G_CALLBACK(callback), NULL);

    gst_object_unref(sink);

    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    g_print("Press 'enter' to stop the stream.\n");
    /* wait for user input to end the program */
    getchar();

    // this stops the pipeline and frees all resources
    gst_element_set_state(pipeline, GST_STATE_NULL);

    /*
      the pipeline automatically handles
      all elements that have been added to it.
      thus they do not have to be cleaned up manually
    */
    gst_object_unref(pipeline);

    return 0;
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env python3

#
# This example will show you how to enable trigger-mode
# and how to trigger images with via software trigger.
#


import sys
import gi
import time

gi.require_version("Gst", "1.0")
gi.require_version("GstVideo", "1.0")

from gi.repository import Gst, GstVideo

framecount = 0


def callback(appsink, user_data):
    """
    This function will be called in a separate thread when our appsink
    says there is data for us. user_data has to be defined
    when calling g_signal_connect. It can be used to pass objects etc.
    from your other function to the callback.
    """
    sample = appsink.emit("pull-sample")

    if sample:

        caps = sample.get_caps()

        gst_buffer = sample.get_buffer()

        try:
            (ret, buffer_map) = gst_buffer.map(Gst.MapFlags.READ)

            video_info = GstVideo.VideoInfo()
            video_info.from_caps(caps)

            stride = video_info.finfo.bits / 8

            pixel_offset = int(video_info.width / 2 * stride +
                               video_info.width * video_info.height / 2 * stride)

            # this is only one pixel
            # when dealing with formats like BGRx
            # pixel_data will have to consist out of
            # pixel_offset   => B
            # pixel_offset+1 => G
            # pixel_offset+2 => R
            # pixel_offset+3 => x
            pixel_data = buffer_map.data[pixel_offset]
            timestamp = gst_buffer.pts

            global framecount

            output_str = "Captured frame {}, Pixel Value={} Timestamp={}".format(framecount,
                                                                                 pixel_data,
                                                                                 timestamp)

            print(output_str, end="\r")  # print with \r to rewrite line

            framecount += 1

        finally:
            gst_buffer.unmap(buffer_map)

    return Gst.FlowReturn.OK


def main():

    Gst.init(sys.argv)  # init gstreamer

    # this line sets the gstreamer default logging level
    # it can be removed in normal applications
    # gstreamer logging can contain verry useful information
    # when debugging your application
    # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
    # for further details
    Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING)

    serial = '01719915'

    pipeline = Gst.parse_launch("tcambin name=source"
                                " ! videoconvert"
                                " ! appsink name=sink")

    # test for error
    if not pipeline:
        print("Could not create pipeline.")
        sys.exit(1)

    # The user has not given a serial, so we prompt for one
    if serial is not None:
        source = pipeline.get_by_name("source")
        source.set_property("serial", serial)

    sink = pipeline.get_by_name("sink")

    # tell appsink to notify us when it receives an image
    sink.set_property("emit-signals", True)

    user_data = "This is our user data"

    # tell appsink what function to call when it notifies us
    sink.connect("new-sample", callback, user_data)

    pipeline.set_state(Gst.State.PLAYING)

    print("Press Ctrl-C to stop.")

    # We wait with this thread until a
    # KeyboardInterrupt in the form of a Ctrl-C
    # arrives. This will cause the pipline
    # to be set to state NULL
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        pass
    finally:
        pipeline.set_state(Gst.State.NULL)


if __name__ == "__main__":
    main()

08 - save-stream

Stores a stream in a file.

Show sample code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

/* This example will show you how to save a videostream into a file */

#include <gst/gst.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    const char* serial = NULL; // the serial number of the camera we want to use

    GError* err = NULL;


    GstElement* pipeline =
        gst_parse_launch("tcambin name=bin"
                         " ! video/x-raw,format=BGRx,width=640,height=480,framerate=30/1"
                         " ! tee name=t"
                         " ! queue"
                         " ! videoconvert"
                         " ! ximagesink"
                         " t."
                         " ! queue"
                         " ! videoconvert"
                         " ! avimux"
                         " ! filesink name=fsink",
                         &err);
    /*
      to save a video without live view reduce the pipeline to the following:

      GstElement* pipeline = Gst.parse_launch("tcambin name=bin"
                                              " ! video/x-raw,format=BGRx,width=640,height=480,framerate=30/1"
                                              " ! videoconvert"
                                              " ! avimux"
                                              " ! filesink name=fsink", &err);

    */

    if (serial != NULL)
    {
        GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline), "bin");
        GValue val = {};
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);
        gst_object_unref(source);
    }

    const char* file_location = "/tmp/tiscamera-save-stream.avi";

    GstElement* fsink = gst_bin_get_by_name(GST_BIN(pipeline), "fsink");

    g_object_set(G_OBJECT(fsink), "location", file_location, NULL);

    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    printf("Press Enter to stop the recording\n");
    getchar();

    // this stops the pipeline and frees all resources
    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(fsink);

    /* the pipeline automatically handles all elements that have been added to it.
       thus they do not have to be cleaned up manually */
    gst_object_unref(pipeline);

    printf("Stream saved to: %s\n", file_location);

    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#!/usr/bin/env python3

#
# This example will show you how to save a video stream to a file
#

import time
import sys
import gi

gi.require_version("Gst", "1.0")

from gi.repository import Gst


def main():

    Gst.init(sys.argv)  # init gstreamer

    # this line sets the gstreamer default logging level
    # it can be removed in normal applications
    # gstreamer logging can contain verry useful information
    # when debugging your application
    # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
    # for further details
    Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING)

    serial = None

    pipeline = Gst.parse_launch("tcambin name=bin"
                                " ! video/x-raw,format=BGRx,width=640,height=480,framerate=30/1"
                                " ! tee name=t"
                                " ! queue"
                                " ! videoconvert"
                                " ! ximagesink"
                                " t."
                                " ! queue"
                                " ! videoconvert"
                                " ! avimux"
                                " ! filesink name=fsink")

    # to save a video without live view reduce the pipeline to the following:

    # pipeline = Gst.parse_launch("tcambin name=bin"
    #                             " ! video/x-raw,format=BGRx,width=640,height=480,framerate=30/1"
    #                             " ! videoconvert"
    #                             " ! avimux"
    #                             " ! filesink name=fsink")

    # serial is defined, thus make the source open that device
    if serial is not None:
        camera = pipeline.get_by_name("bin")
        camera.set_property("serial", serial)

    file_location = "/tmp/tiscamera-save-stream.avi"

    fsink = pipeline.get_by_name("fsink")
    fsink.set_property("location", file_location)

    pipeline.set_state(Gst.State.PLAYING)

    print("Press Ctrl-C to stop.")

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        pass
    finally:
        pipeline.set_state(Gst.State.NULL)


if __name__ == "__main__":
    main()

09 - device-lost

Receives device-lost and other messages and react to them.

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

/* This example will show you how to start a live stream from your camera */

#include <gst/gst.h>
#include <stdio.h> /* printf and putchar */
#include <unistd.h> /* usleep */


static GMainLoop* loop;


static gboolean starts_with(const char* a, const char* b)
{
    if (strncmp(a, b, strlen(b)) == 0)
    {
        return 1;
    }
    return 0;
}


static gboolean bus_callback(GstBus* bus __attribute__((unused)), GstMessage* message, gpointer data __attribute__((unused)))
{
    g_print("Got %s message\n", GST_MESSAGE_TYPE_NAME(message));

    switch (GST_MESSAGE_TYPE(message))
    {
        case GST_MESSAGE_ERROR:
        {
            GError* err;
            gchar* debug;

            gst_message_parse_error(message, &err, &debug);
            g_print("Error: %s \n", err->message);

            if (starts_with(err->message, "Device lost ("))
            {
                char* s_str = strstr(err->message, "(");
                const char* serial = strtok(s_str, "()");
                printf("Device lost came from device with serial = %s\n", serial);

                // device lost handling should be initiated here
                // this example simply stops playback
                g_main_loop_quit(loop);
            }

            g_error_free(err);
            g_free(debug);

            break;
        }
        case GST_MESSAGE_INFO:
        {
            break;
        }
        case GST_MESSAGE_EOS:
        {
            /* end-of-stream */
            g_main_loop_quit(loop);
            break;
        }
        default:
        {
            /* unhandled message */
            break;
        }
    }
    return TRUE;
}


int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    const char* serial = NULL; // set this if you do not want the first found device

    GError* err = NULL;

    GstElement* pipeline =
        gst_parse_launch("tcambin name=source ! videoconvert ! ximagesink", &err);

    /* test for error */
    if (pipeline == NULL)
    {
        printf("Could not create pipeline. Cause: %s\n", err->message);
        return 1;
    }

    if (serial != NULL)
    {
        GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline), "source");
        GValue val = {};
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);
        gst_object_unref(source);
    }

    GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));

    gst_bus_add_watch(bus, bus_callback, NULL);

    gst_object_unref(bus);


    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    printf("Disconnect your camera to trigger a device lost or press enter to stop the stream.\n");

    // we work with a event loop to be automatically
    // notified when a new messages occur.
    loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(loop);

    g_main_loop_unref(loop);
    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(pipeline);

    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/usr/bin/env python3

#
# This example will show you how to react to messages on the gstreamer bus.
#

import sys
import re
import gi

gi.require_version("Gst", "1.0")

from gi.repository import Gst, GLib


loop = GLib.MainLoop()


def bus_callback(bus, message, user_data):
    """
    Gstreamer Message Types and how to parse
    https://lazka.github.io/pgi-docs/Gst-1.0/flags.html#Gst.MessageType
    """
    mtype = message.type

    if mtype == Gst.MessageType.EOS:
        # end-of-stream
        loop.quit()
    elif mtype == Gst.MessageType.ERROR:
        # Handle Errors
        err, debug = message.parse_error()
        print(err, debug)

        if err.message.startswith("Device lost ("):

            m = re.search('Device lost \((.*)\)', err.message)
            print("Device lost came from device with serial = {}".format(m.group(1)))

            # device lost handling should be initiated here
            # this example simply stops playback
            loop.quit()

    elif mtype == Gst.MessageType.WARNING:
        # Handle warnings
        err, debug = message.parse_warning()
        print(err, debug)

    return True


def main():

    Gst.init(sys.argv)

    # this line sets the gstreamer default logging level
    # it can be removed in normal applications
    # gstreamer logging can contain verry useful information
    # when debugging your application
    # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
    # for further details
    #Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING)

    serial = None

    pipeline = Gst.parse_launch("tcambin name=source ! videoconvert ! ximagesink sync=false")

    if not pipeline:
        print("Could not create pipeline")
        sys.exit(1)

    if serial:
        src = pipeline.get_by_name("source")
        src.set_property("serial", serial)
        src = None

    bus = pipeline.get_bus()
    bus.add_signal_watch()
    # bus.enable_sync_message_emission()
    bus.connect('message', bus_callback, None)

    # bus.add_watch(bus_callback, None)

    pipeline.set_state(Gst.State.PLAYING)

    print("Disconnect your camera to trigger a device lost or press enter to stop the stream.")

    # we work with a event loop to be automatically
    # be notified when new messages occur.
    loop.run()

    pipeline.set_state(Gst.State.NULL)


if __name__ == "__main__":
    main()

10 - metadata

Read meta information like is-damaged, camera capture time, etc.

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182

/* This example will show you how to receive data from gstreamer in your application
   and how to get the actual iamge data */

#include "gstmetatcamstatistics.h"
#include "tcam-property-1.0.h" /* gobject introspection interface */

#include <gst/gst.h>
#include <gst/video/video.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


static gboolean meta_struc_print(GQuark field_id, const GValue* value, gpointer user_data  __attribute__((unused)))
{
    // GQuark is a gobject internal ID for strings
    // we call the function g_quark_to_string to get the name of the field
    // value is a simple, generic value
    // user_data can contain things you need for further processing

    printf("%s: ", g_quark_to_string(field_id));

    if (G_VALUE_TYPE(value) == G_TYPE_BOOLEAN)
    {
        gboolean val = g_value_get_boolean(value);
        if (val)
        {
            printf(" true\n");
        }
        else
        {
            printf(" false\n");
        }
    }
    else if (G_VALUE_TYPE(value) == G_TYPE_DOUBLE)
    {
        double val = g_value_get_double(value);
        printf("%f\n", val);
    }
    else if (G_VALUE_TYPE(value) == G_TYPE_UINT64)
    {
        guint64 val = g_value_get_uint64(value);
        printf("%lu\n", val);
    }
    else
    {
        printf("value type not implemented\n");
    }

    return TRUE;
}

/*
  This function will be called in a separate thread when our appsink
  says there is data for us. user_data has to be defined when calling g_signal_connect.
 */
static GstFlowReturn callback(GstElement* sink, void* user_data  __attribute__((unused)))
{
    printf("new sample\n");

    GstSample* sample = NULL;
    /* Retrieve the buffer */
    g_signal_emit_by_name(sink, "pull-sample", &sample, NULL);

    if (sample)
    {
        static guint framecount = 0;

        framecount++;

        GstBuffer* buffer = gst_sample_get_buffer(sample);

        // if you need the associated caps
        // GstCaps* c = gst_sample_get_caps(sample);

        GstMeta* meta = gst_buffer_get_meta(buffer, g_type_from_name("TcamStatisticsMetaApi"));

        if (meta)
        {
            printf("We have meta\n");
        }
        else
        {
            g_warning("No meta data available\n");
        }

        GstStructure* struc = ((TcamStatisticsMeta*)meta)->structure;

        // this prints all contained fields
        gst_structure_foreach(struc, meta_struc_print, NULL);

        // to only print selective fields
        // read the documentation
        // https://www.theimagingsource.com/documentation/tiscamera/tcam-gstreamer.html#metadata
        // concerning available fields and call them manually by name

        /*
          guint64 frame_count = 0;
          gst_structure_get_uint64(struc, "frame_count", &frame_count);
          printf("frame_count: %ul\n", frame_count);
        */

        // delete our reference so that gstreamer can handle the sample
        gst_sample_unref(sample);
    }
    return GST_FLOW_OK;
}


int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv);

    const char* serial = NULL; // set this if you do not want the first found device

    GError* err = NULL;

    // some conversion elements will drop the metadata
    // for the sake of this example we will retrieve buffers
    // directly from the src
    const char* pipeline_str = "tcamsrc name=source ! appsink name=sink";

    GstElement* pipeline = gst_parse_launch(pipeline_str, &err);

    /* test for error */
    if (pipeline == NULL)
    {
        printf("Could not create pipeline. Cause: %s\n", err->message);
        return 1;
    }

    if (serial != NULL)
    {
        GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline), "source");
        GValue val = {};
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);
        gst_object_unref(source);
    }

    /* retrieve the appsink from the pipeline */
    GstElement* sink = gst_bin_get_by_name(GST_BIN(pipeline), "sink");

    // tell appsink to notify us when it receives an image
    g_object_set(G_OBJECT(sink), "emit-signals", TRUE, NULL);

    // tell appsink what function to call when it notifies us
    g_signal_connect(sink, "new-sample", G_CALLBACK(callback), NULL);

    gst_object_unref(sink);

    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    g_print("Press 'enter' to stop the stream.\n");
    /* wait for user input to end the program */
    getchar();

    // this stops the pipeline and frees all resources
    gst_element_set_state(pipeline, GST_STATE_NULL);

    /*
      the pipeline automatically handles
      all elements that have been added to it.
      thus they do not have to be cleaned up manually
    */
    gst_object_unref(pipeline);

    return 0;
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python3

#
# This example will show you how to enable trigger-mode
# and how to trigger images with via software trigger.
#

import sys
import gi
import time
import ctypes

gi.require_version("Gst", "1.0")
gi.require_version("GstVideo", "1.0")
gi.require_version("GObject", "2.0")
gi.require_version("GLib", "2.0")

from gi.repository import Gst, GstVideo, GObject, GLib

# workaround for missing GstMeta apis

# load tiscamera GstMeta library
clib = ctypes.CDLL("libtcamgststatistics.so")

# declare input/output type for our helper function
clib.tcam_statistics_get_structure.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]
clib.tcam_statistics_get_structure.restype = ctypes.c_bool

# allocate a c-string with length 320 bytes
# this _should_ be long enough to hold any
# GstStructure string that will be retrieved
# if not change this to a higher number
meta_out_buffer_size = 320
meta_out_buffer = ctypes.create_string_buffer(meta_out_buffer_size)


def get_meta(gst_buffer):
    """
    Check Gst.Buffer for a valid Gst.Meta object
    and return the contained Gst.Structure

    Parameters:
    Gst.Buffer

    Returns:
    Gst.Structure or None in case of error
    """
    meta = gst_buffer.get_meta("TcamStatisticsMetaApi")

    if not meta:
        return None

    # fill meta_out_buffer with the result of gst_structure_get_string(meta->structure)
    ret = clib.tcam_statistics_get_structure(hash(meta), meta_out_buffer, meta_out_buffer_size)

    # ret is a bool indicating successfull string copy
    if ret:
        # ret is bytecode
        # decode it to get a valide str object
        # ret.decode("utf-8")
        structure_string = ctypes.string_at(meta_out_buffer).decode("utf-8")
        struc = Gst.Structure.from_string(structure_string)
        # Gst.Structure.from_string returns a tuple
        # we only want the actual Gst.Structure
        return struc[0]
    return None


def callback(appsink, user_data):
    """
    This function will be called in a separate thread when our appsink
    says there is data for us. user_data has to be defined
    when calling g_signal_connect. It can be used to pass objects etc.
    from your other function to the callback.
    """
    sample = appsink.emit("pull-sample")

    if sample:
        print("new sample")
        # caps = sample.get_caps()

        gst_buffer = sample.get_buffer()

        tcam_meta = get_meta(gst_buffer)
        if tcam_meta:

            def print_structure(field_id, value, user_data):
                """
                """

                name = GLib.quark_to_string(field_id)

                print(f"{name} => {value}")

                # return true as we want to continue iterating
                return True

            # call print structure for all members of the Gst.Structure
            tcam_meta.foreach(print_structure, None)

        else:
            print("No meta")

    # empty line for more readability
    print("")

    return Gst.FlowReturn.OK


def main():

    Gst.init(sys.argv)
    serial = None

    pipeline = Gst.parse_launch("tcambin name=source"
                                " ! appsink name=sink")

    # test for error
    if not pipeline:
        print("Could not create pipeline.")
        sys.exit(1)

    # The user has not given a serial, so we prompt for one
    if serial is not None:
        source = pipeline.get_by_name("source")
        source.set_property("serial", serial)

    sink = pipeline.get_by_name("sink")

    # tell appsink to notify us when it receives an image
    sink.set_property("emit-signals", True)

    user_data = "This is our user data"

    # tell appsink what function to call when it notifies us
    sink.connect("new-sample", callback, user_data)

    pipeline.set_state(Gst.State.PLAYING)

    print("Press Ctrl-C to stop.")

    # We wait with this thread until a
    # KeyboardInterrupt in the form of a Ctrl-C
    # arrives. This will cause the pipline
    # to be set to state NULL
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        pass
    finally:
        pipeline.set_state(Gst.State.NULL)


if __name__ == "__main__":
    main()

11 - json-state

Save and load JSON device state.

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

/* This example will show you how to get/set the JSON property description for a certain camera */

#include "tcam-property-1.0.h" /* gobject introspection interface */

#include <gst/gst.h>
#include <stdio.h> /* printf and putchar */


gboolean block_until_playing(GstElement* pipeline)
{
    while (TRUE)
    {
        GstState state;
        GstState pending;

        // wait 0.1 seconds for something to happen
        GstStateChangeReturn ret = gst_element_get_state(pipeline, &state, &pending, 100000000);

        if (ret == GST_STATE_CHANGE_SUCCESS)
        {
            return TRUE;
        }
        else if (ret == GST_STATE_CHANGE_FAILURE)
        {
            printf("Failed to change state %s %s %s\n",
                   gst_element_state_change_return_get_name(ret),
                   gst_element_state_get_name(state),
                   gst_element_state_get_name(pending));

            return FALSE;
        }
    }
}


int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    GError* err = NULL;

    // this is a placeholder definition
    // normally your pipeline would be defined here
    GstElement* pipeline = gst_parse_launch("tcambin name=source ! fakesink", &err);

    if (pipeline == NULL)
    {
        printf("Unable to create pipeline: %s\n", err->message);
        g_free(err);
        return 1;
    }

    GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline), "source");

    const char* serial = NULL;

    if (serial != NULL)
    {
        GValue val = {};
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);
    }

    // in the READY state the camera will always be initialized
    // in the PLAYING state additional properties may appear from gstreamer elements
    gst_element_set_state(source, GST_STATE_PLAYING);

    // helper function to ensure we have the right state
    // alternatively wait for the first image
    if (!block_until_playing(pipeline))
    {
        printf("Unable to start pipeline. \n");
    }

    // Device is now in a state for interactions
    GValue state = G_VALUE_INIT;
    g_value_init(&state, G_TYPE_STRING);

    //We print the properties for a before/after comparison,
    g_object_get_property(G_OBJECT(source), "tcam-properties-json", &state);

    printf("State of device is:\n%s", g_value_get_string(&state));

    // Change JSON description here
    // not part of this example

    // second print for the before/after comparison
    g_object_set_property(G_OBJECT(source), "tcam-properties-json", &state);

    //reread state to see if anything changed
    g_object_get_property(G_OBJECT(source), "tcam-properties-json", &state);

    printf("State of device is:\n%s", g_value_get_string(&state));

    // cleanup, reset state
    gst_element_set_state(source, GST_STATE_NULL);

    gst_object_unref(source);
    gst_object_unref(pipeline);
    g_value_unset(&state);

    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/usr/bin/env python3

#
# This example will show you how to set properties
#

import sys
import gi

gi.require_version("Gst", "1.0")

from gi.repository import Gst


def block_until_playing(pipeline):

    while True:
        # wait 0.1 seconds for something to happen
        change_return, state, pending = pipeline.get_state(100000000)
        if change_return == Gst.StateChangeReturn.SUCCESS:
            return True
        elif change_return == Gst.StateChangeReturn.FAILURE:
            print("Failed to change state {} {} {}".format(change_return,
                                                           state,
                                                           pending))
            return False


def main():

    Gst.init(sys.argv)

    # this line sets the gstreamer default logging level
    # it can be removed in normal applications
    # gstreamer logging can contain verry useful information
    # when debugging your application
    # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
    # for further details
    Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING)

    pipeline = Gst.parse_launch("tcambin name=source ! fakesink")

    if not pipeline:
        print("Unable to create pipeline")
        return 1

    # Set this to a serial string for a specific camera
    serial = None

    camera = pipeline.get_by_name("source")

    if serial:
        # This is gstreamer set_property
        camera.set_property("serial", serial)

    # in the READY state the camera will always be initialized
    # in the PLAYING state additional properties may appear from gstreamer elements
    pipeline.set_state(Gst.State.PLAYING)

    if not block_until_playing(pipeline):
        print("Unable to start pipeline")

    # Print properties for a before/after comparison
    state = camera.get_property("tcam-properties-json")

    print(f"State of device is:\n{state}")

    # Change JSON description here
    # not part of this example

    camera.set_property("tcam-properties-json", state)

    # Print properties for a before/after comparison
    state = camera.get_property("tcam-properties-json")
    print(f"State of device is:\n{state}")

    # cleanup, reset state
    pipeline.set_state(Gst.State.NULL)


if __name__ == "__main__":
    sys.exit(main())

12 - tcam-properties

Save and load properties via GstStructure.

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

/* This example will show you how to get/set the properties through a description string */

#include <gst/gst.h>
#include <stdio.h> /* printf and putchar */


gboolean block_until_state_change_done (GstElement* pipeline)
{
    while (TRUE)
    {
        GstState state;
        GstState pending;

        // wait 0.1 seconds for something to happen
        GstStateChangeReturn ret = gst_element_get_state(pipeline, &state, &pending, 100000000);

        if (ret == GST_STATE_CHANGE_SUCCESS || ret == GST_STATE_CHANGE_NO_PREROLL)
        {
            return TRUE;
        }
        else if (ret == GST_STATE_CHANGE_FAILURE)
        {
            printf("Failed to change state %s %s %s\n",
                   gst_element_state_change_return_get_name(ret),
                   gst_element_state_get_name(state),
                   gst_element_state_get_name(pending));

            return FALSE;
        }
    }
}


static void print_current_properties (GstElement* source)
{
    // Initialize the GValue
    GValue current_properties = G_VALUE_INIT;
    g_value_init(&current_properties, GST_TYPE_STRUCTURE);

    // Get the GObject property
    g_object_get_property(G_OBJECT(source), "tcam-properties", &current_properties);

    // get a string to print the current property state
    char* string = gst_structure_to_string(gst_value_get_structure(&current_properties));
    printf("Current properties:\n%s\n", string );
    g_free(string); // free the string

    g_value_unset( &current_properties );  // free the GstStructure in the GValue
}


int main (int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain very useful information
       when debugging your application
       # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    GError* err = NULL;

    // this is a placeholder definition
    // normally your pipeline would be defined here
    GstElement* pipeline = gst_parse_launch("tcambin name=source ! fakesink", &err);

    if (pipeline == NULL)
    {
        printf("Unable to create pipeline: %s\n", err->message);
        g_free(err);
        return 1;
    }

    GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline), "source");

    const char* serial = NULL;

    if (serial != NULL)
    {
        GValue val = G_VALUE_INIT;
        g_value_init(&val, G_TYPE_STRING);
        g_value_set_static_string(&val, serial);

        g_object_set_property(G_OBJECT(source), "serial", &val);
    }

    // in the READY state the camera will always be initialized
    gst_element_set_state(source, GST_STATE_READY);

    // helper function to wait for async state change to be done
    if (!block_until_state_change_done(pipeline))
    {
        printf("Unable to start pipeline. \n");
        return 2;
    }

    print_current_properties( source );

    // Create a new structure
    GstStructure* new_property_struct = gst_structure_new_empty("tcam");

    // Change 2 properties so that we can see a 'difference'
    gst_structure_set(new_property_struct,
                      "ExposureAuto", G_TYPE_STRING, "Off",
                      "ExposureTime", G_TYPE_DOUBLE, 35000.0,
                      NULL );

    GValue new_state = G_VALUE_INIT;
    g_value_init(&new_state, GST_TYPE_STRUCTURE);
    gst_value_set_structure( &new_state, new_property_struct);

    // Set the new property settings
    g_object_set_property(G_OBJECT(source), "tcam-properties", &new_state);

    g_value_unset(&new_state);
    gst_structure_free(new_property_struct);

    // Print the property settings after the change above
    print_current_properties(source);

    // cleanup, reset state
    gst_element_set_state(source, GST_STATE_NULL);

    gst_object_unref(source);
    gst_object_unref(pipeline);

    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env python3

#
# This example will show you how to get/set the properties through a description string
#

import sys
import gi

gi.require_version("Gst", "1.0")

from gi.repository import Gst


def block_until_playing(pipeline):

    while True:
        # wait 0.1 seconds for something to happen
        change_return, state, pending = pipeline.get_state(100000000)
        if change_return == Gst.StateChangeReturn.SUCCESS:
            return True
        elif change_return == Gst.StateChangeReturn.FAILURE:
            print("Failed to change state {} {} {}".format(change_return,
                                                           state,
                                                           pending))
            return False


def main():

    Gst.init(sys.argv)

    # this line sets the gstreamer default logging level
    # it can be removed in normal applications
    # gstreamer logging can contain very useful information
    # when debugging your application
    # see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
    # for further details
    Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING)

    pipeline = Gst.parse_launch("tcambin name=source ! fakesink")

    if not pipeline:
        print("Unable to create pipeline")
        return 1

    serial = None

    source = pipeline.get_by_name("source")

    # The user has not given a serial, so we prompt for one
    if serial is not None:
        source.set_property("serial", serial)

    # in the READY state the camera will always be initialized
    # in the PLAYING state additional properties may appear from gstreamer elements
    pipeline.set_state(Gst.State.PLAYING)

    if not block_until_playing(pipeline):
        print("Unable to start pipeline")

    # Print properties for a before/after comparison
    state = source.get_property("tcam-properties")

    print(f"State of device is:\n{state.to_string()}")

    # Create new structure
    # containing changes we want to apply

    new_state = Gst.Structure.new_empty("tcam")

    new_state.set_value("ExposureAuto", "Off")
    new_state.set_value("ExposureTime", 35000.0)

    # this can also be done by calling Gst.Structure.from_string()

    source.set_property("tcam-properties", new_state)

    # Print properties for a before/after comparison
    state = source.get_property("tcam-properties")
    print(f"New state of device is:\n{state.to_string()}")

    # cleanup, reset state
    pipeline.set_state(Gst.State.NULL)


if __name__ == "__main__":
    sys.exit(main())

13 - GstQuery

Shows how to use GstQuery for GstCaps verification.

Show sample code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109

/*
  This example will show you how to query the tcamsrc
  - to verify potential framerates
  - to verify potential caps
 */

#include <gst/gst.h>
#include <stdio.h> /* printf and putchar */


int main(int argc, char* argv[])
{
    /* this line sets the gstreamer default logging level
       it can be removed in normal applications
       gstreamer logging can contain verry useful information
       when debugging your application
       see https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
       for further details
    */
    gst_debug_set_default_threshold(GST_LEVEL_WARNING);

    gst_init(&argc, &argv); // init gstreamer

    GError* err = NULL;
    const char* pipeline_desc = "tcambin name=bin ! videoconvert ! ximagesink";

    GstElement* pipeline = gst_parse_launch(pipeline_desc, &err);

    /* test for error */
    if (pipeline == NULL)
    {
        printf("Could not create pipeline. Cause: %s\n", err->message);
        return 1;
    }
    GstElement* tcambin = gst_bin_get_by_name(GST_BIN(pipeline), "bin");

    gst_element_set_state(pipeline, GST_STATE_READY);


    /* retrieve the source
       these queries have to be performed on the source
       as the tcambin might alter the query
       which we do not want
    */
    GstElement* source = gst_bin_get_by_name(GST_BIN(tcambin), "tcambin-source");

    GstCaps* framerate_query_caps =
        gst_caps_from_string("video/x-bayer,format=rggb,width=640,height=480");

    // if you have a mono camera try these instead
    // GstCaps* framerate_query_caps =
    //        gst_caps_from_string("video/x-raw,format=GRAY8,width=640,height=480");

    GstQuery* framerate_query = gst_query_new_caps(framerate_query_caps);

    gst_caps_unref(framerate_query_caps);

    if (gst_element_query(source, framerate_query))
    {
        // no transfer, nothing has to be freed
        GstCaps* query_result_caps = NULL;
        gst_query_parse_caps_result(framerate_query, &query_result_caps);

        char* result_caps_string = gst_caps_to_string(query_result_caps);
        printf("Camera supports these framerates: %s\n", result_caps_string);
        g_free(result_caps_string);
    }

    gst_query_unref(framerate_query);

    /*
      verify specific caps
      for this all needed fields have to be set(format, width, height and framerate)
    */

    GstCaps* accept_query_caps =
        gst_caps_from_string("video/x-bayer,format=rggb,width=640,height=480,framerate=30/1");

    GstQuery* accept_query = gst_query_new_accept_caps(accept_query_caps);

    gst_caps_unref(accept_query_caps);

    if (gst_element_query(source, accept_query))
    {
        gboolean accepts_caps;
        gst_query_parse_accept_caps_result(accept_query, &accepts_caps);

        if (accepts_caps)
        {
            printf("Caps are accepted\n");
        }
        else
        {
            printf("Caps are not accepted\n");
        }
    }

    gst_query_unref(accept_query);

    gst_object_unref(source);
    gst_object_unref(tcambin);

    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(pipeline);

    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/usr/bin/env python3

#
# This example will show you how to query the tcamsrc
# - to verify potential framerates
# - to verify potential caps
#

import sys
import gi
import time

gi.require_version("Gst", "1.0")

from gi.repository import  Gst

def main():

    Gst.init(sys.argv)

    pipeline = Gst.parse_launch("tcambin name=bin ! videoconvert ! ximagesink ")

    pipeline.set_state(Gst.State.READY)

    tcambin = pipeline.get_by_name("bin")

    # retrieve the source
    # these queries have to be performed on the source
    # as the tcambin might alter the query
    # which we do not want
    source = tcambin.get_by_name("tcambin-source")

    framerate_query_caps = Gst.Caps.from_string("video/x-bayer,format=rggb,width=640,height=480")
    # if you have a mono camera try these instead
    # framerate_query_caps = Gst.Caps.from_string("video/x-raw,format=GRAY8.width=640,height=480")

    framerate_query = Gst.Query.new_caps(framerate_query_caps)

    if source.query(framerate_query):

        # the result caps will contain our framerate_query_caps + all potential framerates
        supported_framerate_caps = framerate_query.parse_caps_result()
        print("Camera supports these framerates: {}".format(supported_framerate_caps.to_string()))

    #
    # verify specific caps
    # for this all needed fields have to be set (format, width, height and framerate)
    #

    accept_query_caps = Gst.Caps.from_string("video/x-bayer,format=rggb,width=640,height=480,framerate=30/1")

    accept_query = Gst.Query.new_accept_caps(accept_query_caps)

    if source.query(accept_query):

        if accept_query.parse_accept_caps_result():
            print("Caps are supported")
        else:
            print("Caps are not supported")

    pipeline.set_state(Gst.State.NULL)
    return 0


if __name__ == "__main__":
    sys.exit(main())

Further Examples

For extended examples, look through the examples repository.

https://github.com/TheImagingSource/Linux-tiscamera-Programming-Samples

It contains examples on how to interact with OpenCV, ROS, GUI toolkits and much more.