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

来源:互联网 发布:mysql怎么优化 编辑:程序博客网 时间:2024/04/28 21:55

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

不同协议的流有不同的分离器,所以首先来看如果打开正确的分离器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 autodetect696   asf_check_header,697   demux_asf_fill_buffer,698   demux_open_asf,699   demux_close_asf,700   demux_seek_asf,701   demux_asf_control702 };

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

接下来是第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 and484       // 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; // EOF210       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_NETWORK259     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 #else265     len=read(s->fd,s->buffer,STREAM_BUFFER_SIZE);break;266 #endif267   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);   //Leo436       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);//Leo442       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 WMS9488     // 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 header595   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 chunk693   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;  // nosound739 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-only746 } 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_end332   // 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       else162         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音频相关的部分被正确初始化。











原创粉丝点击