1 /* GStreamer RTMP Library
2 * Copyright (C) 2014 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 St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
27 #include "rtmputils.h"
31 #define MAX_RECURSION_DEPTH 16
33 GST_DEBUG_CATEGORY_STATIC (gst_rtmp_amf_debug_category);
34 #define GST_CAT_DEFAULT gst_rtmp_amf_debug_category
36 static GBytes *empty_bytes;
41 static gsize done = 0;
42 if (g_once_init_enter (&done)) {
43 empty_bytes = g_bytes_new_static ("", 0);
44 GST_DEBUG_CATEGORY_INIT (gst_rtmp_amf_debug_category, "rtmpamf", 0,
45 "debug category for the amf parser");
46 g_once_init_leave (&done, 1);
51 gst_amf_type_get_nick (GstAmfType type)
54 case GST_AMF_TYPE_INVALID:
56 case GST_AMF_TYPE_NUMBER:
58 case GST_AMF_TYPE_BOOLEAN:
60 case GST_AMF_TYPE_STRING:
62 case GST_AMF_TYPE_OBJECT:
64 case GST_AMF_TYPE_MOVIECLIP:
66 case GST_AMF_TYPE_NULL:
68 case GST_AMF_TYPE_UNDEFINED:
70 case GST_AMF_TYPE_REFERENCE:
72 case GST_AMF_TYPE_ECMA_ARRAY:
74 case GST_AMF_TYPE_OBJECT_END:
76 case GST_AMF_TYPE_STRICT_ARRAY:
77 return "strict-array";
78 case GST_AMF_TYPE_DATE:
80 case GST_AMF_TYPE_LONG_STRING:
82 case GST_AMF_TYPE_UNSUPPORTED:
84 case GST_AMF_TYPE_RECORDSET:
86 case GST_AMF_TYPE_XML_DOCUMENT:
87 return "xml-document";
88 case GST_AMF_TYPE_TYPED_OBJECT:
89 return "typed-object";
90 case GST_AMF_TYPE_AVMPLUS_OBJECT:
91 return "avmplus-object";
104 amf_object_field_clear (gpointer ptr)
106 AmfObjectField *field = ptr;
107 g_clear_pointer (&field->name, g_free);
108 g_clear_pointer (&field->value, gst_amf_node_free);
120 GPtrArray *v_elements;
124 static inline const AmfObjectField *
125 get_field (const GstAmfNode * node, guint index)
127 return &g_array_index (node->value.v_fields, const AmfObjectField, index);
131 append_field (GstAmfNode * node, gchar * name, GstAmfNode * value)
133 AmfObjectField field = {
137 g_array_append_val (node->value.v_fields, field);
140 static inline const GstAmfNode *
141 get_element (const GstAmfNode * node, guint index)
143 return g_ptr_array_index (node->value.v_elements, index);
147 append_element (GstAmfNode * node, GstAmfNode * value)
149 g_ptr_array_add (node->value.v_elements, value);
153 node_new (GstAmfType type)
159 node = g_slice_alloc0 (sizeof *node);
163 case GST_AMF_TYPE_STRING:
164 case GST_AMF_TYPE_LONG_STRING:
165 node->value.v_bytes = g_bytes_ref (empty_bytes);
168 case GST_AMF_TYPE_OBJECT:
169 case GST_AMF_TYPE_ECMA_ARRAY:
170 node->value.v_fields =
171 g_array_new (FALSE, FALSE, sizeof (AmfObjectField));
172 g_array_set_clear_func (node->value.v_fields, amf_object_field_clear);
175 case GST_AMF_TYPE_STRICT_ARRAY:
176 node->value.v_elements =
177 g_ptr_array_new_with_free_func (gst_amf_node_free);
188 gst_amf_node_new_null (void)
190 return node_new (GST_AMF_TYPE_NULL);
194 gst_amf_node_new_boolean (gboolean value)
196 GstAmfNode *node = node_new (GST_AMF_TYPE_BOOLEAN);
197 node->value.v_int = ! !value;
202 gst_amf_node_new_number (gdouble value)
204 GstAmfNode *node = node_new (GST_AMF_TYPE_NUMBER);
205 node->value.v_double = value;
210 gst_amf_node_new_string (const gchar * value, gssize size)
212 GstAmfNode *node = node_new (GST_AMF_TYPE_STRING);
213 gst_amf_node_set_string (node, value, size);
218 gst_amf_node_new_take_string (gchar * value, gssize size)
220 GstAmfNode *node = node_new (GST_AMF_TYPE_STRING);
221 gst_amf_node_take_string (node, value, size);
226 gst_amf_node_new_object (void)
228 return node_new (GST_AMF_TYPE_OBJECT);
232 gst_amf_node_copy (const GstAmfNode * node)
236 g_return_val_if_fail (node, NULL);
238 copy = node_new (node->type);
240 switch (node->type) {
241 case GST_AMF_TYPE_STRING:
242 case GST_AMF_TYPE_LONG_STRING:
243 copy->value.v_bytes = g_bytes_ref (node->value.v_bytes);
246 case GST_AMF_TYPE_OBJECT:
247 case GST_AMF_TYPE_ECMA_ARRAY:{
248 guint i, len = gst_amf_node_get_num_fields (node);
249 for (i = 0; i < len; i++) {
250 const AmfObjectField *field = get_field (node, i);
251 append_field (copy, g_strdup (field->name),
252 gst_amf_node_copy (field->value));
257 case GST_AMF_TYPE_STRICT_ARRAY:{
258 guint i, len = gst_amf_node_get_num_elements (node);
259 for (i = 0; i < len; i++) {
260 const GstAmfNode *elem = get_element (node, i);
261 append_element (copy, gst_amf_node_copy (elem));
267 copy->value = node->value;
275 gst_amf_node_free (gpointer ptr)
277 GstAmfNode *node = ptr;
279 switch (node->type) {
280 case GST_AMF_TYPE_STRING:
281 case GST_AMF_TYPE_LONG_STRING:
282 g_bytes_unref (node->value.v_bytes);
285 case GST_AMF_TYPE_OBJECT:
286 case GST_AMF_TYPE_ECMA_ARRAY:
287 g_array_unref (node->value.v_fields);
290 case GST_AMF_TYPE_STRICT_ARRAY:
291 g_ptr_array_unref (node->value.v_elements);
298 g_slice_free (GstAmfNode, node);
302 gst_amf_node_get_type (const GstAmfNode * node)
304 g_return_val_if_fail (node, GST_AMF_TYPE_INVALID);
309 gst_amf_node_get_boolean (const GstAmfNode * node)
311 g_return_val_if_fail (gst_amf_node_get_type (node) == GST_AMF_TYPE_BOOLEAN,
313 return node->value.v_int;
317 gst_amf_node_get_number (const GstAmfNode * node)
319 g_return_val_if_fail (gst_amf_node_get_type (node) == GST_AMF_TYPE_NUMBER,
321 return node->value.v_double;
325 gst_amf_node_get_string (const GstAmfNode * node, gsize * out_size)
328 const gchar *data = gst_amf_node_peek_string (node, &size);
332 return g_memdup (data, size);
334 return g_strndup (data, size);
339 gst_amf_node_peek_string (const GstAmfNode * node, gsize * size)
341 GstAmfType type = gst_amf_node_get_type (node);
342 g_return_val_if_fail (type == GST_AMF_TYPE_STRING ||
343 type == GST_AMF_TYPE_LONG_STRING, FALSE);
344 return g_bytes_get_data (node->value.v_bytes, size);
348 gst_amf_node_get_field (const GstAmfNode * node, const gchar * name)
350 guint i, len = gst_amf_node_get_num_fields (node);
352 g_return_val_if_fail (name, NULL);
354 for (i = 0; i < len; i++) {
355 const AmfObjectField *field = get_field (node, i);
356 if (strcmp (field->name, name) == 0) {
365 gst_amf_node_get_field_by_index (const GstAmfNode * node, guint index)
367 guint len = gst_amf_node_get_num_fields (node);
368 g_return_val_if_fail (index < len, NULL);
369 return get_field (node, index)->value;
373 gst_amf_node_get_num_fields (const GstAmfNode * node)
375 GstAmfType type = gst_amf_node_get_type (node);
376 g_return_val_if_fail (type == GST_AMF_TYPE_OBJECT ||
377 type == GST_AMF_TYPE_ECMA_ARRAY, 0);
378 return node->value.v_fields->len;
382 gst_amf_node_get_element (const GstAmfNode * node, guint index)
384 guint len = gst_amf_node_get_num_elements (node);
385 g_return_val_if_fail (index < len, NULL);
386 return get_element (node, index);
390 gst_amf_node_get_num_elements (const GstAmfNode * node)
392 GstAmfType type = gst_amf_node_get_type (node);
393 g_return_val_if_fail (type == GST_AMF_TYPE_STRICT_ARRAY, 0);
394 return node->value.v_elements->len;
398 gst_amf_node_set_boolean (GstAmfNode * node, gboolean value)
400 g_return_if_fail (node->type == GST_AMF_TYPE_BOOLEAN);
401 node->value.v_int = ! !value;
405 gst_amf_node_set_number (GstAmfNode * node, gdouble value)
407 g_return_if_fail (node->type == GST_AMF_TYPE_NUMBER);
408 node->value.v_double = value;
412 gst_amf_node_take_string (GstAmfNode * node, gchar * value, gssize size)
414 g_return_if_fail (node->type == GST_AMF_TYPE_STRING ||
415 node->type == GST_AMF_TYPE_LONG_STRING);
417 g_return_if_fail (value);
420 size = strlen (value);
423 if (size > G_MAXUINT32) {
424 GST_WARNING ("Long string too long (%" G_GSSIZE_FORMAT "), truncating",
430 if (size > G_MAXUINT16) {
431 node->type = GST_AMF_TYPE_LONG_STRING;
434 g_bytes_unref (node->value.v_bytes);
435 node->value.v_bytes = g_bytes_new_take (value, size);
439 gst_amf_node_set_string (GstAmfNode * node, const gchar * value, gssize size)
443 g_return_if_fail (value);
446 size = strlen (value);
447 copy = g_memdup (value, size + 1);
449 copy = g_memdup (value, size);
452 gst_amf_node_take_string (node, copy, size);
456 gst_amf_node_append_field (GstAmfNode * node, const gchar * name,
457 const GstAmfNode * value)
459 gst_amf_node_append_take_field (node, name, gst_amf_node_copy (value));
463 gst_amf_node_append_take_field (GstAmfNode * node, const gchar * name,
466 g_return_if_fail (node->type == GST_AMF_TYPE_OBJECT ||
467 node->type == GST_AMF_TYPE_ECMA_ARRAY);
468 g_return_if_fail (name);
469 append_field (node, g_strdup (name), value);
473 gst_amf_node_append_field_number (GstAmfNode * node, const gchar * name,
476 gst_amf_node_append_take_field (node, name, gst_amf_node_new_number (value));
480 gst_amf_node_append_field_boolean (GstAmfNode * node, const gchar * name,
483 gst_amf_node_append_take_field (node, name, gst_amf_node_new_boolean (value));
487 gst_amf_node_append_field_string (GstAmfNode * node, const gchar * name,
488 const gchar * value, gssize size)
490 gst_amf_node_append_take_field (node, name,
491 gst_amf_node_new_string (value, size));
495 gst_amf_node_append_field_take_string (GstAmfNode * node, const gchar * name,
496 gchar * value, gssize size)
498 gst_amf_node_append_take_field (node, name,
499 gst_amf_node_new_take_string (value, size));
502 /* Dumper *******************************************************************/
505 dump_indent (GString * string, gint indent, guint depth)
508 g_string_append_c (string, ' ');
511 g_string_append_c (string, '\n');
512 for (i = 0; i < indent + depth * 2; i++) {
513 g_string_append_c (string, ' ');
519 dump_bytes (GString * string, GBytes * value)
522 const gchar *data = g_bytes_get_data (value, &size);
523 gst_rtmp_string_print_escaped (string, data, size);
527 dump_node (GString * string, const GstAmfNode * node, gint indent,
528 guint recursion_depth)
530 const gchar *object_delim = "{}";
532 switch (gst_amf_node_get_type (node)) {
533 case GST_AMF_TYPE_NUMBER:
534 g_string_append_printf (string, "%g", node->value.v_double);
537 case GST_AMF_TYPE_BOOLEAN:
538 g_string_append (string, node->value.v_int ? "True" : "False");
541 case GST_AMF_TYPE_LONG_STRING:
542 g_string_append_c (string, 'L');
544 case GST_AMF_TYPE_STRING:
545 dump_bytes (string, node->value.v_bytes);
548 case GST_AMF_TYPE_ECMA_ARRAY:
551 case GST_AMF_TYPE_OBJECT:{
552 guint i, len = gst_amf_node_get_num_fields (node);
553 g_string_append_c (string, object_delim[0]);
555 for (i = 0; i < len; i++) {
556 const AmfObjectField *field = get_field (node, i);
557 dump_indent (string, indent, recursion_depth + 1);
558 gst_rtmp_string_print_escaped (string, field->name, -1);
559 g_string_append_c (string, ':');
560 g_string_append_c (string, ' ');
561 dump_node (string, field->value, indent, recursion_depth + 1);
563 g_string_append_c (string, ',');
566 dump_indent (string, indent, recursion_depth);
568 g_string_append_c (string, object_delim[1]);
572 case GST_AMF_TYPE_STRICT_ARRAY:{
573 guint i, len = gst_amf_node_get_num_elements (node);
574 g_string_append_c (string, '(');
576 for (i = 0; i < len; i++) {
577 const GstAmfNode *value = get_element (node, i);
578 dump_indent (string, indent, recursion_depth + 1);
579 dump_node (string, value, indent, recursion_depth + 1);
581 g_string_append_c (string, ',');
584 dump_indent (string, indent, recursion_depth);
586 g_string_append_c (string, ')');
591 g_string_append (string, gst_amf_type_get_nick (node->type));
597 gst_amf_node_dump (const GstAmfNode * node, gint indent, GString * string)
599 dump_node (string, node, indent, 0);
603 dump_argument (const GstAmfNode * node, guint n)
605 if (G_UNLIKELY (GST_LEVEL_LOG <= _gst_debug_min) &&
606 GST_LEVEL_LOG <= gst_debug_category_get_threshold (GST_CAT_DEFAULT)) {
607 GString *string = g_string_new (NULL);
608 gst_amf_node_dump (node, -1, string);
609 GST_LOG ("Argument #%u: %s", n, string->str);
610 g_string_free (string, TRUE);
614 /* Parser *******************************************************************/
620 guint8 recursion_depth;
623 static GstAmfNode *parse_value (AmfParser * parser);
626 parse_u8 (AmfParser * parser)
629 value = parser->data[parser->offset];
630 parser->offset += sizeof value;
634 static inline guint16
635 parse_u16 (AmfParser * parser)
638 value = GST_READ_UINT16_BE (parser->data + parser->offset);
639 parser->offset += sizeof value;
643 static inline guint32
644 parse_u32 (AmfParser * parser)
647 value = GST_READ_UINT32_BE (parser->data + parser->offset);
648 parser->offset += sizeof value;
653 parse_number (AmfParser * parser)
657 if (sizeof value > parser->size - parser->offset) {
658 GST_ERROR ("number too long");
662 value = GST_READ_DOUBLE_BE (parser->data + parser->offset);
663 parser->offset += sizeof value;
668 parse_boolean (AmfParser * parser)
672 if (sizeof value > parser->size - parser->offset) {
673 GST_ERROR ("boolean too long");
677 value = parse_u8 (parser);
681 static inline GBytes *
682 read_string (AmfParser * parser, gsize size)
687 return g_bytes_ref (empty_bytes);
690 if (size > parser->size - parser->offset) {
691 GST_ERROR ("string too long (%" G_GSIZE_FORMAT ")", size);
695 /* Null-terminate all incoming strings for internal safety */
696 if (parser->data[parser->offset + size - 1] == 0) {
697 string = g_malloc (size);
699 string = g_malloc (size + 1);
703 memcpy (string, parser->data + parser->offset, size);
705 parser->offset += size;
706 return g_bytes_new_take (string, size);
710 parse_string (AmfParser * parser)
714 if (sizeof size > parser->size - parser->offset) {
715 GST_ERROR ("string size too long");
719 size = parse_u16 (parser);
720 return read_string (parser, size);
724 parse_long_string (AmfParser * parser)
728 if (sizeof size > parser->size - parser->offset) {
729 GST_ERROR ("long string size too long");
733 size = parse_u32 (parser);
734 return read_string (parser, size);
738 parse_object (AmfParser * parser, GstAmfNode * node)
740 guint32 n_fields = 0;
747 name = parse_string (parser);
749 GST_ERROR ("object too long");
753 value = parse_value (parser);
755 GST_ERROR ("object too long");
756 g_bytes_unref (name);
760 if (gst_amf_node_get_type (value) == GST_AMF_TYPE_OBJECT_END) {
761 g_bytes_unref (name);
762 gst_amf_node_free (value);
766 if (g_bytes_get_size (name) == 0) {
767 GST_ERROR ("empty object field name");
768 g_bytes_unref (name);
769 gst_amf_node_free (value);
773 append_field (node, g_bytes_unref_to_data (name, &size), value);
781 parse_ecma_array (AmfParser * parser, GstAmfNode * node)
783 guint32 n_elements, n_read;
785 if (sizeof n_elements > parser->size - parser->offset) {
786 GST_ERROR ("array size too long");
790 n_elements = parse_u32 (parser);
792 /* FIXME This is weird. The one time I've seen this, the encoded value
793 * was 0, but the number of elements was 1. */
794 if (n_elements == 0) {
795 GST_DEBUG ("Interpreting ECMA array length 0 as 1");
799 n_read = parse_object (parser, node);
801 if (n_read != n_elements) {
802 GST_WARNING ("Expected array with %" G_GUINT32_FORMAT " elements,"
803 " but read %" G_GUINT32_FORMAT, n_elements, n_read);
808 parse_strict_array (AmfParser * parser, GstAmfNode * node)
810 GstAmfNode *value = NULL;
811 guint32 n_elements, i;
813 if (sizeof n_elements > parser->size - parser->offset) {
814 GST_ERROR ("array size too long");
818 n_elements = parse_u32 (parser);
820 for (i = 0; i < n_elements; i++) {
821 value = parse_value (parser);
823 GST_ERROR ("array too long");
827 append_element (node, value);
832 parse_value (AmfParser * parser)
834 GstAmfNode *node = NULL;
837 if (1 > parser->size - parser->offset) {
838 GST_ERROR ("value too long");
842 type = parse_u8 (parser);
843 node = node_new (type);
844 GST_TRACE ("parsing AMF type %d (%s)", type, gst_amf_type_get_nick (type));
846 parser->recursion_depth++;
847 if (parser->recursion_depth > MAX_RECURSION_DEPTH) {
848 GST_ERROR ("maximum recursion depth %d reached", parser->recursion_depth);
853 case GST_AMF_TYPE_NUMBER:
854 node->value.v_double = parse_number (parser);
856 case GST_AMF_TYPE_BOOLEAN:
857 node->value.v_int = parse_boolean (parser);
859 case GST_AMF_TYPE_STRING:
860 node->value.v_bytes = parse_string (parser);
862 case GST_AMF_TYPE_LONG_STRING:
863 node->value.v_bytes = parse_long_string (parser);
865 case GST_AMF_TYPE_OBJECT:
866 parse_object (parser, node);
868 case GST_AMF_TYPE_ECMA_ARRAY:
869 parse_ecma_array (parser, node);
871 case GST_AMF_TYPE_STRICT_ARRAY:
872 parse_strict_array (parser, node);
874 case GST_AMF_TYPE_NULL:
875 case GST_AMF_TYPE_UNDEFINED:
876 case GST_AMF_TYPE_OBJECT_END:
877 case GST_AMF_TYPE_UNSUPPORTED:
880 GST_ERROR ("unimplemented AMF type %d (%s)", type,
881 gst_amf_type_get_nick (type));
885 parser->recursion_depth--;
890 gst_amf_node_parse (const guint8 * data, gsize size, guint8 ** endptr)
898 g_return_val_if_fail (data, NULL);
899 g_return_val_if_fail (size, NULL);
903 GST_TRACE ("Starting parse with %" G_GSIZE_FORMAT " bytes", parser.size);
905 node = parse_value (&parser);
906 if (gst_amf_node_get_type (node) == GST_AMF_TYPE_INVALID) {
907 GST_ERROR ("invalid value");
911 if (G_UNLIKELY (GST_LEVEL_LOG <= _gst_debug_min) &&
912 GST_LEVEL_LOG <= gst_debug_category_get_threshold (GST_CAT_DEFAULT)) {
913 GString *string = g_string_new (NULL);
914 gst_amf_node_dump (node, -1, string);
915 GST_LOG ("Parsed value: %s", string->str);
916 g_string_free (string, TRUE);
919 GST_TRACE ("Done parsing; consumed %" G_GSIZE_FORMAT " bytes and left %"
920 G_GSIZE_FORMAT " bytes", parser.offset, parser.size - parser.offset);
924 *endptr = (guint8 *) parser.data + parser.offset;
931 gst_amf_parse_command (const guint8 * data, gsize size,
932 gdouble * transaction_id, gchar ** command_name)
938 GstAmfNode *node1 = NULL, *node2 = NULL;
939 GPtrArray *args = NULL;
941 g_return_val_if_fail (data, NULL);
942 g_return_val_if_fail (size, NULL);
946 GST_TRACE ("Starting parse with %" G_GSIZE_FORMAT " bytes", parser.size);
948 node1 = parse_value (&parser);
949 if (gst_amf_node_get_type (node1) != GST_AMF_TYPE_STRING) {
950 GST_ERROR ("no command name");
954 node2 = parse_value (&parser);
955 if (gst_amf_node_get_type (node2) != GST_AMF_TYPE_NUMBER) {
956 GST_ERROR ("no transaction ID");
960 GST_LOG ("Parsing command '%s', transid %.0f",
961 gst_amf_node_peek_string (node1, NULL), gst_amf_node_get_number (node2));
963 args = g_ptr_array_new_with_free_func (gst_amf_node_free);
965 while (parser.offset < parser.size) {
966 GstAmfNode *node = parse_value (&parser);
971 dump_argument (node, args->len);
972 g_ptr_array_add (args, node);
975 GST_TRACE ("Done parsing; consumed %" G_GSIZE_FORMAT " bytes and left %"
976 G_GSIZE_FORMAT " bytes", parser.offset, parser.size - parser.offset);
978 if (args->len == 0) {
979 GST_ERROR ("no command arguments");
980 g_clear_pointer (&args, g_ptr_array_unref);
985 *command_name = gst_amf_node_get_string (node1, NULL);
988 if (transaction_id) {
989 *transaction_id = gst_amf_node_get_number (node2);
993 g_clear_pointer (&node1, gst_amf_node_free);
994 g_clear_pointer (&node2, gst_amf_node_free);
998 /* Serializer ***************************************************************/
1000 static void serialize_value (GByteArray * array, const GstAmfNode * node);
1003 serialize_u8 (GByteArray * array, guint8 value)
1005 g_byte_array_append (array, (guint8 *) & value, sizeof value);
1009 serialize_u16 (GByteArray * array, guint16 value)
1011 value = GUINT16_TO_BE (value);
1012 g_byte_array_append (array, (guint8 *) & value, sizeof value);
1016 serialize_u32 (GByteArray * array, guint32 value)
1018 value = GUINT32_TO_BE (value);
1019 g_byte_array_append (array, (guint8 *) & value, sizeof value);
1023 serialize_number (GByteArray * array, gdouble value)
1025 value = GDOUBLE_TO_BE (value);
1026 g_byte_array_append (array, (guint8 *) & value, sizeof value);
1030 serialize_boolean (GByteArray * array, gboolean value)
1032 serialize_u8 (array, value);
1036 serialize_string (GByteArray * array, const gchar * string, gssize size)
1039 size = strlen (string);
1042 if (size > G_MAXUINT16) {
1043 GST_WARNING ("String too long: %" G_GSSIZE_FORMAT, size);
1047 serialize_u16 (array, size);
1048 g_byte_array_append (array, (guint8 *) string, size);
1052 serialize_long_string (GByteArray * array, const gchar * string, gssize size)
1055 size = strlen (string);
1058 if (size > G_MAXUINT32) {
1059 GST_WARNING ("Long string too long: %" G_GSSIZE_FORMAT, size);
1063 serialize_u32 (array, size);
1064 g_byte_array_append (array, (guint8 *) string, size);
1068 serialize_bytes (GByteArray * array, GBytes * bytes, gboolean long_string)
1071 const gchar *data = g_bytes_get_data (bytes, &size);
1074 serialize_long_string (array, data, size);
1076 serialize_string (array, data, size);
1081 serialize_object (GByteArray * array, const GstAmfNode * node)
1085 for (i = 0; i < gst_amf_node_get_num_fields (node); i++) {
1086 const AmfObjectField *field = get_field (node, i);
1087 serialize_string (array, field->name, -1);
1088 serialize_value (array, field->value);
1090 serialize_u16 (array, 0);
1091 serialize_u8 (array, GST_AMF_TYPE_OBJECT_END);
1095 serialize_ecma_array (GByteArray * array, const GstAmfNode * node)
1097 /* FIXME: Shouldn't this be the field count? */
1098 serialize_u32 (array, 0);
1099 serialize_object (array, node);
1103 serialize_value (GByteArray * array, const GstAmfNode * node)
1105 serialize_u8 (array, node->type);
1106 switch (node->type) {
1107 case GST_AMF_TYPE_NUMBER:
1108 serialize_number (array, node->value.v_double);
1110 case GST_AMF_TYPE_BOOLEAN:
1111 serialize_boolean (array, node->value.v_int);
1113 case GST_AMF_TYPE_STRING:
1114 serialize_bytes (array, node->value.v_bytes, FALSE);
1116 case GST_AMF_TYPE_LONG_STRING:
1117 serialize_bytes (array, node->value.v_bytes, TRUE);
1119 case GST_AMF_TYPE_OBJECT:
1120 serialize_object (array, node);
1122 case GST_AMF_TYPE_ECMA_ARRAY:
1123 serialize_ecma_array (array, node);
1125 case GST_AMF_TYPE_NULL:
1126 case GST_AMF_TYPE_UNDEFINED:
1127 case GST_AMF_TYPE_OBJECT_END:
1128 case GST_AMF_TYPE_UNSUPPORTED:
1131 GST_ERROR ("unimplemented AMF type %d (%s)", node->type,
1132 gst_amf_type_get_nick (node->type));
1138 gst_amf_node_serialize (const GstAmfNode * node)
1140 GByteArray *array = g_byte_array_new ();
1142 g_return_val_if_fail (node, NULL);
1146 if (G_UNLIKELY (GST_LEVEL_LOG <= _gst_debug_min) &&
1147 GST_LEVEL_LOG <= gst_debug_category_get_threshold (GST_CAT_DEFAULT)) {
1148 GString *string = g_string_new (NULL);
1149 gst_amf_node_dump (node, -1, string);
1150 GST_LOG ("Serializing value: %s", string->str);
1151 g_string_free (string, TRUE);
1154 serialize_value (array, node);
1156 GST_TRACE ("Done serializing; produced %u bytes", array->len);
1158 return g_byte_array_free_to_bytes (array);
1162 gst_amf_serialize_command (gdouble transaction_id, const gchar * command_name,
1163 const GstAmfNode * argument, ...)
1168 va_start (ap, argument);
1169 ret = gst_amf_serialize_command_valist (transaction_id, command_name,
1177 gst_amf_serialize_command_valist (gdouble transaction_id,
1178 const gchar * command_name, const GstAmfNode * argument, va_list var_args)
1180 GByteArray *array = g_byte_array_new ();
1183 g_return_val_if_fail (command_name, NULL);
1184 g_return_val_if_fail (argument, NULL);
1188 GST_LOG ("Serializing command '%s', transid %.0f", command_name,
1191 serialize_u8 (array, GST_AMF_TYPE_STRING);
1192 serialize_string (array, command_name, -1);
1193 serialize_u8 (array, GST_AMF_TYPE_NUMBER);
1194 serialize_number (array, transaction_id);
1197 serialize_value (array, argument);
1198 dump_argument (argument, i++);
1200 argument = va_arg (var_args, const GstAmfNode *);
1203 GST_TRACE ("Done serializing; consumed %u args and produced %u bytes", i,
1206 return g_byte_array_free_to_bytes (array);