Mercurial > mplayer.hg
annotate libmpdemux/demux_lmlm4.c @ 25840:1fb0ef174cb1
Add QDM2 codec identifier
author | reimar |
---|---|
date | Sat, 26 Jan 2008 21:41:30 +0000 |
parents | d4fe6e23283e |
children | d643e4643313 |
rev | line source |
---|---|
11590 | 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 | |
22605
4d81dbdf46b9
Add explicit location for headers from the stream/ directory.
diego
parents:
21421
diff
changeset
|
16 #include "stream/stream.h" |
11590 | 17 #include "demuxer.h" |
18 #include "stheader.h" | |
19 | |
25607
9d0b189ce1b2
Fix illegal identifiers: Names starting with __ or _ and uppercase are reserved
diego
parents:
24357
diff
changeset
|
20 typedef struct FrameInfo |
11590 | 21 { |
22 ssize_t frameSize; | |
23 ssize_t paddingSize; | |
24 int frameType; | |
25 int channelNo; | |
26 } FrameInfo; | |
27 | |
28 #define FRAMETYPE_I 0 | |
29 #define FRAMETYPE_P 1 | |
30 #define FRAMETYPE_B 2 | |
31 #define FRAMETYPE_AUDIO_MPEG1L2 4 | |
32 #define FRAMETYPE_AUDIO_ULAW 5 | |
33 #define FRAMETYPE_AUDIO_ADPCM 6 | |
34 | |
35 #define PACKET_BLOCK_SIZE 0x00000200 | |
36 #define PACKET_BLOCK_LAST 0x000001FF | |
37 #define PACKET_BLOCK_MASK 0xFFFFFE00 | |
38 | |
39 #define MAX_PACKET_SIZE 1048576 // 1 Mb | |
40 | |
41 #define STREAM_START_CODE_SIZE 4 | |
42 | |
43 /* | |
44 // codes in MSB first | |
45 static unsigned int start_code [] = | |
46 { | |
47 0xB0010000, // VISUAL_OBJECT_SEQUENCE_START_CODE | |
48 0xB6010000, // VOP_START_CODE | |
49 0x04C4FDFF, // MPEG1LAYERII_START_CODE | |
50 0x00000000 // end of start codes list | |
51 }; | |
52 */ | |
53 | |
54 static int imeHeaderValid(FrameInfo *frame) | |
55 { | |
56 if ( frame->channelNo > 7 || | |
57 frame->frameSize > MAX_PACKET_SIZE || frame->frameSize <= 0) | |
58 { | |
59 mp_msg(MSGT_DEMUX, MSGL_V, "Invalid packet in LMLM4 stream: ch=%d size=%d\n", frame->channelNo, frame->frameSize); | |
60 return 0; | |
61 } | |
62 switch (frame->frameType) { | |
63 case FRAMETYPE_I: | |
64 case FRAMETYPE_P: | |
65 case FRAMETYPE_B: | |
66 case FRAMETYPE_AUDIO_MPEG1L2: | |
67 case FRAMETYPE_AUDIO_ULAW: | |
68 case FRAMETYPE_AUDIO_ADPCM: | |
69 break; | |
70 default: | |
71 mp_msg(MSGT_DEMUX, MSGL_V, "Invalid packet in LMLM4 stream (wrong packet type %d)\n", frame->frameType); | |
72 return 0; | |
73 } | |
74 return 1; | |
75 } | |
76 | |
77 /* | |
78 int searchMPEG4Stream(demuxer_t* demuxer, IME6400Header *imeHeader) | |
79 { | |
80 void *data; | |
81 ssize_t imeHeaderSize = sizeof(IME6400Header); | |
82 ssize_t dataSize = sizeof(IME6400Header) * 3; | |
83 ssize_t ptr = imeHeaderSize * 2; | |
84 int errNo, startCodeNo; | |
85 off_t pos; | |
86 | |
87 data = malloc(dataSize); | |
88 | |
89 imeHeaderSwap(imeHeader); | |
90 memcpy(data + imeHeaderSize, imeHeader, imeHeaderSize); | |
91 | |
92 // printHex(data + imeHeaderSize, imeHeaderSize); | |
93 | |
94 while ((errNo = stream_read(demuxer->stream, data + imeHeaderSize * 2 , imeHeaderSize)) == imeHeaderSize) | |
95 { | |
96 // printHex(data + imeHeaderSize * 2, imeHeaderSize); | |
97 | |
98 pos = stream_tell(demuxer->stream); | |
99 while (dataSize - ptr >= STREAM_START_CODE_SIZE) { | |
100 startCodeNo = 0; | |
101 while (start_code[startCodeNo]) | |
102 { | |
103 if (memcmp(&start_code[startCodeNo], data + ptr, STREAM_START_CODE_SIZE) == 0) // start code match | |
104 { | |
105 memcpy(imeHeader, data + ptr - imeHeaderSize, imeHeaderSize); | |
106 imeHeaderSwap(imeHeader); | |
107 if (imeHeaderValid(imeHeader)) | |
108 { | |
109 stream_seek(demuxer->stream, pos - (dataSize - ptr)); | |
110 free(data); | |
111 return 0; | |
112 } | |
113 } | |
114 startCodeNo++; | |
115 } | |
116 ptr++; | |
117 } | |
118 memcpy(data,data + imeHeaderSize, imeHeaderSize * 2); | |
119 ptr -= imeHeaderSize; | |
120 } | |
121 | |
122 free(data); | |
123 return errNo; | |
124 } | |
125 */ | |
126 | |
127 static int getFrame(demuxer_t *demuxer, FrameInfo *frameInfo) | |
128 { | |
129 unsigned int packetSize; | |
130 | |
131 frameInfo->channelNo = stream_read_word(demuxer->stream); | |
132 frameInfo->frameType = stream_read_word(demuxer->stream); | |
133 packetSize=stream_read_dword(demuxer->stream); | |
134 | |
135 if(stream_eof(demuxer->stream)){ | |
136 frameInfo->frameSize = 0; | |
137 return 0; | |
138 } | |
139 | |
140 frameInfo->frameSize = packetSize - 8; //sizeof(IME6400Header); | |
141 frameInfo->paddingSize = (packetSize & PACKET_BLOCK_LAST) ? PACKET_BLOCK_SIZE - (packetSize & PACKET_BLOCK_LAST) : 0; | |
142 | |
143 mp_msg(MSGT_DEMUX, MSGL_DBG2, "typ: %d chan: %d size: %d pad: %d\n", | |
144 frameInfo->frameType, | |
145 frameInfo->channelNo, | |
146 frameInfo->frameSize, | |
147 frameInfo->paddingSize); | |
148 | |
149 if(!imeHeaderValid(frameInfo)){ | |
150 // skip this packet | |
151 stream_skip(demuxer->stream,PACKET_BLOCK_SIZE-8); | |
152 frameInfo->frameSize = 0; | |
153 return -1; | |
154 } | |
155 | |
156 return 1; | |
157 } | |
158 | |
16175 | 159 static int lmlm4_check_file(demuxer_t* demuxer) |
11590 | 160 { |
161 FrameInfo frameInfo; | |
162 unsigned int first; | |
163 | |
164 mp_msg(MSGT_DEMUX, MSGL_V, "Checking for LMLM4 Stream Format\n"); | |
165 | |
166 if(getFrame(demuxer, &frameInfo)!=1){ | |
167 stream_skip(demuxer->stream,-8); | |
11790 | 168 mp_msg(MSGT_DEMUX, MSGL_V, "LMLM4 Stream Format not found\n"); |
11590 | 169 return 0; |
170 } | |
171 first=stream_read_dword(demuxer->stream); | |
172 stream_skip(demuxer->stream,-12); | |
173 | |
174 mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: first=0x%08X\n",first); | |
175 | |
176 switch(frameInfo.frameType){ | |
177 case FRAMETYPE_AUDIO_MPEG1L2: | |
178 if( (first & 0xffe00000) != 0xffe00000 ){ | |
179 mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: not mpeg audio\n"); | |
180 return 0; | |
181 } | |
182 if((4-((first>>17)&3))!=2){ | |
183 mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: not layer-2\n"); | |
184 return 0; | |
185 } | |
186 if(((first>>10)&0x3)==3){ | |
187 mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: invalid audio sampelrate\n"); | |
188 return 0; | |
189 } | |
190 mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: first packet is audio, header checks OK!\n"); | |
191 break; | |
192 // TODO: add checks for video header too, for case of disabled audio | |
193 } | |
194 | |
195 | |
196 // stream_reset(demuxer->stream); | |
197 mp_msg(MSGT_DEMUX, MSGL_V, "LMLM4 Stream Format found\n"); | |
198 | |
16175 | 199 return DEMUXER_TYPE_LMLM4; |
11590 | 200 } |
201 | |
202 static int video = 0; | |
203 static int frames= 0; | |
204 | |
205 // return value: | |
206 // 0 = EOF or no stream found | |
207 // 1 = successfully read a packet | |
16175 | 208 static int demux_lmlm4_fill_buffer(demuxer_t *demux, demux_stream_t *ds) |
11590 | 209 { |
210 FrameInfo frameInfo; | |
211 double pts; | |
212 int id=1; | |
213 int ret; | |
214 | |
24357 | 215 //hdr: |
11590 | 216 demux->filepos = stream_tell(demux->stream); |
17366 | 217 mp_msg(MSGT_DEMUX, MSGL_DBG2, "fpos = %"PRId64"\n", (int64_t)demux->filepos); |
11590 | 218 |
219 ret=getFrame(demux, &frameInfo); | |
220 if(ret<=0) return ret; // EOF/error | |
221 | |
222 pts=demux->video->sh ? frames*((sh_video_t*)(demux->video->sh))->frametime : 0; | |
223 | |
224 switch(frameInfo.frameType){ | |
225 case FRAMETYPE_AUDIO_MPEG1L2: | |
226 mp_dbg(MSGT_DEMUX, MSGL_DBG2, "Audio Packet\n"); | |
227 if (!video) | |
228 { | |
229 stream_skip(demux->stream, frameInfo.frameSize + frameInfo.paddingSize); | |
230 mp_msg(MSGT_DEMUX, MSGL_V, "Skip Audio Packet\n"); | |
231 return -1; //goto hdr; | |
232 } | |
233 if(demux->audio->id==-1){ | |
234 if(!demux->a_streams[id]) new_sh_audio(demux,id); | |
235 demux->audio->id=id; | |
236 demux->audio->sh=demux->a_streams[id]; | |
237 ((sh_audio_t*)(demux->audio->sh))->format=0x50; // mpeg audio layer 1/2 | |
238 } | |
239 if(demux->audio->id==id) | |
240 ds_read_packet(demux->audio, demux->stream, frameInfo.frameSize, | |
241 pts, demux->filepos, 0); | |
242 else | |
243 stream_skip(demux->stream,frameInfo.frameSize); | |
244 break; | |
245 case FRAMETYPE_I: | |
246 if (!video) { | |
247 video = 1; | |
248 mp_dbg(MSGT_DEMUX, MSGL_DBG2, "First Video Packet\n"); | |
249 } | |
250 case FRAMETYPE_P: | |
251 frames=(frames+1)&(1024*1024-1); // wrap around at 4 hrs to avoid inaccurate float calculations | |
252 if (!video) | |
253 { | |
254 stream_skip(demux->stream, frameInfo.frameSize + frameInfo.paddingSize); | |
255 mp_msg(MSGT_DEMUX, MSGL_V, "Skip Video P Packet\n"); | |
256 return -1; //goto hdr; | |
257 } | |
258 mp_dbg(MSGT_DEMUX, MSGL_DBG2, "Video Packet\n"); | |
259 if(demux->video->id==-1){ | |
260 if(!demux->v_streams[id]) new_sh_video(demux,id); | |
261 demux->video->id=id; | |
262 demux->video->sh=demux->v_streams[id]; | |
263 ((sh_video_t*)(demux->video->sh))->format=0x10000004; // mpeg4-ES | |
264 } | |
265 if(demux->video->id==id) | |
266 ds_read_packet(demux->video, demux->stream, frameInfo.frameSize, | |
267 pts, demux->filepos, 0); | |
268 break; | |
269 default: | |
270 stream_skip(demux->stream,frameInfo.frameSize); | |
271 } | |
272 | |
273 stream_skip(demux->stream, frameInfo.paddingSize); | |
274 | |
275 return 1; | |
276 } | |
277 | |
16175 | 278 static demuxer_t* demux_open_lmlm4(demuxer_t* demuxer){ |
279 sh_audio_t *sh_audio=NULL; | |
280 sh_video_t *sh_video=NULL; | |
11590 | 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 | |
16175 | 330 if(!ds_fill_buffer(demuxer->video)){ |
331 mp_msg(MSGT_DEMUXER,MSGL_INFO,"LMLM4: " MSGTR_MissingVideoStream); | |
332 demuxer->video->sh=NULL; | |
333 } else { | |
334 sh_video=demuxer->video->sh;sh_video->ds=demuxer->video; | |
335 } | |
336 if(demuxer->audio->id!=-2) { | |
337 if(!ds_fill_buffer(demuxer->audio)){ | |
338 mp_msg(MSGT_DEMUXER,MSGL_INFO,"LMLM4: " MSGTR_MissingAudioStream); | |
339 demuxer->audio->sh=NULL; | |
340 } else { | |
341 sh_audio=demuxer->audio->sh;sh_audio->ds=demuxer->audio; | |
342 } | |
343 } | |
11590 | 344 |
16175 | 345 return demuxer; |
11590 | 346 } |
347 | |
16175 | 348 static void demux_close_lmlm4(demuxer_t *demuxer) |
11590 | 349 { |
350 // printf("Close LMLM4 Stream\n"); | |
351 return; | |
352 } | |
16175 | 353 |
354 | |
25707
d4fe6e23283e
Make all demuxer_desc_t const, thus moving them to .rodata
reimar
parents:
25607
diff
changeset
|
355 const demuxer_desc_t demuxer_desc_lmlm4 = { |
16175 | 356 "LMLM4 MPEG4 Compression Card stream demuxer", |
357 "lmlm4", | |
358 "RAW LMLM4", | |
359 "Maxim Yevtyushkin", | |
360 "", | |
361 DEMUXER_TYPE_LMLM4, | |
362 0, // unsafe autodetect | |
363 lmlm4_check_file, | |
364 demux_lmlm4_fill_buffer, | |
365 demux_open_lmlm4, | |
366 demux_close_lmlm4, | |
367 NULL, | |
368 NULL | |
369 }; |