use cloned frames to avoid race conditions

fixes #350
pull/353/merge
Richard Fuchs 9 years ago
parent 5acf56dec4
commit 0e60000001

@ -26,7 +26,6 @@ struct decoder_s {
AVCodecContext *avcctx; AVCodecContext *avcctx;
AVPacket avpkt; AVPacket avpkt;
AVFrame *frame;
unsigned long rtp_ts; unsigned long rtp_ts;
uint64_t pts; 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)); dbg("supported sample format for input codec %s: %s", codec->name, av_get_sample_fmt_name(*sfmt));
av_init_packet(&ret->avpkt); 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->pts = (uint64_t) -1LL;
ret->rtp_ts = (unsigned long) -1L; 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 // determine and save sample type
if (G_UNLIKELY(dec->in_format.format == -1)) 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 // handle mix output
pthread_mutex_lock(&metafile->mix_lock); 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)) if (output_config(metafile->mix_out, &dec->out_format, &actual_format))
goto no_mix_out; goto no_mix_out;
mix_config(metafile->mix, &actual_format); 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) { if (!dec_frame) {
pthread_mutex_unlock(&metafile->mix_lock); pthread_mutex_unlock(&metafile->mix_lock);
return -1; goto err;
} }
AVFrame *clone = av_frame_clone(dec_frame); if (mix_add(metafile->mix, dec_frame, dec->mixer_idx, metafile->mix_out))
if (mix_add(metafile->mix, clone, dec->mixer_idx, metafile->mix_out))
ilog(LOG_ERR, "Failed to add decoded packet to mixed output"); ilog(LOG_ERR, "Failed to add decoded packet to mixed output");
} }
no_mix_out: no_mix_out:
@ -208,15 +202,21 @@ no_mix_out:
// XXX might be a second resampling to same format // XXX might be a second resampling to same format
format_t actual_format; format_t actual_format;
if (output_config(output, &dec->out_format, &actual_format)) if (output_config(output, &dec->out_format, &actual_format))
return -1; goto err;
AVFrame *dec_frame = resample_frame(&dec->output_resample, dec->frame, &actual_format); AVFrame *dec_frame = resample_frame(&dec->output_resample, frame, &actual_format);
if (!dec_frame) if (!dec_frame)
return -1; goto err;
if (output_add(output, dec_frame)) if (output_add(output, dec_frame))
ilog(LOG_ERR, "Failed to add decoded packet to individual output"); ilog(LOG_ERR, "Failed to add decoded packet to individual output");
av_frame_free(&dec_frame);
} }
av_frame_free(&frame);
return 0; 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.size = data->len;
dec->avpkt.pts = dec->pts; dec->avpkt.pts = dec->pts;
AVFrame *frame = NULL;
// loop until all input is consumed and all available output has been processed // loop until all input is consumed and all available output has been processed
int keep_going; int keep_going;
do { do {
keep_going = 0; keep_going = 0;
int got_frame = 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 LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 36, 0)
if (dec->avpkt.size) { 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); dbg("receive frame ret %i", ret);
err = "failed to receive frame from avcodec"; err = "failed to receive frame from avcodec";
if (ret == 0) { 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) if (dec->avpkt.size == 0)
break; 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); dbg("decode frame ret %i, got frame %i", ret, got_frame);
err = "failed to decode audio packet"; err = "failed to decode audio packet";
if (ret < 0) 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 (got_frame) {
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 36, 0) #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 36, 0)
dec->frame->pts = dec->frame->pkt_pts; frame->pts = frame->pkt_pts;
#endif #endif
if (G_UNLIKELY(dec->frame->pts == AV_NOPTS_VALUE)) if (G_UNLIKELY(frame->pts == AV_NOPTS_VALUE))
dec->frame->pts = dec->avpkt.pts; frame->pts = dec->avpkt.pts;
if (decoder_got_frame(dec, output, metafile)) if (decoder_got_frame(dec, output, metafile, frame))
return -1; return -1;
frame = NULL;
} }
} while (keep_going); } while (keep_going);
av_frame_free(&frame);
return 0; return 0;
err: err:
ilog(LOG_ERR, "Error decoding media packet: %s", err); ilog(LOG_ERR, "Error decoding media packet: %s", err);
av_frame_free(&frame);
return -1; return -1;
} }
@ -334,7 +343,6 @@ void decoder_close(decoder_t *dec) {
avcodec_close(dec->avcctx); avcodec_close(dec->avcctx);
av_free(dec->avcctx); av_free(dec->avcctx);
#endif #endif
av_frame_free(&dec->frame);
resample_shutdown(&dec->mix_resample); resample_shutdown(&dec->mix_resample);
resample_shutdown(&dec->output_resample); resample_shutdown(&dec->output_resample);
g_slice_free1(sizeof(*dec), dec); g_slice_free1(sizeof(*dec), dec);

@ -276,6 +276,7 @@ int mix_add(mix_t *mix, AVFrame *frame, unsigned int idx, output_t *output) {
ret = output_add(output, frame); ret = output_add(output, frame);
av_frame_unref(mix->sink_frame); av_frame_unref(mix->sink_frame);
av_frame_free(&frame);
if (ret) if (ret)
return -1; return -1;

@ -27,7 +27,7 @@ AVFrame *resample_frame(resample_t *resample, AVFrame *frame, const format_t *to
if (frame->channel_layout != to_channel_layout) if (frame->channel_layout != to_channel_layout)
goto resample; goto resample;
return frame; return av_frame_clone(frame);
resample: resample:
@ -74,37 +74,33 @@ resample:
int dst_samples = avresample_available(resample->avresample) + int dst_samples = avresample_available(resample->avresample) +
av_rescale_rnd(avresample_get_delay(resample->avresample) + frame->nb_samples, av_rescale_rnd(avresample_get_delay(resample->avresample) + frame->nb_samples,
to_format->clockrate, frame->sample_rate, AV_ROUND_UP); 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; AVFrame *swr_frame = av_frame_alloc();
int ret_samples = avresample_convert(resample->avresample, resample->swr_frame->extended_data,
resample->swr_frame->linesize[0], dst_samples, 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->extended_data,
frame->linesize[0], frame->nb_samples); frame->linesize[0], frame->nb_samples);
err = "failed to resample audio"; err = "failed to resample audio";
if ((errcode = ret_samples) < 0) if ((errcode = ret_samples) < 0)
goto err; goto err;
resample->swr_frame->nb_samples = ret_samples; swr_frame->nb_samples = ret_samples;
resample->swr_frame->pts = av_rescale(frame->pts, to_format->clockrate, frame->sample_rate); swr_frame->pts = av_rescale(frame->pts, to_format->clockrate, frame->sample_rate);
return resample->swr_frame; return swr_frame;
err: err:
ilog(LOG_ERR, "Error resampling: %s (code %i)", err, errcode); ilog(LOG_ERR, "Error resampling: %s (code %i)", err, errcode);
@ -114,6 +110,5 @@ err:
void resample_shutdown(resample_t *resample) { void resample_shutdown(resample_t *resample) {
av_frame_free(&resample->swr_frame);
avresample_free(&resample->avresample); avresample_free(&resample->avresample);
} }

@ -108,8 +108,6 @@ struct metafile_s {
struct resample_s { struct resample_s {
AVAudioResampleContext *avresample; AVAudioResampleContext *avresample;
AVFrame *swr_frame;
int swr_buffers;
}; };

Loading…
Cancel
Save