static GstStateChangeReturn gst_omx_audio_enc_change_state (GstElement * element, GstStateChange transition) { GstOMXAudioEnc *self; GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; g_return_val_if_fail (GST_IS_OMX_AUDIO_ENC (element), GST_STATE_CHANGE_FAILURE); self = GST_OMX_AUDIO_ENC (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: if (!gst_omx_audio_enc_open (self)) ret = GST_STATE_CHANGE_FAILURE; break; case GST_STATE_CHANGE_READY_TO_PAUSED: self->downstream_flow_ret = GST_FLOW_OK; self->draining = FALSE; self->started = FALSE; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; case GST_STATE_CHANGE_PAUSED_TO_READY: if (self->enc_in_port) gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, TRUE); if (self->enc_out_port) gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); break; default: break; } if (ret == GST_STATE_CHANGE_FAILURE) return ret; ret = GST_ELEMENT_CLASS (gst_omx_audio_enc_parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: self->downstream_flow_ret = GST_FLOW_FLUSHING; self->started = FALSE; if (!gst_omx_audio_enc_shutdown (self)) ret = GST_STATE_CHANGE_FAILURE; break; case GST_STATE_CHANGE_READY_TO_NULL: if (!gst_omx_audio_enc_close (self)) ret = GST_STATE_CHANGE_FAILURE; break; default: break; } return ret; }
static gboolean gst_omx_audio_enc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) { GstOMXAudioEnc *self; GstOMXAudioEncClass *klass; gboolean needs_disable = FALSE; OMX_PARAM_PORTDEFINITIONTYPE port_def; OMX_AUDIO_PARAM_PCMMODETYPE pcm_param; gint i; OMX_ERRORTYPE err; self = GST_OMX_AUDIO_ENC (encoder); klass = GST_OMX_AUDIO_ENC_GET_CLASS (encoder); GST_DEBUG_OBJECT (self, "Setting new caps"); /* Set audio encoder base class properties */ gst_audio_encoder_set_frame_samples_min (encoder, gst_util_uint64_scale_ceil (OMX_MIN_PCMPAYLOAD_MSEC, GST_MSECOND * info->rate, GST_SECOND)); gst_audio_encoder_set_frame_samples_max (encoder, 0); gst_omx_port_get_port_definition (self->enc_in_port, &port_def); needs_disable = gst_omx_component_get_state (self->enc, 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) { GST_DEBUG_OBJECT (self, "Need to disable and drain encoder"); gst_omx_audio_enc_drain (self); gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE); /* Wait until the srcpad loop is finished, * unlock GST_AUDIO_ENCODER_STREAM_LOCK to prevent deadlocks * caused by using this lock from inside the loop function */ GST_AUDIO_ENCODER_STREAM_UNLOCK (self); gst_pad_stop_task (GST_AUDIO_ENCODER_SRC_PAD (encoder)); GST_AUDIO_ENCODER_STREAM_LOCK (self); if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) { GST_AUDIO_ENCODER_STREAM_UNLOCK (self); gst_omx_audio_enc_stop (GST_AUDIO_ENCODER (self)); gst_omx_audio_enc_close (GST_AUDIO_ENCODER (self)); GST_AUDIO_ENCODER_STREAM_LOCK (self); if (!gst_omx_audio_enc_open (GST_AUDIO_ENCODER (self))) return FALSE; needs_disable = FALSE; } else { if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone) return FALSE; if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone) return FALSE; if (gst_omx_port_wait_buffers_released (self->enc_in_port, 5 * GST_SECOND) != OMX_ErrorNone) return FALSE; if (gst_omx_port_wait_buffers_released (self->enc_out_port, 1 * GST_SECOND) != OMX_ErrorNone) return FALSE; if (gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone) return FALSE; if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone) return FALSE; if (gst_omx_port_wait_enabled (self->enc_in_port, 1 * GST_SECOND) != OMX_ErrorNone) return FALSE; if (gst_omx_port_wait_enabled (self->enc_out_port, 1 * GST_SECOND) != OMX_ErrorNone) return FALSE; } GST_DEBUG_OBJECT (self, "Encoder drained and disabled"); } port_def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; GST_DEBUG_OBJECT (self, "Setting inport port definition"); if (gst_omx_port_update_port_definition (self->enc_in_port, &port_def) != OMX_ErrorNone) return FALSE; GST_OMX_INIT_STRUCT (&pcm_param); pcm_param.nPortIndex = self->enc_in_port->index; pcm_param.nChannels = info->channels; pcm_param.eNumData = ((info->finfo->flags & GST_AUDIO_FORMAT_FLAG_SIGNED) ? OMX_NumericalDataSigned : OMX_NumericalDataUnsigned); pcm_param.eEndian = ((info->finfo->endianness == G_LITTLE_ENDIAN) ? OMX_EndianLittle : OMX_EndianBig); pcm_param.bInterleaved = OMX_TRUE; pcm_param.nBitPerSample = info->finfo->width; pcm_param.nSamplingRate = info->rate; pcm_param.ePCMMode = OMX_AUDIO_PCMModeLinear; for (i = 0; i < pcm_param.nChannels; i++) { OMX_AUDIO_CHANNELTYPE pos; switch (info->position[i]) { case GST_AUDIO_CHANNEL_POSITION_MONO: case GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER: pos = OMX_AUDIO_ChannelCF; break; case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT: pos = OMX_AUDIO_ChannelLF; break; case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT: pos = OMX_AUDIO_ChannelRF; break; case GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT: pos = OMX_AUDIO_ChannelLS; break; case GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT: pos = OMX_AUDIO_ChannelRS; break; case GST_AUDIO_CHANNEL_POSITION_LFE1: pos = OMX_AUDIO_ChannelLFE; break; case GST_AUDIO_CHANNEL_POSITION_REAR_CENTER: pos = OMX_AUDIO_ChannelCS; break; case GST_AUDIO_CHANNEL_POSITION_REAR_LEFT: pos = OMX_AUDIO_ChannelLR; break; case GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT: pos = OMX_AUDIO_ChannelRR; break; default: pos = OMX_AUDIO_ChannelNone; break; } pcm_param.eChannelMapping[i] = pos; } GST_DEBUG_OBJECT (self, "Setting PCM parameters"); err = gst_omx_component_set_parameter (self->enc, OMX_IndexParamAudioPcm, &pcm_param); if (err != OMX_ErrorNone) { GST_ERROR_OBJECT (self, "Failed to set PCM parameters: %s (0x%08x)", gst_omx_error_to_string (err), err); return FALSE; } if (klass->set_format) { if (!klass->set_format (self, self->enc_in_port, info)) { 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->enc_out_port, NULL) != OMX_ErrorNone) return FALSE; GST_DEBUG_OBJECT (self, "Enabling component"); if (needs_disable) { if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone) return FALSE; if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone) return FALSE; if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) { if (gst_omx_port_set_enabled (self->enc_out_port, TRUE) != OMX_ErrorNone) return FALSE; if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone) return FALSE; if (gst_omx_port_wait_enabled (self->enc_out_port, 5 * GST_SECOND) != OMX_ErrorNone) return FALSE; } if (gst_omx_port_wait_enabled (self->enc_in_port, 5 * GST_SECOND) != OMX_ErrorNone) return FALSE; if (gst_omx_port_mark_reconfigured (self->enc_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->enc_out_port, FALSE) != OMX_ErrorNone) return FALSE; if (gst_omx_port_wait_enabled (self->enc_out_port, 1 * GST_SECOND) != OMX_ErrorNone) return FALSE; if (gst_omx_component_set_state (self->enc, OMX_StateIdle) != OMX_ErrorNone) return FALSE; /* Need to allocate buffers to reach Idle state */ if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone) return FALSE; } else { if (gst_omx_component_set_state (self->enc, OMX_StateIdle) != OMX_ErrorNone) return FALSE; /* Need to allocate buffers to reach Idle state */ if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone) return FALSE; if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone) return FALSE; } if (gst_omx_component_get_state (self->enc, GST_CLOCK_TIME_NONE) != OMX_StateIdle) return FALSE; if (gst_omx_component_set_state (self->enc, OMX_StateExecuting) != OMX_ErrorNone) return FALSE; if (gst_omx_component_get_state (self->enc, GST_CLOCK_TIME_NONE) != OMX_StateExecuting) return FALSE; } /* Unset flushing to allow ports to accept data again */ 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); if (gst_omx_component_get_last_error (self->enc) != OMX_ErrorNone) { GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)", gst_omx_component_get_last_error_string (self->enc), gst_omx_component_get_last_error (self->enc)); return FALSE; } /* Start the srcpad loop again */ GST_DEBUG_OBJECT (self, "Starting task again"); self->downstream_flow_ret = GST_FLOW_OK; gst_pad_start_task (GST_AUDIO_ENCODER_SRC_PAD (self), (GstTaskFunction) gst_omx_audio_enc_loop, encoder, NULL); return TRUE; }