<commit_before>/*
 * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
 *   Author: <NAME> <<EMAIL>>, Collabora Ltd.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation
 * version 2.1 of the License.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gst/gst.h>
#include <string.h>

#include "gstomxaudioenc.h"

GST_DEBUG_CATEGORY_STATIC (gst_omx_audio_enc_debug_category);
#define GST_CAT_DEFAULT gst_omx_audio_enc_debug_category

/* prototypes */
static void gst_omx_audio_enc_finalize (GObject * object);

static GstStateChangeReturn
gst_omx_audio_enc_change_state (GstElement * element,
    GstStateChange transition);

static gboolean gst_omx_audio_enc_start (GstBaseAudioEncoder * encoder);
static gboolean gst_omx_audio_enc_stop (GstBaseAudioEncoder * encoder);
static gboolean gst_omx_audio_enc_set_format (GstBaseAudioEncoder * encoder,
    GstAudioState * state);
static gboolean gst_omx_audio_enc_event (GstBaseAudioEncoder * encoder,
    GstEvent * event);
static GstFlowReturn gst_omx_audio_enc_handle_frame (GstBaseAudioEncoder *
    encoder, GstBuffer * buffer);
static void gst_omx_audio_enc_flush (GstBaseAudioEncoder * encoder);

static GstFlowReturn gst_omx_audio_enc_drain (GstOMXAudioEnc * self);

enum
{
  PROP_0
};

/* class initialization */

#define DEBUG_INIT(bla) \
  GST_DEBUG_CATEGORY_INIT (gst_omx_audio_enc_debug_category, "omxaudioenc", 0, \
      "debug category for gst-omx audio encoder base class");

GST_BOILERPLATE_FULL (GstOMXAudioEnc, gst_omx_audio_enc, GstBaseAudioEncoder,
    GST_TYPE_BASE_AUDIO_ENCODER, DEBUG_INIT);

static void
gst_omx_audio_enc_base_init (gpointer g_class)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
  GstOMXAudioEncClass *audioenc_class = GST_OMX_AUDIO_ENC_CLASS (g_class);
  GKeyFile *config;
  const gchar *element_name;
  GError *err;
  gchar *core_name, *component_name, *component_role;
  gint in_port_index, out_port_index;
  gchar *template_caps;
  GstPadTemplate *templ;
  GstCaps *caps;
  gchar **hacks;

  element_name =
      g_type_get_qdata (G_TYPE_FROM_CLASS (g_class),
      gst_omx_element_name_quark);
  /* This happens for the base class and abstract subclasses */
  if (!element_name)
    return;

  config = gst_omx_get_configuration ();

  /* This will always succeed, see check in plugin_init */
  core_name = g_key_file_get_string (config, element_name, "core-name", NULL);
  g_assert (core_name != NULL);
  audioenc_class->core_name = core_name;
  component_name =
      g_key_file_get_string (config, element_name, "component-name", NULL);
  g_assert (component_name != NULL);
  audioenc_class->component_name = component_name;

  /* If this fails we simply don't set a role */
  if ((component_role =
          g_key_file_get_string (config, element_name, "component-role",
              NULL))) {
    GST_DEBUG ("Using component-role '%s' for element '%s'", component_role,
        element_name);
    audioenc_class->component_role = component_role;
  }


  /* Now set the inport/outport indizes and assume sane defaults */
  err = NULL;
  in_port_index =
      g_key_file_get_integer (config, element_name, "in-port-index", &err);
  if (err != NULL) {
    GST_DEBUG ("No 'in-port-index' set for element '%s', assuming 0: %s",
        element_name, err->message);
    in_port_index = 0;
    g_error_free (err);
  }
  audioenc_class->in_port_index = in_port_index;

  err = NULL;
  out_port_index =
      g_key_file_get_integer (config, element_name, "out-port-index", &err);
  if (err != NULL) {
    GST_DEBUG ("No 'out-port-index' set for element '%s', assuming 1: %s",
        element_name, err->message);
    out_port_index = 1;
    g_error_free (err);
  }
  audioenc_class->out_port_index = out_port_index;

  /* Add pad templates */
  err = NULL;
  if (!(template_caps =
          g_key_file_get_string (config, element_name, "sink-template-caps",
              &err))) {
    GST_DEBUG
        ("No sink template caps specified for element '%s', using default '%s'",
        element_name, audioenc_class->default_sink_template_caps);
    caps = gst_caps_from_string (audioenc_class->default_sink_template_caps);
    g_assert (caps != NULL);
    g_error_free (err);
  } else {
    caps = gst_caps_from_string (template_caps);
    if (!caps) {
      GST_DEBUG
          ("Could not parse sink template caps '%s' for element '%s', using default '%s'",
          template_caps, element_name,
          audioenc_class->default_sink_template_caps);
      caps = gst_caps_from_string (audioenc_class->default_sink_template_caps);
      g_assert (caps != NULL);
    }
  }
  templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
  g_free (template_caps);
  gst_element_class_add_pad_template (element_class, templ);
  gst_object_unref (templ);

  err = NULL;
  if (!(template_caps =
          g_key_file_get_string (config, element_name, "src-template-caps",
              &err))) {
    GST_DEBUG
        ("No src template caps specified for element '%s', using default '%s'",
        element_name, audioenc_class->default_src_template_caps);
    caps = gst_caps_from_string (audioenc_class->default_src_template_caps);
    g_assert (caps != NULL);
    g_error_free (err);
  } else {
    caps = gst_caps_from_string (template_caps);
    if (!caps) {
      GST_DEBUG
          ("Could not parse src template caps '%s' for element '%s', using default '%s'",
          template_caps, element_name,
          audioenc_class->default_src_template_caps);
      caps = gst_caps_from_string (audioenc_class->default_src_template_caps);
      g_assert (caps != NULL);
    }
  }
  templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
  g_free (template_caps);
  gst_element_class_add_pad_template (element_class, templ);
  gst_object_unref (templ);

  if ((hacks =
          g_key_file_get_string_list (config, element_name, "hacks", NULL,
              NULL))) {
#ifndef GST_DISABLE_GST_DEBUG
    gchar **walk = hacks;

    while (*walk) {
      GST_DEBUG ("Using hack: %s", *walk);
      walk++;
    }
#endif

    audioenc_class->hacks = gst_omx_parse_hacks (hacks);
  }
}

