demux_ogg.c

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

C
1,617
字号
	for (i = 0; table[i].ogg; i++)	{	    if (!strncasecmp(*cmt, table[i].ogg, strlen(table[i].ogg)) &&	        (*cmt)[strlen(table[i].ogg)] == '=')	    {		hdr = table[i].mp;		val = *cmt + strlen(table[i].ogg) + 1;	    }	}    }    if (hdr)      demux_info_add(d, hdr, val);      mp_dbg(MSGT_DEMUX, MSGL_DBG2, " %s: %s\n", hdr, val);    cmt++;  }}/// Calculate the timestamp and add the packet to the demux stream// return 1 if the packet was added, 0 otherwisestatic int demux_ogg_add_packet(demux_stream_t* ds,ogg_stream_t* os,int id,ogg_packet* pack) {  demuxer_t* d = ds->demuxer;  demux_packet_t* dp;  unsigned char* data;  float pts = 0;  int flags = 0;  void *context = NULL;  int samplesize = 1;  // If packet is an comment header then we try to get comments at first  if (pack->bytes >= 7 && !memcmp(pack->packet, "\003vorbis", 7))  {    vorbis_info vi;    vorbis_comment vc;    vorbis_info_init(&vi);    vorbis_comment_init(&vc);    vi.rate = 1L; // it's checked by vorbis_synthesis_headerin()    if(vorbis_synthesis_headerin(&vi, &vc, pack) == 0) // if no errors      demux_ogg_check_comments(d, os, id, &vc);    vorbis_comment_clear(&vc);    vorbis_info_clear(&vi);  }  if (os->text) {    if (id == demux_ogg_sub_id(d, d->sub->id)) // don't want to add subtitles to the demuxer for now      demux_ogg_add_sub(os,pack);    return 0;  }  if (os->speex) {    // discard first two packets, they contain the header and comment    if (os->hdr_packets < 2) {      os->hdr_packets++;      return 0;    }  } else  // If packet is an header we jump it except for vorbis and theora  // (PACKET_TYPE_HEADER bit doesn't even exist for theora ?!)  // We jump nothing for FLAC. Ain't this great? Packet contents have to be  // handled differently for each and every stream type. The joy! The joy!  if(!os->flac && ((*pack->packet & PACKET_TYPE_HEADER) &&      (ds != d->audio || ( ((sh_audio_t*)ds->sh)->format != FOURCC_VORBIS || os->hdr_packets >= NUM_VORBIS_HDR_PACKETS ) ) &&     (ds != d->video || (((sh_video_t*)ds->sh)->format != FOURCC_THEORA))))    return 0;  // For vorbis packet the packet is the data, for other codec we must jump  // the header  if(ds == d->audio && ((sh_audio_t*)ds->sh)->format == FOURCC_VORBIS) {     context = ((sh_audio_t *)ds->sh)->context;     samplesize = ((sh_audio_t *)ds->sh)->samplesize;  }  if (ds == d->video && ((sh_audio_t*)ds->sh)->format == FOURCC_THEORA)     context = ((sh_video_t *)ds->sh)->context;  data = demux_ogg_read_packet(os,pack,context,&pts,&flags,samplesize);  if (!data)    return 0;  /// Clear subtitles if necessary (for broken files)  if (sub_clear_text(&ogg_sub, pts)) {    vo_sub = &ogg_sub;    vo_osd_changed(OSDTYPE_SUBTITLE);  }  /// Send the packet  dp = new_demux_packet(pack->bytes-(data-pack->packet));  memcpy(dp->buffer,data,pack->bytes-(data-pack->packet));  dp->pts = pts;  dp->flags = flags;  ds_add_packet(ds,dp);  mp_msg(MSGT_DEMUX,MSGL_DBG2,"New dp: %p  ds=%p  pts=%5.3f  len=%d  flag=%d  \n",      dp, ds, pts, dp->len, flags);  return 1;}/// if -forceidx build a table of all syncpoints to make seeking easier/// otherwise try to get at least the final_granuleposvoid demux_ogg_scan_stream(demuxer_t* demuxer) {  ogg_demuxer_t* ogg_d = demuxer->priv;  stream_t *s = demuxer->stream;  ogg_sync_state* sync = &ogg_d->sync;  ogg_page* page= &ogg_d->page;  ogg_stream_state* oss;  ogg_stream_t* os;  ogg_packet op;  int np,sid,p,samplesize=1;  void *context = NULL;  off_t pos, last_pos;  pos = last_pos = demuxer->movi_start;  // Reset the stream  if(index_mode == 2) {  stream_seek(s,demuxer->movi_start);  } else {    //the 270000 are just a wild guess    stream_seek(s,FFMAX(ogg_d->pos,demuxer->movi_end-270000));  }  ogg_sync_reset(sync);  // Get the serial number of the stream we use  if(demuxer->video->id >= 0) {    sid = demuxer->video->id;    /* demux_ogg_read_packet needs decoder context for Theora streams */    if (((sh_video_t*)demuxer->video->sh)->format == FOURCC_THEORA)      context = ((sh_video_t*)demuxer->video->sh)->context;  }  else if(demuxer->audio->id >= 0) {    sid = demuxer->audio->id;    /* demux_ogg_read_packet needs decoder context for Vorbis streams */    if(((sh_audio_t*)demuxer->audio->sh)->format == FOURCC_VORBIS) {      context = ((sh_audio_t*)demuxer->audio->sh)->context;      samplesize = ((sh_audio_t*)demuxer->audio->sh)->samplesize;    }  }  else return;  os = &ogg_d->subs[sid];  oss = &os->stream;  while(1) {    np = ogg_sync_pageseek(sync,page);    if(np < 0) { // We had to skip some bytes      if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_ERR,"Bad page sync while building syncpoints table (%d)\n",-np);      pos += -np;      continue;    }    if(np <= 0) { // We need more data      char* buf = ogg_sync_buffer(sync,BLOCK_SIZE);      int len = stream_read(s,buf,BLOCK_SIZE);      if(len == 0 && s->eof)	break;      ogg_sync_wrote(sync,len);      continue;    }    // The page is ready    //ogg_sync_pageout(sync,page);    if(ogg_page_serialno(page) != os->stream.serialno) { // It isn't a page from the stream we want      pos += np;      continue;    }    if(ogg_stream_pagein(oss,page) != 0) {      mp_msg(MSGT_DEMUX,MSGL_ERR,"Pagein error ????\n");      pos += np;      continue;    }    p = 0;    while(ogg_stream_packetout(oss,&op) == 1) {      float pts;      int flags;      demux_ogg_read_packet(os,&op,context,&pts,&flags,samplesize);      if(op.granulepos >= 0) ogg_d->final_granulepos = op.granulepos;      if(index_mode == 2 && (flags || (os->vorbis && op.granulepos >= 0))) {	if (ogg_d->num_syncpoint > SIZE_MAX / sizeof(ogg_syncpoint_t) - 1) break;	ogg_d->syncpoints = realloc_struct(ogg_d->syncpoints,(ogg_d->num_syncpoint+1), sizeof(ogg_syncpoint_t));	ogg_d->syncpoints[ogg_d->num_syncpoint].granulepos = op.granulepos;	ogg_d->syncpoints[ogg_d->num_syncpoint].page_pos = (ogg_page_continued(page) && p == 0) ? last_pos : pos;	ogg_d->num_syncpoint++;      }      p++;    }    if(p > 1 || (p == 1 && ! ogg_page_continued(page)))      last_pos = pos;    pos += np;    if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_INFO,"Building syncpoint table %d%%\r",(int)(pos*100/s->end_pos));  }  if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_INFO,"\n");  if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_V,"Ogg syncpoints table builed: %d syncpoints\n",ogg_d->num_syncpoint);  mp_msg(MSGT_DEMUX,MSGL_V,"Ogg stream length (granulepos): %"PRId64"\n",ogg_d->final_granulepos);  stream_reset(s);  stream_seek(s,demuxer->movi_start);  ogg_sync_reset(sync);  for(np = 0 ; np < ogg_d->num_sub ; np++) {    ogg_stream_reset(&ogg_d->subs[np].stream);    ogg_d->subs[np].lastpos = ogg_d->subs[np].lastsize = ogg_d->subs[np].hdr_packets = 0;  }    // Get the first page  while(1) {    np = ogg_sync_pageout(sync,page);    if(np <= 0) { // We need more data      char* buf = ogg_sync_buffer(sync,BLOCK_SIZE);      int len = stream_read(s,buf,BLOCK_SIZE);      if(len == 0 && s->eof) {	mp_msg(MSGT_DEMUX,MSGL_ERR,"EOF while trying to get the first page !!!!\n");	break;      }            ogg_sync_wrote(sync,len);      continue;    }    demux_ogg_get_page_stream(ogg_d,&oss);    ogg_stream_pagein(oss,page);    break;  }  }extern void print_wave_header(WAVEFORMATEX *h, int verbose_level);extern void print_video_header(BITMAPINFOHEADER *h, int verbose_level);/* defined in demux_mov.c */extern unsigned int store_ughvlc(unsigned char *s, unsigned int v);/** \brief Change the current subtitle stream and return its ID.  \param demuxer The demuxer whose subtitle stream will be changed.  \param new_num The number of the new subtitle track. The number must be  between 0 and ogg_d->n_text - 1.  \returns The Ogg stream number ( = page serial number) of the newly selected  track.*/int demux_ogg_sub_id(demuxer_t *demuxer, int index) {  ogg_demuxer_t *ogg_d = (ogg_demuxer_t *)demuxer->priv;  return (index < 0) ? index : (index >= ogg_d->n_text) ? -1 : ogg_d->text_ids[index];}/** \brief Translate the ogg track number into the subtitle number. *  \param demuxer The demuxer about whose subtitles we are inquiring. *  \param id The ogg track number of the subtitle track. */static int demux_ogg_sub_reverse_id(demuxer_t *demuxer, int id) {  ogg_demuxer_t *ogg_d = (ogg_demuxer_t *)demuxer->priv;  int i;  for (i = 0; i < ogg_d->n_text; i++)    if (ogg_d->text_ids[i] == id) return i;  return -1;}/** \brief Lookup the subtitle language by the subtitle number.  Returns NULL on out-of-bounds input. *  \param demuxer The demuxer about whose subtitles we are inquiring. *  \param index The subtitle number. */char *demux_ogg_sub_lang(demuxer_t *demuxer, int index) {  ogg_demuxer_t *ogg_d = (ogg_demuxer_t *)demuxer->priv;  return (index < 0) ? NULL : (index >= ogg_d->n_text) ? NULL : ogg_d->text_langs[index];}static void demux_close_ogg(demuxer_t* demuxer);static void fixup_vorbis_wf(sh_audio_t *sh, ogg_demuxer_t *od){  int i, offset;  int ris, init_error = 0;  ogg_packet op[3];  unsigned char *buf[3];  unsigned char *ptr;  unsigned int len;  ogg_stream_t *os = &od->subs[sh->ds->id];  vorbis_comment vc;  vorbis_info_init(&os->vi);  vorbis_comment_init(&vc);  for(i = 0; i < 3; i++) {    op[i].bytes = ds_get_packet(sh->ds, &(op[i].packet));    mp_msg(MSGT_DEMUX,MSGL_V, "fixup_vorbis_wf: i=%d, size=%ld\n", i, op[i].bytes);    if(op[i].bytes < 0) {       mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg demuxer error!, fixup_vorbis_wf: bad packet n. %d\n", i);       return;    }    buf[i] = malloc(op[i].bytes);    if(!buf[i])      return;    memcpy(buf[i], op[i].packet, op[i].bytes);    op[i].b_o_s = (i==0);    ris = vorbis_synthesis_headerin(&(os->vi),&vc,&(op[i]));    if(ris < 0) {      init_error = 1;      mp_msg(MSGT_DECAUDIO,MSGL_ERR,"DEMUX_OGG: header n. %d broken! len=%ld, code: %d\n", i, op[i].bytes, ris);    }  }  vorbis_comment_clear(&vc);  if(!init_error)    os->vi_inited = 1;  len = op[0].bytes + op[1].bytes + op[2].bytes;  sh->wf = calloc(1, sizeof(WAVEFORMATEX) + len + len/255 + 64);  ptr = (unsigned char*) (sh->wf+1);  ptr[0] = 2;  offset = 1;  offset += store_ughvlc(&ptr[offset], op[0].bytes);  mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, offset after 1st len = %u\n", offset);  offset += store_ughvlc(&ptr[offset], op[1].bytes);  mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, offset after 2nd len = %u\n", offset);  for(i = 0; i < 3; i++) {    mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, i=%d, bytes: %ld, offset: %u\n", i, op[i].bytes, offset);    memcpy(&ptr[offset], buf[i], op[i].bytes);    offset += op[i].bytes;  }  sh->wf->cbSize = offset;  mp_msg(MSGT_DEMUX,MSGL_V, "demux_ogg, extradata size: %d\n", sh->wf->cbSize);  sh->wf = (WAVEFORMATEX*)realloc(sh->wf, sizeof(WAVEFORMATEX) + sh->wf->cbSize);  if(op[0].bytes >= 29) {    unsigned int br;    int nombr, minbr, maxbr;    ptr = buf[0];    sh->channels = ptr[11];    sh->samplerate = sh->wf->nSamplesPerSec = get_uint32(&ptr[12]);    maxbr = get_uint32(&ptr[16]);  //max    nombr = get_uint32(&ptr[20]);  //nominal    minbr = get_uint32(&ptr[24]);  //minimum    if(maxbr == -1)        maxbr = 0;    if(nombr == -1)        nombr = 0;    if(minbr == -1)        minbr = 0;        br = maxbr / 8;    if(!br)      br = nombr / 8;    if(!br)      br = minbr / 8;    sh->wf->nAvgBytesPerSec = br;    sh->wf->wBitsPerSample = 16;    sh->samplesize = (sh->wf->wBitsPerSample+7)/8;    mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, vorbis stream features are: channels: %d, srate: %d, bitrate: %d, max: %u, nominal: %u, min: %u\n",       sh->channels, sh->samplerate, sh->wf->nAvgBytesPerSec, maxbr, nombr, minbr);  }  free(buf[2]);  free(buf[1]);  free(buf[0]);}/// Open an ogg physical stream// Not static because it's used also in demuxer_avi.cint demux_ogg_open(demuxer_t* demuxer) {  ogg_demuxer_t* ogg_d;  stream_t *s;  char* buf;  int np,s_no, n_audio = 0, n_video = 0;  int audio_id = -1, video_id = -1, text_id = -1;  ogg_sync_state* sync;  ogg_page* page;  ogg_packet pack;  sh_audio_t* sh_a;  sh_video_t* sh_v;#ifdef USE_ICONV  subcp_open(NULL);#endif  s = demuxer->stream;  demuxer->priv =  ogg_d = calloc(1,sizeof(ogg_demuxer_t));  sync = &ogg_d->sync;  page = &ogg_d->page;  ogg_sync_init(sync);  while(1) {    /// Try to get a page    ogg_d->pos += ogg_d->last_size;    np = ogg_sync_pageseek(sync,page);    /// Error    if(np < 0) {      mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg demuxer : Bad page sync\n");      goto err_out;    }    /// Need some more data    if(np == 0) {      int len;      buf = ogg_sync_buffer(sync,BLOCK_SIZE);      len = stream_read(s,buf,BLOCK_SIZE);            if(len == 0 && s->eof) {	goto err_out;      }      ogg_sync_wrote(sync,len);      continue;    }    ogg_d->last_size = np;    // We got one page now    if( ! ogg_page_bos(page) ) { // It's not a begining page      // Header parsing end here, we need to get the page otherwise it will be lost      int id = demux_ogg_get_page_stream(ogg_d,NULL);      if(id >= 0)	ogg_stream_pagein(&ogg_d->subs[id].stream,page);      else	mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg : Warning found none bos page from unknown stream %d\n",ogg_page_serialno(page));

⌨️ 快捷键说明

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