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