demux_avi.c

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

C
918
字号
        AVIINDEXENTRY* idx=&((AVIINDEXENTRY *)priv->idx)[i];        demux_stream_t* ds=demux_avi_select_stream(demuxer,idx->ckid);        off_t pos = priv->idx_offset + AVI_IDX_OFFSET(idx);        if(a_pos==-1 && ds==demuxer->audio){          a_pos=pos;          if(v_pos!=-1) break;        }        if(v_pos==-1 && ds==demuxer->video){          v_pos=pos;          if(a_pos!=-1) break;        }      }      if(v_pos==-1){        mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI_NI: " MSGTR_MissingVideoStream);	return NULL;      }      if(a_pos==-1){        d_audio->sh=sh_audio=NULL;      } else {        if(force_ni || abs(a_pos-v_pos)>0x100000){  // distance > 1MB          mp_msg(MSGT_DEMUX,MSGL_INFO,MSGTR_NI_Message,force_ni?MSGTR_NI_Forced:MSGTR_NI_Detected);          demuxer->type=DEMUXER_TYPE_AVI_NI; // HACK!!!!          demuxer->desc=&demuxer_desc_avi_ni; // HACK!!!!	  pts_from_bps=1; // force BPS sync!        }      }  } else {      // no index      if(force_ni){          mp_msg(MSGT_DEMUX,MSGL_INFO,MSGTR_UsingNINI);          demuxer->type=DEMUXER_TYPE_AVI_NINI; // HACK!!!!          demuxer->desc=&demuxer_desc_avi_nini; // HACK!!!!	  priv->idx_pos_a=	  priv->idx_pos_v=demuxer->movi_start;	  pts_from_bps=1; // force BPS sync!      }      demuxer->seekable=0;  }  if(!ds_fill_buffer(d_video)){    mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI: " MSGTR_MissingVideoStreamBug);    return NULL;  }  sh_video=d_video->sh;sh_video->ds=d_video;  if(d_audio->id!=-2){    mp_msg(MSGT_DEMUX,MSGL_V,"AVI: Searching for audio stream (id:%d)\n",d_audio->id);    if(!priv->audio_streams || !ds_fill_buffer(d_audio)){      mp_msg(MSGT_DEMUX,MSGL_INFO,"AVI: " MSGTR_MissingAudioStream);      d_audio->sh=sh_audio=NULL;    } else {      sh_audio=d_audio->sh;sh_audio->ds=d_audio;    }  }  // calculating audio/video bitrate:  if(priv->idx_size>0){    // we have index, let's count 'em!    int64_t vsize=0;    int64_t asize=0;    size_t vsamples=0;    size_t asamples=0;    int i;    for(i=0;i<priv->idx_size;i++){       int id=avi_stream_id(((AVIINDEXENTRY *)priv->idx)[i].ckid);      int len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength;      if(sh_video->ds->id == id) {        vsize+=len;        ++vsamples;      }      else if(sh_audio && sh_audio->ds->id == id) {        asize+=len;	asamples+=(len+priv->audio_block_size-1)/priv->audio_block_size;      }    }    mp_msg(MSGT_DEMUX,MSGL_V,"AVI video size=%"PRId64" (%u) audio size=%"PRId64" (%u)\n",vsize,vsamples,asize,asamples);    priv->numberofframes=vsamples;    sh_video->i_bps=((float)vsize/(float)vsamples)*(float)sh_video->video.dwRate/(float)sh_video->video.dwScale;    if(sh_audio) sh_audio->i_bps=((float)asize/(float)asamples)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale;  } else {    // guessing, results may be inaccurate:    int64_t vsize;    int64_t asize=0;    if((priv->numberofframes=sh_video->video.dwLength)<=1)      // bad video header, try to get number of frames from audio      if(sh_audio && sh_audio->wf->nAvgBytesPerSec) priv->numberofframes=sh_video->fps*sh_audio->audio.dwLength/sh_audio->audio.dwRate*sh_audio->audio.dwScale;    if(priv->numberofframes<=1){      mp_msg(MSGT_SEEK,MSGL_WARN,MSGTR_CouldntDetFNo);      priv->numberofframes=0;    }              if(sh_audio){      if(sh_audio->wf->nAvgBytesPerSec && sh_audio->audio.dwSampleSize!=1){        asize=(float)sh_audio->wf->nAvgBytesPerSec*sh_audio->audio.dwLength*sh_audio->audio.dwScale/sh_audio->audio.dwRate;      } else {        asize=sh_audio->audio.dwLength;        sh_audio->i_bps=(float)asize/(sh_video->frametime*priv->numberofframes);      }    }    vsize=demuxer->movi_end-demuxer->movi_start-asize-8*priv->numberofframes;    mp_msg(MSGT_DEMUX,MSGL_V,"AVI video size=%"PRId64" (%u)  audio size=%"PRId64"\n",vsize,priv->numberofframes,asize);    sh_video->i_bps=(float)vsize/(sh_video->frametime*priv->numberofframes);  }  return demuxer;  }void demux_seek_avi(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags){    avi_priv_t *priv=demuxer->priv;    demux_stream_t *d_audio=demuxer->audio;    demux_stream_t *d_video=demuxer->video;    sh_audio_t *sh_audio=d_audio->sh;    sh_video_t *sh_video=d_video->sh;    float skip_audio_secs=0;    //F("1\n");  //FIXME: OFF_T - Didn't check AVI case yet (avi files can't be >2G anyway?)  //================= seek in AVI ==========================    int rel_seek_frames=rel_seek_secs*sh_video->fps;    int video_chunk_pos=d_video->pos;    int i;      if(flags&1){	// seek absolute	video_chunk_pos=0;      }            if(flags&2){	rel_seek_frames=rel_seek_secs*priv->numberofframes;      }          priv->skip_video_frames=0;      priv->avi_audio_pts=0;// ------------ STEP 1: find nearest video keyframe chunk ------------      // find nearest video keyframe chunk pos:      if(rel_seek_frames>0){        // seek forward        while(video_chunk_pos<priv->idx_size-1){          int id=((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].ckid;          if(avi_stream_id(id)==d_video->id){  // video frame            if((--rel_seek_frames)<0 && ((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break;          }          ++video_chunk_pos;        }      } else {        // seek backward        while(video_chunk_pos>0){          int id=((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].ckid;          if(avi_stream_id(id)==d_video->id){  // video frame            if((++rel_seek_frames)>0 && ((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break;          }          --video_chunk_pos;        }      }      priv->idx_pos_a=priv->idx_pos_v=priv->idx_pos=video_chunk_pos;      // re-calc video pts:      d_video->pack_no=0;      for(i=0;i<video_chunk_pos;i++){          int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;          if(avi_stream_id(id)==d_video->id) ++d_video->pack_no;      }      priv->video_pack_no=      sh_video->num_frames=sh_video->num_frames_decoded=d_video->pack_no;      priv->avi_video_pts=d_video->pack_no*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;      d_video->pos=video_chunk_pos;            mp_msg(MSGT_SEEK,MSGL_DBG2,"V_SEEK:  pack=%d  pts=%5.3f  chunk=%d  \n",d_video->pack_no,priv->avi_video_pts,video_chunk_pos);// ------------ STEP 2: seek audio, find the right chunk & pos ------------      d_audio->pack_no=0;      priv->audio_block_no=0;      d_audio->dpos=0;      if(sh_audio){        int i;        int len=0;	int skip_audio_bytes=0;	int curr_audio_pos=-1;	int audio_chunk_pos=-1;	int chunk_max=(demuxer->type==DEMUXER_TYPE_AVI)?video_chunk_pos:priv->idx_size;		if(sh_audio->audio.dwSampleSize){	    // constant rate audio stream	    /* immediate seeking to audio position, including when streams are delayed */	    curr_audio_pos=(priv->avi_video_pts + audio_delay)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale;	    curr_audio_pos*=sh_audio->audio.dwSampleSize;        // find audio chunk pos:          for(i=0;i<chunk_max;i++){            int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;            if(avi_stream_id(id)==d_audio->id){                len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength;                if(d_audio->dpos<=curr_audio_pos && curr_audio_pos<(d_audio->dpos+len)){                  break;                }                ++d_audio->pack_no;                priv->audio_block_no+=priv->audio_block_size ?		    ((len+priv->audio_block_size-1)/priv->audio_block_size) : 1;                d_audio->dpos+=len;            }          }	  audio_chunk_pos=i;	  skip_audio_bytes=curr_audio_pos-d_audio->dpos;          mp_msg(MSGT_SEEK,MSGL_V,"SEEK: i=%d (max:%d) dpos=%d (wanted:%d)  \n",	      i,chunk_max,(int)d_audio->dpos,curr_audio_pos);	      	} else {	    // VBR audio	    /* immediate seeking to audio position, including when streams are delayed */	    int chunks=(priv->avi_video_pts + audio_delay)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale;	    audio_chunk_pos=0;	            // find audio chunk pos:          for(i=0;i<priv->idx_size && chunks>0;i++){            int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;            if(avi_stream_id(id)==d_audio->id){                len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength;		if(i>chunk_max){		  skip_audio_bytes+=len;		} else {		  ++d_audio->pack_no;                  priv->audio_block_no+=priv->audio_block_size ?		    ((len+priv->audio_block_size-1)/priv->audio_block_size) : 1;                  d_audio->dpos+=len;		  audio_chunk_pos=i;		}		if(priv->audio_block_size)		    chunks-=(len+priv->audio_block_size-1)/priv->audio_block_size;            }          }	}		// Now we have:	//      audio_chunk_pos = chunk no in index table (it's <=chunk_max)	//      skip_audio_bytes = bytes to be skipped after chunk seek	//      d-audio->pack_no = chunk_no in stream at audio_chunk_pos	//      d_audio->dpos = bytepos in stream at audio_chunk_pos	// let's seek!	          // update stream position:          d_audio->pos=audio_chunk_pos;		if(demuxer->type==DEMUXER_TYPE_AVI){	  // interleaved stream:	  if(audio_chunk_pos<video_chunk_pos){            // calc priv->skip_video_frames & adjust video pts counter:	    for(i=audio_chunk_pos;i<video_chunk_pos;i++){              int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;              if(avi_stream_id(id)==d_video->id) ++priv->skip_video_frames;            }            // requires for correct audio pts calculation (demuxer):            priv->avi_video_pts-=priv->skip_video_frames*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;	    priv->avi_audio_pts=priv->avi_video_pts;	    // set index position:	    priv->idx_pos_a=priv->idx_pos_v=priv->idx_pos=audio_chunk_pos;	  }	} else {	    // non-interleaved stream:	    priv->idx_pos_a=audio_chunk_pos;	    priv->idx_pos_v=video_chunk_pos;	    priv->idx_pos=(audio_chunk_pos<video_chunk_pos)?audio_chunk_pos:video_chunk_pos;	}          mp_msg(MSGT_SEEK,MSGL_V,"SEEK: idx=%d  (a:%d v:%d)  v.skip=%d  a.skip=%d/%4.3f  \n",            (int)priv->idx_pos,audio_chunk_pos,video_chunk_pos,            (int)priv->skip_video_frames,skip_audio_bytes,skip_audio_secs);          if(skip_audio_bytes){            demux_read_data(d_audio,NULL,skip_audio_bytes);          }      }	d_video->pts=priv->avi_video_pts; // OSD}void demux_close_avi(demuxer_t *demuxer) {  avi_priv_t* priv=demuxer->priv;  if(!priv)    return;  if(priv->idx_size > 0)    free(priv->idx);  free(priv);}static int demux_avi_control(demuxer_t *demuxer,int cmd, void *arg){    avi_priv_t *priv=demuxer->priv;    demux_stream_t *d_video=demuxer->video;    sh_video_t *sh_video=d_video->sh;    switch(cmd) {	case DEMUXER_CTRL_GET_TIME_LENGTH:    	    if (!priv->numberofframes || !sh_video) return DEMUXER_CTRL_DONTKNOW;	    *((double *)arg)=(double)priv->numberofframes/sh_video->fps;	    if (sh_video->video.dwLength<=1) return DEMUXER_CTRL_GUESS;	    return DEMUXER_CTRL_OK;	case DEMUXER_CTRL_GET_PERCENT_POS:    	    if (!priv->numberofframes || !sh_video) {              return DEMUXER_CTRL_DONTKNOW;	    }	    *((int *)arg)=(int)(priv->video_pack_no*100/priv->numberofframes);	    if (sh_video->video.dwLength<=1) return DEMUXER_CTRL_GUESS;	    return DEMUXER_CTRL_OK;	case DEMUXER_CTRL_SWITCH_AUDIO:	case DEMUXER_CTRL_SWITCH_VIDEO: {	    int audio = (cmd == DEMUXER_CTRL_SWITCH_AUDIO);	    demux_stream_t *ds = audio ? demuxer->audio : demuxer->video;	    void **streams = audio ? demuxer->a_streams : demuxer->v_streams;	    int maxid = FFMIN(100, audio ? MAX_A_STREAMS : MAX_V_STREAMS);	    int chunkid;	    if (ds->id < -1)	      return DEMUXER_CTRL_NOTIMPL;	    if (*(int *)arg >= 0)	      ds->id = *(int *)arg;	    else {	      int i;	      for (i = 0; i < maxid; i++) {	        if (++ds->id >= maxid) ds->id = 0;	        if (streams[ds->id]) break;	      }	    }	    chunkid = (ds->id / 10 + '0') | (ds->id % 10 + '0') << 8;	    ds->sh = NULL;	    if (!streams[ds->id]) // stream not available	      ds->id = -1;	    else	      demux_avi_select_stream(demuxer, chunkid);	    *(int *)arg = ds->id;	    return DEMUXER_CTRL_OK;	}	default:	    return DEMUXER_CTRL_NOTIMPL;    }}static int avi_check_file(demuxer_t *demuxer){	//F("1\n");  int id=stream_read_dword_le(demuxer->stream); // "RIFF"  //F("2\n");  if((id==mmioFOURCC('R','I','F','F')) || (id==mmioFOURCC('O','N','2',' '))) {    stream_read_dword_le(demuxer->stream); //filesize    id=stream_read_dword_le(demuxer->stream); // "AVI "    if(id==formtypeAVI)      return DEMUXER_TYPE_AVI;    // "Samsung Digimax i6 PMP" crap according to bug 742    if(id==mmioFOURCC('A','V','I',0x19))      return DEMUXER_TYPE_AVI;    if(id==mmioFOURCC('O','N','2','f')){      mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_ON2AviFormat);      return DEMUXER_TYPE_AVI;    }  }  return 0;}static demuxer_t* demux_open_hack_avi(demuxer_t *demuxer){   sh_audio_t* sh_a;   demuxer = (demuxer_t*) demux_open_avi(demuxer);   if(!demuxer) return NULL; // failed to open   sh_a = (sh_audio_t*)demuxer->audio->sh;   if(demuxer->audio->id != -2 && sh_a) {#ifdef HAVE_OGGVORBIS    // support for Ogg-in-AVI:    if(sh_a->format == 0xFFFE)#ifdef USE_16M_SDRAM      demuxer = init_avi_with_ogg_funcp(demuxer);#else      demuxer = init_avi_with_ogg(demuxer);#endif    else if(sh_a->format == 0x674F) {      stream_t* s;      demuxer_t  *od;      s = new_ds_stream(demuxer->audio);      od = new_demuxer(s,DEMUXER_TYPE_OGG,-1,-2,-2,NULL);#ifdef USE_16M_SDRAM      if(!demux_ogg_open_funcp(od)) {#else      if(!demux_ogg_open(od)) {#endif        mp_msg( MSGT_DEMUXER,MSGL_ERR,MSGTR_ErrorOpeningOGGDemuxer);        free_stream(s);        demuxer->audio->id = -2;      } else        demuxer = new_demuxers_demuxer(demuxer,od,demuxer);   }#endif   }   return demuxer;}demuxer_desc_t demuxer_desc_avi = {  "AVI demuxer",  "avi",  "AVI",  "Arpi?",  "AVI files, including non interleaved files",  DEMUXER_TYPE_AVI,  1, // safe autodetect  avi_check_file,  demux_avi_fill_buffer,  demux_open_hack_avi,  demux_close_avi,  demux_seek_avi,  demux_avi_control};demuxer_desc_t demuxer_desc_avi_ni = {  "AVI demuxer, non-interleaved",  "avini",  "AVI",  "Arpi?",  "AVI files, including non interleaved files",  DEMUXER_TYPE_AVI,  1, // safe autodetect  avi_check_file,  demux_avi_fill_buffer_ni,  demux_open_hack_avi,  demux_close_avi,  demux_seek_avi,  demux_avi_control};demuxer_desc_t demuxer_desc_avi_nini = {  "AVI demuxer, non-interleaved and no index",  "avinini",  "AVI",  "Arpi?",  "AVI files, including non interleaved files",  DEMUXER_TYPE_AVI,  1, // safe autodetect  avi_check_file,  demux_avi_fill_buffer_nini,  demux_open_hack_avi,  demux_close_avi,  demux_seek_avi,  demux_avi_control};

⌨️ 快捷键说明

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