~ubuntu-branches/ubuntu/saucy/gnash/saucy-proposed

« back to all changes in this revision

Viewing changes to libmedia/gst/gstflvparse.c

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2008-10-13 14:29:49 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20081013142949-f6qdvnu4mn05ltdc
Tags: 0.8.4~~bzr9980-0ubuntu1
* new upstream release 0.8.4 (LP: #240325)
* ship new lib usr/lib/gnash/libmozsdk.so.* in mozilla-plugin-gnash
  - update debian/mozilla-plugin-gnash.install
* ship new lib usr/lib/gnash/libgnashnet.so.* in gnash-common
  - update debian/gnash-common.install
* add basic debian/build_head script to build latest CVS head packages.
  - add debian/build_head
* new sound architecture requires build depend on libsdl1.2-dev
  - update debian/control
* head build script now has been completely migrated to bzr (upstream +
  ubuntu)
  - update debian/build_head
* disable kde gui until klash/qt4 has been fixed; keep kde packages as empty
  packages for now.
  - update debian/rules
  - debian/klash.install
  - debian/klash.links
  - debian/klash.manpages
  - debian/konqueror-plugin-gnash.install
* drop libkonq5-dev build dependency accordingly
  - update debian/control
* don't install headers manually anymore. gnash doesnt provide a -dev
  package after all
  - update debian/rules
* update libs installed in gnash-common; libgnashserver-*.so is not available
  anymore (removed); in turn we add the new libgnashcore-*.so
  - update debian/gnash-common.install
* use -Os for optimization and properly pass CXXFLAGS=$(CFLAGS) to configure
  - update debian/rules
* touch firefox .autoreg in postinst of mozilla plugin
  - update debian/mozilla-plugin-gnash.postinst
* link gnash in ubufox plugins directory for the plugin alternative switcher
  - add debian/mozilla-plugin-gnash.links
* suggest ubufox accordingly
  - update debian/control
* add new required build-depends on libgif-dev
  - update debian/control
* add Xb-Npp-Description and Xb-Npp-File as new plugin database meta data
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* GStreamer
2
 
 * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
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., 59 Temple Place - Suite 330,
17
 
 * Boston, MA 02111-1307, USA.
18
 
 */
19
 
 
20
 
#include "gstflvparse.h"
21
 
 
22
 
#include <string.h>
23
 
 
24
 
GST_DEBUG_CATEGORY_EXTERN (flvdemux_debug);
25
 
#define GST_CAT_DEFAULT flvdemux_debug
26
 
 
27
 
static guint32
28
 
FLV_GET_BEUI24 (const guint8 * data, size_t data_size)
29
 
{
30
 
  guint32 ret = 0;
31
 
 
32
 
  g_return_val_if_fail (data != NULL, 0);
33
 
  g_return_val_if_fail (data_size >= 3, 0);
34
 
 
35
 
  ret = GST_READ_UINT16_BE (data) << 8;
36
 
  ret |= GST_READ_UINT8 (data + 2);
37
 
 
38
 
  return ret;
39
 
}
40
 
 
41
 
static gchar *
42
 
FLV_GET_STRING (const guint8 * data, size_t data_size)
43
 
{
44
 
  guint32 string_size = 0;
45
 
  gchar *string = NULL;
46
 
 
47
 
  g_return_val_if_fail (data != NULL, NULL);
48
 
  g_return_val_if_fail (data_size >= 2, NULL);
49
 
 
50
 
  string_size = GST_READ_UINT16_BE (data);
51
 
  if (G_UNLIKELY (string_size > data_size)) {
52
 
    return NULL;
53
 
  }
54
 
 
55
 
  string = g_try_malloc0 (string_size + 1);
56
 
  if (G_UNLIKELY (!string)) {
57
 
    return NULL;
58
 
  }
59
 
 
60
 
  memcpy (string, data + 2, string_size);
61
 
 
62
 
  return string;
63
 
}
64
 
 
65
 
static const GstQueryType *
66
 
gst_flv_demux_query_types (GstPad * pad)
67
 
{
68
 
  static const GstQueryType query_types[] = {
69
 
    GST_QUERY_DURATION,
70
 
    0
71
 
  };
72
 
 
73
 
  return query_types;
74
 
}
75
 
 
76
 
static size_t
77
 
gst_flv_parse_metadata_item (GstFLVDemux * demux, const guint8 * data,
78
 
    size_t data_size, gboolean * end_marker)
79
 
{
80
 
  gchar *tag_name = NULL;
81
 
  guint8 tag_type = 0;
82
 
  size_t offset = 0;
83
 
 
84
 
  /* Initialize the end_marker flag to FALSE */
85
 
  *end_marker = FALSE;
86
 
 
87
 
  /* Name of the tag */
88
 
  tag_name = FLV_GET_STRING (data, data_size);
89
 
  if (G_UNLIKELY (!tag_name)) {
90
 
    GST_WARNING_OBJECT (demux, "failed reading tag name");
91
 
    goto beach;
92
 
  }
93
 
 
94
 
  offset += strlen (tag_name) + 2;
95
 
 
96
 
  /* What kind of object is that */
97
 
  tag_type = GST_READ_UINT8 (data + offset);
98
 
 
99
 
  offset++;
100
 
 
101
 
  GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
102
 
 
103
 
  switch (tag_type) {
104
 
    case 0:                    // Double
105
 
    {                           /* Use a union to read the uint64 and then as a double */
106
 
      union
107
 
      {
108
 
        guint64 value_uint64;
109
 
        gdouble value_double;
110
 
      } value_union;
111
 
 
112
 
      value_union.value_uint64 = GST_READ_UINT64_BE (data + offset);
113
 
 
114
 
      offset += 8;
115
 
 
116
 
      GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name,
117
 
          value_union.value_double);
118
 
 
119
 
      if (!strcmp (tag_name, "duration")) {
120
 
        demux->duration = value_union.value_double * GST_SECOND;
121
 
 
122
 
        gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
123
 
            GST_TAG_DURATION, demux->duration, NULL);
124
 
      } else {
125
 
        if (tag_name) {
126
 
          if (!strcmp (tag_name, "AspectRatioX")) {
127
 
            demux->par_x = value_union.value_double;
128
 
            demux->got_par = TRUE;
129
 
          } else if (!strcmp (tag_name, "AspectRatioY")) {
130
 
            demux->par_y = value_union.value_double;
131
 
            demux->got_par = TRUE;
132
 
          }
133
 
          if (!gst_tag_exists (tag_name)) {
134
 
            gst_tag_register (tag_name, GST_TAG_FLAG_META, G_TYPE_DOUBLE,
135
 
                tag_name, tag_name, gst_tag_merge_use_first);
136
 
          }
137
 
 
138
 
          if (gst_tag_get_type (tag_name) == G_TYPE_DOUBLE) {
139
 
            gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
140
 
                tag_name, value_union.value_double, NULL);
141
 
          } else {
142
 
            GST_WARNING_OBJECT (demux, "tag %s already registered with a "
143
 
                "different type", tag_name);
144
 
          }
145
 
        }
146
 
      }
147
 
 
148
 
      break;
149
 
    }
