Mplayer学习笔记2--打开分离器demuxer

分离器是把流中的视频和音频数据分离开来,分别进行播放。

不同协议的流有不同的分离器,所以首先来看如果打开正确的分离器demuxer

在mplayer.c中,从main开始执行到打开demuxer部分:

2956 //============ Open DEMUXERS --- DETECT file type =======================

2957 current_module="demux_open";

2960 mpctx->demuxer=demux_open(mpctx->stream,
			   mpctx->file_format,audio_id,video_id,dvdsub_id,filename);

调用demux_open,注意传入的参数。

832 demuxer_t* demux_open(stream_t *vs,int file_format,int audio_id,int video_id,int dvdsub_id,char* filename){

	… …
 876   vd = demux_open_stream(vs, demuxer_type ? demuxer_type : file_format,

 877          demuxer_force, audio_stream ? -2 : audio_id, video_id,

 878          sub_stream ? -2 : dvdsub_id, filename);
… …
 913     return vd;

 914 }

调用demux_open_stream打开流对应的demuxer

677 static demuxer_t* demux_open_stream(stream_t *stream, int file_format,

 678                     int force, int audio_id, int video_id, int dvdsub_id,

 679                     char* filename) {

	… …
694 if (file_format) {

 695   if ((demuxer_desc = get_demuxer_desc_from_type(file_format))) {

 696     demuxer = new_demuxer(stream,demuxer_desc->type,audio_id,video_id,dvdsub_id,filename);

 697     if (demuxer_desc->check_file)

 698       fformat = demuxer_desc->check_file(demuxer);

 699     if (force || !demuxer_desc->check_file)

 700       fformat = demuxer_desc->type;

 701     if (fformat != 0) {

 702       if (fformat == demuxer_desc->type) {

 703         demuxer_t *demux2 = demuxer;

 704         // Move messages to demuxer detection code?

 705         mp_msg(MSGT_DEMUXER, MSGL_INFO, MSGTR_Detected_XXX_FileFormat, 			demuxer_desc->shortdesc);

 706         file_format = demuxer_desc->type = fformat;

 707         if (!demuxer->desc->open || (demux2 = demuxer->desc->open(demuxer))) {

 708           demuxer = demux2;

 709           goto dmx_open;

 710         }

 711       } else {

 712         // Format changed after check, recurse

 713         free_demuxer(demuxer);

 714         return demux_open_stream(stream, fformat, force,

 715                  audio_id, video_id, dvdsub_id, filename);

 716       }

 717     }

 718     // Check failed for forced demuxer, quit

 719     free_demuxer(demuxer);

 720     return NULL;

 721   }

 722 }

	… …
 799 //====== File format recognized, set up these for compatibility: =========

 800 dmx_open:

	… ...
 815 return demuxer;

 816 }

来看第695行的demuxer_desc= get_demuxer_desc_from_type(file_format)

176 static demuxer_desc_t* get_demuxer_desc_from_type(int file_format)

 177 {   

 178   int i;

 179     

 180   for (i = 0; demuxer_list[i]; i++)

 181     if (file_format == demuxer_list[i]->type)

 182       return demuxer_list[i];

 183         

 184   return NULL;

 185 }

demuxer_list数组中通过判断file_format找到对应的demuxer的描述符。

 71 demuxer_desc_t* demuxer_list[] = {

  72   &demuxer_desc_rawaudio,

  73   &demuxer_desc_rawvideo,

  74 #ifdef USE_TV

  75   &demuxer_desc_tv,

  76 #endif

  77   &demuxer_desc_mf,

  78 #ifdef USE_LIBAVFORMAT

  79   &demuxer_desc_lavf_preferred,

  80 #endif

  81   &demuxer_desc_avi,

  82   &demuxer_desc_y4m,

  83   &demuxer_desc_asf,

  84   &demuxer_desc_nsv,

  85   &demuxer_desc_nuv,

  86   &demuxer_desc_real,

  87   &demuxer_desc_smjpeg,

  88   &demuxer_desc_matroska,

	… …
 132 #ifdef HAVE_XMMS

 133   &demuxer_desc_xmms,

 134 #endif

 135   NULL

 136 };

这里如果播放的是MMS网络电台的话,一般都是demuxer_desc_asf这个描述符,在目录

libmpdemux/demux_asf.c下可以找到:

688 demuxer_desc_t demuxer_desc_asf = {

689   "ASF demuxer",

690   "asf",

691   "ASF",

692   "A'rpi",

693   "ASF, WMV, WMA",

694   DEMUXER_TYPE_ASF,

695   1, // safe autodetect

696   asf_check_header,
	
697   demux_asf_fill_buffer,

698   demux_open_asf,

699   demux_close_asf,

700   demux_seek_asf,

701   demux_asf_control

702 };

实际上,接下来的判断操作就是用到这个数组里的操作函数。

接下来是第696行的new一个demuxer,并把描述符demuxer_descstream对象保存到demuxer,这样在播放的时候,只需要得到demuxer就可以做任何关于流的事情了

188 demuxer_t* new_demuxer(stream_t *stream,int type,int a_id,int v_id,int s_id,char *filename){

 189   demuxer_t *d=malloc(sizeof(demuxer_t));

 190   memset(d,0,sizeof(demuxer_t));

 191   d->stream=stream;

 192   d->stream_pts = MP_NOPTS_VALUE;

 193   d->movi_start=stream->start_pos;

 194   d->movi_end=stream->end_pos;

 195   d->seekable=1;

 196   d->synced=0;

 197   d->filepos=0;

 198   d->audio=new_demuxer_stream(d,a_id);

 199   d->video=new_demuxer_stream(d,v_id);

 200   d->sub=new_demuxer_stream(d,s_id);

 201   d->type=type;

 202   if(type)

 203     if (!(d->desc = get_demuxer_desc_from_type(type)))

 204       mp_msg(MSGT_DEMUXER,MSGL_ERR,"BUG! Invalid demuxer type in new_demuxer(), big troubles ahead.");

 205   if(filename) // Filename hack for avs_check_file

 206     d->filename=strdup(filename);

 207   stream_reset(stream);

 208   stream_seek(stream,stream->start_pos);

 209   return d;

 210 }

另外还为音频流(audio)、视频流(video)和子流(sub),三种流建立一个demuxer_stream对象,用来分别保存不同种类流的状态信息,当然demuxer_stream有保存demuxer指针,这样不同种类的流对象demuxer_stream就可以单独运行,通过demuxer来实现读取和解释网络数据的功能。

143 demux_stream_t* new_demuxer_stream(struct demuxer_st *demuxer,int id){

 144   demux_stream_t* ds=malloc(sizeof(demux_stream_t));

 145   ds->buffer_pos=ds->buffer_size=0;

 146   ds->buffer=NULL;

 147   ds->pts=0;

 148   ds->pts_bytes=0;

 149   ds->eof=0;

 150   ds->pos=0;

 151   ds->dpos=0;

 152   ds->pack_no=0;

 153 //---------------

 154   ds->packs=0;

 155   ds->bytes=0;

 156   ds->first=ds->last=ds->current=NULL;

 157   ds->id=id;

 158   ds->demuxer=demuxer;

 159 //----------------

 160   ds->asf_seq=-1;

 161   ds->asf_packet=NULL;

 162 //----------------

 163   ds->ss_mul=ds->ss_div=0;

 164 //----------------

 165   ds->sh=NULL;

 166   return ds;

 167 }


回到demux_open_stream函数,第707行调用了demuxer的描述符desc中的open函数,实际上调用了demuxer_desc_asf中的open函数demux_open_asf

626 static demuxer_t* demux_open_asf(demuxer_t* demuxer)

627 {

628     struct asf_priv* asf = demuxer->priv;

629     sh_audio_t *sh_audio=NULL;   

630     sh_video_t *sh_video=NULL;   

631    

632     //---- ASF header:  

633     if(!asf) return NULL;

634     init_priv(asf);     

635     if (!read_asf_header(demuxer,asf))

636         return NULL;    

637     stream_reset(demuxer->stream);

638     stream_seek(demuxer->stream,demuxer->movi_start);

639 //    demuxer->idx_pos=0;

640 //    demuxer->endpos=avi_header.movi_end;

641     if(demuxer->video->id != -2) {

642         if(!ds_fill_buffer(demuxer->video)){

643             mp_msg(MSGT_DEMUXER,MSGL_WARN,"ASF: " MSGTR_MissingVideoStream);

644             demuxer->video->sh=NULL;     

645             //printf("ASF: missing video stream!? contact the author, it may be a bug :(\n");

646         } else {

647             sh_video=demuxer->video->sh;sh_video->ds=demuxer->video;

648             sh_video->fps=1000.0f; sh_video->frametime=0.001f;

649    

650             if (asf->asf_is_dvr_ms) {    

651                 sh_video->bih->biWidth = 0;  

652                 sh_video->bih->biHeight = 0; 

653             }

654         }

655     }

656 

657     if(demuxer->audio->id!=-2){

658         mp_msg(MSGT_DEMUXER,MSGL_V,MSGTR_ASFSearchingForAudioStream,demuxer->audio->id);

659         if(!ds_fill_buffer(demuxer->audio)){

660             mp_msg(MSGT_DEMUXER,MSGL_INFO,"ASF: " MSGTR_MissingAudioStream);

661             demuxer->audio->sh=NULL;

662         } else {

663             sh_audio=demuxer->audio->sh;sh_audio->ds=demuxer->audio;

664             sh_audio->format=sh_audio->wf->wFormatTag;

665         }

666     }

667     if(!demuxer->stream->seek)

668         demuxer->seekable=0;

669 

670     return demuxer;

671 }

以上的代码片段就开始获取一些网络流信息了,首先读取流信息头,第656read_asf_header(demuxer,asf),并根据信息头查看该流数据中包含哪些各类的流,或者多个各类组合,然后为每个各类的流建立一个streamheader结构体,例如音频流streamheadersh_audio。并将stream_header保存到demuxer中的a_stream[MAX_A_STREAMS]中去。

426 int read_asf_header(demuxer_t *demuxer,struct asf_priv* asf){

427   int hdr_len = asf->header.objh.size - sizeof(asf->header);

428   int hdr_skip = 0;

429   char *hdr = NULL;

430   char guid_buffer[16];

431   int pos, start = stream_tell(demuxer->stream);

432   uint32_t* streams = NULL;

433   int audio_streams=0;

434   int video_streams=0;

435   uint16_t stream_count=0;

436   int best_video = -1;

437   int best_audio = -1;

438   uint64_t data_len;

439   ASF_stream_header_t *streamh;

440   uint8_t *buffer;

441   int audio_pos=0;

442 

443   if(hdr_len < 0) {

444     mp_msg(MSGT_HEADER, MSGL_FATAL, "Header size is too small.\n");

445     return 0;

446   }

447 

448   if (hdr_len > 1024 * 1024) {

449     mp_msg(MSGT_HEADER, MSGL_ERR, MSGTR_MPDEMUX_ASFHDR_HeaderSizeOver1MB,

450             hdr_len);

451     hdr_skip = hdr_len - 1024 * 1024;

452     hdr_len = 1024 * 1024;

453   }

454   hdr = malloc(hdr_len);

455   if (!hdr) {

456     mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_HeaderMallocFailed,

457             hdr_len);

458     return 0;

459   }

