vorbisenc.c 36.5 KB
Newer Older
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1
/* GStreamer
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

20
21
/**
 * SECTION:element-vorbisenc
Wim Taymans's avatar
Wim Taymans committed
22
 * @short_description: an encoder that encodes audio to Vorbis
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 * @see_also: vorbisdec, oggmux
 *
 * <refsect2>
 * <para>
 * This element encodes raw float audio into a Vorbis stream.
 * <ulink url="http://www.vorbis.com/">Vorbis</ulink> is a royalty-free
 * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
 * Foundation</ulink>.
 * </para>
 * <title>Example pipelines</title>
 * <para>
 * Encode a test sine signal to Ogg/Vorbis.  Note that the resulting file
 * will be really small because a sine signal compresses very well.
 * </para>
 * <programlisting>
38
 * gst-launch -v audiotestsrc wave=sine num-buffers=100 ! audioconvert ! vorbisenc ! oggmux ! filesink location=sine.ogg
39
40
41
42
43
44
45
 * </programlisting>
 * <para>
 * Record from a sound card using ALSA and encode to Ogg/Vorbis.
 * </para>
 * <programlisting>
 * gst-launch -v alsasrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg
 * </programlisting>
Wim Taymans's avatar
Wim Taymans committed
46
 * </refsect2>
47
 *
Wim Taymans's avatar
Wim Taymans committed
48
 * Last reviewed on 2006-03-01 (0.10.4)
49
50
 */

51
52
53
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
54
55
#include <stdlib.h>
#include <string.h>
David I. Lehn's avatar
David I. Lehn committed
56
#include <time.h>
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
57
58
#include <vorbis/vorbisenc.h>

59
#include <gst/gsttagsetter.h>
60
#include <gst/tag/tag.h>
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
61
62
#include "vorbisenc.h"

63
64
65
GST_DEBUG_CATEGORY_EXTERN (vorbisenc_debug);
#define GST_CAT_DEFAULT vorbisenc_debug

Iain Holmes's avatar
Iain Holmes committed
66
static GstPadTemplate *gst_vorbisenc_src_template, *gst_vorbisenc_sink_template;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
67
68
69

/* elementfactory information */
GstElementDetails vorbisenc_details = {
70
  "Vorbis encoder",
71
  "Codec/Encoder/Audio",
72
  "Encodes audio in Vorbis format",
73
  "Monty <monty@xiph.org>, " "Wim Taymans <wim@fluendo.com>",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
74
75
};

76
/* GstVorbisEnc signals and args */
Wim Taymans's avatar
Wim Taymans committed
77
78
enum
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
79
80
81
82
  /* FILL ME */
  LAST_SIGNAL
};

Wim Taymans's avatar
Wim Taymans committed
83
84
enum
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
85
  ARG_0,
86
  ARG_MAX_BITRATE,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
87
  ARG_BITRATE,
88
89
90
  ARG_MIN_BITRATE,
  ARG_QUALITY,
  ARG_MANAGED,
91
  ARG_LAST_MESSAGE
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
92
93
};

94
static GstFlowReturn gst_vorbisenc_output_buffers (GstVorbisEnc * vorbisenc);
95

96
97
/* this function takes into account the granulepos_offset and the subgranule
 * time offset */
98
static GstClockTime
99
100
granulepos_to_timestamp_offset (GstVorbisEnc * vorbisenc,
    ogg_int64_t granulepos)
101
102
{
  if (granulepos >= 0)
103
104
105
106
    return gst_util_uint64_scale ((guint64) granulepos
        + vorbisenc->granulepos_offset, GST_SECOND, vorbisenc->frequency)
        + vorbisenc->subgranule_offset;
  return GST_CLOCK_TIME_NONE;
107
108
}

109
110
111
112
113
114
115
116
117
118
/* this function does a straight granulepos -> timestamp conversion */
static GstClockTime
granulepos_to_timestamp (GstVorbisEnc * vorbisenc, ogg_int64_t granulepos)
{
  if (granulepos >= 0)
    return gst_util_uint64_scale ((guint64) granulepos,
        GST_SECOND, vorbisenc->frequency);
  return GST_CLOCK_TIME_NONE;
}

Wim Taymans's avatar
Wim Taymans committed
119
#if 0
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
120
121
static const GstFormat *
gst_vorbisenc_get_formats (GstPad * pad)
122
123
124
125
126
127
128
129
{
  static const GstFormat src_formats[] = {
    GST_FORMAT_BYTES,
    GST_FORMAT_TIME,
    0
  };
  static const GstFormat sink_formats[] = {
    GST_FORMAT_BYTES,
Wim Taymans's avatar
Wim Taymans committed
130
    GST_FORMAT_DEFAULT,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
131
    GST_FORMAT_TIME,
132
133
    0
  };
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
134

135
  return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
136
}
Wim Taymans's avatar
Wim Taymans committed
137
#endif
138

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
139
140
141
142
143
144
#define MAX_BITRATE_DEFAULT     -1
#define BITRATE_DEFAULT         -1
#define MIN_BITRATE_DEFAULT     -1
#define QUALITY_DEFAULT         0.3
#define LOWEST_BITRATE          6000    /* lowest allowed for a 8 kHz stream */
#define HIGHEST_BITRATE         250001  /* highest allowed for a 44 kHz stream */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
145

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
146
static void gst_vorbisenc_base_init (gpointer g_class);
147
148
static void gst_vorbisenc_class_init (GstVorbisEncClass * klass);
static void gst_vorbisenc_init (GstVorbisEnc * vorbisenc);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
149

150
151
static gboolean gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer);
152
static gboolean gst_vorbisenc_setup (GstVorbisEnc * vorbisenc);
153

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
154
155
156
157
static void gst_vorbisenc_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
static void gst_vorbisenc_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
158
159
static GstStateChangeReturn gst_vorbisenc_change_state (GstElement * element,
    GstStateChange transition);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
160
161

static GstElementClass *parent_class = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
162

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
163
164
165
166
167
168
169
170
171
/*static guint gst_vorbisenc_signals[LAST_SIGNAL] = { 0 }; */

GType
vorbisenc_get_type (void)
{
  static GType vorbisenc_type = 0;

  if (!vorbisenc_type) {
    static const GTypeInfo vorbisenc_info = {
172
      sizeof (GstVorbisEncClass),
Iain Holmes's avatar
Iain Holmes committed
173
      gst_vorbisenc_base_init,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
174
      NULL,
Wim Taymans's avatar
Wim Taymans committed
175
      (GClassInitFunc) gst_vorbisenc_class_init,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
176
177
      NULL,
      NULL,
178
      sizeof (GstVorbisEnc),
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
179
      0,
Wim Taymans's avatar
Wim Taymans committed
180
      (GInstanceInitFunc) gst_vorbisenc_init,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
181
    };
182
183
184
185
186
    static const GInterfaceInfo tag_setter_info = {
      NULL,
      NULL,
      NULL
    };
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
187
188

    vorbisenc_type =
189
190
        g_type_register_static (GST_TYPE_ELEMENT, "GstVorbisEnc",
        &vorbisenc_info, 0);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
191
192

    g_type_add_interface_static (vorbisenc_type, GST_TYPE_TAG_SETTER,
193
        &tag_setter_info);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
194
195
196
197
  }
  return vorbisenc_type;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
198
static GstCaps *
Iain Holmes's avatar
Iain Holmes committed
199
200
vorbis_caps_factory (void)
{
201
  return gst_caps_new_simple ("audio/x-vorbis", NULL);
Iain Holmes's avatar
Iain Holmes committed
202
203
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
204
static GstCaps *
Iain Holmes's avatar
Iain Holmes committed
205
206
raw_caps_factory (void)
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
207
208
  /* lowest sample rate is in vorbis/lib/modes/setup_8.h, 8000 Hz
   * highest sample rate is in vorbis/lib/modes/setup_44.h, 50000 Hz */
Iain Holmes's avatar
Iain Holmes committed
209
  return
210
      gst_caps_new_simple ("audio/x-raw-float",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
211
      "rate", GST_TYPE_INT_RANGE, 8000, 50000,
212
      "channels", GST_TYPE_INT_RANGE, 1, 2,
Wim Taymans's avatar
Wim Taymans committed
213
      "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, NULL);
Iain Holmes's avatar
Iain Holmes committed
214
215
216
217
218
219
220
221
222
223
224
}

static void
gst_vorbisenc_base_init (gpointer g_class)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
  GstCaps *raw_caps, *vorbis_caps;

  raw_caps = raw_caps_factory ();
  vorbis_caps = vorbis_caps_factory ();

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
225
226
227
228
229
230
231
232
  gst_vorbisenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
      GST_PAD_ALWAYS, raw_caps);
  gst_vorbisenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
      GST_PAD_ALWAYS, vorbis_caps);
  gst_element_class_add_pad_template (element_class,
      gst_vorbisenc_sink_template);
  gst_element_class_add_pad_template (element_class,
      gst_vorbisenc_src_template);
Iain Holmes's avatar
Iain Holmes committed
233
234
235
  gst_element_class_set_details (element_class, &vorbisenc_details);
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
236
static void
237
gst_vorbisenc_class_init (GstVorbisEncClass * klass)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
238
239
240
241
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