150
 
    case 1:                    // Boolean
151
 
    {
152
 
      gboolean value = GST_READ_UINT8 (data + offset);
153
 
 
154
 
      offset++;
155
 
 
156
 
      GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, value);
157
 
 
158
 
      if (tag_name) {
159
 
        if (!gst_tag_exists (tag_name)) {
160
 
          gst_tag_register (tag_name, GST_TAG_FLAG_META, G_TYPE_BOOLEAN,
161
 
              tag_name, tag_name, gst_tag_merge_use_first);
162
 
        }
163
 
 
164
 
        if (gst_tag_get_type (tag_name) == G_TYPE_BOOLEAN) {
165
 
          gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
166
 
              tag_name, value, NULL);
167
 
        } else {
168
 
          GST_WARNING_OBJECT (demux, "tag %s already registered with a "
169
 
              "different type", tag_name);
170
 
        }
171
 
      }
172
 
 
173
 
      break;
174
 
    }
175
 
    case 2:                    // String
176
 
    {
177
 
      gchar *value = NULL;
178
 
 
179
 
      value = FLV_GET_STRING (data + offset, data_size - offset);
180
 
 
181
 
      offset += strlen (value) + 2;
182
 
 
183
 
      GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, value);
184
 
 
185
 
      if (tag_name) {
186
 
        if (!gst_tag_exists (tag_name)) {
187
 
          gst_tag_register (tag_name, GST_TAG_FLAG_META, G_TYPE_STRING,
188
 
              tag_name, tag_name, gst_tag_merge_strings_with_comma);
189
 
        }
190
 
 
191
 
        if (gst_tag_get_type (tag_name) == G_TYPE_STRING) {
192
 
          gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
193
 
              tag_name, value, NULL);
194
 
        } else {
195
 
          GST_WARNING_OBJECT (demux, "tag %s already registered with a "
196
 
              "different type", tag_name);
197
 
        }
198
 
      }
199
 
 
200
 
      g_free (value);
201
 
 
202
 
      break;
203
 
    }
204
 
    case 3:                    // Object
205
 
    {
206
 
      gboolean end_of_object_marker = FALSE;
207
 
 
208
 
      while (!end_of_object_marker && offset < data_size) {
209
 
        size_t read = gst_flv_parse_metadata_item (demux, data + offset,
210
 
            data_size - offset, &end_of_object_marker);
211
 
 
212
 
        if (G_UNLIKELY (!read)) {
213
 
          GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
214
 
          break;
215
 
        }
216
 
 
217
 
        offset += read;
218
 
      }
219
 
 
220
 
      break;
221
 
    }
222
 
    case 9:                    // End marker
223
 
    {
224
 
      GST_DEBUG_OBJECT (demux, "end marker ?");
225
 
      if (tag_name[0] == '\0') {
226
 
 
227
 
        GST_DEBUG_OBJECT (demux, "end marker detected");
228
 
 
229
 
        *end_marker = TRUE;
230
 
      }
231
 
 
232
 
      break;
233
 
    }
234
 
    case 10:                   // Array