460   stream_read(demuxer->stream, hdr, hdr_len);

461   if (hdr_skip)

462     stream_skip(demuxer->stream, hdr_skip);

463   if (stream_eof(demuxer->stream)) {

464     mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_EOFWhileReadingHeader);

465     goto err_out;

466   }

467 

468   if (is_drm(hdr, hdr_len))

469     mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_DRMProtected);

470 

471   if ((pos = find_asf_guid(hdr, asf_ext_stream_audio, 0, hdr_len)) >= 0)

472   {

473     // Special case: found GUID for dvr-ms audio.

474     // Now skip back to associated stream header.

475     int sh_pos=0;

476 

477     sh_pos = find_backwards_asf_guid(hdr, asf_stream_header_guid, pos);

478 

479     if (sh_pos > 0) {

480       sh_audio_t *sh_audio;

481 

482        mp_msg(MSGT_HEADER, MSGL_V, "read_asf_header found dvr-ms audio stream header pos=%d\n", sh_pos);

483       // found audio stream header - following code reads header and

484       // initializes audio stream.

485       audio_pos = pos - 16 - 8;

486       streamh = (ASF_stream_header_t *)&hdr[sh_pos];

487       le2me_ASF_stream_header_t(streamh);

488       audio_pos += 64; //16+16+4+4+4+16+4;

489       buffer = &hdr[audio_pos];

490       sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F);

491       mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_AudioID, "asfheader", streamh->stream_no & 0x7F);

492       ++audio_streams;

493       if (!asf_init_audio_stream(demuxer, asf, sh_audio, streamh, &audio_pos, &buffer, hdr, hdr_len))

494         goto len_err_out;

495       if (!get_ext_stream_properties(hdr, hdr_len, streamh->stream_no, asf, 0))

496         goto len_err_out;

497     }

498   }

先看460行:stream_read(demuxer->stream,hdr, hdr_len);

读取网络流数据到缓冲区hdr,长度为hdr_len,这有点类似文件系统中的MBR。注意传入参数是demuxer->stream,由之前的分析知道,真正的网络读取函数保存在stream结构体里。

203 inline static int stream_read(stream_t *s,char* mem,int total){

204   int len=total;

205   while(len>0){

206     int x;

207     x=s->buf_len-s->buf_pos;

208     if(x==0){

209       if(!cache_stream_fill_buffer(s)) return total-len; // EOF

210       x=s->buf_len-s->buf_pos;

211     }

212     if(s->buf_pos>s->buf_len) mp_msg(MSGT_DEMUX, MSGL_WARN, "stream_read: WARNING! s->buf_pos>s->buf_len\n");

213     if(x>len) x=len;

214     memcpy(mem,&s->buffer[s->buf_pos],x);

215     s->buf_pos+=x; mem+=x; len-=x;

216   }

217   return total;

218 }

调用cache_stream_fill_buffer来读取流数据,其中s->buffer为接收流数据的缓冲区,s->buf_pos为当前接收数据的在缓冲区的起始地址,s->buf_len为缓冲区的长度。

328 int cache_stream_fill_buffer(stream_t *s){

329   int len;

330   if(s->eof){ s->buf_pos=s->buf_len=0; return 0; }

331   if(!s->cache_pid) return stream_fill_buffer(s);

332     

333 //  cache_stats(s->cache_data);

334     

335   if(s->pos!=((cache_vars_t*)s->cache_data)->read_filepos) mp_msg(MSGT_CACHE,MSGL_ERR,"!!! read_filepos differs!!! report this bug    ...\n"); 

336 

337   len=cache_read(s->cache_data,s->buffer, ((cache_vars_t*)s->cache_data)->sector_size);

338   //printf("cache_stream_fill_buffer->read -> %d\n",len);

339   

340   if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; return 0; }

341   s->buf_pos=0;

342   s->buf_len=len;

343   s->pos+=len;

344 //  printf("[%d]",len);fflush(stdout);

345   return len;

346 

347 }

331行可知,s->cache_pid0,也就是说没有创建cache进程,那么就会直接调用stream_fill_buffer(s)填充s->buffer,然后返回。如果使用cache,那么就从s->cache_data中把一个扇区大小sector_size的数据拷贝到s->buffer。然后更新s->buffer相关的状态变量。

首先来看stream_fill_buffer(s)

253 int stream_fill_buffer(stream_t *s){

254   int len;

255   if (/*s->fd == NULL ||*/ s->eof) { s->buf_pos = s->buf_len = 0; return 0; }

256   switch(s->type){

257   case STREAMTYPE_STREAM:

258 #ifdef MPLAYER_NETWORK

259     if( s->streaming_ctrl!=NULL ) {

260         len=s->streaming_ctrl->streaming_read(s->fd,s->buffer,STREAM_BUFFER_SIZE, s->streaming_ctrl);break;

261     } else {

262       len=read(s->fd,s->buffer,STREAM_BUFFER_SIZE);break;

263     }

264 #else

265     len=read(s->fd,s->buffer,STREAM_BUFFER_SIZE);break;

266 #endif

267   case STREAMTYPE_DS:

268     len = demux_read_data((demux_stream_t*)s->priv,s->buffer,STREAM_BUFFER_SIZE);

269     break;

270 

271 

272   default:

273     len= s->fill_buffer ? s->fill_buffer(s,s->buffer,STREAM_BUFFER_SIZE) : 0;

274   }

275   if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; return 0; }

276   s->buf_pos=0;

277   s->buf_len=len;

278   s->pos+=len;

279 //  printf("[%d]",len);fflush(stdout);

280   return len;

281 }

在这个场景里,s->type=STREAMTYPE_STREAM

