diff --git a/recording-daemon/decoder.c b/recording-daemon/decoder.c index 044033f4f..8292465b7 100644 --- a/recording-daemon/decoder.c +++ b/recording-daemon/decoder.c @@ -26,7 +26,6 @@ struct decoder_s { AVCodecContext *avcctx; AVPacket avpkt; - AVFrame *frame; unsigned long rtp_ts; uint64_t pts; @@ -159,10 +158,6 @@ decoder_t *decoder_new(const char *payload_str) { dbg("supported sample format for input codec %s: %s", codec->name, av_get_sample_fmt_name(*sfmt)); av_init_packet(&ret->avpkt); - ret->frame = av_frame_alloc(); - err = "failed to alloc av frame"; - if (!ret->frame) - goto err; ret->pts = (uint64_t) -1LL; ret->rtp_ts = (unsigned long) -1L; @@ -178,10 +173,10 @@ err: } -static int decoder_got_frame(decoder_t *dec, output_t *output, metafile_t *metafile) { +static int decoder_got_frame(decoder_t *dec, output_t *output, metafile_t *metafile, AVFrame *frame) { // determine and save sample type if (G_UNLIKELY(dec->in_format.format == -1)) - dec->in_format.format = dec->out_format.format = dec->frame->format; + dec->in_format.format = dec->out_format.format = frame->format; // handle mix output pthread_mutex_lock(&metafile->mix_lock); @@ -192,13 +187,12 @@ static int decoder_got_frame(decoder_t *dec, output_t *output, metafile_t *metaf if (output_config(metafile->mix_out, &dec->out_format, &actual_format)) goto no_mix_out; mix_config(metafile->mix, &actual_format); - AVFrame *dec_frame = resample_frame(&dec->mix_resample, dec->frame, &actual_format); + AVFrame *dec_frame = resample_frame(&dec->mix_resample, frame, &actual_format); if (!dec_frame) { pthread_mutex_unlock(&metafile->mix_lock); - return -1; + goto err; } - AVFrame *clone = av_frame_clone(dec_frame); - if (mix_add(metafile->mix, clone, dec->mixer_idx, metafile->mix_out)) + if (mix_add(metafile->mix, dec_frame, dec->mixer_idx, metafile->mix_out)) ilog(LOG_ERR, "Failed to add decoded packet to mixed output"); } no_mix_out: @@ -208,15 +202,21 @@ no_mix_out: // XXX might be a second resampling to same format format_t actual_format; if (output_config(output, &dec->out_format, &actual_format)) - return -1; - AVFrame *dec_frame = resample_frame(&dec->output_resample, dec->frame, &actual_format); + goto err; + AVFrame *dec_frame = resample_frame(&dec->output_resample, frame, &actual_format); if (!dec_frame) - return -1; + goto err; if (output_add(output, dec_frame)) ilog(LOG_ERR, "Failed to add decoded packet to individual output"); + av_frame_free(&dec_frame); } + av_frame_free(&frame); return 0; + +err: + av_frame_free(&frame); + return -1; } @@ -244,11 +244,17 @@ int decoder_input(decoder_t *dec, const str *data, unsigned long ts, output_t *o dec->avpkt.size = data->len; dec->avpkt.pts = dec->pts; + AVFrame *frame = NULL; + // loop until all input is consumed and all available output has been processed int keep_going; do { keep_going = 0; int got_frame = 0; + err = "failed to alloc av frame"; + frame = av_frame_alloc(); + if (!frame) + goto err; #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 36, 0) if (dec->avpkt.size) { @@ -268,7 +274,7 @@ int decoder_input(decoder_t *dec, const str *data, unsigned long ts, output_t *o } } - int ret = avcodec_receive_frame(dec->avcctx, dec->frame); + int ret = avcodec_receive_frame(dec->avcctx, frame); dbg("receive frame ret %i", ret); err = "failed to receive frame from avcodec"; if (ret == 0) { @@ -287,7 +293,7 @@ int decoder_input(decoder_t *dec, const str *data, unsigned long ts, output_t *o if (dec->avpkt.size == 0) break; - int ret = avcodec_decode_audio4(dec->avcctx, dec->frame, &got_frame, &dec->avpkt); + int ret = avcodec_decode_audio4(dec->avcctx, frame, &got_frame, &dec->avpkt); dbg("decode frame ret %i, got frame %i", ret, got_frame); err = "failed to decode audio packet"; if (ret < 0) @@ -307,19 +313,22 @@ int decoder_input(decoder_t *dec, const str *data, unsigned long ts, output_t *o if (got_frame) { #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 36, 0) - dec->frame->pts = dec->frame->pkt_pts; + frame->pts = frame->pkt_pts; #endif - if (G_UNLIKELY(dec->frame->pts == AV_NOPTS_VALUE)) - dec->frame->pts = dec->avpkt.pts; - if (decoder_got_frame(dec, output, metafile)) + if (G_UNLIKELY(frame->pts == AV_NOPTS_VALUE)) + frame->pts = dec->avpkt.pts; + if (decoder_got_frame(dec, output, metafile, frame)) return -1; + frame = NULL; } } while (keep_going); + av_frame_free(&frame); return 0; err: ilog(LOG_ERR, "Error decoding media packet: %s", err); + av_frame_free(&frame); return -1; } @@ -334,7 +343,6 @@ void decoder_close(decoder_t *dec) { avcodec_close(dec->avcctx); av_free(dec->avcctx); #endif - av_frame_free(&dec->frame); resample_shutdown(&dec->mix_resample); resample_shutdown(&dec->output_resample); g_slice_free1(sizeof(*dec), dec); diff --git a/recording-daemon/mix.c b/recording-daemon/mix.c index abb467a55..a751b6740 100644 --- a/recording-daemon/mix.c +++ b/recording-daemon/mix.c @@ -276,6 +276,7 @@ int mix_add(mix_t *mix, AVFrame *frame, unsigned int idx, output_t *output) { ret = output_add(output, frame); av_frame_unref(mix->sink_frame); + av_frame_free(&frame); if (ret) return -1; diff --git a/recording-daemon/resample.c b/recording-daemon/resample.c index 6c00f67a7..df9228cb4 100644 --- a/recording-daemon/resample.c +++ b/recording-daemon/resample.c @@ -27,7 +27,7 @@ AVFrame *resample_frame(resample_t *resample, AVFrame *frame, const format_t *to if (frame->channel_layout != to_channel_layout) goto resample; - return frame; + return av_frame_clone(frame); resample: @@ -74,37 +74,33 @@ resample: int dst_samples = avresample_available(resample->avresample) + av_rescale_rnd(avresample_get_delay(resample->avresample) + frame->nb_samples, to_format->clockrate, frame->sample_rate, AV_ROUND_UP); - if (G_UNLIKELY(!resample->swr_frame || resample->swr_buffers < dst_samples)) { - av_frame_free(&resample->swr_frame); - dbg("allocating resampling frame for %i/%i/%i", to_format->format, (int) to_channel_layout, - to_format->clockrate); - resample->swr_frame = av_frame_alloc(); - err = "failed to alloc resampling frame"; - if (!resample->swr_frame) - goto err; - av_frame_copy_props(resample->swr_frame, frame); - resample->swr_frame->format = to_format->format; - resample->swr_frame->channel_layout = to_channel_layout; - resample->swr_frame->nb_samples = dst_samples; - resample->swr_frame->sample_rate = to_format->clockrate; - err = "failed to get resample buffers"; - if ((errcode = av_frame_get_buffer(resample->swr_frame, 0)) < 0) - goto err; - resample->swr_buffers = dst_samples; - } - resample->swr_frame->nb_samples = dst_samples; - int ret_samples = avresample_convert(resample->avresample, resample->swr_frame->extended_data, - resample->swr_frame->linesize[0], dst_samples, + AVFrame *swr_frame = av_frame_alloc(); + + err = "failed to alloc resampling frame"; + if (!swr_frame) + goto err; + av_frame_copy_props(swr_frame, frame); + swr_frame->format = to_format->format; + swr_frame->channel_layout = to_channel_layout; + swr_frame->nb_samples = dst_samples; + swr_frame->sample_rate = to_format->clockrate; + err = "failed to get resample buffers"; + if ((errcode = av_frame_get_buffer(swr_frame, 0)) < 0) + goto err; + + swr_frame->nb_samples = dst_samples; + int ret_samples = avresample_convert(resample->avresample, swr_frame->extended_data, + swr_frame->linesize[0], dst_samples, frame->extended_data, frame->linesize[0], frame->nb_samples); err = "failed to resample audio"; if ((errcode = ret_samples) < 0) goto err; - resample->swr_frame->nb_samples = ret_samples; - resample->swr_frame->pts = av_rescale(frame->pts, to_format->clockrate, frame->sample_rate); - return resample->swr_frame; + swr_frame->nb_samples = ret_samples; + swr_frame->pts = av_rescale(frame->pts, to_format->clockrate, frame->sample_rate); + return swr_frame; err: ilog(LOG_ERR, "Error resampling: %s (code %i)", err, errcode); @@ -114,6 +110,5 @@ err: void resample_shutdown(resample_t *resample) { - av_frame_free(&resample->swr_frame); avresample_free(&resample->avresample); } diff --git a/recording-daemon/types.h b/recording-daemon/types.h index e387ce42b..546054876 100644 --- a/recording-daemon/types.h +++ b/recording-daemon/types.h @@ -108,8 +108,6 @@ struct metafile_s { struct resample_s { AVAudioResampleContext *avresample; - AVFrame *swr_frame; - int swr_buffers; };