Wim Taymans's avatar
Wim Taymans committed
242
243
  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
244

245
246
247
  gobject_class->set_property = gst_vorbisenc_set_property;
  gobject_class->get_property = gst_vorbisenc_get_property;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
248
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
249
      g_param_spec_int ("max-bitrate", "Maximum Bitrate",
250
251
252
          "Specify a maximum bitrate (in bps). Useful for streaming "
          "applications. (-1 == disabled)",
          -1, HIGHEST_BITRATE, MAX_BITRATE_DEFAULT, G_PARAM_READWRITE));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
253
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
254
      g_param_spec_int ("bitrate", "Target Bitrate",
255
256
257
258
          "Attempt to encode at a bitrate averaging this (in bps). "
          "This uses the bitrate management engine, and is not recommended for most users. "
          "Quality is a better alternative. (-1 == disabled)",
          -1, HIGHEST_BITRATE, BITRATE_DEFAULT, G_PARAM_READWRITE));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
259
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MIN_BITRATE,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
260
      g_param_spec_int ("min_bitrate", "Minimum Bitrate",
261
262
263
          "Specify a minimum bitrate (in bps). Useful for encoding for a "
          "fixed-size channel. (-1 == disabled)",
          -1, HIGHEST_BITRATE, MIN_BITRATE_DEFAULT, G_PARAM_READWRITE));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
264
265
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
      g_param_spec_float ("quality", "Quality",
266
          "Specify quality instead of specifying a particular bitrate.",
267
          -0.1, 1.0, QUALITY_DEFAULT, G_PARAM_READWRITE));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
268
269
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MANAGED,
      g_param_spec_boolean ("managed", "Managed",
270
          "Enable bitrate management engine", FALSE, G_PARAM_READWRITE));
271
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
272
      g_param_spec_string ("last-message", "last-message",
273
          "The last status message", NULL, G_PARAM_READABLE));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
274

Wim Taymans's avatar
Wim Taymans committed
275
  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
276

Wim Taymans's avatar
Wim Taymans committed
277
  gstelement_class->change_state = gst_vorbisenc_change_state;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
278
279
}

280
281
static gboolean
gst_vorbisenc_sink_setcaps (GstPad * pad, GstCaps * caps)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
282
{
283
  GstVorbisEnc *vorbisenc;
David Schleef's avatar
David Schleef committed
284
  GstStructure *structure;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
285

286
  vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
287
  vorbisenc->setup = FALSE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
288

David Schleef's avatar
David Schleef committed
289
  structure = gst_caps_get_structure (caps, 0);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
290
291
  gst_structure_get_int (structure, "channels", &vorbisenc->channels);
  gst_structure_get_int (structure, "rate", &vorbisenc->frequency);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
292
293

  gst_vorbisenc_setup (vorbisenc);
294
295

  if (vorbisenc->setup)
296
    return TRUE;
297

298
  return FALSE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
299
300
}

301
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
302
303
gst_vorbisenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value)
304
305
{
  gboolean res = TRUE;
306
  GstVorbisEnc *vorbisenc;
307
308
309
310
  gint64 avg;

  vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
311
  if (vorbisenc->samples_in == 0 ||
312
313
      vorbisenc->bytes_out == 0 || vorbisenc->frequency == 0) {
    gst_object_unref (vorbisenc);
314
    return FALSE;
315
  }
316

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
317
  avg = (vorbisenc->bytes_out * vorbisenc->frequency) / (vorbisenc->samples_in);
318
319
320
321

  switch (src_format) {
    case GST_FORMAT_BYTES:
      switch (*dest_format) {
322
        case GST_FORMAT_TIME:
323
          *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND, avg);
324
325
326
          break;
        default:
          res = FALSE;
327
328
329
330
      }
      break;
    case GST_FORMAT_TIME:
      switch (*dest_format) {
331
        case GST_FORMAT_BYTES:
332
          *dest_value = gst_util_uint64_scale_int (src_value, avg, GST_SECOND);
333
334
335
          break;
        default:
          res = FALSE;
336
337
338
339
340
      }
      break;
    default:
      res = FALSE;
  }
341
  gst_object_unref (vorbisenc);
