gst_nokia_speech/gstframedaudioenc.c
author hgs
Wed, 24 Mar 2010 18:04:17 -0500
changeset 16 8e837d1bf446
permissions -rw-r--r--
201009
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
16
hgs
parents:
diff changeset
     1
/* GStreamer Framed Audio Encoder
hgs
parents:
diff changeset
     2
 * Copyright 2009 Collabora Ltd,
hgs
parents:
diff changeset
     3
 * Copyright 2009 Nokia Corporation
hgs
parents:
diff changeset
     4
 *  @author: Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>.
hgs
parents:
diff changeset
     5
 *
hgs
parents:
diff changeset
     6
 * This library is free software; you can redistribute it and/or
hgs
parents:
diff changeset
     7
 * modify it under the terms of the GNU Library General Public
hgs
parents:
diff changeset
     8
 * License as published by the Free Software Foundation; either
hgs
parents:
diff changeset
     9
 * version 2 of the License, or (at your option) any later version.
hgs
parents:
diff changeset
    10
 *
hgs
parents:
diff changeset
    11
 * This library is distributed in the hope that it will be useful,
hgs
parents:
diff changeset
    12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
hgs
parents:
diff changeset
    13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
hgs
parents:
diff changeset
    14
 * Library General Public License for more details.
hgs
parents:
diff changeset
    15
 *
hgs
parents:
diff changeset
    16
 * You should have received a copy of the GNU Library General Public
hgs
parents:
diff changeset
    17
 * License along with this library; if not, write to the
hgs
parents:
diff changeset
    18
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
hgs
parents:
diff changeset
    19
 * Boston, MA 02111-1307, USA.
hgs
parents:
diff changeset
    20
 */
hgs
parents:
diff changeset
    21
hgs
parents:
diff changeset
    22
#ifdef HAVE_CONFIG_H
hgs
parents:
diff changeset
    23
#include "config.h"
hgs
parents:
diff changeset
    24
#endif
hgs
parents:
diff changeset
    25
#include <gst/gst.h>
hgs
parents:
diff changeset
    26
#include <gst/audio/audio.h>
hgs
parents:
diff changeset
    27
#include <string.h>
hgs
parents:
diff changeset
    28
hgs
parents:
diff changeset
    29
#include "gstframedaudioenc.h"
hgs
parents:
diff changeset
    30
hgs
parents:
diff changeset
    31
/* generic part */
hgs
parents:
diff changeset
    32
#ifndef RAW_FRAME_SIZE
hgs
parents:
diff changeset
    33
hgs
parents:
diff changeset
    34
/* this will reference caller's debug category;
hgs
parents:
diff changeset
    35
 * there is a copy of this per plugin lib (= debug category) */
hgs
parents:
diff changeset
    36
GST_DEBUG_CATEGORY_STATIC (framedaudioenc_debug);
hgs
parents:
diff changeset
    37
#define GST_CAT_DEFAULT framedaudioenc_debug
hgs
parents:
diff changeset
    38
hgs
parents:
diff changeset
    39
void
hgs
parents:
diff changeset
    40
gst_framed_audio_enc_reset (GstFramedAudioEnc * enc)
hgs
parents:
diff changeset
    41
{
hgs
parents:
diff changeset
    42
  gst_adapter_clear (enc->adapter);
hgs
parents:
diff changeset
    43
  enc->next_ts = GST_CLOCK_TIME_NONE;
hgs
parents:
diff changeset
    44
}
hgs
parents:
diff changeset
    45
hgs
parents:
diff changeset
    46
/* installs @enc as element private for @element's pad,
hgs
parents:
diff changeset
    47
 * and possibly some event and query handler.
hgs
parents:
diff changeset
    48
 * if these need overriding, chain up to them
hgs
parents:
diff changeset
    49
 * chain and setcaps still need to be set by @element */
hgs
parents:
diff changeset
    50
void
hgs
parents:
diff changeset
    51
gst_framed_audio_enc_init (GstFramedAudioEnc * enc, GstElement * element,
hgs
parents:
diff changeset
    52
    GstDebugCategory * cat)
