#include "H264Palyer.h"
#include "BoostLog.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}

H264Palyer::H264Palyer() {
}

H264Palyer::~H264Palyer() {
    if (m_packet != nullptr) {
        av_packet_free(&m_packet);
    }
}

void H264Palyer::open() {
    auto codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (!codec) {
        LOG(error) << "cannot find h264 codec.";
        return;
    }
    m_codecContext = avcodec_alloc_context3(codec);
    if (m_codecContext == nullptr) {
        LOG(error) << "Could not allocate video codec context";
        return;
    }
    if (avcodec_open2(m_codecContext, codec, nullptr) < 0) {
        LOG(error) << "Could not open codec";
        return;
    }

    m_packet = av_packet_alloc();
    if (m_packet == nullptr) {
        LOG(error) << "Could not allocate AVPacket";
    }
    m_frame = av_frame_alloc();
    if (m_frame == nullptr) {
        LOG(error) << "Could not allocate AVFrame";
    }
}

std::optional<QImage> H264Palyer::decode(const uint8_t *data, uint32_t size) {
    m_packet->data = const_cast<uint8_t *>(data);
    m_packet->size = size;
    int ret = avcodec_send_packet(m_codecContext, m_packet);
    if (ret < 0) {
        return std::nullopt;
    }
    ret = avcodec_receive_frame(m_codecContext, m_frame);
    if (ret < 0) {
        return std::nullopt;
    }

    SwsContext *swsCtx = sws_getContext(m_frame->width, m_frame->height, m_codecContext->pix_fmt, m_frame->width,
                                        m_frame->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr);

    QImage image(m_frame->width, m_frame->height, QImage::Format_RGB888);
    uint8_t *imageData[1] = {image.bits()};
    int linesize[1] = {3 * m_frame->width};
    sws_scale(swsCtx, m_frame->data, m_frame->linesize, 0, m_frame->height, imageData, linesize);
    sws_freeContext(swsCtx);
    // LOG(info) << image.width() << "x" << image.height();
    return image;
}