gst_nokia_speech/gstframedaudioenc.c
changeset 9 2a0f36a70380
parent 8 4a7fac7dd34a
child 10 6f340f756486
--- a/gst_nokia_speech/gstframedaudioenc.c	Fri Apr 16 15:15:52 2010 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,439 +0,0 @@
-/* GStreamer Framed Audio Encoder
- * Copyright 2009 Collabora Ltd,
- * Copyright 2009 Nokia Corporation
- *  @author: Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>.
- *
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <gst/gst.h>
-#include <gst/audio/audio.h>
-#include <string.h>
-
-#include "gstframedaudioenc.h"
-
-/* generic part */
-#ifndef RAW_FRAME_SIZE
-
-/* this will reference caller's debug category;
- * there is a copy of this per plugin lib (= debug category) */
-GST_DEBUG_CATEGORY_STATIC (framedaudioenc_debug);
-#define GST_CAT_DEFAULT framedaudioenc_debug
-
-void
-gst_framed_audio_enc_reset (GstFramedAudioEnc * enc)
-{
-  gst_adapter_clear (enc->adapter);
-  enc->next_ts = GST_CLOCK_TIME_NONE;
-}
-
-/* installs @enc as element private for @element's pad,
- * and possibly some event and query handler.
- * if these need overriding, chain up to them
- * chain and setcaps still need to be set by @element */
-void
-gst_framed_audio_enc_init (GstFramedAudioEnc * enc, GstElement * element,
-    GstDebugCategory * cat)
-{
-  enc->element = element;
-#ifndef GST_DISABLE_GST_DEBUG
-  framedaudioenc_debug = cat;
-#endif
-
-  enc->adapter = gst_adapter_new ();
-
-  /* hook some */
-  enc->sinkpad = gst_element_get_pad (enc->element, "sink");
-  g_assert (enc->sinkpad);
-  gst_pad_set_element_private (enc->sinkpad, enc);
-
-  /* watch downstream events */
-  gst_pad_set_event_function (enc->sinkpad,
-      GST_DEBUG_FUNCPTR (gst_framed_audio_enc_sink_event));
-
-  gst_framed_audio_enc_reset (enc);
-}
-
-void
-gst_framed_audio_enc_finalize (GstFramedAudioEnc * enc)
-{
-  gst_object_unref (enc->adapter);
-
-  gst_pad_set_element_private (enc->sinkpad, NULL);
-  gst_object_unref (enc->sinkpad);
-}
-
-GstPad *
-gst_framed_audio_enc_request_new_pad (GstFramedAudioEnc * enc,
-    GstPadTemplate * templ, const gchar * req_name, GstPad ** pad_p)
-{
-  GstElement *element;
-  GstPad *newpad;
-  GstElementClass *klass;
-  GstCaps *caps;
-
-  g_return_val_if_fail (templ != NULL, NULL);
-
-  element = enc->element;
-  klass = GST_ELEMENT_GET_CLASS (element);
-
-  if (templ != gst_element_class_get_pad_template (klass, "cn"))
-    goto wrong_template;
-
-  GST_DEBUG_OBJECT (enc->element, "adding cn pad");
-  newpad = gst_pad_new_from_template (templ, "cn");
-  /* set template caps */
-  caps = gst_caps_copy (gst_pad_get_pad_template_caps (newpad));
-  gst_pad_set_caps (newpad, caps);
-  gst_caps_unref (caps);
-  gst_pad_use_fixed_caps (newpad);
-  gst_pad_set_active (newpad, TRUE);
-  /* only 1 pad by name can be added */
-  if (gst_element_add_pad (element, newpad)) {
-    GST_OBJECT_LOCK (element);
-    gst_object_replace ((GstObject **) pad_p, GST_OBJECT_CAST (newpad));
-    GST_OBJECT_UNLOCK (element);
-    GST_DEBUG_OBJECT (enc->element, "cn pad added");
-  } else {
-    gst_object_unref (newpad);
-    goto already_requested;
-  }
-
-  return newpad;
-
-  /* ERRORS */
-wrong_template:
-  {
-    GST_ERROR_OBJECT (element, "not our template!");
-    return NULL;
-  }
-already_requested:
-  {
-    GST_ERROR_OBJECT (element, "only 1 instance of a pad can be requested");
-    return NULL;
-  }
-}
-
-void
-gst_framed_audio_enc_release_pad (GstFramedAudioEnc * enc, GstPad * pad,
-    GstPad ** pad_p, void (disable_cn) (GstElement *))
-{
-  GstElement *element = enc->element;
-
-  GST_DEBUG_OBJECT (enc->element, "releasing cn pad");
-
-  GST_OBJECT_LOCK (element);
-  if (pad != *pad_p)
-    goto wrong_pad;
-  GST_OBJECT_UNLOCK (element);
-
-  /* reconfigure encoder */
-  disable_cn (element);
-
-  if (gst_element_remove_pad (element, pad)) {
-    GST_OBJECT_LOCK (element);
-    gst_object_replace ((GstObject **) pad_p, NULL);
-    GST_OBJECT_UNLOCK (element);
-    GST_DEBUG_OBJECT (enc->element, "cn pad released");
-  }
-
-  /* ERRORS */
-wrong_pad:
-  {
-    GST_OBJECT_UNLOCK (element);
-    GST_ERROR_OBJECT (element, "pad not requested; can not be released!");
-    return;
-  }
-}
-
-gboolean
-gst_framed_audio_enc_sink_event (GstPad * pad, GstEvent * event)
-{
-  GstFramedAudioEnc *enc;
-
-  enc = gst_pad_get_element_private (pad);
-  g_return_val_if_fail (enc, FALSE);
-
-  GST_LOG_OBJECT (enc->element, "received %s", GST_EVENT_TYPE_NAME (event));
-
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_FLUSH_STOP:
-      /* fall-through */
-    case GST_EVENT_EOS:
-      gst_adapter_clear (enc->adapter);
-      enc->next_ts = GST_CLOCK_TIME_NONE;
-      break;
-    default:
-      break;
-  }
-
-  return gst_pad_event_default (pad, event);
-}
-
-#else
-/* included part */
-
-/* parameters:
-     RAW_FRAME_SIZE
-     CODEC_FRAME_SIZE
-     FRAME_DURATION
-     AUDIO_SAMPLE_RATE (optional)
-   callback:
-     codec_get_data(enc, in, out, dtx)
-
-   If one does not mind a few cycles, include'ing can also be replaced by
-   a regular include & call, at the expense of some additional parameters
-   passed some way or another.
-*/
-
-#ifndef AUDIO_SAMPLE_RATE
-#define AUDIO_SAMPLE_RATE   (8000)
-#endif
-
-/* quite some conditional stuff;
- * the (ugly?) cost of trying to stay inner loop optimal */
-
-static GstFlowReturn
-gst_framed_audio_enc_chain (GstFramedAudioEnc * enc, GstBuffer * buf,
-    GstPad * srcpad, GstPad ** _cnpad)
-{
-  GstFlowReturn ret = GST_FLOW_OK;
-  GstBuffer *obuf = NULL;
-#ifdef CN_PAD
-  GstBuffer *cnbuf = NULL;
-  GstPad *cnpad = NULL;
-#endif
-  gboolean discont = FALSE;
-  const guint8 *data;
-  guint8 *odata;
-  gint av, flush, osize;
-
-#ifdef CN_PAD
-  GST_OBJECT_LOCK (enc->element);
-  if (_cnpad)
-    cnpad = *_cnpad;
-  if (cnpad)
-    gst_object_ref (cnpad);
-  GST_OBJECT_UNLOCK (enc->element);
-#endif
-
-  if (G_LIKELY (buf)) {
-    GST_LOG_OBJECT (enc->element, "input buffer of size %d with ts: %"
-        GST_TIME_FORMAT, GST_BUFFER_SIZE (buf),
-        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
-    discont = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT);
-
-    /* reposition to the new buffer's timestamp,
-     * while correcting for some minor left-over */
-    if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
-      if (GST_CLOCK_TIME_IS_VALID (enc->next_ts)) {
-        GstClockTimeDiff diff, limit;
-        GstClockTime tleft;
-
-        tleft = GST_FRAMES_TO_CLOCK_TIME
-            (gst_adapter_available (enc->adapter) / 2, AUDIO_SAMPLE_RATE);
-        diff =
-            GST_CLOCK_DIFF (enc->next_ts + tleft, GST_BUFFER_TIMESTAMP (buf));
-        limit = GST_SECOND / AUDIO_SAMPLE_RATE / 2;
-        /* try for a perfect stream if possible, do not act on rounding errors */
-        if (diff > limit || diff < -limit) {
-          enc->next_ts = GST_BUFFER_TIMESTAMP (buf);
-          if (enc->next_ts > tleft)
-            enc->next_ts -= tleft;
-          GST_LOG_OBJECT (enc->element, "marking discont based on timestamps");
-          discont = TRUE;
-        }
-      } else
-        enc->next_ts = GST_BUFFER_TIMESTAMP (buf);
-    }
-
-    gst_adapter_push (enc->adapter, buf);
-    buf = NULL;
-  }
-
-  av = gst_adapter_available (enc->adapter);
-  if (G_UNLIKELY (av < RAW_FRAME_SIZE))
-    goto done;
-
-  data = gst_adapter_peek (enc->adapter, av);
-  obuf = gst_buffer_new_and_alloc (av / RAW_FRAME_SIZE * CODEC_FRAME_SIZE);
-  odata = GST_BUFFER_DATA (obuf);
-  osize = 0;
-  flush = 0;
-
-  while (TRUE) {
-    gint esize;
-#ifdef CN_PAD
-    GstDtxDecision dtx;
-
-    /* safe default to start with, should get set */
-    dtx = GST_DTX_DECISION_VOICE;
-    esize = codec_get_data (enc->element, data + flush, odata, &dtx);
-#else
-    esize = codec_get_data (enc->element, data + flush, odata, NULL);
-#endif
-
-    if (G_UNLIKELY (esize < 0))
-      goto encode_failed;
-
-#ifdef CN_PAD
-    /* cn in a separate stream */
-    switch (dtx) {
-      case GST_DTX_DECISION_VOICE:
-#endif
-        flush += RAW_FRAME_SIZE;
-        av -= RAW_FRAME_SIZE;
-
-        odata += esize;
-        osize += esize;
-#ifdef CN_PAD
-        break;
-      case GST_DTX_DECISION_SID_UPDATE:
-        GST_LOG_OBJECT (enc->element, "dtx: SID_UPDATE %d", esize);
-        /* if already data before, need to put SID data separately */
-        if (G_UNLIKELY (osize)) {
-          cnbuf = gst_buffer_new_and_alloc (esize);
-          memcpy (GST_BUFFER_DATA (cnbuf), data + osize, esize);
-        } else {
-          cnbuf = obuf;
-          obuf = NULL;
-        }
-        /* and send one or both */
-        goto send;
-        break;
-      case GST_DTX_DECISION_SID_NONE:
-        GST_LOG_OBJECT (enc->element, "dtx: SID_NONE %d", esize);
-        /* maybe send preceding voice, if any */
-        goto send;
-        break;
-    }
-#endif
-
-#ifdef CODEC_FRAME_VARIABLE
-    /* flush output after insufficient data */
-    if (av >= RAW_FRAME_SIZE)
-      continue;
-#else
-    /* ... or some reduced (e.g. silence) frame */
-    if (esize >= CODEC_FRAME_SIZE && av >= RAW_FRAME_SIZE)
-      continue;
-#endif
-
-#ifdef CN_PAD
-  send:
-#endif
-    /* maybe a silent discarded frame */
-    if (G_LIKELY (osize)) {
-      GST_BUFFER_SIZE (obuf) = osize;
-      GST_BUFFER_DURATION (obuf)
-          = FRAME_DURATION * (flush / RAW_FRAME_SIZE);
-      GST_BUFFER_TIMESTAMP (obuf) = enc->next_ts;
-      if (G_UNLIKELY (discont)) {
-        GST_BUFFER_FLAG_SET (obuf, GST_BUFFER_FLAG_DISCONT);
-        discont = FALSE;
-      }
-
-      GST_LOG_OBJECT (enc->element,
-          "pushing buffer of size %d with ts: %" GST_TIME_FORMAT,
-          GST_BUFFER_SIZE (obuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (obuf)));
-      gst_buffer_set_caps (obuf, GST_PAD_CAPS (srcpad));
-      ret = gst_pad_push (srcpad, obuf);
-      obuf = NULL;
-    } else {
-      ret = GST_FLOW_OK;
-    }
-
-#ifdef CN_PAD
-    /* check for stuff to send on cn pad */
-    if (cnbuf && cnpad) {
-      /* only at most 1 SID update per buffer */
-      GST_BUFFER_SIZE (cnbuf) = esize;
-      GST_BUFFER_DURATION (cnbuf) = FRAME_DURATION;
-      GST_BUFFER_TIMESTAMP (cnbuf) = enc->next_ts;
-
-      GST_LOG_OBJECT (enc->element,
-          "pushing cn buffer of size %d with ts: %" GST_TIME_FORMAT,
-          GST_BUFFER_SIZE (cnbuf),
-          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (cnbuf)));
-      gst_buffer_set_caps (cnbuf, GST_PAD_CAPS (cnpad));
-      if (G_LIKELY (ret == GST_FLOW_OK)) {
-        ret = gst_pad_push (cnpad, cnbuf);
-        /* cn pad may not be linked */
-        if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED))
-          ret = GST_FLOW_OK;
-      } else
-        gst_pad_push (cnpad, cnbuf);
-      cnbuf = NULL;
-    } else if (G_UNLIKELY (cnbuf)) {
-      /* should not occur */
-      gst_buffer_unref (cnbuf);
-      cnbuf = NULL;
-    }
-
-    if (dtx != GST_DTX_DECISION_VOICE) {
-      /* still need to count non-voice encoded frame */
-      flush += RAW_FRAME_SIZE;
-      av -= RAW_FRAME_SIZE;
-    }
-#endif /* CN_PAD */
-
-    /* remove used part */
-    gst_adapter_flush (enc->adapter, flush);
-    if (GST_CLOCK_TIME_IS_VALID (enc->next_ts))
-      enc->next_ts += FRAME_DURATION * (flush / RAW_FRAME_SIZE);
-
-    /* end if insufficient left or error */
-    if (av < RAW_FRAME_SIZE || ret != GST_FLOW_OK)
-      break;
-
-    /* allocate new buffer */
-    if (!obuf) {
-      obuf = gst_buffer_new_and_alloc (av / RAW_FRAME_SIZE * CODEC_FRAME_SIZE);
-      odata = GST_BUFFER_DATA (obuf);
-      osize = 0;
-    }
-    /* and prepare to consume again */
-    data = gst_adapter_peek (enc->adapter, av);
-    flush = 0;
-  }
-
-  if (!av) {
-    enc->next_ts = GST_CLOCK_TIME_NONE;
-  }
-
-done:
-#ifdef CN_PAD
-  GST_OBJECT_LOCK (enc->element);
-  if (cnpad)
-    gst_object_unref (cnpad);
-  GST_OBJECT_UNLOCK (enc->element);
-#endif
-
-  return ret;
-
-  /* ERRORS */
-encode_failed:
-  {
-    GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), (NULL));
-    ret = GST_FLOW_ERROR;
-    gst_buffer_unref (obuf);
-    goto done;
-  }
-}
-#endif