static void
gst_omx_audio_enc_class_init (GstOMXAudioEncClass * klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
  GstBaseAudioEncoderClass *base_audio_encoder_class =
      GST_BASE_AUDIO_ENCODER_CLASS (klass);

  gobject_class->finalize = gst_omx_audio_enc_finalize;

  element_class->change_state =
      GST_DEBUG_FUNCPTR (gst_omx_audio_enc_change_state);

  base_audio_encoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_audio_enc_start);
  base_audio_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_audio_enc_stop);
  base_audio_encoder_class->flush = GST_DEBUG_FUNCPTR (gst_omx_audio_enc_flush);
  base_audio_encoder_class->set_format =
      GST_DEBUG_FUNCPTR (gst_omx_audio_enc_set_format);
  base_audio_encoder_class->handle_frame =
      GST_DEBUG_FUNCPTR (gst_omx_audio_enc_handle_frame);
  base_audio_encoder_class->event = GST_DEBUG_FUNCPTR (gst_omx_audio_enc_event);

  klass->default_sink_template_caps = "audio/x-raw-int, "
      "rate = (int) [ 1, MAX ], "
      "channels = (int) [ 1, " G_STRINGIFY (OMX_AUDIO_MAXCHANNELS) " ], "
      "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
      "width = (int) 8, "
      "depth = (int) 8, "
      "signed = (boolean) { true, false }; "
      "audio/x-raw-int, "
      "rate = (int) [ 1, MAX ], "
      "channels = (int) [ 1, " G_STRINGIFY (OMX_AUDIO_MAXCHANNELS) " ], "
      "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
      "width = (int) 16, "
      "depth = (int) 16, "
      "signed = (boolean) { true, false }; "
      "audio/x-raw-int, "
      "rate = (int) [ 1, MAX ], "
      "channels = (int) [ 1, " G_STRINGIFY (OMX_AUDIO_MAXCHANNELS) " ], "
      "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
      "width = (int) 24, "
      "depth = (int) 24, "
      "signed = (boolean) { true, false }; "
      "audio/x-raw-int, "
      "rate = (int) [ 1, MAX ], "
      "channels = (int) [ 1, " G_STRINGIFY (OMX_AUDIO_MAXCHANNELS) " ], "
      "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
      "width = (int) 32, "
      "depth = (int) 32, " "signed = (boolean) { true, false }";

}

