matroska: use math-compat.h for NAN define
[platform/upstream/gst-plugins-good.git] / gst / matroska / matroska-ids.c
1 /* GStreamer Matroska muxer/demuxer
2  * (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  * (C) 2006 Tim-Philipp Müller <tim centricular net>
4  *
5  * matroska-ids.c: matroska track context utility functions
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "matroska-ids.h"
28
29 #include <string.h>
30
31 gboolean
32 gst_matroska_track_init_video_context (GstMatroskaTrackContext ** p_context)
33 {
34   GstMatroskaTrackVideoContext *video_context;
35
36   g_assert (p_context != NULL && *p_context != NULL);
37
38   /* already set up? (track info might come before track type) */
39   if ((*p_context)->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
40     GST_LOG ("video context already set up");
41     return TRUE;
42   }
43
44   /* it better not have been set up as some other track type ... */
45   if ((*p_context)->type != 0) {
46     g_return_val_if_reached (FALSE);
47   }
48
49   video_context = g_renew (GstMatroskaTrackVideoContext, *p_context, 1);
50   *p_context = (GstMatroskaTrackContext *) video_context;
51
52   /* defaults */
53   (*p_context)->type = GST_MATROSKA_TRACK_TYPE_VIDEO;
54   video_context->display_width = 0;
55   video_context->display_height = 0;
56   video_context->pixel_width = 0;
57   video_context->pixel_height = 0;
58   video_context->asr_mode = 0;
59   video_context->fourcc = 0;
60   video_context->default_fps = 0.0;
61   video_context->earliest_time = GST_CLOCK_TIME_NONE;
62   video_context->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
63   video_context->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
64
65   return TRUE;
66 }
67
68 gboolean
69 gst_matroska_track_init_audio_context (GstMatroskaTrackContext ** p_context)
70 {
71   GstMatroskaTrackAudioContext *audio_context;
72
73   g_assert (p_context != NULL && *p_context != NULL);
74
75   /* already set up? (track info might come before track type) */
76   if ((*p_context)->type == GST_MATROSKA_TRACK_TYPE_AUDIO)
77     return TRUE;
78
79   /* it better not have been set up as some other track type ... */
80   if ((*p_context)->type != 0) {
81     g_return_val_if_reached (FALSE);
82   }
83
84   audio_context = g_renew (GstMatroskaTrackAudioContext, *p_context, 1);
85   *p_context = (GstMatroskaTrackContext *) audio_context;
86
87   /* defaults */
88   (*p_context)->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
89   audio_context->channels = 1;
90   audio_context->samplerate = 8000;
91   return TRUE;
92 }
93
94 gboolean
95 gst_matroska_track_init_subtitle_context (GstMatroskaTrackContext ** p_context)
96 {
97   GstMatroskaTrackSubtitleContext *subtitle_context;
98
99   g_assert (p_context != NULL && *p_context != NULL);
100
101   /* already set up? (track info might come before track type) */
102   if ((*p_context)->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE)
103     return TRUE;
104
105   /* it better not have been set up as some other track type ... */
106   if ((*p_context)->type != 0) {
107     g_return_val_if_reached (FALSE);
108   }
109
110   subtitle_context = g_renew (GstMatroskaTrackSubtitleContext, *p_context, 1);
111   *p_context = (GstMatroskaTrackContext *) subtitle_context;
112
113   (*p_context)->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
114   subtitle_context->invalid_utf8 = FALSE;
115   subtitle_context->seen_markup_tag = FALSE;
116   return TRUE;
117 }
118
119 void
120 gst_matroska_register_tags (void)
121 {
122   /* TODO: register other custom tags */
123 }
124
125 GstBufferList *
126 gst_matroska_parse_xiph_stream_headers (gpointer codec_data,
127     gsize codec_data_size)
128 {
129   GstBufferList *list = NULL;
130   guint8 *p = codec_data;
131   gint i, offset, num_packets;
132   guint *length, last;
133
134   GST_MEMDUMP ("xiph codec data", codec_data, codec_data_size);
135
136   if (codec_data == NULL || codec_data_size == 0)
137     goto error;
138
139   /* start of the stream and vorbis audio or theora video, need to
140    * send the codec_priv data as first three packets */
141   num_packets = p[0] + 1;
142   GST_DEBUG ("%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
143       (guint) num_packets, codec_data_size);
144
145   length = g_alloca (num_packets * sizeof (guint));
146   last = 0;
147   offset = 1;
148
149   /* first packets, read length values */
150   for (i = 0; i < num_packets - 1; i++) {
151     length[i] = 0;
152     while (offset < codec_data_size) {
153       length[i] += p[offset];
154       if (p[offset++] != 0xff)
155         break;
156     }
157     last += length[i];
158   }
159   if (offset + last > codec_data_size)
160     goto error;
161
162   /* last packet is the remaining size */
163   length[i] = codec_data_size - offset - last;
164
165   list = gst_buffer_list_new ();
166
167   for (i = 0; i < num_packets; i++) {
168     GstBuffer *hdr;
169
170     GST_DEBUG ("buffer %d: %u bytes", i, (guint) length[i]);
171
172     if (offset + length[i] > codec_data_size)
173       goto error;
174
175     hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
176     gst_buffer_list_add (list, hdr);
177
178     offset += length[i];
179   }
180
181   return list;
182
183 /* ERRORS */
184 error:
185   {
186     if (list != NULL)
187       gst_buffer_list_unref (list);
188     return NULL;
189   }
190 }
191
192 GstBufferList *
193 gst_matroska_parse_speex_stream_headers (gpointer codec_data,
194     gsize codec_data_size)
195 {
196   GstBufferList *list = NULL;
197   GstBuffer *hdr;
198   guint8 *pdata = codec_data;
199
200   GST_MEMDUMP ("speex codec data", codec_data, codec_data_size);
201
202   if (codec_data == NULL || codec_data_size < 80) {
203     GST_WARNING ("not enough codec priv data for speex headers");
204     return NULL;
205   }
206
207   if (memcmp (pdata, "Speex   ", 8) != 0) {
208     GST_WARNING ("no Speex marker at start of stream headers");
209     return NULL;
210   }
211
212   list = gst_buffer_list_new ();
213
214   hdr = gst_buffer_new_wrapped (g_memdup (pdata, 80), 80);
215   gst_buffer_list_add (list, hdr);
216
217   if (codec_data_size > 80) {
218     hdr = gst_buffer_new_wrapped (g_memdup (pdata + 80, codec_data_size - 80),
219         codec_data_size - 80);
220     gst_buffer_list_add (list, hdr);
221   }
222
223   return list;
224 }
225
226 GstBufferList *
227 gst_matroska_parse_opus_stream_headers (gpointer codec_data,
228     gsize codec_data_size)
229 {
230   GstBufferList *list = NULL;
231   GstBuffer *hdr;
232   guint8 *pdata = codec_data;
233
234   GST_MEMDUMP ("opus codec data", codec_data, codec_data_size);
235
236   if (codec_data == NULL || codec_data_size < 19) {
237     GST_WARNING ("not enough codec priv data for opus headers");
238     return NULL;
239   }
240
241   if (memcmp (pdata, "OpusHead", 8) != 0) {
242     GST_WARNING ("no OpusHead marker at start of stream headers");
243     return NULL;
244   }
245
246   list = gst_buffer_list_new ();
247
248   hdr =
249       gst_buffer_new_wrapped (g_memdup (pdata, codec_data_size),
250       codec_data_size);
251   gst_buffer_list_add (list, hdr);
252
253   return list;
254 }
255
256 GstBufferList *
257 gst_matroska_parse_flac_stream_headers (gpointer codec_data,
258     gsize codec_data_size)
259 {
260   GstBufferList *list = NULL;
261   GstBuffer *hdr;
262   guint8 *pdata = codec_data;
263   guint len, off;
264
265   GST_MEMDUMP ("flac codec data", codec_data, codec_data_size);
266
267   /* need at least 'fLaC' marker + STREAMINFO metadata block */
268   if (codec_data == NULL || codec_data_size < ((4) + (4 + 34))) {
269     GST_WARNING ("not enough codec priv data for flac headers");
270     return NULL;
271   }
272
273   if (memcmp (pdata, "fLaC", 4) != 0) {
274     GST_WARNING ("no flac marker at start of stream headers");
275     return NULL;
276   }
277
278   list = gst_buffer_list_new ();
279
280   hdr = gst_buffer_new_wrapped (g_memdup (pdata, 4), 4);
281   gst_buffer_list_add (list, hdr);
282
283   /* skip fLaC marker */
284   off = 4;
285
286   /* FIXME: check size remaining */
287   while (off < codec_data_size) {
288     len = GST_READ_UINT8 (pdata + off + 1) << 16;
289     len |= GST_READ_UINT8 (pdata + off + 2) << 8;
290     len |= GST_READ_UINT8 (pdata + off + 3);
291
292     GST_DEBUG ("header packet: len=%u bytes, flags=0x%02x", len, pdata[off]);
293
294     /* FIXME: check size remaining */
295     hdr = gst_buffer_new_wrapped (g_memdup (pdata + off, len + 4), len + 4);
296     gst_buffer_list_add (list, hdr);
297
298     off += 4 + len;
299   }
300   return list;
301 }
302
303 GstClockTime
304 gst_matroska_track_get_buffer_timestamp (GstMatroskaTrackContext * track,
305     GstBuffer * buf)
306 {
307   if (track->dts_only) {
308     return GST_BUFFER_DTS_OR_PTS (buf);
309   } else {
310     return GST_BUFFER_PTS (buf);
311   }
312 }
313
314 void
315 gst_matroska_track_free (GstMatroskaTrackContext * track)
316 {
317   g_free (track->codec_id);
318   g_free (track->codec_name);
319   g_free (track->name);
320   g_free (track->language);
321   g_free (track->codec_priv);
322   g_free (track->codec_state);
323
324   if (track->encodings != NULL) {
325     int i;
326
327     for (i = 0; i < track->encodings->len; ++i) {
328       GstMatroskaTrackEncoding *enc = &g_array_index (track->encodings,
329           GstMatroskaTrackEncoding,
330           i);
331
332       g_free (enc->comp_settings);
333     }
334     g_array_free (track->encodings, TRUE);
335   }
336
337   if (track->tags)
338     gst_tag_list_unref (track->tags);
339
340   if (track->index_table)
341     g_array_free (track->index_table, TRUE);
342
343   if (track->stream_headers)
344     gst_buffer_list_unref (track->stream_headers);
345
346   g_free (track);
347 }