static void
output_loop (gpointer data)
{
    GstPad *pad;
    GOmxCore *gomx;
    GOmxPort *out_port;
    GstOmxBaseFilter *self;
    GstFlowReturn ret = GST_FLOW_OK;

    pad = data;
    self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad));
    gomx = self->gomx;

    GST_LOG_OBJECT (self, "begin");

    /* do not bother if we have been setup to bail out */
    if ((ret = g_atomic_int_get (&self->last_pad_push_return)) != GST_FLOW_OK)
        goto leave;

    if (!self->ready)
    {
        g_error ("not ready");
        return;
    }

    out_port = self->out_port;

    if (G_LIKELY (out_port->enabled))
    {
        OMX_BUFFERHEADERTYPE *omx_buffer = NULL;

        GST_LOG_OBJECT (self, "request buffer");
        omx_buffer = g_omx_port_request_buffer (out_port);

        GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);

        if (G_UNLIKELY (!omx_buffer))
        {
            GST_WARNING_OBJECT (self, "null buffer: leaving");
            ret = GST_FLOW_WRONG_STATE;
            goto leave;
        }

        log_buffer (self, omx_buffer);

        if (G_LIKELY (omx_buffer->nFilledLen > 0))
        {
            GstBuffer *buf;

#if 1
            /** @todo remove this check */
            if (G_LIKELY (self->in_port->enabled))
            {
                GstCaps *caps = NULL;

                caps = gst_pad_get_negotiated_caps (self->srcpad);

                if (!caps)
                {
                    /** @todo We shouldn't be doing this. */
                    GST_WARNING_OBJECT (self, "faking settings changed notification");
                    if (gomx->settings_changed_cb)
                        gomx->settings_changed_cb (gomx);
                }
                else
                {
                    GST_LOG_OBJECT (self, "caps already fixed: %" GST_PTR_FORMAT, caps);
                    gst_caps_unref (caps);
                }
            }
#endif

            /* buf is always null when the output buffer pointer isn't shared. */
            buf = omx_buffer->pAppPrivate;

            /** @todo we need to move all the caps handling to one single
             * place, in the output loop probably. */
            if (G_UNLIKELY (omx_buffer->nFlags & 0x80))
            {
                GstCaps *caps = NULL;
                GstStructure *structure;
                GValue value = { 0 };

                caps = gst_pad_get_negotiated_caps (self->srcpad);
                caps = gst_caps_make_writable (caps);
                structure = gst_caps_get_structure (caps, 0);

                g_value_init (&value, GST_TYPE_BUFFER);
                buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
                memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
                gst_value_set_buffer (&value, buf);
                gst_buffer_unref (buf);
                gst_structure_set_value (structure, "codec_data", &value);
                g_value_unset (&value);

                gst_pad_set_caps (self->srcpad, caps);
            }
            else if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS))
            {
                GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen;
                if (self->use_timestamps)
                {
                    GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (omx_buffer->nTimeStamp,
                                                                            GST_SECOND,
                                                                            OMX_TICKS_PER_SECOND);
                }

                omx_buffer->pAppPrivate = NULL;
                omx_buffer->pBuffer = NULL;

                ret = push_buffer (self, buf);

                gst_buffer_unref (buf);
            }
            else
            {
                /* This is only meant for the first OpenMAX buffers,
                 * which need to be pre-allocated. */
                /* Also for the very last one. */
                ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
                                                         GST_BUFFER_OFFSET_NONE,
                                                         omx_buffer->nFilledLen,
                                                         GST_PAD_CAPS (self->srcpad),
                                                         &buf);

                if (G_LIKELY (buf))
                {
                    memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
                    if (self->use_timestamps)
                    {
                        GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (omx_buffer->nTimeStamp,
                                                                                GST_SECOND,
                                                                                OMX_TICKS_PER_SECOND);
                    }

                    if (self->share_output_buffer)
                    {
                        GST_WARNING_OBJECT (self, "couldn't zero-copy");
                        /* If pAppPrivate is NULL, it means it was a dummy
                         * allocation, free it. */
                        if (!omx_buffer->pAppPrivate)
                        {
                            g_free (omx_buffer->pBuffer);
                            omx_buffer->pBuffer = NULL;
                        }
                    }

                    ret = push_buffer (self, buf);
                }
                else
                {
                    GST_WARNING_OBJECT (self, "couldn't allocate buffer of size %" G_GUINT32_FORMAT,
                                        omx_buffer->nFilledLen);
                }
            }
        }
        else
        {
            GST_WARNING_OBJECT (self, "empty buffer");
        }

        if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS))
        {
            GST_DEBUG_OBJECT (self, "got eos");
            gst_pad_push_event (self->srcpad, gst_event_new_eos ());
            ret = GST_FLOW_UNEXPECTED;
            goto leave;
        }

        if (self->share_output_buffer &&
            !omx_buffer->pBuffer &&
            omx_buffer->nOffset == 0)
        {
            GstBuffer *buf;
            GstFlowReturn result;

            GST_LOG_OBJECT (self, "allocate buffer");
            result = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
                                                        GST_BUFFER_OFFSET_NONE,
                                                        omx_buffer->nAllocLen,
                                                        GST_PAD_CAPS (self->srcpad),
                                                        &buf);

            if (G_LIKELY (result == GST_FLOW_OK))
            {
                gst_buffer_ref (buf);
                omx_buffer->pAppPrivate = buf;

                omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
                omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
            }
            else
            {
                GST_WARNING_OBJECT (self, "could not pad allocate buffer, using malloc");
                omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen);
            }
        }

        if (self->share_output_buffer &&
            !omx_buffer->pBuffer)
        {
            GST_ERROR_OBJECT (self, "no input buffer to share");
        }

        omx_buffer->nFilledLen = 0;
        GST_LOG_OBJECT (self, "release_buffer");
        g_omx_port_release_buffer (out_port, omx_buffer);
    }

leave:

    self->last_pad_push_return = ret;

    if (gomx->omx_error != OMX_ErrorNone)
        ret = GST_FLOW_ERROR;

    if (ret != GST_FLOW_OK)
    {
        GST_INFO_OBJECT (self, "pause task, reason:  %s",
                         gst_flow_get_name (ret));
        gst_pad_pause_task (self->srcpad);
    }

    GST_LOG_OBJECT (self, "end");

    gst_object_unref (self);
}
static void
gst_omx_audio_dec_loop (GstOMXAudioDec * self)
{
  GstOMXPort *port = self->dec_out_port;
  GstOMXBuffer *buf = NULL;
  GstFlowReturn flow_ret = GST_FLOW_OK;
  GstOMXAcquireBufferReturn acq_return;
  OMX_ERRORTYPE err;

  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_EOS) {
    goto eos;
  }

  if (!gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (self)) ||
      acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
    OMX_PARAM_PORTDEFINITIONTYPE port_def;
    OMX_AUDIO_PARAM_PCMMODETYPE pcm_param;
    GstAudioChannelPosition omx_position[OMX_AUDIO_MAXCHANNELS];
    GstOMXAudioDecClass *klass = GST_OMX_AUDIO_DEC_GET_CLASS (self);
    gint i;

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

    /* Reallocate all buffers */
    if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE
        && gst_omx_port_is_enabled (port)) {
      err = gst_omx_port_set_enabled (port, FALSE);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_deallocate_buffers (port);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;
    }

    /* Just update caps */
    GST_AUDIO_DECODER_STREAM_LOCK (self);

    gst_omx_port_get_port_definition (port, &port_def);
    g_assert (port_def.format.audio.eEncoding == OMX_AUDIO_CodingPCM);

    GST_OMX_INIT_STRUCT (&pcm_param);
    pcm_param.nPortIndex = self->dec_out_port->index;
    err =
        gst_omx_component_get_parameter (self->dec, OMX_IndexParamAudioPcm,
        &pcm_param);
    if (err != OMX_ErrorNone) {
      GST_ERROR_OBJECT (self, "Failed to get PCM parameters: %s (0x%08x)",
          gst_omx_error_to_string (err), err);
      goto caps_failed;
    }

    g_assert (pcm_param.ePCMMode == OMX_AUDIO_PCMModeLinear);
    g_assert (pcm_param.bInterleaved == OMX_TRUE);

    gst_audio_info_init (&self->info);

    for (i = 0; i < pcm_param.nChannels; i++) {
      switch (pcm_param.eChannelMapping[i]) {
        case OMX_AUDIO_ChannelLF:
          omx_position[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
          break;
        case OMX_AUDIO_ChannelRF:
          omx_position[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
          break;
        case OMX_AUDIO_ChannelCF:
          omx_position[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
          break;
        case OMX_AUDIO_ChannelLS:
          omx_position[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT;
          break;
        case OMX_AUDIO_ChannelRS:
          omx_position[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT;
          break;
        case OMX_AUDIO_ChannelLFE:
          omx_position[i] = GST_AUDIO_CHANNEL_POSITION_LFE1;
          break;
        case OMX_AUDIO_ChannelCS:
          omx_position[i] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER;
          break;
        case OMX_AUDIO_ChannelLR:
          omx_position[i] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
          break;
        case OMX_AUDIO_ChannelRR:
          omx_position[i] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
          break;
        case OMX_AUDIO_ChannelNone:
        default:
          /* This will break the outer loop too as the
           * i == pcm_param.nChannels afterwards */
          for (i = 0; i < pcm_param.nChannels; i++)
            omx_position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
          break;
      }
    }
    if (pcm_param.nChannels == 1
        && omx_position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER)
      omx_position[0] = GST_AUDIO_CHANNEL_POSITION_MONO;

    if (omx_position[0] == GST_AUDIO_CHANNEL_POSITION_NONE
        && klass->get_channel_positions) {
      GST_WARNING_OBJECT (self,
          "Failed to get a valid channel layout, trying fallback");
      klass->get_channel_positions (self, self->dec_out_port, omx_position);
    }

    memcpy (self->position, omx_position, sizeof (omx_position));
    gst_audio_channel_positions_to_valid_order (self->position,
        pcm_param.nChannels);
    self->needs_reorder =
        (memcmp (self->position, omx_position,
            sizeof (GstAudioChannelPosition) * pcm_param.nChannels) != 0);
    if (self->needs_reorder)
      gst_audio_get_channel_reorder_map (pcm_param.nChannels, self->position,
          omx_position, self->reorder_map);

    gst_audio_info_set_format (&self->info,
        gst_audio_format_build_integer (pcm_param.eNumData ==
            OMX_NumericalDataSigned,
            pcm_param.eEndian ==
            OMX_EndianLittle ? G_LITTLE_ENDIAN : G_BIG_ENDIAN,
            pcm_param.nBitPerSample, pcm_param.nBitPerSample),
        pcm_param.nSamplingRate, pcm_param.nChannels, self->position);

    GST_DEBUG_OBJECT (self,
        "Setting output state: format %s, rate %u, channels %u",
        gst_audio_format_to_string (self->info.finfo->format),
        (guint) pcm_param.nSamplingRate, (guint) pcm_param.nChannels);

    if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (self),
            &self->info)
        || !gst_audio_decoder_negotiate (GST_AUDIO_DECODER (self))) {
      if (buf)
        gst_omx_port_release_buffer (port, buf);
      goto caps_failed;
    }

    GST_AUDIO_DECODER_STREAM_UNLOCK (self);

    if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
      err = gst_omx_port_set_enabled (port, TRUE);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_allocate_buffers (port);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_populate (port);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_mark_reconfigured (port);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;
    }

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

  g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
  if (!buf) {
    g_assert ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER));
    GST_AUDIO_DECODER_STREAM_LOCK (self);
    goto eos;
  }

  /* This prevents a deadlock between the srcpad stream
   * lock and the audiocodec stream lock, if ::reset()
   * is called at the wrong time
   */
  if (gst_omx_port_is_flushing (port)) {
    GST_DEBUG_OBJECT (self, "Flushing");
    gst_omx_port_release_buffer (port, buf);
    goto flushing;
  }

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

  GST_AUDIO_DECODER_STREAM_LOCK (self);

  if (buf->omx_buf->nFilledLen > 0) {
    GstBuffer *outbuf;
    gint nframes, spf;
    GstMapInfo minfo;
    GstOMXAudioDecClass *klass = GST_OMX_AUDIO_DEC_GET_CLASS (self);

    GST_DEBUG_OBJECT (self, "Handling output data");

    if (buf->omx_buf->nFilledLen % self->info.bpf != 0) {
      gst_omx_port_release_buffer (port, buf);
      goto invalid_buffer;
    }

    outbuf =
        gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (self),
        buf->omx_buf->nFilledLen);

    gst_buffer_map (outbuf, &minfo, GST_MAP_WRITE);
    if (self->needs_reorder) {
      gint i, n_samples, c, n_channels;
      gint *reorder_map = self->reorder_map;
      gint16 *dest, *source;

      dest = (gint16 *) minfo.data;
      source = (gint16 *) (buf->omx_buf->pBuffer + buf->omx_buf->nOffset);
      n_samples = buf->omx_buf->nFilledLen / self->info.bpf;
      n_channels = self->info.channels;

      for (i = 0; i < n_samples; i++) {
        for (c = 0; c < n_channels; c++) {
          dest[i * n_channels + reorder_map[c]] = source[i * n_channels + c];
        }
      }
    } else {
      memcpy (minfo.data, buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
          buf->omx_buf->nFilledLen);
    }
    gst_buffer_unmap (outbuf, &minfo);

    nframes = 1;
    spf = klass->get_samples_per_frame (self, self->dec_out_port);
    if (spf != -1) {
      nframes = buf->omx_buf->nFilledLen / self->info.bpf;
      if (nframes % spf != 0)
        GST_WARNING_OBJECT (self, "Output buffer does not contain an integer "
            "number of input frames (frames: %d, spf: %d)", nframes, spf);
      nframes = (nframes + spf - 1) / spf;
    }

    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_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf,
        nframes);
  }

  GST_DEBUG_OBJECT (self, "Read frame from component");

  GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));

  if (buf) {
    err = gst_omx_port_release_buffer (port, buf);
    if (err != OMX_ErrorNone)
      goto release_error;
  }

  self->downstream_flow_ret = flow_ret;

  if (flow_ret != GST_FLOW_OK)
    goto flow_error;

  GST_AUDIO_DECODER_STREAM_UNLOCK (self);

  return;

component_error:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
        ("OpenMAX component in error state %s (0x%08x)",
            gst_omx_component_get_last_error_string (self->dec),
            gst_omx_component_get_last_error (self->dec)));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    self->started = FALSE;
    return;
  }

flushing:
  {
    GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_FLUSHING;
    self->started = FALSE;
    return;
  }

eos:
  {
    g_mutex_lock (&self->drain_lock);
    if (self->draining) {
      GST_DEBUG_OBJECT (self, "Drained");
      self->draining = FALSE;
      g_cond_broadcast (&self->drain_cond);
      flow_ret = GST_FLOW_OK;
      gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    } else {
      GST_DEBUG_OBJECT (self, "Component signalled EOS");
      flow_ret = GST_FLOW_EOS;
    }
    g_mutex_unlock (&self->drain_lock);

    GST_AUDIO_DECODER_STREAM_LOCK (self);
    self->downstream_flow_ret = flow_ret;

    /* Here we fallback and pause the task for the EOS case */
    if (flow_ret != GST_FLOW_OK)
      goto flow_error;

    GST_AUDIO_DECODER_STREAM_UNLOCK (self);

    return;
  }

flow_error:
  {
    if (flow_ret == GST_FLOW_EOS) {
      GST_DEBUG_OBJECT (self, "EOS");

      gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self),
          gst_event_new_eos ());
      gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
      self->started = FALSE;
    } else if (flow_ret < GST_FLOW_EOS) {
      GST_ELEMENT_ERROR (self, STREAM, FAILED,
          ("Internal data stream error."), ("stream stopped, reason %s",
              gst_flow_get_name (flow_ret)));

      gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self),
          gst_event_new_eos ());
      gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
      self->started = FALSE;
    } else if (flow_ret == GST_FLOW_FLUSHING) {
      GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
      gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
      self->started = FALSE;
    }
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }

reconfigure_error:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
        ("Unable to reconfigure output port"));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    self->started = FALSE;
    return;
  }

invalid_buffer:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
        ("Invalid sized input buffer"));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
    self->started = FALSE;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }

caps_failed:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps"));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
    self->started = FALSE;
    return;
  }
release_error:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
        ("Failed to relase output buffer to component: %s (0x%08x)",
            gst_omx_error_to_string (err), err));
    gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    self->started = FALSE;
    GST_AUDIO_DECODER_STREAM_UNLOCK (self);
    return;
  }
}
static gboolean
gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
{
  GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (bsrc);
  GstCaps *current_caps;
  const GstDecklinkMode *mode;
  BMDVideoInputFlags flags;
  HRESULT ret;

  GST_DEBUG_OBJECT (self, "Setting caps %" GST_PTR_FORMAT, caps);

  if ((current_caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (bsrc)))) {
    GST_DEBUG_OBJECT (self, "Pad already has caps %" GST_PTR_FORMAT, caps);

    if (!gst_caps_is_equal (caps, current_caps)) {
      GST_DEBUG_OBJECT (self, "New caps, reconfiguring");
      gst_caps_unref (current_caps);
      if (self->mode == GST_DECKLINK_MODE_AUTO) {
        return TRUE;
      } else {
        return FALSE;
      }
    } else {
      gst_caps_unref (current_caps);
      return TRUE;
    }
  }

  if (!gst_video_info_from_caps (&self->info, caps))
    return FALSE;

  if (self->input->config && self->connection != GST_DECKLINK_CONNECTION_AUTO) {
    ret = self->input->config->SetInt (bmdDeckLinkConfigVideoInputConnection,
        gst_decklink_get_connection (self->connection));
    if (ret != S_OK) {
      GST_ERROR_OBJECT (self, "Failed to set configuration (input source)");
      return FALSE;
    }

    if (self->connection == GST_DECKLINK_CONNECTION_COMPOSITE) {
      ret = self->input->config->SetInt (bmdDeckLinkConfigAnalogVideoInputFlags,
          bmdAnalogVideoFlagCompositeSetup75);
      if (ret != S_OK) {
        GST_ERROR_OBJECT (self,
            "Failed to set configuration (composite setup)");
        return FALSE;
      }
    }
  }

  flags = bmdVideoInputFlagDefault;
  if (self->mode == GST_DECKLINK_MODE_AUTO) {
    bool autoDetection = false;

    if (self->input->attributes) {
      ret =
          self->input->
          attributes->GetFlag (BMDDeckLinkSupportsInputFormatDetection,
          &autoDetection);
      if (ret != S_OK) {
        GST_ERROR_OBJECT (self, "Failed to get attribute (autodetection)");
        return FALSE;
      }
      if (autoDetection)
        flags |= bmdVideoInputEnableFormatDetection;
    }
    if (!autoDetection) {
      GST_ERROR_OBJECT (self, "Failed to activate auto-detection");
      return FALSE;
    }
  }

  mode = gst_decklink_get_mode (self->mode);
  g_assert (mode != NULL);

  ret = self->input->input->EnableVideoInput (mode->mode,
      bmdFormat8BitYUV, flags);
  if (ret != S_OK) {
    GST_WARNING_OBJECT (self, "Failed to enable video input");
    return FALSE;
  }

  g_mutex_lock (&self->input->lock);
  self->input->mode = mode;
  self->input->video_enabled = TRUE;
  if (self->input->start_streams)
    self->input->start_streams (self->input->videosrc);
  g_mutex_unlock (&self->input->lock);

  return TRUE;
}
static gboolean
gst_net_client_clock_start (GstNetClientClock * self)
{
  GSocketAddress *servaddr;
  GSocketAddress *myaddr;
  GInetAddress *inetaddr;
  GSocket *socket;
  GError *error = NULL;

  g_return_val_if_fail (self->priv->address != NULL, FALSE);
  g_return_val_if_fail (self->priv->servaddr == NULL, FALSE);

  socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
      G_SOCKET_PROTOCOL_UDP, &error);

  if (socket == NULL)
    goto no_socket;

  /* check address we're bound to, mostly for debugging purposes */
  myaddr = g_socket_get_local_address (socket, &error);

  if (myaddr == NULL)
    goto getsockname_error;

  GST_DEBUG_OBJECT (self, "socket opened on UDP port %hd",
      g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (myaddr)));

  g_object_unref (myaddr);

  /* create target address */
  inetaddr = g_inet_address_new_from_string (self->priv->address);

  if (inetaddr == NULL)
    goto bad_address;

  servaddr = g_inet_socket_address_new (inetaddr, self->priv->port);
  g_object_unref (inetaddr);

  g_assert (servaddr != NULL);

  GST_DEBUG_OBJECT (self, "will communicate with %s:%d", self->priv->address,
      self->priv->port);

  self->priv->cancel = g_cancellable_new ();
  self->priv->socket = socket;
  self->priv->servaddr = G_SOCKET_ADDRESS (servaddr);

  self->priv->thread = g_thread_try_new ("GstNetClientClock",
      gst_net_client_clock_thread, self, &error);

  if (error != NULL)
    goto no_thread;

  return TRUE;

  /* ERRORS */
no_socket:
  {
    GST_ERROR_OBJECT (self, "socket_new() failed: %s", error->message);
    g_error_free (error);
    return FALSE;
  }
getsockname_error:
  {
    GST_ERROR_OBJECT (self, "get_local_address() failed: %s", error->message);
    g_error_free (error);
    g_object_unref (socket);
    return FALSE;
  }
bad_address:
  {
    GST_ERROR_OBJECT (self, "inet_address_new_from_string('%s') failed",
        self->priv->address);
    g_object_unref (socket);
    return FALSE;
  }
no_thread:
  {
    GST_ERROR_OBJECT (self, "could not create thread: %s", error->message);
    g_object_unref (self->priv->servaddr);
    self->priv->servaddr = NULL;
    g_object_unref (self->priv->socket);
    self->priv->socket = NULL;
    g_error_free (error);
    return FALSE;
  }
}
Beispiel #5
0
static gboolean
gst_vp8_enc_finish (GstBaseVideoEncoder * base_video_encoder)
{
  GstVP8Enc *encoder;
  GstVideoFrame *frame;
  int flags = 0;
  vpx_codec_err_t status;
  vpx_codec_iter_t iter = NULL;
  const vpx_codec_cx_pkt_t *pkt;

  GST_DEBUG_OBJECT (base_video_encoder, "finish");

  encoder = GST_VP8_ENC (base_video_encoder);

  status =
      vpx_codec_encode (&encoder->encoder, NULL, encoder->n_frames, 1, flags,
      0);
  if (status != 0) {
    GST_ERROR_OBJECT (encoder, "encode returned %d %s", status,
        gst_vpx_error_name (status));
    return FALSE;
  }

  pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
  while (pkt != NULL) {
    GstBuffer *buffer;
    GstVP8EncCoderHook *hook;
    gboolean invisible, keyframe;

    GST_DEBUG_OBJECT (encoder, "packet %u type %d", (guint) pkt->data.frame.sz,
        pkt->kind);

    if (pkt->kind == VPX_CODEC_STATS_PKT
        && encoder->multipass_mode == VPX_RC_FIRST_PASS) {
      GST_LOG_OBJECT (encoder, "handling STATS packet");

      g_byte_array_append (encoder->first_pass_cache_content,
          pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz);

      frame = gst_base_video_encoder_get_oldest_frame (base_video_encoder);
      if (frame != NULL) {
        buffer = gst_buffer_new ();
        GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_PREROLL);
        frame->src_buffer = buffer;
        gst_base_video_encoder_finish_frame (base_video_encoder, frame);
      }

      pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
      continue;
    } else if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) {
      GST_LOG_OBJECT (encoder, "non frame pkt: %d", pkt->kind);
      pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
      continue;
    }

    invisible = (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) != 0;
    keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
    frame = gst_base_video_encoder_get_oldest_frame (base_video_encoder);
    g_assert (frame != NULL);
    hook = frame->coder_hook;

    buffer = gst_buffer_new_and_alloc (pkt->data.frame.sz);

    memcpy (GST_BUFFER_DATA (buffer), pkt->data.frame.buf, pkt->data.frame.sz);
    frame->is_sync_point = frame->is_sync_point || keyframe;

    if (hook->image)
      g_slice_free (vpx_image_t, hook->image);
    hook->image = NULL;

    if (invisible) {
      hook->invisible = g_list_append (hook->invisible, buffer);
    } else {
      frame->src_buffer = buffer;
      gst_base_video_encoder_finish_frame (base_video_encoder, frame);
      frame = NULL;
    }

    pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
  }

  if (encoder->multipass_mode == VPX_RC_FIRST_PASS
      && encoder->multipass_cache_file) {
    GError *err = NULL;

    if (!g_file_set_contents (encoder->multipass_cache_file,
            (const gchar *) encoder->first_pass_cache_content->data,
            encoder->first_pass_cache_content->len, &err)) {
      GST_ELEMENT_ERROR (encoder, RESOURCE, WRITE, (NULL),
          ("Failed to write multipass cache file: %s", err->message));
      g_error_free (err);
    }
  }

  return TRUE;
}
Beispiel #6
0
static GstFlowReturn
gst_rsvg_decode_image (GstRsvgDec * rsvg, GstBuffer * buffer,
    GstVideoCodecFrame * frame)
{
  GstVideoDecoder *decoder = GST_VIDEO_DECODER (rsvg);
  GstFlowReturn ret = GST_FLOW_OK;
  cairo_t *cr;
  cairo_surface_t *surface;
  RsvgHandle *handle;
  GError *error = NULL;
  RsvgDimensionData dimension;
  gdouble scalex, scaley;
  GstMapInfo minfo;
  GstVideoFrame vframe;
  GstVideoCodecState *output_state;

  GST_LOG_OBJECT (rsvg, "parsing svg");

  if (!gst_buffer_map (buffer, &minfo, GST_MAP_READ)) {
    GST_ERROR_OBJECT (rsvg, "Failed to get SVG image");
    return GST_FLOW_ERROR;
  }
  handle = rsvg_handle_new_from_data (minfo.data, minfo.size, &error);
  if (!handle) {
    GST_ERROR_OBJECT (rsvg, "Failed to parse SVG image: %s", error->message);
    g_error_free (error);
    return GST_FLOW_ERROR;
  }

  rsvg_handle_get_dimensions (handle, &dimension);

  output_state = gst_video_decoder_get_output_state (decoder);
  if ((output_state == NULL)
      || GST_VIDEO_INFO_WIDTH (&output_state->info) != dimension.width
      || GST_VIDEO_INFO_HEIGHT (&output_state->info) != dimension.height) {

    /* Create the output state */
    gst_video_decoder_set_output_state (decoder, GST_RSVG_VIDEO_FORMAT,
        dimension.width, dimension.height, rsvg->input_state);
    if (output_state)
      gst_video_codec_state_unref (output_state);
    output_state = gst_video_decoder_get_output_state (decoder);
  }

  ret = gst_video_decoder_allocate_output_frame (decoder, frame);

  if (ret != GST_FLOW_OK) {
    g_object_unref (handle);
    GST_ERROR_OBJECT (rsvg, "Buffer allocation failed %s",
        gst_flow_get_name (ret));
    return ret;
  }

  GST_LOG_OBJECT (rsvg, "render image at %d x %d",
      GST_VIDEO_INFO_HEIGHT (&output_state->info),
      GST_VIDEO_INFO_WIDTH (&output_state->info));


  if (!gst_video_frame_map (&vframe,
          &gst_video_decoder_get_output_state (decoder)->info,
          frame->output_buffer, GST_MAP_READWRITE)) {
    GST_ERROR_OBJECT (rsvg, "Failed to get SVG image");
    return GST_FLOW_ERROR;
  }
  surface =
      cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA (&vframe,
          0), CAIRO_FORMAT_ARGB32, GST_VIDEO_FRAME_WIDTH (&vframe),
      GST_VIDEO_FRAME_HEIGHT (&vframe), GST_VIDEO_FRAME_PLANE_STRIDE (&vframe,
          0));

  cr = cairo_create (surface);
  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
  cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
  cairo_paint (cr);
  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
  cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);

  scalex = scaley = 1.0;
  if (GST_VIDEO_INFO_WIDTH (&output_state->info) != dimension.width) {
    scalex =
        ((gdouble) GST_VIDEO_INFO_WIDTH (&output_state->info)) /
        ((gdouble) dimension.width);
  }
  if (GST_VIDEO_INFO_HEIGHT (&output_state->info) != dimension.height) {
    scaley =
        ((gdouble) GST_VIDEO_INFO_HEIGHT (&output_state->info)) /
        ((gdouble) dimension.height);
  }
  cairo_scale (cr, scalex, scaley);
  rsvg_handle_render_cairo (handle, cr);

  g_object_unref (handle);
  cairo_destroy (cr);
  cairo_surface_destroy (surface);

  /* Now unpremultiply Cairo's ARGB to match GStreamer's */
  gst_rsvg_decode_unpremultiply (GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0),
      GST_VIDEO_FRAME_WIDTH (&vframe), GST_VIDEO_FRAME_HEIGHT (&vframe));

  gst_video_codec_state_unref (output_state);
  gst_buffer_unmap (buffer, &minfo);
  gst_video_frame_unmap (&vframe);

  return ret;
}
gboolean
gst_egl_adaptation_init_egl_display (GstEglAdaptationContext * ctx)
{
  GstMessage *msg;
  EGLDisplay display;
  GST_DEBUG_OBJECT (ctx->element, "Enter EGL initial configuration");

  if (!platform_wrapper_init ()) {
    GST_ERROR_OBJECT (ctx->element, "Couldn't init EGL platform wrapper");
    goto HANDLE_ERROR;
  }

  msg =
      gst_message_new_need_context (GST_OBJECT_CAST (ctx->element),
      GST_EGL_DISPLAY_CONTEXT_TYPE);
  gst_element_post_message (GST_ELEMENT_CAST (ctx->element), msg);

  GST_OBJECT_LOCK (ctx->element);
  if (!ctx->set_display) {
    GstContext *context;

    GST_OBJECT_UNLOCK (ctx->element);

    display = eglGetDisplay (EGL_DEFAULT_DISPLAY);
    if (display == EGL_NO_DISPLAY) {
      GST_ERROR_OBJECT (ctx->element, "Could not get EGL display connection");
      goto HANDLE_ERROR;        /* No EGL error is set by eglGetDisplay() */
    }
    ctx->display = gst_egl_display_new (display, (GDestroyNotify) eglTerminate);

    context = gst_context_new_egl_display (ctx->display, FALSE);
    msg = gst_message_new_have_context (GST_OBJECT (ctx->element), context);
    gst_element_post_message (GST_ELEMENT_CAST (ctx->element), msg);
  }

  if (!eglInitialize (gst_egl_display_get (ctx->display),
          &ctx->eglglesctx->egl_major, &ctx->eglglesctx->egl_minor)) {
    got_egl_error ("eglInitialize");
    GST_ERROR_OBJECT (ctx->element, "Could not init EGL display connection");
    goto HANDLE_EGL_ERROR;
  }

  /* Check against required EGL version
   * XXX: Need to review the version requirement in terms of the needed API
   */
  if (ctx->eglglesctx->egl_major < GST_EGLGLESSINK_EGL_MIN_VERSION) {
    GST_ERROR_OBJECT (ctx->element, "EGL v%d needed, but you only have v%d.%d",
        GST_EGLGLESSINK_EGL_MIN_VERSION, ctx->eglglesctx->egl_major,
        ctx->eglglesctx->egl_minor);
    goto HANDLE_ERROR;
  }

  GST_INFO_OBJECT (ctx->element, "System reports supported EGL version v%d.%d",
      ctx->eglglesctx->egl_major, ctx->eglglesctx->egl_minor);

  eglBindAPI (EGL_OPENGL_ES_API);

  return TRUE;

  /* Errors */
HANDLE_EGL_ERROR:
  GST_ERROR_OBJECT (ctx->element, "EGL call returned error %x", eglGetError ());
HANDLE_ERROR:
  GST_ERROR_OBJECT (ctx->element, "Couldn't setup window/surface from handle");
  return FALSE;
}
Beispiel #8
0
static GstStructure *gst_avdtp_sink_parse_sbc_caps(
			GstAvdtpSink *self, sbc_capabilities_t *sbc)
{
	GstStructure *structure;
	GValue *value;
	GValue *list;
	gboolean mono, stereo;

	structure = gst_structure_empty_new("audio/x-sbc");
	value = g_value_init(g_new0(GValue, 1), G_TYPE_STRING);

	/* mode */
	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
	if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) {
		g_value_set_static_string(value, "mono");
		gst_value_list_prepend_value(list, value);
	}
	if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) {
		g_value_set_static_string(value, "stereo");
		gst_value_list_prepend_value(list, value);
	}
	if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) {
		g_value_set_static_string(value, "dual");
		gst_value_list_prepend_value(list, value);
	}
	if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) {
		g_value_set_static_string(value, "joint");
		gst_value_list_prepend_value(list, value);
	}
	g_value_unset(value);
	if (list) {
		gst_structure_set_value(structure, "mode", list);
		g_free(list);
		list = NULL;
	}

	/* subbands */
	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
	value = g_value_init(value, G_TYPE_INT);
	if (sbc->subbands & BT_A2DP_SUBBANDS_4) {
		g_value_set_int(value, 4);
		gst_value_list_prepend_value(list, value);
	}
	if (sbc->subbands & BT_A2DP_SUBBANDS_8) {
		g_value_set_int(value, 8);
		gst_value_list_prepend_value(list, value);
	}
	g_value_unset(value);
	if (list) {
		gst_structure_set_value(structure, "subbands", list);
		g_free(list);
		list = NULL;
	}

	/* blocks */
	value = g_value_init(value, G_TYPE_INT);
	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_16) {
		g_value_set_int(value, 16);
		gst_value_list_prepend_value(list, value);
	}
	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_12) {
		g_value_set_int(value, 12);
		gst_value_list_prepend_value(list, value);
	}
	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_8) {
		g_value_set_int(value, 8);
		gst_value_list_prepend_value(list, value);
	}
	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_4) {
		g_value_set_int(value, 4);
		gst_value_list_prepend_value(list, value);
	}
	g_value_unset(value);
	if (list) {
		gst_structure_set_value(structure, "blocks", list);
		g_free(list);
		list = NULL;
	}

	/* allocation */
	g_value_init(value, G_TYPE_STRING);
	list = g_value_init(g_new0(GValue,1), GST_TYPE_LIST);
	if (sbc->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) {
		g_value_set_static_string(value, "loudness");
		gst_value_list_prepend_value(list, value);
	}
	if (sbc->allocation_method & BT_A2DP_ALLOCATION_SNR) {
		g_value_set_static_string(value, "snr");
		gst_value_list_prepend_value(list, value);
	}
	g_value_unset(value);
	if (list) {
		gst_structure_set_value(structure, "allocation", list);
		g_free(list);
		list = NULL;
	}

	/* rate */
	g_value_init(value, G_TYPE_INT);
	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
	if (sbc->frequency & BT_SBC_SAMPLING_FREQ_48000) {
		g_value_set_int(value, 48000);
		gst_value_list_prepend_value(list, value);
	}
	if (sbc->frequency & BT_SBC_SAMPLING_FREQ_44100) {
		g_value_set_int(value, 44100);
		gst_value_list_prepend_value(list, value);
	}
	if (sbc->frequency & BT_SBC_SAMPLING_FREQ_32000) {
		g_value_set_int(value, 32000);
		gst_value_list_prepend_value(list, value);
	}
	if (sbc->frequency & BT_SBC_SAMPLING_FREQ_16000) {
		g_value_set_int(value, 16000);
		gst_value_list_prepend_value(list, value);
	}
	g_value_unset(value);
	if (list) {
		gst_structure_set_value(structure, "rate", list);
		g_free(list);
		list = NULL;
	}

	/* bitpool */
	value = g_value_init(value, GST_TYPE_INT_RANGE);
	gst_value_set_int_range(value,
			MIN(sbc->min_bitpool, TEMPLATE_MAX_BITPOOL),
			MIN(sbc->max_bitpool, TEMPLATE_MAX_BITPOOL));
	gst_structure_set_value(structure, "bitpool", value);
	g_value_unset(value);

	/* channels */
	mono = FALSE;
	stereo = FALSE;
	if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
		mono = TRUE;
	if ((sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) ||
			(sbc->channel_mode &
			BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) ||
			(sbc->channel_mode &
			BT_A2DP_CHANNEL_MODE_JOINT_STEREO))
		stereo = TRUE;

	if (mono && stereo) {
		g_value_init(value, GST_TYPE_INT_RANGE);
		gst_value_set_int_range(value, 1, 2);
	} else {
		g_value_init(value, G_TYPE_INT);
		if (mono)
			g_value_set_int(value, 1);
		else if (stereo)
			g_value_set_int(value, 2);
		else {
			GST_ERROR_OBJECT(self,
				"Unexpected number of channels");
			g_value_set_int(value, 0);
		}
	}

	gst_structure_set_value(structure, "channels", value);
	g_free(value);

	return structure;
}
Beispiel #9
0
static GstStructure *gst_avdtp_sink_parse_mpeg_caps(
			GstAvdtpSink *self, mpeg_capabilities_t *mpeg)
{
	GstStructure *structure;
	GValue *value;
	GValue *list;
	gboolean valid_layer = FALSE;
	gboolean mono, stereo;

	if (!mpeg)
		return NULL;

	GST_LOG_OBJECT(self, "parsing mpeg caps");

	structure = gst_structure_empty_new("audio/mpeg");
	value = g_new0(GValue, 1);
	g_value_init(value, G_TYPE_INT);

	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
	g_value_set_int(value, 1);
	gst_value_list_prepend_value(list, value);
	g_value_set_int(value, 2);
	gst_value_list_prepend_value(list, value);
	gst_structure_set_value(structure, "mpegversion", list);
	g_free(list);

	/* layer */
	GST_LOG_OBJECT(self, "setting mpeg layer");
	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
	if (mpeg->layer & BT_MPEG_LAYER_1) {
		g_value_set_int(value, 1);
		gst_value_list_prepend_value(list, value);
		valid_layer = TRUE;
	}
	if (mpeg->layer & BT_MPEG_LAYER_2) {
		g_value_set_int(value, 2);
		gst_value_list_prepend_value(list, value);
		valid_layer = TRUE;
	}
	if (mpeg->layer & BT_MPEG_LAYER_3) {
		g_value_set_int(value, 3);
		gst_value_list_prepend_value(list, value);
		valid_layer = TRUE;
	}
	if (list) {
		gst_structure_set_value(structure, "layer", list);
		g_free(list);
		list = NULL;
	}

	if (!valid_layer) {
		gst_structure_free(structure);
		g_free(value);
		return NULL;
	}

	/* rate */
	GST_LOG_OBJECT(self, "setting mpeg rate");
	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_48000) {
		g_value_set_int(value, 48000);
		gst_value_list_prepend_value(list, value);
	}
	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_44100) {
		g_value_set_int(value, 44100);
		gst_value_list_prepend_value(list, value);
	}
	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_32000) {
		g_value_set_int(value, 32000);
		gst_value_list_prepend_value(list, value);
	}
	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_24000) {
		g_value_set_int(value, 24000);
		gst_value_list_prepend_value(list, value);
	}
	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_22050) {
		g_value_set_int(value, 22050);
		gst_value_list_prepend_value(list, value);
	}
	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_16000) {
		g_value_set_int(value, 16000);
		gst_value_list_prepend_value(list, value);
	}
	g_value_unset(value);
	if (list) {
		gst_structure_set_value(structure, "rate", list);
		g_free(list);
		list = NULL;
	}

	/* channels */
	GST_LOG_OBJECT(self, "setting mpeg channels");
	mono = FALSE;
	stereo = FALSE;
	if (mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
		mono = TRUE;
	if ((mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) ||
			(mpeg->channel_mode &
			BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) ||
			(mpeg->channel_mode &
			BT_A2DP_CHANNEL_MODE_JOINT_STEREO))
		stereo = TRUE;

	if (mono && stereo) {
		g_value_init(value, GST_TYPE_INT_RANGE);
		gst_value_set_int_range(value, 1, 2);
	} else {
		g_value_init(value, G_TYPE_INT);
		if (mono)
			g_value_set_int(value, 1);
		else if (stereo)
			g_value_set_int(value, 2);
		else {
			GST_ERROR_OBJECT(self,
				"Unexpected number of channels");
			g_value_set_int(value, 0);
		}
	}
	gst_structure_set_value(structure, "channels", value);
	g_free(value);

	return structure;
}
Beispiel #10
0
static gboolean gst_avdtp_sink_init_sbc_pkt_conf(GstAvdtpSink *sink,
					GstCaps *caps,
					sbc_capabilities_t *pkt)
{
	sbc_capabilities_t *cfg;
	const GValue *value = NULL;
	const char *pref, *name;
	gint rate, subbands, blocks;
	GstStructure *structure = gst_caps_get_structure(caps, 0);

	cfg = (void *) gst_avdtp_find_caps(sink, BT_A2DP_SBC_SINK);
	name = gst_structure_get_name(structure);

	if (!(IS_SBC(name))) {
		GST_ERROR_OBJECT(sink, "Unexpected format %s, "
				"was expecting sbc", name);
		return FALSE;
	}

	value = gst_structure_get_value(structure, "rate");
	rate = g_value_get_int(value);
	if (rate == 44100)
		cfg->frequency = BT_SBC_SAMPLING_FREQ_44100;
	else if (rate == 48000)
		cfg->frequency = BT_SBC_SAMPLING_FREQ_48000;
	else if (rate == 32000)
		cfg->frequency = BT_SBC_SAMPLING_FREQ_32000;
	else if (rate == 16000)
		cfg->frequency = BT_SBC_SAMPLING_FREQ_16000;
	else {
		GST_ERROR_OBJECT(sink, "Invalid rate while setting caps");
		return FALSE;
	}

	value = gst_structure_get_value(structure, "mode");
	pref = g_value_get_string(value);
	if (strcmp(pref, "mono") == 0)
		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
	else if (strcmp(pref, "dual") == 0)
		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
	else if (strcmp(pref, "stereo") == 0)
		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;
	else if (strcmp(pref, "joint") == 0)
		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
	else {
		GST_ERROR_OBJECT(sink, "Invalid mode %s", pref);
		return FALSE;
	}

	value = gst_structure_get_value(structure, "allocation");
	pref = g_value_get_string(value);
	if (strcmp(pref, "loudness") == 0)
		cfg->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
	else if (strcmp(pref, "snr") == 0)
		cfg->allocation_method = BT_A2DP_ALLOCATION_SNR;
	else {
		GST_ERROR_OBJECT(sink, "Invalid allocation: %s", pref);
		return FALSE;
	}

	value = gst_structure_get_value(structure, "subbands");
	subbands = g_value_get_int(value);
	if (subbands == 8)
		cfg->subbands = BT_A2DP_SUBBANDS_8;
	else if (subbands == 4)
		cfg->subbands = BT_A2DP_SUBBANDS_4;
	else {
		GST_ERROR_OBJECT(sink, "Invalid subbands %d", subbands);
		return FALSE;
	}

	value = gst_structure_get_value(structure, "blocks");
	blocks = g_value_get_int(value);
	if (blocks == 16)
		cfg->block_length = BT_A2DP_BLOCK_LENGTH_16;
	else if (blocks == 12)
		cfg->block_length = BT_A2DP_BLOCK_LENGTH_12;
	else if (blocks == 8)
		cfg->block_length = BT_A2DP_BLOCK_LENGTH_8;
	else if (blocks == 4)
		cfg->block_length = BT_A2DP_BLOCK_LENGTH_4;
	else {
		GST_ERROR_OBJECT(sink, "Invalid blocks %d", blocks);
		return FALSE;
	}

	value = gst_structure_get_value(structure, "bitpool");
	cfg->max_bitpool = cfg->min_bitpool = g_value_get_int(value);

	memcpy(pkt, cfg, sizeof(*pkt));

	return TRUE;
}
Beispiel #11
0
static gboolean gst_avdtp_sink_conf_recv_stream_fd(
					GstAvdtpSink *self)
{
	struct bluetooth_data *data = self->data;
	gint ret;
	GIOError err;
	GError *gerr = NULL;
	GIOStatus status;
	GIOFlags flags;
	gsize read;

	ret = gst_avdtp_sink_bluetooth_recvmsg_fd(self);
	if (ret < 0)
		return FALSE;

	if (!self->stream) {
		GST_ERROR_OBJECT(self, "Error while configuring device: "
				"could not acquire audio socket");
		return FALSE;
	}

	/* set stream socket to nonblock */
	GST_LOG_OBJECT(self, "setting stream socket to nonblock");
	flags = g_io_channel_get_flags(self->stream);
	flags |= G_IO_FLAG_NONBLOCK;
	status = g_io_channel_set_flags(self->stream, flags, &gerr);
	if (status != G_IO_STATUS_NORMAL) {
		if (gerr)
			GST_WARNING_OBJECT(self, "Error while "
				"setting server socket to nonblock: "
				"%s", gerr->message);
		else
			GST_WARNING_OBJECT(self, "Error while "
					"setting server "
					"socket to nonblock");
	}

	/* It is possible there is some outstanding
	data in the pipe - we have to empty it */
	GST_LOG_OBJECT(self, "emptying stream pipe");
	while (1) {
		err = g_io_channel_read(self->stream, data->buffer,
					(gsize) data->link_mtu,
					&read);
		if (err != G_IO_ERROR_NONE || read <= 0)
			break;
	}

	/* set stream socket to block */
	GST_LOG_OBJECT(self, "setting stream socket to block");
	flags = g_io_channel_get_flags(self->stream);
	flags &= ~G_IO_FLAG_NONBLOCK;
	status = g_io_channel_set_flags(self->stream, flags, &gerr);
	if (status != G_IO_STATUS_NORMAL) {
		if (gerr)
			GST_WARNING_OBJECT(self, "Error while "
				"setting server socket to block:"
				"%s", gerr->message);
		else
			GST_WARNING_OBJECT(self, "Error while "
				"setting server "
				"socket to block");
	}

	memset(data->buffer, 0, sizeof(data->buffer));

	return TRUE;
}
Beispiel #12
0
static gboolean gst_avdtp_sink_configure(GstAvdtpSink *self,
			GstCaps *caps)
{
	gchar buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_open_req *open_req = (void *) buf;
	struct bt_open_rsp *open_rsp = (void *) buf;
	struct bt_set_configuration_req *req = (void *) buf;
	struct bt_set_configuration_rsp *rsp = (void *) buf;
	gboolean ret;
	GIOError io_error;
	gchar *temp;
	GstStructure *structure;
	codec_capabilities_t *codec = NULL;

	temp = gst_caps_to_string(caps);
	GST_DEBUG_OBJECT(self, "configuring device with caps: %s", temp);
	g_free(temp);

	structure = gst_caps_get_structure(caps, 0);

	if (gst_structure_has_name(structure, "audio/x-sbc"))
		codec = (void *) gst_avdtp_find_caps(self, BT_A2DP_SBC_SINK);
	else if (gst_structure_has_name(structure, "audio/mpeg"))
		codec = (void *) gst_avdtp_find_caps(self, BT_A2DP_MPEG12_SINK);

	if (codec == NULL) {
		GST_ERROR_OBJECT(self, "Couldn't parse caps "
				"to packet configuration");
		return FALSE;
	}

	memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
	open_req->h.type = BT_REQUEST;
	open_req->h.name = BT_OPEN;
	open_req->h.length = sizeof(*open_req);

	strncpy(open_req->destination, self->device, 18);
	open_req->seid = codec->seid;
	open_req->lock = BT_WRITE_LOCK;

	io_error = gst_avdtp_sink_audioservice_send(self, &open_req->h);
	if (io_error != G_IO_ERROR_NONE) {
		GST_ERROR_OBJECT(self, "Error ocurred while sending "
					"open packet");
		return FALSE;
	}

	open_rsp->h.length = sizeof(*open_rsp);
	io_error = gst_avdtp_sink_audioservice_expect(self,
			&open_rsp->h, BT_OPEN);
	if (io_error != G_IO_ERROR_NONE) {
		GST_ERROR_OBJECT(self, "Error while receiving device "
					"confirmation");
		return FALSE;
	}

	memset(req, 0, sizeof(buf));
	req->h.type = BT_REQUEST;
	req->h.name = BT_SET_CONFIGURATION;
	req->h.length = sizeof(*req);

	if (codec->type == BT_A2DP_SBC_SINK)
		ret = gst_avdtp_sink_init_sbc_pkt_conf(self, caps,
				(void *) &req->codec);
	else
		ret = gst_avdtp_sink_init_mp3_pkt_conf(self, caps,
				(void *) &req->codec);

	if (!ret) {
		GST_ERROR_OBJECT(self, "Couldn't parse caps "
				"to packet configuration");
		return FALSE;
	}

	req->h.length += req->codec.length - sizeof(req->codec);
	io_error = gst_avdtp_sink_audioservice_send(self, &req->h);
	if (io_error != G_IO_ERROR_NONE) {
		GST_ERROR_OBJECT(self, "Error ocurred while sending "
					"configurarion packet");
		return FALSE;
	}

	rsp->h.length = sizeof(*rsp);
	io_error = gst_avdtp_sink_audioservice_expect(self,
			&rsp->h, BT_SET_CONFIGURATION);
	if (io_error != G_IO_ERROR_NONE) {
		GST_ERROR_OBJECT(self, "Error while receiving device "
					"confirmation");
		return FALSE;
	}

	self->data->link_mtu = rsp->link_mtu;

	return TRUE;
}
static GstFlowReturn
gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame)
{
  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
  GstFlowReturn ret = GST_FLOW_OK;

  GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number);

  if (G_UNLIKELY (!g_atomic_int_get (&self->active)))
    goto flushing;

  if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) {
    if (!self->input_state)
      goto not_negotiated;
    if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps))
      goto not_negotiated;
  }

  if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) {
    GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
    GstVideoInfo info;
    GstVideoCodecState *output_state;
    GstBuffer *codec_data;

    GST_DEBUG_OBJECT (self, "Sending header");

    codec_data = self->input_state->codec_data;

    /* We are running in byte-stream mode, so we don't know the headers, but
     * we need to send something, otherwise the decoder will refuse to
     * intialize.
     */
    if (codec_data) {
      gst_buffer_ref (codec_data);
    } else {
      codec_data = frame->input_buffer;
      frame->input_buffer = NULL;
    }

    /* Ensure input internal pool is active */
    if (!gst_buffer_pool_is_active (pool)) {
      GstStructure *config = gst_buffer_pool_get_config (pool);
      gst_buffer_pool_config_set_params (config, self->input_state->caps,
          self->v4l2output->info.size, 2, 2);

      /* There is no reason to refuse this config */
      if (!gst_buffer_pool_set_config (pool, config))
        goto activate_failed;

      if (!gst_buffer_pool_set_active (pool, TRUE))
        goto activate_failed;
    }

    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
    ret =
        gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
            v4l2output->pool), &codec_data);
    GST_VIDEO_DECODER_STREAM_LOCK (decoder);

    gst_buffer_unref (codec_data);

    if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info))
      goto not_negotiated;

    output_state = gst_video_decoder_set_output_state (decoder,
        info.finfo->format, info.width, info.height, self->input_state);

    /* Copy the rest of the information, there might be more in the future */
    output_state->info.interlace_mode = info.interlace_mode;
    gst_video_codec_state_unref (output_state);

    if (!gst_video_decoder_negotiate (decoder)) {
      if (GST_PAD_IS_FLUSHING (decoder->srcpad))
        goto flushing;
      else
        goto not_negotiated;
    }

    /* Ensure our internal pool is activated */
    if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (self->v4l2capture->pool),
            TRUE))
      goto activate_failed;
  }

  if (g_atomic_int_get (&self->processing) == FALSE) {
    /* It's possible that the processing thread stopped due to an error */
    if (self->output_flow != GST_FLOW_OK &&
        self->output_flow != GST_FLOW_FLUSHING) {
      GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving");
      ret = self->output_flow;
      goto drop;
    }

    GST_DEBUG_OBJECT (self, "Starting decoding thread");

    /* Start the processing task, when it quits, the task will disable input
     * processing to unlock input if draining, or prevent potential block */
    g_atomic_int_set (&self->processing, TRUE);
    if (!gst_pad_start_task (decoder->srcpad,
            (GstTaskFunction) gst_v4l2_video_dec_loop, self,
            (GDestroyNotify) gst_v4l2_video_dec_loop_stopped))
      goto start_task_failed;
  }

  if (frame->input_buffer) {
    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
    ret =
        gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->v4l2output->
            pool), &frame->input_buffer);
    GST_VIDEO_DECODER_STREAM_LOCK (decoder);

    if (ret == GST_FLOW_FLUSHING) {
      if (g_atomic_int_get (&self->processing) == FALSE)
        ret = self->output_flow;
      goto drop;
    } else if (ret != GST_FLOW_OK) {
      goto process_failed;
    }

    /* No need to keep input arround */
    gst_buffer_replace (&frame->input_buffer, NULL);
  }

  gst_video_codec_frame_unref (frame);
  return ret;

  /* ERRORS */
not_negotiated:
  {
    GST_ERROR_OBJECT (self, "not negotiated");
    ret = GST_FLOW_NOT_NEGOTIATED;
    goto drop;
  }
activate_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
        (_("Failed to allocate required memory.")),
        ("Buffer pool activation failed"));
    ret = GST_FLOW_ERROR;
    goto drop;
  }
flushing:
  {
    ret = GST_FLOW_FLUSHING;
    goto drop;
  }

start_task_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
        (_("Failed to start decoding thread.")), (NULL));
    g_atomic_int_set (&self->processing, FALSE);
    ret = GST_FLOW_ERROR;
    goto drop;
  }
process_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
        (_("Failed to process frame.")),
        ("Maybe be due to not enough memory or failing driver"));
    ret = GST_FLOW_ERROR;
    goto drop;
  }
drop:
  {
    gst_video_decoder_drop_frame (decoder, frame);
    return ret;
  }
}
static GstFlowReturn
pad_chain (GstPad *pad,
           GstBuffer *buf)
{
    GOmxCore *gomx;
    GOmxPort *in_port;
    GstOmxBaseFilter *self;
    GstFlowReturn ret = GST_FLOW_OK;

    self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));

    gomx = self->gomx;

    GST_LOG_OBJECT (self, "begin");
    GST_LOG_OBJECT (self, "gst_buffer: size=%u", GST_BUFFER_SIZE (buf));

    GST_LOG_OBJECT (self, "state: %d", gomx->omx_state);

    if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded))
    {
        g_mutex_lock (self->ready_lock);

        GST_INFO_OBJECT (self, "omx: prepare");

        /** @todo this should probably go after doing preparations. */
        if (self->omx_setup)
        {
            self->omx_setup (self);
        }

        setup_ports (self);

        g_omx_core_prepare (self->gomx);

        if (gomx->omx_state == OMX_StateIdle)
        {
            self->ready = TRUE;
            gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
        }

        g_mutex_unlock (self->ready_lock);

        if (gomx->omx_state != OMX_StateIdle)
            goto out_flushing;
    }

    in_port = self->in_port;

    if (G_LIKELY (in_port->enabled))
    {
        guint buffer_offset = 0;

        if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle))
        {
            GST_INFO_OBJECT (self, "omx: play");
            g_omx_core_start (gomx);

            if (gomx->omx_state != OMX_StateExecuting)
                goto out_flushing;

            /* send buffer with codec data flag */
            /** @todo move to util */
            if (self->codec_data)
            {
                OMX_BUFFERHEADERTYPE *omx_buffer;

                GST_LOG_OBJECT (self, "request buffer");
                omx_buffer = g_omx_port_request_buffer (in_port);

                if (G_LIKELY (omx_buffer))
                {
                    omx_buffer->nFlags |= 0x00000080; /* codec data flag */

                    omx_buffer->nFilledLen = GST_BUFFER_SIZE (self->codec_data);
                    memcpy (omx_buffer->pBuffer + omx_buffer->nOffset, GST_BUFFER_DATA (self->codec_data), omx_buffer->nFilledLen);

                    GST_LOG_OBJECT (self, "release_buffer");
                    g_omx_port_release_buffer (in_port, omx_buffer);
                }
            }
        }

        if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting))
        {
            GST_ERROR_OBJECT (self, "Whoa! very wrong");
        }

        while (G_LIKELY (buffer_offset < GST_BUFFER_SIZE (buf)))
        {
            OMX_BUFFERHEADERTYPE *omx_buffer;

            if (self->last_pad_push_return != GST_FLOW_OK ||
                !(gomx->omx_state == OMX_StateExecuting ||
                  gomx->omx_state == OMX_StatePause))
            {
                goto out_flushing;
            }

            GST_LOG_OBJECT (self, "request buffer");
            omx_buffer = g_omx_port_request_buffer (in_port);

            GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);

            if (G_LIKELY (omx_buffer))
            {
                log_buffer (self, omx_buffer);

                if (omx_buffer->nOffset == 0 &&
                    self->share_input_buffer)
                {
                    {
                        GstBuffer *old_buf;
                        old_buf = omx_buffer->pAppPrivate;

                        if (old_buf)
                        {
                            gst_buffer_unref (old_buf);
                        }
                        else if (omx_buffer->pBuffer)
                        {
                            g_free (omx_buffer->pBuffer);
                        }
                    }

                    omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
                    omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
                    omx_buffer->nFilledLen = GST_BUFFER_SIZE (buf);
                    omx_buffer->pAppPrivate = buf;
                }
                else
                {
                    omx_buffer->nFilledLen = MIN (GST_BUFFER_SIZE (buf) - buffer_offset,
                                                  omx_buffer->nAllocLen - omx_buffer->nOffset);
                    memcpy (omx_buffer->pBuffer + omx_buffer->nOffset, GST_BUFFER_DATA (buf) + buffer_offset, omx_buffer->nFilledLen);
                }

                if (self->use_timestamps)
                {
                    GstClockTime timestamp_offset = 0;

                    if (buffer_offset && GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE)
                    {
                        timestamp_offset = gst_util_uint64_scale_int (buffer_offset,
                                                                      GST_BUFFER_DURATION (buf),
                                                                      GST_BUFFER_SIZE (buf));
                    }

                    omx_buffer->nTimeStamp = gst_util_uint64_scale_int (GST_BUFFER_TIMESTAMP (buf) + timestamp_offset,
                                                                        OMX_TICKS_PER_SECOND,
                                                                        GST_SECOND);
                }

                buffer_offset += omx_buffer->nFilledLen;

                GST_LOG_OBJECT (self, "release_buffer");
                /** @todo untaint buffer */
                g_omx_port_release_buffer (in_port, omx_buffer);
            }
            else
            {
                GST_WARNING_OBJECT (self, "null buffer");
                ret = GST_FLOW_WRONG_STATE;
                goto out_flushing;
            }
        }
    }
    else
    {
        GST_WARNING_OBJECT (self, "done");
        ret = GST_FLOW_UNEXPECTED;
    }

    if (!self->share_input_buffer)
    {
        gst_buffer_unref (buf);
    }

leave:

    GST_LOG_OBJECT (self, "end");

    return ret;

    /* special conditions */
out_flushing:
    {
        const gchar *error_msg = NULL;

        if (gomx->omx_error)
        {
            error_msg = "Error from OpenMAX component";
        }
        else if (gomx->omx_state != OMX_StateExecuting &&
                 gomx->omx_state != OMX_StatePause)
        {
            error_msg = "OpenMAX component in wrong state";
        }

        if (error_msg)
        {
            GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), (error_msg));
            ret = GST_FLOW_ERROR;
        }

        gst_buffer_unref (buf);

        goto leave;
    }
}
static GstFlowReturn
gst_inter_audio_src_create (GstBaseSrc * src, guint64 offset, guint size,
    GstBuffer ** buf)
{
  GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
  GstCaps *caps;
  GstBuffer *buffer;
  guint n, bpf;
  guint64 period_time;
  guint64 period_samples;

  GST_DEBUG_OBJECT (interaudiosrc, "create");

  buffer = NULL;
  caps = NULL;

  g_mutex_lock (&interaudiosrc->surface->mutex);
  if (interaudiosrc->surface->audio_info.finfo) {
    if (!gst_audio_info_is_equal (&interaudiosrc->surface->audio_info,
            &interaudiosrc->info)) {
      caps = gst_audio_info_to_caps (&interaudiosrc->surface->audio_info);
      interaudiosrc->timestamp_offset +=
          gst_util_uint64_scale (interaudiosrc->n_samples, GST_SECOND,
          interaudiosrc->info.rate);
      interaudiosrc->n_samples = 0;
    }
  }

  bpf = interaudiosrc->surface->audio_info.bpf;
  period_time = interaudiosrc->surface->audio_period_time;
  period_samples =
      gst_util_uint64_scale (period_time, interaudiosrc->info.rate, GST_SECOND);

  if (bpf > 0)
    n = gst_adapter_available (interaudiosrc->surface->audio_adapter) / bpf;
  else
    n = 0;

  if (n > period_samples)
    n = period_samples;
  if (n > 0) {
    buffer = gst_adapter_take_buffer (interaudiosrc->surface->audio_adapter,
        n * bpf);
  } else {
    buffer = gst_buffer_new ();
    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_GAP);
  }
  g_mutex_unlock (&interaudiosrc->surface->mutex);

  if (caps) {
    gboolean ret = gst_base_src_set_caps (src, caps);
    gst_caps_unref (caps);
    if (!ret) {
      GST_ERROR_OBJECT (src, "Failed to set caps %" GST_PTR_FORMAT, caps);
      if (buffer)
        gst_buffer_unref (buffer);
      return GST_FLOW_NOT_NEGOTIATED;
    }
  }

  buffer = gst_buffer_make_writable (buffer);

  bpf = interaudiosrc->info.bpf;
  if (n < period_samples) {
    GstMapInfo map;
    GstMemory *mem;

    GST_DEBUG_OBJECT (interaudiosrc,
        "creating %" G_GUINT64_FORMAT " samples of silence",
        period_samples - n);
    mem = gst_allocator_alloc (NULL, (period_samples - n) * bpf, NULL);
    if (gst_memory_map (mem, &map, GST_MAP_WRITE)) {
      gst_audio_format_fill_silence (interaudiosrc->info.finfo, map.data,
          map.size);
      gst_memory_unmap (mem, &map);
    }
    gst_buffer_prepend_memory (buffer, mem);
  }
  n = period_samples;

  GST_BUFFER_OFFSET (buffer) = interaudiosrc->n_samples;
  GST_BUFFER_OFFSET_END (buffer) = interaudiosrc->n_samples + n;
  GST_BUFFER_TIMESTAMP (buffer) = interaudiosrc->timestamp_offset +
      gst_util_uint64_scale (interaudiosrc->n_samples, GST_SECOND,
      interaudiosrc->info.rate);
  GST_DEBUG_OBJECT (interaudiosrc, "create ts %" GST_TIME_FORMAT,
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
  GST_BUFFER_DURATION (buffer) = interaudiosrc->timestamp_offset +
      gst_util_uint64_scale (interaudiosrc->n_samples + n, GST_SECOND,
      interaudiosrc->info.rate) - GST_BUFFER_TIMESTAMP (buffer);
  GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
  if (interaudiosrc->n_samples == 0) {
    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
  }
  interaudiosrc->n_samples += n;

  *buf = buffer;

  return GST_FLOW_OK;
}
Beispiel #16
0
static gboolean gst_avdtp_sink_init_mp3_pkt_conf(
		GstAvdtpSink *self, GstCaps *caps,
		mpeg_capabilities_t *pkt)
{
	const GValue *value = NULL;
	gint rate, layer;
	const gchar *name;
	GstStructure *structure = gst_caps_get_structure(caps, 0);

	name = gst_structure_get_name(structure);

	if (!(IS_MPEG_AUDIO(name))) {
		GST_ERROR_OBJECT(self, "Unexpected format %s, "
				"was expecting mp3", name);
		return FALSE;
	}

	/* layer */
	value = gst_structure_get_value(structure, "layer");
	layer = g_value_get_int(value);
	if (layer == 1)
		pkt->layer = BT_MPEG_LAYER_1;
	else if (layer == 2)
		pkt->layer = BT_MPEG_LAYER_2;
	else if (layer == 3)
		pkt->layer = BT_MPEG_LAYER_3;
	else {
		GST_ERROR_OBJECT(self, "Unexpected layer: %d", layer);
		return FALSE;
	}

	/* crc */
	if (self->mp3_using_crc != -1)
		pkt->crc = self->mp3_using_crc;
	else {
		GST_ERROR_OBJECT(self, "No info about crc was received, "
				" can't proceed");
		return FALSE;
	}

	/* channel mode */
	if (self->channel_mode != -1)
		pkt->channel_mode = self->channel_mode;
	else {
		GST_ERROR_OBJECT(self, "No info about channel mode "
				"received, can't proceed");
		return FALSE;
	}

	/* mpf - we will only use the mandatory one */
	pkt->mpf = 0;

	value = gst_structure_get_value(structure, "rate");
	rate = g_value_get_int(value);
	if (rate == 44100)
		pkt->frequency = BT_MPEG_SAMPLING_FREQ_44100;
	else if (rate == 48000)
		pkt->frequency = BT_MPEG_SAMPLING_FREQ_48000;
	else if (rate == 32000)
		pkt->frequency = BT_MPEG_SAMPLING_FREQ_32000;
	else if (rate == 24000)
		pkt->frequency = BT_MPEG_SAMPLING_FREQ_24000;
	else if (rate == 22050)
		pkt->frequency = BT_MPEG_SAMPLING_FREQ_22050;
	else if (rate == 16000)
		pkt->frequency = BT_MPEG_SAMPLING_FREQ_16000;
	else {
		GST_ERROR_OBJECT(self, "Invalid rate while setting caps");
		return FALSE;
	}

	/* vbr - we always say its vbr, we don't have how to know it */
	pkt->bitrate = 0x8000;

	return TRUE;
}
static GstFlowReturn
gst_openjpeg_dec_negotiate (GstOpenJPEGDec * self, opj_image_t * image)
{
  GstVideoFormat format;
  gint width, height;

  if (image->color_space == OPJ_CLRSPC_UNKNOWN || image->color_space == 0)
    image->color_space = self->color_space;

  switch (image->color_space) {
    case OPJ_CLRSPC_SRGB:
      if (image->numcomps == 4) {
        if (image->comps[0].dx != 1 || image->comps[0].dy != 1 ||
            image->comps[1].dx != 1 || image->comps[1].dy != 1 ||
            image->comps[2].dx != 1 || image->comps[2].dy != 1 ||
            image->comps[3].dx != 1 || image->comps[3].dy != 1) {
          GST_ERROR_OBJECT (self, "Sub-sampling for RGB not supported");
          return GST_FLOW_NOT_NEGOTIATED;
        }

        if (get_highest_prec (image) == 8) {
          self->fill_frame = fill_frame_packed8_4;
          format = GST_VIDEO_FORMAT_ARGB;
        } else if (get_highest_prec (image) <= 16) {
          self->fill_frame = fill_frame_packed16_4;
          format = GST_VIDEO_FORMAT_ARGB64;
        } else {
          GST_ERROR_OBJECT (self, "Unsupported depth %d", image->comps[3].prec);
          return GST_FLOW_NOT_NEGOTIATED;
        }
      } else if (image->numcomps == 3) {
        if (image->comps[0].dx != 1 || image->comps[0].dy != 1 ||
            image->comps[1].dx != 1 || image->comps[1].dy != 1 ||
            image->comps[2].dx != 1 || image->comps[2].dy != 1) {
          GST_ERROR_OBJECT (self, "Sub-sampling for RGB not supported");
          return GST_FLOW_NOT_NEGOTIATED;
        }

        if (get_highest_prec (image) == 8) {
          self->fill_frame = fill_frame_packed8_3;
          format = GST_VIDEO_FORMAT_ARGB;
        } else if (get_highest_prec (image) <= 16) {
          self->fill_frame = fill_frame_packed16_3;
          format = GST_VIDEO_FORMAT_ARGB64;
        } else {
          GST_ERROR_OBJECT (self, "Unsupported depth %d",
              get_highest_prec (image));
          return GST_FLOW_NOT_NEGOTIATED;
        }
      } else {
        GST_ERROR_OBJECT (self, "Unsupported number of RGB components: %d",
            image->numcomps);
        return GST_FLOW_NOT_NEGOTIATED;
      }
      break;
    case OPJ_CLRSPC_GRAY:
      if (image->numcomps == 1) {
        if (image->comps[0].dx != 1 && image->comps[0].dy != 1) {
          GST_ERROR_OBJECT (self, "Sub-sampling for GRAY not supported");
          return GST_FLOW_NOT_NEGOTIATED;
        }

        if (get_highest_prec (image) == 8) {
          self->fill_frame = fill_frame_planar8_1;
          format = GST_VIDEO_FORMAT_GRAY8;
        } else if (get_highest_prec (image) <= 16) {
          self->fill_frame = fill_frame_planar16_1;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
          format = GST_VIDEO_FORMAT_GRAY16_LE;
#else
          format = GST_VIDEO_FORMAT_GRAY16_BE;
#endif
        } else {
          GST_ERROR_OBJECT (self, "Unsupported depth %d",
              get_highest_prec (image));
          return GST_FLOW_NOT_NEGOTIATED;
        }
      } else {
        GST_ERROR_OBJECT (self, "Unsupported number of GRAY components: %d",
            image->numcomps);
        return GST_FLOW_NOT_NEGOTIATED;
      }
      break;
    case OPJ_CLRSPC_SYCC:
      if (image->numcomps != 3 && image->numcomps != 4) {
        GST_ERROR_OBJECT (self, "Unsupported number of YUV components: %d",
            image->numcomps);
        return GST_FLOW_NOT_NEGOTIATED;
      }

      if (image->comps[0].dx != 1 || image->comps[0].dy != 1) {
        GST_ERROR_OBJECT (self, "Sub-sampling of luma plane not supported");
        return GST_FLOW_NOT_NEGOTIATED;
      }

      if (image->comps[1].dx != image->comps[2].dx ||
          image->comps[1].dy != image->comps[2].dy) {
        GST_ERROR_OBJECT (self,
            "Different sub-sampling of chroma planes not supported");
        return GST_FLOW_ERROR;
      }

      if (image->numcomps == 4) {
        if (image->comps[3].dx != 1 || image->comps[3].dy != 1) {
          GST_ERROR_OBJECT (self, "Sub-sampling of alpha plane not supported");
          return GST_FLOW_NOT_NEGOTIATED;
        }

        if (get_highest_prec (image) == 8) {
          self->fill_frame = fill_frame_planar8_4_generic;
          format = GST_VIDEO_FORMAT_AYUV;
        } else if (image->comps[3].prec <= 16) {
          self->fill_frame = fill_frame_planar16_4_generic;
          format = GST_VIDEO_FORMAT_AYUV64;
        } else {
          GST_ERROR_OBJECT (self, "Unsupported depth %d", image->comps[0].prec);
          return GST_FLOW_NOT_NEGOTIATED;
        }
      } else if (image->numcomps == 3) {
        if (get_highest_prec (image) == 8) {
          if (image->comps[1].dx == 1 && image->comps[1].dy == 1) {
            self->fill_frame = fill_frame_planar8_3;
            format = GST_VIDEO_FORMAT_Y444;
          } else if (image->comps[1].dx == 2 && image->comps[1].dy == 1) {
            self->fill_frame = fill_frame_planar8_3;
            format = GST_VIDEO_FORMAT_Y42B;
          } else if (image->comps[1].dx == 2 && image->comps[1].dy == 2) {
            self->fill_frame = fill_frame_planar8_3;
            format = GST_VIDEO_FORMAT_I420;
          } else if (image->comps[1].dx == 4 && image->comps[1].dy == 1) {
            self->fill_frame = fill_frame_planar8_3;
            format = GST_VIDEO_FORMAT_Y41B;
          } else if (image->comps[1].dx == 4 && image->comps[1].dy == 4) {
            self->fill_frame = fill_frame_planar8_3;
            format = GST_VIDEO_FORMAT_YUV9;
          } else {
            self->fill_frame = fill_frame_planar8_3_generic;
            format = GST_VIDEO_FORMAT_AYUV;
          }
        } else if (get_highest_prec (image) <= 16) {
          if (image->comps[0].prec == 10 &&
              image->comps[1].prec == 10 && image->comps[2].prec == 10) {
            if (image->comps[1].dx == 1 && image->comps[1].dy == 1) {
              self->fill_frame = fill_frame_planar16_3;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
              format = GST_VIDEO_FORMAT_Y444_10LE;
#else
              format = GST_VIDEO_FORMAT_Y444_10BE;
#endif
            } else if (image->comps[1].dx == 2 && image->comps[1].dy == 1) {
              self->fill_frame = fill_frame_planar16_3;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
              format = GST_VIDEO_FORMAT_I422_10LE;
#else
              format = GST_VIDEO_FORMAT_I422_10BE;
#endif
            } else if (image->comps[1].dx == 2 && image->comps[1].dy == 2) {
              self->fill_frame = fill_frame_planar16_3;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
              format = GST_VIDEO_FORMAT_I420_10LE;
#else
              format = GST_VIDEO_FORMAT_I420_10BE;
#endif
            } else {
              self->fill_frame = fill_frame_planar16_3_generic;
              format = GST_VIDEO_FORMAT_AYUV64;
            }
          } else {
            self->fill_frame = fill_frame_planar16_3_generic;
            format = GST_VIDEO_FORMAT_AYUV64;
          }
        } else {
          GST_ERROR_OBJECT (self, "Unsupported depth %d",
              get_highest_prec (image));
          return GST_FLOW_NOT_NEGOTIATED;
        }
      } else {
        GST_ERROR_OBJECT (self, "Unsupported number of YUV components: %d",
            image->numcomps);
        return GST_FLOW_NOT_NEGOTIATED;
      }
      break;
    default:
      GST_ERROR_OBJECT (self, "Unsupported colorspace %d", image->color_space);
      return GST_FLOW_NOT_NEGOTIATED;
  }

  width = image->x1 - image->x0;
  height = image->y1 - image->y0;

  if (!self->output_state ||
      self->output_state->info.finfo->format != format ||
      self->output_state->info.width != width ||
      self->output_state->info.height != height) {
    if (self->output_state)
      gst_video_codec_state_unref (self->output_state);
    self->output_state =
        gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self), format,
        width, height, self->input_state);

    if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self)))
      return GST_FLOW_NOT_NEGOTIATED;
  }

  return GST_FLOW_OK;
}
static GstFlowReturn
gst_video_mark_yuv (GstSimpleVideoMark * simplevideomark, GstVideoFrame * frame)
{
  gint i, pw, ph, row_stride, pixel_stride;
  gint width, height, offset_calc, x, y;
  guint8 *d;
  guint64 pattern_shift;
  guint8 color;
  gint total_pattern;

  width = frame->info.width;
  height = frame->info.height;

  pw = simplevideomark->pattern_width;
  ph = simplevideomark->pattern_height;
  row_stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
  pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);

  d = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
  offset_calc =
      row_stride * (height - ph - simplevideomark->bottom_offset) +
      pixel_stride * simplevideomark->left_offset;
  x = simplevideomark->left_offset;
  y = height - ph - simplevideomark->bottom_offset;

  total_pattern =
      simplevideomark->pattern_count + simplevideomark->pattern_data_count;
  /* If x and y offset values are outside the video, no need to draw */
  if ((x + (pw * total_pattern)) < 0 || x > width || (y + height) < 0
      || y > height) {
    GST_ERROR_OBJECT (simplevideomark,
        "simplevideomark pattern is outside the video. Not drawing.");
    return GST_FLOW_OK;
  }

  /* Offset calculation less than 0, then reset to 0 */
  if (offset_calc < 0)
    offset_calc = 0;
  /* Y position of mark is negative or pattern exceeds the video height,
     then recalculate pattern height for partial display */
  if (y < 0)
    ph += y;
  else if ((y + ph) > height)
    ph = height - y;
  /* If pattern height is less than 0, need not draw anything */
  if (ph < 0)
    return GST_FLOW_OK;

  /* move to start of bottom left */
  d += offset_calc;

  /* draw the bottom left pixels */
  for (i = 0; i < simplevideomark->pattern_count; i++) {
    gint draw_pw;

    if (i & 1)
      /* odd pixels must be white */
      color = 255;
    else
      color = 0;

    /* X position of mark is negative or pattern exceeds the video width,
       then recalculate pattern width for partial display */
    draw_pw = calculate_pw (pw, x, width);
    /* If pattern width is less than 0, continue with the next pattern */
    if (draw_pw < 0)
      continue;

    /* draw box of width * height */
    gst_video_mark_draw_box (simplevideomark, d, draw_pw, ph, row_stride,
        pixel_stride, color);

    /* move to i-th pattern */
    d += pixel_stride * draw_pw;
    x += draw_pw;

    if ((x + (pw * (total_pattern - i - 1))) < 0 || x >= width)
      return GST_FLOW_OK;
  }

  pattern_shift =
      G_GUINT64_CONSTANT (1) << (simplevideomark->pattern_data_count - 1);

  /* get the data of the pattern */
  for (i = 0; i < simplevideomark->pattern_data_count; i++) {
    gint draw_pw;
    if (simplevideomark->pattern_data & pattern_shift)
      color = 255;
    else
      color = 0;

    /* X position of mark is negative or pattern exceeds the video width,
       then recalculate pattern width for partial display */
    draw_pw = calculate_pw (pw, x, width);
    /* If pattern width is less than 0, continue with the next pattern */
    if (draw_pw < 0)
      continue;

    gst_video_mark_draw_box (simplevideomark, d, draw_pw, ph, row_stride,
        pixel_stride, color);

    pattern_shift >>= 1;

    /* move to i-th pattern data */
    d += pixel_stride * draw_pw;
    x += draw_pw;

    if ((x + (pw * (simplevideomark->pattern_data_count - i - 1))) < 0
        || x >= width)
      return GST_FLOW_OK;
  }

  return GST_FLOW_OK;
}
Beispiel #19
0
static void
gst_insert_bin_do_change (GstInsertBin * self, GstPad * pad)
{
  struct ChangeData *data;

  GST_OBJECT_LOCK (self);

  if (!is_right_direction_for_block (pad)) {
    GST_WARNING_OBJECT (self, "Block pad does not have the expected direction");
    goto next;
  }

  while ((data = g_queue_pop_head (&self->priv->change_queue)) != NULL) {
    GstPad *peer = NULL;
    GstPad *other_peer = NULL;

    GST_OBJECT_UNLOCK (self);


    if (data->action == GST_INSERT_BIN_ACTION_ADD &&
        !validate_element (self, data->element))
      goto error;

    peer = gst_pad_get_peer (pad);

    if (peer == NULL) {
      GST_WARNING_OBJECT (self, "Blocked pad has no peer");
      goto error;
    }

    if (data->action == GST_INSERT_BIN_ACTION_ADD) {
      GstPad *srcpad = NULL, *sinkpad = NULL;
      GstPad *peersrcpad, *peersinkpad;

      /* First let's make sure we have the right pad */
      if (data->sibling) {
        GstElement *parent = NULL;
        GstPad *siblingpad;

        if ((gst_pad_get_direction (pad) == GST_PAD_SRC &&
                data->direction == DIRECTION_BEFORE) ||
            (gst_pad_get_direction (pad) == GST_PAD_SINK &&
                data->direction == DIRECTION_AFTER))
          siblingpad = peer;
        else
          siblingpad = pad;

        parent = gst_pad_get_parent_element (siblingpad);
        if (parent != NULL)
          gst_object_unref (parent);

        if (parent != data->sibling)
          goto retry;
      } else {
        GstObject *parent;
        GstPad *ghost;
        GstPad *proxypad;

        if (data->direction == DIRECTION_BEFORE) {
          ghost = self->priv->srcpad;
          if (gst_pad_get_direction (pad) == GST_PAD_SINK)
            proxypad = pad;
          else
            proxypad = peer;
        } else {
          ghost = self->priv->sinkpad;
          if (gst_pad_get_direction (pad) == GST_PAD_SINK)
            proxypad = peer;
          else
            proxypad = pad;
        }

        if (!GST_IS_PROXY_PAD (proxypad))
          goto retry;
        parent = gst_pad_get_parent (proxypad);
        if (!parent)
          goto retry;
        gst_object_unref (parent);
        if (GST_PAD_CAST (parent) != ghost)
          goto retry;
      }

      if (gst_pad_get_direction (pad) == GST_PAD_SRC) {
        peersrcpad = pad;
        peersinkpad = peer;
      } else {
        peersrcpad = peer;
        peersinkpad = pad;
      }

      if (GST_IS_PROXY_PAD (peersrcpad)) {
        GstObject *parent = gst_pad_get_parent (peersrcpad);

        if (GST_PAD_CAST (parent) == self->priv->sinkpad)
          peersrcpad = NULL;

        if (parent)
          gst_object_unref (parent);
      }

      if (GST_IS_PROXY_PAD (peersinkpad)) {
        GstObject *parent = gst_pad_get_parent (peersinkpad);

        if (GST_PAD_CAST (parent) == self->priv->srcpad)
          peersinkpad = NULL;

        if (parent)
          gst_object_unref (parent);
      }

      if (peersinkpad && peersrcpad) {
        gst_pad_unlink (peersrcpad, peersinkpad);
      } else {
        if (!peersinkpad)
          gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->srcpad), NULL);
        if (!peersrcpad)
          gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->sinkpad), NULL);
      }

      srcpad = get_single_pad (data->element, GST_PAD_SRC);
      sinkpad = get_single_pad (data->element, GST_PAD_SINK);

      if (srcpad == NULL || sinkpad == NULL) {
        GST_WARNING_OBJECT (self, "Can not get element src or sink pad");
        goto error;
      }

      if (!gst_bin_add (GST_BIN (self), data->element)) {
        GST_WARNING_OBJECT (self, "Can not add element to bin");
        goto error;
      }

      if (peersrcpad) {
        if (GST_PAD_LINK_FAILED (gst_pad_link (peersrcpad, sinkpad))) {
          GST_WARNING_OBJECT (self, "Can not link sibling's %s:%s pad"
              " to element's %s:%s pad", GST_DEBUG_PAD_NAME (peersrcpad),
              GST_DEBUG_PAD_NAME (sinkpad));
          goto error;
        }
      } else {
        if (!gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->sinkpad),
                sinkpad)) {
          GST_WARNING_OBJECT (self, "Can not set %s:%s as target for %s:%s",
              GST_DEBUG_PAD_NAME (sinkpad),
              GST_DEBUG_PAD_NAME (self->priv->sinkpad));
          goto error;
        }
      }

      if (peersinkpad) {
        if (GST_PAD_LINK_FAILED (gst_pad_link (srcpad, peersinkpad))) {
          GST_WARNING_OBJECT (self, "Can not link element's %s:%s pad"
              " to sibling's %s:%s pad", GST_DEBUG_PAD_NAME (srcpad),
              GST_DEBUG_PAD_NAME (peersinkpad));
          goto error;
        }
      } else {
        if (!gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->srcpad),
                srcpad)) {
          GST_WARNING_OBJECT (self, "Can not set %s:%s as target for %s:%s",
              GST_DEBUG_PAD_NAME (srcpad),
              GST_DEBUG_PAD_NAME (self->priv->srcpad));
          goto error;
        }
      }

      gst_object_unref (srcpad);
      gst_object_unref (sinkpad);

      if (!gst_element_sync_state_with_parent (data->element)) {
        GST_WARNING_OBJECT (self, "Can not sync element's state with parent");
        goto error;
      }
    } else {
      GstElement *parent = NULL;
      GstPad *other_pad;
      GstCaps *caps = NULL, *peercaps = NULL;
      gboolean can_intersect;
      gboolean success;

      parent = gst_pad_get_parent_element (peer);
      if (parent != NULL)
        gst_object_unref (parent);

      if (parent != data->element)
        goto retry;

      if (gst_pad_get_direction (peer) == GST_PAD_SRC)
        other_pad = get_single_pad (data->element, GST_PAD_SINK);
      else
        other_pad = get_single_pad (data->element, GST_PAD_SRC);

      if (!other_pad) {
        GST_WARNING_OBJECT (self, "Can not get element's other pad");
        goto error;
      }

      other_peer = gst_pad_get_peer (other_pad);
      gst_object_unref (other_pad);

      if (!other_peer) {
        GST_WARNING_OBJECT (self, "Can not get element's other peer");
        goto error;
      }

      /* Get the negotiated caps for the source pad peer,
       * because renegotiation while the pipeline is playing doesn't work
       * that fast.
       */
      if (gst_pad_get_direction (pad) == GST_PAD_SRC)
        caps = gst_pad_get_current_caps (pad);
      else
        peercaps = gst_pad_get_current_caps (other_peer);
      if (!caps)
        caps = gst_pad_query_caps (pad, NULL);
      if (!peercaps)
        peercaps = gst_pad_query_caps (other_peer, NULL);
      can_intersect = gst_caps_can_intersect (caps, peercaps);
      gst_caps_unref (caps);
      gst_caps_unref (peercaps);

      if (!can_intersect) {
        GST_WARNING_OBJECT (self, "Pads are incompatible without the element");
        goto error;
      }

      if (gst_pad_get_direction (other_peer) == GST_PAD_SRC &&
          gst_pad_is_active (other_peer)) {
        gulong probe_id;

        probe_id = gst_pad_add_probe (other_peer,
            GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
            wait_and_drop_eos_cb, NULL, NULL);
        gst_pad_send_event (peer, gst_event_new_eos ());
        gst_pad_remove_probe (other_peer, probe_id);
      }

      gst_element_set_locked_state (data->element, TRUE);
      gst_element_set_state (data->element, GST_STATE_NULL);
      if (!gst_bin_remove (GST_BIN (self), data->element)) {
        GST_WARNING_OBJECT (self, "Element removal rejected");
        goto error;
      }
      gst_element_set_locked_state (data->element, FALSE);

      if (gst_pad_get_direction (pad) == GST_PAD_SRC)
        success = GST_PAD_LINK_SUCCESSFUL (gst_pad_link_full (pad, other_peer,
                GST_PAD_LINK_CHECK_HIERARCHY |
                GST_PAD_LINK_CHECK_TEMPLATE_CAPS));
      else
        success = GST_PAD_LINK_SUCCESSFUL (gst_pad_link_full (other_peer, pad,
                GST_PAD_LINK_CHECK_HIERARCHY |
                GST_PAD_LINK_CHECK_TEMPLATE_CAPS));
      gst_object_unref (other_peer);
      other_peer = NULL;

      if (!success) {
        GST_ERROR_OBJECT (self, "Could not re-link after the element's"
            " removal");
        goto error;
      }
    }


    gst_insert_bin_change_data_complete (self, data, TRUE);
    gst_object_unref (peer);

    GST_OBJECT_LOCK (self);
    continue;
  done:
    if (other_peer != NULL)
      gst_object_unref (other_peer);

    if (peer != NULL)
      gst_object_unref (peer);
    break;
  retry:
    GST_OBJECT_LOCK (self);
    g_queue_push_head (&self->priv->change_queue, data);
    goto done;
  error:
    /* Handle error */
    gst_insert_bin_change_data_complete (self, data, FALSE);
    GST_OBJECT_LOCK (self);
    goto done;
  }

next:
  gst_insert_bin_block_pad_unlock (self);
}
static gboolean
gst_video_convert_set_info (GstVideoFilter * filter,
    GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
    GstVideoInfo * out_info)
{
  GstVideoConvert *space;

  space = GST_VIDEO_CONVERT_CAST (filter);

  if (space->convert) {
    gst_video_converter_free (space->convert);
    space->convert = NULL;
  }

  /* these must match */
  if (in_info->width != out_info->width || in_info->height != out_info->height
      || in_info->fps_n != out_info->fps_n || in_info->fps_d != out_info->fps_d)
    goto format_mismatch;

  /* if present, these must match too */
  if (in_info->par_n != out_info->par_n || in_info->par_d != out_info->par_d)
    goto format_mismatch;

  /* if present, these must match too */
  if (in_info->interlace_mode != out_info->interlace_mode)
    goto format_mismatch;


  space->convert = gst_video_converter_new (in_info, out_info,
      gst_structure_new ("GstVideoConvertConfig",
          GST_VIDEO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_VIDEO_DITHER_METHOD,
          space->dither,
          GST_VIDEO_CONVERTER_OPT_DITHER_QUANTIZATION, G_TYPE_UINT,
          space->dither_quantization,
          GST_VIDEO_CONVERTER_OPT_CHROMA_RESAMPLER_METHOD,
          GST_TYPE_VIDEO_RESAMPLER_METHOD, space->chroma_resampler,
          GST_VIDEO_CONVERTER_OPT_ALPHA_MODE,
          GST_TYPE_VIDEO_ALPHA_MODE, space->alpha_mode,
          GST_VIDEO_CONVERTER_OPT_ALPHA_VALUE,
          G_TYPE_DOUBLE, space->alpha_value,
          GST_VIDEO_CONVERTER_OPT_CHROMA_MODE,
          GST_TYPE_VIDEO_CHROMA_MODE, space->chroma_mode,
          GST_VIDEO_CONVERTER_OPT_MATRIX_MODE,
          GST_TYPE_VIDEO_MATRIX_MODE, space->matrix_mode,
          GST_VIDEO_CONVERTER_OPT_GAMMA_MODE,
          GST_TYPE_VIDEO_GAMMA_MODE, space->gamma_mode,
          GST_VIDEO_CONVERTER_OPT_PRIMARIES_MODE,
          GST_TYPE_VIDEO_PRIMARIES_MODE, space->primaries_mode,
          GST_VIDEO_CONVERTER_OPT_THREADS, G_TYPE_UINT,
          space->n_threads, NULL));
  if (space->convert == NULL)
    goto no_convert;

  GST_DEBUG ("reconfigured %d %d", GST_VIDEO_INFO_FORMAT (in_info),
      GST_VIDEO_INFO_FORMAT (out_info));

  return TRUE;

  /* ERRORS */
format_mismatch:
  {
    GST_ERROR_OBJECT (space, "input and output formats do not match");
    return FALSE;
  }
no_convert:
  {
    GST_ERROR_OBJECT (space, "could not create converter");
    return FALSE;
  }
}
GstBuffer *
gst_egl_image_allocator_alloc_eglimage (GstAllocator * allocator,
    GstEGLDisplay * display, EGLContext eglcontext, GstVideoFormat format,
    gint width, gint height)
{
  GstEGLGLESImageData *data = NULL;
  GstBuffer *buffer;
  GstVideoInfo info;
  gint i;
  gint stride[3];
  gsize offset[3];
  GstMemory *mem[3] = { NULL, NULL, NULL };
  guint n_mem;
  GstMemoryFlags flags = 0;

  memset (stride, 0, sizeof (stride));
  memset (offset, 0, sizeof (offset));

  if (!gst_egl_image_memory_is_mappable ())
    flags |= GST_MEMORY_FLAG_NOT_MAPPABLE;
  /* See https://bugzilla.gnome.org/show_bug.cgi?id=695203 */
  flags |= GST_MEMORY_FLAG_NO_SHARE;

  gst_video_info_set_format (&info, format, width, height);

  switch (format) {
    case GST_VIDEO_FORMAT_RGB:
    case GST_VIDEO_FORMAT_BGR:{
      gsize size;
      EGLImageKHR image;

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info),
          GST_VIDEO_INFO_HEIGHT (&info), &size);
      if (mem[0]) {
        stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 1;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        data = g_slice_new0 (GstEGLGLESImageData);

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 3);
        size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);

        glGenTextures (1, &data->texture);
        if (got_gl_error ("glGenTextures"))
          goto mem_error;

        glBindTexture (GL_TEXTURE_2D, data->texture);
        if (got_gl_error ("glBindTexture"))
          goto mem_error;

        /* Set 2D resizing params */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        /* If these are not set the texture image unit will return
         * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
         * * frames. For a deeper explanation take a look at the OpenGL ES
         * * documentation for glTexParameter */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        if (got_gl_error ("glTexParameteri"))
          goto mem_error;

        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
            GST_VIDEO_INFO_WIDTH (&info),
            GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
        if (got_gl_error ("glTexImage2D"))
          goto mem_error;

        image =
            eglCreateImageKHR (gst_egl_display_get (display),
            eglcontext, EGL_GL_TEXTURE_2D_KHR,
            (EGLClientBuffer) (guintptr) data->texture, NULL);
        if (got_egl_error ("eglCreateImageKHR"))
          goto mem_error;

        mem[0] =
            gst_egl_image_allocator_wrap (allocator, display,
            image, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
            flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
        n_mem = 1;
      }
      break;
    }
    case GST_VIDEO_FORMAT_RGB16:{
      EGLImageKHR image;
      gsize size;

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info),
          GST_VIDEO_INFO_HEIGHT (&info), &size);
      if (mem[0]) {
        stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 1;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        data = g_slice_new0 (GstEGLGLESImageData);

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 2);
        size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);

        glGenTextures (1, &data->texture);
        if (got_gl_error ("glGenTextures"))
          goto mem_error;

        glBindTexture (GL_TEXTURE_2D, data->texture);
        if (got_gl_error ("glBindTexture"))
          goto mem_error;

        /* Set 2D resizing params */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        /* If these are not set the texture image unit will return
         * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
         * * frames. For a deeper explanation take a look at the OpenGL ES
         * * documentation for glTexParameter */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        if (got_gl_error ("glTexParameteri"))
          goto mem_error;

        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
            GST_VIDEO_INFO_WIDTH (&info),
            GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
            NULL);
        if (got_gl_error ("glTexImage2D"))
          goto mem_error;

        image =
            eglCreateImageKHR (gst_egl_display_get (display),
            eglcontext, EGL_GL_TEXTURE_2D_KHR,
            (EGLClientBuffer) (guintptr) data->texture, NULL);
        if (got_egl_error ("eglCreateImageKHR"))
          goto mem_error;

        mem[0] =
            gst_egl_image_allocator_wrap (allocator, display,
            image, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
            flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
        n_mem = 1;
      }
      break;
    }
    case GST_VIDEO_FORMAT_NV12:
    case GST_VIDEO_FORMAT_NV21:{
      EGLImageKHR image;
      gsize size[2];

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]);
      mem[1] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA,
          GST_VIDEO_INFO_COMP_WIDTH (&info, 1),
          GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]);

      if (mem[0] && mem[1]) {
        stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (&info);
        offset[1] = size[0];
        stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 2;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        if (mem[0])
          gst_memory_unref (mem[0]);
        if (mem[1])
          gst_memory_unref (mem[1]);
        mem[0] = mem[1] = NULL;

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 0));
        stride[1] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 1) * 2);
        offset[1] = stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 0);
        size[0] = offset[1];
        size[1] = stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 1);

        for (i = 0; i < 2; i++) {
          data = g_slice_new0 (GstEGLGLESImageData);

          glGenTextures (1, &data->texture);
          if (got_gl_error ("glGenTextures"))
            goto mem_error;

          glBindTexture (GL_TEXTURE_2D, data->texture);
          if (got_gl_error ("glBindTexture"))
            goto mem_error;

          /* Set 2D resizing params */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

          /* If these are not set the texture image unit will return
           * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
           * * frames. For a deeper explanation take a look at the OpenGL ES
           * * documentation for glTexParameter */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
          if (got_gl_error ("glTexParameteri"))
            goto mem_error;

          if (i == 0)
            glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
                GST_VIDEO_INFO_COMP_WIDTH (&info, i),
                GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE,
                GL_UNSIGNED_BYTE, NULL);
          else
            glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
                GST_VIDEO_INFO_COMP_WIDTH (&info, i),
                GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE_ALPHA,
                GL_UNSIGNED_BYTE, NULL);

          if (got_gl_error ("glTexImage2D"))
            goto mem_error;

          image =
              eglCreateImageKHR (gst_egl_display_get (display),
              eglcontext, EGL_GL_TEXTURE_2D_KHR,
              (EGLClientBuffer) (guintptr) data->texture, NULL);
          if (got_egl_error ("eglCreateImageKHR"))
            goto mem_error;

          mem[i] =
              gst_egl_image_allocator_wrap (allocator, display,
              image,
              (i ==
                  0 ? GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE :
                  GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA),
              flags, size[i], data,
              (GDestroyNotify) gst_egl_gles_image_data_free);
        }

        n_mem = 2;
      }
      break;
    }
    case GST_VIDEO_FORMAT_I420:
    case GST_VIDEO_FORMAT_YV12:
    case GST_VIDEO_FORMAT_Y444:
    case GST_VIDEO_FORMAT_Y42B:
    case GST_VIDEO_FORMAT_Y41B:{
      EGLImageKHR image;
      gsize size[3];

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]);
      mem[1] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              1), GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]);
      mem[2] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              2), GST_VIDEO_INFO_COMP_HEIGHT (&info, 2), &size[2]);

      if (mem[0] && mem[1] && mem[2]) {
        stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (&info);
        offset[1] = size[0];
        stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (&info);
        offset[2] = size[1];
        stride[2] = size[2] / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 3;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[2], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        if (mem[0])
          gst_memory_unref (mem[0]);
        if (mem[1])
          gst_memory_unref (mem[1]);
        if (mem[2])
          gst_memory_unref (mem[2]);
        mem[0] = mem[1] = mem[2] = NULL;

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 0));
        stride[1] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 1));
        stride[2] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 2));
        size[0] = stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 0);
        size[1] = stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 1);
        size[2] = stride[2] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 2);
        offset[0] = 0;
        offset[1] = size[0];
        offset[2] = offset[1] + size[1];

        for (i = 0; i < 3; i++) {
          data = g_slice_new0 (GstEGLGLESImageData);

          glGenTextures (1, &data->texture);
          if (got_gl_error ("glGenTextures"))
            goto mem_error;

          glBindTexture (GL_TEXTURE_2D, data->texture);
          if (got_gl_error ("glBindTexture"))
            goto mem_error;

          /* Set 2D resizing params */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

          /* If these are not set the texture image unit will return
           * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
           * * frames. For a deeper explanation take a look at the OpenGL ES
           * * documentation for glTexParameter */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
          if (got_gl_error ("glTexParameteri"))
            goto mem_error;

          glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
              GST_VIDEO_INFO_COMP_WIDTH (&info, i),
              GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE,
              GL_UNSIGNED_BYTE, NULL);

          if (got_gl_error ("glTexImage2D"))
            goto mem_error;

          image =
              eglCreateImageKHR (gst_egl_display_get (display),
              eglcontext, EGL_GL_TEXTURE_2D_KHR,
              (EGLClientBuffer) (guintptr) data->texture, NULL);
          if (got_egl_error ("eglCreateImageKHR"))
            goto mem_error;

          mem[i] =
              gst_egl_image_allocator_wrap (allocator, display,
              image, GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE,
              flags, size[i], data,
              (GDestroyNotify) gst_egl_gles_image_data_free);
        }

        n_mem = 3;
      }
      break;
    }
    case GST_VIDEO_FORMAT_RGBA:
    case GST_VIDEO_FORMAT_BGRA:
    case GST_VIDEO_FORMAT_ARGB:
    case GST_VIDEO_FORMAT_ABGR:
    case GST_VIDEO_FORMAT_RGBx:
    case GST_VIDEO_FORMAT_BGRx:
    case GST_VIDEO_FORMAT_xRGB:
    case GST_VIDEO_FORMAT_xBGR:
    case GST_VIDEO_FORMAT_AYUV:{
      gsize size;
      EGLImageKHR image;

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_INFO_WIDTH (&info),
          GST_VIDEO_INFO_HEIGHT (&info), &size);
      if (mem[0]) {
        stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 1;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        data = g_slice_new0 (GstEGLGLESImageData);

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 4);
        size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);

        glGenTextures (1, &data->texture);
        if (got_gl_error ("glGenTextures"))
          goto mem_error;

        glBindTexture (GL_TEXTURE_2D, data->texture);
        if (got_gl_error ("glBindTexture"))
          goto mem_error;

        /* Set 2D resizing params */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        /* If these are not set the texture image unit will return
         * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
         * * frames. For a deeper explanation take a look at the OpenGL ES
         * * documentation for glTexParameter */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        if (got_gl_error ("glTexParameteri"))
          goto mem_error;

        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
            GST_VIDEO_INFO_WIDTH (&info),
            GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        if (got_gl_error ("glTexImage2D"))
          goto mem_error;

        image =
            eglCreateImageKHR (gst_egl_display_get (display),
            eglcontext, EGL_GL_TEXTURE_2D_KHR,
            (EGLClientBuffer) (guintptr) data->texture, NULL);
        if (got_egl_error ("eglCreateImageKHR"))
          goto mem_error;

        mem[0] =
            gst_egl_image_allocator_wrap (allocator, display,
            image, GST_VIDEO_GL_TEXTURE_TYPE_RGBA,
            flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);

        n_mem = 1;
      }
      break;
    }
    default:
      g_assert_not_reached ();
      break;
  }

  buffer = gst_buffer_new ();
  gst_buffer_add_video_meta_full (buffer, 0, format, width, height,
      GST_VIDEO_INFO_N_PLANES (&info), offset, stride);

  for (i = 0; i < n_mem; i++)
    gst_buffer_append_memory (buffer, mem[i]);

  return buffer;

