// Time used to seek external tracks to. double get_main_demux_pts(struct MPContext *mpctx) { double main_new_pos = MP_NOPTS_VALUE; if (mpctx->demuxer) { for (int n = 0; n < mpctx->demuxer->num_streams; n++) { if (main_new_pos == MP_NOPTS_VALUE) main_new_pos = demux_get_next_pts(mpctx->demuxer->streams[n]); } } return main_new_pos; }
void update_subtitles(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; if (!(mpctx->initialized_flags & INITIALIZED_SUB)) return; struct track *track = mpctx->current_track[STREAM_SUB]; struct dec_sub *dec_sub = mpctx->d_sub; assert(track && dec_sub); if (mpctx->d_video) { struct mp_image_params params = mpctx->d_video->vf_input; if (params.imgfmt) sub_control(dec_sub, SD_CTRL_SET_VIDEO_PARAMS, ¶ms); } mpctx->osd->video_offset = track->under_timeline ? mpctx->video_offset : 0; double refpts_s = mpctx->playback_pts - mpctx->osd->video_offset; double curpts_s = refpts_s + opts->sub_delay; if (!track->preloaded && track->stream) { struct sh_stream *sh_stream = track->stream; bool interleaved = is_interleaved(mpctx, track); assert(sh_stream->sub->dec_sub == dec_sub); while (1) { if (interleaved && !demux_has_packet(sh_stream)) break; double subpts_s = demux_get_next_pts(sh_stream); if (!demux_has_packet(sh_stream)) break; if (subpts_s > curpts_s) { MP_DBG(mpctx, "Sub early: c_pts=%5.3f s_pts=%5.3f\n", curpts_s, subpts_s); // Libass handled subs can be fed to it in advance if (!sub_accept_packets_in_advance(dec_sub)) break; // Try to avoid demuxing whole file at once if (subpts_s > curpts_s + 1 && !interleaved) break; } struct demux_packet *pkt = demux_read_packet(sh_stream); MP_DBG(mpctx, "Sub: c_pts=%5.3f s_pts=%5.3f duration=%5.3f len=%d\n", curpts_s, pkt->pts, pkt->duration, pkt->len); sub_decode(dec_sub, pkt); talloc_free(pkt); } } if (!mpctx->osd->render_bitmap_subs || !mpctx->video_out) set_osd_subtitle(mpctx, sub_get_text(dec_sub, curpts_s)); }
// Time used to seek external tracks to. double get_main_demux_pts(struct MPContext *mpctx) { double main_new_pos = MP_NOPTS_VALUE; if (mpctx->demuxer) { for (int n = 0; n < mpctx->demuxer->num_streams; n++) { struct sh_stream *stream = mpctx->demuxer->streams[n]; if (main_new_pos == MP_NOPTS_VALUE && stream->type != STREAM_SUB) main_new_pos = demux_get_next_pts(stream); } } return main_new_pos; }
static struct demux_packet *video_read_frame(struct MPContext *mpctx) { sh_video_t *sh_video = mpctx->sh_video; demuxer_t *demuxer = sh_video->gsh->demuxer; float pts1 = sh_video->last_pts; struct demux_packet *pkt = demux_read_packet(sh_video->gsh); if (!pkt) return NULL; // EOF if (pkt->pts != MP_NOPTS_VALUE) sh_video->last_pts = pkt->pts; float frame_time = sh_video->fps > 0 ? 1.0f / sh_video->fps : 0; // override frame_time for variable/unknown FPS formats: if (!mpctx->opts->force_fps) { double next_pts = demux_get_next_pts(sh_video->gsh); double d = next_pts == MP_NOPTS_VALUE ? sh_video->last_pts - pts1 : next_pts - sh_video->last_pts; if (d >= 0) { if (demuxer->type == DEMUXER_TYPE_TV) { if (d > 0) sh_video->fps = 1.0f / d; frame_time = d; } else { if ((int)sh_video->fps <= 1) frame_time = d; } } } sh_video->pts = sh_video->last_pts; sh_video->next_frame_time = frame_time; return pkt; }
void update_osd_sub_state(struct MPContext *mpctx, int order, struct osd_sub_state *out_state) { struct MPOpts *opts = mpctx->opts; struct track *track = mpctx->current_track[order][STREAM_SUB]; struct dec_sub *dec_sub = mpctx->d_sub[order]; int obj = order ? OSDTYPE_SUB2 : OSDTYPE_SUB; bool textsub = dec_sub && sub_has_get_text(dec_sub); struct osd_sub_state state = { .dec_sub = dec_sub, // Decides whether to use OSD path or normal subtitle rendering path. .render_bitmap_subs = opts->ass_enabled || !textsub, .video_offset = get_track_video_offset(mpctx, track), }; // Secondary subs are rendered with the "text" renderer to transform them // to toptitles. if (order == 1 && textsub) state.render_bitmap_subs = false; if (!mpctx->current_track[0][STREAM_VIDEO]) state.render_bitmap_subs = false; osd_set_sub(mpctx->osd, obj, &state); if (out_state) *out_state = state; } static void update_subtitle(struct MPContext *mpctx, int order) { struct MPOpts *opts = mpctx->opts; struct track *track = mpctx->current_track[order][STREAM_SUB]; struct dec_sub *dec_sub = mpctx->d_sub[order]; if (!track || !dec_sub) return; int obj = order ? OSDTYPE_SUB2 : OSDTYPE_SUB; if (mpctx->d_video) { struct mp_image_params params = mpctx->d_video->vfilter->override_params; if (params.imgfmt) sub_control(dec_sub, SD_CTRL_SET_VIDEO_PARAMS, ¶ms); } struct osd_sub_state state; update_osd_sub_state(mpctx, order, &state); double refpts_s = mpctx->playback_pts - state.video_offset; double curpts_s = refpts_s - opts->sub_delay; if (!track->preloaded && track->stream) { struct sh_stream *sh_stream = track->stream; bool interleaved = is_interleaved(mpctx, track); assert(sh_stream->sub->dec_sub == dec_sub); while (1) { if (interleaved && !demux_has_packet(sh_stream)) break; double subpts_s = demux_get_next_pts(sh_stream); if (!demux_has_packet(sh_stream)) break; if (subpts_s > curpts_s) { MP_DBG(mpctx, "Sub early: c_pts=%5.3f s_pts=%5.3f\n", curpts_s, subpts_s); // Libass handled subs can be fed to it in advance if (!sub_accept_packets_in_advance(dec_sub)) break; // Try to avoid demuxing whole file at once if (subpts_s > curpts_s + 1 && !interleaved) break; } struct demux_packet *pkt = demux_read_packet(sh_stream); MP_DBG(mpctx, "Sub: c_pts=%5.3f s_pts=%5.3f duration=%5.3f len=%d\n", curpts_s, pkt->pts, pkt->duration, pkt->len); sub_decode(dec_sub, pkt); talloc_free(pkt); } } // Handle displaying subtitles on terminal; never done for secondary subs if (order == 0) { if (!state.render_bitmap_subs || !mpctx->video_out) set_osd_subtitle(mpctx, sub_get_text(dec_sub, curpts_s)); } else if (order == 1) { osd_set_text(mpctx->osd, obj, sub_get_text(dec_sub, curpts_s)); } } void update_subtitles(struct MPContext *mpctx) { update_subtitle(mpctx, 0); update_subtitle(mpctx, 1); }