cedarX_vdec.c 12.5 KB
/*

    基于aodzip移植的cedarx写的解码文件

*/

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

#include "../CedarX_include/memoryAdapter.h"
#include "../CedarX_include/vdecoder.h"

#include <sys/time.h>
#include <time.h>
#include <sys/timeb.h>

#include "JZsdkLib.h"
#include "version_choose.h"

#if ALLWINNER_CEDAR == VERSION_SWITCH_ON
    typedef struct CedarX_VideoDecode {
    //解码器
    VideoDecoder   *decoder;
    //解码器基本配置
    VConfig         video_config;
    //创建一个视频流信息结构体 
    //用于初始化解码器 时码流 的基本信息
    VideoStreamInfo video_info;

    //解码输入相关
    unsigned int input_width; //输入的视频宽度
    unsigned int input_height; //输入的视频长度

    //解码输出相关
    unsigned int output_width; //输出的视频宽度
    unsigned int output_height; //输出的视频长度

    unsigned int ScaleRatio;

} CedarX_VideoDecode;

//解码结构体
static CedarX_VideoDecode *vdecoder = NULL;

/**********************************************************/       
/***********   解码器配置 *********************/
/**********************************************************/
static int CedarX_vedc_decoder_config()
{
    //清空
    memset(&vdecoder->video_config, 0, sizeof(VConfig));
    
    //注册内存
    vdecoder->video_config.memops = MemAdapterGetOpsS();
    if (vdecoder->video_config.memops == NULL)
    {
        JZSDK_LOG_ERROR("MemAdapterGetOpsS failed");
        return -1;
    }
    CdcMemOpen(vdecoder->video_config.memops);

    //输出的像素类型
    vdecoder->video_config.eOutputPixelFormat  = PIXEL_FORMAT_NV21;

    if (vdecoder->ScaleRatio != 0)
    {
        vdecoder->video_config.bScaleDownEn = 1; //配置缩小输出,取值为 0 或 1, 默认值为 0;
    }
    else
    {
        vdecoder->video_config.bScaleDownEn = 0; //配置缩小输出,取值为 0 或 1, 默认值为 0;
    }
    
    vdecoder->video_config.bRotationEn = 0;//配置旋转输出 取值为 0 或 1, 默认值为 0;


    // 视频输出图像水平方向缩小比例,0 表示不缩放,1 表示缩放为 1/2 大小,2 表示缩放为 1/4 大小,3 表示缩放为 1/8大小;
    vdecoder->video_config.nHorizonScaleDownRatio = vdecoder->ScaleRatio;

    //视频输出图像竖直方向缩小比例,0 表示不缩放,1 表示缩放为 1/2 大小,2 表示缩放为 1/4 大小,3 表示缩放为 1/8 大小;
    //(注:缩放比例是针对原始图像设置, 同时进行旋转时需要注意;VP6、WMV1、WMV2 格式的视频不支持 ScaleDown 功能);
    vdecoder->video_config.nVerticalScaleDownRatio = vdecoder->ScaleRatio;

    //从通道视频输出图像水平方向缩小比例,0 表示不缩放,1 表示缩放为 1/2 大小,2 表示缩放为 1/4 大小,3表示缩放为 1/8 大小,4 表示缩放 1/16,5 表示缩放 1/32;
    vdecoder->video_config.nSecHorizonScaleDownRatio = vdecoder->ScaleRatio;

    //从通道视频输出图像垂直方向缩小比例,0 表示不缩放,1 表示缩放为 1/2 大小,2 表示缩放为 1/4 大小,3表示缩放为 1/8 大小,4 表示缩放 1/16,5 表示缩放 1/32;
    vdecoder->video_config.nSecVerticalScaleDownRatio = vdecoder->ScaleRatio;

    //视频输出图像的旋转角度,以顺时针方向计算,0 表示不旋转,1 表示 90 度,2 表示 180 度,3 表示 270 度;
    vdecoder->video_config.nRotateDegree = 0;

    
    //解码器以缩略图模式工作,当应用程序只是希望解码视频文件的一幅图像作为缩略图显示时,解码器可以只申请一个图像Buffer,
    //解码输出图像后应用程序关闭解码器,不再继续解码, 取值为0 或 1, 默认值为 0;
    vdecoder->video_config.bThumbnailMode = 0;

    //视频源是否没有 B 帧, 取值为 0 或 1(默认值为 0);
    vdecoder->video_config.bNoBFrames = 0;

    //不支持 3D 模式,取值 0 或 1(默认值为 0);
    vdecoder->video_config.bDisable3D = 0;

    //是否支持 de_interlace 功能,只用于 A20
    vdecoder->video_config.bSupportMaf = 0;

    //以及未配
    vdecoder->video_config.bGpuBufValid = 0;
    vdecoder->video_config.nAlignStride = 16;
    vdecoder->video_config.nDeInterlaceHoldingFrameBufferNum = 2;
    vdecoder->video_config.nDisplayHoldingFrameBufferNum = 2;
    //vdecoder->video_config.nRotateHoldingFrameBufferNum = 5;
    vdecoder->video_config.nDecodeSmoothFrameBufferNum = 3;
}

