/*
*
* Copyright 2015 Rockchip Electronics Co. LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#define MODULE_TAG "vp9d_api"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "mpp_mem.h"
#include "mpp_packet_impl.h"

#include "vp9d_codec.h"
#include "vp9d_parser.h"
#include "vp9d_api.h"

/*!
***********************************************************************
* \brief
*   alloc all buffer
***********************************************************************
*/

MPP_RET vp9d_init(void *ctx, ParserCfg *init)
{
    MPP_RET ret = MPP_OK;
    RK_U8 *buf = NULL;
    RK_S32 size = SZ_512K;
    Vp9CodecContext *vp9_ctx = (Vp9CodecContext *)ctx;

    if (!vp9_ctx || !init) {
        mpp_err("vp9d init fail");
        return MPP_ERR_NULL_PTR;
    }

    if ((ret = vp9d_parser_init(vp9_ctx, init)) != MPP_OK)
        goto _err_exit;

    if ((ret = vp9d_split_init(vp9_ctx)) != MPP_OK)
        goto _err_exit;

    buf = mpp_malloc(RK_U8, size);
    if (!buf) {
        mpp_err("vp9 init malloc stream buffer fail");
        ret = MPP_ERR_NOMEM;
        goto _err_exit;
    }

    if ((ret = mpp_packet_init(&vp9_ctx->pkt, (void *)buf, size)) != MPP_OK)
        goto _err_exit;

    return ret;

_err_exit:
    vp9d_deinit(vp9_ctx);
    return ret;
}

/*!
***********************************************************************
* \brief
*   free all buffer
***********************************************************************
*/
MPP_RET vp9d_deinit(void *ctx)
{
    RK_U8 *buf = NULL;
    Vp9CodecContext *vp9_ctx = (Vp9CodecContext *)ctx;

    if (vp9_ctx) {
        vp9d_parser_deinit(vp9_ctx);
        vp9d_split_deinit(vp9_ctx);
        if (vp9_ctx->pkt) {
            buf = mpp_packet_get_data(vp9_ctx->pkt);
            MPP_FREE(buf);
            mpp_packet_deinit(&vp9_ctx->pkt);
        }
    }

    return MPP_OK;
}

/*!
***********************************************************************
* \brief
*   reset
***********************************************************************
*/
MPP_RET  vp9d_reset(void *ctx)
{
    MPP_RET ret = MPP_ERR_UNKNOW;

    Vp9CodecContext *vp9_ctx = (Vp9CodecContext *)ctx;
    vp9d_paser_reset(vp9_ctx);
    return ret = MPP_OK;
}

/*!
***********************************************************************
* \brief
*   flush
***********************************************************************
*/
MPP_RET  vp9d_flush(void *ctx)
{
    MPP_RET ret = MPP_ERR_UNKNOW;

    (void)ctx;
    return ret = MPP_OK;
}

/*!
***********************************************************************
* \brief
*   prepare
***********************************************************************
*/
MPP_RET vp9d_prepare(void *ctx, MppPacket pkt, HalDecTask *task)
{
    MPP_RET ret = MPP_OK;
    Vp9CodecContext *vp9_ctx = (Vp9CodecContext *)ctx;
    SplitContext_t *ps = (SplitContext_t *)vp9_ctx->priv_data2;
    RK_S64 pts = -1;
    RK_S64 dts = -1;
    RK_U8 *buf = NULL;
    RK_S32 length = 0;
    RK_U8 *out_data = NULL;
    RK_S32 out_size = -1;
    RK_S32 consumed = 0;
    RK_U8 *pos = NULL;
    task->valid = -1;

    pts = mpp_packet_get_pts(pkt);
    dts = mpp_packet_get_dts(pkt);
    vp9_ctx->eos = mpp_packet_get_eos(pkt);
    buf = pos = mpp_packet_get_pos(pkt);
    length = (RK_S32)mpp_packet_get_length(pkt);

    consumed = vp9d_split_frame(ps, &out_data, &out_size, buf, length);
    pos += (consumed >= 0) ? consumed : length;

    mpp_packet_set_pos(pkt, pos);
    vp9d_dbg(VP9D_DBG_STRMIN, "pkt_len=%d, pts=%lld\n", length, pts);
    if (out_size > 0) {
        vp9d_get_frame_stream(vp9_ctx, out_data, out_size);
        task->input_packet = vp9_ctx->pkt;
        task->valid = 1;
        mpp_packet_set_pts(vp9_ctx->pkt, pts);
        mpp_packet_set_dts(vp9_ctx->pkt, dts);
        task->flags.eos = vp9_ctx->eos;
    } else {
        task->valid = 0;
        task->flags.eos = vp9_ctx->eos;
    }

    (void)pts;
    (void)dts;
    (void)task;
    return ret = MPP_OK;
}


/*!
***********************************************************************
* \brief
*   parser
***********************************************************************
*/
MPP_RET vp9d_parse(void *ctx, HalDecTask *in_task)
{
    Vp9CodecContext *vp9_ctx = (Vp9CodecContext *)ctx;
    MPP_RET ret = MPP_OK;
    vp9_parser_frame(vp9_ctx, in_task);

    return ret;
}
/*!
***********************************************************************
* \brief
*   callback
***********************************************************************
*/
MPP_RET vp9d_callback(void *decoder, void *info)
{
    MPP_RET ret = MPP_ERR_UNKNOW;
    Vp9CodecContext *vp9_ctx = (Vp9CodecContext *)decoder;
    vp9_parser_update(vp9_ctx, info);

    return ret = MPP_OK;
}

/*!
***********************************************************************
* \brief
*   api struct interface
***********************************************************************
*/

const ParserApi api_vp9d_parser = {
    .name = "vp9d_parse",
    .coding = MPP_VIDEO_CodingVP9,
    .ctx_size = sizeof(Vp9CodecContext),
    .flag = 0,
    .init = vp9d_init,
    .deinit = vp9d_deinit,
    .prepare = vp9d_prepare,
    .parse = vp9d_parse,
    .reset = vp9d_reset,
    .flush = vp9d_flush,
    .control = NULL,
    .callback = vp9d_callback,
};

