static int do_decode(AVCodecContext *avctx, AVPacket *pkt)
{
    int got_frame;
    int ret;

    av_assert0(!avctx->internal->buffer_frame->buf[0]);

    if (!pkt)
        pkt = avctx->internal->buffer_pkt;

    // This is the lesser evil. The field is for compatibility with legacy users
    // of the legacy API, and users using the new API should not be forced to
    // even know about this field.
    avctx->refcounted_frames = 1;

    // Some codecs (at least wma lossless) will crash when feeding drain packets
    // after EOF was signaled.
    if (avctx->internal->draining_done)
        return AVERROR_EOF;

    if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
        ret = avcodec_decode_video2(avctx, avctx->internal->buffer_frame,
                                    &got_frame, pkt);
        if (ret >= 0 && !(avctx->flags & AV_CODEC_FLAG_TRUNCATED))
            ret = pkt->size;
    } else if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
        ret = avcodec_decode_audio4(avctx, avctx->internal->buffer_frame,
                                    &got_frame, pkt);
    } else {
        ret = AVERROR(EINVAL);
    }

    if (ret == AVERROR(EAGAIN))
        ret = pkt->size;

    if (avctx->internal->draining && !got_frame)
        avctx->internal->draining_done = 1;

    if (ret < 0)
        return ret;

    if (ret >= pkt->size) {
        av_packet_unref(avctx->internal->buffer_pkt);
    } else {
        int consumed = ret;

        if (pkt != avctx->internal->buffer_pkt) {
            av_packet_unref(avctx->internal->buffer_pkt);
            if ((ret = av_packet_ref(avctx->internal->buffer_pkt, pkt)) < 0)
                return ret;
        }

        avctx->internal->buffer_pkt->data += consumed;
        avctx->internal->buffer_pkt->size -= consumed;
        avctx->internal->buffer_pkt->pts   = AV_NOPTS_VALUE;
        avctx->internal->buffer_pkt->dts   = AV_NOPTS_VALUE;
    }

    if (got_frame)
        av_assert0(avctx->internal->buffer_frame->buf[0]);

    return 0;
}