342
343
344
345
  return res;
}

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
346
347
gst_vorbisenc_convert_sink (GstPad * pad, GstFormat src_format,
    gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
348
349
350
351
{
  gboolean res = TRUE;
  guint scale = 1;
  gint bytes_per_sample;
352
  GstVorbisEnc *vorbisenc;
353
354

  vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
355

356
  bytes_per_sample = vorbisenc->channels * 2;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
357

358
359
360
  switch (src_format) {
    case GST_FORMAT_BYTES:
      switch (*dest_format) {
361
362
363
364
365
366
367
368
369
370
371
        case GST_FORMAT_DEFAULT:
          if (bytes_per_sample == 0)
            return FALSE;
          *dest_value = src_value / bytes_per_sample;
          break;
        case GST_FORMAT_TIME:
        {
          gint byterate = bytes_per_sample * vorbisenc->frequency;

          if (byterate == 0)
            return FALSE;
372
373
          *dest_value =
              gst_util_uint64_scale_int (src_value, GST_SECOND, byterate);
374
375
376
377
          break;
        }
        default:
          res = FALSE;
378
379
      }
      break;
Wim Taymans's avatar
Wim Taymans committed
380
    case GST_FORMAT_DEFAULT:
381
      switch (*dest_format) {
382
383
384
385
386
387
        case GST_FORMAT_BYTES:
          *dest_value = src_value * bytes_per_sample;
          break;
        case GST_FORMAT_TIME:
          if (vorbisenc->frequency == 0)
            return FALSE;
388
389
390
          *dest_value =
              gst_util_uint64_scale_int (src_value, GST_SECOND,
              vorbisenc->frequency);
391
392
393
          break;
        default:
          res = FALSE;
394
395
396
397
      }
      break;
    case GST_FORMAT_TIME:
      switch (*dest_format) {
398
399
400
401
        case GST_FORMAT_BYTES:
          scale = bytes_per_sample;
          /* fallthrough */
        case GST_FORMAT_DEFAULT:
402
403
404
          *dest_value =
              gst_util_uint64_scale_int (src_value,
              scale * vorbisenc->frequency, GST_SECOND);
405
406
407
          break;
        default:
          res = FALSE;
408
409
410
411
412
      }
      break;
    default:
      res = FALSE;
  }
413
  gst_object_unref (vorbisenc);
414
415
416
  return res;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
417
418
static const GstQueryType *
gst_vorbisenc_get_query_types (GstPad * pad)
419
{
Wim Taymans's avatar
Wim Taymans committed
420
421
  static const GstQueryType gst_vorbisenc_src_query_types[] = {
    GST_QUERY_POSITION,
422
423
    GST_QUERY_DURATION,
    GST_QUERY_CONVERT,
424
425
    0
  };
426

427
428
429
430
  return gst_vorbisenc_src_query_types;
}

static gboolean
Wim Taymans's avatar
Wim Taymans committed
431
gst_vorbisenc_src_query (GstPad * pad, GstQuery * query)
432
433
{
  gboolean res = TRUE;
434
  GstVorbisEnc *vorbisenc;
435
  GstPad *peerpad;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
436

437
438
  vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
  peerpad = gst_pad_get_peer (GST_PAD (vorbisenc->sinkpad));
439

Wim Taymans's avatar
Wim Taymans committed
440
441
  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_POSITION:
442
    {
443
444
      GstFormat fmt, req_fmt;
      gint64 pos, val;
445

446
447
448
449
450
      gst_query_parse_position (query, &req_fmt, NULL);
      if ((res = gst_pad_query_position (peerpad, &req_fmt, &val))) {
        gst_query_set_position (query, req_fmt, val);
        break;
      }
451

452
453
454
      fmt = GST_FORMAT_TIME;
      if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
        break;
455

456
457
458
459
460
461
462
463
464
      if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val))) {
        gst_query_set_position (query, req_fmt, val);
      }
      break;
    }
    case GST_QUERY_DURATION:
    {
      GstFormat fmt, req_fmt;
      gint64 dur, val;
465

466
467
468
469
470
      gst_query_parse_duration (query, &req_fmt, NULL);
      if ((res = gst_pad_query_duration (peerpad, &req_fmt, &val))) {
        gst_query_set_duration (query, req_fmt, val);
        break;
      }
471

472
473
474
      fmt = GST_FORMAT_TIME;
      if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
        break;
475

476
477
      if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
        gst_query_set_duration (query, req_fmt, val);
478
479
480
      }
      break;
    }
Wim Taymans's avatar
Wim Taymans committed
481
482
483
484
485
486
487
488
489
490
491
492
493
494
    case GST_QUERY_CONVERT:
    {
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;

      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
      if (!(res =
              gst_vorbisenc_convert_src (pad, src_fmt, src_val, &dest_fmt,
                  &dest_val)))
        goto error;
      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
      break;
    }
    default:
495
      res = gst_pad_query_default (pad, query);
Wim Taymans's avatar
Wim Taymans committed
496
497
498
499
      break;
  }

