SmartAudio/package/allwinner/liballwinner_tina/demo/jpegdecodedemo/demojpeg.c

713 lines
19 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <log.h>
#include <vdecoder.h>
#include "memoryAdapter.h"
#include <errno.h>
#define SAVE_RGB (1)
typedef struct VideoFrame
{
// Intentional public access modifier:
uint32_t mWidth;
uint32_t mHeight;
uint32_t mDisplayWidth;
uint32_t mDisplayHeight;
uint32_t mSize; // Number of bytes in mData
uint8_t* mData; // Actual binary data
int32_t mRotationAngle; // rotation angle, clockwise
}VideoFrame;
#if SAVE_RGB
//-------------------------------------------------------------------
char* gOutPutPath = NULL;
/*
  位图文件的组成
结构名称 符 号
位图文件头 (bitmap-file header) BITMAPFILEHEADER bmfh
位图信息头 (bitmap-information header) BITMAPINFOHEADER bmih
彩色表 (color table) RGBQUAD aColors[]
图象数据阵列字节 BYTE aBitmapBits[]
*/
typedef struct bmp_header
{
short twobyte ;//两个字节,用来保证下面成员紧凑排列,这两个字符不能写到文件中
//14B
char bfType[2] ;//!文件的类型,该值必需是0x4D42也就是字符'BM'
unsigned int bfSize ;//!说明文件的大小,用字节为单位
unsigned int bfReserved1;//保留必须设置为0
unsigned int bfOffBits ;//!说明从文件头开始到实际的图象数据之间的字节的偏移量这里为14B+sizeof(BMPINFO)
}BMPHEADER;
typedef struct bmp_info
{
//40B
unsigned int biSize ;//!BMPINFO结构所需要的字数
int biWidth ;//!图象的宽度,以象素为单位
int biHeight ;//!图象的宽度,以象素为单位,如果该值是正数,说明图像是倒向的,如果该值是负数,则是正向的
unsigned short biPlanes ;//!目标设备说明位面数其值将总是被设为1
unsigned short biBitCount ;//!比特数/象素其值为1、4、8、16、24、或32
unsigned int biCompression ;//说明图象数据压缩的类型
#define BI_RGB 0L //没有压缩
#define BI_RLE8 1L //每个象素8比特的RLE压缩编码压缩格式由2字节组成重复象素计数和颜色索引
#define BI_RLE4 2L //每个象素4比特的RLE压缩编码压缩格式由2字节组成
#define BI_BITFIELDS 3L //每个象素的比特由指定的掩码决定。
unsigned int biSizeImage ;//图象的大小以字节为单位。当用BI_RGB格式时可设置为0
int biXPelsPerMeter ;//水平分辨率,用象素/米表示
int biYPelsPerMeter ;//垂直分辨率,用象素/米表示
unsigned int biClrUsed ;//位图实际使用的彩色表中的颜色索引数设为0的话则说明使用所有调色板项
unsigned int biClrImportant ;//对图象显示有重要影响的颜色索引的数目如果是0表示都重要。
}BMPINFO;
typedef struct tagRGBQUAD
{
unsigned char rgbBlue;
unsigned char rgbGreen;
unsigned char rgbRed;
unsigned char rgbReserved;
} RGBQUAD;
typedef struct tagBITMAPINFO
{
BMPINFO bmiHeader;
//RGBQUAD bmiColors[1];
unsigned int rgb[3];
} BITMAPINFO;
static int get_rgb565_header(int w, int h, BMPHEADER * head, BITMAPINFO * info)
{
int size = 0;
if (head && info)
{
size = w * h * 2;
memset(head, 0, sizeof(* head));
memset(info, 0, sizeof(* info));
head->bfType[0] = 'B';
head->bfType[1] = 'M';
head->bfOffBits = 14 + sizeof(* info);
head->bfSize = head->bfOffBits + size;
head->bfSize = (head->bfSize + 3) & ~3;
size = head->bfSize - head->bfOffBits;
info->bmiHeader.biSize = sizeof(info->bmiHeader);
info->bmiHeader.biWidth = w;
info->bmiHeader.biHeight = -h;
info->bmiHeader.biPlanes = 1;
info->bmiHeader.biBitCount = 16;
info->bmiHeader.biCompression = BI_BITFIELDS;
info->bmiHeader.biSizeImage = size;
info->rgb[0] = 0xF800;
info->rgb[1] = 0x07E0;
info->rgb[2] = 0x001F;
logd("rgb565:%dbit,%d*%d,%d\n", info->bmiHeader.biBitCount, w, h, head->bfSize);
}
return size;
}
static int save_bmp_rgb565(FILE* fp, int width, int height, unsigned char* pData)
{
int success = 0;
int size = 0;
BMPHEADER head;
BITMAPINFO info;
size = get_rgb565_header(width, height, &head, &info);
if(size > 0)
{
fwrite(head.bfType,1,2,fp);
fwrite(&head.bfSize,1,4,fp);
fwrite(&head.bfReserved1,1,4,fp);
fwrite(&head.bfOffBits,1,4,fp);
fwrite(&info,1,sizeof(info), fp);
fwrite(pData,1,size, fp);
success = 1;
}
logd("*****success=%d\n", success);
return success;
}
#endif
#if 0
static int get_rgb888_header(int w, int h, BMPHEADER * head, BITMAPINFO * info)
{
int size = 0;
if (head && info)
{
size = w * h * 3;
memset(head, 0, sizeof(* head));
memset(info, 0, sizeof(* info));
head->bfType[0] = 'B';
head->bfType[1] = 'M';
head->bfOffBits = 14 + sizeof(* info);
head->bfSize = head->bfOffBits + size;
head->bfSize = (head->bfSize + 3) & ~3;
size = head->bfSize - head->bfOffBits;
info->bmiHeader.biSize = sizeof(info->bmiHeader);
info->bmiHeader.biWidth = w;
info->bmiHeader.biHeight = -h;
info->bmiHeader.biPlanes = 1;
info->bmiHeader.biBitCount = 24;
info->bmiHeader.biCompression = BI_RGB;
info->bmiHeader.biSizeImage = size;
logd("rgb888:%dbit,%d*%d,%d\n", info->bmiHeader.biBitCount, w, h, head->bfSize);
}
return size;
}
static int save_bmp_rgb888(FILE* fp, int width, int height, unsigned char* pData)
{
int success = 0;
int size = 0;
BMPHEADER head;
BITMAPINFO info;
size = get_rgb888_header(width, height, &head, &info);
if(size > 0)
{
fwrite(head.bfType,1,14,fp);
fwrite(&info,1,sizeof(info), fp);
fwrite(pData,1,size, fp);
success = 1;
}
logd("*****success=%d\n", success);
return success;
}
static int transformPictureMb32ToRGB888(VideoPicture* pPicture, unsigned char* pData, int nWidth, int nHeight)
{
unsigned char* pClipTable;
unsigned char* pClip;
static const int nClipMin = -278;
static const int nClipMax = 535;
unsigned short* pDst = NULL;
unsigned char* pSrcY = NULL;
unsigned char* pSrcVU = NULL;
int x = 0;
int y = 0;
int nMbWidth = 0;
int nMbHeight = 0;
int nVMb = 0;
int nHMb = 0;
int yPos = 0;
int pos = 0;
int uvPos = 0;
//* initialize the clip table.
pClipTable = (unsigned char*)malloc(nClipMax - nClipMin + 1);
if(pClipTable == NULL)
{
loge("can not allocate memory for the clip table, quit.");
return -1;
}
for(x=nClipMin; x<=nClipMax; x++)
{
pClipTable[x-nClipMin] = (x<0) ? 0 : (x>255) ? 255 : x;
}
pClip = &pClipTable[-nClipMin];
//* flush cache.
MemAdapterFlushCache(pPicture->pData0, pPicture->nWidth*pPicture->nHeight);
MemAdapterFlushCache(pPicture->pData1, pPicture->nHeight*pPicture->nHeight/2);
pDst = (unsigned short*)pData;
logd("+++++ pDst: %p", pDst);
pSrcY = (unsigned char*)pPicture->pData0;
pSrcVU = (unsigned char*)pPicture->pData1;
nMbWidth = pPicture->nWidth/32;
nMbHeight = pPicture->nHeight/32;
for(nVMb=0; nVMb<nMbHeight;nVMb++)
{
for(nHMb=0; nHMb<nMbWidth; nHMb++)
{
#if 1
pos = 3*(nVMb*pPicture->nWidth*32+nHMb*32);
#else
pos = nVMb*pPicture->nWidth*32+nHMb*32;
#endif
for(y=0; y<32; y++)
{
yPos = (nVMb*nMbWidth+nHMb)*1024+y*32;
uvPos = ((nVMb/2)*nMbWidth*1024)+nHMb*1024+(y/2)*32+ (((nVMb%2)==1) ? 512 : 0);
for(x=0; x<32; x+=2)
{
signed y1 = (signed)pSrcY[yPos+x+0] - 16;
signed y2 = (signed)pSrcY[yPos+x+1] - 16;
signed u = (signed)pSrcVU[uvPos+x+0] - 128;
signed v = (signed)pSrcVU[uvPos+x+1] - 128;
signed u_b = u * 517;
signed u_g = -u * 100;
signed v_g = -v * 208;
signed v_r = v * 409;
signed tmp1 = y1 * 298;
signed b1 = (tmp1 + u_b) / 256;
signed g1 = (tmp1 + v_g + u_g) / 256;
signed r1 = (tmp1 + v_r) / 256;
signed tmp2 = y2 * 298;
signed b2 = (tmp2 + u_b) / 256;
signed g2 = (tmp2 + v_g + u_g) / 256;
signed r2 = (tmp2 + v_r) / 256;
#if 1
pDst[pos+0] = pClip[r1];
pDst[pos+1] = pClip[g1];
pDst[pos+2] = pClip[b1];
pDst[pos+3] = pClip[r2];
pDst[pos+4] = pClip[g2];
pDst[pos+5] = pClip[b2];
pos += 6;
}
pos += 3*(nMbWidth-1)*32;
#else
unsigned int rgb1 = ((pClip[r1] >> 3) << 11) |
((pClip[g1] >> 2) << 5) |
(pClip[b1] >> 3);
unsigned int rgb2 = ((pClip[r2] >> 3) << 11) |
((pClip[g2] >> 2) << 5) |
(pClip[b2] >> 3);
*(unsigned int *)(&pDst[pos]) = (rgb2 << 16) | rgb1;
pos += 2;
}
pos += (nMbWidth-1)*32;
#endif
}
}
}
logd("pos: %d", pos);
pDst = (unsigned short*)pData;
for(y=0; y<pPicture->nTopOffset; y++)
{
memset(pDst+y*nWidth, 0, 2*nWidth);
}
for(y=pPicture->nBottomOffset; y<nHeight; y++)
{
memset(pDst+y*nWidth, 0, 2*nWidth);
}
for(y=pPicture->nTopOffset; y<pPicture->nBottomOffset; y++)
{
memset(pDst+y*nWidth, 0, 2*pPicture->nLeftOffset);
memset(pDst+y*nWidth+pPicture->nRightOffset, 0, 2*(nWidth-pPicture->nRightOffset));
}
#if 1
FILE* outFp = fopen("/mnt/UDISK/rgb.data", "wb");
if(outFp != NULL)
{
logd("************save_bmp_rgb565\n");
save_bmp_rgb888(outFp, nWidth, nHeight, pData);
fwrite(pDst, 1, nWidth*nHeight*3, outFp);
fclose(outFp);
}
#endif
free(pClipTable);
return 0;
}
#endif
static int transformPictureMb32ToRGB(struct ScMemOpsS* memops, VideoPicture* pPicture, unsigned char* pData, int nWidth, int nHeight)
{
unsigned char* pClipTable;
unsigned char* pClip;
static const int nClipMin = -278;
static const int nClipMax = 535;
unsigned short* pDst = NULL;
unsigned char* pSrcY = NULL;
unsigned char* pSrcVU = NULL;
int x = 0;
int y = 0;
int nMbWidth = 0;
int nMbHeight = 0;
int nVMb = 0;
int nHMb = 0;
int yPos = 0;
int pos = 0;
int uvPos = 0;
//* initialize the clip table.
pClipTable = (unsigned char*)malloc(nClipMax - nClipMin + 1);
if(pClipTable == NULL)
{
loge("can not allocate memory for the clip table, quit.");
return -1;
}
for(x=nClipMin; x<=nClipMax; x++)
{
pClipTable[x-nClipMin] = (x<0) ? 0 : (x>255) ? 255 : x;
}
pClip = &pClipTable[-nClipMin];
//* flush cache.
CdcMemFlushCache(memops, pPicture->pData0, pPicture->nWidth*pPicture->nHeight);
CdcMemFlushCache(memops, pPicture->pData1, pPicture->nHeight*pPicture->nHeight/2);
pDst = (unsigned short*)pData;
logd("+++++ pDst: %p", pDst);
pSrcY = (unsigned char*)pPicture->pData0;
pSrcVU = (unsigned char*)pPicture->pData1;
nMbWidth = pPicture->nWidth/32;
nMbHeight = pPicture->nHeight/32;
for(nVMb=0; nVMb<nMbHeight;nVMb++)
{
for(nHMb=0; nHMb<nMbWidth; nHMb++)
{
pos = nVMb*pPicture->nWidth*32+nHMb*32;
for(y=0; y<32; y++)
{
yPos = (nVMb*nMbWidth+nHMb)*1024+y*32;
uvPos = ((nVMb/2)*nMbWidth*1024)+nHMb*1024+(y/2)*32+ (((nVMb%2)==1) ? 512 : 0);
for(x=0; x<32; x+=2)
{
signed y1 = (signed)pSrcY[yPos+x+0] - 16;
signed y2 = (signed)pSrcY[yPos+x+1] - 16;
signed u = (signed)pSrcVU[uvPos+x+0] - 128;
signed v = (signed)pSrcVU[uvPos+x+1] - 128;
signed u_b = u * 517;
signed u_g = -u * 100;
signed v_g = -v * 208;
signed v_r = v * 409;
signed tmp1 = y1 * 298;
signed b1 = (tmp1 + u_b) / 256;
signed g1 = (tmp1 + v_g + u_g) / 256;
signed r1 = (tmp1 + v_r) / 256;
signed tmp2 = y2 * 298;
signed b2 = (tmp2 + u_b) / 256;
signed g2 = (tmp2 + v_g + u_g) / 256;
signed r2 = (tmp2 + v_r) / 256;
unsigned int rgb1 = ((pClip[r1] >> 3) << 11) |
((pClip[g1] >> 2) << 5) |
(pClip[b1] >> 3);
unsigned int rgb2 = ((pClip[r2] >> 3) << 11) |
((pClip[g2] >> 2) << 5) |
(pClip[b2] >> 3);
*(unsigned int *)(&pDst[pos]) = (rgb2 << 16) | rgb1;
pos += 2;
}
pos += (nMbWidth-1)*32;
}
}
}
logd("pos: %d", pos);
pDst = (unsigned short*)pData;
for(y=0; y<pPicture->nTopOffset; y++)
{
memset(pDst+y*nWidth, 0, 2*nWidth);
}
for(y=pPicture->nBottomOffset; y<nHeight; y++)
{
memset(pDst+y*nWidth, 0, 2*nWidth);
}
for(y=pPicture->nTopOffset; y<pPicture->nBottomOffset; y++)
{
memset(pDst+y*nWidth, 0, 2*pPicture->nLeftOffset);
memset(pDst+y*nWidth+pPicture->nRightOffset, 0, 2*(nWidth-pPicture->nRightOffset));
}
#if SAVE_RGB
FILE* outFp = NULL;
if(gOutPutPath != NULL){
outFp = fopen(gOutPutPath, "wb");
}else{
outFp = fopen("/tmp/rgb.bmp", "wb");
}
if(outFp != NULL){
logd("************save_bmp_rgb565\n");
save_bmp_rgb565(outFp, nWidth, nHeight, pData);
fclose(outFp);
}else{
loge("fopen output path fail\n");
}
#endif
free(pClipTable);
return 0;
}
static char * readJpegData(char *path, int *pLen)
{
FILE *fp = NULL;
int ret = 0;
char *data = NULL;
fp = fopen(path, "rb");
if(fp == NULL)
{
loge("read jpeg file error, errno(%d)", errno);
return NULL;
}
fseek(fp,0,SEEK_END);
*pLen = ftell(fp);
rewind(fp);
data = (char *) malloc (sizeof(char)*(*pLen));
if(data == NULL)
{
loge("malloc memory fail");
fclose(fp);
return NULL;
}
ret = fread (data,1,*pLen,fp);
if (ret != *pLen)
{
loge("read file fail");
fclose(fp);
free(data);
return NULL;
}
if(fp != NULL)
{
fclose(fp);
}
return data;
}
static int dumpData(char *path, uint8_t *data, int len)
{
FILE *fp;
fp = fopen(path, "a+");
if(fp != NULL)
{
logd("dump data '%d'", len);
fwrite(data, 1, len, fp);
fclose(fp);
}
else
{
loge("saving picture open file error, errno(%d)", errno);
return -1;
}
return 0;
}
int main(int argc, char** argv)
{
int ret;
VConfig vConfig;
char *jpegData = NULL;
int dataLen =0;
char * uri= NULL;
VideoDecoder *pVideo;
VideoPicture *videoPicture = NULL;
struct ScMemOpsS* memops = MemAdapterGetOpsS();
if(memops == NULL)
{
return -1;
}
CdcMemOpen(memops);
AddVDPlugin();
if (argc != 3)
{
logd("argc must be '3'");
logd("usage:");
logd("jpegdecodedemo /mnt/UDISK/test.jpg /mnt/UDISK/save.bmp");
return 0;
}
uri = argv[1];
#if SAVE_RGB
gOutPutPath = argv[2];
#endif
jpegData = readJpegData(uri , &dataLen);
logd("dataLen = %d",dataLen);
if (dataLen <= 0 || jpegData == NULL)
{
loge("read file fail");
return 0;
}
memset(&vConfig, 0x00, sizeof(VConfig));
vConfig.bDisable3D = 0;
vConfig.bDispErrorFrame = 0;
vConfig.bNoBFrames = 0;
vConfig.bRotationEn = 0;
vConfig.bScaleDownEn = 0;
vConfig.nHorizonScaleDownRatio = 0;
vConfig.nVerticalScaleDownRatio = 0;
vConfig.eOutputPixelFormat =PIXEL_FORMAT_YUV_MB32_420;
vConfig.nDeInterlaceHoldingFrameBufferNum = 0;
vConfig.nDisplayHoldingFrameBufferNum = 0;
vConfig.nRotateHoldingFrameBufferNum = 0;
vConfig.nDecodeSmoothFrameBufferNum = 1;
if(dataLen < 2*1024*1024){
vConfig.nVbvBufferSize = 2*1024*1024;
}else{
int cnt = dataLen/(4*1024);
logd("cnt = %d",cnt);
vConfig.nVbvBufferSize = (cnt+1)*4*1024;
}
logd("vConfig.nVbvBufferSize = %d",vConfig.nVbvBufferSize);
vConfig.bThumbnailMode = 0;
vConfig.memops = memops;
VideoStreamInfo videoInfo;
memset(&videoInfo, 0x00, sizeof(VideoStreamInfo));
videoInfo.eCodecFormat = VIDEO_CODEC_FORMAT_MJPEG;
pVideo = CreateVideoDecoder();
if(!pVideo)
{
loge("create video decoder failed\n");
return 0;
}
logd("create video decoder ok\n");
if ((InitializeVideoDecoder(pVideo, &videoInfo, &vConfig)) != 0)
{
loge("InitializeVideoDecoder failed !\n");
return 0;
}
logd("Initialize video decoder ok\n");
char *buf, *ringBuf;
int buflen, ringBufLen;
if((RequestVideoStreamBuffer(pVideo,
dataLen,
(char**)&buf,
&buflen,
(char**)&ringBuf,
&ringBufLen,
0)) != 0){
loge("Request Video Stream Buffer failed\n");
return 0;
}
logd("Request Video Stream Buffer ok\n");
if(buflen + ringBufLen < dataLen)
{
loge("#####Error: request buffer failed, buffer is not enough\n");
return 0;
}
logd("goto to copy Video Stream Data ok!\n");
// copy stream to video decoder SBM
if(buflen >= dataLen)
{
memcpy(buf,jpegData,dataLen);
}
else
{
memcpy(buf,jpegData,buflen);
memcpy(ringBuf,jpegData+buflen,dataLen-buflen);
}
logd("Copy Video Stream Data ok!\n");
VideoStreamDataInfo DataInfo;
memset(&DataInfo, 0, sizeof(DataInfo));
DataInfo.pData = buf;
DataInfo.nLength = dataLen;
DataInfo.bIsFirstPart = 1;
DataInfo.bIsLastPart = 1;
if (SubmitVideoStreamData(pVideo, &DataInfo, 0))
{
loge("#####Error: Submit Video Stream Data failed!\n");
return 0;
}
logd("Submit Video Stream Data ok!\n");
// step : decode stream now
int endofstream = 0;
int dropBFrameifdelay = 0;
int64_t currenttimeus = 0;
int decodekeyframeonly = 0;
ret = DecodeVideoStream(pVideo, endofstream, decodekeyframeonly,dropBFrameifdelay, currenttimeus);
logd("decoder ret is %d",ret);
switch (ret)
{
case VDECODE_RESULT_KEYFRAME_DECODED:
case VDECODE_RESULT_FRAME_DECODED:
case VDECODE_RESULT_NO_FRAME_BUFFER:
{
ret = ValidPictureNum(pVideo, 0);
if (ret>= 0)
{
videoPicture = RequestPicture(pVideo, 0);
if (videoPicture == NULL){
loge("decoder fail");
return 0;
}
logd("decoder one pic...");
logd("pic nWidth is %d,nHeight is %d",videoPicture->nWidth,videoPicture->nHeight);
VideoFrame jpegData;
jpegData.mWidth = videoPicture->nWidth;
jpegData.mHeight = videoPicture->nHeight;
jpegData.mSize = jpegData.mWidth*jpegData.mWidth*2;
jpegData.mData = (unsigned char*)malloc(jpegData.mSize);
if(jpegData.mData == NULL)
{
return -1;
}
transformPictureMb32ToRGB(memops, videoPicture, jpegData.mData, jpegData.mWidth, jpegData.mHeight);
char path[1024] = "./pic.rgb";
dumpData(path, (uint8_t *)jpegData.mData, jpegData.mWidth * jpegData.mHeight * 2);
sync();
}
else
{
logd("no ValidPictureNum ret is %d",ret);
}
break;
}
case VDECODE_RESULT_OK:
case VDECODE_RESULT_CONTINUE:
case VDECODE_RESULT_NO_BITSTREAM:
case VDECODE_RESULT_RESOLUTION_CHANGE:
case VDECODE_RESULT_UNSUPPORTED:
default:
loge("video decode Error: %d!\n", ret);
return 0;
}
if (jpegData != NULL)
{
free(jpegData);
jpegData = NULL;
}
CdcMemClose(memops);
return 0;
}