在笔记1中打开流的操作中有对s->streaming_ctrl的赋值分析。这里是通过其成员函数streaming_read来读取网络流数据,读取STREAM_BUFFER_SIZE大小的数据,当然返回值len才是真正的读取到的数据大小。

根据笔记1的分析,找到streaming_read的出处stream/asf_mmst_streaming.c

505 static int asf_mmst_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) 

506 {

507   int len, ret;

508     

509   while( stream_ctrl->buffer_size==0 ) {

510           // buffer is empty - fill it!

511       int ret = get_media_packet( fd, packet_length1, stream_ctrl);

512       if( ret<0 ) {

513           mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_GetMediaPacketErr,strerror(errno));

514           return -1;

515       } else if (ret==0){ //EOF?   

516           return ret;

517         }

518   }

519    

520       len = stream_ctrl->buffer_size-stream_ctrl->buffer_pos;

521 //    printf("buffer_size====%d\tbuffer_pos=====%d\n",stream_ctrl->buffer_size,stream_ctrl->buffer_pos);

522       if(len>size) len=size;

523       memcpy( buffer, (stream_ctrl->buffer)+(stream_ctrl->buffer_pos), len );                                                     

524       stream_ctrl->buffer_pos += len;

525       if( stream_ctrl->buffer_pos>=stream_ctrl->buffer_size ) {

526           free( stream_ctrl->buffer ); 

527           stream_ctrl->buffer = NULL;  

528           stream_ctrl->buffer_size = 0;

529           stream_ctrl->buffer_pos = 0; 

530       }

531       return len;

532    

533 }  

以上的这个代码主要通过第511行的get_media_packet函数来获取网络包数据,数据存放在stream_ctrl->buffer中,这里的stream_ctrl也维护了一组与stream结构体类似的缓冲区和状态变量。数据接收成功之后,再把stream_ctrl->buffer中的数据拷贝到传入的buffer中,实际上就是s->buffer

409 static int get_media_packet (int s, int padding, streaming_ctrl_t *stream_ctrl) {

410   unsigned char  pre_header[8];

411   char           data[BUF_SIZE];

412    

413   if (!get_data (s, pre_header, 8)) {

414     mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_PreHeaderReadFailed);

415     return 0;

416   }

417 //  char i; 

418 //  for (i=0; i<8; i++)  
419 //    mp_msg(MSGT_NETWORK,MSGL_INFO,"pre_header[%d] = %02x (%d)\n",

420 //      i, pre_header[i], pre_header[i]);

421 //    printf("%2x\t",pre_header[i]);

422 //    printf("\n");     

423 //    mp_msg(MSGT_NETWORK,MSGL_INFO,"pre_header[%d] = %02x (%d)\n",

424 //      0, pre_header[0], pre_header[0]);

425    

426   if (pre_header[4] == 0x04) {

427    

428     int packet_len;     

429    

430     packet_len = (pre_header[7] << 8 | pre_header[6]) - 8;

431 

432 //    mp_msg(MSGT_NETWORK,MSGL_INFO,"asf media packet detected, len=%d\n", packet_len);

433 

434     if (packet_len < 0 || packet_len > BUF_SIZE) {

435     mp_msg(MSGT_NETWORK,MSGL_INFO,"asf media packet detected, len=%d\n", packet_len);   //Leo

436       mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize);

437       return 0;

438     }

439       

440     if (!get_data (s, data, packet_len)) {

441       mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_MediaDataReadFailed);//Leo

442       return 0;

443     }

444 

445     streaming_bufferize(stream_ctrl, data, padding);

446 

447   } else {

448 

449     int32_t packet_len;

450     int command;

451 

452     if (!get_data (s, (char*)&packet_len, 4)) {

453       mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_packet_lenReadFailed);

454       return 0;

455     }

456 

457     packet_len = get_32 ((unsigned char*)&packet_len, 0) + 4;

458 

459     if (packet_len < 0 || packet_len > BUF_SIZE) {

460       mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize);

461       return 0;

462     }

463 

464     if (!get_data (s, data, packet_len)) {

465       mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_CmdDataReadFailed);

466       return 0;

467     }

468 

469     if ( (pre_header[7] != 0xb0) || (pre_header[6] != 0x0b)

470      || (pre_header[5] != 0xfa) || (pre_header[4] != 0xce) ) {

471 

472       mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_MissingSignature);

473       return -1;

474     }

475 

476     command = get_32 (data, 24) & 0xFFFF;

477 

478 //    mp_msg(MSGT_NETWORK,MSGL_INFO,"\ncommand packet detected, len=%d  cmd=0x%X\n", packet_len, command);

479 

480     if (command == 0x1b)

481       send_command (s, 0x1b, 0, 0, 0, data);

482     else if (command == 0x1e) {

483       mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_PatentedTechnologyJoke);

484       return 0;

485     }

486     else if (command == 0x21 ) {

487     // Looks like it's new in WMS9

488     // Unknown command, but ignoring it seems to work.

489     return 0;

490     }

491     else if (command != 0x05) {

492       mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_UnknownCmd,command);

493       return -1;

494     }

495   }

496 

497 //  mp_msg(MSGT_NETWORK,MSGL_INFO,"get media packet succ\n");

498 

499   return 1;

500 }

从上述代码片段可以看到,读取mms数据流的基本步骤是,首先读取8个字节的数据包头到pre_header中。然后判断pre_header[4],估计这是不同mms流的判别标志。如果pre_header[4]=0x04,那么从pre_header中分析出接下来要接收的数据包大小packet_len,然后读取packet_len大小的数据。如果是其它类别是的mms流,还要根据其协议与服务器进行交互,甚至通过send_command函数发送命令给服务器。

接下来看真正的读取网络数据函数get_data

201 static int get_data (int s, char *buf, size_t count)