hgs
parents:
diff changeset
    53
{
hgs
parents:
diff changeset
    54
  enc->element = element;
hgs
parents:
diff changeset
    55
#ifndef GST_DISABLE_GST_DEBUG
hgs
parents:
diff changeset
    56
  framedaudioenc_debug = cat;
hgs
parents:
diff changeset
    57
#endif
hgs
parents:
diff changeset
    58
hgs
parents:
diff changeset
    59
  enc->adapter = gst_adapter_new ();
hgs
parents:
diff changeset
    60
hgs
parents:
diff changeset
    61
  /* hook some */
hgs
parents:
diff changeset
    62
  enc->sinkpad = gst_element_get_pad (enc->element, "sink");
hgs
parents:
diff changeset
    63
  g_assert (enc->sinkpad);
hgs
parents:
diff changeset
    64
  gst_pad_set_element_private (enc->sinkpad, enc);
hgs
parents:
diff changeset
    65
hgs
parents:
diff changeset
    66
  /* watch downstream events */
hgs
parents:
diff changeset
    67
  gst_pad_set_event_function (enc->sinkpad,
hgs
parents:
diff changeset
    68
      GST_DEBUG_FUNCPTR (gst_framed_audio_enc_sink_event));
hgs
parents:
diff changeset
    69
hgs
parents:
diff changeset
    70
  gst_framed_audio_enc_reset (enc);
hgs
parents:
diff changeset
    71
}
hgs
parents:
diff changeset
    72
hgs
parents:
diff changeset
    73
void
hgs
parents:
diff changeset
    74
gst_framed_audio_enc_finalize (GstFramedAudioEnc * enc)
hgs
parents:
diff changeset
    75
{
hgs
parents:
diff changeset
    76
  gst_object_unref (enc->adapter);
hgs
parents:
diff changeset
    77
hgs
parents:
diff changeset
    78
  gst_pad_set_element_private (enc->sinkpad, NULL);
hgs
parents:
diff changeset
    79
  gst_object_unref (enc->sinkpad);
hgs
parents:
diff changeset
    80
}
hgs
parents:
diff changeset
    81
hgs
parents:
diff changeset
    82
GstPad *
hgs
parents:
diff changeset
    83
gst_framed_audio_enc_request_new_pad (GstFramedAudioEnc * enc,
hgs
parents:
diff changeset
    84
    GstPadTemplate * templ, const gchar * req_name, GstPad ** pad_p)
hgs
parents:
diff changeset
    85
{
hgs
parents:
diff changeset
    86
  GstElement *element;
hgs
parents:
diff changeset
    87
  GstPad *newpad;
hgs
parents:
diff changeset
    88
  GstElementClass *klass;
hgs
parents:
diff changeset
    89
  GstCaps *caps;
hgs
parents:
diff changeset
    90
hgs
parents:
diff changeset
    91
  g_return_val_if_fail (templ != NULL, NULL);
hgs
parents:
diff changeset
    92
hgs
parents:
diff changeset
    93
  element = enc->element;
hgs
parents:
diff changeset
    94
  klass = GST_ELEMENT_GET_CLASS (element);
hgs
parents:
diff changeset
    95
hgs
parents:
diff changeset
    96
  if (templ != gst_element_class_get_pad_template (klass, "cn"))
hgs
parents:
diff changeset
    97
    goto wrong_template;
hgs
parents:
diff changeset
    98
hgs
parents:
diff changeset
    99
  GST_DEBUG_OBJECT (enc->element, "adding cn pad");
hgs
parents:
diff changeset
   100
  newpad = gst_pad_new_from_template (templ, "cn");
hgs
parents:
diff changeset
   101
  /* set template caps */
hgs
parents:
diff changeset
   102
  caps = gst_caps_copy (gst_pad_get_pad_template_caps (newpad));
hgs
parents:
diff changeset
   103
  gst_pad_set_caps (newpad, caps);
hgs
parents:
diff changeset
   104
  gst_caps_unref (caps);
hgs
parents:
diff changeset
   105
  gst_pad_use_fixed_caps (newpad);
hgs
parents:
diff changeset
   106
  gst_pad_set_active (newpad, TRUE);
hgs
parents:
diff changeset
   107
  /* only 1 pad by name can be added */
hgs
parents:
diff changeset
   108
  if (gst_element_add_pad (element, newpad)) {
hgs
parents:
diff changeset
   109
    GST_OBJECT_LOCK (element);
hgs
parents:
diff changeset
   110
    gst_object_replace ((GstObject **) pad_p, GST_OBJECT_CAST (newpad));
hgs
parents:
diff changeset
   111
    GST_OBJECT_UNLOCK (element);
hgs
parents:
diff changeset
   112
    GST_DEBUG_OBJECT (enc->element, "cn pad added");
hgs
parents:
diff changeset
   113
  } else {
hgs
parents:
diff changeset
   114
    gst_object_unref (newpad);
hgs
parents:
diff changeset
   115
    goto already_requested;
hgs
parents:
diff changeset
   116
  }
hgs
parents:
diff changeset
   117
hgs
parents:
diff changeset
   118
  return newpad;
hgs
parents:
diff changeset
   119
hgs
parents:
diff changeset
   120
  /* ERRORS */
hgs
parents:
diff changeset
   121
wrong_template:
hgs
parents:
diff changeset
   122
  {
hgs
parents:
diff changeset
   123
    GST_ERROR_OBJECT (element, "not our template!");
hgs
parents:
diff changeset
   124
    return NULL;
hgs
parents:
diff changeset
   125
  }
hgs
parents:
diff changeset
   126
already_requested:
hgs
parents:
diff changeset
   127
  {
hgs
parents:
diff changeset
   128
    GST_ERROR_OBJECT (element, "only 1 instance of a pad can be requested");
hgs
parents:
diff changeset
   129
    return NULL;
hgs
parents:
diff changeset
   130
  }
hgs
parents:
diff changeset
   131
}
hgs
parents:
diff changeset
   132
