changeset 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 5cff0d11b47b
children 96206a53e2c5
files libmpdemux/Makefile libmpdemux/demux_lmlm4.c libmpdemux/demuxer.c libmpdemux/demuxer.h
diffstat 4 files changed, 378 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/Makefile	Mon Dec 08 18:35:39 2003 +0000
+++ b/libmpdemux/Makefile	Mon Dec 08 19:33:38 2003 +0000
@@ -3,7 +3,7 @@
 
 include ../config.mak
 
-SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_ty.c demux_ty_osd.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c stream_file.c stream_netstream.c stream_vcd.c stream_null.c stream_ftp.c tv.c tvi_dummy.c tvi_v4l.c tvi_v4l2.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c demux_ts.c demux_realaud.c url.c 
+SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_ty.c demux_ty_osd.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c stream_file.c stream_netstream.c stream_vcd.c stream_null.c stream_ftp.c tv.c tvi_dummy.c tvi_v4l.c tvi_v4l2.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c demux_lmlm4.c cue_read.c extension.c demux_gif.c demux_ts.c demux_realaud.c url.c 
 ifeq ($(XMMS_PLUGINS),yes)
 SRCS += demux_xmms.c
 endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpdemux/demux_lmlm4.c	Mon Dec 08 19:33:38 2003 +0000
