#include #include #include #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; }