hgs
parents:
diff changeset
   133
void
hgs
parents:
diff changeset
   134
gst_framed_audio_enc_release_pad (GstFramedAudioEnc * enc, GstPad * pad,
hgs
parents:
diff changeset
   135
    GstPad ** pad_p, void (disable_cn) (GstElement *))
hgs
parents:
diff changeset
   136
{
hgs
parents:
diff changeset
   137
  GstElement *element = enc->element;
hgs
parents:
diff changeset
   138
hgs
parents:
diff changeset
   139
  GST_DEBUG_OBJECT (enc->element, "releasing cn pad");
hgs
parents:
diff changeset
   140
hgs
parents:
diff changeset
   141
  GST_OBJECT_LOCK (element);
hgs
parents:
diff changeset
   142
  if (pad != *pad_p)
hgs
parents:
diff changeset
   143
    goto wrong_pad;
hgs
parents:
diff changeset
   144
  GST_OBJECT_UNLOCK (element);
hgs
parents:
diff changeset
   145
hgs
parents:
diff changeset
   146
  /* reconfigure encoder */
hgs
parents:
diff changeset
   147
  disable_cn (element);
hgs
parents:
diff changeset
   148
hgs
parents:
diff changeset
   149
  if (gst_element_remove_pad (element, pad)) {
hgs
parents:
diff changeset
   150
    GST_OBJECT_LOCK (element);
hgs
parents:
diff changeset
   151
    gst_object_replace ((GstObject **) pad_p, NULL);
hgs
parents:
diff changeset
   152
    GST_OBJECT_UNLOCK (element);
hgs
parents:
diff changeset
   153
    GST_DEBUG_OBJECT (enc->element, "cn pad released");
hgs
parents:
diff changeset
   154
  }
hgs
parents:
diff changeset
   155
hgs
parents:
diff changeset
   156
  /* ERRORS */
hgs
parents:
diff changeset
   157
wrong_pad:
hgs
parents:
diff changeset
   158
  {
hgs
parents:
diff changeset
   159
    GST_OBJECT_UNLOCK (element);
hgs
parents:
diff changeset
   160
    GST_ERROR_OBJECT (element, "pad not requested; can not be released!");
hgs
parents:
diff changeset
   161
    return;
hgs
parents:
diff changeset
   162
  }
hgs
parents:
diff changeset
   163
}
hgs
parents:
diff changeset
   164
hgs
parents:
diff changeset
   165
gboolean
hgs
parents:
diff changeset
   166