@@ -0,0 +1,339 @@
+/*
+ LMLM4 MPEG4 Compression Card stream & file parser by Maxim Yevtyushkin <max@linuxmedialabs.com>
+ Based on SMJPEG file parser by Alex Beregszaszi
+ 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h> /* strtok */
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "stream.h"
+#include "demuxer.h"
+#include "stheader.h"
+#include "bswap.h"
+
+typedef struct __FrameInfo
+{
+    ssize_t frameSize;
+    ssize_t paddingSize;
+    int     frameType;
+    int     channelNo;
+} FrameInfo;
+
+#define FRAMETYPE_I             0
+#define FRAMETYPE_P             1
+#define FRAMETYPE_B             2
+#define FRAMETYPE_AUDIO_MPEG1L2 4
+#define FRAMETYPE_AUDIO_ULAW    5
+#define FRAMETYPE_AUDIO_ADPCM   6
+
+#define PACKET_BLOCK_SIZE   0x00000200
+#define PACKET_BLOCK_LAST   0x000001FF
+#define PACKET_BLOCK_MASK   0xFFFFFE00
+
+#define MAX_PACKET_SIZE   1048576 // 1 Mb
+
+#define STREAM_START_CODE_SIZE   4
+
+/*
+// codes in MSB first
+static unsigned int start_code [] = 
+{
+    0xB0010000,         // VISUAL_OBJECT_SEQUENCE_START_CODE   
+    0xB6010000,         // VOP_START_CODE                      
+    0x04C4FDFF,          // MPEG1LAYERII_START_CODE             
+    0x00000000          // end of start codes list
+};
+*/
+
+static int imeHeaderValid(FrameInfo *frame)
+{
+    if ( frame->channelNo > 7 ||
+         frame->frameSize > MAX_PACKET_SIZE || frame->frameSize <= 0) 
+    {
+        mp_msg(MSGT_DEMUX, MSGL_V, "Invalid packet in LMLM4 stream: ch=%d size=%d\n", frame->channelNo, frame->frameSize);
+        return 0;
+    }
+    switch (frame->frameType) {
+    case FRAMETYPE_I:
+    case FRAMETYPE_P:
+    case FRAMETYPE_B:            
+    case FRAMETYPE_AUDIO_MPEG1L2:
+    case FRAMETYPE_AUDIO_ULAW:
+    case FRAMETYPE_AUDIO_ADPCM:
+        break;   
+    default:
+        mp_msg(MSGT_DEMUX, MSGL_V, "Invalid packet in LMLM4 stream (wrong packet type %d)\n", frame->frameType);
+        return 0;
+    }
+    return 1;
+}
+
+/*
+int searchMPEG4Stream(demuxer_t* demuxer, IME6400Header *imeHeader)
+{
+    void *data;
+    ssize_t imeHeaderSize = sizeof(IME6400Header);
+    ssize_t dataSize = sizeof(IME6400Header) * 3;
+    ssize_t ptr = imeHeaderSize * 2;
+    int errNo, startCodeNo;
+    off_t pos;
+
+    data = malloc(dataSize);
+
+    imeHeaderSwap(imeHeader);
+    memcpy(data + imeHeaderSize, imeHeader, imeHeaderSize);
+    
+//    printHex(data + imeHeaderSize, imeHeaderSize);
+
+    while ((errNo = stream_read(demuxer->stream, data + imeHeaderSize * 2 , imeHeaderSize)) == imeHeaderSize) 
+    {
+//        printHex(data + imeHeaderSize * 2, imeHeaderSize);
+
+        pos = stream_tell(demuxer->stream);
+        while (dataSize - ptr >= STREAM_START_CODE_SIZE) {
+            startCodeNo = 0;
+            while (start_code[startCodeNo]) 
+            {
+                if (memcmp(&start_code[startCodeNo], data + ptr, STREAM_START_CODE_SIZE) == 0) // start code match
+                {
+                    memcpy(imeHeader, data + ptr - imeHeaderSize, imeHeaderSize);
+                    imeHeaderSwap(imeHeader);
+                    if (imeHeaderValid(imeHeader))
+                    {
+                        stream_seek(demuxer->stream, pos - (dataSize - ptr));
+                        free(data);
+                        return 0;
+                    }
+                }
+                startCodeNo++;
+            }
+            ptr++;
+        }
+        memcpy(data,data + imeHeaderSize, imeHeaderSize * 2);
+        ptr -= imeHeaderSize;
+    }
+
+    free(data);
+    return errNo;
+}
+*/
+
+static int getFrame(demuxer_t *demuxer, FrameInfo *frameInfo)
+{
+    int retCode;
+    unsigned int packetSize;
+
+    frameInfo->channelNo = stream_read_word(demuxer->stream);
+    frameInfo->frameType = stream_read_word(demuxer->stream);
+    packetSize=stream_read_dword(demuxer->stream);
+
+    if(stream_eof(demuxer->stream)){
+        frameInfo->frameSize = 0;
+	return 0;
+    }
+
+    frameInfo->frameSize = packetSize - 8; //sizeof(IME6400Header);
+    frameInfo->paddingSize = (packetSize & PACKET_BLOCK_LAST) ? PACKET_BLOCK_SIZE - (packetSize & PACKET_BLOCK_LAST) : 0;
+
+    mp_msg(MSGT_DEMUX, MSGL_DBG2, "typ: %d chan: %d size: %d pad: %d\n",
+            frameInfo->frameType,                                        
+            frameInfo->channelNo,                                        
+            frameInfo->frameSize,                                        
+            frameInfo->paddingSize);                                     
+    
+    if(!imeHeaderValid(frameInfo)){
+	// skip this packet
+	stream_skip(demuxer->stream,PACKET_BLOCK_SIZE-8);
+        frameInfo->frameSize = 0;
+	return -1;
+    }
+
+    return 1;
+}
+                        
+int lmlm4_check_file(demuxer_t* demuxer)
+{
+    FrameInfo frameInfo;
+    unsigned int first;
+    
+    mp_msg(MSGT_DEMUX, MSGL_V, "Checking for LMLM4 Stream Format\n");
+    
+    if(getFrame(demuxer, &frameInfo)!=1){
+	stream_skip(demuxer->stream,-8);
+        mp_msg(MSGT_DEMUX, MSGL_INFO, "LMLM4 Stream Format not found\n");
+        return 0;
+    }
+    first=stream_read_dword(demuxer->stream);
+    stream_skip(demuxer->stream,-12);
+    
+    mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: first=0x%08X\n",first);
+    
+    switch(frameInfo.frameType){
+    case FRAMETYPE_AUDIO_MPEG1L2:
+	if( (first & 0xffe00000) != 0xffe00000 ){
+    	    mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: not mpeg audio\n");
+    	    return 0;
+	}
+	if((4-((first>>17)&3))!=2){ 
+    	    mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: not layer-2\n");
+    	    return 0;
+	}
+	if(((first>>10)&0x3)==3){
+    	    mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: invalid audio sampelrate\n");
+    	    return 0;
+	}
+	mp_msg(MSGT_DEMUXER,MSGL_V,"LMLM4: first packet is audio, header checks OK!\n");
+	break;
+    // TODO: add checks for video header too, for case of disabled audio
+    }
+
+
+//    stream_reset(demuxer->stream);
+    mp_msg(MSGT_DEMUX, MSGL_V, "LMLM4 Stream Format found\n");
+
+    return 1;
+}
+
+static int video = 0;
+static int frames= 0;
+
+// return value:
+//     0 = EOF or no stream found
+//     1 = successfully read a packet
+int demux_lmlm4_fill_buffer(demuxer_t *demux)
+{
+    FrameInfo frameInfo;
+    double pts;
+    int id=1;
+    int ret;
+
+hdr:
+    demux->filepos = stream_tell(demux->stream);
+    mp_msg(MSGT_DEMUX, MSGL_DBG2, "fpos = %d\n", demux->filepos);
+    
+    ret=getFrame(demux, &frameInfo);
+    if(ret<=0) return ret; // EOF/error
+    
+    pts=demux->video->sh ? frames*((sh_video_t*)(demux->video->sh))->frametime : 0;
+    
+    switch(frameInfo.frameType){
+    case FRAMETYPE_AUDIO_MPEG1L2:
+        mp_dbg(MSGT_DEMUX, MSGL_DBG2, "Audio Packet\n");
+        if (!video) 
+        {
+            stream_skip(demux->stream, frameInfo.frameSize + frameInfo.paddingSize);
+            mp_msg(MSGT_DEMUX, MSGL_V, "Skip Audio Packet\n");
+            return -1; //goto hdr;
+        }
+	if(demux->audio->id==-1){
+	    if(!demux->a_streams[id]) new_sh_audio(demux,id);
+	    demux->audio->id=id;
+	    demux->audio->sh=demux->a_streams[id];
+	    ((sh_audio_t*)(demux->audio->sh))->format=0x50; // mpeg audio layer 1/2
+	}
+	if(demux->audio->id==id)
+	    ds_read_packet(demux->audio, demux->stream, frameInfo.frameSize,
+		pts, demux->filepos, 0);
+	else
+	    stream_skip(demux->stream,frameInfo.frameSize);
+	break;
+    case FRAMETYPE_I:
+        if (!video) {
+            video = 1;
+            mp_dbg(MSGT_DEMUX, MSGL_DBG2, "First Video Packet\n");
+        }
+    case FRAMETYPE_P:
+	frames=(frames+1)&(1024*1024-1); // wrap around at 4 hrs to avoid inaccurate float calculations
+        if (!video) 
+        {
+            stream_skip(demux->stream, frameInfo.frameSize + frameInfo.paddingSize);
+            mp_msg(MSGT_DEMUX, MSGL_V, "Skip Video P Packet\n");
+            return -1; //goto hdr;
+        }
+        mp_dbg(MSGT_DEMUX, MSGL_DBG2, "Video Packet\n");
+	if(demux->video->id==-1){
+	    if(!demux->v_streams[id]) new_sh_video(demux,id);
+	    demux->video->id=id;
+	    demux->video->sh=demux->v_streams[id];
+	    ((sh_video_t*)(demux->video->sh))->format=0x10000004; // mpeg4-ES
+	}
+	if(demux->video->id==id)
+	    ds_read_packet(demux->video, demux->stream, frameInfo.frameSize,
+		pts, demux->filepos, 0);
+	break;
+    default:
+	stream_skip(demux->stream,frameInfo.frameSize);
+    }
+    
+    stream_skip(demux->stream, frameInfo.paddingSize);
+
+    return 1;
+}
+
+int demux_open_lmlm4(demuxer_t* demuxer){
+
+#if 0
+    sh_video_t* sh_video;
+    sh_audio_t* sh_audio;
+    unsigned int htype = 0, hleng;
+    int i = 0;
+    
+    sh_video = new_sh_video(demuxer, 0);
+    demuxer->video->sh = sh_video;
+    sh_video->ds = demuxer->video;
+    sh_video->disp_w = 640;
+    sh_video->disp_h = 480;
+    sh_video->format = mmioFOURCC('D','I','V','X');
+
+    sh_video->bih = malloc(sizeof(BITMAPINFOHEADER));
+    memset(sh_video->bih, 0, sizeof(BITMAPINFOHEADER));
+
+    /* these are false values */
+    sh_video->bih->biSize = 40;
+    sh_video->bih->biWidth = sh_video->disp_w;
+    sh_video->bih->biHeight = sh_video->disp_h;
+    sh_video->bih->biPlanes = 3;
+    sh_video->bih->biBitCount = 16;
+    sh_video->bih->biCompression = sh_video->format;
+    sh_video->bih->biSizeImage = sh_video->disp_w*sh_video->disp_h;
+    
+    sh_audio = new_sh_audio(demuxer, 0);
+    demuxer->audio->sh = sh_audio;
+    sh_audio->ds = demuxer->audio;
+
+    sh_audio->wf = malloc(sizeof(WAVEFORMATEX));
+    memset(sh_audio->wf, 0, sizeof(WAVEFORMATEX));
+
+    sh_audio->samplerate = 48000;
+    sh_audio->wf->wBitsPerSample = 16;
+    sh_audio->channels = 2;
+    sh_audio->format = 0x50;
+    sh_audio->wf->wFormatTag = sh_audio->format;
+    sh_audio->wf->nChannels = sh_audio->channels;
+    sh_audio->wf->nSamplesPerSec = sh_audio->samplerate;
+    sh_audio->wf->nAvgBytesPerSec = sh_audio->wf->nChannels*
+    sh_audio->wf->wBitsPerSample*sh_audio->wf->nSamplesPerSec/8;
+    sh_audio->wf->nBlockAlign = sh_audio->channels *2;
+    sh_audio->wf->cbSize = 0;
+
+#endif
+
+    demuxer->seekable = 0;
+    
+    
+    
+    return 1;
+}
+
+void demux_close_lmlm4(demuxer_t *demuxer)
+{
+//    printf("Close LMLM4 Stream\n");
+    return;
+}
--- a/libmpdemux/demuxer.c	Mon Dec 08 18:35:39 2003 +0000
+++ b/libmpdemux/demuxer.c	Mon Dec 08 19:33:38 2003 +0000
@@ -134,6 +134,7 @@
 extern void demux_close_smjpeg(demuxer_t* demuxer);
 extern void demux_close_xmms(demuxer_t* demuxer);
 extern void demux_close_gif(demuxer_t* demuxer);
