demux_avi.c

来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 918 行 · 第 1/2 页

C
918
字号
//  AVI file parser for DEMUXER v2.9  by A'rpi/ESP-team#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include "config.h"#include "mp_msg.h"#include "help_mp.h"#include "stream/stream.h"#include "demuxer.h"#include "stheader.h"#include "aviheader.h"#ifdef USE_16M_SDRAMdemuxer_t* (*init_avi_with_ogg_funcp)(demuxer_t* demuxer) = NULL;int (*demux_ogg_open_funcp)(demuxer_t* demuxer) = NULL;#elseextern demuxer_t* init_avi_with_ogg(demuxer_t* demuxer);extern int demux_ogg_open(demuxer_t* demuxer);#endifextern demuxer_desc_t demuxer_desc_avi_ni;extern demuxer_desc_t demuxer_desc_avi_nini;// PTS:  0=interleaved  1=BPS-basedint pts_from_bps=1;// Select ds from IDdemux_stream_t* demux_avi_select_stream(demuxer_t *demux,unsigned int id){  int stream_id=avi_stream_id(id);  if(demux->video->id==-1)    if(demux->v_streams[stream_id])        demux->video->id=stream_id;  if(demux->audio->id==-1)    if(demux->a_streams[stream_id])        demux->audio->id=stream_id;  if(stream_id==demux->audio->id){      if(!demux->audio->sh){        sh_audio_t* sh;	avi_priv_t *priv=demux->priv;        sh=demux->audio->sh=demux->a_streams[stream_id];        mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected AVI audio ID = %d\n",demux->audio->id);	if(sh->wf){	  priv->audio_block_size=sh->wf->nBlockAlign;	  if(!priv->audio_block_size){	    // for PCM audio we can calculate the blocksize:	    if(sh->format==1)		priv->audio_block_size=sh->wf->nChannels*(sh->wf->wBitsPerSample/8);	    else		priv->audio_block_size=1; // hope the best...	  } else {	    // workaround old mencoder's bug:	    if(sh->audio.dwSampleSize==1 && sh->audio.dwScale==1 &&	       (sh->wf->nBlockAlign==1152 || sh->wf->nBlockAlign==576)){		mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_WorkAroundBlockAlignHeaderBug);		priv->audio_block_size=1;	    }	  }	} else {	  priv->audio_block_size=sh->audio.dwSampleSize;	}      }      return demux->audio;  }  if(stream_id==demux->video->id){      if(!demux->video->sh){        demux->video->sh=demux->v_streams[stream_id];        mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected AVI video ID = %d\n",demux->video->id);      }      return demux->video;  }  if(id!=mmioFOURCC('J','U','N','K')){     // unknown     mp_msg(MSGT_DEMUX,MSGL_DBG2,"Unknown chunk: %.4s (%X)\n",(char *) &id,id);     //abort();  }  return NULL;}static int valid_fourcc(unsigned int id){    static const char valid[] = "0123456789abcdefghijklmnopqrstuvwxyz"                                "ABCDEFGHIJKLMNOPQRSTUVWXYZ_";    unsigned char* fcc=(unsigned char*)(&id);    return strchr(valid, fcc[0]) && strchr(valid, fcc[1]) &&           strchr(valid, fcc[2]) && strchr(valid, fcc[3]);}static int choose_chunk_len(unsigned int len1,unsigned int len2){    // len1 has a bit more priority than len2. len1!=len2    // Note: this is a first-idea-logic, may be wrong. comments welcomed.    // prefer small frames rather than 0    if(!len1) return (len2>0x80000) ? len1 : len2;    if(!len2) return (len1>0x100000) ? len2 : len1;    // choose the smaller value:    return (len1<len2)? len1 : len2;}static int demux_avi_read_packet(demuxer_t *demux,demux_stream_t *ds,unsigned int id,unsigned int len,int idxpos,int flags){  avi_priv_t *priv=demux->priv;  int skip;  float pts=0;    mp_dbg(MSGT_DEMUX,MSGL_DBG3,"demux_avi.read_packet: %X\n",id);  if(ds==demux->audio){      if(priv->pts_corrected==0){          if(priv->pts_has_video){	      // we have video pts now	      float delay=0;	      if(((sh_audio_t*)(ds->sh))->wf->nAvgBytesPerSec)	          delay=(float)priv->pts_corr_bytes/((sh_audio_t*)(ds->sh))->wf->nAvgBytesPerSec;	      mp_msg(MSGT_DEMUX,MSGL_V,"XXX initial  v_pts=%5.3f  a_pos=%d (%5.3f) \n",priv->avi_audio_pts,priv->pts_corr_bytes,delay);	      //priv->pts_correction=-priv->avi_audio_pts+delay;	      priv->pts_correction=delay-priv->avi_audio_pts;	      priv->avi_audio_pts+=priv->pts_correction;	      priv->pts_corrected=1;	  } else	      priv->pts_corr_bytes+=len;      }      if(pts_from_bps){	  pts = priv->audio_block_no *	    (float)((sh_audio_t*)demux->audio->sh)->audio.dwScale /	    (float)((sh_audio_t*)demux->audio->sh)->audio.dwRate;      } else          pts=priv->avi_audio_pts; //+priv->pts_correction;      priv->avi_audio_pts=0;      // update blockcount:      priv->audio_block_no+=priv->audio_block_size ?	((len+priv->audio_block_size-1)/priv->audio_block_size) : 1;  } else   if(ds==demux->video){     // video     if(priv->skip_video_frames>0){       // drop frame (seeking)       --priv->skip_video_frames;       ds=NULL;     }     pts = priv->avi_video_pts = priv->video_pack_no *         (float)((sh_video_t*)demux->video->sh)->video.dwScale /	 (float)((sh_video_t*)demux->video->sh)->video.dwRate;     priv->avi_audio_pts=priv->avi_video_pts+priv->pts_correction;     priv->pts_has_video=1;     if(ds) ++priv->video_pack_no;  }    skip=(len+1)&(~1); // total bytes in this chunk    if(ds){    mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_AVI: Read %d data bytes from packet %04X\n",len,id);    ds_read_packet(ds,demux->stream,len,pts,idxpos,flags);    skip-=len;  }  if(skip){    mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_AVI: Skipping %d bytes from packet %04X\n",skip,id);    stream_skip(demux->stream,skip);  }  return ds?1:0;}// return value://     0 = EOF or no stream found//     1 = successfully read a packetstatic int demux_avi_fill_buffer(demuxer_t *demux, demux_stream_t *dsds){avi_priv_t *priv=demux->priv;unsigned int id=0;unsigned int len;int ret=0;demux_stream_t *ds;//F("1\n");do{  int flags=1;  AVIINDEXENTRY *idx=NULL;  if(priv->idx_size>0 && priv->idx_pos<priv->idx_size){    off_t pos;        idx=&((AVIINDEXENTRY *)priv->idx)[priv->idx_pos++];        if(idx->dwFlags&AVIIF_LIST){      // LIST      continue;    }    if(!demux_avi_select_stream(demux,idx->ckid)){      mp_dbg(MSGT_DEMUX,MSGL_DBG3,"Skip chunk %.4s (0x%X)  \n",(char *)&idx->ckid,(unsigned int)idx->ckid);      continue; // skip this chunk    }    pos = (off_t)priv->idx_offset+AVI_IDX_OFFSET(idx);    if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start) && (demux->stream->flags & STREAM_SEEK)){      mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range!   idx=0x%"PRIX64"  \n",(int64_t)pos);      continue;    }    //F("pos = %x\n",pos);    stream_seek(demux->stream,pos);       demux->filepos=stream_tell(demux->stream);    //F("demux->filepos = %x\n",demux->filepos);    id=stream_read_dword_le(demux->stream);    if(stream_eof(demux->stream)) return 0; // EOF!        if(id!=idx->ckid){      mp_msg(MSGT_DEMUX,MSGL_V,"ChunkID mismatch! raw=%.4s idx=%.4s  \n",(char *)&id,(char *)&idx->ckid);      if(valid_fourcc(idx->ckid))          id=idx->ckid;	// use index if valid      else          if(!valid_fourcc(id)) continue; // drop chunk if both id and idx bad    }    len=stream_read_dword_le(demux->stream);    if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){      mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%d  \n",len,idx->dwChunkLength);      if(len>0x200000 && idx->dwChunkLength>0x200000) continue; // both values bad :(      len=choose_chunk_len(idx->dwChunkLength,len);    }    if(!(idx->dwFlags&AVIIF_KEYFRAME)) flags=0;  } else {    demux->filepos=stream_tell(demux->stream);    if(demux->filepos>=demux->movi_end && demux->movi_end>demux->movi_start && (demux->stream->flags & STREAM_SEEK)){          demux->stream->eof=1;          return 0;    }    id=stream_read_dword_le(demux->stream);    len=stream_read_dword_le(demux->stream);    if(stream_eof(demux->stream)) return 0; // EOF!        if(id==mmioFOURCC('L','I','S','T') || id==mmioFOURCC('R', 'I', 'F', 'F')){      id=stream_read_dword_le(demux->stream); // list or RIFF type      continue;    }  }  ds=demux_avi_select_stream(demux,id);  if(ds)    if(ds->packs+1>=MAX_PACKS || ds->bytes+len>=MAX_PACK_BYTES){	// this packet will cause a buffer overflow, switch to -ni mode!!!	mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_SwitchToNi);	if(priv->idx_size>0){	    // has index	    demux->type=DEMUXER_TYPE_AVI_NI;	    demux->desc=&demuxer_desc_avi_ni;	    --priv->idx_pos; // hack	} else {	    // no index	    demux->type=DEMUXER_TYPE_AVI_NINI;	    demux->desc=&demuxer_desc_avi_nini;	    priv->idx_pos=demux->filepos; // hack	}	priv->idx_pos_v=priv->idx_pos_a=priv->idx_pos;	// quit now, we can't even (no enough buffer memory) read this packet :(	return -1;    }    ret=demux_avi_read_packet(demux,ds,id,len,priv->idx_pos-1,flags);} while(ret!=1);  return 1;}// return value://     0 = EOF or no stream found//     1 = successfully read a packetint demux_avi_fill_buffer_ni(demuxer_t *demux,demux_stream_t* ds){avi_priv_t *priv=demux->priv;unsigned int id=0;unsigned int len;int ret=0;//F("1\n");do{  int flags=1;  AVIINDEXENTRY *idx=NULL;  int idx_pos=0;  demux->filepos=stream_tell(demux->stream);    if(ds==demux->video) idx_pos=priv->idx_pos_v++; else  if(ds==demux->audio) idx_pos=priv->idx_pos_a++; else                       idx_pos=priv->idx_pos++;    if(priv->idx_size>0 && idx_pos<priv->idx_size){    off_t pos;    idx=&((AVIINDEXENTRY *)priv->idx)[idx_pos];        if(idx->dwFlags&AVIIF_LIST){      // LIST      continue;    }    if(ds && demux_avi_select_stream(demux,idx->ckid)!=ds){      mp_dbg(MSGT_DEMUX,MSGL_DBG3,"Skip chunk %.4s (0x%X)  \n",(char *)&idx->ckid,(unsigned int)idx->ckid);      continue; // skip this chunk    }    pos = priv->idx_offset+AVI_IDX_OFFSET(idx);    if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start)){      mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range!  current=0x%"PRIX64"  idx=0x%"PRIX64"  \n",(int64_t)demux->filepos,(int64_t)pos);      continue;    }    stream_seek(demux->stream,pos);    id=stream_read_dword_le(demux->stream);    if(stream_eof(demux->stream)) return 0;    if(id!=idx->ckid){      mp_msg(MSGT_DEMUX,MSGL_V,"ChunkID mismatch! raw=%.4s idx=%.4s  \n",(char *)&id,(char *)&idx->ckid);      if(valid_fourcc(idx->ckid))          id=idx->ckid;	// use index if valid      else          if(!valid_fourcc(id)) continue; // drop chunk if both id and idx bad    }    len=stream_read_dword_le(demux->stream);    if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){      mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%d  \n",len,idx->dwChunkLength);      if(len>0x200000 && idx->dwChunkLength>0x200000) continue; // both values bad :(      len=choose_chunk_len(idx->dwChunkLength,len);    }    if(!(idx->dwFlags&AVIIF_KEYFRAME)) flags=0;  } else return 0;  ret=demux_avi_read_packet(demux,demux_avi_select_stream(demux,id),id,len,idx_pos,flags);} while(ret!=1);  return 1;}// return value://     0 = EOF or no stream found//     1 = successfully read a packetint demux_avi_fill_buffer_nini(demuxer_t *demux,demux_stream_t* ds){avi_priv_t *priv=demux->priv;unsigned int id=0;unsigned int len;int ret=0;off_t *fpos=NULL;	//F("1\n");  if(ds==demux->video) fpos=&priv->idx_pos_v; else  if(ds==demux->audio) fpos=&priv->idx_pos_a; else  return 0;  stream_seek(demux->stream,fpos[0]);do{  demux->filepos=stream_tell(demux->stream);  if(demux->filepos>=demux->movi_end && (demux->movi_end>demux->movi_start)){	  ds->eof=1;          return 0;  }  id=stream_read_dword_le(demux->stream);  len=stream_read_dword_le(demux->stream);  if(stream_eof(demux->stream)) return 0;    if(id==mmioFOURCC('L','I','S','T')){      id=stream_read_dword_le(demux->stream);      // list type      continue;  }    if(id==mmioFOURCC('R','I','F','F')){      mp_msg(MSGT_DEMUX,MSGL_V,"additional RIFF header...\n");      id=stream_read_dword_le(demux->stream);      // "AVIX"      continue;  }    if(ds==demux_avi_select_stream(demux,id)){    // read it!    ret=demux_avi_read_packet(demux,ds,id,len,priv->idx_pos-1,0);  } else {    // skip it!    int skip=(len+1)&(~1); // total bytes in this chunk    stream_skip(demux->stream,skip);  }  } while(ret!=1);  fpos[0]=stream_tell(demux->stream);  return 1;}// AVI demuxer parameters:int index_mode=-1;  // -1=untouched  0=don't use index  1=use (geneate) indexchar *index_file_save = NULL, *index_file_load = NULL;int force_ni=0;     // force non-interleaved AVI parsingvoid read_avi_header(demuxer_t *demuxer,int index_mode);static demuxer_t* demux_open_avi(demuxer_t* demuxer){    demux_stream_t *d_audio=demuxer->audio;    demux_stream_t *d_video=demuxer->video;    sh_audio_t *sh_audio=NULL;    sh_video_t *sh_video=NULL;    avi_priv_t* priv=malloc(sizeof(avi_priv_t));  // priv struct:  priv->avi_audio_pts=priv->avi_video_pts=0.0f;  priv->pts_correction=0.0f;  priv->skip_video_frames=0;  priv->pts_corr_bytes=0;  priv->pts_has_video=priv->pts_corrected=0;  priv->video_pack_no=0;  priv->audio_block_no=0;  priv->audio_block_size=0;  priv->isodml = 0;  priv->suidx_size = 0;  priv->suidx = NULL;  demuxer->priv=(void*)priv;  //---- AVI header:  read_avi_header(demuxer,(demuxer->stream->flags & STREAM_SEEK_BW)?index_mode:-2);    if(demuxer->audio->id>=0 && !demuxer->a_streams[demuxer->audio->id]){      mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_InvalidAudioStreamNosound,demuxer->audio->id);      demuxer->audio->id=-2; // disabled  }  if(demuxer->video->id>=0 && !demuxer->v_streams[demuxer->video->id]){      mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_InvalidAudioStreamUsingDefault,demuxer->video->id);      demuxer->video->id=-1; // autodetect  }    stream_reset(demuxer->stream);  stream_seek(demuxer->stream,demuxer->movi_start);  priv->idx_pos=0;  priv->idx_pos_a=0;  priv->idx_pos_v=0;  if(priv->idx_size>1){    // decide index format:#if 1    if((AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[0])<demuxer->movi_start ||        AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[1])<demuxer->movi_start )&& !priv->isodml)      priv->idx_offset=demuxer->movi_start-4;    else      priv->idx_offset=0;#else    if(AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[0])<demuxer->movi_start)      priv->idx_offset=demuxer->movi_start-4;    else      priv->idx_offset=0;#endif    mp_msg(MSGT_DEMUX,MSGL_V,"AVI index offset: 0x%X (movi=0x%X idx0=0x%X idx1=0x%X)\n",	    (int)priv->idx_offset,(int)demuxer->movi_start,	    (int)((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset,	    (int)((AVIINDEXENTRY *)priv->idx)[1].dwChunkOffset);  }    if(priv->idx_size>0){      // check that file is non-interleaved:      int i;      off_t a_pos=-1;      off_t v_pos=-1;      for(i=0;i<priv->idx_size;i++){

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?