// This function must be called before // any other decoding functions int nv_opus_init(int sampleRate, int channelCount, int streams, int coupledStreams, const unsigned char *mapping) { int err; decoder = opus_multistream_decoder_create( sampleRate, channelCount, streams, coupledStreams, mapping, &err); return err; }
FOpusDecoderWrapper(uint16 SampleRate, uint8 NumChannels) { #if WITH_OPUS check(NumChannels <= 8); const UnrealChannelLayout& Layout = UnrealMappings[NumChannels-1]; #if USE_UE4_MEM_ALLOC int32 DecSize = opus_multistream_decoder_get_size(Layout.NumStreams, Layout.NumCoupledStreams); Decoder = (OpusMSDecoder*)FMemory::Malloc(DecSize); DecError = opus_multistream_decoder_init(Decoder, SampleRate, NumChannels, Layout.NumStreams, Layout.NumCoupledStreams, Layout.Mapping); #else Decoder = opus_multistream_decoder_create(SampleRate, NumChannels, Layout.NumStreams, Layout.NumCoupledStreams, Layout.Mapping, &DecError); #endif #endif }
void MoonlightInstance::AudDecInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig) { int rc; g_Instance->m_OpusDecoder = opus_multistream_decoder_create(opusConfig->sampleRate, opusConfig->channelCount, opusConfig->streams, opusConfig->coupledStreams, opusConfig->mapping, &rc); g_Instance->m_AudioPlayer = pp::Audio(g_Instance, pp::AudioConfig(g_Instance, PP_AUDIOSAMPLERATE_48000, FRAME_SIZE), AudioPlayerSampleCallback, NULL); // Start playback now g_Instance->m_AudioPlayer.StartPlayback(); }
bool OpusState::Init(void) { if (!mActive) return false; int error; NS_ASSERTION(mDecoder == nullptr, "leaking OpusDecoder"); mDecoder = opus_multistream_decoder_create(mParser->mRate, mParser->mChannels, mParser->mStreams, mParser->mCoupledStreams, mParser->mMappingTable, &error); mSkip = mParser->mPreSkip; LOG(PR_LOG_DEBUG, ("Opus decoder init, to skip %d", mSkip)); return error == OPUS_OK; }
/***************************************************************************** * ProcessInitialHeader: processes the inital Opus header packet. *****************************************************************************/ static int ProcessInitialHeader( decoder_t *p_dec, ogg_packet *p_oggpacket ) { int err; unsigned char new_stream_map[8]; decoder_sys_t *p_sys = p_dec->p_sys; OpusHeader *p_header = &p_sys->header; if( !opus_header_parse((unsigned char *)p_oggpacket->packet,p_oggpacket->bytes,p_header) ) { msg_Err( p_dec, "cannot read Opus header" ); return VLC_EGENERIC; } msg_Dbg( p_dec, "Opus audio with %d channels", p_header->channels); if((p_header->channels>2 && p_header->channel_mapping==0) || (p_header->channels>8 && p_header->channel_mapping==1) || p_header->channel_mapping>1) { msg_Err( p_dec, "Unsupported channel mapping" ); return VLC_EGENERIC; } /* Setup the format */ p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_maps[p_header->channels]; p_dec->fmt_out.audio.i_channels = p_header->channels; p_dec->fmt_out.audio.i_rate = 48000; if( p_header->channels>2 && p_header->channels<9 ) { static const uint32_t *pi_ch[6] = { pi_3channels_in, pi_4channels_in, pi_5channels_in, pi_6channels_in, pi_7channels_in, pi_8channels_in }; uint8_t pi_chan_table[AOUT_CHAN_MAX]; aout_CheckChannelReorder( pi_ch[p_header->channels-3], NULL, p_dec->fmt_out.audio.i_physical_channels, pi_chan_table ); for(int i=0;i<p_header->channels;i++) new_stream_map[pi_chan_table[i]]=p_header->stream_map[i]; } /* Opus decoder init */ p_sys->p_st = opus_multistream_decoder_create( 48000, p_header->channels, p_header->nb_streams, p_header->nb_coupled, p_header->channels>2?new_stream_map:p_header->stream_map, &err ); if( !p_sys->p_st || err!=OPUS_OK ) { msg_Err( p_dec, "decoder initialization failed" ); return VLC_EGENERIC; } #ifdef OPUS_SET_GAIN if( opus_multistream_decoder_ctl( p_sys->p_st,OPUS_SET_GAIN(p_header->gain) ) != OPUS_OK ) { msg_Err( p_dec, "OPUS_SET_GAIN failed" ); opus_multistream_decoder_destroy( p_sys->p_st ); return VLC_EGENERIC; } #endif date_Init( &p_sys->end_date, 48000, 1 ); return VLC_SUCCESS; }
static GstFlowReturn opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) { GstFlowReturn res = GST_FLOW_OK; gsize size; guint8 *data; GstBuffer *outbuf; gint16 *out_data; int n, err; int samples; unsigned int packet_size; GstBuffer *buf; GstMapInfo map, omap; if (dec->state == NULL) { /* If we did not get any headers, default to 2 channels */ if (dec->n_channels == 0) { GST_INFO_OBJECT (dec, "No header, assuming single stream"); dec->n_channels = 2; dec->sample_rate = 48000; /* default stereo mapping */ dec->channel_mapping_family = 0; dec->channel_mapping[0] = 0; dec->channel_mapping[1] = 1; dec->n_streams = 1; dec->n_stereo_streams = 1; gst_opus_dec_negotiate (dec, NULL); } GST_DEBUG_OBJECT (dec, "Creating decoder with %d channels, %d Hz", dec->n_channels, dec->sample_rate); #ifndef GST_DISABLE_GST_DEBUG gst_opus_common_log_channel_mapping_table (GST_ELEMENT (dec), opusdec_debug, "Mapping table", dec->n_channels, dec->channel_mapping); #endif GST_DEBUG_OBJECT (dec, "%d streams, %d stereo", dec->n_streams, dec->n_stereo_streams); dec->state = opus_multistream_decoder_create (dec->sample_rate, dec->n_channels, dec->n_streams, dec->n_stereo_streams, dec->channel_mapping, &err); if (!dec->state || err != OPUS_OK) goto creation_failed; } if (buffer) { GST_DEBUG_OBJECT (dec, "Received buffer of size %" G_GSIZE_FORMAT, gst_buffer_get_size (buffer)); } else { GST_DEBUG_OBJECT (dec, "Received missing buffer"); } /* if using in-band FEC, we introdude one extra frame's delay as we need to potentially wait for next buffer to decode a missing buffer */ if (dec->use_inband_fec && !dec->primed) { GST_DEBUG_OBJECT (dec, "First buffer received in FEC mode, early out"); gst_buffer_replace (&dec->last_buffer, buffer); dec->primed = TRUE; goto done; } /* That's the buffer we'll be sending to the opus decoder. */ buf = (dec->use_inband_fec && gst_buffer_get_size (dec->last_buffer) > 0) ? dec->last_buffer : buffer; if (buf && gst_buffer_get_size (buf) > 0) { gst_buffer_map (buf, &map, GST_MAP_READ); data = map.data; size = map.size; GST_DEBUG_OBJECT (dec, "Using buffer of size %" G_GSIZE_FORMAT, size); } else { /* concealment data, pass NULL as the bits parameters */ GST_DEBUG_OBJECT (dec, "Using NULL buffer"); data = NULL; size = 0; } /* use maximum size (120 ms) as the number of returned samples is not constant over the stream. */ samples = 120 * dec->sample_rate / 1000; packet_size = samples * dec->n_channels * 2; outbuf = gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (dec), packet_size); if (!outbuf) { goto buffer_failed; } gst_buffer_map (outbuf, &omap, GST_MAP_WRITE); out_data = (gint16 *) omap.data; if (dec->use_inband_fec) { if (dec->last_buffer) { /* normal delayed decode */ GST_LOG_OBJECT (dec, "FEC enabled, decoding last delayed buffer"); n = opus_multistream_decode (dec->state, data, size, out_data, samples, 0); } else { /* FEC reconstruction decode */ GST_LOG_OBJECT (dec, "FEC enabled, reconstructing last buffer"); n = opus_multistream_decode (dec->state, data, size, out_data, samples, 1); } } else { /* normal decode */ GST_LOG_OBJECT (dec, "FEC disabled, decoding buffer"); n = opus_multistream_decode (dec->state, data, size, out_data, samples, 0); } gst_buffer_unmap (outbuf, &omap); if (data != NULL) gst_buffer_unmap (buf, &map); if (n < 0) { GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Decoding error: %d", n), (NULL)); gst_buffer_unref (outbuf); return GST_FLOW_ERROR; } GST_DEBUG_OBJECT (dec, "decoded %d samples", n); gst_buffer_set_size (outbuf, n * 2 * dec->n_channels); /* Skip any samples that need skipping */ if (dec->pre_skip > 0) { guint scaled_pre_skip = dec->pre_skip * dec->sample_rate / 48000; guint skip = scaled_pre_skip > n ? n : scaled_pre_skip; guint scaled_skip = skip * 48000 / dec->sample_rate; gst_buffer_resize (outbuf, skip * 2 * dec->n_channels, -1); dec->pre_skip -= scaled_skip; GST_INFO_OBJECT (dec, "Skipping %u samples (%u at 48000 Hz, %u left to skip)", skip, scaled_skip, dec->pre_skip); } if (gst_buffer_get_size (outbuf) == 0) { gst_buffer_unref (outbuf); outbuf = NULL; } else if (dec->opus_pos[0] != GST_AUDIO_CHANNEL_POSITION_INVALID) { gst_audio_buffer_reorder_channels (outbuf, GST_AUDIO_FORMAT_S16, dec->n_channels, dec->opus_pos, dec->info.position); } /* Apply gain */ /* Would be better off leaving this to a volume element, as this is a naive conversion that does too many int/float conversions. However, we don't have control over the pipeline... So make it optional if the user program wants to use a volume, but do it by default so the correct volume goes out by default */ if (dec->apply_gain && outbuf && dec->r128_gain) { gsize rsize; unsigned int i, nsamples; double volume = dec->r128_gain_volume; gint16 *samples; gst_buffer_map (outbuf, &omap, GST_MAP_READWRITE); samples = (gint16 *) omap.data; rsize = omap.size; GST_DEBUG_OBJECT (dec, "Applying gain: volume %f", volume); nsamples = rsize / 2; for (i = 0; i < nsamples; ++i) { int sample = (int) (samples[i] * volume + 0.5); samples[i] = sample < -32768 ? -32768 : sample > 32767 ? 32767 : sample; } gst_buffer_unmap (outbuf, &omap); } if (dec->use_inband_fec) { gst_buffer_replace (&dec->last_buffer, buffer); } res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1); if (res != GST_FLOW_OK) GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (res)); done: return res; creation_failed: GST_ERROR_OBJECT (dec, "Failed to create Opus decoder: %d", err); return GST_FLOW_ERROR; buffer_failed: GST_ERROR_OBJECT (dec, "Failed to create %u byte buffer", packet_size); return GST_FLOW_ERROR; }
static GstFlowReturn opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) { GstFlowReturn res = GST_FLOW_OK; gsize size; guint8 *data; GstBuffer *outbuf, *bufd; gint16 *out_data; int n, err; int samples; unsigned int packet_size; GstBuffer *buf; GstMapInfo map, omap; GstAudioClippingMeta *cmeta = NULL; if (dec->state == NULL) { /* If we did not get any headers, default to 2 channels */ if (dec->n_channels == 0) { GST_INFO_OBJECT (dec, "No header, assuming single stream"); dec->n_channels = 2; dec->sample_rate = 48000; /* default stereo mapping */ dec->channel_mapping_family = 0; dec->channel_mapping[0] = 0; dec->channel_mapping[1] = 1; dec->n_streams = 1; dec->n_stereo_streams = 1; if (!gst_opus_dec_negotiate (dec, NULL)) return GST_FLOW_NOT_NEGOTIATED; } if (dec->n_channels == 2 && dec->n_streams == 1 && dec->n_stereo_streams == 0) { /* if we are automatically decoding 2 channels, but only have a single encoded one, direct both channels to it */ dec->channel_mapping[1] = 0; } GST_DEBUG_OBJECT (dec, "Creating decoder with %d channels, %d Hz", dec->n_channels, dec->sample_rate); #ifndef GST_DISABLE_GST_DEBUG gst_opus_common_log_channel_mapping_table (GST_ELEMENT (dec), opusdec_debug, "Mapping table", dec->n_channels, dec->channel_mapping); #endif GST_DEBUG_OBJECT (dec, "%d streams, %d stereo", dec->n_streams, dec->n_stereo_streams); dec->state = opus_multistream_decoder_create (dec->sample_rate, dec->n_channels, dec->n_streams, dec->n_stereo_streams, dec->channel_mapping, &err); if (!dec->state || err != OPUS_OK) goto creation_failed; } if (buffer) { GST_DEBUG_OBJECT (dec, "Received buffer of size %" G_GSIZE_FORMAT, gst_buffer_get_size (buffer)); } else { GST_DEBUG_OBJECT (dec, "Received missing buffer"); } /* if using in-band FEC, we introdude one extra frame's delay as we need to potentially wait for next buffer to decode a missing buffer */ if (dec->use_inband_fec && !dec->primed) { GST_DEBUG_OBJECT (dec, "First buffer received in FEC mode, early out"); gst_buffer_replace (&dec->last_buffer, buffer); dec->primed = TRUE; goto done; } /* That's the buffer we'll be sending to the opus decoder. */ buf = (dec->use_inband_fec && gst_buffer_get_size (dec->last_buffer) > 0) ? dec->last_buffer : buffer; /* That's the buffer we get duration from */ bufd = dec->use_inband_fec ? dec->last_buffer : buffer; if (buf && gst_buffer_get_size (buf) > 0) { gst_buffer_map (buf, &map, GST_MAP_READ); data = map.data; size = map.size; GST_DEBUG_OBJECT (dec, "Using buffer of size %" G_GSIZE_FORMAT, size); } else { /* concealment data, pass NULL as the bits parameters */ GST_DEBUG_OBJECT (dec, "Using NULL buffer"); data = NULL; size = 0; } if (gst_buffer_get_size (bufd) == 0) { GstClockTime const opus_plc_alignment = 2500 * GST_USECOND; GstClockTime aligned_missing_duration; GstClockTime missing_duration = GST_BUFFER_DURATION (bufd); if (!GST_CLOCK_TIME_IS_VALID (missing_duration) || missing_duration == 0) { if (GST_CLOCK_TIME_IS_VALID (dec->last_known_buffer_duration)) { missing_duration = dec->last_known_buffer_duration; GST_WARNING_OBJECT (dec, "Missing duration, using last duration %" GST_TIME_FORMAT, GST_TIME_ARGS (missing_duration)); } else { GST_WARNING_OBJECT (dec, "Missing buffer, but unknown duration, and no previously known duration, assuming 20 ms"); missing_duration = 20 * GST_MSECOND; } } GST_DEBUG_OBJECT (dec, "missing buffer, doing PLC duration %" GST_TIME_FORMAT " plus leftover %" GST_TIME_FORMAT, GST_TIME_ARGS (missing_duration), GST_TIME_ARGS (dec->leftover_plc_duration)); /* add the leftover PLC duration to that of the buffer */ missing_duration += dec->leftover_plc_duration; /* align the combined buffer and leftover PLC duration to multiples * of 2.5ms, rounding to nearest, and store excess duration for later */ aligned_missing_duration = ((missing_duration + opus_plc_alignment / 2) / opus_plc_alignment) * opus_plc_alignment; dec->leftover_plc_duration = missing_duration - aligned_missing_duration; /* Opus' PLC cannot operate with less than 2.5ms; skip PLC * and accumulate the missing duration in the leftover_plc_duration * for the next PLC attempt */ if (aligned_missing_duration < opus_plc_alignment) { GST_DEBUG_OBJECT (dec, "current duration %" GST_TIME_FORMAT " of missing data not enough for PLC (minimum needed: %" GST_TIME_FORMAT ") - skipping", GST_TIME_ARGS (missing_duration), GST_TIME_ARGS (opus_plc_alignment)); goto done; } /* convert the duration (in nanoseconds) to sample count */ samples = gst_util_uint64_scale_int (aligned_missing_duration, dec->sample_rate, GST_SECOND); GST_DEBUG_OBJECT (dec, "calculated PLC frame length: %" GST_TIME_FORMAT " num frame samples: %d new leftover: %" GST_TIME_FORMAT, GST_TIME_ARGS (aligned_missing_duration), samples, GST_TIME_ARGS (dec->leftover_plc_duration)); } else { /* use maximum size (120 ms) as the number of returned samples is not constant over the stream. */ samples = 120 * dec->sample_rate / 1000; } packet_size = samples * dec->n_channels * 2; outbuf = gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (dec), packet_size); if (!outbuf) { goto buffer_failed; } if (size > 0) dec->last_known_buffer_duration = packet_duration_opus (data, size); gst_buffer_map (outbuf, &omap, GST_MAP_WRITE); out_data = (gint16 *) omap.data; do { if (dec->use_inband_fec) { if (gst_buffer_get_size (dec->last_buffer) > 0) { /* normal delayed decode */ GST_LOG_OBJECT (dec, "FEC enabled, decoding last delayed buffer"); n = opus_multistream_decode (dec->state, data, size, out_data, samples, 0); } else { /* FEC reconstruction decode */ GST_LOG_OBJECT (dec, "FEC enabled, reconstructing last buffer"); n = opus_multistream_decode (dec->state, data, size, out_data, samples, 1); } } else { /* normal decode */ GST_LOG_OBJECT (dec, "FEC disabled, decoding buffer"); n = opus_multistream_decode (dec->state, data, size, out_data, samples, 0); } if (n == OPUS_BUFFER_TOO_SMALL) { /* if too small, add 2.5 milliseconds and try again, up to the * Opus max size of 120 milliseconds */ if (samples >= 120 * dec->sample_rate / 1000) break; samples += 25 * dec->sample_rate / 10000; packet_size = samples * dec->n_channels * 2; gst_buffer_unmap (outbuf, &omap); gst_buffer_unref (outbuf); outbuf = gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (dec), packet_size); if (!outbuf) { goto buffer_failed; } gst_buffer_map (outbuf, &omap, GST_MAP_WRITE); out_data = (gint16 *) omap.data; } } while (n == OPUS_BUFFER_TOO_SMALL); gst_buffer_unmap (outbuf, &omap); if (data != NULL) gst_buffer_unmap (buf, &map); if (n < 0) { GstFlowReturn ret = GST_FLOW_ERROR; gst_buffer_unref (outbuf); GST_AUDIO_DECODER_ERROR (dec, 1, STREAM, DECODE, (NULL), ("Decoding error (%d): %s", n, opus_strerror (n)), ret); return ret; } GST_DEBUG_OBJECT (dec, "decoded %d samples", n); gst_buffer_set_size (outbuf, n * 2 * dec->n_channels); GST_BUFFER_DURATION (outbuf) = samples * GST_SECOND / dec->sample_rate; samples = n; cmeta = gst_buffer_get_audio_clipping_meta (buf); g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT); /* Skip any samples that need skipping */ if (cmeta && cmeta->start) { guint pre_skip = cmeta->start; guint scaled_pre_skip = pre_skip * dec->sample_rate / 48000; guint skip = scaled_pre_skip > n ? n : scaled_pre_skip; guint scaled_skip = skip * 48000 / dec->sample_rate; gst_buffer_resize (outbuf, skip * 2 * dec->n_channels, -1); GST_INFO_OBJECT (dec, "Skipping %u samples at the beginning (%u at 48000 Hz)", skip, scaled_skip); } if (cmeta && cmeta->end) { guint post_skip = cmeta->end; guint scaled_post_skip = post_skip * dec->sample_rate / 48000; guint skip = scaled_post_skip > n ? n : scaled_post_skip; guint scaled_skip = skip * 48000 / dec->sample_rate; guint outsize = gst_buffer_get_size (outbuf); guint skip_bytes = skip * 2 * dec->n_channels; if (outsize > skip_bytes) outsize -= skip_bytes; else outsize = 0; gst_buffer_resize (outbuf, 0, outsize); GST_INFO_OBJECT (dec, "Skipping %u samples at the end (%u at 48000 Hz)", skip, scaled_skip); } if (gst_buffer_get_size (outbuf) == 0) { gst_buffer_unref (outbuf); outbuf = NULL; } else if (dec->opus_pos[0] != GST_AUDIO_CHANNEL_POSITION_INVALID) { gst_audio_buffer_reorder_channels (outbuf, GST_AUDIO_FORMAT_S16, dec->n_channels, dec->opus_pos, dec->info.position); } /* Apply gain */ /* Would be better off leaving this to a volume element, as this is a naive conversion that does too many int/float conversions. However, we don't have control over the pipeline... So make it optional if the user program wants to use a volume, but do it by default so the correct volume goes out by default */ if (dec->apply_gain && outbuf && dec->r128_gain) { gsize rsize; unsigned int i, nsamples; double volume = dec->r128_gain_volume; gint16 *samples; gst_buffer_map (outbuf, &omap, GST_MAP_READWRITE); samples = (gint16 *) omap.data; rsize = omap.size; GST_DEBUG_OBJECT (dec, "Applying gain: volume %f", volume); nsamples = rsize / 2; for (i = 0; i < nsamples; ++i) { int sample = (int) (samples[i] * volume + 0.5); samples[i] = sample < -32768 ? -32768 : sample > 32767 ? 32767 : sample; } gst_buffer_unmap (outbuf, &omap); } if (dec->use_inband_fec) { gst_buffer_replace (&dec->last_buffer, buffer); } res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1); if (res != GST_FLOW_OK) GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (res)); done: return res; creation_failed: GST_ELEMENT_ERROR (dec, LIBRARY, INIT, ("Failed to create Opus decoder"), ("Failed to create Opus decoder (%d): %s", err, opus_strerror (err))); return GST_FLOW_ERROR; buffer_failed: GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Failed to create %u byte buffer", packet_size)); return GST_FLOW_ERROR; }
static void omx_renderer_init(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig) { int rc, error; OMX_ERRORTYPE err; unsigned char omxMapping[6]; char* componentName = "audio_render"; channelCount = opusConfig->channelCount; /* The supplied mapping array has order: FL-FR-C-LFE-RL-RR * OMX expects the order: FL-FR-LFE-C-RL-RR * We need copy the mapping locally and swap the channels around. */ memcpy(omxMapping, opusConfig->mapping, sizeof(omxMapping)); if (opusConfig->channelCount > 2) { omxMapping[2] = opusConfig->mapping[3]; omxMapping[3] = opusConfig->mapping[2]; } decoder = opus_multistream_decoder_create(opusConfig->sampleRate, opusConfig->channelCount, opusConfig->streams, opusConfig->coupledStreams, omxMapping, &rc); handle = ilclient_init(); if (handle == NULL) { fprintf(stderr, "IL client init failed\n"); exit(1); } if (ilclient_create_component(handle, &component, componentName, ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0) { fprintf(stderr, "Component create failed\n"); exit(1); } if (ilclient_change_component_state(component, OMX_StateIdle)!= 0) { fprintf(stderr, "Couldn't change state to Idle\n"); exit(1); } // must be before we enable buffers OMX_AUDIO_PARAM_PORTFORMATTYPE audioPortFormat; memset(&audioPortFormat, 0, sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE)); audioPortFormat.nSize = sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE); audioPortFormat.nVersion.nVersion = OMX_VERSION; audioPortFormat.nPortIndex = 100; OMX_GetParameter(ilclient_get_handle(component), OMX_IndexParamAudioPortFormat, &audioPortFormat); audioPortFormat.eEncoding = OMX_AUDIO_CodingPCM; OMX_SetParameter(ilclient_get_handle(component), OMX_IndexParamAudioPortFormat, &audioPortFormat); OMX_AUDIO_PARAM_PCMMODETYPE sPCMMode; memset(&sPCMMode, 0, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); sPCMMode.nSize = sizeof(OMX_AUDIO_PARAM_PCMMODETYPE); sPCMMode.nVersion.nVersion = OMX_VERSION; sPCMMode.nPortIndex = 100; sPCMMode.nChannels = channelCount; sPCMMode.eNumData = OMX_NumericalDataSigned; sPCMMode.eEndian = OMX_EndianLittle; sPCMMode.nSamplingRate = opusConfig->sampleRate; sPCMMode.bInterleaved = OMX_TRUE; sPCMMode.nBitPerSample = 16; sPCMMode.ePCMMode = OMX_AUDIO_PCMModeLinear; switch(channelCount) { case 1: sPCMMode.eChannelMapping[0] = OMX_AUDIO_ChannelCF; break; case 8: sPCMMode.eChannelMapping[7] = OMX_AUDIO_ChannelRS; case 7: sPCMMode.eChannelMapping[6] = OMX_AUDIO_ChannelLS; case 6: sPCMMode.eChannelMapping[5] = OMX_AUDIO_ChannelRR; case 5: sPCMMode.eChannelMapping[4] = OMX_AUDIO_ChannelLR; case 4: sPCMMode.eChannelMapping[3] = OMX_AUDIO_ChannelLFE; case 3: sPCMMode.eChannelMapping[2] = OMX_AUDIO_ChannelCF; case 2: sPCMMode.eChannelMapping[1] = OMX_AUDIO_ChannelRF; sPCMMode.eChannelMapping[0] = OMX_AUDIO_ChannelLF; break; } err = OMX_SetParameter(ilclient_get_handle(component), OMX_IndexParamAudioPcm, &sPCMMode); if(err != OMX_ErrorNone){ fprintf(stderr, "PCM mode unsupported\n"); return; } OMX_CONFIG_BRCMAUDIODESTINATIONTYPE arDest; if (audio_device == NULL) audio_device = "hdmi"; if (audio_device && strlen(audio_device) < sizeof(arDest.sName)) { memset(&arDest, 0, sizeof(OMX_CONFIG_BRCMAUDIODESTINATIONTYPE)); arDest.nSize = sizeof(OMX_CONFIG_BRCMAUDIODESTINATIONTYPE); arDest.nVersion.nVersion = OMX_VERSION; strcpy((char *)arDest.sName, audio_device); err = OMX_SetParameter(ilclient_get_handle(component), OMX_IndexConfigBrcmAudioDestination, &arDest); if (err != OMX_ErrorNone) { fprintf(stderr, "Error on setting audio destination\nomx option must be set to hdmi or local\n"); exit(1); } } // input port ilclient_enable_port_buffers(component, 100, NULL, NULL, NULL); ilclient_enable_port(component, 100); err = ilclient_change_component_state(component, OMX_StateExecuting); if (err < 0) { fprintf(stderr, "Couldn't change state to Executing\n"); exit(1); } }
static av_cold int libopus_decode_init(AVCodecContext *avc) { struct libopus_context *opus = avc->priv_data; int ret, channel_map = 0, gain_db = 0, nb_streams, nb_coupled; uint8_t mapping_arr[8] = { 0, 1 }, *mapping; avc->sample_rate = 48000; avc->sample_fmt = avc->request_sample_fmt == AV_SAMPLE_FMT_FLT ? AV_SAMPLE_FMT_FLT : AV_SAMPLE_FMT_S16; avc->channel_layout = avc->channels > 8 ? 0 : ff_vorbis_channel_layouts[avc->channels - 1]; if (avc->extradata_size >= OPUS_HEAD_SIZE) { gain_db = sign_extend(AV_RL16(avc->extradata + 16), 16); channel_map = AV_RL8 (avc->extradata + 18); } if (avc->extradata_size >= OPUS_HEAD_SIZE + 2 + avc->channels) { nb_streams = avc->extradata[OPUS_HEAD_SIZE + 0]; nb_coupled = avc->extradata[OPUS_HEAD_SIZE + 1]; if (nb_streams + nb_coupled != avc->channels) av_log(avc, AV_LOG_WARNING, "Inconsistent channel mapping.\n"); mapping = avc->extradata + OPUS_HEAD_SIZE + 2; } else { if (avc->channels > 2 || channel_map) { av_log(avc, AV_LOG_ERROR, "No channel mapping for %d channels.\n", avc->channels); return AVERROR(EINVAL); } nb_streams = 1; nb_coupled = avc->channels > 1; mapping = mapping_arr; } if (avc->channels > 2 && avc->channels <= 8) { const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[avc->channels - 1]; int ch; /* Remap channels from vorbis order to libav order */ for (ch = 0; ch < avc->channels; ch++) mapping_arr[ch] = mapping[vorbis_offset[ch]]; mapping = mapping_arr; } opus->dec = opus_multistream_decoder_create(avc->sample_rate, avc->channels, nb_streams, nb_coupled, mapping, &ret); if (!opus->dec) { av_log(avc, AV_LOG_ERROR, "Unable to create decoder: %s\n", opus_strerror(ret)); return ff_opus_error_to_averror(ret); } ret = opus_multistream_decoder_ctl(opus->dec, OPUS_SET_GAIN(gain_db)); if (ret != OPUS_OK) av_log(avc, AV_LOG_WARNING, "Failed to set gain: %s\n", opus_strerror(ret)); avc->delay = 3840; /* Decoder delay (in samples) at 48kHz */ avcodec_get_frame_defaults(&opus->frame); avc->coded_frame = &opus->frame; return 0; }
/*Process an Opus header and setup the opus decoder based on it. It takes several pointers for header values which are needed elsewhere in the code.*/ static OpusMSDecoder *process_header(ogg_packet *op, opus_int32 *rate, int *mapping_family, int *channels, int *preskip, float *gain, float manual_gain, int *streams, int wav_format, int quiet) { int err; OpusMSDecoder *st; OpusHeader header; if (opus_header_parse(op->packet, op->bytes, &header)==0) { fprintf(stderr, "Cannot parse header\n"); return NULL; } *mapping_family = header.channel_mapping; *channels = header.channels; if(wav_format)adjust_wav_mapping(*mapping_family, *channels, header.stream_map); if(!*rate)*rate=header.input_sample_rate; /*If the rate is unspecified we decode to 48000*/ if(*rate==0)*rate=48000; if(*rate<8000||*rate>192000){ fprintf(stderr,"Warning: Crazy input_rate %d, decoding to 48000 instead.\n",*rate); *rate=48000; } *preskip = header.preskip; st = opus_multistream_decoder_create(48000, header.channels, header.nb_streams, header.nb_coupled, header.stream_map, &err); if(err != OPUS_OK){ fprintf(stderr, "Cannot create encoder: %s\n", opus_strerror(err)); return NULL; } if (!st) { fprintf (stderr, "Decoder initialization failed: %s\n", opus_strerror(err)); return NULL; } *streams=header.nb_streams; if(header.gain!=0 || manual_gain!=0) { /*Gain API added in a newer libopus version, if we don't have it we apply the gain ourselves. We also add in a user provided manual gain at the same time.*/ int gainadj = (int)(manual_gain*256.)+header.gain; #ifdef OPUS_SET_GAIN err=opus_multistream_decoder_ctl(st,OPUS_SET_GAIN(gainadj)); if(err==OPUS_UNIMPLEMENTED) { #endif *gain = pow(10., gainadj/5120.); #ifdef OPUS_SET_GAIN } else if (err!=OPUS_OK) { fprintf (stderr, "Error setting gain: %s\n", opus_strerror(err)); return NULL; } #endif } if (!quiet) { fprintf(stderr, "Decoding to %d Hz (%d channel%s)", *rate, *channels, *channels>1?"s":""); if(header.version!=1)fprintf(stderr, ", Header v%d",header.version); fprintf(stderr, "\n"); if (header.gain!=0)fprintf(stderr,"Playback gain: %f dB\n", header.gain/256.); if (manual_gain!=0)fprintf(stderr,"Manual gain: %f dB\n", manual_gain); } return st; }
krad_opus_t *krad_opus_decoder_create (unsigned char *header_data, int header_length, float output_sample_rate) { int c; krad_opus_t *krad_opus = calloc (1, sizeof(krad_opus_t)); krad_opus->output_sample_rate = output_sample_rate; krad_opus->opus_header = calloc (1, sizeof(OpusHeader)); if (opus_header_parse (header_data, header_length, krad_opus->opus_header) != 1) { failfast ("krad_opus_decoder_create problem reading opus header"); } // oops //krad_opus->input_sample_rate = krad_opus->opus_header->input_sample_rate; krad_opus->channels = krad_opus->opus_header->channels; krad_opus->interleaved_samples = malloc(16 * 8192); for (c = 0; c < krad_opus->channels; c++) { krad_opus->ringbuf[c] = krad_ringbuffer_create (RINGBUFFER_SIZE); krad_opus->resampled_ringbuf[c] = krad_ringbuffer_create (RINGBUFFER_SIZE); krad_opus->samples[c] = malloc (16 * 8192); krad_opus->read_samples[c] = malloc (16 * 8192); krad_opus->resampled_samples[c] = malloc (16 * 8192); krad_opus->src_resampler[c] = src_new (KRAD_OPUS_SRC_QUALITY, 1, &krad_opus->src_error[c]); if (krad_opus->src_resampler[c] == NULL) { failfast ("krad_opus_decoder_create src resampler error: %s", src_strerror (krad_opus->src_error[c])); } krad_opus->src_data[c].src_ratio = output_sample_rate / 48000; printk ("krad_opus_decoder_create src resampler ratio is: %f", krad_opus->src_data[c].src_ratio); } krad_opus->streams = krad_opus->opus_header->nb_streams; krad_opus->coupled_streams = krad_opus->opus_header->nb_coupled; memcpy (krad_opus->mapping, krad_opus->opus_header->stream_map, 256); printk ("krad_opus_decoder_create channels %d streams %d coupled %d", krad_opus->channels, krad_opus->streams, krad_opus->coupled_streams ); krad_opus->decoder = opus_multistream_decoder_create (48000, krad_opus->opus_header->channels, krad_opus->streams, krad_opus->coupled_streams, krad_opus->mapping, &krad_opus->opus_decoder_error); if (krad_opus->opus_decoder_error != OPUS_OK) { failfast ("Cannot create decoder: %s", opus_strerror (krad_opus->opus_decoder_error)); } return krad_opus; }
void SoftOpus::onQueueFilled(OMX_U32 /* portIndex */) { List<BufferInfo *> &inQueue = getPortQueue(0); List<BufferInfo *> &outQueue = getPortQueue(1); if (mOutputPortSettingsChange != NONE) { return; } while (!mHaveEOS && !inQueue.empty() && !outQueue.empty()) { BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; if (mInputBufferCount < 3) { const uint8_t *data = inHeader->pBuffer + inHeader->nOffset; size_t size = inHeader->nFilledLen; if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && size == 0) { handleEOS(); return; } if (mInputBufferCount == 0) { CHECK(mHeader == NULL); mHeader = new OpusHeader(); memset(mHeader, 0, sizeof(*mHeader)); if (!ParseOpusHeader(data, size, mHeader)) { ALOGV("Parsing Opus Header failed."); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; } uint8_t channel_mapping[kMaxChannels] = {0}; if (mHeader->channels <= kMaxChannelsWithDefaultLayout) { memcpy(&channel_mapping, kDefaultOpusChannelLayout, kMaxChannelsWithDefaultLayout); } else { memcpy(&channel_mapping, mHeader->stream_map, mHeader->channels); } int status = OPUS_INVALID_STATE; mDecoder = opus_multistream_decoder_create(kRate, mHeader->channels, mHeader->num_streams, mHeader->num_coupled, channel_mapping, &status); if (!mDecoder || status != OPUS_OK) { ALOGV("opus_multistream_decoder_create failed status=%s", opus_strerror(status)); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; } status = opus_multistream_decoder_ctl(mDecoder, OPUS_SET_GAIN(mHeader->gain_db)); if (status != OPUS_OK) { ALOGV("Failed to set OPUS header gain; status=%s", opus_strerror(status)); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; } } else if (mInputBufferCount == 1) { mCodecDelay = ns_to_samples( *(reinterpret_cast<int64_t*>(inHeader->pBuffer + inHeader->nOffset)), kRate); mSamplesToDiscard = mCodecDelay; } else { mSeekPreRoll = ns_to_samples( *(reinterpret_cast<int64_t*>(inHeader->pBuffer + inHeader->nOffset)), kRate); notify(OMX_EventPortSettingsChanged, 1, 0, NULL); mOutputPortSettingsChange = AWAITING_DISABLED; } if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { handleEOS(); return; } inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); ++mInputBufferCount; continue; } // Ignore CSD re-submissions. if (mInputBufferCount >= 3 && (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { handleEOS(); return; } inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); continue; } BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) { handleEOS(); return; } if (inHeader->nOffset == 0) { mAnchorTimeUs = inHeader->nTimeStamp; mNumFramesOutput = 0; } // When seeking to zero, |mCodecDelay| samples has to be discarded // instead of |mSeekPreRoll| samples (as we would when seeking to any // other timestamp). if (inHeader->nTimeStamp == 0) { mSamplesToDiscard = mCodecDelay; } const uint8_t *data = inHeader->pBuffer + inHeader->nOffset; const uint32_t size = inHeader->nFilledLen; size_t frameSize = kMaxOpusOutputPacketSizeSamples; if (frameSize > outHeader->nAllocLen / sizeof(int16_t) / mHeader->channels) { frameSize = outHeader->nAllocLen / sizeof(int16_t) / mHeader->channels; android_errorWriteLog(0x534e4554, "27833616"); } int numFrames = opus_multistream_decode(mDecoder, data, size, (int16_t *)outHeader->pBuffer, frameSize, 0); if (numFrames < 0) { ALOGE("opus_multistream_decode returned %d", numFrames); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; } outHeader->nOffset = 0; if (mSamplesToDiscard > 0) { if (mSamplesToDiscard > numFrames) { mSamplesToDiscard -= numFrames; numFrames = 0; } else { numFrames -= mSamplesToDiscard; outHeader->nOffset = mSamplesToDiscard * sizeof(int16_t) * mHeader->channels; mSamplesToDiscard = 0; } } outHeader->nFilledLen = numFrames * sizeof(int16_t) * mHeader->channels; outHeader->nTimeStamp = mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / kRate; mNumFramesOutput += numFrames; if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { outHeader->nFlags = OMX_BUFFERFLAG_EOS; mHaveEOS = true; } else { outHeader->nFlags = 0; } inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); notifyEmptyBufferDone(inHeader); ++mInputBufferCount; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); notifyFillBufferDone(outHeader); } }