rt-thread-official/bsp/renesas/ra6m3-hmi-board/board/ports/avi/avifile.c

230 lines
8.2 KiB
C

#include <stdio.h>
#include <string.h>
#include <rtthread.h>
#include "avifile.h"
//#define DEBUGINFO
AVI_TypeDef AVI_file;
#define MAKE_FOURCC(a, b, c, d) ((uint32_t)(d)<<24 | (uint32_t)(c)<<16 | (uint32_t)(b)<<8 | (uint32_t)(a))
#define READ_WORD(a) ((uint32_t)*(a)<<24 | (uint32_t)*(a)<<16 | (uint32_t)*(a)<<8 | (uint32_t)*(a))
static uint32_t _REV(uint32_t value)
{
return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 |
(value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24;
}
static int search_fourcc(uint32_t fourcc, const uint8_t *buffer, uint32_t length)
{
uint32_t i, j;
uint32_t *pdata;
j = length - 4;
rt_kprintf("movi index:%d\n\n", j);
for (i = 0; i < j; i++)
{
pdata = (uint32_t *)(buffer + i);
if (fourcc == *pdata)
{
rt_kprintf("==>find movi:%#x,%d\n", pdata, i);
return i;
}
}
return -1;
}
static int Strl_Parser(const uint8_t *buffer, uint32_t length, uint32_t *list_length)
{
/**
* TODO: how to deal with the list is not complete in the buffer
*/
const uint8_t *pdata = buffer;
// strl(stream list), include "strh" and "strf"
AVI_LIST_HEAD *strl = (AVI_LIST_HEAD *)pdata;
if (strl->List != LIST_ID || strl->FourCC != strl_ID)
{
return -1;
}
pdata += sizeof(AVI_LIST_HEAD);
*list_length = strl->size + 8; //return the entire size of list
// strh
AVI_STRH_CHUNK *strh = (AVI_STRH_CHUNK *)pdata;
if (strh->FourCC != strh_ID || strh->size + 8 != sizeof(AVI_STRH_CHUNK))
{
return -5;
}
#ifdef DEBUGINFO
rt_kprintf("-----strh info------\r\n");
rt_kprintf("fourcc_type:0x%x\r\n", strh->fourcc_type);
rt_kprintf("fourcc_codec:0x%x\r\n", strh->fourcc_codec);
rt_kprintf("flags:%d\r\n", strh->flags);
rt_kprintf("Priority:%d\r\n", strh->priority);
rt_kprintf("Language:%d\r\n", strh->language);
rt_kprintf("InitFrames:%d\r\n", strh->init_frames);
rt_kprintf("Scale:%d\r\n", strh->scale);
rt_kprintf("Rate:%d\r\n", strh->rate);
rt_kprintf("Start:%d\r\n", strh->start);
rt_kprintf("Length:%d\r\n", strh->length);
rt_kprintf("RefBufSize:%d\r\n", strh->suggest_buff_size);
rt_kprintf("Quality:%d\r\n", strh->quality);
rt_kprintf("SampleSize:%d\r\n", strh->sample_size);
rt_kprintf("FrameLeft:%d\r\n", strh->rcFrame.left);
rt_kprintf("FrameTop:%d\r\n", strh->rcFrame.top);
rt_kprintf("FrameRight:%d\r\n", strh->rcFrame.right);
rt_kprintf("FrameBottom:%d\r\n\n", strh->rcFrame.bottom);
#endif
pdata += sizeof(AVI_STRH_CHUNK);
if (vids_ID == strh->fourcc_type)
{
rt_kprintf("Find a video stream\n");
if (mjpg_ID != strh->fourcc_codec)
{
rt_kprintf("only support mjpeg decoder, but needed is 0x%x\n", strh->fourcc_codec);
return -1;
}
AVI_VIDS_STRF_CHUNK *strf = (AVI_VIDS_STRF_CHUNK *)pdata;
if (strf->FourCC != strf_ID || strf->size + 8 != sizeof(AVI_VIDS_STRF_CHUNK))
{
return -5;
}
#ifdef DEBUGINFO
rt_kprintf("-----video strf info------\r\n");
rt_kprintf("本结构体大小:%d\r\n", strf->size1);
rt_kprintf("图像宽:%d\r\n", strf->width);
rt_kprintf("图像高:%d\r\n", strf->height);
rt_kprintf("平面数:%d\r\n", strf->planes);
rt_kprintf("像素位数:%d\r\n", strf->bitcount);
rt_kprintf("压缩类型:0x%x\r\n", strf->fourcc_compression);
rt_kprintf("图像大小:%d\r\n", strf->image_size);
rt_kprintf("水平分辨率:%d\r\n", strf->x_pixels_per_meter);
rt_kprintf("垂直分辨率:%d\r\n", strf->y_pixels_per_meter);
rt_kprintf("使用调色板颜色数:%d\r\n", strf->num_colors);
rt_kprintf("重要颜色:%d\r\n\n", strf->imp_colors);
#endif
AVI_file.vids_fps = strh->rate / strh->scale;
AVI_file.vids_width = strf->width;
AVI_file.vids_height = strf->height;
pdata += sizeof(AVI_VIDS_STRF_CHUNK);
}
else if (auds_ID == strh->fourcc_type)
{
rt_kprintf("Find a audio stream\n");
AVI_AUDS_STRF_CHUNK *strf = (AVI_AUDS_STRF_CHUNK *)pdata;
if (strf->FourCC != strf_ID || (strf->size + 8 != sizeof(AVI_AUDS_STRF_CHUNK) && strf->size + 10 != sizeof(AVI_AUDS_STRF_CHUNK)))
{
rt_kprintf("FourCC=0x%x|%x, size=%d|%d\n", strf->FourCC, strf_ID, strf->size, sizeof(AVI_AUDS_STRF_CHUNK));
return -5;
}
#ifdef DEBUGINFO
rt_kprintf("-----audio strf info------\r\n");
rt_kprintf("strf数据块信息(音频流):");
rt_kprintf("格式标志:%d\r\n", strf->format_tag);
rt_kprintf("声道数:%d\r\n", strf->channels);
rt_kprintf("采样率:%d\r\n", strf->samples_per_sec);
rt_kprintf("波特率:%d\r\n", strf->avg_bytes_per_sec);
rt_kprintf("块对齐:%d\r\n", strf->block_align);
rt_kprintf("采样位宽:%d\r\n\n", (uint8_t)strf->bits_per_sample);
#endif
AVI_file.auds_channels = strf->channels;
AVI_file.auds_sample_rate = strf->samples_per_sec;
AVI_file.auds_bits = strf->bits_per_sample;
pdata += sizeof(AVI_AUDS_STRF_CHUNK);
}
else
{
rt_kprintf("Unsupport stream 0x%x\n", strh->fourcc_type);
}
return 0;
}
int AVI_Parser(const uint8_t *buffer, uint32_t length)
{
const uint8_t *pdata = buffer;
AVI_LIST_HEAD *riff = (AVI_LIST_HEAD *)pdata;
if (riff->List != RIFF_ID || riff->FourCC != AVI_ID)
{
return -1;
}
AVI_file.RIFFchunksize = riff->size; //RIFF数据块长度
pdata += sizeof(AVI_LIST_HEAD);
AVI_LIST_HEAD *list = (AVI_LIST_HEAD *)pdata;
if (list->List != LIST_ID || list->FourCC != hdrl_ID)
{
return -3;
}
AVI_file.LISTchunksize = list->size; //LIST数据块长度
pdata += sizeof(AVI_LIST_HEAD);
// avih chunk
AVI_AVIH_CHUNK *avih = (AVI_AVIH_CHUNK *)pdata;
if (avih->FourCC != avih_ID || avih->size + 8 != sizeof(AVI_AVIH_CHUNK))
{
return -5;
}
AVI_file.avihsize = avih->size; //avih数据块长度
AVI_file.avi_hd.avih.us_per_frame = avih->us_per_frame;
AVI_file.avi_hd.avih.max_bytes_per_sec = avih->max_bytes_per_sec;
AVI_file.avi_hd.avih.total_frames = avih->total_frames;
AVI_file.avi_hd.avih.init_frames = avih->init_frames;
#ifdef DEBUGINFO
rt_kprintf("\r\n-----avih info------\r\n");
rt_kprintf("显示一帧所需时间:%dus\r\n", avih->us_per_frame);
rt_kprintf("最大数据传输率:%d\r\n", avih->max_bytes_per_sec);
rt_kprintf("视频总帧数:%d\r\n", avih->total_frames);
rt_kprintf("开始播放前需要帧数:%d\r\n", avih->init_frames);
rt_kprintf("数据流个数:%d\r\n", avih->streams);
rt_kprintf("缓冲区的大小:%d\r\n", avih->suggest_buff_size);
rt_kprintf("主窗口宽度:%d\r\n", avih->width);
rt_kprintf("主窗口高度:%d\r\n\n", avih->height);
#endif
if ((avih->width > 800) || (avih->height > 480))
{
rt_kprintf("The size of video is too large\n");
return -6; //视频尺寸不支持
}
pdata += sizeof(AVI_AVIH_CHUNK);
// process all streams in turn
for (size_t i = 0; i < avih->streams; i++)
{
uint32_t strl_size = 0;
int ret = Strl_Parser(pdata, length - (pdata - buffer), &strl_size);
if (0 > ret)
{
rt_kprintf("strl of stream%d prase failed\n", i);
break;
/**
* TODO: how to deal this error? maybe we should search for the next strl.
*/
}
pdata += strl_size;
}
rt_kprintf("MAKE_FOURCC:%d\n\n", MAKE_FOURCC('m', 'o', 'v', 'i'));
int movi_offset = search_fourcc(MAKE_FOURCC('m', 'o', 'v', 'i'), pdata, length - (pdata - buffer));
if (0 > movi_offset)
{
rt_kprintf("can't find \"movi\" list\n");
return -7;
}
AVI_file.movi_start = movi_offset + 4 + pdata - buffer;
pdata += movi_offset - 8; // back to the list head
AVI_LIST_HEAD *movi = (AVI_LIST_HEAD *)pdata;
if (movi->List != LIST_ID || movi->FourCC != movi_ID)
{
return -8;
}
AVI_file.movi_size = movi->size; //LIST数据块长度
pdata += sizeof(AVI_LIST_HEAD);
rt_kprintf("movi pos:%d, size:%d\n", AVI_file.movi_start, AVI_file.movi_size);
return 0;
}