📄 demux_ogg.c
字号:
}#endif /* HAVE_OGGTHEORA */# ifdef HAVE_FLAC } else if (os->flac) { /* we pass complete packets to flac, mustn't strip the header! */ data = pack->packet;#endif /* HAVE_FLAC */ } else { if(*pack->packet & PACKET_TYPE_HEADER) os->hdr_packets++; else { // Find data start int16_t hdrlen = (*pack->packet & PACKET_LEN_BITS01)>>6; hdrlen |= (*pack->packet & PACKET_LEN_BITS2) <<1; data = pack->packet + 1 + hdrlen; // Calculate the timestamp if(pack->granulepos == -1) pack->granulepos = os->lastpos + (os->lastsize ? os->lastsize : 1); // If we alredy have a timestamp it can be a syncpoint if(*pack->packet & PACKET_IS_SYNCPOINT) *flags = 1; *pts = pack->granulepos/os->samplerate; // Save the packet length and timestamp os->lastsize = 0; while(hdrlen) { os->lastsize <<= 8; os->lastsize |= pack->packet[hdrlen]; hdrlen--; } os->lastpos = pack->granulepos; } } return data;}// check if clang has substring from comma separated langliststatic int demux_ogg_check_lang(char *clang, char *langlist){ char *c; if (!langlist || !*langlist) return 0; while ((c = strchr(langlist, ','))) { if (!strncasecmp(clang, langlist, c - langlist)) return 1; langlist = &c[1]; } if (!strncasecmp(clang, langlist, strlen(langlist))) return 1; return 0;}static int demux_ogg_sub_reverse_id(demuxer_t *demuxer, int id);/// Try to print out comments and also check for LANGUAGE= tagstatic void demux_ogg_check_comments(demuxer_t *d, ogg_stream_t *os, int id, vorbis_comment *vc){ char *hdr, *val; char **cmt = vc->user_comments; int index; ogg_demuxer_t *ogg_d = (ogg_demuxer_t *)d->priv; while(*cmt) { hdr = NULL; if (!strncasecmp(*cmt, "ENCODED_USING=", 14)) { hdr = "Software"; val = *cmt + 14; } else if (!strncasecmp(*cmt, "LANGUAGE=", 9)) { val = *cmt + 9; if (identify) { if (ogg_d->subs[id].text) mp_msg(MSGT_GLOBAL, MSGL_INFO, "ID_SID_%d_LANG=%s\n", ogg_d->subs[id].id, val); else if (id != d->video->id) mp_msg(MSGT_GLOBAL, MSGL_INFO, "ID_AID_%d_LANG=%s\n", ogg_d->subs[id].id, val); } if (ogg_d->subs[id].text) mp_msg(MSGT_DEMUX, MSGL_INFO, "[Ogg] Language for -sid %d is '-slang \"%s\"'\n", ogg_d->subs[id].id, val); // copy this language name into the array index = demux_ogg_sub_reverse_id(d, id); if (index >= 0) { // in case of malicious files with more than one lang per track: if (ogg_d->text_langs[index]) free(ogg_d->text_langs[index]); ogg_d->text_langs[index] = strdup(val); } // check for -slang if subs are uninitialized yet if (os->text && d->sub->id == -1 && demux_ogg_check_lang(val, dvdsub_lang)) { d->sub->id = id; dvdsub_id = index; mp_msg(MSGT_DEMUX, MSGL_V, "Ogg demuxer: Displaying subtitle stream id %d which matched -slang %s\n", id, val); } else hdr = "Language"; } else if (!strncasecmp(*cmt, "ENCODER_URL=", 12)) { hdr = "Encoder URL"; val = *cmt + 12; } else if (!strncasecmp(*cmt, "TITLE=", 6)) { hdr = "Name"; val = *cmt + 6; } if (hdr) mp_msg(MSGT_DEMUX, MSGL_V, " %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 == d->sub->id) // don't want to add subtitles to the demuxer for now demux_ogg_add_sub(os,pack); return 0; } // 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(d->video->id < 0) ((sh_audio_t*)ds->sh)->delay = pts; /// Clear subtitles if necessary (for broken files) if ((clear_sub > 0) && (pts >= clear_sub)) { ogg_sub.lines = 0; vo_sub = &ogg_sub; vo_osd_changed(OSDTYPE_SUBTITLE); clear_sub = -1; } /// 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,max(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 { 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; } } 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))) { ogg_d->syncpoints = (ogg_syncpoint_t*)realloc(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): %lld\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);extern void print_video_header(BITMAPINFOHEADER *h);/** \brief Return the number of subtitle tracks in the file. \param demuxer The demuxer for which the number of subtitle tracks should be returned.*/int demux_ogg_num_subs(demuxer_t *demuxer) { ogg_demuxer_t *ogg_d = (ogg_demuxer_t *)demuxer->priv; return ogg_d->n_text;}/** \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];}void demux_close_ogg(demuxer_t* demuxer);/// Open an ogg physical streamint 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 clear_sub = -1; s = demuxer->stream; ogg_d = (ogg_demuxer_t*)calloc(1,sizeof(ogg_demuxer_t)); sync = &ogg_d->sync; page = &ogg_d->page;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -