Browse Source

TT#5566 loop over encoding and decoding as required by the specs

Change-Id: I575b0653e00e2bae15cb9bfda564ff7a9a2b7ffe
changes/97/9997/1
Richard Fuchs 9 years ago
parent
commit
040d1bec10
2 changed files with 200 additions and 105 deletions
  1. +137
    -78
      recording-daemon/decoder.c
  2. +63
    -27
      recording-daemon/output.c

+ 137
- 78
recording-daemon/decoder.c View File

@ -166,6 +166,84 @@ err:
}
static AVFrame *decoder_resample_frame(decoder_t *dec) {
const char *err;
if (dec->in_clockrate == dec->out_clockrate)
return dec->frame;
if (!dec->avresample) {
dec->avresample = avresample_alloc_context();
err = "failed to alloc resample context";
if (!dec->avresample)
goto err;
av_opt_set_int(dec->avresample, "in_channel_layout", av_get_default_channel_layout(dec->channels), 0);
av_opt_set_int(dec->avresample, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_int(dec->avresample, "in_sample_rate", dec->in_clockrate, 0);
av_opt_set_int(dec->avresample, "out_channel_layout", av_get_default_channel_layout(dec->channels), 0);
av_opt_set_int(dec->avresample, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_int(dec->avresample, "out_sample_rate", dec->out_clockrate, 0);
// av_opt_set_int(dec->avresample, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); // ?
err = "failed to init resample context";
if (avresample_open(dec->avresample) < 0)
goto err;
}
// get a large enough buffer for resampled audio - this should be enough so we don't
// have to loop
int dst_samples = avresample_available(dec->avresample) +
av_rescale_rnd(avresample_get_delay(dec->avresample) + dec->frame->nb_samples,
dec->out_clockrate, dec->in_clockrate, AV_ROUND_UP);
if (!dec->swr_frame || dec->swr_buffers < dst_samples) {
av_frame_free(&dec->swr_frame);
dec->swr_frame = av_frame_alloc();
err = "failed to alloc resampling frame";
if (!dec->swr_frame)
goto err;
av_frame_copy_props(dec->swr_frame, dec->frame);
dec->swr_frame->format = dec->frame->format;
dec->swr_frame->channel_layout = dec->frame->channel_layout;
dec->swr_frame->nb_samples = dst_samples;
dec->swr_frame->sample_rate = dec->out_clockrate;
err = "failed to get resample buffers";
if (av_frame_get_buffer(dec->swr_frame, 0) < 0)
goto err;
dec->swr_buffers = dst_samples;
}
dec->swr_frame->nb_samples = dst_samples;
int ret_samples = avresample_convert(dec->avresample, dec->swr_frame->extended_data,
dec->swr_frame->linesize[0], dst_samples,
dec->frame->extended_data,
dec->frame->linesize[0], dec->frame->nb_samples);
err = "failed to resample audio";
if (ret_samples < 0)
goto err;
dec->swr_frame->nb_samples = ret_samples;
dec->swr_frame->pts = av_rescale(dec->frame->pts, dec->out_clockrate, dec->in_clockrate);
return dec->swr_frame;
err:
ilog(LOG_ERR, "Error resampling: %s", err);
return NULL;
}
static int decoder_got_frame(decoder_t *dec, output_t *output) {
// do we need to resample?
AVFrame *dec_frame = decoder_resample_frame(dec);
output_config(output, dec->out_clockrate, dec->channels);
if (output_add(output, dec_frame))
return -1;
return 0;
}
int decoder_input(decoder_t *dec, const str *data, unsigned long ts, output_t *output) {
const char *err;
@ -190,91 +268,72 @@ 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;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 0, 0)
int ret = avcodec_send_packet(dec->avcctx, &dec->avpkt);
dbg("send packet ret %i", ret);
err = "failed to send packet to avcodec";
if (ret)
goto err;
// loop until all input is consumed and all available output has been processed
int keep_going;
do {
keep_going = 0;
int got_frame = 0;
ret = avcodec_receive_frame(dec->avcctx, dec->frame);
dbg("receive frame ret %i", ret);
err = "failed to receive frame from avcodec";
if (ret)
goto err;
#else
int got_frame = 0;
int ret = avcodec_decode_audio4(dec->avcctx, dec->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)
goto err;
if (!got_frame)
return 0;
#endif
dbg("%p dec frame pts %lu pkt_pts %lu", dec, (unsigned long) dec->frame->pts,
(unsigned long) dec->frame->pkt_dts);
// do we need to resample?
AVFrame *dec_frame = dec->frame;
if (dec->in_clockrate != dec->out_clockrate) {
if (!dec->avresample) {
dec->avresample = avresample_alloc_context();
err = "failed to alloc resample context";
if (!dec->avresample)
goto err;
av_opt_set_int(dec->avresample, "in_channel_layout", av_get_default_channel_layout(dec->channels), 0);
av_opt_set_int(dec->avresample, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_int(dec->avresample, "in_sample_rate", dec->in_clockrate, 0);
av_opt_set_int(dec->avresample, "out_channel_layout", av_get_default_channel_layout(dec->channels), 0);
av_opt_set_int(dec->avresample, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_int(dec->avresample, "out_sample_rate", dec->out_clockrate, 0);
// av_opt_set_int(dec->avresample, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); // ?
err = "failed to init resample context";
if (avresample_open(dec->avresample) < 0)
goto err;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 0, 0)
if (dec->avpkt.size) {
int ret = avcodec_send_packet(dec->avcctx, &dec->avpkt);
dbg("send packet ret %i", ret);
err = "failed to send packet to avcodec";
if (ret == 0) {
// consumed the packet
dec->avpkt.size = 0;
keep_going = 1;
}
else {
if (ret == AVERROR(EAGAIN))
; // try again after reading output
else
goto err;
}
}
// get a large enough buffer for resampled audio
int dst_samples = av_rescale_rnd(dec->frame->nb_samples, dec->out_clockrate,
dec->in_clockrate, AV_ROUND_UP);
if (!dec->swr_frame || dec->swr_buffers < dst_samples) {
av_frame_free(&dec->swr_frame);
dec->swr_frame = av_frame_alloc();
err = "failed to alloc resampling frame";
if (!dec->swr_frame)
goto err;
av_frame_copy_props(dec->swr_frame, dec->frame);
dec->swr_frame->format = dec->frame->format;
dec->swr_frame->channel_layout = dec->frame->channel_layout;
dec->swr_frame->nb_samples = dst_samples;
dec->swr_frame->sample_rate = dec->out_clockrate;
err = "failed to get resample buffers";
if (av_frame_get_buffer(dec->swr_frame, 0) < 0)
int ret = avcodec_receive_frame(dec->avcctx, dec->frame);
dbg("receive frame ret %i", ret);
err = "failed to receive frame from avcodec";
if (ret == 0) {
// got a frame
keep_going = 1;
got_frame = 1;
}
else {
if (ret == AVERROR(EAGAIN))
; // maybe needs more input now
else
goto err;
dec->swr_buffers = dst_samples;
}
dec->swr_frame->nb_samples = dst_samples;
int ret_samples = avresample_convert(dec->avresample, dec->swr_frame->extended_data,
dec->swr_frame->linesize[0], dst_samples,
dec->frame->extended_data,
dec->frame->linesize[0], dec->frame->nb_samples);
err = "failed to resample audio";
if (ret_samples < 0)
#else
// only do this if we have any input left
if (dec->avpkt.size == 0)
break;
int ret = avcodec_decode_audio4(dec->avcctx, dec->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)
goto err;
if (ret > 0) {
// consumed some input
err = "invalid return value";
if (ret > dec->avpkt.size)
goto err;
dec->avpkt.size -= ret;
dec->avpkt.data += ret;
keep_going = 1;
}
if (got_frame)
keep_going = 1;
#endif
dec_frame = dec->swr_frame;
dec_frame->nb_samples = ret_samples;
dec_frame->pts = av_rescale(dec->frame->pts, dec->out_clockrate, dec->in_clockrate);
}
output_config(output, dec->out_clockrate, dec->channels);
if (output_add(output, dec_frame))
return -1;
if (got_frame) {
if (decoder_got_frame(dec, output))
return -1;
}
} while (keep_going);
return 0;


+ 63
- 27
recording-daemon/output.c View File

@ -50,40 +50,76 @@ static int output_flush(output_t *output) {
dbg("%p output fifo pts %lu", output, (unsigned long) output->fifo_pts);
output->frame->pts = output->fifo_pts;
int keep_going;
int have_frame = 1;
do {
keep_going = 0;
int got_packet = 0;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 0, 0)
int ret = avcodec_send_frame(output->avcctx, output->frame);
dbg("%p send frame ret %i", output, ret);
if (ret)
return -1;
ret = avcodec_receive_packet(output->avcctx, &output->avpkt);
dbg("%p receive packet ret %i", output, ret);
if (ret)
return -1;
if (have_frame) {
int ret = avcodec_send_frame(output->avcctx, output->frame);
dbg("%p send frame ret %i", output, ret);
if (ret == 0) {
// consumed
have_frame = 0;
keep_going = 1;
}
else {
if (ret == AVERROR(EAGAIN))
; // check output and maybe try again
else
return -1;
}
}
int ret = avcodec_receive_packet(output->avcctx, &output->avpkt);
dbg("%p receive packet ret %i", output, ret);
if (ret == 0) {
// got some data
keep_going = 1;
got_packet = 1;
}
else {
if (ret == AVERROR(EAGAIN))
; // try again if there's still more input
else
return -1;
}
#else
int got_packet = 0;
int ret = avcodec_encode_audio2(output->avcctx, &output->avpkt, output->frame, &got_packet);
dbg("%p encode frame ret %i, got packet %i", output, ret, got_packet);
if (!got_packet)
return 0;
if (!have_frame)
break;
int ret = avcodec_encode_audio2(output->avcctx, &output->avpkt, output->frame, &got_packet);
dbg("%p encode frame ret %i, got packet %i", output, ret, got_packet);
if (ret == 0)
have_frame = 0; // consumed
else
return -1; // error
if (got_packet)
keep_going = 1;
#endif
dbg("%p output avpkt size is %i", output, (int) output->avpkt.size);
dbg("%p output pkt pts/dts is %li/%li", output, (long) output->avpkt.pts,
(long) output->avpkt.dts);
dbg("%p output dts %li", output, (long) output->mux_dts);
if (!got_packet)
continue;
dbg("%p output avpkt size is %i", output, (int) output->avpkt.size);
dbg("%p output pkt pts/dts is %li/%li", output, (long) output->avpkt.pts,
(long) output->avpkt.dts);
dbg("%p output dts %li", output, (long) output->mux_dts);
// the encoder may return frames with the same dts multiple consecutive times.
// the muxer may not like this, so ensure monotonically increasing dts.
if (output->mux_dts > output->avpkt.dts)
output->avpkt.dts = output->mux_dts;
if (output->avpkt.pts < output->avpkt.dts)
output->avpkt.pts = output->avpkt.dts;
// the encoder may return frames with the same dts multiple consecutive times.
// the muxer may not like this, so ensure monotonically increasing dts.
if (output->mux_dts > output->avpkt.dts)
output->avpkt.dts = output->mux_dts;
if (output->avpkt.pts < output->avpkt.dts)
output->avpkt.pts = output->avpkt.dts;
av_write_frame(output->fmtctx, &output->avpkt);
av_write_frame(output->fmtctx, &output->avpkt);
output->fifo_pts += output->frame->nb_samples;
output->mux_dts = output->avpkt.dts + 1; // min next expected dts
output->fifo_pts += output->frame->nb_samples;
output->mux_dts = output->avpkt.dts + 1; // min next expected dts
} while (keep_going);
}
return 0;


Loading…
Cancel
Save