202 {

203   ssize_t  len;

204   size_t total = 0;

205   int num = 0;

206   while (total < count) {

207     len = recv (s, &buf[total], count-total, 0);

208 

209     if (len<=0) {

210       perror ("read error:");

211       return 0;

212     }

223     total += len;

224 

225     if (len != 0) {

226       mp_msg(MSGT_NETWORK,MSGL_INFO,"[%d/%d]", total, count);

228       fflush (stdout);

229     }

230 

231   }

232 

233   return 1;

234 

235 }

由第214行知道,通过recv函数来读取网络流数据。这样的读取网络操作是不能被打断的,不过在笔记1的分析中,连接服务器的时候已经设置网络操作函数为非阻塞的了,且设置了超时,所以没有读取到数据超时后返回。不过上述代码对网络接收的处理比较简单,如果网络产生错误,可能会产生一些信号,影响到进程,这里应该可以处理得更好些,以适应较差的网络环境。

回到读取头信息函数read_asf_header

471   if ((pos = find_asf_guid(hdr, asf_ext_stream_audio, 0, hdr_len)) >= 0)
从hdr中查找 asf_ext_stream_audio标志,该标志定义在libmpdemux/asfheader.c中。
然后查找asf_stream_header_guid标志:
sh_pos = find_backwards_asf_guid(hdr, asf_stream_header_guid, pos);

如果找到则创建一个sh_audio结构体:

sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F);


 240 sh_audio_t* new_sh_audio_aid(demuxer_t *demuxer,int id,int aid){

 241     if(id > MAX_A_STREAMS-1 || id < 0)

 242     {

 243     mp_msg(MSGT_DEMUXER,MSGL_WARN,"Requested audio stream id overflow (%d > %d)\n",

 244         id, MAX_A_STREAMS);

 245     return NULL;

 246     }

 247     if(demuxer->a_streams[id]){

 248         mp_msg(MSGT_DEMUXER,MSGL_WARN,MSGTR_AudioStreamRedefined,id);

 249     } else {

 250         sh_audio_t *sh;

 251         mp_msg(MSGT_DEMUXER,MSGL_V,MSGTR_FoundAudioStream,id);

 252         demuxer->a_streams[id]=calloc(1, sizeof(sh_audio_t));

 253         sh = demuxer->a_streams[id];

 254         // set some defaults

 255         sh->samplesize=2;

 256         sh->sample_format=AF_FORMAT_S16_NE;

 257         sh->audio_out_minsize=8192;/* default size, maybe not enough for Win32/ACM*/

 258         sh->pts=MP_NOPTS_VALUE;

 259           mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_ID=%d\n", aid);

 260     }

 261     ((sh_audio_t *)demuxer->a_streams[id])->aid = aid;

 262     return demuxer->a_streams[id];

 263 }

所创建的sh_audio结构体保存在demuxer中的a_streams数组中。并对sh_audio作一些初始化工作,由sh_audio的成员变量初始化,猜得sh_audio肯定跟audio的输出有关。

streamh->stream_no的低15位保存了该sh_audioID,也就是说可以根据demuxer->a_streams数组找到该sh_audio。其中streamh结构体数据是来自hdr,在read_asf_header函数中:

486       streamh = (ASF_stream_header_t *)&hdr[sh_pos];

487       le2me_ASF_stream_header_t(streamh);

这样,意味着一个分离器demuxer最大可以处理MAX_A_STREAMS路语音,不同音频流只需要根据头信息hdr就可以找到对应的sh_audio。同理对于其它类的流处理:

176 typedef struct demuxer_st {

	… ...
193   // stream headers:

194   void* a_streams[MAX_A_STREAMS]; // audio streams (sh_audio_t)

195   void* v_streams[MAX_V_STREAMS]; // video sterams (sh_video_t)

196   void *s_streams[MAX_S_STREAMS];   // dvd subtitles (flag)

	… ...
203 } demuxer_t;


继续回到读取头信息函数read_asf_header,接着往下分析:

493       if (!asf_init_audio_stream(demuxer, asf, sh_audio, streamh, &audio_pos, &buffer, hdr, hdr_len))

494         goto len_err_out;


进入 asf_init_audio_stream:

400 static int asf_init_audio_stream(demuxer_t *demuxer,struct asf_priv* asf, sh_audio_t* sh_audio, ASF_stream_header_t *streamh, int     *ppos, uint8_t** buf, char *hdr, unsigned int hdr_len)

401 {       

402   uint8_t *buffer = *buf;

403   int pos = *ppos;

404     

405   sh_audio->wf=calloc((streamh->type_size<sizeof(WAVEFORMATEX))?sizeof(WAVEFORMATEX):streamh->type_size,1);

406   memcpy(sh_audio->wf,buffer,streamh->type_size);

407   le2me_WAVEFORMATEX(sh_audio->wf);

408   if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_audio->wf,MSGL_V);

409   if(ASF_LOAD_GUID_PREFIX(streamh->concealment)==ASF_GUID_PREFIX_audio_conceal_interleave){

410     buffer = &hdr[pos];

411     pos += streamh->stream_size;

412     if (pos > hdr_len) return 0;

413     asf->scrambling_h=buffer[0];

414     asf->scrambling_w=(buffer[2]<<8)|buffer[1];

415     asf->scrambling_b=(buffer[4]<<8)|buffer[3];

416     if(asf->scrambling_b>0){

417       asf->scrambling_w/=asf->scrambling_b;

418     }

419   } else {

420     asf->scrambling_b=asf->scrambling_h=asf->scrambling_w=1;

421   }

422   mp_msg(MSGT_HEADER,MSGL_V,"ASF: audio scrambling: %d x %d x %d\n",asf->scrambling_h,asf->scrambling_w,asf->scrambling_b);

