#include "ffutil.h"
#include <QPainter>
#include <QDebug>
extern "C"{
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}

static void imgCleanupHandler(void *info) {
    delete [] (uchar*)info;
}

QString videoInfo(QByteArray url, QImage &img, int64_t *dur, AVCodecID *codec_id) {
    AVFormatContext *fmt_ctx = avformat_alloc_context();
    QString err;
    {
        if(avformat_open_input(&fmt_ctx, url.constData(), nullptr, nullptr) != 0) {
            err = "Couldn't open input stream";
            goto free;
        }
        if(avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
            err = "Couldn't find stream information";
            goto free;
        }
        if(dur!=nullptr) *dur = fmt_ctx->duration;
        int vi_idx = -1;
        for(uint ss=0; ss<fmt_ctx->nb_streams; ss++) if(fmt_ctx->streams[ss]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) vi_idx = ss;
        if(vi_idx == -1) {
            err = "Didn't find a Video Stream";
            goto free;
        }
        auto codecpar = fmt_ctx->streams[vi_idx]->codecpar;
        if(codec_id!=nullptr) *codec_id = codecpar->codec_id;
        qDebug()<<"codec_id"<<codecpar->codec_id<<avcodec_get_name(codecpar->codec_id);
        if(av_seek_frame(fmt_ctx, -1, 1000000, AVSEEK_FLAG_BACKWARD) < 0) {
            err = "av_seek_frame fail";
            goto free;
        }
        const AVCodec *decoder = avcodec_find_decoder(codecpar->codec_id);
        if(decoder==nullptr) {
            err = "Could not found Video Decoder";
            goto free;
        }
        auto vcCtx = avcodec_alloc_context3(decoder);
        avcodec_parameters_to_context(vcCtx, codecpar);
        if(avcodec_open2(vcCtx, decoder, nullptr) < 0) {
            err = "Could not open Video Codec Ctx";
            avcodec_free_context(&vcCtx);
            goto free;
        }
        auto sws_ctx = sws_getContext(vcCtx->width, vcCtx->height, vcCtx->pix_fmt, vcCtx->width, vcCtx->height, AV_PIX_FMT_RGB32, SWS_FAST_BILINEAR, 0, 0, 0);
        auto packet = av_packet_alloc();
        auto frm = av_frame_alloc();
        int dstStride[4]{(vcCtx->width*4+63)/64*64};
        dstStride[3] = dstStride[0] * vcCtx->height;
        uint8_t *dst[4]{0};
        while(1) {
            if(av_read_frame(fmt_ctx, packet) < 0) break;
            if(packet->stream_index != vi_idx) continue;
            int res = avcodec_send_packet(vcCtx, packet);
            if(res < 0) break;
            while((res = avcodec_receive_frame(vcCtx, frm)) != AVERROR(EAGAIN)) {
                if(res < 0) goto free2;
                dst[0] = new uchar[dstStride[3]];
                sws_scale(sws_ctx, frm->data, frm->linesize, 0, vcCtx->height, dst, dstStride);
                img = QImage(dst[0], vcCtx->width, vcCtx->height, dstStride[0], QImage::Format_ARGB32, imgCleanupHandler, dst[0]);
                goto free2;
            }
        }
        free2:
        av_frame_free(&frm);
        av_packet_free(&packet);
        avcodec_free_context(&vcCtx);
        sws_freeContext(sws_ctx);
    }
    free:
    avformat_close_input(&fmt_ctx);
    return err;
}
QString audioInfo(QByteArray url, int64_t *dur) {
    AVFormatContext *fmt_ctx = avformat_alloc_context();
    QString err;
    {
        if(avformat_open_input(&fmt_ctx, url.constData(), nullptr, nullptr) != 0) {
            err = "Couldn't open input stream";
            goto free;
        }
        if(avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
            err = "Couldn't find stream information";
            goto free;
        }
        if(dur!=nullptr) *dur = fmt_ctx->duration;
    }
    free:
    avformat_close_input(&fmt_ctx);
    return err;
}
