📄 demux_ogg.c
字号:
ogg_d->pos -= pa; continue; } /// We need more data buf = ogg_sync_buffer(sync,BLOCK_SIZE); len = stream_read(s,buf,BLOCK_SIZE); if(len == 0 && s->eof) { mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg : Stream EOF !!!!\n"); return 0; } ogg_sync_wrote(sync,len); } /// Page loop ogg_d->last_size = pa; /// Find the page's logical stream if( (id = demux_ogg_get_page_stream(ogg_d,&os)) < 0) { mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg demuxer error : we met an unknown stream\n"); return 0; } /// Take the page if(ogg_stream_pagein(os,page) == 0) break; /// Page was invalid => retry mp_msg(MSGT_DEMUX,MSGL_WARN,"Ogg demuxer : got invalid page !!!!!\n"); ogg_d->pos += ogg_d->last_size; } } else /// Packet was corrupted mp_msg(MSGT_DEMUX,MSGL_WARN,"Ogg : bad packet in stream %d\n",id); } /// Packet loop /// Is the actual logical stream in use ? if(id == d->audio->id) ds = d->audio; else if(id == d->video->id) ds = d->video; else if (ogg_d->subs[id].text) ds = d->sub; if(ds) { if(!demux_ogg_add_packet(ds,&ogg_d->subs[id],id,&pack)) continue; /// Unuseful packet, get another d->filepos = ogg_d->pos; return 1; } } /// while(1)}/// For avi with Ogg audio stream we have to create an ogg demuxer for this// stream, then we join the avi and ogg demuxer with a demuxers demuxerdemuxer_t* init_avi_with_ogg(demuxer_t* demuxer) { demuxer_t *od; ogg_demuxer_t *ogg_d; stream_t* s; uint32_t hdrsizes[3]; demux_packet_t *dp; sh_audio_t *sh_audio = demuxer->audio->sh; int np; unsigned char *p = NULL,*buf; int plen; /// Check that the cbSize is enouth big for the following reads if(sh_audio->wf->cbSize < 22+3*sizeof(uint32_t)) { mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI Ogg : Initial audio header is too small !!!!!\n"); goto fallback; } /// Get the size of the 3 header packet memcpy(hdrsizes, ((unsigned char*)sh_audio->wf)+22+sizeof(WAVEFORMATEX), 3*sizeof(uint32_t));// printf("\n!!!!!! hdr sizes: %d %d %d \n",hdrsizes[0],hdrsizes[1],hdrsizes[2]); /// Check the size if(sh_audio->wf->cbSize < 22+3*sizeof(uint32_t)+hdrsizes[0]+hdrsizes[1] + hdrsizes[2]) { mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI Ogg : Audio header is too small !!!!!\n"); goto fallback; } // Build the ogg demuxer private datas ogg_d = (ogg_demuxer_t*)calloc(1,sizeof(ogg_demuxer_t)); ogg_d->num_sub = 1; ogg_d->subs = (ogg_stream_t*)malloc(sizeof(ogg_stream_t)); ogg_d->subs[0].vorbis = 1; // Init the ogg physical stream ogg_sync_init(&ogg_d->sync); // Get the first page of the stream : we assume there only 1 logical stream while((np = ogg_sync_pageout(&ogg_d->sync,&ogg_d->page)) <= 0 ) { if(np < 0) { mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI Ogg error : Can't init using first stream packets\n"); free(ogg_d); goto fallback; } // Add some data plen = ds_get_packet(demuxer->audio,&p); buf = ogg_sync_buffer(&ogg_d->sync,plen); memcpy(buf,p,plen); ogg_sync_wrote(&ogg_d->sync,plen); } // Init the logical stream mp_msg(MSGT_DEMUX,MSGL_DBG2,"AVI Ogg found page with serial %d\n",ogg_page_serialno(&ogg_d->page)); ogg_stream_init(&ogg_d->subs[0].stream,ogg_page_serialno(&ogg_d->page)); // Write the page ogg_stream_pagein(&ogg_d->subs[0].stream,&ogg_d->page); // Create the ds_stream and the ogg demuxer s = new_ds_stream(demuxer->audio); od = new_demuxer(s,DEMUXER_TYPE_OGG,0,-2,-2); /// Add the header packets in the ogg demuxer audio stream // Initial header dp = new_demux_packet(hdrsizes[0]); memcpy(dp->buffer,((unsigned char*)sh_audio->wf)+22+sizeof(WAVEFORMATEX)+3*sizeof(uint32_t),hdrsizes[0]); ds_add_packet(od->audio,dp); /// Comments dp = new_demux_packet(hdrsizes[1]); memcpy(dp->buffer,((unsigned char*)sh_audio->wf)+22+sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0],hdrsizes[1]); ds_add_packet(od->audio,dp); /// Code book dp = new_demux_packet(hdrsizes[2]); memcpy(dp->buffer,((unsigned char*)sh_audio->wf)+22+sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0]+hdrsizes[1],hdrsizes[2]); ds_add_packet(od->audio,dp); // Finish setting up the ogg demuxer od->priv = ogg_d; sh_audio = new_sh_audio(od,0); od->audio->id = 0; od->video->id = -2; od->audio->sh = sh_audio; sh_audio->ds = od->audio; sh_audio->format = FOURCC_VORBIS; /// Return the joined demuxers return new_demuxers_demuxer(demuxer,od,demuxer); fallback: demuxer->audio->id = -2; return demuxer;}extern void resync_audio_stream(sh_audio_t *sh_audio);void demux_ogg_seek(demuxer_t *demuxer,float rel_seek_secs,int flags) { ogg_demuxer_t* ogg_d = demuxer->priv; ogg_sync_state* sync = &ogg_d->sync; ogg_page* page= &ogg_d->page; ogg_stream_state* oss; ogg_stream_t* os; demux_stream_t* ds; sh_audio_t* sh_audio = demuxer->audio->sh; ogg_packet op; float rate; int i,sp,first,precision=1,do_seek=1; vorbis_info* vi = NULL; int64_t gp = 0, old_gp; void *context = NULL; off_t pos, old_pos; int np; int is_gp_valid; float pts; int is_keyframe; int samplesize=1; if(demuxer->video->id >= 0) { ds = demuxer->video; /* 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; rate = ogg_d->subs[ds->id].samplerate; } else { ds = demuxer->audio; /* 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; vi = &((ov_struct_t*)((sh_audio_t*)ds->sh)->context)->vi; rate = (float)vi->rate; samplesize = ((sh_audio_t*)ds->sh)->samplesize; } os = &ogg_d->subs[ds->id]; oss = &os->stream; old_gp = os->lastpos; old_pos = ogg_d->pos; //calculate the granulepos to seek to gp = flags & 1 ? 0 : os->lastpos; if(flags & 2) { if (ogg_d->final_granulepos > 0) gp += ogg_d->final_granulepos * rel_seek_secs; else gp += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) * os->lastpos / ogg_d->pos; } else gp += rel_seek_secs * rate; if (gp < 0) gp = 0; //calculate the filepos to seek to if(ogg_d->syncpoints) { for(sp = 0; sp < ogg_d->num_syncpoint ; sp++) { if(ogg_d->syncpoints[sp].granulepos >= gp) break; } if(sp >= ogg_d->num_syncpoint) return; if (sp > 0 && ogg_d->syncpoints[sp].granulepos - gp > gp - ogg_d->syncpoints[sp-1].granulepos) sp--; if (ogg_d->syncpoints[sp].granulepos == os->lastpos) { if (sp > 0 && gp < os->lastpos) sp--; if (sp < ogg_d->num_syncpoint-1 && gp > os->lastpos) sp++; } pos = ogg_d->syncpoints[sp].page_pos; precision = 0; } else { pos = flags & 1 ? 0 : ogg_d->pos; if(flags & 2) pos += (demuxer->movi_end - demuxer->movi_start) * rel_seek_secs; else { if (ogg_d->final_granulepos > 0) { pos += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) / (ogg_d->final_granulepos / rate); } else if (os->lastpos > 0) { pos += rel_seek_secs * ogg_d->pos / (os->lastpos / rate); } } if (pos < 0) pos = 0; if (pos > (demuxer->movi_end - demuxer->movi_start)) return; } // if(ogg_d->syncpoints) while(1) { if (do_seek) { stream_seek(demuxer->stream,pos+demuxer->movi_start); ogg_sync_reset(sync); for(i = 0 ; i < ogg_d->num_sub ; i++) { ogg_stream_reset(&ogg_d->subs[i].stream); ogg_d->subs[i].lastpos = ogg_d->subs[i].lastsize = 0; } ogg_d->pos = pos; ogg_d->last_size = 0; /* we just guess that we reached correct granulepos, in case a subsequent search occurs before we read a valid granulepos */ os->lastpos = gp; first = !(ogg_d->syncpoints); do_seek=0; } ogg_d->pos += ogg_d->last_size; ogg_d->last_size = 0; np = ogg_sync_pageseek(sync,page); if(np < 0) ogg_d->pos -= np; if(np <= 0) { // We need more data char* buf = ogg_sync_buffer(sync,BLOCK_SIZE); int len = stream_read(demuxer->stream,buf,BLOCK_SIZE); if(len == 0 && demuxer->stream->eof) { mp_msg(MSGT_DEMUX,MSGL_ERR,"EOF while trying to seek !!!!\n"); break; } ogg_sync_wrote(sync,len); continue; } ogg_d->last_size = np; if(ogg_page_serialno(page) != oss->serialno) continue; if(ogg_stream_pagein(oss,page) != 0) continue; while(1) { np = ogg_stream_packetout(oss,&op); if(np < 0) continue; else if(np == 0) break; if (first) { /* Discard the first packet as it's probably broken, and we don't have any other means to decide whether it is complete or not. */ first = 0; break; } is_gp_valid = (op.granulepos >= 0); demux_ogg_read_packet(os,&op,context,&pts,&is_keyframe,samplesize); if (precision && is_gp_valid) { precision--; if (abs(gp - op.granulepos) > rate && (op.granulepos != old_gp)) { //prepare another seek because we are off by more than 1s pos += (gp - op.granulepos) * (pos - old_pos) / (op.granulepos - old_gp); if (pos < 0) pos = 0; if (pos < (demuxer->movi_end - demuxer->movi_start)) { do_seek=1; break; } } } if (is_gp_valid && (pos > 0) && (old_gp > gp) && (2 * (old_gp - op.granulepos) < old_gp - gp)) { /* prepare another seek because looking for a syncpoint destroyed the backward search */ pos = old_pos - 1.5 * (old_pos - pos); if (pos < 0) pos = 0; if (pos < (demuxer->movi_end - demuxer->movi_start)) { do_seek=1; break; } } if(!precision && (is_keyframe || os->vorbis) ) { ogg_sub.lines = 0; vo_sub = &ogg_sub; vo_osd_changed(OSDTYPE_SUBTITLE); clear_sub = -1; demux_ogg_add_packet(ds,os,ds->id,&op); if(sh_audio) resync_audio_stream(sh_audio); return; } } } mp_msg(MSGT_DEMUX,MSGL_ERR,"Can't find the good packet :(\n"); }void demux_close_ogg(demuxer_t* demuxer) { ogg_demuxer_t* ogg_d = demuxer->priv; int i; if(!ogg_d) return;#ifdef USE_ICONV subcp_close();#endif ogg_sync_clear(&ogg_d->sync); if(ogg_d->subs) { for (i = 0; i < ogg_d->num_sub; i++) ogg_stream_clear(&ogg_d->subs[i].stream); free(ogg_d->subs); } if(ogg_d->syncpoints) free(ogg_d->syncpoints); if (ogg_d->text_ids) free(ogg_d->text_ids); if (ogg_d->text_langs) { for (i = 0; i < ogg_d->n_text; i++) if (ogg_d->text_langs[i]) free(ogg_d->text_langs[i]); free(ogg_d->text_langs); } free(ogg_d);}int demux_ogg_control(demuxer_t *demuxer,int cmd, void *arg){ ogg_demuxer_t* ogg_d = demuxer->priv; ogg_stream_t* os; float rate; if(demuxer->video->id >= 0) { os = &ogg_d->subs[demuxer->video->id]; rate = os->samplerate; } else { os = &ogg_d->subs[demuxer->audio->id]; rate = (float)((ov_struct_t*)((sh_audio_t*)demuxer->audio->sh)->context)->vi.rate; } switch(cmd) { case DEMUXER_CTRL_GET_TIME_LENGTH: if (ogg_d->final_granulepos<=0) return DEMUXER_CTRL_DONTKNOW; *((unsigned long *)arg)=ogg_d->final_granulepos / rate; return DEMUXER_CTRL_GUESS; case DEMUXER_CTRL_GET_PERCENT_POS: if (ogg_d->final_granulepos<=0) return DEMUXER_CTRL_DONTKNOW; *((int *)arg)=(int)( (os->lastpos*100) / ogg_d->final_granulepos); return DEMUXER_CTRL_OK; default: return DEMUXER_CTRL_NOTIMPL; }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -