static void gst_omx_audio_enc_flush (GstAudioEncoder * encoder) { GstOMXAudioEnc *self; self = GST_OMX_AUDIO_ENC (encoder); GST_DEBUG_OBJECT (self, "Resetting encoder"); gst_omx_audio_enc_drain (self); gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE); gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE); /* Wait until the srcpad loop is finished */ GST_AUDIO_ENCODER_STREAM_UNLOCK (self); GST_PAD_STREAM_LOCK (GST_AUDIO_ENCODER_SRC_PAD (self)); GST_PAD_STREAM_UNLOCK (GST_AUDIO_ENCODER_SRC_PAD (self)); GST_AUDIO_ENCODER_STREAM_LOCK (self); gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE); gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE); gst_omx_port_populate (self->enc_out_port); /* Start the srcpad loop again */ self->last_upstream_ts = 0; self->downstream_flow_ret = GST_FLOW_OK; self->eos = FALSE; gst_pad_start_task (GST_AUDIO_ENCODER_SRC_PAD (self), (GstTaskFunction) gst_omx_audio_enc_loop, encoder, NULL); }
static void gst_omx_audio_dec_flush (GstAudioDecoder * decoder, gboolean hard) { GstOMXAudioDec *self = GST_OMX_AUDIO_DEC (decoder); OMX_ERRORTYPE err = OMX_ErrorNone; GST_DEBUG_OBJECT (self, "Flushing decoder"); if (gst_omx_component_get_state (self->dec, 0) == OMX_StateLoaded) return; /* 0) Pause the components */ if (gst_omx_component_get_state (self->dec, 0) == OMX_StateExecuting) { gst_omx_component_set_state (self->dec, OMX_StatePause); gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE); } /* 1) Wait until the srcpad loop is stopped, * unlock GST_AUDIO_DECODER_STREAM_LOCK to prevent deadlocks * caused by using this lock from inside the loop function */ GST_AUDIO_DECODER_STREAM_UNLOCK (self); gst_pad_stop_task (GST_AUDIO_DECODER_SRC_PAD (decoder)); GST_DEBUG_OBJECT (self, "Flushing -- task stopped"); GST_AUDIO_DECODER_STREAM_LOCK (self); /* 2) Flush the ports */ GST_DEBUG_OBJECT (self, "flushing ports"); gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE); gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE); /* 3) Resume components */ gst_omx_component_set_state (self->dec, OMX_StateExecuting); gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE); /* 4) 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); err = gst_omx_port_populate (self->dec_out_port); if (err != OMX_ErrorNone) { GST_WARNING_OBJECT (self, "Failed to populate output port: %s (0x%08x)", gst_omx_error_to_string (err), err); } /* Reset our state */ self->last_upstream_ts = 0; self->downstream_flow_ret = GST_FLOW_OK; self->started = FALSE; GST_DEBUG_OBJECT (self, "Flush finished"); }
static void gst_omx_audio_enc_loop (GstOMXAudioEnc * self) { GstOMXAudioEncClass *klass; GstOMXPort *port = self->enc_out_port; GstOMXBuffer *buf = NULL; GstFlowReturn flow_ret = GST_FLOW_OK; GstOMXAcquireBufferReturn acq_return; OMX_ERRORTYPE err; klass = GST_OMX_AUDIO_ENC_GET_CLASS (self); acq_return = gst_omx_port_acquire_buffer (port, &buf); if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) { goto component_error; } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) { goto flushing; } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) { goto eos; } if (!gst_pad_has_current_caps (GST_AUDIO_ENCODER_SRC_PAD (self)) || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) { GstAudioInfo *info = gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (self)); GstCaps *caps; GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps"); /* Reallocate all buffers */ if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) { 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; } GST_AUDIO_ENCODER_STREAM_LOCK (self); caps = klass->get_caps (self, self->enc_out_port, info); if (!caps) { if (buf) gst_omx_port_release_buffer (self->enc_out_port, buf); GST_AUDIO_ENCODER_STREAM_UNLOCK (self); goto caps_failed; } GST_DEBUG_OBJECT (self, "Setting output caps: %" GST_PTR_FORMAT, caps); if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (self), caps)) { gst_caps_unref (caps); if (buf) gst_omx_port_release_buffer (self->enc_out_port, buf); GST_AUDIO_ENCODER_STREAM_UNLOCK (self); goto caps_failed; } gst_caps_unref (caps); GST_AUDIO_ENCODER_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_ENCODER_STREAM_LOCK (self); goto eos; } GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %" G_GUINT64_FORMAT, (guint) buf->omx_buf->nFlags, (guint64) buf->omx_buf->nTimeStamp); /* This prevents a deadlock between the srcpad stream * lock and the videocodec stream lock, if ::reset() * is called at the wrong time */ if (gst_omx_port_is_flushing (self->enc_out_port)) { GST_DEBUG_OBJECT (self, "Flushing"); gst_omx_port_release_buffer (self->enc_out_port, buf); goto flushing; } GST_AUDIO_ENCODER_STREAM_LOCK (self); if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) && buf->omx_buf->nFilledLen > 0) { GstCaps *caps; GstBuffer *codec_data; GstMapInfo map = GST_MAP_INFO_INIT; GST_DEBUG_OBJECT (self, "Handling codec data"); caps = gst_caps_copy (gst_pad_get_current_caps (GST_AUDIO_ENCODER_SRC_PAD (self))); codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen); gst_buffer_map (codec_data, &map, GST_MAP_WRITE); memcpy (map.data, buf->omx_buf->pBuffer + buf->omx_buf->nOffset, buf->omx_buf->nFilledLen); gst_buffer_unmap (codec_data, &map); gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL); if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (self), caps)) { gst_caps_unref (caps); if (buf) gst_omx_port_release_buffer (self->enc_out_port, buf); GST_AUDIO_ENCODER_STREAM_UNLOCK (self); goto caps_failed; } gst_caps_unref (caps); flow_ret = GST_FLOW_OK; } else if (buf->omx_buf->nFilledLen > 0) { GstBuffer *outbuf; guint n_samples; GST_DEBUG_OBJECT (self, "Handling output data"); n_samples = klass->get_num_samples (self, self->enc_out_port, gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (self)), buf); if (buf->omx_buf->nFilledLen > 0) { GstMapInfo map = GST_MAP_INFO_INIT; outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen); gst_buffer_map (outbuf, &map, GST_MAP_WRITE); memcpy (map.data, buf->omx_buf->pBuffer + buf->omx_buf->nOffset, buf->omx_buf->nFilledLen); gst_buffer_unmap (outbuf, &map); } else { outbuf = gst_buffer_new (); } 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_encoder_finish_frame (GST_AUDIO_ENCODER (self), outbuf, n_samples); } GST_DEBUG_OBJECT (self, "Handled output data"); GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret)); 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_ENCODER_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->enc), gst_omx_component_get_last_error (self->enc))); gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_ENCODER_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_ENCODER_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_ENCODER_SRC_PAD (self)); } else { GST_DEBUG_OBJECT (self, "Component signalled EOS"); flow_ret = GST_FLOW_EOS; } g_mutex_unlock (&self->drain_lock); GST_AUDIO_ENCODER_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_ENCODER_STREAM_UNLOCK (self); return; } flow_error: { if (flow_ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (self, "EOS"); gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self)); } else if (flow_ret == GST_FLOW_NOT_LINKED || 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_ENCODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self)); } self->started = FALSE; GST_AUDIO_ENCODER_STREAM_UNLOCK (self); return; } reconfigure_error: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Unable to reconfigure output port")); gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED; self->started = FALSE; return; } caps_failed: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps")); gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (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_ENCODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; self->started = FALSE; GST_AUDIO_ENCODER_STREAM_UNLOCK (self); return; } }
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; } }