gst_framed_audio_enc_sink_event (GstPad * pad, GstEvent * event)
hgs
parents:
diff changeset
   167
{
hgs
parents:
diff changeset
   168
  GstFramedAudioEnc *enc;
hgs
parents:
diff changeset
   169
hgs
parents:
diff changeset
   170
  enc = gst_pad_get_element_private (pad);
hgs
parents:
diff changeset
   171
  g_return_val_if_fail (enc, FALSE);
hgs
parents:
diff changeset
   172
hgs
parents:
diff changeset
   173
  GST_LOG_OBJECT (enc->element, "received %s", GST_EVENT_TYPE_NAME (event));
hgs
parents:
diff changeset
   174
hgs
parents:
diff changeset
   175
  switch (GST_EVENT_TYPE (event)) {
hgs
parents:
diff changeset
   176
    case GST_EVENT_FLUSH_STOP:
hgs
parents:
diff changeset
   177
      /* fall-through */
hgs
parents:
diff changeset
   178
    case GST_EVENT_EOS:
hgs
parents:
diff changeset
   179
      gst_adapter_clear (enc->adapter);
hgs
parents:
diff changeset
   180
      enc->next_ts = GST_CLOCK_TIME_NONE;
hgs
parents:
diff changeset
   181
      break;
hgs
parents:
diff changeset
   182
    default:
hgs
parents:
diff changeset
   183
      break;
hgs
parents:
diff changeset
   184
  }
hgs
parents:
diff changeset
   185
hgs
parents:
diff changeset
   186
  return gst_pad_event_default (pad, event);
hgs
parents:
diff changeset
   187
}
hgs
parents:
diff changeset
   188
hgs
parents:
diff changeset
   189
#else
hgs
parents:
diff changeset
   190
/* included part */
hgs
parents:
diff changeset
   191
hgs
parents:
diff changeset
   192
/* parameters:
hgs
parents:
diff changeset
   193
     RAW_FRAME_SIZE
hgs
parents:
diff changeset
   194
     CODEC_FRAME_SIZE
hgs
parents:
diff changeset
   195
     FRAME_DURATION
hgs
parents:
diff changeset
   196
     AUDIO_SAMPLE_RATE (optional)
hgs
parents:
diff changeset
   197
   callback:
hgs
parents:
diff changeset
   198
     codec_get_data(enc, in, out, dtx)
hgs
parents:
diff changeset
   199
hgs
parents:
diff changeset
   200
   If one does not mind a few cycles, include'ing can also be replaced by
hgs
parents:
diff changeset
   201
   a regular include & call, at the expense of some additional parameters
hgs
parents:
diff changeset
   202
   passed some way or another.
hgs
parents:
diff changeset
   203
*/
hgs
parents:
diff changeset
   204
hgs
parents:
diff changeset
   205
#ifndef AUDIO_SAMPLE_RATE
hgs
parents:
diff changeset
   206
#define AUDIO_SAMPLE_RATE   (8000)
hgs
parents:
diff changeset
   207
#endif
hgs
parents:
diff changeset
   208
hgs
parents:
diff changeset
   209
/* quite some conditional stuff;
hgs
parents:
diff changeset
   210
 * the (ugly?) cost of trying to stay inner loop optimal */
hgs
parents:
diff changeset
   211
hgs
parents:
diff changeset
   212
static GstFlowReturn
hgs
parents:
diff changeset
   213
gst_framed_audio_enc_chain (GstFramedAudioEnc * enc, GstBuffer * buf,
hgs
parents:
diff changeset
   214
    GstPad * srcpad, GstPad ** _cnpad)
