/src/gstreamer/subprojects/gst-plugins-base/gst-libs/gst/video/video-sei.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* GStreamer |
2 | | * Copyright (C) 2021 Fluendo S.A. <support@fluendo.com> |
3 | | * Authors: Andoni Morales Alastruey <amorales@fluendo.com> |
4 | | * |
5 | | * This library is free software; you can redistribute it and/or |
6 | | * modify it under the terms of the GNU Library General Public |
7 | | * License as published by the Free Software Foundation; either |
8 | | * version 2 of the License, or (at your option) any later version. |
9 | | * |
10 | | * This library is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | | * Library General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU Library General Public |
16 | | * License along with this library; if not, write to the |
17 | | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
18 | | * Boston, MA 02110-1301, USA. |
19 | | */ |
20 | | |
21 | | #ifdef HAVE_CONFIG_H |
22 | | # include "config.h" |
23 | | #endif |
24 | | |
25 | | #include <string.h> |
26 | | #include <gst/base/gstbytereader.h> |
27 | | #include "video-sei.h" |
28 | | |
29 | | /** |
30 | | * SECTION:gstvideosei |
31 | | * @title: GstVideo SEI Unregistered User Data |
32 | | * @short_description: Utilities for SEI User Data Unregistered |
33 | | * |
34 | | * A collection of objects and methods to assist with SEI User Data Unregistered |
35 | | * metadata in H.264 and H.265 streams. |
36 | | * |
37 | | * Since: 1.22 |
38 | | */ |
39 | | |
40 | | #ifndef GST_DISABLE_GST_DEBUG |
41 | | #define GST_CAT_DEFAULT ensure_debug_category() |
42 | | static GstDebugCategory * |
43 | | ensure_debug_category (void) |
44 | 0 | { |
45 | 0 | static gsize cat_gonce = 0; |
46 | |
|
47 | 0 | if (g_once_init_enter (&cat_gonce)) { |
48 | 0 | gsize cat_done; |
49 | |
|
50 | 0 | cat_done = (gsize) _gst_debug_category_new ("video-sei", 0, |
51 | 0 | "H.264 / H.265 SEI messages utilities"); |
52 | |
|
53 | 0 | g_once_init_leave (&cat_gonce, cat_done); |
54 | 0 | } |
55 | |
|
56 | 0 | return (GstDebugCategory *) cat_gonce; |
57 | 0 | } |
58 | | #else |
59 | | #define ensure_debug_category() /* NOOP */ |
60 | | #endif /* GST_DISABLE_GST_DEBUG */ |
61 | | |
62 | | /* SEI User Data Unregistered implementation */ |
63 | | |
64 | | /** |
65 | | * gst_video_sei_user_data_unregistered_meta_api_get_type: |
66 | | * |
67 | | * Returns: #GType for the #GstVideoSEIUserDataUnregisteredMeta structure. |
68 | | * |
69 | | * Since: 1.22 |
70 | | */ |
71 | | GType |
72 | | gst_video_sei_user_data_unregistered_meta_api_get_type (void) |
73 | 0 | { |
74 | 0 | static GType type = 0; |
75 | |
|
76 | 0 | if (g_once_init_enter (&type)) { |
77 | 0 | static const gchar *tags[] = { |
78 | 0 | GST_META_TAG_VIDEO_STR, |
79 | 0 | NULL |
80 | 0 | }; |
81 | 0 | GType _type = |
82 | 0 | gst_meta_api_type_register ("GstVideoSEIUserDataUnregisteredMetaAPI", |
83 | 0 | tags); |
84 | 0 | g_once_init_leave (&type, _type); |
85 | 0 | } |
86 | 0 | return type; |
87 | 0 | } |
88 | | |
89 | | static gboolean |
90 | | gst_video_sei_user_data_unregistered_meta_init (GstMeta * meta, gpointer params, |
91 | | GstBuffer * buffer) |
92 | 0 | { |
93 | 0 | GstVideoSEIUserDataUnregisteredMeta *emeta = |
94 | 0 | (GstVideoSEIUserDataUnregisteredMeta *) meta; |
95 | |
|
96 | 0 | emeta->data = NULL; |
97 | 0 | emeta->size = 0; |
98 | |
|
99 | 0 | return TRUE; |
100 | 0 | } |
101 | | |
102 | | static gboolean |
103 | | gst_video_sei_user_data_unregistered_meta_transform (GstBuffer * dest, |
104 | | GstMeta * meta, GstBuffer * buffer, GQuark type, gpointer data) |
105 | 0 | { |
106 | 0 | GstVideoSEIUserDataUnregisteredMeta *smeta = |
107 | 0 | (GstVideoSEIUserDataUnregisteredMeta *) meta; |
108 | |
|
109 | 0 | if (GST_META_TRANSFORM_IS_COPY (type)) { |
110 | 0 | GST_DEBUG ("copy SEI User Data Unregistered metadata"); |
111 | 0 | gst_buffer_add_video_sei_user_data_unregistered_meta (dest, |
112 | 0 | smeta->uuid, smeta->data, smeta->size); |
113 | 0 | return TRUE; |
114 | 0 | } else { |
115 | | /* return FALSE, if transform type is not supported */ |
116 | 0 | return FALSE; |
117 | 0 | } |
118 | 0 | } |
119 | | |
120 | | static void |
121 | | gst_video_sei_user_data_unregistered_meta_free (GstMeta * meta, GstBuffer * buf) |
122 | 0 | { |
123 | 0 | GstVideoSEIUserDataUnregisteredMeta *smeta = |
124 | 0 | (GstVideoSEIUserDataUnregisteredMeta *) meta; |
125 | |
|
126 | 0 | g_free (smeta->data); |
127 | 0 | smeta->data = NULL; |
128 | 0 | } |
129 | | |
130 | | /** |
131 | | * gst_video_sei_user_data_unregistered_meta_get_info: |
132 | | * |
133 | | * Returns: #GstMetaInfo pointer that describes #GstVideoSEIUserDataUnregisteredMeta. |
134 | | * |
135 | | * Since: 1.22 |
136 | | */ |
137 | | const GstMetaInfo * |
138 | | gst_video_sei_user_data_unregistered_meta_get_info (void) |
139 | 0 | { |
140 | 0 | static const GstMetaInfo *meta_info = NULL; |
141 | |
|
142 | 0 | if (g_once_init_enter ((GstMetaInfo **) & meta_info)) { |
143 | 0 | const GstMetaInfo *mi = |
144 | 0 | gst_meta_register (GST_VIDEO_SEI_USER_DATA_UNREGISTERED_META_API_TYPE, |
145 | 0 | "GstVideoSEIUserDataUnregisteredMeta", |
146 | 0 | sizeof (GstVideoSEIUserDataUnregisteredMeta), |
147 | 0 | gst_video_sei_user_data_unregistered_meta_init, |
148 | 0 | gst_video_sei_user_data_unregistered_meta_free, |
149 | 0 | gst_video_sei_user_data_unregistered_meta_transform); |
150 | 0 | g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) mi); |
151 | 0 | } |
152 | 0 | return meta_info; |
153 | 0 | } |
154 | | |
155 | | /** |
156 | | * gst_buffer_add_video_sei_user_data_unregistered_meta: |
157 | | * @buffer: a #GstBuffer |
158 | | * @uuid: User Data Unregistered UUID |
159 | | * @data: (transfer none) (allow-none): SEI User Data Unregistered buffer |
160 | | * @size: size of the data buffer |
161 | | * |
162 | | * Attaches #GstVideoSEIUserDataUnregisteredMeta metadata to @buffer with the given |
163 | | * parameters. |
164 | | * |
165 | | * Returns: (transfer none): the #GstVideoSEIUserDataUnregisteredMeta on @buffer. |
166 | | * |
167 | | * Since: 1.22 |
168 | | */ |
169 | | GstVideoSEIUserDataUnregisteredMeta * |
170 | | gst_buffer_add_video_sei_user_data_unregistered_meta (GstBuffer * buffer, |
171 | | guint8 uuid[16], guint8 * data, gsize size) |
172 | 0 | { |
173 | 0 | GstVideoSEIUserDataUnregisteredMeta *meta; |
174 | 0 | g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL); |
175 | | |
176 | 0 | meta = (GstVideoSEIUserDataUnregisteredMeta *) gst_buffer_add_meta (buffer, |
177 | 0 | GST_VIDEO_SEI_USER_DATA_UNREGISTERED_META_INFO, NULL); |
178 | 0 | g_assert (meta != NULL); |
179 | 0 | memcpy (meta->uuid, uuid, 16); |
180 | 0 | meta->data = g_malloc (size); |
181 | 0 | memcpy (meta->data, data, size); |
182 | 0 | meta->size = size; |
183 | |
|
184 | 0 | return meta; |
185 | 0 | } |
186 | | |
187 | | /** |
188 | | * gst_video_sei_user_data_unregistered_parse_precision_time_stamp: |
189 | | * @user_data: (transfer none): a #GstVideoSEIUserDataUnregisteredMeta |
190 | | * @status: (out): User Data Unregistered UUID |
191 | | * @precision_time_stamp: (out): The parsed Precision Time Stamp SEI |
192 | | * |
193 | | * Parses and returns the Precision Time Stamp (ST 0604) from the SEI User Data Unregistered buffer |
194 | | * |
195 | | * Returns: True if data is a Precision Time Stamp and it was parsed correctly |
196 | | * |
197 | | * Since: 1.22 |
198 | | */ |
199 | | gboolean |
200 | | gst_video_sei_user_data_unregistered_parse_precision_time_stamp |
201 | | (GstVideoSEIUserDataUnregisteredMeta * user_data, guint8 * status, |
202 | 0 | guint64 * precision_time_stamp) { |
203 | 0 | guint8 *data = user_data->data; |
204 | |
|
205 | 0 | if (memcmp (user_data->uuid, &H264_MISP_MICROSECTIME, 16) != 0 && |
206 | 0 | memcmp (user_data->uuid, &H265_MISP_MICROSECONDS, 16) != 0 && |
207 | 0 | memcmp (user_data->uuid, &H265_MISP_NANOSECONDS, 16) != 0) { |
208 | 0 | GST_WARNING |
209 | 0 | ("User Data Unregistered UUID is not a known MISP Timestamp UUID"); |
210 | 0 | return FALSE; |
211 | 0 | } |
212 | | |
213 | 0 | if (user_data->size < 12) { |
214 | 0 | GST_WARNING ("MISP Precision Time Stamp data size is too short, ignoring"); |
215 | 0 | return FALSE; |
216 | 0 | } |
217 | | |
218 | | /* Status */ |
219 | 0 | *status = data[0]; |
220 | |
|
221 | 0 | *precision_time_stamp = |
222 | | /* Two MS bytes of Time Stamp (microseconds) */ |
223 | 0 | _GST_GET (data, 1, 64, 56) | _GST_GET (data, 2, 64, 48) | |
224 | | /* Start Code Emulation Prevention Byte (0xFF) */ |
225 | | /* Two next MS bytes of Time Stamp (microseconds) */ |
226 | 0 | _GST_GET (data, 4, 64, 40) | _GST_GET (data, 5, 64, 32) | |
227 | | /* Start Code Emulation Prevention Byte (0xFF) */ |
228 | | /* Two LS bytes of Time Stamp (microseconds) */ |
229 | 0 | _GST_GET (data, 7, 64, 24) | _GST_GET (data, 8, 64, 16) | |
230 | | /* Start Code Emulation Prevention Byte (0xFF) */ |
231 | | /* Two next LS bytes of Time Stamp (microseconds) */ |
232 | 0 | _GST_GET (data, 10, 64, 8) | _GST_GET (data, 11, 64, 0); |
233 | |
|
234 | 0 | return TRUE; |
235 | 0 | } |