mem_error:
  {
    GST_ERROR_OBJECT (GST_CAT_DEFAULT, "Failed to create EGLImage");

    if (data)
      gst_egl_gles_image_data_free (data);

    if (mem[0])
      gst_memory_unref (mem[0]);
    if (mem[1])
      gst_memory_unref (mem[1]);
    if (mem[2])
      gst_memory_unref (mem[2]);

    return NULL;
  }
}
static gboolean
gst_gio_base_src_get_size (GstBaseSrc * base_src, guint64 * size)
{
  GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);

  if (G_IS_FILE_INPUT_STREAM (src->stream)) {
    GFileInfo *info;
    GError *err = NULL;

    info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (src->stream),
        G_FILE_ATTRIBUTE_STANDARD_SIZE, src->cancel, &err);

    if (info != NULL) {
      *size = g_file_info_get_size (info);
      g_object_unref (info);
      GST_DEBUG_OBJECT (src, "found size: %" G_GUINT64_FORMAT, *size);
      return TRUE;
    }

    if (!gst_gio_error (src, "g_file_input_stream_query_info", &err, NULL)) {

      if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED))
        GST_DEBUG_OBJECT (src, "size information not available");
      else
        GST_WARNING_OBJECT (src, "size information retrieval failed: %s",
            err->message);

      g_clear_error (&err);
    }
  }

  if (GST_GIO_STREAM_IS_SEEKABLE (src->stream)) {
    goffset old;
    goffset stream_size;
    gboolean ret;
    GSeekable *seekable = G_SEEKABLE (src->stream);
    GError *err = NULL;

    old = g_seekable_tell (seekable);

    ret = g_seekable_seek (seekable, 0, G_SEEK_END, src->cancel, &err);
    if (!ret) {
      if (!gst_gio_error (src, "g_seekable_seek", &err, NULL)) {
        if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED))
          GST_DEBUG_OBJECT (src,
              "Seeking to the end of stream is not supported");
        else
          GST_WARNING_OBJECT (src, "Seeking to end of stream failed: %s",
              err->message);
        g_clear_error (&err);
      } else {
        GST_WARNING_OBJECT (src, "Seeking to end of stream failed");
      }
      return FALSE;
    }

    stream_size = g_seekable_tell (seekable);

    ret = g_seekable_seek (seekable, old, G_SEEK_SET, src->cancel, &err);
    if (!ret) {
      if (!gst_gio_error (src, "g_seekable_seek", &err, NULL)) {
        if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED))
          GST_ERROR_OBJECT (src, "Seeking to the old position not supported");
        else
          GST_ERROR_OBJECT (src, "Seeking to the old position failed: %s",
              err->message);
        g_clear_error (&err);
      } else {
        GST_ERROR_OBJECT (src, "Seeking to the old position faile");
      }
      return FALSE;
    }

    if (stream_size >= 0) {
      *size = stream_size;
      return TRUE;
    }
  }

  return FALSE;
}
Beispiel #23
0
/* Answer the allocation query downstream. */
static gboolean
gst_video_filter_propose_allocation (GstBaseTransform * trans,
    GstQuery * decide_query, GstQuery * query)
{
  GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
  GstVideoInfo info;
  GstBufferPool *pool;
  GstCaps *caps;
  guint size;

  if (!GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
          decide_query, query))
    return FALSE;

  /* passthrough, we're done */
  if (decide_query == NULL)
    return TRUE;

  gst_query_parse_allocation (query, &caps, NULL);

  if (caps == NULL)
    return FALSE;

  if (!gst_video_info_from_caps (&info, caps))
    return FALSE;

  size = GST_VIDEO_INFO_SIZE (&info);

  if (gst_query_get_n_allocation_pools (query) == 0) {
    GstStructure *structure;
    GstAllocator *allocator = NULL;
    GstAllocationParams params = { 0, 0, 0, 15, };

    if (gst_query_get_n_allocation_params (query) > 0)
      gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
    else
      gst_query_add_allocation_param (query, allocator, &params);

    pool = gst_video_buffer_pool_new ();

    structure = gst_buffer_pool_get_config (pool);
    gst_buffer_pool_config_set_params (structure, caps, size, 0, 0);
    gst_buffer_pool_config_set_allocator (structure, allocator, &params);

    if (allocator)
      gst_object_unref (allocator);

    if (!gst_buffer_pool_set_config (pool, structure))
      goto config_failed;

    gst_query_add_allocation_pool (query, pool, size, 0, 0);
    gst_object_unref (pool);
    gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
  }

  return TRUE;

  /* ERRORS */
config_failed:
  {
    GST_ERROR_OBJECT (filter, "failed to set config");
    gst_object_unref (pool);
    return FALSE;
  }
}
static GstFlowReturn
gst_gio_base_src_create (GstBaseSrc * base_src, guint64 offset, guint size,
    GstBuffer ** buf_return)
{
  GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
  GstBuffer *buf;
  GstFlowReturn ret = GST_FLOW_OK;

  g_return_val_if_fail (G_IS_INPUT_STREAM (src->stream), GST_FLOW_ERROR);

  /* If we have the requested part in our cache take a subbuffer of that,
   * otherwise fill the cache again with at least 4096 bytes from the
   * requested offset and return a subbuffer of that.
   *
   * We need caching because every read/seek operation will need to go
   * over DBus if our backend is GVfs and this is painfully slow. */
  if (src->cache && offset >= GST_BUFFER_OFFSET (src->cache) &&
      offset + size <= GST_BUFFER_OFFSET_END (src->cache)) {
    GST_DEBUG_OBJECT (src, "Creating subbuffer from cached buffer: offset %"
        G_GUINT64_FORMAT " length %u", offset, size);

    buf = gst_buffer_create_sub (src->cache,
        offset - GST_BUFFER_OFFSET (src->cache), size);

    GST_BUFFER_OFFSET (buf) = offset;
    GST_BUFFER_OFFSET_END (buf) = offset + size;
    GST_BUFFER_SIZE (buf) = size;
  } else {
    guint cachesize = MAX (4096, size);
    gssize read, res;
    gboolean success, eos;
    GError *err = NULL;

    if (src->cache) {
      gst_buffer_unref (src->cache);
      src->cache = NULL;
    }

    if (G_UNLIKELY (offset != src->position)) {
      if (!GST_GIO_STREAM_IS_SEEKABLE (src->stream))
        return GST_FLOW_NOT_SUPPORTED;

      GST_DEBUG_OBJECT (src, "Seeking to position %" G_GUINT64_FORMAT, offset);
      ret = gst_gio_seek (src, G_SEEKABLE (src->stream), offset, src->cancel);

      if (ret == GST_FLOW_OK)
        src->position = offset;
      else
        return ret;
    }

    src->cache = gst_buffer_try_new_and_alloc (cachesize);
    if (G_UNLIKELY (src->cache == NULL)) {
      GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", cachesize);
      return GST_FLOW_ERROR;
    }

    GST_LOG_OBJECT (src, "Reading %u bytes from offset %" G_GUINT64_FORMAT,
        cachesize, offset);

    /* GIO sometimes gives less bytes than requested although
     * it's not at the end of file. SMB for example only
     * supports reads up to 64k. So we loop here until we get at
     * at least the requested amount of bytes or a read returns
     * nothing. */
    read = 0;
    while (size - read > 0 && (res =
            g_input_stream_read (G_INPUT_STREAM (src->stream),
                GST_BUFFER_DATA (src->cache) + read, cachesize - read,
                src->cancel, &err)) > 0) {
      read += res;
    }

    success = (read >= 0);
    eos = (cachesize > 0 && read == 0);

    if (!success && !gst_gio_error (src, "g_input_stream_read", &err, &ret)) {
      GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
          ("Could not read from stream: %s", err->message));
      g_clear_error (&err);
    }

    if (success && !eos) {
      src->position += read;
      GST_BUFFER_SIZE (src->cache) = read;

      GST_BUFFER_OFFSET (src->cache) = offset;
      GST_BUFFER_OFFSET_END (src->cache) = offset + read;

      GST_DEBUG_OBJECT (src, "Read successful");
      GST_DEBUG_OBJECT (src, "Creating subbuffer from new "
          "cached buffer: offset %" G_GUINT64_FORMAT " length %u", offset,
          size);

      buf = gst_buffer_create_sub (src->cache, 0, MIN (size, read));

      GST_BUFFER_OFFSET (buf) = offset;
      GST_BUFFER_OFFSET_END (buf) = offset + MIN (size, read);
      GST_BUFFER_SIZE (buf) = MIN (size, read);
    } else {
      GST_DEBUG_OBJECT (src, "Read not successful");
      gst_buffer_unref (src->cache);
      src->cache = NULL;
      buf = NULL;
    }

    if (eos)
      ret = GST_FLOW_UNEXPECTED;
  }

  *buf_return = buf;

  return ret;
}
static GstFlowReturn
gst_omx_audio_dec_drain (GstOMXAudioDec * self)
{
  GstOMXAudioDecClass *klass;
  GstOMXBuffer *buf;
  GstOMXAcquireBufferReturn acq_ret;
  OMX_ERRORTYPE err;

  GST_DEBUG_OBJECT (self, "Draining component");

  klass = GST_OMX_AUDIO_DEC_GET_CLASS (self);

  if (!self->started) {
    GST_DEBUG_OBJECT (self, "Component not started yet");
    return GST_FLOW_OK;
  }
  self->started = FALSE;

  if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
    GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
    return GST_FLOW_OK;
  }

  /* Make sure to release the base class stream lock, otherwise
   * _loop() can't call _finish_frame() and we might block forever
   * because no input buffers are released */
  GST_AUDIO_DECODER_STREAM_UNLOCK (self);

  /* Send an EOS buffer to the component and let the base
   * class drop the EOS event. We will send it later when
   * the EOS buffer arrives on the output port. */
  acq_ret = gst_omx_port_acquire_buffer (self->dec_in_port, &buf);
  if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
    GST_AUDIO_DECODER_STREAM_LOCK (self);
    GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d",
        acq_ret);
    return GST_FLOW_ERROR;
  }

  g_mutex_lock (&self->drain_lock);
  self->draining = TRUE;
  buf->omx_buf->nFilledLen = 0;
  buf->omx_buf->nTimeStamp =
      gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND,
      GST_SECOND);
  buf->omx_buf->nTickCount = 0;
  buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS;
  err = gst_omx_port_release_buffer (self->dec_in_port, buf);
  if (err != OMX_ErrorNone) {
    GST_ERROR_OBJECT (self, "Failed to drain component: %s (0x%08x)",
        gst_omx_error_to_string (err), err);
    g_mutex_unlock (&self->drain_lock);
    GST_AUDIO_DECODER_STREAM_LOCK (self);
    return GST_FLOW_ERROR;
  }

  GST_DEBUG_OBJECT (self, "Waiting until component is drained");

  if (G_UNLIKELY (self->dec->hacks & GST_OMX_HACK_DRAIN_MAY_NOT_RETURN)) {
    gint64 wait_until = g_get_monotonic_time () + G_TIME_SPAN_SECOND / 2;

    if (!g_cond_wait_until (&self->drain_cond, &self->drain_lock, wait_until))
      GST_WARNING_OBJECT (self, "Drain timed out");
    else
      GST_DEBUG_OBJECT (self, "Drained component");

  } else {
    g_cond_wait (&self->drain_cond, &self->drain_lock);
    GST_DEBUG_OBJECT (self, "Drained component");
  }

  g_mutex_unlock (&self->drain_lock);
  GST_AUDIO_DECODER_STREAM_LOCK (self);

  self->started = FALSE;

  return GST_FLOW_OK;
}
static FLAC__StreamDecoderWriteStatus
gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
    const FLAC__int32 * const buffer[])
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstBuffer *outbuf;
  guint depth = frame->header.bits_per_sample;
  guint width, gdepth;
  guint sample_rate = frame->header.sample_rate;
  guint channels = frame->header.channels;
  guint samples = frame->header.blocksize;
  guint j, i;
  GstMapInfo map;
  gboolean caps_changed;
  GstAudioChannelPosition chanpos[8];

  GST_LOG_OBJECT (flacdec, "samples in frame header: %d", samples);

  if (depth == 0) {
    if (flacdec->depth < 4 || flacdec->depth > 32) {
      GST_ERROR_OBJECT (flacdec, "unsupported depth %d from STREAMINFO",
          flacdec->depth);
      ret = GST_FLOW_ERROR;
      goto done;
    }

    depth = flacdec->depth;
  }

  switch (depth) {
    case 8:
      gdepth = width = 8;
      break;
    case 12:
    case 16:
      gdepth = width = 16;
      break;
    case 20:
    case 24:
      gdepth = 24;
      width = 32;
      break;
    case 32:
      gdepth = width = 32;
      break;
    default:
      GST_ERROR_OBJECT (flacdec, "unsupported depth %d", depth);
      ret = GST_FLOW_ERROR;
      goto done;
  }

  if (sample_rate == 0) {
    if (flacdec->info.rate != 0) {
      sample_rate = flacdec->info.rate;
    } else {
      GST_ERROR_OBJECT (flacdec, "unknown sample rate");
      ret = GST_FLOW_ERROR;
      goto done;
    }
  }

  caps_changed = (sample_rate != GST_AUDIO_INFO_RATE (&flacdec->info))
      || (width != GST_AUDIO_INFO_WIDTH (&flacdec->info))
      || (gdepth != GST_AUDIO_INFO_DEPTH (&flacdec->info))
      || (channels != GST_AUDIO_INFO_CHANNELS (&flacdec->info));

  if (caps_changed
      || !gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (flacdec))) {
    GST_DEBUG_OBJECT (flacdec, "Negotiating %d Hz @ %d channels", sample_rate,
        channels);

    memcpy (chanpos, channel_positions[flacdec->info.channels - 1],
        sizeof (chanpos));
    gst_audio_channel_positions_to_valid_order (chanpos,
        flacdec->info.channels);
    gst_audio_info_set_format (&flacdec->info,
        gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, width, gdepth),
        sample_rate, channels, chanpos);

    /* Note: we create the inverse reordering map here */
    gst_audio_get_channel_reorder_map (flacdec->info.channels,
        flacdec->info.position, channel_positions[flacdec->info.channels - 1],
        flacdec->channel_reorder_map);

    flacdec->depth = depth;

    gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (flacdec),
        &flacdec->info);
  }

  outbuf =
      gst_buffer_new_allocate (NULL, samples * channels * (width / 8), NULL);

  gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
  if (width == 8) {
    gint8 *outbuffer = (gint8 *) map.data;
    gint *reorder_map = flacdec->channel_reorder_map;

    g_assert (gdepth == 8 && depth == 8);
    for (i = 0; i < samples; i++) {
      for (j = 0; j < channels; j++) {
        *outbuffer++ = (gint8) buffer[reorder_map[j]][i];
      }
    }
  } else if (width == 16) {
    gint16 *outbuffer = (gint16 *) map.data;
    gint *reorder_map = flacdec->channel_reorder_map;

    if (gdepth != depth) {
      for (i = 0; i < samples; i++) {
        for (j = 0; j < channels; j++) {
          *outbuffer++ =
              (gint16) (buffer[reorder_map[j]][i] << (gdepth - depth));
        }
      }
    } else {
      for (i = 0; i < samples; i++) {
        for (j = 0; j < channels; j++) {
          *outbuffer++ = (gint16) buffer[reorder_map[j]][i];
        }
      }
    }
  } else if (width == 32) {
    gint32 *outbuffer = (gint32 *) map.data;
    gint *reorder_map = flacdec->channel_reorder_map;

    if (gdepth != depth) {
      for (i = 0; i < samples; i++) {
        for (j = 0; j < channels; j++) {
          *outbuffer++ =
              (gint32) (buffer[reorder_map[j]][i] << (gdepth - depth));
        }
      }
    } else {
      for (i = 0; i < samples; i++) {
        for (j = 0; j < channels; j++) {
          *outbuffer++ = (gint32) buffer[reorder_map[j]][i];
        }
      }
    }
  } else {
    g_assert_not_reached ();
  }
  gst_buffer_unmap (outbuf, &map);

  GST_DEBUG_OBJECT (flacdec, "pushing %d samples", samples);
  if (flacdec->error_count)
    flacdec->error_count--;

  ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (flacdec), outbuf, 1);

  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
    GST_DEBUG_OBJECT (flacdec, "finish_frame flow %s", gst_flow_get_name (ret));
  }