static void
gst_omx_audio_enc_init (GstOMXAudioEnc * self, GstOMXAudioEncClass * klass)
{
  self->drain_lock = g_mutex_new ();
  self->drain_cond = g_cond_new ();
}

static gboolean
gst_omx_audio_enc_open (GstOMXAudioEnc * self)
{
  GstOMXAudioEncClass *klass = GST_OMX_AUDIO_ENC_GET_CLASS (self);

  self->component =
      gst_omx_component_new (GST_OBJECT_CAST (self), klass->core_name,
      klass->component_name, klass->component_role, klass->hacks);
  self->started = FALSE;

  if (!self->component)
    return FALSE;

  if (gst_omx_component_get_state (self->component,
          GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
    return FALSE;

  self->in_port =
      gst_omx_component_add_port (self->component, klass->in_port_index);
  self->out_port =
      gst_omx_component_add_port (self->component, klass->out_port_index);

  if (!self->in_port || !self->out_port)
    return FALSE;

  return TRUE;
}


static gboolean
gst_omx_audio_enc_shutdown (GstOMXAudioEnc * self)
{
  OMX_STATETYPE state;

  GST_DEBUG_OBJECT (self, "Shutting down encoder");

  state = gst_omx_component_get_state (self->component, 0);
  if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
    if (state > OMX_StateIdle) {
      gst_omx_component_set_state (self->component, OMX_StateIdle);
      gst_omx_component_get_state (self->component, 5 * GST_SECOND);
    }
    gst_omx_component_set_state (self->component, OMX_StateLoaded);
    gst_omx_port_deallocate_buffers (self->in_port);
    gst_omx_port_deallocate_buffers (self->out_port);
    if (state > OMX_StateLoaded)
      gst_omx_component_get_state (self->component, 5 * GST_SECOND);
  }

  return TRUE;
}

static gboolean
gst_omx_audio_enc_close (GstOMXAudioEnc * self)
{
  GST_DEBUG_OBJECT (self, "Closing encoder");

  if (!gst_omx_audio_enc_shutdown (self))
    return FALSE;

  self->in_port = NULL;
  self->out_port = NULL;
  if (self->component)
    gst_omx_component_free (self->component);
  self->component = NULL;

  return TRUE;
}

static void
gst_omx_audio_enc_finalize (GObject * object)
{
  GstOMXAudioEnc *self = GST_OMX_AUDIO_ENC (object);

  g_mutex_free (self->drain_lock);
  g_cond_free (self->drain_cond);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static GstStateChangeReturn
gst_omx_audio_enc_change_state (GstElement * element, GstStateChange transition)
{
  GstOMXAudioEnc *self;
  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;

  g_return_val_if_fail (GST_IS_OMX_AUDIO_ENC (element),
      GST_STATE_CHANGE_FAILURE);
  self = GST_OMX_AUDIO_ENC (element);

  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      if (!gst_omx_audio_enc_open (self))
        ret = GST_STATE_CHANGE_FAILURE;
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      if (self->in_port)
        gst_omx_port_set_flushing (self->in_port, FALSE);
      if (self->out_port)
        gst_omx_port_set_flushing (self->out_port, FALSE);
      self->downstream_flow_ret = GST_FLOW_OK;

      self->draining = FALSE;
      self->started = FALSE;
      break;
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
      break;
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      if (self->in_port)
        gst_omx_port_set_flushing (self->in_port, TRUE);
      if (self->out_port)
        gst_omx_port_set_flushing (self->out_port, TRUE);

      g_mutex_lock (self->drain_lock);
      self->draining = FALSE;
      g_cond_broadcast (self->drain_cond);
      g_mutex_unlock (self->drain_lock);
      break;
    default:
      break;
  }

  if (ret == GST_STATE_CHANGE_FAILURE)
    return ret;

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  if (ret == GST_STATE_CHANGE_FAILURE)
    return ret;

  switch (transition) {
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
      break;
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      self->downstream_flow_ret = GST_FLOW_WRONG_STATE;
      self->started = FALSE;

      if (!gst_omx_audio_enc_shutdown (self))
        ret = GST_STATE_CHANGE_FAILURE;
      break;
    case GST_STATE_CHANGE_READY_TO_NULL:
      if (!gst_omx_audio_enc_close (self))
        ret = GST_STATE_CHANGE_FAILURE;
      break;
    default:
      break;
  }

  return ret;
}

static void
gst_omx_audio_enc_loop (GstOMXAudioEnc * self)
{
  GstOMXAudioEncClass *klass;
  GstOMXPort *port = self->out_port;
  GstOMXBuffer *buf = NULL;
  GstFlowReturn flow_ret = GST_FLOW_OK;
  GstOMXAcquireBufferReturn acq_return;

  klass = GST_OMX_AUDIO_ENC_GET_CLASS (self);

  acq_return = gst_omx_port_acquire_buffer (port, &buf);
  if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
    goto component_error;
  } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
    goto flushing;
  } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
    if (gst_omx_port_reconfigure (self->out_port) != OMX_ErrorNone)
      goto reconfigure_error;
    /* And restart the loop */
    return;
  }

  if (!GST_PAD_CAPS (GST_BASE_AUDIO_ENCODER_SRC_PAD (self))
      || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURED) {
    GstAudioState *state = &GST_BASE_AUDIO_ENCODER (self)->ctx->state;
    GstCaps *caps;

    GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");

    GST_BASE_AUDIO_ENCODER_STREAM_LOCK (self);
    caps = klass->get_caps (self, self->out_port, state);
    if (!caps) {
      if (buf)
        gst_omx_port_release_buffer (self->out_port, buf);
      GST_BASE_AUDIO_ENCODER_STREAM_UNLOCK (self);
      goto caps_failed;
    }

    if (!gst_pad_set_caps (GST_BASE_AUDIO_ENCODER_SRC_PAD (self), caps)) {
      gst_caps_unref (caps);
      if (buf)
        gst_omx_port_release_buffer (self->out_port, buf);
      GST_BASE_AUDIO_ENCODER_STREAM_UNLOCK (self);
      goto caps_failed;
    }
    gst_caps_unref (caps);
    GST_BASE_AUDIO_ENCODER_STREAM_UNLOCK (self);

    /* Now get a buffer */
    if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK)
      return;
  }

  g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);

  GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %lu", buf->omx_buf->nFlags,
      buf->omx_buf->nTimeStamp);

  GST_BASE_AUDIO_ENCODER_STREAM_LOCK (self);
  if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG)
      && buf->omx_buf->nFilledLen > 0) {
    GstCaps *caps;
    GstBuffer *codec_data;

    caps = gst_caps_copy (GST_PAD_CAPS (GST_BASE_AUDIO_ENCODER_SRC_PAD (self)));
    codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
    memcpy (GST_BUFFER_DATA (codec_data),
        buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
        buf->omx_buf->nFilledLen);

    gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
    if (!gst_pad_set_caps (GST_BASE_AUDIO_ENCODER_SRC_PAD (self), caps)) {
      gst_caps_unref (caps);
      if (buf)
        gst_omx_port_release_buffer (self->out_port, buf);
      GST_BASE_AUDIO_ENCODER_STREAM_UNLOCK (self);
      goto caps_failed;
    }
    gst_caps_unref (caps);
    flow_ret = GST_FLOW_OK;
  } else if (buf->omx_buf->nFilledLen > 0) {
    GstBuffer *outbuf;
    guint n_samples;

    n_samples =
        klass->get_num_samples (self, self->out_port,
        &GST_BASE_AUDIO_ENCODER (self)->ctx->state, buf);

    if (buf->omx_buf->nFilledLen > 0) {
      outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);

      memcpy (GST_BUFFER_DATA (outbuf),
          buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
          buf->omx_buf->nFilledLen);
    } else {
      outbuf = gst_buffer_new ();
    }

    gst_buffer_set_caps (outbuf,
        GST_PAD_CAPS (GST_BASE_AUDIO_ENCODER_SRC_PAD (self)));

    GST_BUFFER_TIMESTAMP (outbuf) =
        gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND,
        OMX_TICKS_PER_SECOND);
    if (buf->omx_buf->nTickCount != 0)
      GST_BUFFER_DURATION (outbuf) =
          gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND,
          OMX_TICKS_PER_SECOND);

    flow_ret =
        gst_base_audio_encoder_finish_frame (GST_BASE_AUDIO_ENCODER (self),
        outbuf, n_samples);
  }

  if ((flow_ret == GST_FLOW_OK && (buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS))
      || flow_ret == GST_FLOW_UNEXPECTED) {<commit_msg>omxaudioenc: Signal the drain GCond even if downstream returned an error<commit_after>/*
 * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
 *   Author: <NAME> <<EMAIL>>, Collabora Ltd.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation
 * version 2.1 of the License.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gst/gst.h>
#include <string.h>

#include "gstomxaudioenc.h"

GST_DEBUG_CATEGORY_STATIC (gst_omx_audio_enc_debug_category);
#define GST_CAT_DEFAULT gst_omx_audio_enc_debug_category

/* prototypes */
static void gst_omx_audio_enc_finalize (GObject * object);

static GstStateChangeReturn
gst_omx_audio_enc_change_state (GstElement * element,
    GstStateChange transition);

static gboolean gst_omx_audio_enc_start (GstBaseAudioEncoder * encoder);
static gboolean gst_omx_audio_enc_stop (GstBaseAudioEncoder * encoder);
static gboolean gst_omx_audio_enc_set_format (GstBaseAudioEncoder * encoder,
    GstAudioState * state);
static gboolean gst_omx_audio_enc_event (GstBaseAudioEncoder * encoder,
    GstEvent * event);
static GstFlowReturn gst_omx_audio_enc_handle_frame (GstBaseAudioEncoder *
    encoder, GstBuffer * buffer);
static void gst_omx_audio_enc_flush (GstBaseAudioEncoder * encoder);

static GstFlowReturn gst_omx_audio_enc_drain (GstOMXAudioEnc * self);

enum
{
  PROP_0
};

/* class initialization */

#define DEBUG_INIT(bla) \
  GST_DEBUG_CATEGORY_INIT (gst_omx_audio_enc_debug_category, "omxaudioenc", 0, \
      "debug category for gst-omx audio encoder base class");

GST_BOILERPLATE_FULL (GstOMXAudioEnc, gst_omx_audio_enc, GstBaseAudioEncoder,
    GST_TYPE_BASE_AUDIO_ENCODER, DEBUG_INIT);

static void
gst_omx_audio_enc_base_init (gpointer g_class)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
  GstOMXAudioEncClass *audioenc_class = GST_OMX_AUDIO_ENC_CLASS (g_class);
  GKeyFile *config;
  const gchar *element_name;
  GError *err;
  gchar *core_name, *component_name, *component_role;
  gint in_port_index, out_port_index;
  gchar *template_caps;
  GstPadTemplate *templ;
  GstCaps *caps;
  gchar **hacks;

  element_name =
      g_type_get_qdata (G_TYPE_FROM_CLASS (g_class),
      gst_omx_element_name_quark);
  /* This happens for the base class and abstract subclasses */
  if (!element_name)
    return;

  config = gst_omx_get_configuration ();

  /* This will always succeed, see check in plugin_init */
  core_name = g_key_file_get_string (config, element_name, "core-name", NULL);
  g_assert (core_name != NULL);
  audioenc_class->core_name = core_name;
  component_name =
      g_key_file_get_string (config, element_name, "component-name", NULL);
  g_assert (component_name != NULL);
  audioenc_class->component_name = component_name;

  /* If this fails we simply don't set a role */
  if ((component_role =
          g_key_file_get_string (config, element_name, "component-role",
              NULL))) {
    GST_DEBUG ("Using component-role '%s' for element '%s'", component_role,
        element_name);
    audioenc_class->component_role = component_role;
  }


  /* Now set the inport/outport indizes and assume sane defaults */
  err = NULL;
  in_port_index =
      g_key_file_get_integer (config, element_name, "in-port-index", &err);
  if (err != NULL) {
    GST_DEBUG ("No 'in-port-index' set for element '%s', assuming 0: %s",
        element_name, err->message);
    in_port_index = 0;
    g_error_free (err);
  }
  audioenc_class->in_port_index = in_port_index;

  err = NULL;
  out_port_index =
      g_key_file_get_integer (config, element_name, "out-port-index", &err);
  if (err != NULL) {
    GST_DEBUG ("No 'out-port-index' set for element '%s', assuming 1: %s",
        element_name, err->message);
    out_port_index = 1;
    g_error_free (err);
  }
  audioenc_class->out_port_index = out_port_index;

  /* Add pad templates */
  err = NULL;
  if (!(template_caps =
          g_key_file_get_string (config, element_name, "sink-template-caps",
              &err))) {
    GST_DEBUG
        ("No sink template caps specified for element '%s', using default '%s'",
        element_name, audioenc_class->default_sink_template_caps);
    caps = gst_caps_from_string (audioenc_class->default_sink_template_caps);
    g_assert (caps != NULL);
    g_error_free (err);
  } else {
    caps = gst_caps_from_string (template_caps);
    if (!caps) {
      GST_DEBUG
          ("Could not parse sink template caps '%s' for element '%s', using default '%s'",
          template_caps, element_name,
          audioenc_class->default_sink_template_caps);
      caps = gst_caps_from_string (audioenc_class->default_sink_template_caps);
      g_assert (caps != NULL);
    }
  }
  templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
  g_free (template_caps);
  gst_element_class_add_pad_template (element_class, templ);
  gst_object_unref (templ);

  err = NULL;
  if (!(template_caps =
          g_key_file_get_string (config, element_name, "src-template-caps",
              &err))) {
    GST_DEBUG
        ("No src template caps specified for element '%s', using default '%s'",
        element_name, audioenc_class->default_src_template_caps);
    caps = gst_caps_from_string (audioenc_class->default_src_template_caps);
    g_assert (caps != NULL);
    g_error_free (err);
  } else {
    caps = gst_caps_from_string (template_caps);
    if (!caps) {
      GST_DEBUG
          ("Could not parse src template caps '%s' for element '%s', using default '%s'",
          template_caps, element_name,
          audioenc_class->default_src_template_caps);
      caps = gst_caps_from_string (audioenc_class->default_src_template_caps);
      g_assert (caps != NULL);
    }
  }
  templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
  g_free (template_caps);
  gst_element_class_add_pad_template (element_class, templ);
  gst_object_unref (templ);

  if ((hacks =
          g_key_file_get_string_list (config, element_name, "hacks", NULL,
              NULL))) {
#ifndef GST_DISABLE_GST_DEBUG
    gchar **walk = hacks;

    while (*walk) {
      GST_DEBUG ("Using hack: %s", *walk);
      walk++;
    }
#endif

    audioenc_class->hacks = gst_omx_parse_hacks (hacks);
  }
}

