1 /* GStreamer
2  * Copyright (C) 2015 Sebastian Dröge <sebastian@centricular.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include "gstrtputils.h"
21 
22 typedef struct
23 {
24   GstElement *element;
25   GstBuffer *outbuf;
26   GQuark copy_tag;
27 } CopyMetaData;
28 
29 GQuark rtp_quark_meta_tag_video;
30 GQuark rtp_quark_meta_tag_audio;
31 
32 static gboolean
foreach_metadata_copy(GstBuffer * inbuf,GstMeta ** meta,gpointer user_data)33 foreach_metadata_copy (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data)
34 {
35   CopyMetaData *data = user_data;
36   GstElement *element = data->element;
37   GstBuffer *outbuf = data->outbuf;
38   GQuark copy_tag = data->copy_tag;
39   const GstMetaInfo *info = (*meta)->info;
40   const gchar *const *tags = gst_meta_api_type_get_tags (info->api);
41 
42   if (!tags || (copy_tag != 0 && g_strv_length ((gchar **) tags) == 1
43           && gst_meta_api_type_has_tag (info->api, copy_tag))) {
44     GstMetaTransformCopy copy_data = { FALSE, 0, -1 };
45     GST_DEBUG_OBJECT (element, "copy metadata %s", g_type_name (info->api));
46     /* simply copy then */
47     info->transform_func (outbuf, *meta, inbuf,
48         _gst_meta_transform_copy, &copy_data);
49   } else {
50     GST_DEBUG_OBJECT (element, "not copying metadata %s",
51         g_type_name (info->api));
52   }
53 
54   return TRUE;
55 }
56 
57 /* TODO: Should probably make copy_tag an array at some point */
58 void
gst_rtp_copy_meta(GstElement * element,GstBuffer * outbuf,GstBuffer * inbuf,GQuark copy_tag)59 gst_rtp_copy_meta (GstElement * element, GstBuffer * outbuf, GstBuffer * inbuf,
60     GQuark copy_tag)
61 {
62   CopyMetaData data = { element, outbuf, copy_tag };
63 
64   gst_buffer_foreach_meta (inbuf, foreach_metadata_copy, &data);
65 }
66 
67 void
gst_rtp_copy_video_meta(gpointer element,GstBuffer * outbuf,GstBuffer * inbuf)68 gst_rtp_copy_video_meta (gpointer element, GstBuffer * outbuf,
69     GstBuffer * inbuf)
70 {
71   gst_rtp_copy_meta (element, outbuf, inbuf, rtp_quark_meta_tag_video);
72 }
73 
74 void
gst_rtp_copy_audio_meta(gpointer element,GstBuffer * outbuf,GstBuffer * inbuf)75 gst_rtp_copy_audio_meta (gpointer element, GstBuffer * outbuf,
76     GstBuffer * inbuf)
77 {
78   gst_rtp_copy_meta (element, outbuf, inbuf, rtp_quark_meta_tag_audio);
79 }
80 
81 typedef struct
82 {
83   GstElement *element;
84   GQuark keep_tag;
85 } DropMetaData;
86 
87 static gboolean
foreach_metadata_drop(GstBuffer * inbuf,GstMeta ** meta,gpointer user_data)88 foreach_metadata_drop (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data)
89 {
90   DropMetaData *data = user_data;
91   GstElement *element = data->element;
92   GQuark keep_tag = data->keep_tag;
93   const GstMetaInfo *info = (*meta)->info;
94   const gchar *const *tags = gst_meta_api_type_get_tags (info->api);
95 
96   if (!tags || (keep_tag != 0 && g_strv_length ((gchar **) tags) == 1
97           && gst_meta_api_type_has_tag (info->api, keep_tag))) {
98     GST_DEBUG_OBJECT (element, "keeping metadata %s", g_type_name (info->api));
99   } else {
100     GST_DEBUG_OBJECT (element, "dropping metadata %s", g_type_name (info->api));
101     *meta = NULL;
102   }
103 
104   return TRUE;
105 }
106 
107 /* TODO: Should probably make keep_tag an array at some point */
108 void
gst_rtp_drop_meta(GstElement * element,GstBuffer * buf,GQuark keep_tag)109 gst_rtp_drop_meta (GstElement * element, GstBuffer * buf, GQuark keep_tag)
110 {
111   DropMetaData data = { element, keep_tag };
112 
113   gst_buffer_foreach_meta (buf, foreach_metadata_drop, &data);
114 }
115 
116 void
gst_rtp_drop_non_audio_meta(gpointer element,GstBuffer * buf)117 gst_rtp_drop_non_audio_meta (gpointer element, GstBuffer * buf)
118 {
119   gst_rtp_drop_meta (element, buf, rtp_quark_meta_tag_audio);
120 }
121 
122 void
gst_rtp_drop_non_video_meta(gpointer element,GstBuffer * buf)123 gst_rtp_drop_non_video_meta (gpointer element, GstBuffer * buf)
124 {
125   gst_rtp_drop_meta (element, buf, rtp_quark_meta_tag_video);
126 }
127 
128 /* Stolen from bad/gst/mpegtsdemux/payloader_parsers.c */
129 /* variable length Exp-Golomb parsing according to H.265 spec section 9.2*/
130 gboolean
gst_rtp_read_golomb(GstBitReader * br,guint32 * value)131 gst_rtp_read_golomb (GstBitReader * br, guint32 * value)
132 {
133   guint8 b, leading_zeros = -1;
134   *value = 1;
135 
136   for (b = 0; !b; leading_zeros++) {
137     if (!gst_bit_reader_get_bits_uint8 (br, &b, 1))
138       return FALSE;
139     *value *= 2;
140   }
141 
142   *value = (*value >> 1) - 1;
143   if (leading_zeros > 0) {
144     guint32 tmp = 0;
145     if (!gst_bit_reader_get_bits_uint32 (br, &tmp, leading_zeros))
146       return FALSE;
147     *value += tmp;
148   }
149 
150   return TRUE;
151 }
152