GStreamer는 지원하는 두 가지 유형의 metadata를 명확하게 구분합니다. 첫 번째는 비기술적인 방식으로 스트림의 콘텐츠를 설명하는 stream tag, 두 번째는 스트림 속성에 대한 다소 기술적인 설명인 stream-info 입니다.. Stream tag의 예에는 노래 저자, 노래 제목 또는 해당 노래가 속한 앨범이 포함됩니다. Stream-info의 예로는 비디오 크기, 오디오 samplerate, 사용된 코덱 등이 있습니다.
Tag는 GStreamer tagging 시스템을 사용하여 처리됩니다. Stream-info는 해당 pad에 대한 현재 (협상된) GstCap을 가져와서 GstPad에서 검색할 수 있습니다.
Metadata 읽기
스트림 정보는 GstPad에서 가장 쉽게 얻을 수 있습니다. 이를 위해서는 스트림 정보를 원하는 모든 pad에 대한 액세스가 필요합니다. 이 접근 방식은 Metadata를 위한 capabilities 사용에서 이미 논의 되었습니다. 그러므로 여기서는 생략하겠습니다.
Tag 읽기는 GStreamer의 bus를 통해 수행됩니다. GST_MESSAGE_TAG 메시지를 확인하고 원하는 대로 처리할 수 있습니다. 이에 대해서는 이전에 Bus에서 논의한 바 있습니다.
그러나 GST_MESSAGE_TAG 메시지는 여러 번 생성될 수 있으며 일관된 방식으로 tag를 집계하고 표시하는 것은 애플리케이션의 책임입니다. 이는 gst_tag_list_merge()를 사용하여 수행할 수 있지만 새 노래를 로드할 때나 인터넷 라디오를 들을 때 몇 분마다 캐시를 비워야 합니다. 또한 GST_TAG_MERGE_PREPEND를 병합 모드로 사용하여 새 제목 (나중에 추가된)이 이전 제목보다 우선하도록 하세요.
다음 예에서는 파일에서 tag를 추출하고 출력하는 방법을 보여줍니다.
/* compile with:
* gcc -o tags tags.c `pkg-config --cflags --libs gstreamer-1.0` */
#include <gst/gst.h>
static void
print_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
{
int i, num;
num = gst_tag_list_get_tag_size (list, tag);
for (i = 0; i < num; ++i) {
const GValue *val;
/* Note: when looking for specific tags, use the gst_tag_list_get_xyz() API,
* we only use the GValue approach here because it is more generic */
val = gst_tag_list_get_value_index (list, tag, i);
if (G_VALUE_HOLDS_STRING (val)) {
g_print ("\t%20s : %s\n", tag, g_value_get_string (val));
} else if (G_VALUE_HOLDS_UINT (val)) {
g_print ("\t%20s : %u\n", tag, g_value_get_uint (val));
} else if (G_VALUE_HOLDS_DOUBLE (val)) {
g_print ("\t%20s : %g\n", tag, g_value_get_double (val));
} else if (G_VALUE_HOLDS_BOOLEAN (val)) {
g_print ("\t%20s : %s\n", tag,
(g_value_get_boolean (val)) ? "true" : "false");
} else if (GST_VALUE_HOLDS_BUFFER (val)) {
GstBuffer *buf = gst_value_get_buffer (val);
guint buffer_size = gst_buffer_get_size (buf);
g_print ("\t%20s : buffer of size %u\n", tag, buffer_size);
} else if (GST_VALUE_HOLDS_DATE_TIME (val)) {
GstDateTime *dt = g_value_get_boxed (val);
gchar *dt_str = gst_date_time_to_iso8601_string (dt);
g_print ("\t%20s : %s\n", tag, dt_str);
g_free (dt_str);
} else {
g_print ("\t%20s : tag of type '%s'\n", tag, G_VALUE_TYPE_NAME (val));
}
}
}
static void
on_new_pad (GstElement * dec, GstPad * pad, GstElement * fakesink)
{
GstPad *sinkpad;
sinkpad = gst_element_get_static_pad (fakesink, "sink");
if (!gst_pad_is_linked (sinkpad)) {
if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
g_error ("Failed to link pads!");
}
gst_object_unref (sinkpad);
}
int
main (int argc, char ** argv)
{
GstElement *pipe, *dec, *sink;
GstMessage *msg;
gchar *uri;
gst_init (&argc, &argv);
if (argc < 2)
g_error ("Usage: %s FILE or URI", argv[0]);
if (gst_uri_is_valid (argv[1])) {
uri = g_strdup (argv[1]);
} else {
uri = gst_filename_to_uri (argv[1], NULL);
}
pipe = gst_pipeline_new ("pipeline");
dec = gst_element_factory_make ("uridecodebin", NULL);
g_object_set (dec, "uri", uri, NULL);
gst_bin_add (GST_BIN (pipe), dec);
sink = gst_element_factory_make ("fakesink", NULL);
gst_bin_add (GST_BIN (pipe), sink);
g_signal_connect (dec, "pad-added", G_CALLBACK (on_new_pad), sink);
gst_element_set_state (pipe, GST_STATE_PAUSED);
while (TRUE) {
GstTagList *tags = NULL;
msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe),
GST_CLOCK_TIME_NONE,
GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_TAG | GST_MESSAGE_ERROR);
if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_TAG) /* error or async_done */
break;
gst_message_parse_tag (msg, &tags);
g_print ("Got tags from element %s:\n", GST_OBJECT_NAME (msg->src));
gst_tag_list_foreach (tags, print_one_tag, NULL);
g_print ("\n");
gst_tag_list_unref (tags);
gst_message_unref (msg);
}
if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
GError *err = NULL;
gst_message_parse_error (msg, &err, NULL);
g_printerr ("Got error: %s\n", err->message);
g_error_free (err);
}
gst_message_unref (msg);
gst_element_set_state (pipe, GST_STATE_NULL);
gst_object_unref (pipe);
g_free (uri);
return 0;
}
Tag 쓰기
Tag 쓰기는 GstTagSetter 인터페이스를 사용하여 수행됩니다. 파이프라인에 tag-set-supporting element만 있으면 됩니다.
파이프라인의 element 중 태그 쓰기를 지원하는지 확인하려면 gst_bin_iterate_all_by_interface (파이프라인, GST_TYPE_TAG_SETTER) 함수를 사용할 수 있습니다. 일반적으로 인코더 또는 muxer와 같은 resulting element에서 tag 목록과 함께 gst_tag_setter_merge_tags() 또는 개별 tag와 함께 gst_tag_setter_add_tags()를 사용하여 tag를 설정할 수 있습니다.
GStreamer tag 지원의 멋진 추가 기능은 tag가 파이프라인에 보존된다는 것입니다. 즉, tag가 포함된 파일 하나를 다른 tag-supporting 미디어 타입으로 트랜스코딩하면 tag가 데이터 스트림의 일부로 처리되어 새로 작성된 미디어 파일에 병합됩니다.
원문: Metadata (gstreamer.freedesktop.org)
Metadata
GStreamer makes a clear distinction between the two types of metadata it supports: Stream tags, which describe the content of a stream in a non-technical way; and Stream-info, which is a somewhat technical description of the properties of a stream. Stream
gstreamer.freedesktop.org
'IT와 개발 > GStreamer Study' 카테고리의 다른 글
Clocks and synchronization in GStreamer (3) | 2024.06.07 |
---|---|
Interfaces (3) | 2024.05.31 |
Position tracking and seeking (0) | 2024.05.17 |
Your first application (0) | 2024.05.10 |
Buffers and Events (0) | 2024.05.03 |