423   return 1;

424 }

以上代码初始化asf的音频流,从hdr中把waveformat信息拷贝到sh_audio->wf中,把关于asf的编码信息拷贝到demux->priv中,对于asf的加解扰信息就不讨论了。来看看sh_audio->wf保存了的信息意义:

 9 typedef struct {
	… …
45   WAVEFORMATEX* wf;
	… ...
52 } sh_audio_t;
  6 typedef struct __attribute__((__packed__)) _WAVEFORMATEX {

  7   unsigned short  wFormatTag;

  8   unsigned short  nChannels;

  9   unsigned int    nSamplesPerSec;

 10   unsigned int    nAvgBytesPerSec;

 11   unsigned short  nBlockAlign;

 12   unsigned short  wBitsPerSample;

 13   unsigned short  cbSize;

 14 } WAVEFORMATEX, *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;

从成员变量来看,sh_audio->wf保存的是音频流的物理信息:位码、采样率、通道数等。


继续回到读取头信息函数read_asf_header,接着往下分析:

495     if (!get_ext_stream_properties(hdr, hdr_len, streamh->stream_no, asf, 0))

496         goto len_err_out;

497     }

该函数主要是继续从hdr中获取一些其它关于流属性的信息,保存到asf中,也就是保存到demuxer->priv中。

505   while ((pos = find_asf_guid(hdr, asf_stream_header_guid, pos, hdr_len)) >= 0)

506   {

507     streamh = (ASF_stream_header_t *)&hdr[pos];

508     pos += sizeof(ASF_stream_header_t);

	… …
522     buffer = &hdr[pos];

523     pos += streamh->type_size;

524     if (pos > hdr_len) goto len_err_out;

525     switch(ASF_LOAD_GUID_PREFIX(streamh->type)){

526       case ASF_GUID_PREFIX_audio_stream: {

527         sh_audio_t* sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F);

528         mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_AudioID, "asfheader", streamh->stream_no & 0x7F);

529         ++audio_streams;

530         if (!asf_init_audio_stream(demuxer, asf, sh_audio, streamh, &pos, &buffer, hdr, hdr_len))

531           goto len_err_out;

532     //if(demuxer->audio->id==-1) demuxer->audio->id=streamh.stream_no & 0x7F;

533         break;

534         }

535       case ASF_GUID_PREFIX_video_stream: {

		… …
570       }
573   }

从以上代码片段可以看到,继续查找asf_stream_header_guid如果找到类型是音频流,建立一个sh_audio,如果是视频流,建立一个sh_video。音频流的初始化操作跟之前的一样,视频的,就不在这里分析了。


接下来是从hdr中提取file_header信息,并把信息保存到asfdemuxer->priv)中。

576   pos = find_asf_guid(hdr, asf_file_header_guid, 0, hdr_len);

接下来是从hdr中提取contentheader信息:

594   // find content header

595   pos = find_asf_guid(hdr, asf_content_desc_guid, 0, hdr_len);

596   if (pos >= 0) {

	… ...
607           wstring = (uint16_t*)&hdr[pos];

	… ...
610           if ((string = get_ucs2str(wstring, len))) {

611             mp_msg(MSGT_HEADER,MSGL_V," Title: %s\n", string);

612             demux_info_add(demuxer, "name", string);


614           }

	… ...
623             demux_info_add(demuxer, "author", string);

	… …
634             demux_info_add(demuxer, "copyright", string);

	… ...
645             demux_info_add(demuxer, "comments", string);

	… ...
660   }

接着是提取asf_stream_group_guid相关信息:

663   pos = find_asf_guid(hdr, asf_stream_group_guid, 0, hdr_len);

HDR到此分析完毕,读取第一块数据:

692   start = stream_tell(demuxer->stream); // start of first data chunk

693   stream_read(demuxer->stream, guid_buffer, 16);

694   if (memcmp(guid_buffer, asf_data_chunk_guid, 16) != 0) {

695     mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_NoDataChunkAfterHeader);

696     free(streams);

697     streams = NULL; 

698     return 0;

699   }

判断读取到的数据是否是数据块标志asf_data_chunk_guid

读取第一个数据块长度:

701   stream_read(demuxer->stream, (char *)&data_len, sizeof(data_len))

设置demuxer的音频和视频id标志,id-2表示音频或视频不存在:

738 if(!audio_streams) demuxer->audio->id=-2;  // nosound

739 else if(best_audio > 0 && demuxer->audio->id == -1) demuxer->audio->id=best_audio;

740 if(!video_streams){

741     if(!audio_streams){

742     mp_msg(MSGT_HEADER,MSGL_ERR,MSGTR_MPDEMUX_ASFHDR_AudioVideoHeaderNotFound);

743     return 0;

744     }

745     demuxer->video->id=-2; // audio-only

746 } else if (best_video > 0 && demuxer->video->id == -1) demuxer->video->id = best_video;

回到demux_open_asf函数:

641     if(demuxer->video->id != -2) {

642         if(!ds_fill_buffer(demuxer->video)){

		… ...
654         }

655     }


657     if(demuxer->audio->id!=-2){

658         mp_msg(MSGT_DEMUXER,MSGL_V,MSGTR_ASFSearchingForAudioStream,demuxer->audio->id);

659         if(!ds_fill_buffer(demuxer->audio)){

660             mp_msg(MSGT_DEMUXER,MSGL_INFO,"ASF: " MSGTR_MissingAudioStream);

661             demuxer->audio->sh=NULL;

662         } else {

663             sh_audio=demuxer->audio->sh;sh_audio->ds=demuxer->audio;

664             sh_audio->format=sh_audio->wf->wFormatTag;

665         }

666     }