235
 
    {
236
 
      guint32 nb_elems = GST_READ_UINT32_BE (data + offset);
237
 
 
238
 
      offset += 4;
239
 
 
240
 
      GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
241
 
 
242
 
      if (!strcmp (tag_name, "times")) {
243
 
        if (demux->times) {
244
 
          g_array_free (demux->times, TRUE);
245
 
        }
246
 
        demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
247
 
      } else if (!strcmp (tag_name, "filepositions")) {
248
 
        if (demux->filepositions) {
249
 
          g_array_free (demux->filepositions, TRUE);
250
 
        }
251
 
        demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
252
 
      }
253
 
 
254
 
      while (nb_elems--) {
255
 
        guint8 elem_type = GST_READ_UINT8 (data + offset);
256
 
 
257
 
        offset++;
258
 
 
259
 
        switch (elem_type) {
260
 
          case 0:
261
 
          {
262
 
            union
263
 
            {
264
 
              guint64 value_uint64;
265
 
              gdouble value_double;
266
 
            } value_union;
267
 
 
268
 
            value_union.value_uint64 = GST_READ_UINT64_BE (data + offset);
269
 
 
270
 
            offset += 8;
271
 
 
272
 
            GST_DEBUG_OBJECT (demux, "element is a double %f",
273
 
                value_union.value_double);
274
 
 
275
 
            if (!strcmp (tag_name, "times") && demux->times) {
276
 
              g_array_append_val (demux->times, value_union.value_double);
277
 
            } else if (!strcmp (tag_name, "filepositions") &&
278
 
                demux->filepositions) {
279
 
              g_array_append_val (demux->filepositions,
280
 
                  value_union.value_double);
281
 
            }
282
 
            break;
283
 
          }
284
 
          default:
285
 
            GST_WARNING_OBJECT (demux, "unsupported array element type %d",
286
 
                elem_type);
287
 
        }
288
 
      }
289
 
 
290
 
      break;
291
 
    }
292
 
    case 11:                   // Date
293
 
    {
294
 
      union
295
 
      {
296
 
        guint64 value_uint64;
297
 
        gdouble value_double;
298
 
      } value_union;
299
 
 
300
 
      value_union.value_uint64 = GST_READ_UINT64_BE (data + offset);
301
 
 
302
 
      offset += 8;
303
 
 
304
 
      /* There are 2 additional bytes */
305
 
      offset += 2;
306
 
 
307
 
      GST_DEBUG_OBJECT (demux, "%s => (date as a double) %f", tag_name,
308
 
          value_union.value_double);
309
 
 
310
 
      break;
311
 
    }
312
 
    default:
313
 
      GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
314
 
  }
315
 
 
316
 
  g_free (tag_name);
317
 
 
318
 
beach:
319
 
  return offset;
320
 
}
321
 
 
322
 
GstFlowReturn
323
 
gst_flv_parse_tag_script (GstFLVDemux * demux, const guint8 * data,
324
 
    size_t data_size)
325
 
{
326
 
  GstFlowReturn ret = GST_FLOW_OK;
327
 
  size_t offset = 7;
328
 
 
329
 
  GST_LOG_OBJECT (demux, "parsing a script tag");
330
 
 
331
 
  if (GST_READ_UINT8 (data + offset++) == 2) {
332
 
    guint i;
333
 
    gchar *function_name = FLV_GET_STRING (data + offset, data_size - offset);
334
 
 
335
 
    GST_LOG_OBJECT (demux, "function name is %s", function_name);
336
 
 
337
 
    if (TRUE) {
338
 
      guint32 nb_elems = 0;
339
 
      gboolean end_marker = FALSE;
340
 
 
341
 
      GST_DEBUG_OBJECT (demux, "we have a metadata script object");
342
 
      
343
 
      if (!gst_tag_exists ("___function_name___")) {
344
 
        gst_tag_register ("___function_name___", GST_TAG_FLAG_META, G_TYPE_STRING,
345
 
                          "___function_name___", "___function_name___", 
346
 
                          gst_tag_merge_strings_with_comma);
347
 
      }
348
 
 
349
 
      if (gst_tag_get_type ("___function_name___") == G_TYPE_STRING) {
350
 
        gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
351
 
                          "___function_name___", function_name, NULL);
352
 
      }
353
 
 
354
 
      /* Jump over the function_name string and the array indicator */
355
 
      offset += strlen(function_name) + 3;
356
 
 
357
 
      nb_elems = GST_READ_UINT32_BE (data + offset);
358
 
 
359
 
      /* Jump over the number of elements */
360
 
      offset += 4;
361
 
 
362
 
      GST_DEBUG_OBJECT (demux, "there are %d elements in the array", nb_elems);
363
 
 
364
 
      while (nb_elems-- && !end_marker) {
365
 
        size_t read = gst_flv_parse_metadata_item (demux, data + offset,
366
 
            data_size - offset, &end_marker);
367
 
 
368
 
        if (G_UNLIKELY (!read)) {
369
 
          GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
370
 
          break;
371
 
        }
372
 
        offset += read;
373
 
      }
374
 
 
375
 
      demux->push_tags = TRUE;
376
 
    }
377
 
 
378
 
    g_free (function_name);
379
 
 
380
 
    if (demux->index && demux->times && demux->filepositions) {
381
 
      /* If an index was found, insert associations */
382
 
      for (i = 0; i < MIN (demux->times->len, demux->filepositions->len); i++) {
383
 
        guint64 time, fileposition;
384
 
 
385
 
        time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
386
 
        fileposition = g_array_index (demux->filepositions, gdouble, i);
387
 
        GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
388
 
            G_GUINT64_FORMAT, GST_TIME_ARGS (time), fileposition);
389
 
        gst_index_add_association (demux->index, demux->index_id,
390
 
            GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, time,
391
 
            GST_FORMAT_BYTES, fileposition, NULL);
392
 
      }
393
 
    }
394
 
  }
395
 
 
396
 
 
397
 
  return ret;
398
 
}
399
 
 
400
 
GstFlowReturn
401
 
gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data,
402
 
    size_t data_size)
403
 
{
404
 
  GstFlowReturn ret = GST_FLOW_OK;
405
 
  GstBuffer *buffer = NULL;
406
 
  guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
407
 
  guint32 codec_data = 0, pts_ext = 0;
408
 
  guint8 flags = 0;
409
 
 
410
 
  GST_LOG_OBJECT (demux, "parsing an audio tag");
411
 
 
412
 
  GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
413
 
      data[2], data[3]);
414
 
 
415
 
  /* Grab information about audio tag */
416
 
  pts = FLV_GET_BEUI24 (data, data_size);
417
 
  /* read the pts extension to 32 bits integer */
418
 
  pts_ext = GST_READ_UINT8 (data + 3);
419
 
  /* Combine them */
420
 
  pts |= pts_ext << 24;
421
 
  /* Skip the stream id and go directly to the flags */
422
 
  flags = GST_READ_UINT8 (data + 7);
423
 
 
424
 
  /* Channels */
425
 
  if (flags & 0x01) {
426
 
    channels = 2;
427
 
  }
428
 
  /* Width */
429
 
  if (flags & 0x02) {
430
 
    width = 16;
431
 
  }
432
 
  /* Sampling rate */
433
 
  if ((flags & 0x0C) == 0x0C) {
434
 
    rate = 44100;
435
 
  } else if ((flags & 0x0C) == 0x08) {
436
 
    rate = 22050;
437
 
  } else if ((flags & 0x0C) == 0x04) {
438
 
    rate = 11025;
439
 
  }
440
 
  /* Codec tag */
441
 
  codec_tag = flags >> 4;
442
 
  codec_data = 1;
443
 
 
444
 
  GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
445
 
      "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
446
 
      codec_tag, flags);
447
 
 
448
 
  /* If we don't have our audio pad created, then create it. */
449
 
  if (G_UNLIKELY (!demux->audio_pad)) {
450
 
    GstCaps *caps = NULL;
451
 
    gchar *codec_name = NULL;
452
 
 
453
 
    demux->audio_pad = gst_pad_new ("audio", GST_PAD_SRC);
454
 
    if (G_UNLIKELY (!demux->audio_pad)) {
455
 
      GST_WARNING_OBJECT (demux, "failed creating audio pad");
456
 
      ret = GST_FLOW_ERROR;
457
 
      goto beach;
458
 
    }
459
 
 
460
 
    /* Make it active */
461
 
    gst_pad_set_active (demux->audio_pad, TRUE);
462
 
 
463
 
    switch (codec_tag) {
464
 
      case 1:
465
 
        caps =
466
 
            gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
467
 
            "swf", NULL);
468
 
        codec_name = "Shockwave ADPCM";
469
 
        break;
470
 
      case 2:
471
 
        caps = gst_caps_new_simple ("audio/mpeg",
472
 
            "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL);
473
 
        codec_name = "MPEG 1 Audio, Layer 3 (MP3)";
474
 
        break;
475
 
      case 0:
476
 
      case 3:
477
 
        caps = gst_caps_new_simple ("audio/x-raw-int",
478
 
            "endianness", G_TYPE_INT, G_BYTE_ORDER,
479
 
            "signed", G_TYPE_BOOLEAN, TRUE,
480
 
            "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL);
481
 
        codec_name = "Raw Audio";
482
 
        break;
483
 
      case 5:
484
 
      case 6:
485
 
        caps = gst_caps_new_simple ("audio/x-nellymoser", NULL);
486
 
        codec_name = "Nellymoser ASAO";
487
 
        break;
488
 
      default:
489
 
        GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
490
 
    }
491
 
 
492
 
    if (G_UNLIKELY (!caps)) {
493
 
      GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
494
 
      ret = GST_FLOW_ERROR;
495
 
      gst_object_unref (demux->audio_pad);
496
 
      demux->audio_pad = NULL;
497
 
      goto beach;
498
 
    }
499
 
 
500
 
    gst_caps_set_simple (caps,
501
 
        "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL);
502
 
 
503
 
    gst_pad_set_caps (demux->audio_pad, caps);
504
 
    if (codec_name) {
505
 
      if (demux->taglist == NULL)
506
 
        demux->taglist = gst_tag_list_new ();
507
 
      gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
508
 
          GST_TAG_AUDIO_CODEC, codec_name, NULL);
509
 
    }
510
 
 
511
 
    GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
512
 
        caps);
513
 
 
514
 
    gst_caps_unref (caps);
515
 
 
516
 
    /* Store the caps we have set */
517
 
    demux->audio_codec_tag = codec_tag;
518
 
    demux->rate = rate;
519
 
    demux->channels = channels;
520
 
    demux->width = width;
521
 
 
522
 
    /* Set functions on the pad */
523
 
    gst_pad_set_query_type_function (demux->audio_pad,
524
 
        GST_DEBUG_FUNCPTR (gst_flv_demux_query_types));
525
 
    gst_pad_set_query_function (demux->audio_pad,
526
 
        GST_DEBUG_FUNCPTR (gst_flv_demux_query));
527
 
    gst_pad_set_event_function (demux->audio_pad,
528
 
        GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
529
 
 
530
 
    /* We need to set caps before adding */
531
 
    gst_element_add_pad (GST_ELEMENT (demux),
532
 
        gst_object_ref (demux->audio_pad));
533
 
 
534
 
    /* We only emit no more pads when we have audio and video. Indeed we can
535
 
     * not trust the FLV header to tell us if there will be only audio or 
536
 
     * only video and we would just break discovery of some files */
537
 
    if (demux->audio_pad && demux->video_pad) {
538
 
      GST_DEBUG_OBJECT (demux, "emitting no more pads");
539
 
      gst_element_no_more_pads (GST_ELEMENT (demux));
540
 
    }
541
 
  }
542
 
 
543
 
  /* Check if caps have changed */
544
 
  if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
545
 
          codec_tag != demux->audio_codec_tag || width != demux->width)) {
546
 
    GstCaps *caps = NULL;
547
 
    gchar *codec_name = NULL;
548
 
 
549
 
    GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
550
 
 
551
 
    switch (codec_tag) {
552
 
      case 1:
553
 
        caps =
554
 
            gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
555
 
            "swf", NULL);
556
 
        codec_name = "Shockwave ADPCM";
557
 
        break;
558
 
      case 2:
559
 
        caps = gst_caps_new_simple ("audio/mpeg",
560
 
            "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL);
561
 
        codec_name = "MPEG 1 Audio, Layer 3 (MP3)";
562
 
        break;
563
 
      case 0:
564
 
      case 3:
565
 
        caps = gst_caps_new_simple ("audio/x-raw-int", NULL);
566
 
        codec_name = "Raw Audio";
567
 
        break;
568
 
      case 6:
569
 
        caps = gst_caps_new_simple ("audio/x-nellymoser", NULL);
570
 
        codec_name = "Nellymoser ASAO";
571
 
        break;
572
 
      default:
573
 
        GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
574
 
    }
575
 
 
576
 
    if (G_UNLIKELY (!caps)) {
577
 
      GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
578
 
      ret = GST_FLOW_ERROR;
579
 
      goto beach;
580
 
    }
581
 
 
582
 
    gst_caps_set_simple (caps,
583
 
        "rate", G_TYPE_INT, rate,
584
 
        "channels", G_TYPE_INT, channels, "width", G_TYPE_INT, width, NULL);
585
 
 
586
 
    gst_pad_set_caps (demux->audio_pad, caps);
587
 
    if (codec_name) {
588
 
      if (demux->taglist == NULL)
589
 
        demux->taglist = gst_tag_list_new ();
590
 
      gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
591
 
          GST_TAG_AUDIO_CODEC, codec_name, NULL);
592
 
    }