hgs
parents:
diff changeset
   215
{
hgs
parents:
diff changeset
   216
  GstFlowReturn ret = GST_FLOW_OK;
hgs
parents:
diff changeset
   217
  GstBuffer *obuf = NULL;
hgs
parents:
diff changeset
   218
#ifdef CN_PAD
hgs
parents:
diff changeset
   219
  GstBuffer *cnbuf = NULL;
hgs
parents:
diff changeset
   220
  GstPad *cnpad = NULL;
hgs
parents:
diff changeset
   221
#endif
hgs
parents:
diff changeset
   222
  gboolean discont = FALSE;
hgs
parents:
diff changeset
   223
  const guint8 *data;
hgs
parents:
diff changeset
   224
  guint8 *odata;
hgs
parents:
diff changeset
   225
  gint av, flush, osize;
hgs
parents:
diff changeset
   226
hgs
parents:
diff changeset
   227
#ifdef CN_PAD
hgs
parents:
diff changeset
   228
  GST_OBJECT_LOCK (enc->element);
hgs
parents:
diff changeset
   229
  if (_cnpad)
hgs
parents:
diff changeset
   230
    cnpad = *_cnpad;
hgs
parents:
diff changeset
   231
  if (cnpad)
hgs
parents:
diff changeset
   232
    gst_object_ref (cnpad);
hgs
parents:
diff changeset
   233
  GST_OBJECT_UNLOCK (enc->element);
hgs
parents:
diff changeset
   234
#endif
hgs
parents:
diff changeset
   235
hgs
parents:
diff changeset
   236
  if (G_LIKELY (buf)) {
hgs
parents:
diff changeset
   237
    GST_LOG_OBJECT (enc->element, "input buffer of size %d with ts: %"
hgs
parents:
diff changeset
   238
        GST_TIME_FORMAT, GST_BUFFER_SIZE (buf),
hgs
parents:
diff changeset
   239
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
hgs
parents:
diff changeset
   240
    discont = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT);
hgs
parents:
diff changeset
   241
hgs
parents:
diff changeset
   242
    /* reposition to the new buffer's timestamp,
hgs
parents:
diff changeset
   243
     * while correcting for some minor left-over */
hgs
parents:
diff changeset
   244
    if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
hgs
parents:
diff changeset
   245
      if (GST_CLOCK_TIME_IS_VALID (enc->next_ts)) {
hgs
parents:
diff changeset
   246
        GstClockTimeDiff diff, limit;
hgs
parents:
diff changeset
   247
        GstClockTime tleft;
hgs
parents:
diff changeset
   248
hgs
parents:
diff changeset
   249
        tleft = GST_FRAMES_TO_CLOCK_TIME
hgs
parents:
diff changeset
   250
            (gst_adapter_available (enc->adapter) / 2, AUDIO_SAMPLE_RATE);
hgs
parents:
diff changeset
   251
        diff =
hgs
parents:
diff changeset
   252
            GST_CLOCK_DIFF (enc->next_ts + tleft, GST_BUFFER_TIMESTAMP (buf));
hgs
parents:
diff changeset
   253
        limit = GST_SECOND / AUDIO_SAMPLE_RATE / 2;
hgs
parents:
diff changeset
   254
        /* try for a perfect stream if possible, do not act on rounding errors */
hgs
parents:
diff changeset
   255
        if (diff > limit || diff < -limit) {
hgs
parents:
diff changeset
   256
          enc->next_ts = GST_BUFFER_TIMESTAMP (buf);
hgs
parents:
diff changeset
   257
          if (enc->next_ts > tleft)
hgs
parents:
diff changeset
   258
            enc->next_ts -= tleft;
hgs
parents:
diff changeset
   259
          GST_LOG_OBJECT (enc->element, "marking discont based on timestamps");
hgs
parents:
diff changeset
   260
          discont = TRUE;
hgs
parents:
diff changeset
   261
        }
hgs
parents:
diff changeset
   262
      } else
hgs
parents:
diff changeset
   263
        enc->next_ts = GST_BUFFER_TIMESTAMP (buf);
hgs
parents:
diff changeset
   264
    }
hgs
parents:
diff changeset
   265
hgs
parents:
diff changeset
   266
    gst_adapter_push (enc->adapter, buf);
hgs
parents:
diff changeset
   267
    buf = NULL;
hgs
parents:
diff changeset
   268
  }
hgs
parents:
diff changeset
   269
hgs
parents:
diff changeset
   270
  av = gst_adapter_available (enc->adapter);
hgs
parents:
diff changeset
   271
  if (G_UNLIKELY (av < RAW_FRAME_SIZE))
hgs
parents:
diff changeset
   272
    goto done;
hgs
parents:
diff changeset
   273
hgs
parents:
diff changeset
   274
  data = gst_adapter_peek (enc->adapter, av);
hgs
parents:
diff changeset
   275
  obuf = gst_buffer_new_and_alloc (av / RAW_FRAME_SIZE * CODEC_FRAME_SIZE);
