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

Change-Id: I575b0653e00e2bae15cb9bfda564ff7a9a2b7ffe
changes/97/9997/1
Richard Fuchs 10 years ago
parent df869fff0f
commit 040d1bec10

@ -166,59 +166,12 @@ err:
} }
int decoder_input(decoder_t *dec, const str *data, unsigned long ts, output_t *output) { static AVFrame *decoder_resample_frame(decoder_t *dec) {
const char *err; const char *err;
if (G_UNLIKELY(!dec)) if (dec->in_clockrate == dec->out_clockrate)
return -1; return dec->frame;
dbg("%p dec pts %lu rtp_ts %lu incoming ts %lu", dec, (unsigned long) dec->pts,
(unsigned long) dec->rtp_ts, (unsigned long) ts);
if (G_UNLIKELY(dec->rtp_ts == (unsigned long) -1L)) {
// initialize pts
dec->pts = 0;
}
else {
// shift pts according to rtp ts shift
dec->pts += (ts - dec->rtp_ts) /* * output->avst->time_base.num * 8000 / output->avst->time_base.den */ ;
// XXX handle lost packets here if timestamps don't line up?
}
dec->rtp_ts = ts;
dec->avpkt.data = (unsigned char *) data->s;
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;
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) { if (!dec->avresample) {
dec->avresample = avresample_alloc_context(); dec->avresample = avresample_alloc_context();
err = "failed to alloc resample context"; err = "failed to alloc resample context";
@ -238,9 +191,11 @@ int decoder_input(decoder_t *dec, const str *data, unsigned long ts, output_t *o
goto err; goto err;
} }
// get a large enough buffer for resampled audio // get a large enough buffer for resampled audio - this should be enough so we don't
int dst_samples = av_rescale_rnd(dec->frame->nb_samples, dec->out_clockrate, // have to loop
dec->in_clockrate, AV_ROUND_UP); 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) { if (!dec->swr_frame || dec->swr_buffers < dst_samples) {
av_frame_free(&dec->swr_frame); av_frame_free(&dec->swr_frame);
dec->swr_frame = av_frame_alloc(); dec->swr_frame = av_frame_alloc();
@ -267,16 +222,120 @@ int decoder_input(decoder_t *dec, const str *data, unsigned long ts, output_t *o
if (ret_samples < 0) if (ret_samples < 0)
goto err; goto err;
dec_frame = dec->swr_frame; dec->swr_frame->nb_samples = ret_samples;
dec_frame->nb_samples = ret_samples; dec->swr_frame->pts = av_rescale(dec->frame->pts, dec->out_clockrate, dec->in_clockrate);
dec_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); output_config(output, dec->out_clockrate, dec->channels);
if (output_add(output, dec_frame)) if (output_add(output, dec_frame))
return -1; return -1;
return 0; return 0;
}
int decoder_input(decoder_t *dec, const str *data, unsigned long ts, output_t *output) {
const char *err;
if (G_UNLIKELY(!dec))
return -1;
dbg("%p dec pts %lu rtp_ts %lu incoming ts %lu", dec, (unsigned long) dec->pts,
(unsigned long) dec->rtp_ts, (unsigned long) ts);
if (G_UNLIKELY(dec->rtp_ts == (unsigned long) -1L)) {
// initialize pts
dec->pts = 0;
}
else {
// shift pts according to rtp ts shift
dec->pts += (ts - dec->rtp_ts) /* * output->avst->time_base.num * 8000 / output->avst->time_base.den */ ;
// XXX handle lost packets here if timestamps don't line up?
}
dec->rtp_ts = ts;
dec->avpkt.data = (unsigned char *) data->s;
dec->avpkt.size = data->len;
dec->avpkt.pts = dec->pts;
// loop until all input is consumed and all available output has been processed
int keep_going;
do {
keep_going = 0;
int got_frame = 0;
#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;
}
}
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;
}
#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
if (got_frame) {
if (decoder_got_frame(dec, output))
return -1;
}
} while (keep_going);
return 0;
err: err:
ilog(LOG_ERR, "Error decoding media packet: %s", err); ilog(LOG_ERR, "Error decoding media packet: %s", err);

@ -50,24 +50,59 @@ static int output_flush(output_t *output) {
dbg("%p output fifo pts %lu", output, (unsigned long) output->fifo_pts); dbg("%p output fifo pts %lu", output, (unsigned long) output->fifo_pts);
output->frame->pts = 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) #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 0, 0)
if (have_frame) {
int ret = avcodec_send_frame(output->avcctx, output->frame); int ret = avcodec_send_frame(output->avcctx, output->frame);
dbg("%p send frame ret %i", output, ret); dbg("%p send frame ret %i", output, ret);
if (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; return -1;
}
}
ret = avcodec_receive_packet(output->avcctx, &output->avpkt); int ret = avcodec_receive_packet(output->avcctx, &output->avpkt);
dbg("%p receive packet ret %i", output, ret); dbg("%p receive packet ret %i", output, ret);
if (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; return -1;
}
#else #else
int got_packet = 0; if (!have_frame)
break;
int ret = avcodec_encode_audio2(output->avcctx, &output->avpkt, output->frame, &got_packet); 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); dbg("%p encode frame ret %i, got packet %i", output, ret, got_packet);
if (!got_packet) if (ret == 0)
return 0; have_frame = 0; // consumed
else
return -1; // error
if (got_packet)
keep_going = 1;
#endif #endif
if (!got_packet)
continue;
dbg("%p output avpkt size is %i", output, (int) output->avpkt.size); 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, dbg("%p output pkt pts/dts is %li/%li", output, (long) output->avpkt.pts,
(long) output->avpkt.dts); (long) output->avpkt.dts);
@ -84,6 +119,7 @@ static int output_flush(output_t *output) {
output->fifo_pts += output->frame->nb_samples; output->fifo_pts += output->frame->nb_samples;
output->mux_dts = output->avpkt.dts + 1; // min next expected dts output->mux_dts = output->avpkt.dts + 1; // min next expected dts
} while (keep_going);
} }
return 0; return 0;

Loading…
Cancel
Save