/**********************************************************/       
/***********   解码器时码流配置 *********************/
/**********************************************************/
static int CedarX_vedc_decoder_StreamConfig()
{
    //清空
    memset(&vdecoder->video_info, 0, sizeof(VideoStreamInfo));

    //1、解码的类型
    vdecoder->video_info.eCodecFormat = VIDEO_CODEC_FORMAT_H264;

    //2、宽高及帧
    vdecoder->video_info.nWidth = vdecoder->input_width;
    vdecoder->video_info.nHeight = vdecoder->input_height;
    //vdecoder->video_info.nFrameRate = DECODE_FRAME;
    
    //宽高比
    //vdecoder->video_info.nAspectRatio

    //剩下的先不配 自行查阅文档
    //pVideoInfo->nFrameRate = 4*1024*1024;
    //vdecoder->video_info->nFrameDuration = 50;
    //vdecoder->video_info->nAspectRatio = program->video[i].nAspectRatio;
    //vdecoder->video_info->bIs3DStream = program->video[i].bIs3DStream;
    //vdecoder->video_info->nCodecSpecificDataLen = program->video[i].nCodecSpecificDataLen;
    //vdecoder->video_info->pCodecSpecificData = program->video[i].pCodecSpecificData;

}

/**********************************************************/       
/***********       解码器创建与初始化 *********************/
/**********************************************************/
static int CedarX_vdec_decoder_init()
{
    //初始化配置
    if(InitializeVideoDecoder(vdecoder->decoder, &vdecoder->video_info, &vdecoder->video_config) < 0)
    {
        JZSDK_LOG_ERROR(" init video decoder failed");
        return -1;
    }
    return 0;
}

/**********************************************************/       
/***********    解码器的初始化       **********************/
/**************输入视频的宽,高,缩小比,帧速*********************************/
/**********************************************************/
int CedarX_vdec_init(int width, int height,  int ScaleRatio,int FrameRate)
{
    //给解码结构体分配内存
    vdecoder = (CedarX_VideoDecode *)malloc(sizeof(CedarX_VideoDecode));
    if (vdecoder == NULL) {
        JZSDK_LOG_ERROR("解码器结构体分配内存失败");
        return -1;
    }

    vdecoder->input_height = height;
    vdecoder->input_width = width;
    vdecoder->output_height = height;
    vdecoder->output_width = width;
    vdecoder->ScaleRatio = ScaleRatio;

    //加载所有子解码库 可能不用这个 因为我只需要jpeg的解码库
    AddVDPlugin();

    //注册一个解码器
    vdecoder->decoder = CreateVideoDecoder();
    if(vdecoder->decoder == NULL)
    {
        JZSDK_LOG_ERROR(" create video decoder failed");
        return -1;
    }
    else
    {
        JZSDK_LOG_INFO("解码器创建完成");
    }

    //解码器码流配置
    CedarX_vedc_decoder_StreamConfig();

    //解码器配置
    CedarX_vedc_decoder_config();

    //解码器创建与初始化
    CedarX_vdec_decoder_init();
}