hgs
parents:
diff changeset
   276
  odata = GST_BUFFER_DATA (obuf);
hgs
parents:
diff changeset
   277
  osize = 0;
hgs
parents:
diff changeset
   278
  flush = 0;
hgs
parents:
diff changeset
   279
hgs
parents:
diff changeset
   280
  while (TRUE) {
hgs
parents:
diff changeset
   281
    gint esize;
hgs
parents:
diff changeset
   282
#ifdef CN_PAD
hgs
parents:
diff changeset
   283
    GstDtxDecision dtx;
hgs
parents:
diff changeset
   284
hgs
parents:
diff changeset
   285
    /* safe default to start with, should get set */
hgs
parents:
diff changeset
   286
    dtx = GST_DTX_DECISION_VOICE;
hgs
parents:
diff changeset
   287
    esize = codec_get_data (enc->element, data + flush, odata, &dtx);
hgs
parents:
diff changeset
   288
#else
hgs
parents:
diff changeset
   289
    esize = codec_get_data (enc->element, data + flush, odata, NULL);
hgs
parents:
diff changeset
   290
#endif
hgs
parents:
diff changeset
   291
hgs
parents:
diff changeset
   292
    if (G_UNLIKELY (esize < 0))
hgs
parents:
diff changeset
   293
      goto encode_failed;
hgs
parents:
diff changeset
   294
hgs
parents:
diff changeset
   295
#ifdef CN_PAD
hgs
parents:
diff changeset
   296
    /* cn in a separate stream */
hgs
parents:
diff changeset
   297
    switch (dtx) {
hgs
parents:
diff changeset
   298
      case GST_DTX_DECISION_VOICE:
hgs
parents:
diff changeset
   299
#endif
hgs
parents:
diff changeset
   300
        flush += RAW_FRAME_SIZE;
hgs
parents:
diff changeset
   301
        av -= RAW_FRAME_SIZE;
hgs
parents:
diff changeset
   302
hgs
parents:
diff changeset
   303
        odata += esize;
hgs
parents:
diff changeset
   304
        osize += esize;
hgs
parents:
diff changeset
   305
#ifdef CN_PAD
hgs
parents:
diff changeset
   306
        break;
hgs
parents:
diff changeset
   307
      case GST_DTX_DECISION_SID_UPDATE:
hgs
parents:
diff changeset
   308
        GST_LOG_OBJECT (enc->element, "dtx: SID_UPDATE %d", esize);
hgs
parents:
diff changeset
   309
        /* if already data before, need to put SID data separately */
hgs
parents:
diff changeset
   310
        if (G_UNLIKELY (osize)) {
hgs
parents:
diff changeset
   311
          cnbuf = gst_buffer_new_and_alloc (esize);
hgs
parents:
diff changeset
   312
          memcpy (GST_BUFFER_DATA (cnbuf), data + osize, esize);
hgs
parents:
diff changeset
   313
        } else {
hgs
parents:
diff changeset
   314
          cnbuf = obuf;
hgs
parents:
diff changeset
   315
          obuf = NULL;
hgs
parents:
diff changeset
   316
        }
hgs
parents:
diff changeset
   317
        /* and send one or both */
hgs
parents:
diff changeset
   318
        goto send;
hgs
parents:
diff changeset
   319
        break;
hgs
parents:
diff changeset
   320
      case GST_DTX_DECISION_SID_NONE:
hgs
parents:
diff changeset
   321
        GST_LOG_OBJECT (enc->element, "dtx: SID_NONE %d", esize);
hgs
parents:
diff changeset
   322
        /* maybe send preceding voice, if any */
hgs
parents:
diff changeset
   323
        goto send;
hgs
parents:
diff changeset
   324
        break;
hgs
parents:
diff changeset
   325
    }
hgs
parents:
diff changeset
   326
#endif
hgs
parents:
diff changeset
   327
hgs
parents:
diff changeset
   328
#ifdef CODEC_FRAME_VARIABLE
hgs
parents:
diff changeset
   329
    /* flush output after insufficient data */
hgs
parents:
diff changeset
   330
    if (av >= RAW_FRAME_SIZE)
hgs
parents:
diff changeset
   331
      continue;
hgs
parents:
diff changeset
   332
#else
hgs
parents:
diff changeset
   333
    /* ... or some reduced (e.g. silence) frame */
hgs
parents:
diff changeset
   334
    if (esize >= CODEC_FRAME_SIZE && av >= RAW_FRAME_SIZE)
hgs
parents:
diff changeset
   335
      continue;
hgs
parents:
diff changeset
   336
#endif
hgs
parents:
diff changeset
   337
hgs
parents:
diff changeset
   338
#ifdef CN_PAD
hgs
parents:
diff changeset
   339
  send:
hgs
parents:
diff changeset
   340
#endif
hgs
parents:
diff changeset
   341
    /* maybe a silent discarded frame */
hgs
parents:
diff changeset
   342
    if (G_LIKELY (osize)) {
hgs
parents:
diff changeset
   343
      GST_BUFFER_SIZE (obuf) = osize;
hgs
parents:
diff changeset
   344
      GST_BUFFER_DURATION (obuf)
hgs
parents:
diff changeset
   345
          = FRAME_DURATION * (flush / RAW_FRAME_SIZE);
hgs
parents:
diff changeset
   346
      GST_BUFFER_TIMESTAMP (obuf) = enc->next_ts;
hgs
parents:
diff changeset
   347
      if (G_UNLIKELY (discont)) {
hgs
parents:
diff changeset
   348
        GST_BUFFER_FLAG_SET (obuf, GST_BUFFER_FLAG_DISCONT);
hgs
parents:
diff changeset
   349
        discont = FALSE;
hgs
parents:
diff changeset
   350
      }
hgs
parents:
diff changeset
   351
hgs
parents:
diff changeset
   352
      GST_LOG_OBJECT (enc->element,
hgs
parents:
diff changeset
   353
          "pushing buffer of size %d with ts: %" GST_TIME_FORMAT,
hgs
parents:
diff changeset
   354
          GST_BUFFER_SIZE (obuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (obuf)));
hgs
parents:
diff changeset
   355
      gst_buffer_set_caps (obuf, GST_PAD_CAPS (srcpad));
hgs
parents:
diff changeset
   356
      ret = gst_pad_push (srcpad, obuf);
hgs
parents:
diff changeset
   357
      obuf = NULL;
hgs
parents:
diff changeset
   358
    } else {
hgs
parents:
diff changeset
   359
      ret = GST_FLOW_OK;
hgs
parents:
diff changeset
   360
    }
hgs
parents:
diff changeset
   361
hgs
parents:
diff changeset
   362
#ifdef CN_PAD
hgs
parents:
diff changeset
   363
    /* check for stuff to send on cn pad */
hgs
parents:
diff changeset
   364
    if (cnbuf && cnpad) {
hgs
parents:
diff changeset
   365
      /* only at most 1 SID update per buffer */
hgs
parents:
diff changeset
   366
      GST_BUFFER_SIZE (cnbuf) = esize;
hgs
parents:
diff changeset
   367
      GST_BUFFER_DURATION (cnbuf) = FRAME_DURATION;
hgs
parents:
diff changeset
   368
      GST_BUFFER_TIMESTAMP (cnbuf) = enc->next_ts;
hgs
parents:
diff changeset
   369
hgs
parents:
diff changeset
   370
      GST_LOG_OBJECT (enc->element,
hgs
parents:
diff changeset
   371
          "pushing cn buffer of size %d with ts: %" GST_TIME_FORMAT,
hgs
parents:
diff changeset
   372
          GST_BUFFER_SIZE (cnbuf),
hgs
parents:
diff changeset
   373
          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (cnbuf)));
hgs
parents:
diff changeset
   374
      gst_buffer_set_caps (cnbuf, GST_PAD_CAPS (cnpad));
hgs
parents:
diff changeset
   375
      if (G_LIKELY (ret == GST_FLOW_OK)) {
hgs
parents:
diff changeset
   376
        ret = gst_pad_push (cnpad, cnbuf);
hgs
parents:
diff changeset
   377
        /* cn pad may not be linked */
hgs
parents:
diff changeset
   378
        if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED))
