Mercurial > mplayer.hg
diff 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 |
line wrap: on
line diff
--- /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; +}