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_desc和stream对象保存到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 }
以上的代码片段就开始获取一些网络流信息了,首先读取流信息头,第656行read_asf_header(demuxer,asf),并根据信息头查看该流数据中包含哪些各类的流,或者多个各类组合,然后为每个各类的流建立一个streamheader结构体,例如音频流streamheader的sh_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_pid为0,也就是说没有创建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_audio的ID,也就是说可以根据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信息,并把信息保存到asf(demuxer->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)来读取网络流数据并保存到audio的demuxer_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音频相关的部分被正确初始化。
- Mplayer学习笔记2--打开分离器demuxer
- Mplayer学习笔记1--打开流媒体
- 最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)
- 最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)
- 最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)
- 最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)
- 最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)
- 最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)
- 最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)
- 最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)
- Cygwin编译Mplayer笔记
- MPlayer 源码阅读笔记
- ubuntu安装mplayer笔记
- Mplayer源码学习
- libavformat/libavcodec学习(mplayer)
- Firefox关联mplayer打开mms的方法
- selenium(webdriver)学习笔记2--打开指定路径的firefox
- MPlayer移植到EPC9600笔记
- 新的CCSDS图像压缩推荐标准
- 什么是能力的思考??
- xmlhttp的缓存清除的俩种方案
- 整理的eclipse indigo汉化和JAVADOC汉化方法
- PowerDesigner正逆向工程
- Mplayer学习笔记2--打开分离器demuxer
- cvEigenVV 特征值 对应的特征向量
- C++ Hash表设计V2.0
- Linux_用U盘安装Linux系统的简单方法
- STL-模板
- 8052单片机中定时器T2的应用
- gsensor架构和原理分析
- 轻身健脾与护肝
- spi FLASH 问答