error:
500
501
  gst_object_unref (peerpad);
  gst_object_unref (vorbisenc);
Wim Taymans's avatar
Wim Taymans committed
502
503
504
505
506
507
508
  return res;
}

static gboolean
gst_vorbisenc_sink_query (GstPad * pad, GstQuery * query)
{
  gboolean res = TRUE;
509
  GstVorbisEnc *vorbisenc;
Wim Taymans's avatar
Wim Taymans committed
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524

  vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_CONVERT:
    {
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;

      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
      if (!(res =
              gst_vorbisenc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
                  &dest_val)))
        goto error;
      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
525
      break;
Wim Taymans's avatar
Wim Taymans committed
526
    }
527
    default:
528
      res = gst_pad_query_default (pad, query);
529
530
      break;
  }
Wim Taymans's avatar
Wim Taymans committed
531
532

error:
533
534
535
  return res;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
536
static void
537
gst_vorbisenc_init (GstVorbisEnc * vorbisenc)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
538
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
539
540
  vorbisenc->sinkpad =
      gst_pad_new_from_template (gst_vorbisenc_sink_template, "sink");
Wim Taymans's avatar
Wim Taymans committed
541
  gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->sinkpad);
542
  gst_pad_set_event_function (vorbisenc->sinkpad, gst_vorbisenc_sink_event);
Wim Taymans's avatar
Wim Taymans committed
543
  gst_pad_set_chain_function (vorbisenc->sinkpad, gst_vorbisenc_chain);
544
  gst_pad_set_setcaps_function (vorbisenc->sinkpad, gst_vorbisenc_sink_setcaps);
Wim Taymans's avatar
Wim Taymans committed
545
546
  gst_pad_set_query_function (vorbisenc->sinkpad,
      GST_DEBUG_FUNCPTR (gst_vorbisenc_sink_query));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
547
548
549
550
551
552
553

  vorbisenc->srcpad =
      gst_pad_new_from_template (gst_vorbisenc_src_template, "src");
  gst_pad_set_query_function (vorbisenc->srcpad,
      GST_DEBUG_FUNCPTR (gst_vorbisenc_src_query));
  gst_pad_set_query_type_function (vorbisenc->srcpad,
      GST_DEBUG_FUNCPTR (gst_vorbisenc_get_query_types));
Wim Taymans's avatar
Wim Taymans committed
554
  gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->srcpad);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
555

Wim Taymans's avatar
Wim Taymans committed
556
557
  vorbisenc->channels = -1;
  vorbisenc->frequency = -1;
558
559
560
561
562
563
564
565

  vorbisenc->managed = FALSE;
  vorbisenc->max_bitrate = MAX_BITRATE_DEFAULT;
  vorbisenc->bitrate = BITRATE_DEFAULT;
  vorbisenc->min_bitrate = MIN_BITRATE_DEFAULT;
  vorbisenc->quality = QUALITY_DEFAULT;
  vorbisenc->quality_set = FALSE;
  vorbisenc->last_message = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
566
567
}

568
569

static gchar *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
570
571
gst_vorbisenc_get_tag_value (const GstTagList * list, const gchar * tag,
    int index)
572
{
573
  GType tag_type;
574
575
  gchar *vorbisvalue = NULL;

576
  if (tag == NULL)
577
    return NULL;
578
579

  tag_type = gst_tag_get_type (tag);
580
581

  /* get tag name right */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
582
583
584
  if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
      || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
      || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
585
586
      || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
    guint track_no;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
587

588
    if (!gst_tag_list_get_uint_index (list, tag, index, &track_no))
589
590
      g_return_val_if_reached (NULL);

591
    vorbisvalue = g_strdup_printf ("%u", track_no);
592
  } else if (tag_type == GST_TYPE_DATE) {
593
    GDate *date;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
594

595
596
597
    if (!gst_tag_list_get_date_index (list, tag, index, &date))
      g_return_val_if_reached (NULL);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
598
    vorbisvalue =
599
600
        g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
        (gint) g_date_get_month (date), (gint) g_date_get_day (date));
601
    g_date_free (date);
602
  } else if (tag_type == G_TYPE_STRING) {
603
    if (!gst_tag_list_get_string_index (list, tag, index, &vorbisvalue))
604
      g_return_val_if_reached (NULL);
605
606
607
608
609
  }

  return vorbisvalue;
}

610
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
611
612
gst_vorbisenc_metadata_set1 (const GstTagList * list, const gchar * tag,
    gpointer vorbisenc)