593
 
 
594
 
    gst_caps_unref (caps);
595
 
 
596
 
    /* Store the caps we have set */
597
 
    demux->audio_codec_tag = codec_tag;
598
 
    demux->rate = rate;
599
 
    demux->channels = channels;
600
 
    demux->width = width;
601
 
  }
602
 
 
603
 
  /* Push taglist if present */
604
 
  if ((demux->has_audio && !demux->audio_pad) ||
605
 
      (demux->has_video && !demux->video_pad)) {
606
 
    GST_DEBUG_OBJECT (demux, "we are still waiting for a stream to come up "
607
 
        "before we can push tags");
608
 
  } else {
609
 
    if (demux->taglist && demux->push_tags) {
610
 
      GST_DEBUG_OBJECT (demux, "pushing tags out");
611
 
      gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
612
 
      demux->taglist = gst_tag_list_new ();
613
 
      demux->push_tags = FALSE;
614
 
    }
615
 
  }
616
 
 
617
 
  /* Check if we have anything to push */
618
 
  if (demux->tag_data_size <= codec_data) {
619
 
    GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
620
 
    goto beach;
621
 
  }
622
 
 
623
 
  /* Create buffer from pad */
624
 
  ret = gst_pad_alloc_buffer (demux->audio_pad, GST_BUFFER_OFFSET_NONE,
625
 
      demux->tag_data_size - codec_data, GST_PAD_CAPS (demux->audio_pad),
626
 
      &buffer);
627
 
  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
628
 
    GST_WARNING_OBJECT (demux, "failed allocating a %" G_GUINT64_FORMAT
629
 
        " bytes buffer: %s", demux->tag_data_size, gst_flow_get_name (ret));
630
 
    if (ret == GST_FLOW_NOT_LINKED) {
631
 
      demux->audio_linked = FALSE;
632
 
    }
633
 
    goto beach;
634
 
  }
635
 
 
636
 
  demux->audio_linked = TRUE;
637
 
 
638
 
  /* Fill buffer with data */
639
 
  GST_BUFFER_TIMESTAMP (buffer) = pts * GST_MSECOND;
640
 
  GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
641
 
  GST_BUFFER_OFFSET (buffer) = demux->audio_offset++;
642
 
  GST_BUFFER_OFFSET_END (buffer) = demux->audio_offset;
643
 
 
644
 
  if (G_UNLIKELY (demux->audio_need_discont)) {
645
 
    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
646
 
    demux->audio_need_discont = FALSE;
647
 
  }
648
 
 
649
 
  gst_segment_set_last_stop (demux->segment, GST_FORMAT_TIME,
650
 
      GST_BUFFER_TIMESTAMP (buffer));
