int avresample_get_out_samples(AVAudioResampleContext *avr, int in_nb_samples) { int64_t samples = avresample_get_delay(avr) + (int64_t)in_nb_samples; if (avr->resample_needed) { samples = av_rescale_rnd(samples, avr->out_sample_rate, avr->in_sample_rate, AV_ROUND_UP); } samples += avresample_available(avr); if (samples > INT_MAX) return AVERROR(EINVAL); return samples; }
static int request_frame(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; ResampleContext *s = ctx->priv; int ret = 0; s->got_output = 0; while (ret >= 0 && !s->got_output) ret = ff_request_frame(ctx->inputs[0]); /* flush the lavr delay buffer */ if (ret == AVERROR_EOF && s->avr) { AVFilterBufferRef *buf; int nb_samples = av_rescale_rnd(avresample_get_delay(s->avr), outlink->sample_rate, ctx->inputs[0]->sample_rate, AV_ROUND_UP); if (!nb_samples) return ret; buf = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples); if (!buf) return AVERROR(ENOMEM); ret = avresample_convert(s->avr, (void**)buf->extended_data, buf->linesize[0], nb_samples, NULL, 0, 0); if (ret <= 0) { avfilter_unref_buffer(buf); return (ret == 0) ? AVERROR_EOF : ret; } buf->pts = s->next_pts; return ff_filter_samples(outlink, buf); } return ret; }
static int request_frame(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; ResampleContext *s = ctx->priv; int ret = 0; s->got_output = 0; while (ret >= 0 && !s->got_output) ret = ff_request_frame(ctx->inputs[0]); /* flush the lavr delay buffer */ if (ret == AVERROR_EOF && s->avr) { AVFrame *frame; int nb_samples = av_rescale_rnd(avresample_get_delay(s->avr), outlink->sample_rate, ctx->inputs[0]->sample_rate, AV_ROUND_UP); if (!nb_samples) return ret; frame = ff_get_audio_buffer(outlink, nb_samples); if (!frame) return AVERROR(ENOMEM); ret = avresample_convert(s->avr, frame->extended_data, frame->linesize[0], nb_samples, NULL, 0, 0); if (ret <= 0) { av_frame_free(&frame); return (ret == 0) ? AVERROR_EOF : ret; } frame->pts = s->next_pts; return ff_filter_frame(outlink, frame); } return ret; }
static double get_delay(struct af_resample *s) { return avresample_get_delay(s->avrctx) / (double)s->in_rate + avresample_available(s->avrctx) / (double)s->out_rate; }
static int get_delay(struct af_resample *s) { return avresample_get_delay(s->avrctx); }
int64_t swr_get_delay(struct SwrContext *s, int64_t base) { int64_t in_sr, out_sr; av_opt_get_int(s, "in_sample_rate", 0, &in_sr); av_opt_get_int(s, "out_sample_rate", 0, &out_sr); return av_rescale_rnd(avresample_available(s), base, out_sr, AV_ROUND_UP) + av_rescale_rnd(avresample_get_delay(s), base, in_sr, AV_ROUND_UP); }
long audio_tutorial_resample(VideoState *is, struct AVFrame *inframe) { #ifdef __RESAMPLER__ #ifdef __LIBAVRESAMPLE__ // There is pre 1.0 libavresample and then there is above.. #if LIBAVRESAMPLE_VERSION_MAJOR == 0 void **resample_input_bytes = (void **)inframe->extended_data; #else uint8_t **resample_input_bytes = (uint8_t **)inframe->extended_data; #endif #else uint8_t **resample_input_bytes = (uint8_t **)inframe->extended_data; #endif int resample_nblen = 0; long resample_long_bytes = 0; if( is->pResampledOut == NULL || inframe->nb_samples > is->resample_size) { #if __LIBAVRESAMPLE__ is->resample_size = av_rescale_rnd(avresample_get_delay(is->pSwrCtx) + inframe->nb_samples, 44100, 44100, AV_ROUND_UP); #else is->resample_size = av_rescale_rnd(swr_get_delay(is->pSwrCtx, 44100) + inframe->nb_samples, 44100, 44100, AV_ROUND_UP); #endif if(is->pResampledOut != NULL) { av_free(is->pResampledOut); is->pResampledOut = NULL; } av_samples_alloc(&is->pResampledOut, &is->resample_lines, 2, is->resample_size, AV_SAMPLE_FMT_S16, 0); } #ifdef __LIBAVRESAMPLE__ // OLD API (0.0.3) ... still NEW API (1.0.0 and above).. very frustrating.. // USED IN FFMPEG 1.0 (LibAV SOMETHING!). New in FFMPEG 1.1 and libav 9 #if LIBAVRESAMPLE_VERSION_INT <= 3 // AVResample OLD resample_nblen = avresample_convert(is->pSwrCtx, (void **)&is->pResampledOut, 0, is->resample_size, (void **)resample_input_bytes, 0, inframe->nb_samples); #else //AVResample NEW resample_nblen = avresample_convert(is->pSwrCtx, (uint8_t **)&is->pResampledOut, 0, is->resample_size, (uint8_t **)resample_input_bytes, 0, inframe->nb_samples); #endif #else // SWResample resample_nblen = swr_convert(is->pSwrCtx, (uint8_t **)&is->pResampledOut, is->resample_size, (const uint8_t **)resample_input_bytes, inframe->nb_samples); #endif resample_long_bytes = av_samples_get_buffer_size(NULL, 2, resample_nblen, AV_SAMPLE_FMT_S16, 1); if (resample_nblen < 0) { fprintf(stderr, "reSample to another sample format failed!\n"); return -1; } return resample_long_bytes; #else return -1; #endif }
static void audio_process_audio(audio_decoder_t *ad, media_buf_t *mb) { const audio_class_t *ac = ad->ad_ac; AVFrame *frame = ad->ad_frame; media_pipe_t *mp = ad->ad_mp; media_queue_t *mq = &mp->mp_audio; int r; int got_frame; if(mb->mb_skip || mb->mb_stream != mq->mq_stream) return; while(mb->mb_size) { if(mb->mb_cw == NULL) { frame->sample_rate = mb->mb_rate; frame->format = AV_SAMPLE_FMT_S16; switch(mb->mb_channels) { case 1: frame->channel_layout = AV_CH_LAYOUT_MONO; frame->nb_samples = mb->mb_size / 2; break; case 2: frame->channel_layout = AV_CH_LAYOUT_STEREO; frame->nb_samples = mb->mb_size / 4; break; default: abort(); } frame->data[0] = mb->mb_data; frame->linesize[0] = 0; r = mb->mb_size; got_frame = 1; } else { media_codec_t *mc = mb->mb_cw; AVCodecContext *ctx = mc->ctx; if(mc->codec_id != ad->ad_in_codec_id) { AVCodec *codec = avcodec_find_decoder(mc->codec_id); TRACE(TRACE_DEBUG, "audio", "Codec changed to %s (0x%x)", codec ? codec->name : "???", mc->codec_id); ad->ad_in_codec_id = mc->codec_id; ad->ad_in_sample_rate = 0; audio_cleanup_spdif_muxer(ad); ad->ad_mode = ac->ac_get_mode != NULL ? ac->ac_get_mode(ad, mc->codec_id, ctx ? ctx->extradata : NULL, ctx ? ctx->extradata_size : 0) : AUDIO_MODE_PCM; if(ad->ad_mode == AUDIO_MODE_SPDIF) { audio_setup_spdif_muxer(ad, codec, mq); } else if(ad->ad_mode == AUDIO_MODE_CODED) { hts_mutex_lock(&mp->mp_mutex); ac->ac_deliver_coded_locked(ad, mb->mb_data, mb->mb_size, mb->mb_pts, mb->mb_epoch); hts_mutex_unlock(&mp->mp_mutex); return; } } if(ad->ad_spdif_muxer != NULL) { mb->mb_pkt.stream_index = 0; ad->ad_pts = mb->mb_pts; ad->ad_epoch = mb->mb_epoch; mb->mb_pts = AV_NOPTS_VALUE; mb->mb_dts = AV_NOPTS_VALUE; av_write_frame(ad->ad_spdif_muxer, &mb->mb_pkt); avio_flush(ad->ad_spdif_muxer->pb); return; } if(ad->ad_mode == AUDIO_MODE_CODED) { ad->ad_pts = mb->mb_pts; ad->ad_epoch = mb->mb_epoch; } if(ctx == NULL) { AVCodec *codec = avcodec_find_decoder(mc->codec_id); assert(codec != NULL); // Checked in libav.c ctx = mc->ctx = avcodec_alloc_context3(codec); if(ad->ad_stereo_downmix) ctx->request_channel_layout = AV_CH_LAYOUT_STEREO; if(avcodec_open2(mc->ctx, codec, NULL) < 0) { av_freep(&mc->ctx); return; } } r = avcodec_decode_audio4(ctx, frame, &got_frame, &mb->mb_pkt); if(r < 0) return; if(frame->sample_rate == 0) { frame->sample_rate = ctx->sample_rate; if(frame->sample_rate == 0 && mb->mb_cw->fmt_ctx) frame->sample_rate = mb->mb_cw->fmt_ctx->sample_rate; if(frame->sample_rate == 0) { if(!ad->ad_sample_rate_fail) { ad->ad_sample_rate_fail = 1; TRACE(TRACE_ERROR, "Audio", "Unable to determine sample rate"); } return; } } if(frame->channel_layout == 0) { frame->channel_layout = av_get_default_channel_layout(ctx->channels); if(frame->channel_layout == 0) { if(!ad->ad_channel_layout_fail) { ad->ad_channel_layout_fail = 1; TRACE(TRACE_ERROR, "Audio", "Unable to map %d channels to channel layout"); } return; } } if(mp->mp_stats) mp_set_mq_meta(mq, ctx->codec, ctx); } if(mb->mb_pts != PTS_UNSET) { int od = 0, id = 0; if(ad->ad_avr != NULL) { od = avresample_available(ad->ad_avr) * 1000000LL / ad->ad_out_sample_rate; id = avresample_get_delay(ad->ad_avr) * 1000000LL / frame->sample_rate; } ad->ad_pts = mb->mb_pts - od - id; ad->ad_epoch = mb->mb_epoch; if(mb->mb_drive_clock) mp_set_current_time(mp, mb->mb_pts - ad->ad_delay, mb->mb_epoch, mb->mb_delta); mb->mb_pts = PTS_UNSET; // No longer valid } mb->mb_data += r; mb->mb_size -= r; if(got_frame) { if(frame->sample_rate != ad->ad_in_sample_rate || frame->format != ad->ad_in_sample_format || frame->channel_layout != ad->ad_in_channel_layout || ad->ad_want_reconfig) { ad->ad_want_reconfig = 0; ad->ad_in_sample_rate = frame->sample_rate; ad->ad_in_sample_format = frame->format; ad->ad_in_channel_layout = frame->channel_layout; ac->ac_reconfig(ad); if(ad->ad_avr == NULL) ad->ad_avr = avresample_alloc_context(); else avresample_close(ad->ad_avr); av_opt_set_int(ad->ad_avr, "in_sample_fmt", ad->ad_in_sample_format, 0); av_opt_set_int(ad->ad_avr, "in_sample_rate", ad->ad_in_sample_rate, 0); av_opt_set_int(ad->ad_avr, "in_channel_layout", ad->ad_in_channel_layout, 0); av_opt_set_int(ad->ad_avr, "out_sample_fmt", ad->ad_out_sample_format, 0); av_opt_set_int(ad->ad_avr, "out_sample_rate", ad->ad_out_sample_rate, 0); av_opt_set_int(ad->ad_avr, "out_channel_layout", ad->ad_out_channel_layout, 0); char buf1[128]; char buf2[128]; av_get_channel_layout_string(buf1, sizeof(buf1), -1, ad->ad_in_channel_layout); av_get_channel_layout_string(buf2, sizeof(buf2), -1, ad->ad_out_channel_layout); TRACE(TRACE_DEBUG, "Audio", "Converting from [%s %dHz %s] to [%s %dHz %s]", buf1, ad->ad_in_sample_rate, av_get_sample_fmt_name(ad->ad_in_sample_format), buf2, ad->ad_out_sample_rate, av_get_sample_fmt_name(ad->ad_out_sample_format)); if(avresample_open(ad->ad_avr)) { TRACE(TRACE_ERROR, "Audio", "Unable to open resampler"); avresample_free(&ad->ad_avr); } prop_set(mp->mp_prop_ctrl, "canAdjustVolume", PROP_SET_INT, 1); if(ac->ac_set_volume != NULL) ac->ac_set_volume(ad, ad->ad_vol_scale); } if(ad->ad_avr != NULL) { avresample_convert(ad->ad_avr, NULL, 0, 0, frame->data, frame->linesize[0], frame->nb_samples); } else { int delay = 1000000LL * frame->nb_samples / frame->sample_rate; usleep(delay); } } } }
static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; ResampleContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; int ret; if (s->avr) { AVFrame *out; int delay, nb_samples; /* maximum possible samples lavr can output */ delay = avresample_get_delay(s->avr); nb_samples = avresample_get_out_samples(s->avr, in->nb_samples); out = ff_get_audio_buffer(outlink, nb_samples); if (!out) { ret = AVERROR(ENOMEM); goto fail; } ret = avresample_convert(s->avr, out->extended_data, out->linesize[0], nb_samples, in->extended_data, in->linesize[0], in->nb_samples); if (ret <= 0) { av_frame_free(&out); if (ret < 0) goto fail; } av_assert0(!avresample_available(s->avr)); if (s->next_pts == AV_NOPTS_VALUE) { if (in->pts == AV_NOPTS_VALUE) { av_log(ctx, AV_LOG_WARNING, "First timestamp is missing, " "assuming 0.\n"); s->next_pts = 0; } else s->next_pts = av_rescale_q(in->pts, inlink->time_base, outlink->time_base); } if (ret > 0) { out->nb_samples = ret; ret = av_frame_copy_props(out, in); if (ret < 0) { av_frame_free(&out); goto fail; } out->sample_rate = outlink->sample_rate; /* Only convert in->pts if there is a discontinuous jump. This ensures that out->pts tracks the number of samples actually output by the resampler in the absence of such a jump. Otherwise, the rounding in av_rescale_q() and av_rescale() causes off-by-1 errors. */ if (in->pts != AV_NOPTS_VALUE && in->pts != s->next_in_pts) { out->pts = av_rescale_q(in->pts, inlink->time_base, outlink->time_base) - av_rescale(delay, outlink->sample_rate, inlink->sample_rate); } else out->pts = s->next_pts; s->next_pts = out->pts + out->nb_samples; s->next_in_pts = in->pts + in->nb_samples; ret = ff_filter_frame(outlink, out); s->got_output = 1; } fail: av_frame_free(&in); } else { in->format = outlink->format; ret = ff_filter_frame(outlink, in); s->got_output = 1; } return ret; }
static void audio_process_audio(audio_decoder_t *ad, media_buf_t *mb) { const audio_class_t *ac = ad->ad_ac; AVFrame *frame = ad->ad_frame; media_pipe_t *mp = ad->ad_mp; media_queue_t *mq = &mp->mp_audio; int r; int got_frame; AVPacket avpkt; int offset = 0; if(mb->mb_skip || mb->mb_stream != mq->mq_stream) return; while(offset < mb->mb_size) { if(mb->mb_cw == NULL) { frame->sample_rate = mb->mb_rate; frame->format = AV_SAMPLE_FMT_S16; switch(mb->mb_channels) { case 1: frame->channel_layout = AV_CH_LAYOUT_MONO; frame->nb_samples = mb->mb_size / 2; break; case 2: frame->channel_layout = AV_CH_LAYOUT_STEREO; frame->nb_samples = mb->mb_size / 4; break; default: abort(); } frame->data[0] = mb->mb_data; frame->linesize[0] = 0; r = mb->mb_size; got_frame = 1; } else { av_init_packet(&avpkt); avpkt.data = mb->mb_data + offset; avpkt.size = mb->mb_size - offset; r = avcodec_decode_audio4(mb->mb_cw->codec_ctx, frame, &got_frame, &avpkt); if(r < 0) return; if(frame->sample_rate == 0) frame->sample_rate = mb->mb_cw->codec_ctx->sample_rate; if(frame->sample_rate == 0) return; if(mp->mp_stats) mp_set_mq_meta(mq, mb->mb_cw->codec, mb->mb_cw->codec_ctx); } if(offset == 0 && mb->mb_pts != AV_NOPTS_VALUE) { int od = 0, id = 0; if(ad->ad_avr != NULL) { od = avresample_available(ad->ad_avr) * 1000000LL / ad->ad_out_sample_rate; id = avresample_get_delay(ad->ad_avr) * 1000000LL / frame->sample_rate; } ad->ad_pts = mb->mb_pts - od - id; ad->ad_epoch = mb->mb_epoch; // printf("od=%-20d id=%-20d PTS=%-20ld oPTS=%-20ld\n", // od, id, mb->mb_pts, pts); if(mb->mb_drive_clock) mp_set_current_time(mp, mb->mb_pts - ad->ad_delay, mb->mb_epoch, mb->mb_delta); } offset += r; if(got_frame) { if(frame->sample_rate != ad->ad_in_sample_rate || frame->format != ad->ad_in_sample_format || frame->channel_layout != ad->ad_in_channel_layout) { ad->ad_in_sample_rate = frame->sample_rate; ad->ad_in_sample_format = frame->format; ad->ad_in_channel_layout = frame->channel_layout; ac->ac_reconfig(ad); if(ad->ad_avr == NULL) ad->ad_avr = avresample_alloc_context(); else avresample_close(ad->ad_avr); av_opt_set_int(ad->ad_avr, "in_sample_fmt", ad->ad_in_sample_format, 0); av_opt_set_int(ad->ad_avr, "in_sample_rate", ad->ad_in_sample_rate, 0); av_opt_set_int(ad->ad_avr, "in_channel_layout", ad->ad_in_channel_layout, 0); av_opt_set_int(ad->ad_avr, "out_sample_fmt", ad->ad_out_sample_format, 0); av_opt_set_int(ad->ad_avr, "out_sample_rate", ad->ad_out_sample_rate, 0); av_opt_set_int(ad->ad_avr, "out_channel_layout", ad->ad_out_channel_layout, 0); char buf1[128]; char buf2[128]; av_get_channel_layout_string(buf1, sizeof(buf1), -1, ad->ad_in_channel_layout); av_get_channel_layout_string(buf2, sizeof(buf2), -1, ad->ad_out_channel_layout); TRACE(TRACE_DEBUG, "Audio", "Converting from [%s %dHz %s] to [%s %dHz %s]", buf1, ad->ad_in_sample_rate, av_get_sample_fmt_name(ad->ad_in_sample_format), buf2, ad->ad_out_sample_rate, av_get_sample_fmt_name(ad->ad_out_sample_format)); if(avresample_open(ad->ad_avr)) { TRACE(TRACE_ERROR, "AudioQueue", "Unable to open resampler"); avresample_free(&ad->ad_avr); } } if(ad->ad_avr != NULL) avresample_convert(ad->ad_avr, NULL, 0, 0, frame->data, frame->linesize[0], frame->nb_samples); } } }
static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) { AVFilterContext *ctx = inlink->dst; ResampleContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; int ret; if (s->avr) { AVFilterBufferRef *buf_out; int delay, nb_samples; /* maximum possible samples lavr can output */ delay = avresample_get_delay(s->avr); nb_samples = av_rescale_rnd(buf->audio->nb_samples + delay, outlink->sample_rate, inlink->sample_rate, AV_ROUND_UP); buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples); if (!buf_out) { ret = AVERROR(ENOMEM); goto fail; } ret = avresample_convert(s->avr, (void**)buf_out->extended_data, buf_out->linesize[0], nb_samples, (void**)buf->extended_data, buf->linesize[0], buf->audio->nb_samples); if (ret < 0) { avfilter_unref_buffer(buf_out); goto fail; } av_assert0(!avresample_available(s->avr)); if (s->next_pts == AV_NOPTS_VALUE) { if (buf->pts == AV_NOPTS_VALUE) { av_log(ctx, AV_LOG_WARNING, "First timestamp is missing, " "assuming 0.\n"); s->next_pts = 0; } else s->next_pts = av_rescale_q(buf->pts, inlink->time_base, outlink->time_base); } if (ret > 0) { buf_out->audio->nb_samples = ret; if (buf->pts != AV_NOPTS_VALUE) { buf_out->pts = av_rescale_q(buf->pts, inlink->time_base, outlink->time_base) - av_rescale(delay, outlink->sample_rate, inlink->sample_rate); } else buf_out->pts = s->next_pts; s->next_pts = buf_out->pts + buf_out->audio->nb_samples; ret = ff_filter_samples(outlink, buf_out); s->got_output = 1; } fail: avfilter_unref_buffer(buf); } else { ret = ff_filter_samples(outlink, buf); s->got_output = 1; } return ret; }
static int filter_frame(AVFilterLink *inlink, AVFrame *buf) { AVFilterContext *ctx = inlink->dst; ASyncContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; int nb_channels = av_get_channel_layout_nb_channels(buf->channel_layout); int64_t pts = (buf->pts == AV_NOPTS_VALUE) ? buf->pts : av_rescale_q(buf->pts, inlink->time_base, outlink->time_base); int out_size, ret; int64_t delta; int64_t new_pts; /* buffer data until we get the next timestamp */ if (s->pts == AV_NOPTS_VALUE || pts == AV_NOPTS_VALUE) { if (pts != AV_NOPTS_VALUE) { s->pts = pts - get_delay(s); } return write_to_fifo(s, buf); } if (s->first_pts != AV_NOPTS_VALUE) { handle_trimming(ctx); if (!avresample_available(s->avr)) return write_to_fifo(s, buf); } /* when we have two timestamps, compute how many samples would we have * to add/remove to get proper sync between data and timestamps */ delta = pts - s->pts - get_delay(s); out_size = avresample_available(s->avr); if (llabs(delta) > s->min_delta || (s->first_frame && delta && s->first_pts != AV_NOPTS_VALUE)) { av_log(ctx, AV_LOG_VERBOSE, "Discontinuity - %"PRId64" samples.\n", delta); out_size = av_clipl_int32((int64_t)out_size + delta); } else { if (s->resample) { // adjust the compensation if delta is non-zero int delay = get_delay(s); int comp = s->comp + av_clip(delta * inlink->sample_rate / delay, -s->max_comp, s->max_comp); if (comp != s->comp) { av_log(ctx, AV_LOG_VERBOSE, "Compensating %d samples per second.\n", comp); if (avresample_set_compensation(s->avr, comp, inlink->sample_rate) == 0) { s->comp = comp; } } } // adjust PTS to avoid monotonicity errors with input PTS jitter pts -= delta; delta = 0; } if (out_size > 0) { AVFrame *buf_out = ff_get_audio_buffer(outlink, out_size); if (!buf_out) { ret = AVERROR(ENOMEM); goto fail; } if (s->first_frame && delta > 0) { int planar = av_sample_fmt_is_planar(buf_out->format); int planes = planar ? nb_channels : 1; int block_size = av_get_bytes_per_sample(buf_out->format) * (planar ? 1 : nb_channels); int ch; av_samples_set_silence(buf_out->extended_data, 0, delta, nb_channels, buf->format); for (ch = 0; ch < planes; ch++) buf_out->extended_data[ch] += delta * block_size; avresample_read(s->avr, buf_out->extended_data, out_size); for (ch = 0; ch < planes; ch++) buf_out->extended_data[ch] -= delta * block_size; } else { avresample_read(s->avr, buf_out->extended_data, out_size); if (delta > 0) { av_samples_set_silence(buf_out->extended_data, out_size - delta, delta, nb_channels, buf->format); } } buf_out->pts = s->pts; ret = ff_filter_frame(outlink, buf_out); if (ret < 0) goto fail; s->got_output = 1; } else if (avresample_available(s->avr)) { av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping " "whole buffer.\n"); } /* drain any remaining buffered data */ avresample_read(s->avr, NULL, avresample_available(s->avr)); new_pts = pts - avresample_get_delay(s->avr); /* check for s->pts monotonicity */ if (new_pts > s->pts) { s->pts = new_pts; ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data, buf->linesize[0], buf->nb_samples); } else { av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping " "whole buffer.\n"); ret = 0; } s->first_frame = 0; fail: av_frame_free(&buf); return ret; }
/* get amount of data currently buffered, in samples */ static int64_t get_delay(ASyncContext *s) { return avresample_available(s->avr) + avresample_get_delay(s->avr); }
static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; ResampleContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; int ret; if (s->avr) { AVFrame *out; int delay, nb_samples; /* maximum possible samples lavr can output */ delay = avresample_get_delay(s->avr); nb_samples = av_rescale_rnd(in->nb_samples + delay, outlink->sample_rate, inlink->sample_rate, AV_ROUND_UP); out = ff_get_audio_buffer(outlink, nb_samples); if (!out) { ret = AVERROR(ENOMEM); goto fail; } ret = avresample_convert(s->avr, out->extended_data, out->linesize[0], nb_samples, in->extended_data, in->linesize[0], in->nb_samples); if (ret <= 0) { av_frame_free(&out); if (ret < 0) goto fail; } av_assert0(!avresample_available(s->avr)); if (s->next_pts == AV_NOPTS_VALUE) { if (in->pts == AV_NOPTS_VALUE) { av_log(ctx, AV_LOG_WARNING, "First timestamp is missing, " "assuming 0.\n"); s->next_pts = 0; } else s->next_pts = av_rescale_q(in->pts, inlink->time_base, outlink->time_base); } if (ret > 0) { out->nb_samples = ret; if (in->pts != AV_NOPTS_VALUE) { out->pts = av_rescale_q(in->pts, inlink->time_base, outlink->time_base) - av_rescale(delay, outlink->sample_rate, inlink->sample_rate); } else out->pts = s->next_pts; s->next_pts = out->pts + out->nb_samples; ret = ff_filter_frame(outlink, out); s->got_output = 1; } fail: av_frame_free(&in); } else { in->format = outlink->format; ret = ff_filter_frame(outlink, in); s->got_output = 1; } return ret; }
static void audio_process_audio(audio_decoder_t *ad, media_buf_t *mb) { const audio_class_t *ac = ad->ad_ac; AVFrame *frame = ad->ad_frame; media_pipe_t *mp = ad->ad_mp; media_queue_t *mq = &mp->mp_audio; int r; int got_frame; AVPacket avpkt; int offset = 0; if(mb->mb_skip || mb->mb_stream != mq->mq_stream) return; while(offset < mb->mb_size) { if(mb->mb_cw == NULL) { frame->sample_rate = mb->mb_rate; frame->format = AV_SAMPLE_FMT_S16; switch(mb->mb_channels) { case 1: frame->channel_layout = AV_CH_LAYOUT_MONO; frame->nb_samples = mb->mb_size / 2; break; case 2: frame->channel_layout = AV_CH_LAYOUT_STEREO; frame->nb_samples = mb->mb_size / 4; break; default: abort(); } frame->data[0] = mb->mb_data; frame->linesize[0] = 0; r = mb->mb_size; got_frame = 1; } else { media_codec_t *mc = mb->mb_cw; AVCodecContext *ctx = mc->ctx; if(mc->codec_id != ad->ad_in_codec_id) { AVCodec *codec = avcodec_find_decoder(mc->codec_id); TRACE(TRACE_DEBUG, "audio", "Codec changed to %s", codec ? codec->name : "???"); ad->ad_in_codec_id = mc->codec_id; audio_cleanup_spdif_muxer(ad); if(ac->ac_check_passthru != NULL && codec != NULL && ac->ac_check_passthru(ad, mc->codec_id)) { audio_setup_spdif_muxer(ad, codec, mq); } } av_init_packet(&avpkt); avpkt.data = mb->mb_data + offset; avpkt.size = mb->mb_size - offset; if(ad->ad_spdif_muxer != NULL) { av_write_frame(ad->ad_spdif_muxer, &avpkt); avio_flush(ad->ad_spdif_muxer->pb); ad->ad_pts = mb->mb_pts; ad->ad_epoch = mb->mb_epoch; return; } if(ctx == NULL) { AVCodec *codec = avcodec_find_decoder(mc->codec_id); assert(codec != NULL); // Checked in libav.c ctx = mc->ctx = avcodec_alloc_context3(codec); if(ad->ad_stereo_downmix) ctx->request_channels = 2; if(avcodec_open2(mc->ctx, codec, NULL) < 0) { av_freep(&mc->ctx); return; } } r = avcodec_decode_audio4(ctx, frame, &got_frame, &avpkt); if(r < 0) return; if(frame->sample_rate == 0) { frame->sample_rate = ctx->sample_rate; if(frame->sample_rate == 0 && mb->mb_cw->fmt_ctx) frame->sample_rate = mb->mb_cw->fmt_ctx->sample_rate; if(frame->sample_rate == 0) return; } if(frame->channel_layout == 0) { switch(ctx->channels) { case 1: frame->channel_layout = AV_CH_LAYOUT_MONO; break; case 2: frame->channel_layout = AV_CH_LAYOUT_STEREO; break; default: return; } } if(mp->mp_stats) mp_set_mq_meta(mq, ctx->codec, ctx); } if(offset == 0 && mb->mb_pts != AV_NOPTS_VALUE) { int od = 0, id = 0; if(ad->ad_avr != NULL) { od = avresample_available(ad->ad_avr) * 1000000LL / ad->ad_out_sample_rate; id = avresample_get_delay(ad->ad_avr) * 1000000LL / frame->sample_rate; } ad->ad_pts = mb->mb_pts - od - id; ad->ad_epoch = mb->mb_epoch; // printf("od=%-20d id=%-20d PTS=%-20ld oPTS=%-20ld\n", // od, id, mb->mb_pts, pts); if(mb->mb_drive_clock) mp_set_current_time(mp, mb->mb_pts - ad->ad_delay, mb->mb_epoch, mb->mb_delta); } offset += r; if(got_frame) { if(frame->sample_rate != ad->ad_in_sample_rate || frame->format != ad->ad_in_sample_format || frame->channel_layout != ad->ad_in_channel_layout) { ad->ad_in_sample_rate = frame->sample_rate; ad->ad_in_sample_format = frame->format; ad->ad_in_channel_layout = frame->channel_layout; ac->ac_reconfig(ad); if(ad->ad_avr == NULL) ad->ad_avr = avresample_alloc_context(); else avresample_close(ad->ad_avr); av_opt_set_int(ad->ad_avr, "in_sample_fmt", ad->ad_in_sample_format, 0); av_opt_set_int(ad->ad_avr, "in_sample_rate", ad->ad_in_sample_rate, 0); av_opt_set_int(ad->ad_avr, "in_channel_layout", ad->ad_in_channel_layout, 0); av_opt_set_int(ad->ad_avr, "out_sample_fmt", ad->ad_out_sample_format, 0); av_opt_set_int(ad->ad_avr, "out_sample_rate", ad->ad_out_sample_rate, 0); av_opt_set_int(ad->ad_avr, "out_channel_layout", ad->ad_out_channel_layout, 0); char buf1[128]; char buf2[128]; av_get_channel_layout_string(buf1, sizeof(buf1), -1, ad->ad_in_channel_layout); av_get_channel_layout_string(buf2, sizeof(buf2), -1, ad->ad_out_channel_layout); TRACE(TRACE_DEBUG, "Audio", "Converting from [%s %dHz %s] to [%s %dHz %s]", buf1, ad->ad_in_sample_rate, av_get_sample_fmt_name(ad->ad_in_sample_format), buf2, ad->ad_out_sample_rate, av_get_sample_fmt_name(ad->ad_out_sample_format)); if(avresample_open(ad->ad_avr)) { TRACE(TRACE_ERROR, "AudioQueue", "Unable to open resampler"); avresample_free(&ad->ad_avr); } if(ac->ac_set_volume != NULL) { prop_set(mp->mp_prop_ctrl, "canAdjustVolume", PROP_SET_INT, 1); ac->ac_set_volume(ad, ad->ad_vol_scale); } } if(ad->ad_avr != NULL) avresample_convert(ad->ad_avr, NULL, 0, 0, frame->data, frame->linesize[0], frame->nb_samples); } } }