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 */
16 #include "stream/stream.h"
20 typedef struct FrameInfo
31 #define FRAMETYPE_AUDIO_MPEG1L2 4
32 #define FRAMETYPE_AUDIO_ULAW 5
33 #define FRAMETYPE_AUDIO_ADPCM 6
35 #define PACKET_BLOCK_SIZE 0x00000200
36 #define PACKET_BLOCK_LAST 0x000001FF
37 #define PACKET_BLOCK_MASK 0xFFFFFE00
39 #define MAX_PACKET_SIZE 1048576 // 1 Mb
41 #define STREAM_START_CODE_SIZE 4
45 static unsigned int start_code [] =
47 0xB0010000, // VISUAL_OBJECT_SEQUENCE_START_CODE
48 0xB6010000, // VOP_START_CODE
49 0x04C4FDFF, // MPEG1LAYERII_START_CODE
50 0x00000000 // end of start codes list
54 static int imeHeaderValid(FrameInfo
*frame
)
56 if ( frame
->channelNo
> 7 ||
57 frame
->frameSize
> MAX_PACKET_SIZE
|| frame
->frameSize
<= 0)
59 mp_msg(MSGT_DEMUX
, MSGL_V
, "Invalid packet in LMLM4 stream: ch=%d size=%d\n", frame
->channelNo
, frame
->frameSize
);
62 switch (frame
->frameType
) {
66 case FRAMETYPE_AUDIO_MPEG1L2
:
67 case FRAMETYPE_AUDIO_ULAW
:
68 case FRAMETYPE_AUDIO_ADPCM
:
71 mp_msg(MSGT_DEMUX
, MSGL_V
, "Invalid packet in LMLM4 stream (wrong packet type %d)\n", frame
->frameType
);
78 int searchMPEG4Stream(demuxer_t* demuxer, IME6400Header *imeHeader)
81 ssize_t imeHeaderSize = sizeof(IME6400Header);
82 ssize_t dataSize = sizeof(IME6400Header) * 3;
83 ssize_t ptr = imeHeaderSize * 2;
84 int errNo, startCodeNo;
87 data = malloc(dataSize);
89 imeHeaderSwap(imeHeader);
90 memcpy(data + imeHeaderSize, imeHeader, imeHeaderSize);
92 // printHex(data + imeHeaderSize, imeHeaderSize);
94 while ((errNo = stream_read(demuxer->stream, data + imeHeaderSize * 2 , imeHeaderSize)) == imeHeaderSize)
96 // printHex(data + imeHeaderSize * 2, imeHeaderSize);
98 pos = stream_tell(demuxer->stream);
99 while (dataSize - ptr >= STREAM_START_CODE_SIZE) {
101 while (start_code[startCodeNo])
103 if (memcmp(&start_code[startCodeNo], data + ptr, STREAM_START_CODE_SIZE) == 0) // start code match
105 memcpy(imeHeader, data + ptr - imeHeaderSize, imeHeaderSize);
106 imeHeaderSwap(imeHeader);
107 if (imeHeaderValid(imeHeader))
109 stream_seek(demuxer->stream, pos - (dataSize - ptr));
118 memcpy(data,data + imeHeaderSize, imeHeaderSize * 2);
119 ptr -= imeHeaderSize;
127 static int getFrame(demuxer_t
*demuxer
, FrameInfo
*frameInfo
)
129 unsigned int packetSize
;
131 frameInfo
->channelNo
= stream_read_word(demuxer
->stream
);
132 frameInfo
->frameType
= stream_read_word(demuxer
->stream
);
133 packetSize
=stream_read_dword(demuxer
->stream
);
135 if(stream_eof(demuxer
->stream
)){
136 frameInfo
->frameSize
= 0;
140 frameInfo
->frameSize
= packetSize
- 8; //sizeof(IME6400Header);
141 frameInfo
->paddingSize
= (packetSize
& PACKET_BLOCK_LAST
) ? PACKET_BLOCK_SIZE
- (packetSize
& PACKET_BLOCK_LAST
) : 0;
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
);
149 if(!imeHeaderValid(frameInfo
)){
151 stream_skip(demuxer
->stream
,PACKET_BLOCK_SIZE
-8);
152 frameInfo
->frameSize
= 0;
159 static int lmlm4_check_file(demuxer_t
* demuxer
)
164 mp_msg(MSGT_DEMUX
, MSGL_V
, "Checking for LMLM4 Stream Format\n");
166 if(getFrame(demuxer
, &frameInfo
)!=1){
167 stream_skip(demuxer
->stream
,-8);
168 mp_msg(MSGT_DEMUX
, MSGL_V
, "LMLM4 Stream Format not found\n");
171 first
=stream_read_dword(demuxer
->stream
);
172 stream_skip(demuxer
->stream
,-12);
174 mp_msg(MSGT_DEMUXER
,MSGL_V
,"LMLM4: first=0x%08X\n",first
);
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");
182 if((4-((first
>>17)&3))!=2){
183 mp_msg(MSGT_DEMUXER
,MSGL_V
,"LMLM4: not layer-2\n");
186 if(((first
>>10)&0x3)==3){
187 mp_msg(MSGT_DEMUXER
,MSGL_V
,"LMLM4: invalid audio sampelrate\n");
190 mp_msg(MSGT_DEMUXER
,MSGL_V
,"LMLM4: first packet is audio, header checks OK!\n");
192 // TODO: add checks for video header too, for case of disabled audio
196 // stream_reset(demuxer->stream);
197 mp_msg(MSGT_DEMUX
, MSGL_V
, "LMLM4 Stream Format found\n");
199 return DEMUXER_TYPE_LMLM4
;
202 static int video
= 0;
203 static int frames
= 0;
206 // 0 = EOF or no stream found
207 // 1 = successfully read a packet
208 static int demux_lmlm4_fill_buffer(demuxer_t
*demux
, demux_stream_t
*ds
)
216 demux
->filepos
= stream_tell(demux
->stream
);
217 mp_msg(MSGT_DEMUX
, MSGL_DBG2
, "fpos = %"PRId64
"\n", (int64_t)demux
->filepos
);
219 ret
=getFrame(demux
, &frameInfo
);
220 if(ret
<=0) return ret
; // EOF/error
222 pts
=demux
->video
->sh
? frames
*((sh_video_t
*)(demux
->video
->sh
))->frametime
: 0;
224 switch(frameInfo
.frameType
){
225 case FRAMETYPE_AUDIO_MPEG1L2
:
226 mp_dbg(MSGT_DEMUX
, MSGL_DBG2
, "Audio Packet\n");
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;
233 if(demux
->audio
->id
==-1){
234 if(!demux
->a_streams
[id
]) new_sh_audio(demux
,id
);
236 demux
->audio
->sh
=demux
->a_streams
[id
];
237 ((sh_audio_t
*)(demux
->audio
->sh
))->format
=0x50; // mpeg audio layer 1/2
239 if(demux
->audio
->id
==id
)
240 ds_read_packet(demux
->audio
, demux
->stream
, frameInfo
.frameSize
,
241 pts
, demux
->filepos
, 0);
243 stream_skip(demux
->stream
,frameInfo
.frameSize
);
248 mp_dbg(MSGT_DEMUX
, MSGL_DBG2
, "First Video Packet\n");
251 frames
=(frames
+1)&(1024*1024-1); // wrap around at 4 hrs to avoid inaccurate float calculations
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;
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
);
262 demux
->video
->sh
=demux
->v_streams
[id
];
263 ((sh_video_t
*)(demux
->video
->sh
))->format
=0x10000004; // mpeg4-ES
265 if(demux
->video
->id
==id
)
266 ds_read_packet(demux
->video
, demux
->stream
, frameInfo
.frameSize
,
267 pts
, demux
->filepos
, 0);
270 stream_skip(demux
->stream
,frameInfo
.frameSize
);
273 stream_skip(demux
->stream
, frameInfo
.paddingSize
);
278 static demuxer_t
* demux_open_lmlm4(demuxer_t
* demuxer
){
279 sh_audio_t
*sh_audio
=NULL
;
280 sh_video_t
*sh_video
=NULL
;
283 sh_video_t
* sh_video
;
284 sh_audio_t
* sh_audio
;
285 unsigned int htype
= 0, hleng
;
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');
295 sh_video
->bih
= malloc(sizeof(BITMAPINFOHEADER
));
296 memset(sh_video
->bih
, 0, sizeof(BITMAPINFOHEADER
));
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
;
307 sh_audio
= new_sh_audio(demuxer
, 0);
308 demuxer
->audio
->sh
= sh_audio
;
309 sh_audio
->ds
= demuxer
->audio
;
311 sh_audio
->wf
= malloc(sizeof(WAVEFORMATEX
));
312 memset(sh_audio
->wf
, 0, sizeof(WAVEFORMATEX
));
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;
328 demuxer
->seekable
= 0;
330 if(!ds_fill_buffer(demuxer
->video
)){
331 mp_msg(MSGT_DEMUXER
,MSGL_INFO
,"LMLM4: " MSGTR_MissingVideoStream
);
332 demuxer
->video
->sh
=NULL
;
334 sh_video
=demuxer
->video
->sh
;sh_video
->ds
=demuxer
->video
;
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
;
341 sh_audio
=demuxer
->audio
->sh
;sh_audio
->ds
=demuxer
->audio
;
348 static void demux_close_lmlm4(demuxer_t
*demuxer
)
350 // printf("Close LMLM4 Stream\n");
355 const demuxer_desc_t demuxer_desc_lmlm4
= {
356 "LMLM4 MPEG4 Compression Card stream demuxer",
362 0, // unsafe autodetect
364 demux_lmlm4_fill_buffer
,