static void
gst_omx_audio_enc_class_init (GstOMXAudioEncClass * klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
  GstBaseAudioEncoderClass *base_audio_encoder_class =
      GST_BASE_AUDIO_ENCODER_CLASS (klass);

  gobject_class->finalize = gst_omx_audio_enc_finalize;

  element_class->change_state =
      GST_DEBUG_FUNCPTR (gst_omx_audio_enc_change_state);

  base_audio_encoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_audio_enc_start);
  base_audio_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_audio_enc_stop);
  base_audio_encoder_class->flush = GST_DEBUG_FUNCPTR (gst_omx_audio_enc_flush);
  base_audio_encoder_class->set_format =
      GST_DEBUG_FUNCPTR (gst_omx_audio_enc_set_format);
  base_audio_encoder_class->handle_frame =
      GST_DEBUG_FUNCPTR (gst_omx_audio_enc_handle_frame);
  base_audio_encoder_class->event = GST_DEBUG_FUNCPTR (gst_omx_audio_enc_event);

  klass->default_sink_template_caps = "audio/x-raw-int, "
      "rate = (int) [ 1, MAX ], "
      "channels = (int) [ 1, " G_STRINGIFY (OMX_AUDIO_MAXCHANNELS) " ], "
      "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
      "width = (int) 8, "
      "depth = (int) 8, "
      "signed = (boolean) { true, false }; "
      "audio/x-raw-int, "
      "rate = (int) [ 1, MAX ], "
      "channels = (int) [ 1, " G_STRINGIFY (OMX_AUDIO_MAXCHANNELS) " ], "
      "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
      "width = (int) 16, "
      "depth = (int) 16, "
      "signed = (boolean) { true, false }; "
      "audio/x-raw-int, "
      "rate = (int) [ 1, MAX ], "
      "channels = (int) [ 1, " G_STRINGIFY (OMX_AUDIO_MAXCHANNELS) " ], "
      "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
      "width = (int) 24, "
      "depth = (int) 24, "
      "signed = (boolean) { true, false }; "
      "audio/x-raw-int, "
      "rate = (int) [ 1, MAX ], "
      "channels = (int) [ 1, " G_STRINGIFY (OMX_AUDIO_MAXCHANNELS) " ], "
      "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
      "width = (int) 32, "
      "depth = (int) 32, " "signed = (boolean) { true, false }";

}