+extern void demux_close_lmlm4(demuxer_t* demuxer);
 extern void demux_close_ts(demuxer_t* demuxer);
 extern void demux_close_mkv(demuxer_t* demuxer);
 extern void demux_close_ra(demuxer_t* demuxer);
@@ -215,6 +216,8 @@
     case DEMUXER_TYPE_GIF:
       demux_close_gif(demuxer); break;
 #endif
+    case DEMUXER_TYPE_LMLM4:
+      demux_close_lmlm4(demuxer); break;
     case DEMUXER_TYPE_MPEG_TS:
     case DEMUXER_TYPE_MPEG4_IN_TS:
       demux_close_ts(demuxer); break;
@@ -308,6 +311,7 @@
 extern int demux_rawaudio_fill_buffer(demuxer_t* demuxer, demux_stream_t *ds);
 extern int demux_rawvideo_fill_buffer(demuxer_t* demuxer, demux_stream_t *ds);
 extern int demux_smjpeg_fill_buffer(demuxer_t* demux);
+extern int demux_lmlm4_fill_buffer(demuxer_t* demux);
 extern int demux_mkv_fill_buffer(demuxer_t *d);
 
 int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){
@@ -360,6 +364,7 @@
 #ifdef HAVE_GIF
     case DEMUXER_TYPE_GIF: return demux_gif_fill_buffer(demux);
 #endif
+    case DEMUXER_TYPE_LMLM4: return demux_lmlm4_fill_buffer(demux);
     case DEMUXER_TYPE_MPEG_TS: 
     case DEMUXER_TYPE_MPEG4_IN_TS: 
 	return demux_ts_fill_buffer(demux);
@@ -597,6 +602,8 @@
 extern int demux_xmms_open(demuxer_t* demuxer);
 extern int gif_check_file(demuxer_t *demuxer);
 extern int demux_open_gif(demuxer_t* demuxer);
+extern int lmlm4_check_file(demuxer_t* demuxer);
+extern int demux_open_lmlm4(demuxer_t* demuxer);
 extern int ts_check_file(demuxer_t * demuxer);
 extern int demux_open_ts(demuxer_t *demuxer);
 extern int demux_open_mkv(demuxer_t *demuxer);
@@ -895,6 +902,17 @@
 		demuxer=NULL;
 	}
 }
+//=============== Try to open as LMLM4 file: =================
+if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_LMLM4){
+  demuxer=new_demuxer(stream,DEMUXER_TYPE_LMLM4,audio_id,video_id,dvdsub_id);
+  if(lmlm4_check_file(demuxer)){
+      mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_Detected_XXX_FileFormat,"RAW LMLM4");
+      file_format=DEMUXER_TYPE_LMLM4;
+  } else {
+      free_demuxer(demuxer);
+      demuxer = NULL;
+  }
+}
 //=============== Try to open as MPEG-PS file: =================
 if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_PS){
  int pes=1;
@@ -1167,6 +1185,24 @@
   demux_open_y4m(demuxer);
   break;
  }
+ case DEMUXER_TYPE_LMLM4: {
+  demux_open_lmlm4(demuxer);
+  if(!ds_fill_buffer(d_video)){
+    mp_msg(MSGT_DEMUXER,MSGL_INFO,"LMLM4: " MSGTR_MissingVideoStream);
+    sh_video=NULL;
+  } else {
+    sh_video=d_video->sh;sh_video->ds=d_video;
+  }
+  if(audio_id!=-2) {
+   if(!ds_fill_buffer(d_audio)){
+    mp_msg(MSGT_DEMUXER,MSGL_INFO,"LMLM4: " MSGTR_MissingAudioStream);
+    sh_audio=NULL;
+   } else {
+    sh_audio=d_audio->sh;sh_audio->ds=d_audio;
+   }
+  }
+  break;
+ }
  case DEMUXER_TYPE_REAL: {
   demux_open_real(demuxer);
   break;
--- a/libmpdemux/demuxer.h	Mon Dec 08 18:35:39 2003 +0000
+++ b/libmpdemux/demuxer.h	Mon Dec 08 19:33:38 2003 +0000
@@ -42,12 +42,12 @@
 #define DEMUXER_TYPE_MATROSKA 31
 #define DEMUXER_TYPE_REALAUDIO 32
 #define DEMUXER_TYPE_MPEG_TY 33
-
+#define DEMUXER_TYPE_LMLM4 34
 
 // This should always match the higest demuxer type number.
 // Unless you want to disallow users to force the demuxer to some types
 #define DEMUXER_TYPE_MIN 0
-#define DEMUXER_TYPE_MAX 33
+#define DEMUXER_TYPE_MAX 34
 
 #define DEMUXER_TYPE_DEMUXERS (1<<16)
 // A virtual demuxer type for the network code