Mercurial > mplayer.hg
comparison libmpdemux/demux_lmlm4.c @ 11590:0908285ada31
LML-M4 mpeg4 capture card raw stream format support
original code by Maxim Yevtyushkin <max@linuxmedialabs.com>
partially rewritten, "mplayerized" by me
author | arpi |
---|---|
date | Mon, 08 Dec 2003 19:33:38 +0000 |
parents | |
children | 10b4938a2818 |
comparison
equal
deleted
inserted
replaced
11589:5cff0d11b47b | 11590:0908285ada31 |
---|---|
1 /* | |
2 LMLM4 MPEG4 Compression Card stream & file parser by Maxim Yevtyushkin <max@linuxmedialabs.com> | |
3 Based on SMJPEG file parser by Alex Beregszaszi | |
4 | |
5 */ | |
6 | |
7 #include <stdio.h> | |
8 #include <stdlib.h> | |
9 #include <unistd.h> | |
10 #include <string.h> /* strtok */ | |
11 | |
12 #include "config.h" | |
13 #include "mp_msg.h" | |
14 #include "help_mp.h" | |
15 | |
16 #include "stream.h" | |
17 #include "demuxer.h" | |
18 #include "stheader.h" | |
19 #include "bswap.h" | |
20 | |
21 typedef struct __FrameInfo | |
22 { | |
23 ssize_t frameSize; | |
24 ssize_t paddingSize; | |
25 int frameType; | |
26 int channelNo; | |
27 } FrameInfo; | |
28 | |
29 #define FRAMETYPE_I 0 | |
30 #define FRAMETYPE_P 1 | |
31 #define FRAMETYPE_B 2 | |
32 #define FRAMETYPE_AUDIO_MPEG1L2 4 | |
33 #define FRAMETYPE_AUDIO_ULAW 5 | |
34 #define FRAMETYPE_AUDIO_ADPCM 6 | |
35 | |
36 #define PACKET_BLOCK_SIZE 0x00000200 | |
37 #define PACKET_BLOCK_LAST 0x000001FF | |
38 #define PACKET_BLOCK_MASK 0xFFFFFE00 | |
39 | |
40 #define MAX_PACKET_SIZE 1048576 // 1 Mb | |
41 | |
42 #define STREAM_START_CODE_SIZE 4 | |
43 | |
44 /* | |
45 // codes in MSB first | |
46 static unsigned int start_code [] = | |
47 { | |
48 0xB0010000, // VISUAL_OBJECT_SEQUENCE_START_CODE | |
49 0xB6010000, // VOP_START_CODE | |
50 0x04C4FDFF, // MPEG1LAYERII_START_CODE | |
51 0x00000000 // end of start codes list | |
52 }; | |
53 */ | |
54 | |
55 static int imeHeaderValid(FrameInfo *frame) | |
56 { | |
57 if ( frame->channelNo > 7 || | |
58 frame->frameSize > MAX_PACKET_SIZE || frame->frameSize <= 0) | |
59 { | |
60 mp_msg(MSGT_DEMUX, MSGL_V, "Invalid packet in LMLM4 stream: ch=%d size=%d\n", frame->channelNo, frame->frameSize); | |
61 return 0; | |
62 } | |
63 switch (frame->frameType) { | |
64 case FRAMETYPE_I: | |
65 case FRAMETYPE_P: | |
66 case FRAMETYPE_B: | |
67 case FRAMETYPE_AUDIO_MPEG1L2: | |
68 case FRAMETYPE_AUDIO_ULAW: | |
69 case FRAMETYPE_AUDIO_ADPCM: | |
70 break; | |
71 default: | |
72 mp_msg(MSGT_DEMUX, MSGL_V, "Invalid packet in LMLM4 stream (wrong packet type %d)\n", frame->frameType); | |
73 return 0; | |
74 } | |
75 return 1; | |
76 } | |
77 | |
78 /* | |
79 int searchMPEG4Stream(demuxer_t* demuxer, IME6400Header *imeHeader) | |
80 { | |
81 void *data; | |
82 ssize_t imeHeaderSize = sizeof(IME6400Header); | |
83 ssize_t dataSize = sizeof(IME6400Header) * 3; | |
84 ssize_t ptr = imeHeaderSize * 2; | |
85 int errNo, startCodeNo; | |
86 off_t pos; | |
87 | |
88 data = malloc(dataSize); | |
89 | |
90 imeHeaderSwap(imeHeader); | |
91 memcpy(data + imeHeaderSize, imeHeader, imeHeaderSize); | |
92 | |
93 // printHex(data + imeHeaderSize, imeHeaderSize); | |
94 | |
95 while ((errNo = stream_read(demuxer->stream, data + imeHeaderSize * 2 , imeHeaderSize)) == imeHeaderSize) | |
96 { | |
97 // printHex(data + imeHeaderSize * 2, imeHeaderSize); | |
98 | |
99 pos = stream_tell(demuxer->stream); | |
100 while (dataSize - ptr >= STREAM_START_CODE_SIZE) { | |
101 startCodeNo = 0; | |
102 while (start_code[startCodeNo]) | |
103 { | |
104 if (memcmp(&start_code[startCodeNo], data + ptr, STREAM_START_CODE_SIZE) == 0) // start code match | |
105 { | |
106 memcpy(imeHeader, data + ptr - imeHeaderSize, imeHeaderSize); | |
107 imeHeaderSwap(imeHeader); | |
108 if (imeHeaderValid(imeHeader)) | |
109 { | |
110 stream_seek(demuxer->stream, pos - (dataSize - ptr)); | |
111 free(data); | |
112 return 0; | |
113 } | |
114 } | |
115 startCodeNo++; | |
116 } | |
117 ptr++; | |
118 } | |
119 memcpy(data,data + imeHeaderSize, imeHeaderSize * 2); | |
120 ptr -= imeHeaderSize; | |
121 } | |
122 | |
123 free(data); | |
124 return errNo; | |
125 } | |
126 */ | |
127 | |
128 static int getFrame(demuxer_t *demuxer, FrameInfo *frameInfo) | |
129 { | |
130 int retCode; | |
131 unsigned int packetSize; | |
132 | |
133 frameInfo->channelNo = stream_read_word(demuxer->stream); | |
134 frameInfo->frameType = stream_read_word(demuxer->stream); | |
135 packetSize=stream_read_dword(demuxer->stream); | |
136 | |
137 if(stream_eof(demuxer->stream)){ | |
138 frameInfo->frameSize = 0; | |
139 return 0; | |
140 } | |
141 | |
142 frameInfo->frameSize = packetSize - 8; //sizeof(IME6400Header); | |
143 frameInfo->paddingSize = (packetSize & PACKET_BLOCK_LAST) ? PACKET_BLOCK_SIZE - (packetSize & PACKET_BLOCK_LAST) : 0; | |
144 | |
145 mp_msg(MSGT_DEMUX, MSGL_DBG2, "typ: %d chan: %d size: %d pad: %d\n", | |
146 frameInfo->frameType, | |
147 frameInfo->channelNo, | |
148 frameInfo->frameSize, | |
149 frameInfo->paddingSize); | |
150 | |
151 if(!imeHeaderValid(frameInfo)){ | |
152 // skip this packet | |
153 stream_skip(demuxer->stream,PACKET_BLOCK_SIZE-8); | |
154 frameInfo->frameSize = 0; | |
155 return -1; | |
156 } | |
157 | |
158 return 1; | |
159 } | |
160 | |
161 int lmlm4_check_file(demuxer_t* demuxer) | |
162 { | |
163 FrameInfo frameInfo; | |
164 unsigned int first; | |
165 | |
166 mp_msg(MSGT_DEMUX, MSGL_V, "Checking for LMLM4 Stream Format\n"); | |
167 | |
168 if(getFrame(demuxer, &frameInfo)!=1){ | |
169 stream_skip(demuxer->stream,-8); | |
170 mp_msg(MSGT_DEMUX, MSGL_INFO, "LMLM4 Stream Format not found\n"); | |
171 return 0; | |
172 } | |
173 first=stream_read_dword(demuxer->stream); | |
174 stream_skip(demuxer->stream,-12); | |
175 | |
176 mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: first=0x%08X\n",first); | |
177 | |
178 switch(frameInfo.frameType){ | |
179 case FRAMETYPE_AUDIO_MPEG1L2: | |
180 if( (first & 0xffe00000) != 0xffe00000 ){ | |
181 mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: not mpeg audio\n"); | |
182 return 0; | |
183 } | |
184 if((4-((first>>17)&3))!=2){ | |
185 mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: not layer-2\n"); | |
186 return 0; | |
187 } | |
188 if(((first>>10)&0x3)==3){ | |
189 mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: invalid audio sampelrate\n"); | |
190 return 0; | |
191 } | |
192 mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: first packet is audio, header checks OK!\n"); | |
193 break; | |
194 // TODO: add checks for video header too, for case of disabled audio | |
195 } | |
196 | |
197 | |
198 // stream_reset(demuxer->stream); | |
199 mp_msg(MSGT_DEMUX, MSGL_V, "LMLM4 Stream Format found\n"); | |
200 | |
201 return 1; | |
202 } | |
203 | |
204 static int video = 0; | |
205 static int frames= 0; | |
206 | |
207 // return value: | |
208 // 0 = EOF or no stream found | |
209 // 1 = successfully read a packet | |
210 int demux_lmlm4_fill_buffer(demuxer_t *demux) | |
211 { | |
212 FrameInfo frameInfo; | |
213 double pts; | |
214 int id=1; | |
215 int ret; | |
216 | |
217 hdr: | |
218 demux->filepos = stream_tell(demux->stream); | |
219 mp_msg(MSGT_DEMUX, MSGL_DBG2, "fpos = %d\n", demux->filepos); | |
220 | |
221 ret=getFrame(demux, &frameInfo); | |
222 if(ret<=0) return ret; // EOF/error | |
223 | |
224 pts=demux->video->sh ? frames*((sh_video_t*)(demux->video->sh))->frametime : 0; | |
225 | |
226 switch(frameInfo.frameType){ | |
227 case FRAMETYPE_AUDIO_MPEG1L2: | |
228 mp_dbg(MSGT_DEMUX, MSGL_DBG2, "Audio Packet\n"); | |
229 if (!video) | |
230 { | |
231 stream_skip(demux->stream, frameInfo.frameSize + frameInfo.paddingSize); | |
232 mp_msg(MSGT_DEMUX, MSGL_V, "Skip Audio Packet\n"); | |
233 return -1; //goto hdr; | |
234 } | |
235 if(demux->audio->id==-1){ | |
236 if(!demux->a_streams[id]) new_sh_audio(demux,id); | |
237 demux->audio->id=id; | |
238 demux->audio->sh=demux->a_streams[id]; | |
239 ((sh_audio_t*)(demux->audio->sh))->format=0x50; // mpeg audio layer 1/2 | |
240 } | |
241 if(demux->audio->id==id) | |
242 ds_read_packet(demux->audio, demux->stream, frameInfo.frameSize, | |
243 pts, demux->filepos, 0); | |
244 else | |
245 stream_skip(demux->stream,frameInfo.frameSize); | |
246 break; | |
247 case FRAMETYPE_I: | |
248 if (!video) { | |
249 video = 1; | |
250 mp_dbg(MSGT_DEMUX, MSGL_DBG2, "First Video Packet\n"); | |
251 } | |
252 case FRAMETYPE_P: | |
253 frames=(frames+1)&(1024*1024-1); // wrap around at 4 hrs to avoid inaccurate float calculations | |
254 if (!video) | |
255 { | |
256 stream_skip(demux->stream, frameInfo.frameSize + frameInfo.paddingSize); | |
257 mp_msg(MSGT_DEMUX, MSGL_V, "Skip Video P Packet\n"); | |
258 return -1; //goto hdr; | |
259 } | |
260 mp_dbg(MSGT_DEMUX, MSGL_DBG2, "Video Packet\n"); | |
261 if(demux->video->id==-1){ | |
262 if(!demux->v_streams[id]) new_sh_video(demux,id); | |
263 demux->video->id=id; | |
264 demux->video->sh=demux->v_streams[id]; | |
265 ((sh_video_t*)(demux->video->sh))->format=0x10000004; // mpeg4-ES | |
266 } | |
267 if(demux->video->id==id) | |
268 ds_read_packet(demux->video, demux->stream, frameInfo.frameSize, | |
269 pts, demux->filepos, 0); | |
270 break; | |
271 default: | |
272 stream_skip(demux->stream,frameInfo.frameSize); | |
273 } | |
274 | |
275 stream_skip(demux->stream, frameInfo.paddingSize); | |
276 | |
277 return 1; | |
278 } | |
279 | |
280 int demux_open_lmlm4(demuxer_t* demuxer){ | |
281 | |
282 #if 0 | |
283 sh_video_t* sh_video; | |
284 sh_audio_t* sh_audio; | |
285 unsigned int htype = 0, hleng; | |
286 int i = 0; | |
287 | |
288 sh_video = new_sh_video(demuxer, 0); | |
289 demuxer->video->sh = sh_video; | |
290 sh_video->ds = demuxer->video; | |
291 sh_video->disp_w = 640; | |
292 sh_video->disp_h = 480; | |
293 sh_video->format = mmioFOURCC('D','I','V','X'); | |
294 | |
295 sh_video->bih = malloc(sizeof(BITMAPINFOHEADER)); | |
296 memset(sh_video->bih, 0, sizeof(BITMAPINFOHEADER)); | |
297 | |
298 /* these are false values */ | |
299 sh_video->bih->biSize = 40; | |
300 sh_video->bih->biWidth = sh_video->disp_w; | |
301 sh_video->bih->biHeight = sh_video->disp_h; | |
302 sh_video->bih->biPlanes = 3; | |
303 sh_video->bih->biBitCount = 16; | |
304 sh_video->bih->biCompression = sh_video->format; | |
305 sh_video->bih->biSizeImage = sh_video->disp_w*sh_video->disp_h; | |
306 | |
307 sh_audio = new_sh_audio(demuxer, 0); | |
308 demuxer->audio->sh = sh_audio; | |
309 sh_audio->ds = demuxer->audio; | |
310 | |
311 sh_audio->wf = malloc(sizeof(WAVEFORMATEX)); | |
312 memset(sh_audio->wf, 0, sizeof(WAVEFORMATEX)); | |
313 | |
314 sh_audio->samplerate = 48000; | |
315 sh_audio->wf->wBitsPerSample = 16; | |
316 sh_audio->channels = 2; | |
317 sh_audio->format = 0x50; | |
318 sh_audio->wf->wFormatTag = sh_audio->format; | |
319 sh_audio->wf->nChannels = sh_audio->channels; | |
320 sh_audio->wf->nSamplesPerSec = sh_audio->samplerate; | |
321 sh_audio->wf->nAvgBytesPerSec = sh_audio->wf->nChannels* | |
322 sh_audio->wf->wBitsPerSample*sh_audio->wf->nSamplesPerSec/8; | |
323 sh_audio->wf->nBlockAlign = sh_audio->channels *2; | |
324 sh_audio->wf->cbSize = 0; | |
325 | |
326 #endif | |
327 | |
328 demuxer->seekable = 0; | |
329 | |
330 | |
331 | |
332 return 1; | |
333 } | |
334 | |
335 void demux_close_lmlm4(demuxer_t *demuxer) | |
336 { | |
337 // printf("Close LMLM4 Stream\n"); | |
338 return; | |
339 } |