static void
gst_omx_audio_enc_init (GstOMXAudioEnc * self, GstOMXAudioEncClass * klass)
{
  self->drain_lock = g_mutex_new ();
  self->drain_cond = g_cond_new ();
}

static gboolean
gst_omx_audio_enc_open (GstOMXAudioEnc * self)
{
  GstOMXAudioEncClass *klass = GST_OMX_AUDIO_ENC_GET_CLASS (self);

  self->component =
      gst_omx_component_new (GST_OBJECT_CAST (self), klass->core_name,
      klass->component_name, klass->component_role, klass->hacks);
  self->started = FALSE;

  if (!self->component)
    return FALSE;

  if (gst_omx_component_get_state (self->component,
          GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
    return FALSE;

  self->in_port =
      gst_omx_component_add_port (self->component, klass->in_port_index);
  self->out_port =
      gst_omx_component_add_port (self->component, klass->out_port_index);

  if (!self->in_port || !self->out_port)
    return FALSE;

  return TRUE;
}


static gboolean
gst_omx_audio_enc_shutdown (GstOMXAudioEnc * self)
{
  OMX_STATETYPE state;

  GST_DEBUG_OBJECT (self, "Shutting down encoder");

  state = gst_omx_component_get_state (self->component, 0);
  if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
    if (state > OMX_StateIdle) {
      gst_omx_component_set_state (self->component, OMX_StateIdle);
      gst_omx_component_get_state (self->component, 5 * GST_SECOND);
    }
    gst_omx_component_set_state (self->component, OMX_StateLoaded);
    gst_omx_port_deallocate_buffers (self->in_port);
    gst_omx_port_deallocate_buffers (self->out_port);
    if (state > OMX_StateLoaded)
      gst_omx_component_get_state (self->component, 5 * GST_SECOND);
  }

  return TRUE;
}

static gboolean
gst_omx_audio_enc_close (GstOMXAudioEnc * self)
{
  GST_DEBUG_OBJECT (self, "Closing encoder");

  if (!gst_omx_audio_enc_shutdown (self))
    return FALSE;

  self->in_port = NULL;
  self->out_port = NULL;
  if (self->component)
    gst_omx_component_free (self->component);
  self->component = NULL;

  return TRUE;
}

static void
gst_omx_audio_enc_finalize (GObject * object)
{
  GstOMXAudioEnc *self = GST_OMX_AUDIO_ENC (object);

  g_mutex_free (self->drain_lock);
  g_cond_free (self->drain_cond);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static GstStateChangeReturn
gst_omx_audio_enc_change_state (GstElement * element, GstStateChange transition)
{
  GstOMXAudioEnc *self;
  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;

  g_return_val_if_fail (GST_IS_OMX_AUDIO_ENC (element),
      GST_STATE_CHANGE_FAILURE);
  self = GST_OMX_AUDIO_ENC (element);

  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      if (!gst_omx_audio_enc_open (self))
        ret = GST_STATE_CHANGE_FAILURE;
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      if (self->in_port)
        gst_omx_port_set_flushing (self->in_port, FALSE);
      if (self->out_port)
        gst_omx_port_set_flushing (self->out_port, FALSE);
      self->downstream_flow_ret = GST_FLOW_OK;

      self->draining = FALSE;
      self->started = FALSE;
      break;
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
      break;
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      if (self->in_port)
        gst_omx_port_set_flushing (self->in_port, TRUE);
      if (self->out_port)
        gst_omx_port_set_flushing (self->out_port, TRUE);

      g_mutex_lock (self->drain_lock);
      self->draining = FALSE;
      g_cond_broadcast (self->drain_cond);
      g_mutex_unlock (self->drain_lock);
      break;
    default:
      break;
  }

  if (ret == GST_STATE_CHANGE_FAILURE)
    return ret;

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  if (ret == GST_STATE_CHANGE_FAILURE)
    return ret;

  switch (transition) {
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
      break;
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      self->downstream_flow_ret = GST_FLOW_WRONG_STATE;
      self->started = FALSE;

      if (!gst_omx_audio_enc_shutdown (self))
        ret = GST_STATE_CHANGE_FAILURE;
      break;
    case GST_STATE_CHANGE_READY_TO_NULL:
      if (!gst_omx_audio_enc_close (self))
        ret = GST_STATE_CHANGE_FAILURE;
      break;
    default:
      break;
  }

  return ret;
}

static void
gst_omx_audio_enc_loop (GstOMXAudioEnc * self)
{
  GstOMXAudioEncClass *klass;
  GstOMXPort *port = self->out_port;
  GstOMXBuffer *buf = NULL;
  GstFlowReturn flow_ret = GST_FLOW_OK;
  GstOMXAcquireBufferReturn acq_return;
  gboolean is_eos;

  klass = GST_OMX_AUDIO_ENC_GET_CLASS (self);

  acq_return = gst_omx_port_acquire_buffer (port, &buf);
  if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
    goto component_error;
  } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
    goto flushing;
  } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
    if (gst_omx_port_reconfigure (self->out_port) != OMX_ErrorNone)
      goto reconfigure_error;
    /* And restart the loop */
    return;
  }

  if (!GST_PAD_CAPS (GST_BASE_AUDIO_ENCODER_SRC_PAD (self))
      || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURED) {
    GstAudioState *state = &GST_BASE_AUDIO_ENCODER (self)->ctx->state;
    GstCaps *caps;

    GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");

    GST_BASE_AUDIO_ENCODER_STREAM_LOCK (self);
    caps = klass->get_caps (self, self->out_port, state);
    if (!caps) {
      if (buf)
        gst_omx_port_release_buffer (self->out_port, buf);
      GST_BASE_AUDIO_ENCODER_STREAM_UNLOCK (self);
      goto caps_failed;
    }

    if (!gst_pad_set_caps (GST_BASE_AUDIO_ENCODER_SRC_PAD (self), caps)) {
      gst_caps_unref (caps);
      if (buf)
        gst_omx_port_release_buffer (self->out_port, buf);
      GST_BASE_AUDIO_ENCODER_STREAM_UNLOCK (self);
      goto caps_failed;
    }
    gst_caps_unref (caps);
    GST_BASE_AUDIO_ENCODER_STREAM_UNLOCK (self);

    /* Now get a buffer */
    if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK)
      return;
  }

  g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);

  GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %lu", buf->omx_buf->nFlags,
      buf->omx_buf->nTimeStamp);

  GST_BASE_AUDIO_ENCODER_STREAM_LOCK (self);
  is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS);

  if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG)
      && buf->omx_buf->nFilledLen > 0) {
    GstCaps *caps;
    GstBuffer *codec_data;

    caps = gst_caps_copy (GST_PAD_CAPS (GST_BASE_AUDIO_ENCODER_SRC_PAD (self)));
    codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
    memcpy (GST_BUFFER_DATA (codec_data),
        buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
        buf->omx_buf->nFilledLen);

    gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
    if (!gst_pad_set_caps (GST_BASE_AUDIO_ENCODER_SRC_PAD (self), caps)) {
      gst_caps_unref (caps);
      if (buf)
        gst_omx_port_release_buffer (self->out_port, buf);
      GST_BASE_AUDIO_ENCODER_STREAM_UNLOCK (self);
      goto caps_failed;
    }
    gst_caps_unref (caps);
    flow_ret = GST_FLOW_OK;
  } else if (buf->omx_buf->nFilledLen > 0) {
    GstBuffer *outbuf;
    guint n_samples;

    n_samples =
        klass->get_num_samples (self, self->out_port,
        &GST_BASE_AUDIO_ENCODER (self)->ctx->state, buf);

    if (buf->omx_buf->nFilledLen > 0) {
      outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);

      memcpy (GST_BUFFER_DATA (outbuf),
          buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
          buf->omx_buf->nFilledLen);
    } else {
      outbuf = gst_buffer_new ();
    }

    gst_buffer_set_caps (outbuf,
        GST_PAD_CAPS (GST_BASE_AUDIO_ENCODER_SRC_PAD (self)));

    GST_BUFFER_TIMESTAMP (outbuf) =
        gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND,
        OMX_TICKS_PER_SECOND);
    if (buf->omx_buf->nTickCount != 0)
      GST_BUFFER_DURATION (outbuf) =
          gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND,
          OMX_TICKS_PER_SECOND);

    flow_ret =
        gst_base_audio_encoder_finish_frame (GST_BASE_AUDIO_ENCODER (self),
        outbuf, n_samples);
  }

  if (is_eos || flow_ret == GST_FLOW_UNEXPECTED) {
{'fraction_non_alphanumeric': 0.10567583382094792, 'fraction_numerical': 0.0034523112931538914, 'mean_word_length': 3.8927855711422845, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 275, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7180173', 'n_tokens_mistral': 13010, 'n_tokens_neox': 12672, 'n_words': 2434}