1 #include <stdio.h>
2 #include <string.h>
3 #include <rtthread.h>
4 #include "avifile.h"
5 
6 //#define DEBUGINFO
7 
8 AVI_TypeDef AVI_file;
9 
10 #define MAKE_FOURCC(a, b, c, d) ((uint32_t)(d)<<24 | (uint32_t)(c)<<16 | (uint32_t)(b)<<8 | (uint32_t)(a))
11 #define READ_WORD(a) ((uint32_t)*(a)<<24 | (uint32_t)*(a)<<16 | (uint32_t)*(a)<<8 | (uint32_t)*(a))
12 
_REV(uint32_t value)13 static uint32_t _REV(uint32_t value)
14 {
15     return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 |
16            (value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24;
17 }
18 
search_fourcc(uint32_t fourcc,const uint8_t * buffer,uint32_t length)19 static int search_fourcc(uint32_t fourcc, const uint8_t *buffer, uint32_t length)
20 {
21     uint32_t i, j;
22     uint32_t *pdata;
23     j = length - 4;
24     rt_kprintf("movi index:%d\n\n", j);
25     for (i = 0; i < j; i++)
26     {
27         pdata = (uint32_t *)(buffer + i);
28         if (fourcc == *pdata)
29         {
30             rt_kprintf("==>find movi:%#x,%d\n", pdata, i);
31             return i;
32         }
33     }
34     return -1;
35 }
36 
Strl_Parser(const uint8_t * buffer,uint32_t length,uint32_t * list_length)37 static int Strl_Parser(const uint8_t *buffer, uint32_t length, uint32_t *list_length)
38 {
39     /**
40      * TODO: how to deal with the list is not complete in the buffer
41      */
42     const uint8_t *pdata = buffer;
43     // strl(stream list), include "strh" and "strf"
44     AVI_LIST_HEAD *strl = (AVI_LIST_HEAD *)pdata;
45     if (strl->List != LIST_ID || strl->FourCC != strl_ID)
46     {
47         return -1;
48     }
49     pdata += sizeof(AVI_LIST_HEAD);
50     *list_length = strl->size + 8; //return the entire size of list
51 
52     // strh
53     AVI_STRH_CHUNK *strh = (AVI_STRH_CHUNK *)pdata;
54     if (strh->FourCC != strh_ID || strh->size + 8 != sizeof(AVI_STRH_CHUNK))
55     {
56         return -5;
57     }
58 #ifdef DEBUGINFO
59     rt_kprintf("-----strh info------\r\n");
60     rt_kprintf("fourcc_type:0x%x\r\n", strh->fourcc_type);
61     rt_kprintf("fourcc_codec:0x%x\r\n", strh->fourcc_codec);
62     rt_kprintf("flags:%d\r\n", strh->flags);
63     rt_kprintf("Priority:%d\r\n", strh->priority);
64     rt_kprintf("Language:%d\r\n", strh->language);
65     rt_kprintf("InitFrames:%d\r\n", strh->init_frames);
66     rt_kprintf("Scale:%d\r\n", strh->scale);
67     rt_kprintf("Rate:%d\r\n", strh->rate);
68     rt_kprintf("Start:%d\r\n", strh->start);
69     rt_kprintf("Length:%d\r\n", strh->length);
70     rt_kprintf("RefBufSize:%d\r\n", strh->suggest_buff_size);
71     rt_kprintf("Quality:%d\r\n", strh->quality);
72     rt_kprintf("SampleSize:%d\r\n", strh->sample_size);
73     rt_kprintf("FrameLeft:%d\r\n", strh->rcFrame.left);
74     rt_kprintf("FrameTop:%d\r\n", strh->rcFrame.top);
75     rt_kprintf("FrameRight:%d\r\n", strh->rcFrame.right);
76     rt_kprintf("FrameBottom:%d\r\n\n", strh->rcFrame.bottom);
77 #endif
78     pdata += sizeof(AVI_STRH_CHUNK);
79 
80     if (vids_ID == strh->fourcc_type)
81     {
82         rt_kprintf("Find a video stream\n");
83         if (mjpg_ID != strh->fourcc_codec)
84         {
85             rt_kprintf("only support mjpeg decoder, but needed is 0x%x\n", strh->fourcc_codec);
86             return -1;
87         }
88         AVI_VIDS_STRF_CHUNK *strf = (AVI_VIDS_STRF_CHUNK *)pdata;
89         if (strf->FourCC != strf_ID || strf->size + 8 != sizeof(AVI_VIDS_STRF_CHUNK))
90         {
91             return -5;
92         }
93 #ifdef DEBUGINFO
94         rt_kprintf("-----video strf info------\r\n");
95         rt_kprintf("本结构体大小:%d\r\n", strf->size1);
96         rt_kprintf("图像宽:%d\r\n", strf->width);
97         rt_kprintf("图像高:%d\r\n", strf->height);
98         rt_kprintf("平面数:%d\r\n", strf->planes);
99         rt_kprintf("像素位数:%d\r\n", strf->bitcount);
100         rt_kprintf("压缩类型:0x%x\r\n", strf->fourcc_compression);
101         rt_kprintf("图像大小:%d\r\n", strf->image_size);
102         rt_kprintf("水平分辨率:%d\r\n", strf->x_pixels_per_meter);
103         rt_kprintf("垂直分辨率:%d\r\n", strf->y_pixels_per_meter);
104         rt_kprintf("使用调色板颜色数:%d\r\n", strf->num_colors);
105         rt_kprintf("重要颜色:%d\r\n\n", strf->imp_colors);
106 #endif
107         AVI_file.vids_fps = strh->rate / strh->scale;
108         AVI_file.vids_width = strf->width;
109         AVI_file.vids_height = strf->height;
110         pdata += sizeof(AVI_VIDS_STRF_CHUNK);
111 
112     }
113     else if (auds_ID == strh->fourcc_type)
114     {
115         rt_kprintf("Find a audio stream\n");
116         AVI_AUDS_STRF_CHUNK *strf = (AVI_AUDS_STRF_CHUNK *)pdata;
117         if (strf->FourCC != strf_ID || (strf->size + 8 != sizeof(AVI_AUDS_STRF_CHUNK) && strf->size + 10 != sizeof(AVI_AUDS_STRF_CHUNK)))
118         {
119             rt_kprintf("FourCC=0x%x|%x, size=%d|%d\n", strf->FourCC, strf_ID, strf->size, sizeof(AVI_AUDS_STRF_CHUNK));
120             return -5;
121         }
122 #ifdef DEBUGINFO
123         rt_kprintf("-----audio strf info------\r\n");
124         rt_kprintf("strf数据块信息(音频流):");
125         rt_kprintf("格式标志:%d\r\n", strf->format_tag);
126         rt_kprintf("声道数:%d\r\n", strf->channels);
127         rt_kprintf("采样率:%d\r\n", strf->samples_per_sec);
128         rt_kprintf("波特率:%d\r\n", strf->avg_bytes_per_sec);
129         rt_kprintf("块对齐:%d\r\n", strf->block_align);
130         rt_kprintf("采样位宽:%d\r\n\n", (uint8_t)strf->bits_per_sample);
131 #endif
132         AVI_file.auds_channels = strf->channels;
133         AVI_file.auds_sample_rate = strf->samples_per_sec;
134         AVI_file.auds_bits = strf->bits_per_sample;
135         pdata += sizeof(AVI_AUDS_STRF_CHUNK);
136     }
137     else
138     {
139         rt_kprintf("Unsupport stream 0x%x\n", strh->fourcc_type);
140     }
141     return 0;
142 }
143 
AVI_Parser(const uint8_t * buffer,uint32_t length)144 int AVI_Parser(const uint8_t *buffer, uint32_t length)
145 {
146     const uint8_t *pdata = buffer;
147     AVI_LIST_HEAD *riff = (AVI_LIST_HEAD *)pdata;
148     if (riff->List != RIFF_ID || riff->FourCC != AVI_ID)
149     {
150         return -1;
151     }
152     AVI_file.RIFFchunksize = riff->size; //RIFF数据块长度
153     pdata += sizeof(AVI_LIST_HEAD);
154 
155     AVI_LIST_HEAD *list = (AVI_LIST_HEAD *)pdata;
156     if (list->List != LIST_ID || list->FourCC != hdrl_ID)
157     {
158         return -3;
159     }
160     AVI_file.LISTchunksize = list->size; //LIST数据块长度
161     pdata += sizeof(AVI_LIST_HEAD);
162 
163     // avih chunk
164     AVI_AVIH_CHUNK *avih = (AVI_AVIH_CHUNK *)pdata;
165     if (avih->FourCC != avih_ID || avih->size + 8 != sizeof(AVI_AVIH_CHUNK))
166     {
167         return -5;
168     }
169     AVI_file.avihsize = avih->size; //avih数据块长度
170 
171     AVI_file.avi_hd.avih.us_per_frame = avih->us_per_frame;
172     AVI_file.avi_hd.avih.max_bytes_per_sec = avih->max_bytes_per_sec;
173     AVI_file.avi_hd.avih.total_frames = avih->total_frames;
174     AVI_file.avi_hd.avih.init_frames = avih->init_frames;
175 
176 #ifdef DEBUGINFO
177     rt_kprintf("\r\n-----avih info------\r\n");
178     rt_kprintf("显示一帧所需时间:%dus\r\n", avih->us_per_frame);
179     rt_kprintf("最大数据传输率:%d\r\n", avih->max_bytes_per_sec);
180     rt_kprintf("视频总帧数:%d\r\n", avih->total_frames);
181     rt_kprintf("开始播放前需要帧数:%d\r\n", avih->init_frames);
182     rt_kprintf("数据流个数:%d\r\n", avih->streams);
183     rt_kprintf("缓冲区的大小:%d\r\n", avih->suggest_buff_size);
184     rt_kprintf("主窗口宽度:%d\r\n", avih->width);
185     rt_kprintf("主窗口高度:%d\r\n\n", avih->height);
186 #endif
187     if ((avih->width > 800) || (avih->height > 480))
188     {
189         rt_kprintf("The size of video is too large\n");
190         return -6;    //视频尺寸不支持
191     }
192     pdata += sizeof(AVI_AVIH_CHUNK);
193 
194     // process all streams in turn
195     for (size_t i = 0; i < avih->streams; i++)
196     {
197         uint32_t strl_size = 0;
198         int ret = Strl_Parser(pdata, length - (pdata - buffer), &strl_size);
199         if (0 > ret)
200         {
201             rt_kprintf("strl of stream%d prase failed\n", i);
202             break;
203             /**
204              * TODO: how to deal this error? maybe we should search for the next strl.
205              */
206         }
207         pdata += strl_size;
208     }
209 
210     rt_kprintf("MAKE_FOURCC:%d\n\n", MAKE_FOURCC('m', 'o', 'v', 'i'));
211     int movi_offset = search_fourcc(MAKE_FOURCC('m', 'o', 'v', 'i'), pdata, length - (pdata - buffer));
212     if (0 > movi_offset)
213     {
214         rt_kprintf("can't find \"movi\" list\n");
215         return -7;
216     }
217     AVI_file.movi_start = movi_offset + 4  + pdata - buffer;
218     pdata += movi_offset - 8; // back to the list head
219     AVI_LIST_HEAD *movi = (AVI_LIST_HEAD *)pdata;
220     if (movi->List != LIST_ID || movi->FourCC != movi_ID)
221     {
222         return -8;
223     }
224     AVI_file.movi_size = movi->size; //LIST数据块长度
225     pdata += sizeof(AVI_LIST_HEAD);
226     rt_kprintf("movi pos:%d, size:%d\n", AVI_file.movi_start, AVI_file.movi_size);
227 
228     return 0;
229 }
230