void reset_subtitles(struct MPContext *mpctx) { if (mpctx->d_sub) sub_reset(mpctx->d_sub); set_osd_subtitle(mpctx, NULL); osd_changed(mpctx->osd, OSDTYPE_SUB); }
static void reset_subtitles(struct MPContext *mpctx, int order) { int obj = order ? OSDTYPE_SUB2 : OSDTYPE_SUB; if (mpctx->d_sub[order]) sub_reset(mpctx->d_sub[order]); set_osd_subtitle(mpctx, NULL); osd_set_text(mpctx->osd, obj, NULL); }
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)); }
void find_sub(struct MPContext *mpctx, sub_data* subd,int key){ subtitle *subs; subtitle *new_sub = NULL; int i,j; if ( !subd || subd->sub_num == 0) return; subs = subd->subtitles; if (last_sub_data != subd) { // Sub data changed, reset nosub range. last_sub_data = subd; nosub_range_start = -1; nosub_range_end = -1; } if(vo_sub){ if(key>=vo_sub->start && key<=vo_sub->end) return; // OK! } else { if(key>nosub_range_start && key<nosub_range_end) return; // OK! } // sub changed! /* Tell the OSD subsystem that the OSD contents will change soon */ vo_osd_changed(OSDTYPE_SUBTITLE); if(key<=0){ // no sub here goto update; } // printf("\r---- sub changed ----\n"); // check next sub. if(current_sub>=0 && current_sub+1 < subd->sub_num){ if(key>subs[current_sub].end && key<subs[current_sub+1].start){ // no sub nosub_range_start=subs[current_sub].end; nosub_range_end=subs[current_sub+1].start; goto update; } // next sub? ++current_sub; new_sub=&subs[current_sub]; if(key>=new_sub->start && key<=new_sub->end) goto update; // OK! } // printf("\r---- sub log search... ----\n"); // use logarithmic search: i=0; j = subd->sub_num - 1; // printf("Searching %d in %d..%d\n",key,subs[i].start,subs[j].end); while(j>=i){ current_sub=(i+j+1)/2; new_sub=&subs[current_sub]; if(key<new_sub->start) j=current_sub-1; else if(key>new_sub->end) i=current_sub+1; else goto update; // found! } // if(key>=new_sub->start && key<=new_sub->end) return; // OK! // check where are we... if(key<new_sub->start){ if(current_sub<=0){ // before the first sub nosub_range_start=key-1; // tricky nosub_range_end=new_sub->start; // printf("FIRST... key=%d end=%d \n",key,new_sub->start); new_sub=NULL; goto update; } --current_sub; if(key>subs[current_sub].end && key<subs[current_sub+1].start){ // no sub nosub_range_start=subs[current_sub].end; nosub_range_end=subs[current_sub+1].start; // printf("No sub... 1 \n"); new_sub=NULL; goto update; } printf("HEH???? "); } else { if(key<=new_sub->end) printf("JAJJ! "); else if(current_sub+1 >= subd->sub_num){ // at the end? nosub_range_start=new_sub->end; nosub_range_end=0x7FFFFFFF; // MAXINT // printf("END!?\n"); new_sub=NULL; goto update; } else if(key>subs[current_sub].end && key<subs[current_sub+1].start){ // no sub nosub_range_start=subs[current_sub].end; nosub_range_end=subs[current_sub+1].start; // printf("No sub... 2 \n"); new_sub=NULL; goto update; } } mp_msg(MSGT_FIXME,MSGL_FIXME,"SUB ERROR: %d ? %d --- %d [%d] \n",key,(int)new_sub->start,(int)new_sub->end,current_sub); new_sub=NULL; // no sub here update: set_osd_subtitle(mpctx, new_sub); }
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); }
void update_subtitles(sh_video_t *sh_video, double refpts, demux_stream_t *d_dvdsub, int reset) { double curpts = refpts - sub_delay; unsigned char *packet=NULL; int len; int type = d_dvdsub->sh ? ((sh_sub_t *)d_dvdsub->sh)->type : 'v'; static subtitle subs; if (reset) { sub_clear_text(&subs, MP_NOPTS_VALUE); if (vo_sub) { set_osd_subtitle(NULL); } if (vo_spudec) { spudec_reset(vo_spudec); vo_osd_changed(OSDTYPE_SPU); } #ifdef CONFIG_FFMPEG if (is_av_sub(type)) reset_avsub(d_dvdsub->sh); #endif } // find sub if (subdata) { if (sub_fps==0) sub_fps = sh_video ? sh_video->fps : 25; current_module = "find_sub"; if (refpts > sub_last_pts || refpts < sub_last_pts-1.0) { find_sub(subdata, curpts * (subdata->sub_uses_time ? 100. : sub_fps)); if (vo_sub) vo_sub_last = vo_sub; // FIXME! frame counter... sub_last_pts = refpts; } } // DVD sub: if (vo_config_count && (vobsub_id >= 0 || type == 'v')) { int timestamp; current_module = "spudec"; /* Get a sub packet from the DVD or a vobsub */ while(1) { // Vobsub len = 0; if (vo_vobsub) { if (curpts >= 0) { len = vobsub_get_packet(vo_vobsub, curpts, (void**)&packet, ×tamp); if (len > 0) { mp_dbg(MSGT_CPLAYER,MSGL_V,"\rVOB sub: len=%d v_pts=%5.3f v_timer=%5.3f sub=%5.3f ts=%d \n",len,refpts,sh_video->timer,timestamp / 90000.0,timestamp); } } } else { // DVD sub len = ds_get_packet_sub(d_dvdsub, (unsigned char**)&packet, NULL, NULL); if (len > 0) { // XXX This is wrong, sh_video->pts can be arbitrarily // much behind demuxing position. Unfortunately using // d_video->pts which would have been the simplest // improvement doesn't work because mpeg specific hacks // in video.c set d_video->pts to 0. float x = d_dvdsub->pts - refpts; if (x > -20 && x < 20) // prevent missing subs on pts reset timestamp = 90000*d_dvdsub->pts; else timestamp = 90000*curpts; mp_dbg(MSGT_CPLAYER, MSGL_V, "\rDVD sub: len=%d " "v_pts=%5.3f s_pts=%5.3f ts=%d \n", len, refpts, d_dvdsub->pts, timestamp); } } if (len<=0 || !packet) break; // create it only here, since with some broken demuxers we might // type = v but no DVD sub and we currently do not change the // "original frame size" ever after init, leading to wrong-sized // PGS subtitles. if (!vo_spudec) vo_spudec = spudec_new(NULL); if (vo_vobsub || timestamp >= 0) spudec_assemble(vo_spudec, packet, len, timestamp); } } else if (is_text_sub(type) || is_av_sub(type) || type == 'd') { int orig_type = type; double endpts; if (type == 'd' && !d_dvdsub->demuxer->teletext) { tt_stream_props tsp = {0}; void *ptr = &tsp; if (teletext_control(NULL, TV_VBI_CONTROL_START, &ptr) == VBI_CONTROL_TRUE) d_dvdsub->demuxer->teletext = ptr; } if (d_dvdsub->non_interleaved) ds_get_next_pts(d_dvdsub); while (1) { double subpts = curpts; type = orig_type; len = ds_get_packet_sub(d_dvdsub, &packet, &subpts, &endpts); if (len < 0) break; if (is_av_sub(type)) { #ifdef CONFIG_FFMPEG type = decode_avsub(d_dvdsub->sh, &packet, &len, &subpts, &endpts); if (type <= 0) #endif continue; } if (type == 'm') { if (len < 2) continue; len = FFMIN(len - 2, AV_RB16(packet)); packet += 2; } if (type == 'd') { if (d_dvdsub->demuxer->teletext) { uint8_t *p = packet; p++; len--; while (len >= 46) { int sublen = p[1]; if (p[0] == 2 || p[0] == 3) teletext_control(d_dvdsub->demuxer->teletext, TV_VBI_CONTROL_DECODE_DVB, p + 2); p += sublen + 2; len -= sublen + 2; } } continue; } #ifdef CONFIG_ASS if (ass_enabled) { sh_sub_t* sh = d_dvdsub->sh; ass_track = sh ? sh->ass_track : NULL; if (!ass_track) continue; if (type == 'a') { // ssa/ass subs with libass if (len > 10 && memcmp(packet, "Dialogue: ", 10) == 0) ass_process_data(ass_track, packet, len); else ass_process_chunk(ass_track, packet, len, (long long)(subpts*1000 + 0.5), (long long)((endpts-subpts)*1000 + 0.5)); } else { // plaintext subs with libass if (subpts != MP_NOPTS_VALUE) { subtitle tmp_subs = {0}; if (endpts == MP_NOPTS_VALUE) endpts = subpts + 3; sub_add_text(&tmp_subs, packet, len, endpts, 0); tmp_subs.start = subpts * 100; tmp_subs.end = endpts * 100; ass_process_subtitle(ass_track, &tmp_subs); sub_clear_text(&tmp_subs, MP_NOPTS_VALUE); } } continue; } #endif if (subpts != MP_NOPTS_VALUE) { if (endpts == MP_NOPTS_VALUE) sub_clear_text(&subs, MP_NOPTS_VALUE); if (type == 'a') { // ssa/ass subs without libass => convert to plaintext int i; unsigned char* p = packet; int skip_commas = 8; if (len > 10 && memcmp(packet, "Dialogue: ", 10) == 0) skip_commas = 9; for (i=0; i < skip_commas && *p != '\0'; p++) if (*p == ',') i++; if (*p == '\0') /* Broken line? */ continue; len -= p - packet; packet = p; } sub_add_text(&subs, packet, len, endpts, 1); set_osd_subtitle(&subs); } if (d_dvdsub->non_interleaved) ds_get_next_pts(d_dvdsub); } if (sub_clear_text(&subs, curpts)) set_osd_subtitle(&subs); } if (vo_spudec) { spudec_heartbeat(vo_spudec, 90000*curpts); if (spudec_changed(vo_spudec)) vo_osd_changed(OSDTYPE_SPU); } current_module=NULL; }