int CedarX_H264_TO_NV21_DecodeOneFrame(unsigned char *InputBuffer, int InputBufferLenth)
{
    int ret; //状态返回值

    //1、获取码流
    char *pBuf = NULL;
    char *pRingBuf = NULL;
    int   nBufSize = 0;
    int   nRingBufSize = 0;
    int stream_buf_index = 0;

    ret = RequestVideoStreamBuffer( 
                vdecoder->decoder,     //解码器
                InputBufferLenth,       //解码数组长度
                &pBuf,                  //输出参数,码流 Buffer 起始地址,等于 NULL 表示失败;
                &nBufSize,              //输出参数,码流 Buffer ppBuf 的大小
                &pRingBuf,              //输出参数,第二块 Buffer 的起始地址,等于 NULL 表示没有
                &nRingBufSize,          //第二块 Buffer ppRingBuf 的大小
                stream_buf_index                       //双码流
            );

    //printf("InputBufferLenth%d nBufSize %d \n",InputBufferLenth, nBufSize);
    if(ret < 0 || nBufSize +  nRingBufSize <InputBufferLenth)
    {
        JZSDK_LOG_ERROR("获取码流失败");
        return -1;
    }

    //2、递交码流
    memcpy(pBuf, InputBuffer, nBufSize);
    if (pRingBuf) {
        memcpy(pRingBuf, InputBuffer + nBufSize, nRingBufSize);
    }

    //中间件到解码器的每笔数据结构信息
    VideoStreamDataInfo InputDataInfo;

    memset(&InputDataInfo, 0, sizeof(VideoStreamDataInfo));
    InputDataInfo.pData   = pBuf;           //传输的一笔视频数据所用的 buffer 指针
    InputDataInfo.nLength = nBufSize + nRingBufSize;       //传输的一笔视频数据的长度
    InputDataInfo.nStreamIndex = 0;         //传输的视频数据属于第几路视频的标记,(主流为 0,从流为 1)
    InputDataInfo.bIsFirstPart = 1;         //传输的一笔视频数据的第一部分的标记
    InputDataInfo.bIsLastPart  = 1;         //传输的一笔视频数据的最后一部分的标记
    InputDataInfo.bValid       = 1;         //视频数据有效的标记

    //3、输入一帧图像
    ret = SubmitVideoStreamData(vdecoder->decoder, &InputDataInfo, stream_buf_index);
    {
        if(ret < 0)
        {
            JZSDK_LOG_ERROR("输入图像失败");
        }
    }
    //JZSDK_LOG_INFO("输入图像");

    //4、解码一帧图像
    
    int bDropBFrameIfDelay = 0;
    int bDecodeKeyFrameOnly = 0;
    int64_t nCurrentTimeUs = 0;

    ret = DecodeVideoStream(
        vdecoder->decoder,             //解码器
        0,                              //最后一笔流数据
        bDropBFrameIfDelay,             //解码时允许丢掉b帧数
        bDecodeKeyFrameOnly,            
        nCurrentTimeUs);                //当前系统时间
    {
        switch (ret)
        {
            case VDECODE_RESULT_FRAME_DECODED:
                    //JZSDK_LOG_INFO("解码成功,输出了一帧图像");
                break;
            case VDECODE_RESULT_CONTINUE:
                    JZSDK_LOG_INFO("码流被解码,但没有图像输出,需继续解码");
                break;
            case VDECODE_RESULT_KEYFRAME_DECODED:
                    JZSDK_LOG_INFO("解码成功,输出了一帧关键帧图像");
                break;
            case VDECODE_RESULT_NO_FRAME_BUFFER:
                    JZSDK_LOG_INFO("当前无法获取到图像 Buffer");
                break;
            case VDECODE_RESULT_NO_BITSTREAM:
                    JZSDK_LOG_INFO("当前无法获取到码流数据");
                break;
            case VDECODE_RESULT_RESOLUTION_CHANGE:
                    JZSDK_LOG_INFO("视频分辨率发生变化,无法继续");
                break;  
            case VDECODE_RESULT_UNSUPPORTED:
                    JZSDK_LOG_INFO("不能支持的格式或申请内存失败,无法继续解码");
                break;      
            default:
                break;
        }
    }
    //JZSDK_LOG_INFO("解码图像");

    //5、获取输出的图像
    VideoPicture *pPicture;
    pPicture = RequestPicture(vdecoder->decoder, stream_buf_index);
    {
        if(pPicture == NULL)
        {
            JZSDK_LOG_ERROR("解码输出头像为空");
            return -1;
        }
    }
    //printf("pPicture->nWidth %d pPicture->h %d \n",pPicture->nWidth,pPicture->nHeight);

    // //输出一帧图像
    // /* save y */
    // fwrite(pPicture->pData0, 1, pPicture->nWidth*pPicture->nHeight, save_fp);

    // /* save uv */
    // fwrite(pPicture->pData0+pPicture->nWidth*pPicture->nHeight, 1, pPicture->nWidth*pPicture->nHeight/2, save_fp);
    //JZSDK_LOG_INFO("保存输出");

    if (ret == VDECODE_RESULT_FRAME_DECODED || ret == VDECODE_RESULT_KEYFRAME_DECODED)
    {
        Get_LightSpot_Yvalue(pPicture->pData0,480,272 );
    }
    

    //返还已经使用完成的buffer
    ReturnPicture(vdecoder->decoder, pPicture);

    //printf("ReturnpPicture->nWidth %d ReturnpPicture->h %d \n",pPicture->nWidth,pPicture->nHeight);

    return 0;
}

#endif