static BOOL ffmpeg_resample_frame(AVAudioResampleContext* context, AVFrame* in, AVFrame* out) { int ret; if (!avresample_is_open(context)) { if ((ret = avresample_config(context, out, in)) < 0) { const char* err = av_err2str(ret); WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); return FALSE; } if ((ret = (avresample_open(context))) < 0) { const char* err = av_err2str(ret); WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); return FALSE; } } if ((ret = avresample_convert_frame(context, out, in)) < 0) { const char* err = av_err2str(ret); WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); return FALSE; } return TRUE; }
static BOOL ffmpeg_decode(AVCodecContext* dec_ctx, AVPacket* pkt, AVFrame* frame, AVAudioResampleContext* resampleContext, AVFrame* resampled, wStream* out) { int ret; /* send the packet with the compressed data to the decoder */ ret = avcodec_send_packet(dec_ctx, pkt); if (ret < 0) { const char* err = av_err2str(ret); WLog_ERR(TAG, "Error submitting the packet to the decoder %s [%d]", err, ret); return FALSE; } /* read all the output frames (in general there may be any number of them */ while (ret >= 0) { ret = avcodec_receive_frame(dec_ctx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return TRUE; else if (ret < 0) { const char* err = av_err2str(ret); WLog_ERR(TAG, "Error during decoding %s [%d]", err, ret); return FALSE; } if (!avresample_is_open(resampleContext)) { if ((ret = avresample_config(resampleContext, resampled, frame)) < 0) { const char* err = av_err2str(ret); WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); return FALSE; } if ((ret = (avresample_open(resampleContext))) < 0) { const char* err = av_err2str(ret); WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); return FALSE; } } if ((ret = avresample_convert_frame(resampleContext, resampled, frame)) < 0) { const char* err = av_err2str(ret); WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); return FALSE; } { const size_t data_size = resampled->channels * resampled->nb_samples * 2; Stream_EnsureRemainingCapacity(out, data_size); Stream_Write(out, resampled->data[0], data_size); } } return TRUE; }
int avresample_open(AVAudioResampleContext *avr) { int ret; if (avresample_is_open(avr)) { av_log(avr, AV_LOG_ERROR, "The resampling context is already open.\n"); return AVERROR(EINVAL); } /* set channel mixing parameters */ avr->in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); if (avr->in_channels <= 0 || avr->in_channels > AVRESAMPLE_MAX_CHANNELS) { av_log(avr, AV_LOG_ERROR, "Invalid input channel layout: %"PRIu64"\n", avr->in_channel_layout); return AVERROR(EINVAL); } avr->out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); if (avr->out_channels <= 0 || avr->out_channels > AVRESAMPLE_MAX_CHANNELS) { av_log(avr, AV_LOG_ERROR, "Invalid output channel layout: %"PRIu64"\n", avr->out_channel_layout); return AVERROR(EINVAL); } avr->resample_channels = FFMIN(avr->in_channels, avr->out_channels); avr->downmix_needed = avr->in_channels > avr->out_channels; avr->upmix_needed = avr->out_channels > avr->in_channels || (!avr->downmix_needed && (avr->mix_matrix || avr->in_channel_layout != avr->out_channel_layout)); avr->mixing_needed = avr->downmix_needed || avr->upmix_needed; /* set resampling parameters */ avr->resample_needed = avr->in_sample_rate != avr->out_sample_rate || avr->force_resampling; /* select internal sample format if not specified by the user */ if (avr->internal_sample_fmt == AV_SAMPLE_FMT_NONE && (avr->mixing_needed || avr->resample_needed)) { enum AVSampleFormat in_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); enum AVSampleFormat out_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); int max_bps = FFMAX(av_get_bytes_per_sample(in_fmt), av_get_bytes_per_sample(out_fmt)); if (max_bps <= 2) { avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P; } else if (avr->mixing_needed) { avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; } else { if (max_bps <= 4) { if (in_fmt == AV_SAMPLE_FMT_S32P || out_fmt == AV_SAMPLE_FMT_S32P) { if (in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_FLTP) { /* if one is s32 and the other is flt, use dbl */ avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; } else { /* if one is s32 and the other is s32, s16, or u8, use s32 */ avr->internal_sample_fmt = AV_SAMPLE_FMT_S32P; } } else { /* if one is flt and the other is flt, s16 or u8, use flt */ avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; } } else { /* if either is dbl, use dbl */ avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; } } av_log(avr, AV_LOG_DEBUG, "Using %s as internal sample format\n", av_get_sample_fmt_name(avr->internal_sample_fmt)); } /* treat all mono as planar for easier comparison */ if (avr->in_channels == 1) avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); if (avr->out_channels == 1) avr->out_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); /* we may need to add an extra conversion in order to remap channels if the output format is not planar */ if (avr->use_channel_map && !avr->mixing_needed && !avr->resample_needed && !av_sample_fmt_is_planar(avr->out_sample_fmt)) { avr->internal_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); } /* set sample format conversion parameters */ if (avr->resample_needed || avr->mixing_needed) avr->in_convert_needed = avr->in_sample_fmt != avr->internal_sample_fmt; else avr->in_convert_needed = avr->use_channel_map && !av_sample_fmt_is_planar(avr->out_sample_fmt); if (avr->resample_needed || avr->mixing_needed || avr->in_convert_needed) avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt; else avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt; avr->in_copy_needed = !avr->in_convert_needed && (avr->mixing_needed || (avr->use_channel_map && avr->resample_needed)); if (avr->use_channel_map) { if (avr->in_copy_needed) { avr->remap_point = REMAP_IN_COPY; av_dlog(avr, "remap channels during in_copy\n"); } else if (avr->in_convert_needed) { avr->remap_point = REMAP_IN_CONVERT; av_dlog(avr, "remap channels during in_convert\n"); } else if (avr->out_convert_needed) { avr->remap_point = REMAP_OUT_CONVERT; av_dlog(avr, "remap channels during out_convert\n"); } else { avr->remap_point = REMAP_OUT_COPY; av_dlog(avr, "remap channels during out_copy\n"); } #ifdef DEBUG { int ch; av_dlog(avr, "output map: "); if (avr->ch_map_info.do_remap) for (ch = 0; ch < avr->in_channels; ch++) av_dlog(avr, " % 2d", avr->ch_map_info.channel_map[ch]); else av_dlog(avr, "n/a"); av_dlog(avr, "\n"); av_dlog(avr, "copy map: "); if (avr->ch_map_info.do_copy) for (ch = 0; ch < avr->in_channels; ch++) av_dlog(avr, " % 2d", avr->ch_map_info.channel_copy[ch]); else av_dlog(avr, "n/a"); av_dlog(avr, "\n"); av_dlog(avr, "zero map: "); if (avr->ch_map_info.do_zero) for (ch = 0; ch < avr->in_channels; ch++) av_dlog(avr, " % 2d", avr->ch_map_info.channel_zero[ch]); else av_dlog(avr, "n/a"); av_dlog(avr, "\n"); av_dlog(avr, "input map: "); for (ch = 0; ch < avr->in_channels; ch++) av_dlog(avr, " % 2d", avr->ch_map_info.input_map[ch]); av_dlog(avr, "\n"); } #endif } else avr->remap_point = REMAP_NONE; /* allocate buffers */ if (avr->in_copy_needed || avr->in_convert_needed) { avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels), 0, avr->internal_sample_fmt, "in_buffer"); if (!avr->in_buffer) { ret = AVERROR(EINVAL); goto error; } } if (avr->resample_needed) { avr->resample_out_buffer = ff_audio_data_alloc(avr->out_channels, 1024, avr->internal_sample_fmt, "resample_out_buffer"); if (!avr->resample_out_buffer) { ret = AVERROR(EINVAL); goto error; } } if (avr->out_convert_needed) { avr->out_buffer = ff_audio_data_alloc(avr->out_channels, 0, avr->out_sample_fmt, "out_buffer"); if (!avr->out_buffer) { ret = AVERROR(EINVAL); goto error; } } avr->out_fifo = av_audio_fifo_alloc(avr->out_sample_fmt, avr->out_channels, 1024); if (!avr->out_fifo) { ret = AVERROR(ENOMEM); goto error; } /* setup contexts */ if (avr->in_convert_needed) { avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt, avr->in_sample_fmt, avr->in_channels, avr->in_sample_rate, avr->remap_point == REMAP_IN_CONVERT); if (!avr->ac_in) { ret = AVERROR(ENOMEM); goto error; } } if (avr->out_convert_needed) { enum AVSampleFormat src_fmt; if (avr->in_convert_needed) src_fmt = avr->internal_sample_fmt; else src_fmt = avr->in_sample_fmt; avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt, avr->out_channels, avr->out_sample_rate, avr->remap_point == REMAP_OUT_CONVERT); if (!avr->ac_out) { ret = AVERROR(ENOMEM); goto error; } } if (avr->resample_needed) { avr->resample = ff_audio_resample_init(avr); if (!avr->resample) { ret = AVERROR(ENOMEM); goto error; } } if (avr->mixing_needed) { avr->am = ff_audio_mix_alloc(avr); if (!avr->am) { ret = AVERROR(ENOMEM); goto error; } } return 0; error: avresample_close(avr); return ret; }
static int opus_decode_subpacket(OpusStreamContext *s, const uint8_t *buf, int buf_size, int nb_samples) { int output_samples = 0; int flush_needed = 0; int i, j, ret; /* check if we need to flush the resampler */ if (avresample_is_open(s->avr)) { if (buf) { int64_t cur_samplerate; av_opt_get_int(s->avr, "in_sample_rate", 0, &cur_samplerate); flush_needed = (s->packet.mode == OPUS_MODE_CELT) || (cur_samplerate != s->silk_samplerate); } else { flush_needed = !!s->delayed_samples; } } if (!buf && !flush_needed) return 0; /* use dummy output buffers if the channel is not mapped to anything */ if (!s->out[0] || (s->output_channels == 2 && !s->out[1])) { av_fast_malloc(&s->out_dummy, &s->out_dummy_allocated_size, s->out_size); if (!s->out_dummy) return AVERROR(ENOMEM); if (!s->out[0]) s->out[0] = s->out_dummy; if (!s->out[1]) s->out[1] = s->out_dummy; } /* flush the resampler if necessary */ if (flush_needed) { ret = opus_flush_resample(s, s->delayed_samples); if (ret < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error flushing the resampler.\n"); return ret; } avresample_close(s->avr); output_samples += s->delayed_samples; s->delayed_samples = 0; if (!buf) goto finish; } /* decode all the frames in the packet */ for (i = 0; i < s->packet.frame_count; i++) { int size = s->packet.frame_size[i]; int samples = opus_decode_frame(s, buf + s->packet.frame_offset[i], size); if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error decoding an Opus frame.\n"); if (s->avctx->err_recognition & AV_EF_EXPLODE) return samples; for (j = 0; j < s->output_channels; j++) memset(s->out[j], 0, s->packet.frame_duration * sizeof(float)); samples = s->packet.frame_duration; } output_samples += samples; for (j = 0; j < s->output_channels; j++) s->out[j] += samples; s->out_size -= samples * sizeof(float); } finish: s->out[0] = s->out[1] = NULL; s->out_size = 0; return output_samples; }
static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size) { int samples = s->packet.frame_duration; int redundancy = 0; int redundancy_size, redundancy_pos; int ret, i, consumed; int delayed_samples = s->delayed_samples; ret = opus_rc_init(&s->rc, data, size); if (ret < 0) return ret; /* decode the silk frame */ if (s->packet.mode == OPUS_MODE_SILK || s->packet.mode == OPUS_MODE_HYBRID) { if (!avresample_is_open(s->avr)) { ret = opus_init_resample(s); if (ret < 0) return ret; } samples = ff_silk_decode_superframe(s->silk, &s->rc, s->silk_output, FFMIN(s->packet.bandwidth, OPUS_BANDWIDTH_WIDEBAND), s->packet.stereo + 1, silk_frame_duration_ms[s->packet.config]); if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error decoding a SILK frame.\n"); return samples; } samples = avresample_convert(s->avr, (uint8_t**)s->out, s->out_size, s->packet.frame_duration, (uint8_t**)s->silk_output, sizeof(s->silk_buf[0]), samples); if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error resampling SILK data.\n"); return samples; } s->delayed_samples += s->packet.frame_duration - samples; } else ff_silk_flush(s->silk); // decode redundancy information consumed = opus_rc_tell(&s->rc); if (s->packet.mode == OPUS_MODE_HYBRID && consumed + 37 <= size * 8) redundancy = opus_rc_p2model(&s->rc, 12); else if (s->packet.mode == OPUS_MODE_SILK && consumed + 17 <= size * 8) redundancy = 1; if (redundancy) { redundancy_pos = opus_rc_p2model(&s->rc, 1); if (s->packet.mode == OPUS_MODE_HYBRID) redundancy_size = opus_rc_unimodel(&s->rc, 256) + 2; else redundancy_size = size - (consumed + 7) / 8; size -= redundancy_size; if (size < 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid redundancy frame size.\n"); return AVERROR_INVALIDDATA; } if (redundancy_pos) { ret = opus_decode_redundancy(s, data + size, redundancy_size); if (ret < 0) return ret; ff_celt_flush(s->celt); } } /* decode the CELT frame */ if (s->packet.mode == OPUS_MODE_CELT || s->packet.mode == OPUS_MODE_HYBRID) { float *out_tmp[2] = { s->out[0], s->out[1] }; float **dst = (s->packet.mode == OPUS_MODE_CELT) ? out_tmp : s->celt_output; int celt_output_samples = samples; int delay_samples = av_audio_fifo_size(s->celt_delay); if (delay_samples) { if (s->packet.mode == OPUS_MODE_HYBRID) { av_audio_fifo_read(s->celt_delay, (void**)s->celt_output, delay_samples); for (i = 0; i < s->output_channels; i++) { s->fdsp->vector_fmac_scalar(out_tmp[i], s->celt_output[i], 1.0, delay_samples); out_tmp[i] += delay_samples; } celt_output_samples -= delay_samples; } else { av_log(s->avctx, AV_LOG_WARNING, "Spurious CELT delay samples present.\n"); av_audio_fifo_drain(s->celt_delay, delay_samples); if (s->avctx->err_recognition & AV_EF_EXPLODE) return AVERROR_BUG; } } opus_raw_init(&s->rc, data + size, size); ret = ff_celt_decode_frame(s->celt, &s->rc, dst, s->packet.stereo + 1, s->packet.frame_duration, (s->packet.mode == OPUS_MODE_HYBRID) ? 17 : 0, celt_band_end[s->packet.bandwidth]); if (ret < 0) return ret; if (s->packet.mode == OPUS_MODE_HYBRID) { int celt_delay = s->packet.frame_duration - celt_output_samples; void *delaybuf[2] = { s->celt_output[0] + celt_output_samples, s->celt_output[1] + celt_output_samples }; for (i = 0; i < s->output_channels; i++) { s->fdsp->vector_fmac_scalar(out_tmp[i], s->celt_output[i], 1.0, celt_output_samples); } ret = av_audio_fifo_write(s->celt_delay, delaybuf, celt_delay); if (ret < 0) return ret; } } else ff_celt_flush(s->celt); if (s->redundancy_idx) { for (i = 0; i < s->output_channels; i++) opus_fade(s->out[i], s->out[i], s->redundancy_output[i] + 120 + s->redundancy_idx, ff_celt_window2 + s->redundancy_idx, 120 - s->redundancy_idx); s->redundancy_idx = 0; } if (redundancy) { if (!redundancy_pos) { ff_celt_flush(s->celt); ret = opus_decode_redundancy(s, data + size, redundancy_size); if (ret < 0) return ret; for (i = 0; i < s->output_channels; i++) { opus_fade(s->out[i] + samples - 120 + delayed_samples, s->out[i] + samples - 120 + delayed_samples, s->redundancy_output[i] + 120, ff_celt_window2, 120 - delayed_samples); if (delayed_samples) s->redundancy_idx = 120 - delayed_samples; } } else { for (i = 0; i < s->output_channels; i++) { memcpy(s->out[i] + delayed_samples, s->redundancy_output[i], 120 * sizeof(float)); opus_fade(s->out[i] + 120 + delayed_samples, s->redundancy_output[i] + 120, s->out[i] + 120 + delayed_samples, ff_celt_window2, 120); } } } return samples; }
static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size) { int samples = s->packet.frame_duration; int redundancy = 0; int redundancy_size, redundancy_pos; int ret, i, consumed; int delayed_samples = s->delayed_samples; ret = ff_opus_rc_dec_init(&s->rc, data, size); if (ret < 0) return ret; /* decode the silk frame */ if (s->packet.mode == OPUS_MODE_SILK || s->packet.mode == OPUS_MODE_HYBRID) { #if CONFIG_SWRESAMPLE if (!swr_is_initialized(s->swr)) { #elif CONFIG_AVRESAMPLE if (!avresample_is_open(s->avr)) { #endif ret = opus_init_resample(s); if (ret < 0) return ret; } samples = ff_silk_decode_superframe(s->silk, &s->rc, s->silk_output, FFMIN(s->packet.bandwidth, OPUS_BANDWIDTH_WIDEBAND), s->packet.stereo + 1, silk_frame_duration_ms[s->packet.config]); if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error decoding a SILK frame.\n"); return samples; } #if CONFIG_SWRESAMPLE samples = swr_convert(s->swr, (uint8_t**)s->out, s->packet.frame_duration, (const uint8_t**)s->silk_output, samples); #elif CONFIG_AVRESAMPLE samples = avresample_convert(s->avr, (uint8_t**)s->out, s->out_size, s->packet.frame_duration, (uint8_t**)s->silk_output, sizeof(s->silk_buf[0]), samples); #endif if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error resampling SILK data.\n"); return samples; } av_assert2((samples & 7) == 0); s->delayed_samples += s->packet.frame_duration - samples; } else ff_silk_flush(s->silk); // decode redundancy information consumed = opus_rc_tell(&s->rc); if (s->packet.mode == OPUS_MODE_HYBRID && consumed + 37 <= size * 8) redundancy = ff_opus_rc_dec_log(&s->rc, 12); else if (s->packet.mode == OPUS_MODE_SILK && consumed + 17 <= size * 8) redundancy = 1; if (redundancy) { redundancy_pos = ff_opus_rc_dec_log(&s->rc, 1); if (s->packet.mode == OPUS_MODE_HYBRID) redundancy_size = ff_opus_rc_dec_uint(&s->rc, 256) + 2; else redundancy_size = size - (consumed + 7) / 8; size -= redundancy_size; if (size < 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid redundancy frame size.\n"); return AVERROR_INVALIDDATA; } if (redundancy_pos) { ret = opus_decode_redundancy(s, data + size, redundancy_size); if (ret < 0) return ret; ff_celt_flush(s->celt); } } /* decode the CELT frame */ if (s->packet.mode == OPUS_MODE_CELT || s->packet.mode == OPUS_MODE_HYBRID) { float *out_tmp[2] = { s->out[0], s->out[1] }; float **dst = (s->packet.mode == OPUS_MODE_CELT) ? out_tmp : s->celt_output; int celt_output_samples = samples; int delay_samples = av_audio_fifo_size(s->celt_delay); if (delay_samples) { if (s->packet.mode == OPUS_MODE_HYBRID) { av_audio_fifo_read(s->celt_delay, (void**)s->celt_output, delay_samples); for (i = 0; i < s->output_channels; i++) { s->fdsp->vector_fmac_scalar(out_tmp[i], s->celt_output[i], 1.0, delay_samples); out_tmp[i] += delay_samples; } celt_output_samples -= delay_samples; } else { av_log(s->avctx, AV_LOG_WARNING, "Spurious CELT delay samples present.\n"); av_audio_fifo_drain(s->celt_delay, delay_samples); if (s->avctx->err_recognition & AV_EF_EXPLODE) return AVERROR_BUG; } } ff_opus_rc_dec_raw_init(&s->rc, data + size, size); ret = ff_celt_decode_frame(s->celt, &s->rc, dst, s->packet.stereo + 1, s->packet.frame_duration, (s->packet.mode == OPUS_MODE_HYBRID) ? 17 : 0, ff_celt_band_end[s->packet.bandwidth]); if (ret < 0) return ret; if (s->packet.mode == OPUS_MODE_HYBRID) { int celt_delay = s->packet.frame_duration - celt_output_samples; void *delaybuf[2] = { s->celt_output[0] + celt_output_samples, s->celt_output[1] + celt_output_samples }; for (i = 0; i < s->output_channels; i++) { s->fdsp->vector_fmac_scalar(out_tmp[i], s->celt_output[i], 1.0, celt_output_samples); } ret = av_audio_fifo_write(s->celt_delay, delaybuf, celt_delay); if (ret < 0) return ret; } } else ff_celt_flush(s->celt); if (s->redundancy_idx) { for (i = 0; i < s->output_channels; i++) opus_fade(s->out[i], s->out[i], s->redundancy_output[i] + 120 + s->redundancy_idx, ff_celt_window2 + s->redundancy_idx, 120 - s->redundancy_idx); s->redundancy_idx = 0; } if (redundancy) { if (!redundancy_pos) { ff_celt_flush(s->celt); ret = opus_decode_redundancy(s, data + size, redundancy_size); if (ret < 0) return ret; for (i = 0; i < s->output_channels; i++) { opus_fade(s->out[i] + samples - 120 + delayed_samples, s->out[i] + samples - 120 + delayed_samples, s->redundancy_output[i] + 120, ff_celt_window2, 120 - delayed_samples); if (delayed_samples) s->redundancy_idx = 120 - delayed_samples; } } else { for (i = 0; i < s->output_channels; i++) { memcpy(s->out[i] + delayed_samples, s->redundancy_output[i], 120 * sizeof(float)); opus_fade(s->out[i] + 120 + delayed_samples, s->redundancy_output[i] + 120, s->out[i] + 120 + delayed_samples, ff_celt_window2, 120); } } } return samples; } static int opus_decode_subpacket(OpusStreamContext *s, const uint8_t *buf, int buf_size, float **out, int out_size, int nb_samples) { int output_samples = 0; int flush_needed = 0; int i, j, ret; s->out[0] = out[0]; s->out[1] = out[1]; s->out_size = out_size; /* check if we need to flush the resampler */ #if CONFIG_SWRESAMPLE if (swr_is_initialized(s->swr)) { if (buf) { int64_t cur_samplerate; av_opt_get_int(s->swr, "in_sample_rate", 0, &cur_samplerate); flush_needed = (s->packet.mode == OPUS_MODE_CELT) || (cur_samplerate != s->silk_samplerate); } else { flush_needed = !!s->delayed_samples; } } #elif CONFIG_AVRESAMPLE if (avresample_is_open(s->avr)) { if (buf) { int64_t cur_samplerate; av_opt_get_int(s->avr, "in_sample_rate", 0, &cur_samplerate); flush_needed = (s->packet.mode == OPUS_MODE_CELT) || (cur_samplerate != s->silk_samplerate); } else { flush_needed = !!s->delayed_samples; } } #endif if (!buf && !flush_needed) return 0; /* use dummy output buffers if the channel is not mapped to anything */ if (!s->out[0] || (s->output_channels == 2 && !s->out[1])) { av_fast_malloc(&s->out_dummy, &s->out_dummy_allocated_size, s->out_size); if (!s->out_dummy) return AVERROR(ENOMEM); if (!s->out[0]) s->out[0] = s->out_dummy; if (!s->out[1]) s->out[1] = s->out_dummy; } /* flush the resampler if necessary */ if (flush_needed) { ret = opus_flush_resample(s, s->delayed_samples); if (ret < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error flushing the resampler.\n"); return ret; } #if CONFIG_SWRESAMPLE swr_close(s->swr); #elif CONFIG_AVRESAMPLE avresample_close(s->avr); #endif output_samples += s->delayed_samples; s->delayed_samples = 0; if (!buf) goto finish; } /* decode all the frames in the packet */ for (i = 0; i < s->packet.frame_count; i++) { int size = s->packet.frame_size[i]; int samples = opus_decode_frame(s, buf + s->packet.frame_offset[i], size); if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error decoding an Opus frame.\n"); if (s->avctx->err_recognition & AV_EF_EXPLODE) return samples; for (j = 0; j < s->output_channels; j++) memset(s->out[j], 0, s->packet.frame_duration * sizeof(float)); samples = s->packet.frame_duration; } output_samples += samples; for (j = 0; j < s->output_channels; j++) s->out[j] += samples; s->out_size -= samples * sizeof(float); } finish: s->out[0] = s->out[1] = NULL; s->out_size = 0; return output_samples; }