651
 
 
652
 
  /* Do we need a newsegment event ? */
653
 
  if (G_UNLIKELY (demux->audio_need_segment)) {
654
 
    if (!demux->new_seg_event) {
655
 
      GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
656
 
          GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
657
 
          GST_TIME_ARGS (demux->segment->last_stop),
658
 
          GST_TIME_ARGS (demux->segment->stop));
659
 
      demux->new_seg_event =
660
 
          gst_event_new_new_segment (FALSE, demux->segment->rate,
661
 
          demux->segment->format, demux->segment->last_stop,
662
 
          demux->segment->stop, demux->segment->last_stop);
663
 
    } else {
664
 
      GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
665
 
    }
666
 
 
667
 
    gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
668
 
 
669
 
    demux->audio_need_segment = FALSE;
670
 
  }
671
 
 
672
 
  memcpy (GST_BUFFER_DATA (buffer), data + 7 + codec_data,
673
 
      demux->tag_data_size - codec_data);
674
 
 
675
 
  GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
676
 
      " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
677
 
      GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
678
 
      GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_OFFSET (buffer));
679
 
 
680
 
  /* Push downstream */
681
 
  ret = gst_pad_push (demux->audio_pad, buffer);
682
 
 
683
 
beach:
684
 
  return ret;
685
 
}
686
 
 
687
 
GstFlowReturn
688
 
gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data,
689
 
    size_t data_size)
690
 
{
691
 
  GstFlowReturn ret = GST_FLOW_OK;
692
 
  GstBuffer *buffer = NULL;
693
 
  guint32 pts = 0, codec_data = 1, pts_ext = 0;
694
 
  gboolean keyframe = FALSE;
695
 
  guint8 flags = 0, codec_tag = 0;
696
 
 
697
 
  GST_LOG_OBJECT (demux, "parsing a video tag");
698
 
 
699
 
  GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
700
 
      data[2], data[3]);
701
 
 
702
 
  /* Grab information about video tag */
703
 
  pts = FLV_GET_BEUI24 (data, data_size);
704
 
  /* read the pts extension to 32 bits integer */
705
 
  pts_ext = GST_READ_UINT8 (data + 3);
706
 
  /* Combine them */
707
 
  pts |= pts_ext << 24;
708
 
  /* Skip the stream id and go directly to the flags */
709
 
  flags = GST_READ_UINT8 (data + 7);
710
 
 
711
 
  /* Keyframe */
712
 
  if ((flags >> 4) == 1) {
713
 
    keyframe = TRUE;
714
 
  }
715
 
  /* Codec tag */
716
 
  codec_tag = flags & 0x0F;
717
 
  if (codec_tag == 4 || codec_tag == 5) {
718
 
    codec_data = 2;
719
 
  }
720
 
 
721
 
  GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
722
 
      "(flags %02X)", codec_tag, keyframe, flags);
723
 
 
724
 
  /* If we don't have our video pad created, then create it. */
725
 
  if (G_UNLIKELY (!demux->video_pad)) {
726
 
    GstCaps *caps = NULL;
727
 
    gchar *codec_name = NULL;
728
 
 
729
 
    demux->video_pad = gst_pad_new ("video", GST_PAD_SRC);
730
 
    if (G_UNLIKELY (!demux->video_pad)) {
731
 
      GST_WARNING_OBJECT (demux, "failed creating video pad");
732
 
      ret = GST_FLOW_ERROR;
733
 
      goto beach;
734
 
    }
735
 
    /* Make it active */
736
 
    gst_pad_set_active (demux->video_pad, TRUE);
737
 
 
738
 
    /* Generate caps for that pad */
739
 
    switch (codec_tag) {
740
 
      case 2:
741
 
        caps = gst_caps_new_simple ("video/x-flash-video", NULL);
742
 
        codec_name = "Sorenson Video";
743
 
        break;
744
 
      case 3:
745
 
        caps = gst_caps_new_simple ("video/x-flash-screen", NULL);
746
 
        codec_name = "Flash Screen Video";
747
 
      case 4:
748
 
      case 5:
749
 
        caps = gst_caps_new_simple ("video/x-vp6-flash", NULL);
750
 
        codec_name = "On2 VP6 Video";
751
 
        break;
752
 
      default:
753
 
        GST_WARNING_OBJECT (demux, "unsupported video codec tag %d", codec_tag);
754
 
    }
755
 
 
756
 
    if (G_UNLIKELY (!caps)) {
757
 
      GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
758
 
      gst_object_unref (demux->video_pad);
759
 
      demux->video_pad = NULL;
760
 
      ret = GST_FLOW_ERROR;
761
 
      goto beach;
762
 
    }
763
 
 
764
 
    gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
765
 
        demux->par_x, demux->par_y, NULL);
766
 
 
767
 
    /* When we ve set pixel-aspect-ratio we use that boolean to detect a 
768
 
     * metadata tag that would come later and trigger a caps change */
769
 
    demux->got_par = FALSE;
770
 
 
771
 
    gst_pad_set_caps (demux->video_pad, caps);
772
 
 
773
 
    GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
774
 
        caps);
775
 
 
776
 
    gst_caps_unref (caps);
777
 
    if (codec_name) {
778
 
      if (demux->taglist == NULL)
779
 
        demux->taglist = gst_tag_list_new ();
780
 
      gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
781
 
          GST_TAG_VIDEO_CODEC, codec_name, NULL);