hgs
parents:
diff changeset
   379
          ret = GST_FLOW_OK;
hgs
parents:
diff changeset
   380
      } else
hgs
parents:
diff changeset
   381
        gst_pad_push (cnpad, cnbuf);
hgs
parents:
diff changeset
   382
      cnbuf = NULL;
hgs
parents:
diff changeset
   383
    } else if (G_UNLIKELY (cnbuf)) {
hgs
parents:
diff changeset
   384
      /* should not occur */
hgs
parents:
diff changeset
   385
      gst_buffer_unref (cnbuf);
hgs
parents:
diff changeset
   386
      cnbuf = NULL;
hgs
parents:
diff changeset
   387
    }
hgs
parents:
diff changeset
   388
hgs
parents:
diff changeset
   389
    if (dtx != GST_DTX_DECISION_VOICE) {
hgs
parents:
diff changeset
   390
      /* still need to count non-voice encoded frame */
hgs
parents:
diff changeset
   391
      flush += RAW_FRAME_SIZE;
hgs
parents:
diff changeset
   392
      av -= RAW_FRAME_SIZE;
hgs
parents:
diff changeset
   393
    }
hgs
parents:
diff changeset
   394
#endif /* CN_PAD */
hgs
parents:
diff changeset
   395
hgs
parents:
diff changeset
   396
    /* remove used part */
