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 + -
显示快捷键?