613
{
614
  const gchar *vorbistag = NULL;
615
  gchar *vorbisvalue = NULL;
616
  guint i, count;
617
  GstVorbisEnc *enc = GST_VORBISENC (vorbisenc);
618

619
620
621
622
623
  vorbistag = gst_tag_to_vorbis_tag (tag);
  if (vorbistag == NULL) {
    return;
  }

624
625
  count = gst_tag_list_get_tag_size (list, tag);
  for (i = 0; i < count; i++) {
626
    vorbisvalue = gst_vorbisenc_get_tag_value (list, tag, i);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
627

628
    if (vorbisvalue != NULL) {
629
630
631
632
      gchar *tmptag = g_strdup (vorbistag);

      vorbis_comment_add_tag (&enc->vc, tmptag, vorbisvalue);
      g_free (tmptag);
633
      g_free (vorbisvalue);
634
635
636
    }
  }
}
637

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
638
static void
639
gst_vorbisenc_set_metadata (GstVorbisEnc * vorbisenc)
640
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
641
  GstTagList *copy;
642
  const GstTagList *user_tags;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
643

644
  user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (vorbisenc));
645
  if (!(vorbisenc->tags || user_tags))
646
647
    return;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
648
649
  copy =
      gst_tag_list_merge (user_tags, vorbisenc->tags,
650
      gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (vorbisenc)));
651
  vorbis_comment_init (&vorbisenc->vc);
652
653
  gst_tag_list_foreach (copy, gst_vorbisenc_metadata_set1, vorbisenc);
  gst_tag_list_free (copy);
654
655
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
656
static gchar *
657
get_constraints_string (GstVorbisEnc * vorbisenc)
658
659
660
661
662
663
{
  gint min = vorbisenc->min_bitrate;
  gint max = vorbisenc->max_bitrate;
  gchar *result;

  if (min > 0 && max > 0)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
664
    result = g_strdup_printf ("(min %d bps, max %d bps)", min, max);
665
666
667
668
669
670
671
672
673
674
  else if (min > 0)
    result = g_strdup_printf ("(min %d bps, no max)", min);
  else if (max > 0)
    result = g_strdup_printf ("(no min, max %d bps)", max);
  else
    result = g_strdup_printf ("(no min or max)");

  return result;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
675
static void
676
update_start_message (GstVorbisEnc * vorbisenc)
677
678
679
680
681
682
683
684
{
  gchar *constraints;

  g_free (vorbisenc->last_message);

  if (vorbisenc->bitrate > 0) {
    if (vorbisenc->managed) {
      constraints = get_constraints_string (vorbisenc);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
685
      vorbisenc->last_message =
686
687
          g_strdup_printf ("encoding at average bitrate %d bps %s",
          vorbisenc->bitrate, constraints);
688
      g_free (constraints);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
689
690
    } else {
      vorbisenc->last_message =
691
692
693
          g_strdup_printf
          ("encoding at approximate bitrate %d bps (VBR encoding enabled)",
          vorbisenc->bitrate);
694
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
695
  } else {
696
697
    if (vorbisenc->quality_set) {
      if (vorbisenc->managed) {
698
699
700
701
702
703
        constraints = get_constraints_string (vorbisenc);
        vorbisenc->last_message =
            g_strdup_printf
            ("encoding at quality level %2.2f using constrained VBR %s",
            vorbisenc->quality, constraints);
        g_free (constraints);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
704
      } else {
705
706
707
        vorbisenc->last_message =
            g_strdup_printf ("encoding at quality level %2.2f",
            vorbisenc->quality);
708
      }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
709
    } else {
710
      constraints = get_constraints_string (vorbisenc);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
711
      vorbisenc->last_message =
712
          g_strdup_printf ("encoding using bitrate management %s", constraints);
713
714
715
716
717
718
719
720
      g_free (constraints);
    }
  }

  g_object_notify (G_OBJECT (vorbisenc), "last_message");
}

static gboolean
721
gst_vorbisenc_setup (GstVorbisEnc * vorbisenc)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
722
{
723
724
  vorbisenc->setup = FALSE;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
725
726
  if (vorbisenc->bitrate < 0 && vorbisenc->min_bitrate < 0
      && vorbisenc->max_bitrate < 0) {
727
728
729
730
    vorbisenc->quality_set = TRUE;
  }

  update_start_message (vorbisenc);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
731

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
732
733
  /* choose an encoding mode */
  /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */
Wim Taymans's avatar
Wim Taymans committed
734
  vorbis_info_init (&vorbisenc->vi);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
735

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
736
737
  if (vorbisenc->quality_set) {
    if (vorbis_encode_setup_vbr (&vorbisenc->vi,
738
739
740
741
            vorbisenc->channels, vorbisenc->frequency,
            vorbisenc->quality) != 0) {
      GST_ERROR_OBJECT (vorbisenc,
          "vorbisenc: initialisation failed: invalid parameters for quality");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
742
743
      vorbis_info_clear (&vorbisenc->vi);
      return FALSE;
744
745
746
    }

    /* do we have optional hard quality restrictions? */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
747
    if (vorbisenc->max_bitrate > 0 || vorbisenc->min_bitrate > 0) {
748
      struct ovectl_ratemanage_arg ai;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
749

750
751
      vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_GET, &ai);

752
753
      ai.bitrate_hard_min = vorbisenc->min_bitrate;
      ai.bitrate_hard_max = vorbisenc->max_bitrate;
754
755
756
757
      ai.management_active = 1;

      vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, &ai);
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
758
  } else {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
759
760
761
762
763
    long min_bitrate, max_bitrate;

    min_bitrate = vorbisenc->min_bitrate > 0 ? vorbisenc->min_bitrate : -1;
    max_bitrate = vorbisenc->max_bitrate > 0 ? vorbisenc->max_bitrate : -1;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
764
    if (vorbis_encode_setup_managed (&vorbisenc->vi,
765
766
            vorbisenc->channels,
            vorbisenc->frequency,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
767
            max_bitrate, vorbisenc->bitrate, min_bitrate) != 0) {
768
      GST_ERROR_OBJECT (vorbisenc,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
769
770
771
772
          "vorbis_encode_setup_managed "
          "(c %d, rate %d, max br %ld, br %ld, min br %ld) failed",
          vorbisenc->channels, vorbisenc->frequency, max_bitrate,
          vorbisenc->bitrate, min_bitrate);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
773
      vorbis_info_clear (&vorbisenc->vi);
774
775
776
777
      return FALSE;
    }
  }

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
778
779
780
  if (vorbisenc->managed && vorbisenc->bitrate < 0) {
    vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_AVG, NULL);
  } else if (!vorbisenc->managed) {
781
    /* Turn off management entirely (if it was turned on). */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
782
    vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, NULL);
783
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
784
  vorbis_encode_setup_init (&vorbisenc->vi);
785

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
786
  /* set up the analysis state and auxiliary encoding storage */
Wim Taymans's avatar
Wim Taymans committed
787
788
  vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi);
  vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
789

790
  vorbisenc->next_ts = 0;
791

Wim Taymans's avatar
Wim Taymans committed
792
  vorbisenc->setup = TRUE;
793
794

  return TRUE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
795
796
}

797
static GstFlowReturn
798
799
gst_vorbisenc_clear (GstVorbisEnc * vorbisenc)
{
800
801
  GstFlowReturn ret = GST_FLOW_OK;

802
803
  if (vorbisenc->setup) {
    vorbis_analysis_wrote (&vorbisenc->vd, 0);
804
    ret = gst_vorbisenc_output_buffers (vorbisenc);
805
806
807
808
809
810
811
812
813
814

    vorbisenc->setup = FALSE;
  }

  /* clean up and exit.  vorbis_info_clear() must be called last */
  vorbis_block_clear (&vorbisenc->vb);
  vorbis_dsp_clear (&vorbisenc->vd);
  vorbis_info_clear (&vorbisenc->vi);

  vorbisenc->header_sent = FALSE;
815
816

  return ret;
817
818
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
819
820
/* prepare a buffer for transmission by passing data through libvorbis */
static GstBuffer *
821
gst_vorbisenc_buffer_from_packet (GstVorbisEnc * vorbisenc, ogg_packet * packet)
Wim Taymans's avatar
Wim Taymans committed
822
823
824
{
  GstBuffer *outbuf;

825
826
  outbuf = gst_buffer_new_and_alloc (packet->bytes);
  memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
827
828
  /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
   * time representation */
829
830
  GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos +
      vorbisenc->granulepos_offset;
831
832
  GST_BUFFER_OFFSET (outbuf) = granulepos_to_timestamp (vorbisenc,
      GST_BUFFER_OFFSET_END (outbuf));
833
834
  GST_BUFFER_TIMESTAMP (outbuf) = vorbisenc->next_ts;

835
836
837
838
  /* update the next timestamp, taking granulepos_offset and subgranule offset
   * into account */
  vorbisenc->next_ts =
      granulepos_to_timestamp_offset (vorbisenc, packet->granulepos);
839
  GST_BUFFER_DURATION (outbuf) =
840
      vorbisenc->next_ts - GST_BUFFER_TIMESTAMP (outbuf);
Wim Taymans's avatar
Wim Taymans committed
841

842
843
  GST_LOG_OBJECT (vorbisenc, "encoded buffer of %d bytes",
      GST_BUFFER_SIZE (outbuf));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
844
845
  return outbuf;
}
Wim Taymans's avatar
Wim Taymans committed
846

847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
/* the same as above, but different logic for setting timestamp and granulepos
 * */
static GstBuffer *
gst_vorbisenc_buffer_from_header_packet (GstVorbisEnc * vorbisenc,
    ogg_packet * packet)
{
  GstBuffer *outbuf;

  outbuf = gst_buffer_new_and_alloc (packet->bytes);
  memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
  GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out;
  GST_BUFFER_OFFSET_END (outbuf) = 0;
  GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
  GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;

  GST_DEBUG ("created header packet buffer, %d bytes",
      GST_BUFFER_SIZE (outbuf));
  return outbuf;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
867
/* push out the buffer and do internal bookkeeping */
868
static GstFlowReturn
869
gst_vorbisenc_push_buffer (GstVorbisEnc * vorbisenc, GstBuffer * buffer)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
870
871
{
  vorbisenc->bytes_out += GST_BUFFER_SIZE (buffer);
Wim Taymans's avatar
Wim Taymans committed
872

873
  return gst_pad_push (vorbisenc->srcpad, buffer);
Wim Taymans's avatar
Wim Taymans committed
874
875
}

876
static GstFlowReturn
877
gst_vorbisenc_push_packet (GstVorbisEnc * vorbisenc, ogg_packet * packet)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
878
879
880
881
{
  GstBuffer *outbuf;

  outbuf = gst_vorbisenc_buffer_from_packet (vorbisenc, packet);
882
  return gst_vorbisenc_push_buffer (vorbisenc, outbuf);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
883
}
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
884

885
static GstCaps *
886
887
888
gst_vorbisenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
    GstBuffer * buf2, GstBuffer * buf3)
{
889
  GstStructure *structure;
890
  GValue array = { 0 };
891
892
  GValue value = { 0 };

893
894
895
  caps = gst_caps_make_writable (caps);
  structure = gst_caps_get_structure (caps, 0);

896
  /* mark buffers */
897
898
899
  GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
  GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
  GST_BUFFER_FLAG_SET (buf3, GST_BUFFER_FLAG_IN_CAPS);
900
901

  /* put buffers in a fixed list */
902
  g_value_init (&array, GST_TYPE_ARRAY);
903
  g_value_init (&value, GST_TYPE_BUFFER);
904
  gst_value_set_buffer (&value, buf1);
905
  gst_value_array_append_value (&array, &value);
906
907
  g_value_unset (&value);
  g_value_init (&value, GST_TYPE_BUFFER);
908
  gst_value_set_buffer (&value, buf2);
909
  gst_value_array_append_value (&array, &value);
910
911
  g_value_unset (&value);
  g_value_init (&value, GST_TYPE_BUFFER);
912
  gst_value_set_buffer (&value, buf3);
913
914
  gst_value_array_append_value (&array, &value);
  gst_structure_set_value (structure, "streamheader", &array);
915
  g_value_unset (&value);
916
  g_value_unset (&array);
917
918

  return caps;
919
}
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
920

921
922
static gboolean
gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
923
{
924
  gboolean res = TRUE;
925
  GstVorbisEnc *vorbisenc;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
926

927
928
929
930
  vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_EOS:
931
932
933
      /* Tell the library we're at end of stream so that it can handle
       * the last frame and mark end of stream in the output properly */
      GST_DEBUG_OBJECT (vorbisenc, "EOS, clearing state and sending event on");
934
      gst_vorbisenc_clear (vorbisenc);
935

936
      res = gst_pad_push_event (vorbisenc->srcpad, event);
937
938
939
      break;
    case GST_EVENT_TAG:
      if (vorbisenc->tags) {
940
941
942
943
        GstTagList *list;

        gst_event_parse_tag (event, &list);
        gst_tag_list_insert (vorbisenc->tags, list,
944
            gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (vorbisenc)));
945
946
947
      } else {
        g_assert_not_reached ();
      }
948
      res = gst_pad_push_event (vorbisenc->srcpad, event);
949
950
      break;
    default:
951
      res = gst_pad_push_event (vorbisenc->srcpad, event);
952
953
954
955
      break;
  }
  return res;
}
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
956

957
958
959
static GstFlowReturn
gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer)
{
960
  GstVorbisEnc *vorbisenc;
961
  GstFlowReturn ret = GST_FLOW_OK;
962
963
964
965
  gfloat *data;
  gulong size;
  gulong i, j;
  float **vorbis_buffer;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
966

967
968
  vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));

969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990