hgs
parents:
diff changeset
   397
    gst_adapter_flush (enc->adapter, flush);
hgs
parents:
diff changeset
   398
    if (GST_CLOCK_TIME_IS_VALID (enc->next_ts))
hgs
parents:
diff changeset
   399
      enc->next_ts += FRAME_DURATION * (flush / RAW_FRAME_SIZE);
hgs
parents:
diff changeset
   400
hgs
parents:
diff changeset
   401
    /* end if insufficient left or error */
hgs
parents:
diff changeset
   402
    if (av < RAW_FRAME_SIZE || ret != GST_FLOW_OK)
hgs
parents:
diff changeset
   403
      break;
hgs
parents:
diff changeset
   404
hgs
parents:
diff changeset
   405
    /* allocate new buffer */
hgs
parents:
diff changeset
   406
    if (!obuf) {
hgs
parents:
diff changeset
   407
      obuf = gst_buffer_new_and_alloc (av / RAW_FRAME_SIZE * CODEC_FRAME_SIZE);
hgs
parents:
diff changeset
   408
      odata = GST_BUFFER_DATA (obuf);
hgs
parents:
diff changeset
   409
      osize = 0;
hgs
parents:
diff changeset
   410
    }
hgs
parents:
diff changeset
   411
    /* and prepare to consume again */
hgs
parents:
diff changeset
   412
    data = gst_adapter_peek (enc->adapter, av);
hgs
parents:
diff changeset
   413
    flush = 0;
hgs
parents:
diff changeset
   414
  }
hgs
parents:
diff changeset
   415
hgs
parents:
diff changeset
   416
  if (!av) {
hgs
parents:
diff changeset
   417
    enc->next_ts = GST_CLOCK_TIME_NONE;
hgs
parents:
diff changeset
   418
  }
hgs
parents:
diff changeset
   419
hgs
parents:
diff changeset
   420
done:
hgs
parents:
diff changeset
   421
#ifdef CN_PAD
hgs
parents:
diff changeset
   422
  GST_OBJECT_LOCK (enc->element);
hgs
parents:
diff changeset
   423
  if (cnpad)
hgs
parents:
diff changeset
   424
    gst_object_unref (cnpad);
hgs
parents:
diff changeset
   425
  GST_OBJECT_UNLOCK (enc->element);
hgs
parents:
diff changeset
   426
#endif
hgs
parents:
diff changeset
   427
hgs
parents:
diff changeset
   428
  return ret;
hgs
parents:
diff changeset
   429
hgs
parents:
diff changeset
   430
  /* ERRORS */
hgs
parents:
diff changeset
   431
encode_failed:
hgs
parents:
diff changeset
   432
  {
hgs
parents:
diff changeset
   433
    GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), (NULL));
hgs
parents:
diff changeset
   434
    ret = GST_FLOW_ERROR;
hgs
parents:
diff changeset
   435
    gst_buffer_unref (obuf);
hgs
parents:
diff changeset
   436
    goto done;
hgs
parents:
diff changeset
   437
  }
hgs
parents:
diff changeset
   438
}
hgs
parents:
diff changeset
   439
#endif