1 /* GStreamer RTMP Library
2 * Copyright (C) 2013 David Schleef <ds@schleef.org>
3 * Copyright (C) 2017 Make.TV, Inc. <info@make.tv>
4 * Contact: Jan Alexander Steffens (heftig) <jsteffens@make.tv>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
19 * Boston, MA 02110-1335, USA.
26 #include "rtmputils.h"
29 static void read_all_bytes_done (GObject * source, GAsyncResult * result,
31 static void write_all_bytes_done (GObject * source, GAsyncResult * result,
33 static void write_all_buffer_done (GObject * source, GAsyncResult * result,
37 gst_rtmp_byte_array_append_bytes (GByteArray * bytearray, GBytes * bytes)
43 g_return_if_fail (bytearray);
45 offset = bytearray->len;
46 data = g_bytes_get_data (bytes, &size);
48 g_return_if_fail (data);
50 g_byte_array_set_size (bytearray, offset + size);
51 memcpy (bytearray->data + offset, data, size);
55 gst_rtmp_input_stream_read_all_bytes_async (GInputStream * stream, gsize count,
56 int io_priority, GCancellable * cancellable, GAsyncReadyCallback callback,
62 g_return_if_fail (G_IS_INPUT_STREAM (stream));
64 task = g_task_new (stream, cancellable, callback, user_data);
66 ba = g_byte_array_sized_new (count);
67 g_byte_array_set_size (ba, count);
68 g_task_set_task_data (task, ba, (GDestroyNotify) g_byte_array_unref);
70 g_input_stream_read_all_async (stream, ba->data, count, io_priority,
71 cancellable, read_all_bytes_done, task);
75 read_all_bytes_done (GObject * source, GAsyncResult * result,
78 GInputStream *is = G_INPUT_STREAM (source);
79 GTask *task = user_data;
80 GByteArray *ba = g_task_get_task_data (task);
86 res = g_input_stream_read_all_finish (is, result, &bytes_read, &error);
88 g_task_return_error (task, error);
89 g_object_unref (task);
93 g_byte_array_set_size (ba, bytes_read);
94 bytes = g_byte_array_free_to_bytes (g_byte_array_ref (ba));
96 g_task_return_pointer (task, bytes, (GDestroyNotify) g_bytes_unref);
97 g_object_unref (task);
101 gst_rtmp_input_stream_read_all_bytes_finish (GInputStream * stream,
102 GAsyncResult * result, GError ** error)
104 g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
105 return g_task_propagate_pointer (G_TASK (result), error);
109 gst_rtmp_output_stream_write_all_bytes_async (GOutputStream * stream,
110 GBytes * bytes, int io_priority, GCancellable * cancellable,
111 GAsyncReadyCallback callback, gpointer user_data)
117 g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
118 g_return_if_fail (bytes);
120 data = g_bytes_get_data (bytes, &size);
121 g_return_if_fail (data);
123 task = g_task_new (stream, cancellable, callback, user_data);
124 g_task_set_task_data (task, g_bytes_ref (bytes),
125 (GDestroyNotify) g_bytes_unref);
127 g_output_stream_write_all_async (stream, data, size, io_priority,
128 cancellable, write_all_bytes_done, task);
132 write_all_bytes_done (GObject * source, GAsyncResult * result,
135 GOutputStream *os = G_OUTPUT_STREAM (source);
136 GTask *task = user_data;
137 GError *error = NULL;
140 res = g_output_stream_write_all_finish (os, result, NULL, &error);
142 g_task_return_error (task, error);
143 g_object_unref (task);
147 g_task_return_boolean (task, TRUE);
148 g_object_unref (task);
152 gst_rtmp_output_stream_write_all_bytes_finish (GOutputStream * stream,
153 GAsyncResult * result, GError ** error)
155 g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
156 return g_task_propagate_boolean (G_TASK (result), error);
165 } WriteAllBufferData;
167 static WriteAllBufferData *
168 write_all_buffer_data_new (GstBuffer * buffer)
170 WriteAllBufferData *data = g_slice_new0 (WriteAllBufferData);
171 data->buffer = gst_buffer_ref (buffer);
176 write_all_buffer_data_free (gpointer ptr)
178 WriteAllBufferData *data = ptr;
180 gst_buffer_unmap (data->buffer, &data->map);
182 g_clear_pointer (&data->buffer, gst_buffer_unref);
183 g_slice_free (WriteAllBufferData, data);
187 gst_rtmp_output_stream_write_all_buffer_async (GOutputStream * stream,
188 GstBuffer * buffer, int io_priority, GCancellable * cancellable,
189 GAsyncReadyCallback callback, gpointer user_data)
192 WriteAllBufferData *data;
194 g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
195 g_return_if_fail (GST_IS_BUFFER (buffer));
197 task = g_task_new (stream, cancellable, callback, user_data);
199 data = write_all_buffer_data_new (buffer);
200 g_task_set_task_data (task, data, write_all_buffer_data_free);
202 if (!gst_buffer_map (buffer, &data->map, GST_MAP_READ)) {
203 g_task_return_new_error (task, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ,
204 "Failed to map buffer for reading");
205 g_object_unref (task);
211 g_output_stream_write_all_async (stream, data->map.data, data->map.size,
212 io_priority, cancellable, write_all_buffer_done, task);
216 write_all_buffer_done (GObject * source, GAsyncResult * result,
219 GOutputStream *os = G_OUTPUT_STREAM (source);
220 GTask *task = user_data;
221 WriteAllBufferData *data = g_task_get_task_data (task);
222 GError *error = NULL;
225 res = g_output_stream_write_all_finish (os, result, &data->bytes_written,
228 gst_buffer_unmap (data->buffer, &data->map);
229 data->mapped = FALSE;
232 g_task_return_error (task, error);
233 g_object_unref (task);
237 g_task_return_boolean (task, TRUE);
238 g_object_unref (task);
243 gst_rtmp_output_stream_write_all_buffer_finish (GOutputStream * stream,
244 GAsyncResult * result, gsize * bytes_written, GError ** error)
246 WriteAllBufferData *data;
249 g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
250 task = G_TASK (result);
252 data = g_task_get_task_data (task);
254 *bytes_written = data->bytes_written;
257 return g_task_propagate_boolean (task, error);
260 static const gchar ascii_table[128] = {
261 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
262 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
263 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
264 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
265 ' ', '!', 0x0, '#', '$', '%', '&', '\'',
266 '(', ')', '*', '+', ',', '-', '.', '/',
267 '0', '1', '2', '3', '4', '5', '6', '7',
268 '8', '9', ':', ';', '<', '=', '>', '?',
269 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
270 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
271 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
272 'X', 'Y', 'Z', '[', 0x0, ']', '^', '_',
273 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
274 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
275 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
276 'x', 'y', 'z', '{', '|', '}', '~', 0x0,
279 static const gchar ascii_escapes[128] = {
280 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 'a',
281 'b', 't', 'n', 'v', 'f', 'r', 0x0, 0x0,
282 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
283 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
284 0x0, 0x0, '"', 0x0, 0x0, 0x0, 0x0, 0x0,
285 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
286 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
287 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
288 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
289 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
290 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
291 0x0, 0x0, 0x0, 0x0, '\\', 0x0, 0x0, 0x0,
292 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
293 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
294 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
295 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
299 gst_rtmp_string_print_escaped (GString * string, const gchar * data,
304 g_return_if_fail (string);
307 g_string_append (string, "(NULL)");
311 g_string_append_c (string, '"');
313 for (i = 0; size < 0 ? data[i] != 0 : i < size; i++) {
316 if (G_LIKELY (c < G_N_ELEMENTS (ascii_table))) {
317 if (ascii_table[c]) {
318 g_string_append_c (string, c);
322 if (ascii_escapes[c]) {
323 g_string_append_c (string, '\\');
324 g_string_append_c (string, ascii_escapes[c]);
328 gunichar uc = g_utf8_get_char_validated (data + i,
329 size < 0 ? -1 : size - i);
330 if (uc != (gunichar) (-2) && uc != (gunichar) (-1)) {
331 if (g_unichar_isprint (uc)) {
332 g_string_append_unichar (string, uc);
333 } else if (uc <= G_MAXUINT16) {
334 g_string_append_printf (string, "\\u%04X", uc);
336 g_string_append_printf (string, "\\U%08X", uc);
339 i += g_utf8_skip[c] - 1;
344 g_string_append_printf (string, "\\x%02X", c);
347 g_string_append_c (string, '"');