static int demux_demuxers_fill_buffer(demuxer_t *demux,demux_stream_t *ds) { dd_priv_t* priv; priv=demux->priv; if(ds->demuxer == priv->vd) return demux_fill_buffer(priv->vd,ds); else if(ds->demuxer == priv->ad) return demux_fill_buffer(priv->ad,ds); else if(ds->demuxer == priv->sd) return demux_fill_buffer(priv->sd,ds); mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_MPDEMUX_DEMUXERS_FillBufferError); return 0; }
static void demux_demuxers_seek(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags) { dd_priv_t* priv; float pos; priv=demuxer->priv; priv->ad->stream->eof = 0; priv->sd->stream->eof = 0; // Seek video demux_seek(priv->vd,rel_seek_secs,audio_delay,flags); // Get the new pos pos = demuxer->video->pts; if (!pos) { demux_fill_buffer(priv->vd, demuxer->video); if (demuxer->video->first) pos = demuxer->video->first->pts; } if(priv->ad != priv->vd && demuxer->audio->sh) { sh_audio_t* sh = demuxer->audio->sh; demux_seek(priv->ad,pos,audio_delay,1); // In case the demuxer don't set pts if(!demuxer->audio->pts) demuxer->audio->pts = pos-((ds_tell_pts(demuxer->audio)-sh->a_in_buffer_len)/(float)sh->i_bps); } if(priv->sd != priv->vd) demux_seek(priv->sd,pos,audio_delay,1); }
double ds_get_next_pts(demux_stream_t *ds) { demuxer_t *demux = ds->demuxer; // if we have not read from the "current" packet, consider it // as the next, otherwise we never get the pts for the first packet. while (!ds->first && (!ds->current || ds->buffer_pos)) { if (demux->audio->packs >= MAX_PACKS || demux->audio->bytes >= MAX_PACK_BYTES) { mp_tmsg(MSGT_DEMUXER, MSGL_ERR, "\nToo many audio packets in the buffer: (%d in %d bytes).\n", demux->audio->packs, demux->audio->bytes); mp_tmsg(MSGT_DEMUXER, MSGL_HINT, MaybeNI); return MP_NOPTS_VALUE; } if (demux->video->packs >= MAX_PACKS || demux->video->bytes >= MAX_PACK_BYTES) { mp_tmsg(MSGT_DEMUXER, MSGL_ERR, "\nToo many video packets in the buffer: (%d in %d bytes).\n", demux->video->packs, demux->video->bytes); mp_tmsg(MSGT_DEMUXER, MSGL_HINT, MaybeNI); return MP_NOPTS_VALUE; } if (!demux_fill_buffer(demux, ds)) return MP_NOPTS_VALUE; } // take pts from "current" if we never read from it. if (ds->current && !ds->buffer_pos) return ds->current->pts; return ds->first->pts; }
/// Open an mpg physical stream static demuxer_t* demux_mpg_open(demuxer_t* demuxer) { stream_t *s = demuxer->stream; mpg_demuxer_t* mpg_d = calloc(1,sizeof(*mpg_d)); if (!mpg_d) return NULL; demuxer->priv = mpg_d; while (demuxer->video->packs + demuxer->audio->packs < 2) if (!demux_fill_buffer(demuxer, demuxer->video)) return 0; mpg_d->last_pts = -1.0; mpg_d->first_pts = -1.0; //if seeking is allowed set has_valid_timestamps if appropriate if(demuxer->seekable && (demuxer->stream->type == STREAMTYPE_FILE || demuxer->stream->type == STREAMTYPE_VCD) && demuxer->movi_start != demuxer-> movi_end ) { //We seek to the beginning of the stream, to somewhere in the //middle, and to the end of the stream, while remembering the pts //at each of the three positions. With these pts, we check whether //or not the pts are "linear enough" to justify seeking by the pts //of the stream //The position where the stream is now off_t pos = stream_tell(s); float first_pts = read_first_mpeg_pts_at_position(demuxer, demuxer->movi_start); if(first_pts != -1.0) { float middle_pts = read_first_mpeg_pts_at_position(demuxer, (demuxer->movi_end + demuxer->movi_start)/2); if(middle_pts != -1.0) { float final_pts = read_first_mpeg_pts_at_position(demuxer, demuxer->movi_end - TIMESTAMP_PROBE_LEN); if(final_pts != -1.0) { // found proper first, middle, and final pts. float proportion = (middle_pts-first_pts==0) ? -1 : (final_pts-middle_pts)/(middle_pts-first_pts); // if they are linear enough set has_valid_timestamps if((0.5 < proportion) && (proportion < 2)) { mpg_d->first_pts = first_pts; mpg_d->first_to_final_pts_len = final_pts - first_pts; mpg_d->has_valid_timestamps = 1; } } } } //Cleaning up from seeking in stream reset_eof(demuxer); stream_seek(s,pos); ds_fill_buffer(demuxer->video); } // if ( demuxer->seekable ) return demuxer; }
static int demux_demuxers_fill_buffer(demuxer_t *demux,demux_stream_t *ds) { dd_priv_t* priv; priv=demux->priv; // HACK: make sure the subtitles get properly interleaved if with -subfile if (priv->sd && priv->sd->sub != ds && priv->sd != priv->vd && priv->sd != priv->ad) ds_get_next_pts(priv->sd->sub); if(priv->vd && priv->vd->video == ds) return demux_fill_buffer(priv->vd,ds); else if(priv->ad && priv->ad->audio == ds) return demux_fill_buffer(priv->ad,ds); else if(priv->sd && priv->sd->sub == ds) return demux_fill_buffer(priv->sd,ds); mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_MPDEMUX_DEMUXERS_FillBufferError); return 0; }
static void demux_demuxers_seek(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags) { dd_priv_t* priv; float pos; priv=demuxer->priv; priv->ad->stream->eof = 0; priv->sd->stream->eof = 0; // Seek video demux_seek(priv->vd,rel_seek_secs,audio_delay,flags); // Get the new pos pos = demuxer->video->pts; if (!pos) { // since the video demuxer might provide multiple // streams (e.g. subs) we might have to call // demux_fill_buffer multiple times. int limit = 10; do { demux_fill_buffer(priv->vd, demuxer->video); } while (--limit && !demuxer->video->first); if (demuxer->video->first) pos = demuxer->video->first->pts; } if(priv->ad != priv->vd && demuxer->audio->sh) { sh_audio_t* sh = demuxer->audio->sh; demux_seek(priv->ad,pos,audio_delay,1); // In case the demuxer don't set pts if(!demuxer->audio->pts) demuxer->audio->pts = pos-((ds_tell_pts(demuxer->audio)-sh->a_in_buffer_len)/(float)sh->i_bps); } if(priv->sd != priv->vd) demux_seek(priv->sd,pos,audio_delay,1); }
// return value: // 0 = EOF // 1 = successful int ds_fill_buffer(demux_stream_t *ds) { demuxer_t *demux = ds->demuxer; if (ds->current) free_demux_packet(ds->current); ds->current = NULL; mp_dbg(MSGT_DEMUXER, MSGL_DBG3, "ds_fill_buffer (%s) called\n", ds == demux->audio ? "d_audio" : ds == demux->video ? "d_video" : ds == demux->sub ? "d_sub" : "unknown"); while (1) { if (ds->packs) { demux_packet_t *p = ds->first; // copy useful data: ds->buffer = p->buffer; ds->buffer_pos = 0; ds->buffer_size = p->len; ds->pos = p->pos; ds->dpos += p->len; // !!! ++ds->pack_no; if (p->pts != MP_NOPTS_VALUE) { ds->pts = p->pts; ds->pts_bytes = 0; } ds->pts_bytes += p->len; // !!! if (p->stream_pts != MP_NOPTS_VALUE) demux->stream_pts = p->stream_pts; ds->keyframe = p->keyframe; // unlink packet: ds->bytes -= p->len; ds->current = p; ds->first = p->next; if (!ds->first) ds->last = NULL; --ds->packs; /* The code below can set ds->eof to 1 when another stream runs * out of buffer space. That makes sense because in that situation * the calling code should not count on being able to demux more * packets from this stream. * If however the situation improves and we're called again * despite the eof flag then it's better to clear it to avoid * weird behavior. */ ds->eof = 0; return 1; } #define MaybeNI _("Maybe you are playing a non-interleaved stream/file or the codec failed?\n" \ "For AVI files, try to force non-interleaved mode with the -ni option.\n") if (demux->audio->packs >= MAX_PACKS || demux->audio->bytes >= MAX_PACK_BYTES) { mp_tmsg(MSGT_DEMUXER, MSGL_ERR, "\nToo many audio packets in the buffer: (%d in %d bytes).\n", demux->audio->packs, demux->audio->bytes); mp_tmsg(MSGT_DEMUXER, MSGL_HINT, MaybeNI); break; } if (demux->video->packs >= MAX_PACKS || demux->video->bytes >= MAX_PACK_BYTES) { mp_tmsg(MSGT_DEMUXER, MSGL_ERR, "\nToo many video packets in the buffer: (%d in %d bytes).\n", demux->video->packs, demux->video->bytes); mp_tmsg(MSGT_DEMUXER, MSGL_HINT, MaybeNI); break; } if (!demux_fill_buffer(demux, ds)) { mp_dbg(MSGT_DEMUXER, MSGL_DBG2, "ds_fill_buffer()->demux_fill_buffer() failed\n"); break; // EOF } } ds->buffer_pos = ds->buffer_size = 0; ds->buffer = NULL; mp_msg(MSGT_DEMUXER, MSGL_V, "ds_fill_buffer: EOF reached (stream: %s) \n", ds == demux->audio ? "audio" : "video"); ds->eof = 1; return 0; }