782
 
    }
783
 
 
784
 
    /* Store the caps we have set */
785
 
    demux->video_codec_tag = codec_tag;
786
 
 
787
 
    /* Set functions on the pad */
788
 
    gst_pad_set_query_type_function (demux->video_pad,
789
 
        GST_DEBUG_FUNCPTR (gst_flv_demux_query_types));
790
 
    gst_pad_set_query_function (demux->video_pad,
791
 
        GST_DEBUG_FUNCPTR (gst_flv_demux_query));
792
 
    gst_pad_set_event_function (demux->video_pad,
793
 
        GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
794
 
 
795
 
    /* We need to set caps before adding */
796
 
    gst_element_add_pad (GST_ELEMENT (demux),
797
 
        gst_object_ref (demux->video_pad));
798
 
 
799
 
    /* We only emit no more pads when we have audio and video. Indeed we can
800
 
     * not trust the FLV header to tell us if there will be only audio or 
801
 
     * only video and we would just break discovery of some files */
802
 
    if (demux->audio_pad && demux->video_pad) {
803
 
      GST_DEBUG_OBJECT (demux, "emitting no more pads");
804
 
      gst_element_no_more_pads (GST_ELEMENT (demux));
805
 
    }
806
 
  }
807
 
 
808
 
  /* Check if caps have changed */
809
 
  if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
810
 
    GstCaps *caps = NULL;
811
 
    gchar *codec_name = NULL;
812
 
 
813
 
    GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
814
 
 
815
 
    /* Generate caps for that pad */
816
 
    switch (codec_tag) {
817
 
      case 2:
818
 
        caps = gst_caps_new_simple ("video/x-flash-video", NULL);
819
 
        codec_name = "Sorenson Video";
820
 
        break;
821
 
      case 3:
822
 
        caps = gst_caps_new_simple ("video/x-flash-screen", NULL);
823
 
        codec_name = "Flash Screen Video";
824
 
      case 4:
825
 
      case 5:
826
 
        caps = gst_caps_new_simple ("video/x-vp6", NULL);
827
 
        codec_name = "On2 VP6 Video";
828
 
        break;
829
 
      default:
830
 
        GST_WARNING_OBJECT (demux, "unsupported video codec tag %d", codec_tag);
831
 
    }
832
 
 
833
 
    if (G_UNLIKELY (!caps)) {
834
 
      GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
835
 
      ret = GST_FLOW_ERROR;
836
 
      goto beach;
837
 
    }
838
 
 
839
 
    gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
840
 
        demux->par_x, demux->par_y, NULL);
841
 
 
842
 
    /* When we ve set pixel-aspect-ratio we use that boolean to detect a 
843
 
     * metadata tag that would come later and trigger a caps change */
844
 
    demux->got_par = FALSE;
845
 
 
846
 
    gst_pad_set_caps (demux->video_pad, caps);
847
 
 
848
 
    gst_caps_unref (caps);
849
 
    if (codec_name) {
850
 
      if (demux->taglist == NULL)
851
 
        demux->taglist = gst_tag_list_new ();
852
 
      gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
853
 
          GST_TAG_VIDEO_CODEC, codec_name, NULL);
854
 
    }
855
 
 
856
 
    /* Store the caps we have set */
857
 
    demux->video_codec_tag = codec_tag;
858
 
  }
859
 
 
860
 
  /* Push taglist if present */
861
 
  if ((demux->has_audio && !demux->audio_pad) ||
862
 
      (demux->has_video && !demux->video_pad)) {
863
 
    GST_DEBUG_OBJECT (demux, "we are still waiting for a stream to come up "
864
 
        "before we can push tags");
865
 
  } else {
866
 
    if (demux->taglist && demux->push_tags) {
867
 
      GST_DEBUG_OBJECT (demux, "pushing tags out");
868
 
      gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
869
 
      demux->taglist = gst_tag_list_new ();
870
 
      demux->push_tags = FALSE;
871
 
    }
872
 
  }
873
 
 
874
 
  /* Check if we have anything to push */
875
 
  if (demux->tag_data_size <= codec_data) {
876
 
    GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
877
 
    goto beach;
878
 
  }
879
 
 
880
 
  /* Create buffer from pad */
881
 
  ret = gst_pad_alloc_buffer (demux->video_pad, GST_BUFFER_OFFSET_NONE,
882
 
      demux->tag_data_size - codec_data, GST_PAD_CAPS (demux->video_pad),
883
 
      &buffer);
884
 
  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
885
 
    GST_WARNING_OBJECT (demux, "failed allocating a %" G_GUINT64_FORMAT
886
 
        " bytes buffer: %s", demux->tag_data_size, gst_flow_get_name (ret));
887
 
    if (ret == GST_FLOW_NOT_LINKED) {
888
 
      demux->video_linked = FALSE;
889
 
    }
890
 
    goto beach;
891
 
  }
892
 
 
893
 
  demux->video_linked = TRUE;
894
 
 
895
 
  /* Fill buffer with data */
896
 
  GST_BUFFER_TIMESTAMP (buffer) = pts * GST_MSECOND;
897
 
  GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
898
 
  GST_BUFFER_OFFSET (buffer) = demux->video_offset++;
899
 
  GST_BUFFER_OFFSET_END (buffer) = demux->video_offset;
