2 LMLM4 MPEG4 Compression Card stream & file parser by Maxim Yevtyushkin <max@linuxmedialabs.com>
3 Based on SMJPEG file parser by Alex Beregszaszi
10 #include <string.h> /* strtok */
21 typedef struct __FrameInfo
32 #define FRAMETYPE_AUDIO_MPEG1L2 4
33 #define FRAMETYPE_AUDIO_ULAW 5
34 #define FRAMETYPE_AUDIO_ADPCM 6
36 #define PACKET_BLOCK_SIZE 0x00000200
37 #define PACKET_BLOCK_LAST 0x000001FF
38 #define PACKET_BLOCK_MASK 0xFFFFFE00
40 #define MAX_PACKET_SIZE 1048576 // 1 Mb
42 #define STREAM_START_CODE_SIZE 4
46 static unsigned int start_code [] =
48 0xB0010000, // VISUAL_OBJECT_SEQUENCE_START_CODE
49 0xB6010000, // VOP_START_CODE
50 0x04C4FDFF, // MPEG1LAYERII_START_CODE
51 0x00000000 // end of start codes list
55 static int imeHeaderValid(FrameInfo
*frame
)
57 if ( frame
->channelNo
> 7 ||
58 frame
->frameSize
> MAX_PACKET_SIZE
|| frame
->frameSize
<= 0)
60 mp_msg(MSGT_DEMUX
, MSGL_V
, "Invalid packet in LMLM4 stream: ch=%d size=%d\n", frame
->channelNo
, frame
->frameSize
);
63 switch (frame
->frameType
) {
67 case FRAMETYPE_AUDIO_MPEG1L2
:
68 case FRAMETYPE_AUDIO_ULAW
:
69 case FRAMETYPE_AUDIO_ADPCM
:
72 mp_msg(MSGT_DEMUX
, MSGL_V
, "Invalid packet in LMLM4 stream (wrong packet type %d)\n", frame
->frameType
);
79 int searchMPEG4Stream(demuxer_t* demuxer, IME6400Header *imeHeader)
82 ssize_t imeHeaderSize = sizeof(IME6400Header);
83 ssize_t dataSize = sizeof(IME6400Header) * 3;
84 ssize_t ptr = imeHeaderSize * 2;
85 int errNo, startCodeNo;
88 data = malloc(dataSize);
90 imeHeaderSwap(imeHeader);
91 memcpy(data + imeHeaderSize, imeHeader, imeHeaderSize);
93 // printHex(data + imeHeaderSize, imeHeaderSize);
95 while ((errNo = stream_read(demuxer->stream, data + imeHeaderSize * 2 , imeHeaderSize)) == imeHeaderSize)
97 // printHex(data + imeHeaderSize * 2, imeHeaderSize);
99 pos = stream_tell(demuxer->stream);
100 while (dataSize - ptr >= STREAM_START_CODE_SIZE) {
102 while (start_code[startCodeNo])
104 if (memcmp(&start_code[startCodeNo], data + ptr, STREAM_START_CODE_SIZE) == 0) // start code match
106 memcpy(imeHeader, data + ptr - imeHeaderSize, imeHeaderSize);
107 imeHeaderSwap(imeHeader);
108 if (imeHeaderValid(imeHeader))
110 stream_seek(demuxer->stream, pos - (dataSize - ptr));
119 memcpy(data,data + imeHeaderSize, imeHeaderSize * 2);
120 ptr -= imeHeaderSize;
128 static int getFrame(demuxer_t
*demuxer
, FrameInfo
*frameInfo
)
131 unsigned int packetSize
;
133 frameInfo
->channelNo
= stream_read_word(demuxer
->stream
);
134 frameInfo
->frameType
= stream_read_word(demuxer
->stream
);
135 packetSize
=stream_read_dword(demuxer
->stream
);
137 if(stream_eof(demuxer
->stream
)){
138 frameInfo
->frameSize
= 0;
142 frameInfo
->frameSize
= packetSize
- 8; //sizeof(IME6400Header);
143 frameInfo
->paddingSize
= (packetSize
& PACKET_BLOCK_LAST
) ? PACKET_BLOCK_SIZE
- (packetSize
& PACKET_BLOCK_LAST
) : 0;
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
);
151 if(!imeHeaderValid(frameInfo
)){
153 stream_skip(demuxer
->stream
,PACKET_BLOCK_SIZE
-8);
154 frameInfo
->frameSize
= 0;
161 static int lmlm4_check_file(demuxer_t
* demuxer
)
166 mp_msg(MSGT_DEMUX
, MSGL_V
, "Checking for LMLM4 Stream Format\n");
168 if(getFrame(demuxer
, &frameInfo
)!=1){
169 stream_skip(demuxer
->stream
,-8);
170 mp_msg(MSGT_DEMUX
, MSGL_V
, "LMLM4 Stream Format not found\n");
173 first
=stream_read_dword(demuxer
->stream
);
174 stream_skip(demuxer
->stream
,-12);
176 mp_msg(MSGT_DEMUXER
,MSGL_V
,"LMLM4: first=0x%08X\n",first
);
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");
184 if((4-((first
>>17)&3))!=2){
185 mp_msg(MSGT_DEMUXER
,MSGL_V
,"LMLM4: not layer-2\n");
188 if(((first
>>10)&0x3)==3){
189 mp_msg(MSGT_DEMUXER
,MSGL_V
,"LMLM4: invalid audio sampelrate\n");
192 mp_msg(MSGT_DEMUXER
,MSGL_V
,"LMLM4: first packet is audio, header checks OK!\n");
194 // TODO: add checks for video header too, for case of disabled audio
198 // stream_reset(demuxer->stream);
199 mp_msg(MSGT_DEMUX
, MSGL_V
, "LMLM4 Stream Format found\n");
201 return DEMUXER_TYPE_LMLM4
;
204 static int video
= 0;
205 static int frames
= 0;
208 // 0 = EOF or no stream found
209 // 1 = successfully read a packet
210 static int demux_lmlm4_fill_buffer(demuxer_t
*demux
, demux_stream_t
*ds
)
218 demux
->filepos
= stream_tell(demux
->stream
);
219 mp_msg(MSGT_DEMUX
, MSGL_DBG2
, "fpos = %"PRId64
"\n", (int64_t)demux
->filepos
);
221 ret
=getFrame(demux
, &frameInfo
);
222 if(ret
<=0) return ret
; // EOF/error
224 pts
=demux
->video
->sh
? frames
*((sh_video_t
*)(demux
->video
->sh
))->frametime
: 0;
226 switch(frameInfo
.frameType
){
227 case FRAMETYPE_AUDIO_MPEG1L2
:
228 mp_dbg(MSGT_DEMUX
, MSGL_DBG2
, "Audio Packet\n");
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;
235 if(demux
->audio
->id
==-1){
236 if(!demux
->a_streams
[id
]) new_sh_audio(demux
,id
);
238 demux
->audio
->sh
=demux
->a_streams
[id
];
239 ((sh_audio_t
*)(demux
->audio
->sh
))->format
=0x50; // mpeg audio layer 1/2
241 if(demux
->audio
->id
==id
)
242 ds_read_packet(demux
->audio
, demux
->stream
, frameInfo
.frameSize
,
243 pts
, demux
->filepos
, 0);
245 stream_skip(demux
->stream
,frameInfo
.frameSize
);
250 mp_dbg(MSGT_DEMUX
, MSGL_DBG2
, "First Video Packet\n");
253 frames
=(frames
+1)&(1024*1024-1); // wrap around at 4 hrs to avoid inaccurate float calculations
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;
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
);
264 demux
->video
->sh
=demux
->v_streams
[id
];
265 ((sh_video_t
*)(demux
->video
->sh
))->format
=0x10000004; // mpeg4-ES
267 if(demux
->video
->id
==id
)
268 ds_read_packet(demux
->video
, demux
->stream
, frameInfo
.frameSize
,
269 pts
, demux
->filepos
, 0);
272 stream_skip(demux
->stream
,frameInfo
.frameSize
);
275 stream_skip(demux
->stream
, frameInfo
.paddingSize
);
280 static demuxer_t
* demux_open_lmlm4(demuxer_t
* demuxer
){
281 sh_audio_t
*sh_audio
=NULL
;
282 sh_video_t
*sh_video
=NULL
;
285 sh_video_t
* sh_video
;
286 sh_audio_t
* sh_audio
;
287 unsigned int htype
= 0, hleng
;
290 sh_video
= new_sh_video(demuxer
, 0);
291 demuxer
->video
->sh
= sh_video
;
292 sh_video
->ds
= demuxer
->video
;
293 sh_video
->disp_w
= 640;
294 sh_video
->disp_h
= 480;
295 sh_video
->format
= mmioFOURCC('D','I','V','X');
297 sh_video
->bih
= malloc(sizeof(BITMAPINFOHEADER
));
298 memset(sh_video
->bih
, 0, sizeof(BITMAPINFOHEADER
));
300 /* these are false values */
301 sh_video
->bih
->biSize
= 40;
302 sh_video
->bih
->biWidth
= sh_video
->disp_w
;
303 sh_video
->bih
->biHeight
= sh_video
->disp_h
;
304 sh_video
->bih
->biPlanes
= 3;
305 sh_video
->bih
->biBitCount
= 16;
306 sh_video
->bih
->biCompression
= sh_video
->format
;
307 sh_video
->bih
->biSizeImage
= sh_video
->disp_w
*sh_video
->disp_h
;
309 sh_audio
= new_sh_audio(demuxer
, 0);
310 demuxer
->audio
->sh
= sh_audio
;
311 sh_audio
->ds
= demuxer
->audio
;
313 sh_audio
->wf
= malloc(sizeof(WAVEFORMATEX
));
314 memset(sh_audio
->wf
, 0, sizeof(WAVEFORMATEX
));
316 sh_audio
->samplerate
= 48000;
317 sh_audio
->wf
->wBitsPerSample
= 16;
318 sh_audio
->channels
= 2;
319 sh_audio
->format
= 0x50;
320 sh_audio
->wf
->wFormatTag
= sh_audio
->format
;
321 sh_audio
->wf
->nChannels
= sh_audio
->channels
;
322 sh_audio
->wf
->nSamplesPerSec
= sh_audio
->samplerate
;
323 sh_audio
->wf
->nAvgBytesPerSec
= sh_audio
->wf
->nChannels
*
324 sh_audio
->wf
->wBitsPerSample
*sh_audio
->wf
->nSamplesPerSec
/8;
325 sh_audio
->wf
->nBlockAlign
= sh_audio
->channels
*2;
326 sh_audio
->wf
->cbSize
= 0;
330 demuxer
->seekable
= 0;
332 if(!ds_fill_buffer(demuxer
->video
)){
333 mp_msg(MSGT_DEMUXER
,MSGL_INFO
,"LMLM4: " MSGTR_MissingVideoStream
);
334 demuxer
->video
->sh
=NULL
;
336 sh_video
=demuxer
->video
->sh
;sh_video
->ds
=demuxer
->video
;
338 if(demuxer
->audio
->id
!=-2) {
339 if(!ds_fill_buffer(demuxer
->audio
)){
340 mp_msg(MSGT_DEMUXER
,MSGL_INFO
,"LMLM4: " MSGTR_MissingAudioStream
);
341 demuxer
->audio
->sh
=NULL
;
343 sh_audio
=demuxer
->audio
->sh
;sh_audio
->ds
=demuxer
->audio
;
350 static void demux_close_lmlm4(demuxer_t
*demuxer
)
352 // printf("Close LMLM4 Stream\n");
357 demuxer_desc_t demuxer_desc_lmlm4
= {
358 "LMLM4 MPEG4 Compression Card stream demuxer",
364 0, // unsafe autodetect
366 demux_lmlm4_fill_buffer
,