done:

  /* we act on the flow return value later in the handle_frame function, as we
   * don't want to mess up the internal decoder state by returning ABORT when
   * the error is in fact non-fatal (like a pad in flushing mode) and we want
   * to continue later. So just pretend everything's dandy and act later. */
  flacdec->last_flow = ret;

  return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
static gboolean
gst_omx_audio_dec_set_format (GstAudioDecoder * decoder, GstCaps * caps)
{
  GstOMXAudioDec *self;
  GstOMXAudioDecClass *klass;
  GstStructure *s;
  const GValue *codec_data;
  gboolean is_format_change = FALSE;
  gboolean needs_disable = FALSE;

  self = GST_OMX_AUDIO_DEC (decoder);
  klass = GST_OMX_AUDIO_DEC_GET_CLASS (decoder);

  GST_DEBUG_OBJECT (self, "Setting new caps %" GST_PTR_FORMAT, caps);

  /* Check if the caps change is a real format change or if only irrelevant
   * parts of the caps have changed or nothing at all.
   */
  if (klass->is_format_change)
    is_format_change = klass->is_format_change (self, self->dec_in_port, caps);

  needs_disable =
      gst_omx_component_get_state (self->dec,
      GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
  /* If the component is not in Loaded state and a real format change happens
   * we have to disable the port and re-allocate all buffers. If no real
   * format change happened we can just exit here.
   */
  if (needs_disable && !is_format_change) {
    GST_DEBUG_OBJECT (self,
        "Already running and caps did not change the format");
    return TRUE;
  }

  if (needs_disable && is_format_change) {
    GstOMXPort *out_port = self->dec_out_port;

    GST_DEBUG_OBJECT (self, "Need to disable and drain decoder");

    gst_omx_audio_dec_drain (self);
    gst_omx_audio_dec_flush (decoder, FALSE);
    gst_omx_port_set_flushing (out_port, 5 * GST_SECOND, TRUE);

    if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) {
      GST_AUDIO_DECODER_STREAM_UNLOCK (self);
      gst_omx_audio_dec_stop (GST_AUDIO_DECODER (self));
      gst_omx_audio_dec_close (GST_AUDIO_DECODER (self));
      GST_AUDIO_DECODER_STREAM_LOCK (self);

      if (!gst_omx_audio_dec_open (GST_AUDIO_DECODER (self)))
        return FALSE;
      needs_disable = FALSE;
    } else {
      if (gst_omx_port_set_enabled (self->dec_in_port, FALSE) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_set_enabled (out_port, FALSE) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_wait_buffers_released (self->dec_in_port,
              5 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_wait_buffers_released (out_port,
              1 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_deallocate_buffers (self->dec_in_port) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_deallocate_buffers (self->dec_out_port) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_wait_enabled (self->dec_in_port,
              1 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_wait_enabled (out_port, 1 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;
    }

    GST_DEBUG_OBJECT (self, "Decoder drained and disabled");
  }

  if (klass->set_format) {
    if (!klass->set_format (self, self->dec_in_port, caps)) {
      GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
      return FALSE;
    }
  }

  GST_DEBUG_OBJECT (self, "Updating outport port definition");
  if (gst_omx_port_update_port_definition (self->dec_out_port,
          NULL) != OMX_ErrorNone)
    return FALSE;

  /* Get codec data from caps */
  gst_buffer_replace (&self->codec_data, NULL);
  s = gst_caps_get_structure (caps, 0);
  codec_data = gst_structure_get_value (s, "codec_data");
  if (codec_data) {
    /* Vorbis and some other codecs have multiple buffers in
     * the stream-header field */
    self->codec_data = gst_value_get_buffer (codec_data);
    if (self->codec_data)
      gst_buffer_ref (self->codec_data);
  }

  GST_DEBUG_OBJECT (self, "Enabling component");

  if (needs_disable) {
    if (gst_omx_port_set_enabled (self->dec_in_port, TRUE) != OMX_ErrorNone)
      return FALSE;
    if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
      return FALSE;

    if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
      if (gst_omx_port_set_enabled (self->dec_out_port, TRUE) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
        return FALSE;

      if (gst_omx_port_wait_enabled (self->dec_out_port,
              5 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;
    }

    if (gst_omx_port_wait_enabled (self->dec_in_port,
            5 * GST_SECOND) != OMX_ErrorNone)
      return FALSE;
    if (gst_omx_port_mark_reconfigured (self->dec_in_port) != OMX_ErrorNone)
      return FALSE;
  } else {
    if (!(klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
      /* Disable output port */
      if (gst_omx_port_set_enabled (self->dec_out_port, FALSE) != OMX_ErrorNone)
        return FALSE;

      if (gst_omx_port_wait_enabled (self->dec_out_port,
              1 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;

      if (gst_omx_component_set_state (self->dec,
              OMX_StateIdle) != OMX_ErrorNone)
        return FALSE;

      /* Need to allocate buffers to reach Idle state */
      if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
        return FALSE;
    } else {
      if (gst_omx_component_set_state (self->dec,
              OMX_StateIdle) != OMX_ErrorNone)
        return FALSE;

      /* Need to allocate buffers to reach Idle state */
      if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
        return FALSE;
    }

    if (gst_omx_component_get_state (self->dec,
            GST_CLOCK_TIME_NONE) != OMX_StateIdle)
      return FALSE;

    if (gst_omx_component_set_state (self->dec,
            OMX_StateExecuting) != OMX_ErrorNone)
      return FALSE;

    if (gst_omx_component_get_state (self->dec,
            GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
      return FALSE;
  }

  /* Unset flushing to allow ports to accept data again */
  gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, FALSE);
  gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);

  if (gst_omx_component_get_last_error (self->dec) != OMX_ErrorNone) {
    GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)",
        gst_omx_component_get_last_error_string (self->dec),
        gst_omx_component_get_last_error (self->dec));
    return FALSE;
  }

  self->downstream_flow_ret = GST_FLOW_OK;

  return TRUE;
}
Beispiel #28
0
/**
 * gst_rtsp_server_get_io_channel:
 * @server: a #GstRTSPServer
 *
 * Create a #GIOChannel for @server. The io channel will listen on the
 * configured service.
 *
 * Returns: the GIOChannel for @server or NULL when an error occured.
 */
GIOChannel *
gst_rtsp_server_get_io_channel (GstRTSPServer * server)
{
  GIOChannel *channel;
  int ret, sockfd = -1;
  struct addrinfo hints;
  struct addrinfo *result, *rp;
#ifdef USE_SOLINGER
  struct linger linger;
#endif

  g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);

  memset (&hints, 0, sizeof (struct addrinfo));
  hints.ai_family = AF_UNSPEC;  /* Allow IPv4 or IPv6 */
  hints.ai_socktype = SOCK_STREAM;      /* stream socket */
  hints.ai_flags = AI_PASSIVE | AI_CANONNAME;   /* For wildcard IP address */
  hints.ai_protocol = 0;        /* Any protocol */
  hints.ai_canonname = NULL;
  hints.ai_addr = NULL;
  hints.ai_next = NULL;

  GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address,
      server->service);

  GST_RTSP_SERVER_LOCK (server);
  /* resolve the server IP address */
  if ((ret =
          getaddrinfo (server->address, server->service, &hints, &result)) != 0)
    goto no_address;

  /* create server socket, we loop through all the addresses until we manage to
   * create a socket and bind. */
  for (rp = result; rp; rp = rp->ai_next) {
    sockfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
    if (sockfd == -1) {
      GST_DEBUG_OBJECT (server, "failed to make socket (%s), try next",
          g_strerror (errno));
      continue;
    }

    /* make address reusable */
    ret = 1;
    if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR,
            (void *) &ret, sizeof (ret)) < 0) {
      /* warn but try to bind anyway */
      GST_WARNING_OBJECT (server, "failed to reuse socker (%s)",
          g_strerror (errno));
    }

    if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0) {
      GST_DEBUG_OBJECT (server, "bind on %s", rp->ai_canonname);
      break;
    }

    GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next",
        g_strerror (errno));
    close (sockfd);
    sockfd = -1;
  }
  freeaddrinfo (result);

  if (sockfd == -1)
    goto no_socket;

  GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d", sockfd);

  /* keep connection alive; avoids SIGPIPE during write */
  ret = 1;
  if (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE,
          (void *) &ret, sizeof (ret)) < 0)
    goto keepalive_failed;

#ifdef USE_SOLINGER
  /* make sure socket is reset 5 seconds after close. This ensure that we can
   * reuse the socket quickly while still having a chance to send data to the
   * client. */
  linger.l_onoff = 1;
  linger.l_linger = 5;
  if (setsockopt (sockfd, SOL_SOCKET, SO_LINGER,
          (void *) &linger, sizeof (linger)) < 0)
    goto linger_failed;
#endif

  /* set the server socket to nonblocking */
  fcntl (sockfd, F_SETFL, O_NONBLOCK);

  GST_DEBUG_OBJECT (server, "listening on server socket %d with queue of %d",
      sockfd, server->backlog);
  if (listen (sockfd, server->backlog) == -1)
    goto listen_failed;

  GST_DEBUG_OBJECT (server,
      "listened on server socket %d, returning from connection setup", sockfd);

  /* create IO channel for the socket */
  channel = g_io_channel_unix_new (sockfd);
  g_io_channel_set_close_on_unref (channel, TRUE);

  GST_INFO_OBJECT (server, "listening on service %s", server->service);
  GST_RTSP_SERVER_UNLOCK (server);

  return channel;

  /* ERRORS */
no_address:
  {
    GST_ERROR_OBJECT (server, "failed to resolve address: %s",
        gai_strerror (ret));
    goto close_error;
  }
no_socket:
  {
    GST_ERROR_OBJECT (server, "failed to create socket: %s",
        g_strerror (errno));
    goto close_error;
  }
keepalive_failed:
  {
    GST_ERROR_OBJECT (server, "failed to configure keepalive socket: %s",
        g_strerror (errno));
    goto close_error;
  }
#ifdef USE_SOLINGER
linger_failed:
  {
    GST_ERROR_OBJECT (server, "failed to no linger socket: %s",
        g_strerror (errno));
    goto close_error;
  }
#endif
listen_failed:
  {
    GST_ERROR_OBJECT (server, "failed to listen on socket: %s",
        g_strerror (errno));
    goto close_error;
  }
close_error:
  {
    if (sockfd >= 0) {
      close (sockfd);
    }
    GST_RTSP_SERVER_UNLOCK (server);
    return NULL;
  }
}
static gboolean
gst_timecodestamper_sink_event (GstBaseTransform * trans, GstEvent * event)
{
  gboolean ret = FALSE;
  GstTimeCodeStamper *timecodestamper = GST_TIME_CODE_STAMPER (trans);

  GST_DEBUG_OBJECT (trans, "received event %" GST_PTR_FORMAT, event);
  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEGMENT:
    {
      GstSegment segment;
      guint64 frames;
      gchar *tc_str;
      gboolean notify = FALSE;

      GST_OBJECT_LOCK (timecodestamper);

      gst_event_copy_segment (event, &segment);
      if (segment.format != GST_FORMAT_TIME) {
        GST_OBJECT_UNLOCK (timecodestamper);
        GST_ERROR_OBJECT (timecodestamper, "Invalid segment format");
        return FALSE;
      }
      if (GST_VIDEO_INFO_FORMAT (&timecodestamper->vinfo) ==
          GST_VIDEO_FORMAT_UNKNOWN) {
        GST_ERROR_OBJECT (timecodestamper,
            "Received segment event without caps");
        GST_OBJECT_UNLOCK (timecodestamper);
        return FALSE;
      }

      if (timecodestamper->first_tc_now && !timecodestamper->first_tc) {
        GDateTime *dt = g_date_time_new_now_local ();
        GstVideoTimeCode *tc;

        gst_timecodestamper_set_drop_frame (timecodestamper);

        tc = gst_video_time_code_new_from_date_time (timecodestamper->
            vinfo.fps_n, timecodestamper->vinfo.fps_d, dt,
            timecodestamper->current_tc->config.flags, 0);

        g_date_time_unref (dt);

        timecodestamper->first_tc = tc;
        notify = TRUE;
      }

      frames =
          gst_util_uint64_scale (segment.time, timecodestamper->vinfo.fps_n,
          timecodestamper->vinfo.fps_d * GST_SECOND);
      gst_timecodestamper_reset_timecode (timecodestamper);
      gst_video_time_code_add_frames (timecodestamper->current_tc, frames);
      GST_DEBUG_OBJECT (timecodestamper,
          "Got %" G_GUINT64_FORMAT " frames when segment time is %"
          GST_TIME_FORMAT, frames, GST_TIME_ARGS (segment.time));
      tc_str = gst_video_time_code_to_string (timecodestamper->current_tc);
      GST_DEBUG_OBJECT (timecodestamper, "New timecode is %s", tc_str);
      g_free (tc_str);
      GST_OBJECT_UNLOCK (timecodestamper);
      if (notify)
        g_object_notify (G_OBJECT (timecodestamper), "first-timecode");
      break;
    }
    case GST_EVENT_CAPS:
    {
      GstCaps *caps;

      GST_OBJECT_LOCK (timecodestamper);
      gst_event_parse_caps (event, &caps);
      if (!gst_video_info_from_caps (&timecodestamper->vinfo, caps)) {
        GST_OBJECT_UNLOCK (timecodestamper);
        return FALSE;
      }
      gst_timecodestamper_reset_timecode (timecodestamper);
      GST_OBJECT_UNLOCK (timecodestamper);
      break;
    }
    default:
      break;
  }
  ret =
      GST_BASE_TRANSFORM_CLASS (gst_timecodestamper_parent_class)->sink_event
      (trans, event);
  return ret;
}
Beispiel #30
0
static GstFlowReturn
daala_handle_type_packet (GstDaalaDec * dec)
{
  gint par_num, par_den;
  GstFlowReturn ret = GST_FLOW_OK;
  GstVideoCodecState *state;
  GstVideoFormat fmt;
  GstVideoInfo *info;

  if (!dec->input_state)
    return GST_FLOW_NOT_NEGOTIATED;

  info = &dec->input_state->info;

  GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d",
      dec->info.timebase_numerator, dec->info.timebase_denominator,
      dec->info.pixel_aspect_numerator, dec->info.pixel_aspect_denominator);

  /* calculate par
   * the info.aspect_* values reflect PAR;
   * 0:x and x:0 are allowed and can be interpreted as 1:1.
   */
  par_num = GST_VIDEO_INFO_PAR_N (info);
  par_den = GST_VIDEO_INFO_PAR_D (info);

  /* If we have a default PAR, see if the decoder specified a different one */
  if (par_num == 1 && par_den == 1 &&
      (dec->info.pixel_aspect_numerator != 0
          && dec->info.pixel_aspect_denominator != 0)) {
    par_num = dec->info.pixel_aspect_numerator;
    par_den = dec->info.pixel_aspect_denominator;
  }
  /* daala has:
   *
   *  width/height : dimension of the encoded frame 
   *  pic_width/pic_height : dimension of the visible part
   *  pic_x/pic_y : offset in encoded frame where visible part starts
   */
  GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.pic_width,
      dec->info.pic_height, par_num, par_den);

  if (dec->info.nplanes == 3 && dec->info.plane_info[0].xdec == 0 &&
      dec->info.plane_info[0].ydec == 0 &&
      dec->info.plane_info[1].xdec == 1 &&
      dec->info.plane_info[1].ydec == 1 &&
      dec->info.plane_info[2].xdec == 1 && dec->info.plane_info[2].ydec == 1) {
    fmt = GST_VIDEO_FORMAT_I420;
  } else if (dec->info.nplanes == 3 && dec->info.plane_info[0].xdec == 0 &&
      dec->info.plane_info[0].ydec == 0 &&
      dec->info.plane_info[1].xdec == 0 &&
      dec->info.plane_info[1].ydec == 0 &&
      dec->info.plane_info[2].xdec == 0 && dec->info.plane_info[2].ydec == 0) {
    fmt = GST_VIDEO_FORMAT_Y444;
  } else {
    goto unsupported_format;
  }

  GST_VIDEO_INFO_WIDTH (info) = dec->info.pic_width;
  GST_VIDEO_INFO_HEIGHT (info) = dec->info.pic_height;

  /* done */
  dec->decoder = daala_decode_alloc (&dec->info, dec->setup);

  /* Create the output state */
  dec->output_state = state =
      gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec), fmt,
      info->width, info->height, dec->input_state);

  /* FIXME : Do we still need to set fps/par now that we pass the reference input stream ? */
  state->info.fps_n = dec->info.timebase_numerator;
  state->info.fps_d = dec->info.timebase_denominator;
  state->info.par_n = par_num;
  state->info.par_d = par_den;

  gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));

  dec->have_header = TRUE;

  return ret;

  /* ERRORS */
unsupported_format:
  {
    GST_ERROR_OBJECT (dec, "Invalid pixel format");
    return GST_FLOW_ERROR;
  }
}