900
 
 
901
 
  if (!keyframe) {
902
 
    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
903
 
  } else {
904
 
    if (demux->index) {
905
 
      GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
906
 
          G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
907
 
          demux->cur_tag_offset);
908
 
      gst_index_add_association (demux->index, demux->index_id,
909
 
          GST_ASSOCIATION_FLAG_KEY_UNIT,
910
 
          GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer),
911
 
          GST_FORMAT_BYTES, demux->cur_tag_offset, NULL);
912
 
    }
913
 
  }
914
 
 
915
 
  if (G_UNLIKELY (demux->video_need_discont)) {
916
 
    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
917
 
    demux->video_need_discont = FALSE;
918
 
  }
919
 
 
920
 
  gst_segment_set_last_stop (demux->segment, GST_FORMAT_TIME,
921
 
      GST_BUFFER_TIMESTAMP (buffer));
922
 
 
923
 
  /* Do we need a newsegment event ? */
924
 
  if (G_UNLIKELY (demux->video_need_segment)) {
925
 
    if (!demux->new_seg_event) {
926
 
      GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
927
 
          GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
928
 
          GST_TIME_ARGS (demux->segment->last_stop),
929
 
          GST_TIME_ARGS (demux->segment->stop));
930
 
      demux->new_seg_event =
931
 
          gst_event_new_new_segment (FALSE, demux->segment->rate,
932
 
          demux->segment->format, demux->segment->last_stop,
933
 
          demux->segment->stop, demux->segment->last_stop);
934
 
    } else {
935
 
      GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
936
 
    }
937
 
 
938
 
    gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
939
 
 
940
 
    demux->video_need_segment = FALSE;
941
 
  }
942
 
 
943
 
  /* FIXME: safety checks */
944
 
  memcpy (GST_BUFFER_DATA (buffer), data + 7 + codec_data,
945
 
      demux->tag_data_size - codec_data);
946
 
 
947
 
  GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
948
 
      " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
949
 
      ", keyframe (%d)", GST_BUFFER_SIZE (buffer),
950
 
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
951
 
      GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_OFFSET (buffer),
952
 
      keyframe);
953
 
 
954
 
  /* Push downstream */
955
 
  ret = gst_pad_push (demux->video_pad, buffer);
956
 
 
957
 
beach:
958
 
  return ret;
959
 
}
960
 
 
961
 
GstFlowReturn
962
 
gst_flv_parse_tag_type (GstFLVDemux * demux, const guint8 * data,
963
 
    size_t data_size)
964
 
{
965
 
  GstFlowReturn ret = GST_FLOW_OK;
966
 
  guint8 tag_type = 0;
967
 
 
968
 
  tag_type = data[0];
969
 
 
970
 
  switch (tag_type) {
971
 
    case 9:
972
 
      demux->state = FLV_STATE_TAG_VIDEO;
973
 
      demux->has_video = TRUE;
974
 
      break;
975
 
    case 8:
976
 
      demux->state = FLV_STATE_TAG_AUDIO;
977
 
      demux->has_audio = TRUE;
978
 
      break;
979
 
    case 18:
980
 
      demux->state = FLV_STATE_TAG_SCRIPT;
981
 
      break;
982
 
    default:
983
 
      GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
984
 
  }
985
 
 
986
 
  /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
987
 
   * 4 bytes of previous tag size */
988
 
  demux->tag_data_size = FLV_GET_BEUI24 (data + 1, data_size - 1);
989
 
  demux->tag_size = demux->tag_data_size + 11;
990
 
 
991
 
  GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
992
 
      demux->tag_data_size);
993
 
 
994
 
  return ret;
995
 
}
996
 
 
997
 
GstFlowReturn
998
 
gst_flv_parse_header (GstFLVDemux * demux, const guint8 * data,
999
 
    size_t data_size)
1000
 
{
1001
 
  GstFlowReturn ret = GST_FLOW_OK;
1002
 
 
1003
 
  /* Check for the FLV tag */
1004
 
  if (data[0] == 'F' && data[1] == 'L' && data[2] == 'V') {
1005
 
    GST_DEBUG_OBJECT (demux, "FLV header detected");
1006
 
  } else {
1007
 
    if (G_UNLIKELY (demux->strict)) {
1008
 
      GST_WARNING_OBJECT (demux, "invalid header tag detected");
1009
 
      ret = GST_FLOW_UNEXPECTED;
1010
 
      goto beach;
1011
 
    }
1012
 
  }
1013
 
 
1014
 
  /* Jump over the 4 first bytes */
1015
 
  data += 4;
1016
 
 
1017
 
  /* Now look at audio/video flags */
1018
 
  {
1019
 
    guint8 flags = data[0];
1020
 
 
1021
 
    demux->has_video = demux->has_audio = FALSE;
1022
 
 
1023
 
    if (flags & 1) {
1024
 
      GST_DEBUG_OBJECT (demux, "there is a video stream");
1025
 
      demux->has_video = TRUE;
1026
 
    }
1027
 
    if (flags & 4) {
1028
 
      GST_DEBUG_OBJECT (demux, "there is an audio stream");
1029
 
      demux->has_audio = TRUE;
1030
 
    }
1031
 
  }
1032
 
 
1033
 
  /* We don't care about the rest */
1034
 
  demux->need_header = FALSE;
1035
 
 
1036
 
beach:
1037
 
  return ret;
1038
 
}