如果demuxer->audio->id或者demuxer->video->id不等于-2,那么说明流数据包含audio或者video。以audio为例,调用ds_fill_buffer(demuxer->audio)来读取网络流数据并保存到audiodemuxer_stream的缓冲区。

379 int ds_fill_buffer(demux_stream_t *ds){

 380   demuxer_t *demux=ds->demuxer;

 381   if(ds->current) free_demux_packet(ds->current);

 382   if( mp_msg_test(MSGT_DEMUXER,MSGL_DBG3) ){

 383     if(ds==demux->audio) mp_dbg(MSGT_DEMUXER,MSGL_DBG3,"ds_fill_buffer(d_audio) called\n");else

 384     if(ds==demux->video) mp_dbg(MSGT_DEMUXER,MSGL_DBG3,"ds_fill_buffer(d_video) called\n");else

 385     if(ds==demux->sub)   mp_dbg(MSGT_DEMUXER,MSGL_DBG3,"ds_fill_buffer(d_sub) called\n");else

 386                          mp_dbg(MSGT_DEMUXER,MSGL_DBG3,"ds_fill_buffer(unknown 0x%X) called\n",(unsigned int)ds);

 387   }

 388   while(1){

 389     if(ds->packs){

 390       demux_packet_t *p=ds->first;

 391       // copy useful data:

 392       ds->buffer=p->buffer;

 393       ds->buffer_pos=0;

 394       ds->buffer_size=p->len;

 395       ds->pos=p->pos;

 396       ds->dpos+=p->len; // !!!

 397       ++ds->pack_no;

 398       if (p->pts != (correct_pts ? MP_NOPTS_VALUE : 0)) {

 399         ds->pts=p->pts;

 400         ds->pts_bytes=0;

 401       }

 402       ds->pts_bytes+=p->len; // !!!

 403       if(p->stream_pts != MP_NOPTS_VALUE) demux->stream_pts=p->stream_pts;

 404       ds->flags=p->flags;

 405       // unlink packet:

 406       ds->bytes-=p->len;

 407       ds->current=p;

 408       ds->first=p->next;

 409       if(!ds->first) ds->last=NULL;

 410       --ds->packs;

 411       return 1; //ds->buffer_size;

 412     }

 413 

 414     if(demux->audio->packs>=MAX_PACKS || demux->audio->bytes>=MAX_PACK_BYTES){

 415       mp_msg(MSGT_DEMUXER,MSGL_ERR,MSGTR_TooManyAudioInBuffer,demux->audio->packs,demux->audio->bytes);

 416       mp_msg(MSGT_DEMUXER,MSGL_HINT,MSGTR_MaybeNI);

 417       break;

 418     }

 419     if(demux->video->packs>=MAX_PACKS || demux->video->bytes>=MAX_PACK_BYTES){

 420       mp_msg(MSGT_DEMUXER,MSGL_ERR,MSGTR_TooManyVideoInBuffer,demux->video->packs,demux->video->bytes);

 421       mp_msg(MSGT_DEMUXER,MSGL_HINT,MSGTR_MaybeNI);

 422       break;

 423     }

 424     if(!demux_fill_buffer(demux,ds)){

 425        mp_dbg(MSGT_DEMUXER,MSGL_DBG2,"ds_fill_buffer()->demux_fill_buffer() failed\n");

 426        break; // EOF

 427     }

 428   }

 429   ds->buffer_pos=ds->buffer_size=0;

 430   ds->buffer=NULL;

 431   ds->current=NULL;

 432   mp_msg(MSGT_DEMUXER,MSGL_V,"ds_fill_buffer: EOF reached (stream: %s)  \n",ds==demux->audio?"audio":"video");

 433   ds->eof=1;

 434   return 0;

 435 }

ds->packs不为0时,也就是说已接收到的数据包数不为0时,返回成功。如果数据包数为0,那么通过demux_fill_buffer(demux,ds)去读取数据:

370 int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){

 371   // Note: parameter 'ds' can be NULL!

 372 //  printf("demux->type=%d\n",demux->type);

 373   return demux->desc->fill_buffer(demux, ds);

 374 }

调用demuxer描述符的fill_buffer,以asf为例,在目录文件libmpdemux/demux_asf.c中找到描述符的fill_buffer定义:

327 static int demux_asf_fill_buffer(demuxer_t *demux, demux_stream_t *ds){ 

328   struct asf_priv* asf = demux->priv; 

329    

330   demux->filepos=stream_tell(demux->stream);

331   // Brodcast stream have movi_start==movi_end

332   // Better test ?

333   if((demux->movi_start < demux->movi_end) && (demux->filepos>=demux->movi_end)){

334           demux->stream->eof=1;        

335           return 0;

336   }

337    

338     stream_read(demux->stream,asf->packet,asf->packetsize);
	… …
514               switch(rlen){
515               case 0x01:
516                 // GROUPING:
517                 //printf("ASF_parser: warning! grouping (flag=1) not yet supported!\n",len);
518                 //printf("  total: %d  \n",len);
519         while(len>0){
520           int len2=p[0];
521           p++;
522                   //printf("  group part: %d bytes\n",len2);
523                   demux_asf_read_packet(demux,p,len2,streamno,seq,x,duration,-1,keyframe);
524                   p+=len2;
525           len-=len2+1;
526           ++seq;
527         }
528                 if(len!=0){
529                   mp_msg(MSGT_DEMUX,MSGL_V,"ASF_parser: warning! groups total != len\n");
530                 }
531                 break;
532               default:
533                 // NO GROUPING:
534                 //printf("fragment offset: %d  \n",sh->x);
535                 if (!asf->asf_is_dvr_ms || asf->found_first_key_frame)
536                     demux_asf_read_packet(demux,p,len,streamno,seq,time2,duration,x,keyframe);
537                 p+=len;
538                 break;
539           }

通过stream_read把数据读取到asf->packet中,也就是保存到demux->priv->packet中。然后根据协议定义或者文件格式进行数据解析,然后通过demux_asf_read_packet来进一步解析数据并保存起来。

94 static int demux_asf_read_packet(demuxer_t *demux,unsigned char *data,int len,int id,int seq,uint64_t time,unsigned short dur,int     offs,int keyframe){
 95   struct asf_priv* asf = demux->priv;
 96   demux_stream_t *ds=NULL;
 97   int close_seg=0;
	… ...
126   if(ds){
127     if(ds->asf_packet){
128       demux_packet_t* dp=ds->asf_packet;
129 
130       if (ds==demux->video && asf->asf_is_dvr_ms) {
131         if (asf->new_vid_frame_seg) {
132           dp->pos=demux->filepos;
133           close_seg = 1;
134         } else seq = ds->asf_seq;
135       } else close_seg = ds->asf_seq!=seq;
136 
137       if(close_seg){
138         // closed segment, finalize packet:
139         if(ds==demux->audio)
140           if(asf->scrambling_h>1 && asf->scrambling_w>1 && asf->scrambling_b>0)
141             asf_descrambling(&ds->asf_packet->buffer,ds->asf_packet->len,asf);
142         ds_add_packet(ds,ds->asf_packet);
143         ds->asf_packet=NULL;
144       } else {
145         // append data to it!
146         demux_asf_append_to_packet(dp,data,len,offs);
147         // we are ready now.
148         return 1;
149       }
150     }
151     // create new packet:
152     { demux_packet_t* dp;
153       if(offs>0){
154         mp_msg(MSGT_DEMUX,MSGL_V,"warning!  broken fragment, %d bytes missing  \n",offs);
155         return 0;
156       }
157       dp=new_demux_packet(len);
158       fast_memcpy(dp->buffer,data,len);
159       if (asf->asf_is_dvr_ms)
160         dp->pts=time*0.0000001;
161       else
162         dp->pts=time*0.001;
163       dp->flags=keyframe;
164 //      if(ds==demux->video) printf("ASF time: %8d  dur: %5d  \n",time,dur);
165       dp->pos=demux->filepos;
166       ds->asf_packet=dp;
167       ds->asf_seq=seq;
168       // we are ready now.
169       return 1;
170     }
171   }
172 
173   return 0;
174 }

以上的代码片段功能是把数据data拷贝到新建的dp(demux_packet)buffer中,然后对dp缓冲区buffer,即ds->asf_packet->buffer中的数据进行解扰(descrambling)并使该缓冲区指针指向解扰后的数据,通过ds_add_packet更新ds(demux_stream)的状态变量:

334 void ds_add_packet(demux_stream_t *ds,demux_packet_t* dp){
 339     // append packet to DS stream:
 340     ++ds->packs;
 341     ds->bytes+=dp->len;
 342     if(ds->last){
 343       // next packet in stream
 344       ds->last->next=dp;
 345       ds->last=dp;
 346     } else {
 347       // first packet in stream
 348       ds->first=ds->last=dp;
 349     }
 350     mp_dbg(MSGT_DEMUXER,MSGL_DBG2,"DEMUX: Append packet to %s, len=%d  pts=%5.3f  pos=%u  [packs: A=%d V=%d]\n",
 351         (ds==ds->demuxer->audio)?"d_audio":"d_video",
 352         dp->len,dp->pts,(unsigned int)dp->pos,ds->demuxer->audio->packs,ds->demuxer->video->packs);
 353 }

注意到第340行,ds的包数加1,这样回到ds_fill_buffer函数:

388   while(1){
 389     if(ds->packs){     
 390       demux_packet_t *p=ds->first;
 391       // copy useful data:
 392       ds->buffer=p->buffer;
 393       ds->buffer_pos=0;
 394       ds->buffer_size=p->len;      
 395       ds->pos=p->pos;  
 396       ds->dpos+=p->len; // !!!     
 397       ++ds->pack_no;   
 398       if (p->pts != (correct_pts ? MP_NOPTS_VALUE : 0)) {                                                                        
 399         ds->pts=p->pts;
 400         ds->pts_bytes=0;
 401       }
 402       ds->pts_bytes+=p->len; // !!!
 403       if(p->stream_pts != MP_NOPTS_VALUE) demux->stream_pts=p->stream_pts;                                                       
 404       ds->flags=p->flags;
 405       // unlink packet:
 406       ds->bytes-=p->len;
 407       ds->current=p;   
 408       ds->first=p->next;
 409       if(!ds->first) ds->last=NULL;
 410       --ds->packs;
 411       return 1; //ds->buffer_size; 
 412     }

回到调用ds_fill_buffer函数地方demux_open_asf

626 static demuxer_t* demux_open_asf(demuxer_t* demuxer)
627 {
	… …
657     if(demuxer->audio->id!=-2){
658         mp_msg(MSGT_DEMUXER,MSGL_V,MSGTR_ASFSearchingForAudioStream,demuxer->audio->id);
659         if(!ds_fill_buffer(demuxer->audio)){
660             mp_msg(MSGT_DEMUXER,MSGL_INFO,"ASF: " MSGTR_MissingAudioStream);
661             demuxer->audio->sh=NULL;
662         } else {
663             sh_audio=demuxer->audio->sh;sh_audio->ds=demuxer->audio;
664             sh_audio->format=sh_audio->wf->wFormatTag;
665         }
666     }
667     if(!demuxer->stream->seek)
668         demuxer->seekable=0;
669 
670     return demuxer;
671 }

ds_fill_buffer返回成功后demuxer音频相关的部分被正确初始化。











  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值