コード例 #1
0
ファイル: nv_opus_dec.c プロジェクト: A2K/moonlight-android
// 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;
}
コード例 #2
0
	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
	}
コード例 #3
0
ファイル: auddec.cpp プロジェクト: Aghassi/moonlight-chrome
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();
}
コード例 #4
0
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;
}
コード例 #5
0
ファイル: opus.c プロジェクト: MSalmo/vlc
/*****************************************************************************
 * 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;
}
コード例 #6
0
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;
}
コード例 #7
0
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;
}
コード例 #8
0
ファイル: omx.c プロジェクト: 4ydx/moonlight-embedded
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);
  }
}
コード例 #9
0
ファイル: libopusdec.c プロジェクト: JSinglan/libav
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;
}
コード例 #10
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;
}
コード例 #11
0
ファイル: krad_opus.c プロジェクト: imclab/krad_radio
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;

}
コード例 #12
0
ファイル: SoftOpus.cpp プロジェクト: MIPS/frameworks-av
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);
    }
}