diff options
Diffstat (limited to 'mplayer.c')
-rw-r--r-- | mplayer.c | 465 |
1 files changed, 410 insertions, 55 deletions
@@ -76,6 +76,7 @@ #include "osdep/getch2.h" #include "osdep/timer.h" +#include "osdep/findfiles.h" #ifdef CONFIG_GUI #include "gui/interface.h" @@ -201,11 +202,6 @@ int enqueue=0; static int list_properties = 0; -int osd_level=1; -// if nonzero, hide current OSD contents when GetTimerMS() reaches this -unsigned int osd_visible; -int osd_duration = 1000; - int term_osd = 1; static char* term_osd_esc = "\x1b[A\r\x1b[K"; static char* playing_msg = NULL; @@ -213,7 +209,6 @@ static char* playing_msg = NULL; static double seek_to_sec; static off_t seek_to_byte=0; static off_t step_sec=0; -static int loop_seek=0; static m_time_size_t end_at = { .type = END_AT_NONE, .pos = 0 }; @@ -314,7 +309,6 @@ static char* rtc_device; edl_record_ptr edl_records = NULL; ///< EDL entries memory area edl_record_ptr next_edl_record = NULL; ///< only for traversing edl_records -short edl_decision = 0; ///< 1 when an EDL operation has been made. FILE* edl_fd = NULL; ///< fd to write to when in -edlout mode. int use_filedir_conf; @@ -572,6 +566,22 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask){ if(mask&INITIALIZED_DEMUXER){ mpctx->initialized_flags&=~INITIALIZED_DEMUXER; current_module="free_demuxer"; + if (mpctx->num_sources) { + mpctx->demuxer = mpctx->sources[0].demuxer; + for (int i = 1; i < mpctx->num_sources; i++) { + free_stream(mpctx->sources[i].stream); + free_demuxer(mpctx->sources[i].demuxer); + } + } + talloc_free(mpctx->sources); + mpctx->sources = NULL; + mpctx->num_sources = 0; + talloc_free(mpctx->timeline); + mpctx->timeline = NULL; + mpctx->num_timeline_parts = 0; + talloc_free(mpctx->chapters); + mpctx->num_chapters = 0; + mpctx->video_offset = 0; if(mpctx->demuxer){ mpctx->stream=mpctx->demuxer->stream; free_demuxer(mpctx->demuxer); @@ -1405,22 +1415,25 @@ static void clear_osd_msgs(void) { static mp_osd_msg_t* get_osd_msg(struct MPContext *mpctx) { + struct MPOpts *opts = &mpctx->opts; mp_osd_msg_t *msg,*prev,*last = NULL; static unsigned last_update = 0; unsigned now = GetTimerMS(); unsigned diff; char hidden_dec_done = 0; - if (osd_visible) { + if (mpctx->osd_visible) { // 36000000 means max timed visibility is 1 hour into the future, if // the difference is greater assume it's wrapped around from below 0 - if (osd_visible - now > 36000000) { - osd_visible = 0; + if (mpctx->osd_visible - now > 36000000) { + mpctx->osd_visible = 0; vo_osd_progbar_type = -1; // disable vo_osd_changed(OSDTYPE_PROGBAR); mpctx->osd_function = mpctx->paused ? OSD_PAUSE : OSD_PLAY; } } + if (mpctx->osd_show_percentage_until - now > 36000000) + mpctx->osd_show_percentage_until = 0; if(!last_update) last_update = now; diff = now >= last_update ? now - last_update : 0; @@ -1430,14 +1443,16 @@ static mp_osd_msg_t* get_osd_msg(struct MPContext *mpctx) // Look for the first message in the stack with high enough level. for(msg = osd_msg_stack ; msg ; last = msg, msg = prev) { prev = msg->prev; - if(msg->level > osd_level && hidden_dec_done) continue; + if (msg->level > opts->osd_level && hidden_dec_done) + continue; // The message has a high enough level or it is the first hidden one // in both cases we decrement the timer or kill it. if(!msg->started || msg->time > diff) { if(msg->started) msg->time -= diff; else msg->started = 1; // display it - if(msg->level <= osd_level) return msg; + if (msg->level <= opts->osd_level) + return msg; hidden_dec_done = 1; continue; } @@ -1463,19 +1478,20 @@ static mp_osd_msg_t* get_osd_msg(struct MPContext *mpctx) */ void set_osd_bar(struct MPContext *mpctx, int type,const char* name,double min,double max,double val) { - - if(osd_level < 1) return; + struct MPOpts *opts = &mpctx->opts; + if (opts->osd_level < 1) + return; if(mpctx->sh_video) { - osd_visible = (GetTimerMS() + 1000) | 1; + mpctx->osd_visible = (GetTimerMS() + 1000) | 1; vo_osd_progbar_type = type; vo_osd_progbar_value = 256*(val-min)/(max-min); vo_osd_changed(OSDTYPE_PROGBAR); return; } - set_osd_msg(OSD_MSG_BAR,1,osd_duration,"%s: %d %%", - name,ROUND(100*(val-min)/(max-min))); + set_osd_msg(OSD_MSG_BAR, 1, opts->osd_duration, "%s: %d %%", + name, ROUND(100*(val-min)/(max-min))); } @@ -1490,10 +1506,24 @@ void set_osd_bar(struct MPContext *mpctx, int type,const char* name,double min,d static void update_osd_msg(struct MPContext *mpctx) { + struct MPOpts *opts = &mpctx->opts; mp_osd_msg_t *msg; struct osd_state *osd = mpctx->osd; char osd_text_timer[128]; - + + if (mpctx->add_osd_seek_info) { + double percentage; + if (mpctx->timeline && mpctx->sh_video) + percentage = mpctx->sh_video->pts * 100 / + mpctx->timeline[mpctx->num_timeline_parts].start; + else + percentage = demuxer_get_percent_pos(mpctx->demuxer); + set_osd_bar(mpctx, 0, "Position", 0, 100, percentage); + if (mpctx->sh_video) + mpctx->osd_show_percentage_until = (GetTimerMS() + 1000) | 1; + mpctx->add_osd_seek_info = false; + } + // Look if we have a msg if((msg = get_osd_msg(mpctx))) { if (strcmp(osd->osd_text, msg->msg)) { @@ -1506,21 +1536,29 @@ static void update_osd_msg(struct MPContext *mpctx) if(mpctx->sh_video) { // fallback on the timer - if(osd_level>=2) { - int len = demuxer_get_time_length(mpctx->demuxer); + if (opts->osd_level >= 2) { + int len; + if (mpctx->timeline) + len = mpctx->timeline[mpctx->num_timeline_parts].start; + else + len = demuxer_get_time_length(mpctx->demuxer); int percentage = -1; char percentage_text[10]; int pts = demuxer_get_current_time(mpctx->demuxer); - if (mpctx->osd_show_percentage) - percentage = demuxer_get_percent_pos(mpctx->demuxer); + if (mpctx->osd_show_percentage_until) + if (mpctx->timeline) + percentage = mpctx->sh_video->pts * 100 / + mpctx->timeline[mpctx->num_timeline_parts].start; + else + percentage = demuxer_get_percent_pos(mpctx->demuxer); if (percentage >= 0) snprintf(percentage_text, 9, " (%d%%)", percentage); else percentage_text[0] = 0; - if (osd_level == 3) + if (opts->osd_level == 3) snprintf(osd_text_timer, 63, "%c %02d:%02d:%02d / %02d:%02d:%02d%s", mpctx->osd_function,pts/3600,(pts/60)%60,pts%60, @@ -1532,10 +1570,6 @@ static void update_osd_msg(struct MPContext *mpctx) } else osd_text_timer[0]=0; - // always decrement the percentage timer - if(mpctx->osd_show_percentage) - mpctx->osd_show_percentage--; - if (strcmp(osd->osd_text, osd_text_timer)) { strncpy(osd->osd_text, osd_text_timer, 63); vo_osd_changed(OSDTYPE_OSD); @@ -1680,7 +1714,7 @@ static double written_audio_pts(struct MPContext *mpctx) // to get the length in original units without speedup or slowdown a_pts -= buffered_output * mpctx->opts.playback_speed / ao_data.bps; - return a_pts; + return a_pts + mpctx->video_offset; } // Return pts value corresponding to currently playing audio. @@ -2218,7 +2252,7 @@ static double update_video_nocorrect_pts(struct MPContext *mpctx, #endif if (decoded_frame) { // These updates are done here for vf_expand OSD/subtitles - update_subtitles(sh_video, mpctx->d_sub, 0); + update_subtitles(sh_video, mpctx->d_sub, mpctx->video_offset, 0); update_teletext(sh_video, mpctx->demuxer, 0); update_osd_msg(mpctx); current_module = "filter video"; @@ -2250,6 +2284,8 @@ static double update_video(struct MPContext *mpctx, int *blit_frame) unsigned char *packet = NULL; bool hit_eof = false; int in_size = ds_get_packet_pts(mpctx->d_video, &packet, &pts); + if (pts != MP_NOPTS_VALUE) + pts += mpctx->video_offset; if (in_size < 0) { // try to extract last frames in case of decoder lag in_size = 0; @@ -2264,7 +2300,7 @@ static double update_video(struct MPContext *mpctx, int *blit_frame) framedrop_type, pts); if (decoded_frame) { // These updates are done here for vf_expand OSD/subtitles - update_subtitles(sh_video, mpctx->d_sub, 0); + update_subtitles(sh_video, mpctx->d_sub, mpctx->video_offset, 0); update_teletext(sh_video, mpctx->demuxer, 0); update_osd_msg(mpctx); current_module = "filter video"; @@ -2445,7 +2481,6 @@ static void edl_update(MPContext *mpctx) mp_msg(MSGT_CPLAYER, MSGL_DBG4, "EDL_SKIP: start [%f], stop " "[%f], length [%f]\n", next_edl_record->start_sec, next_edl_record->stop_sec, next_edl_record->length_sec); - edl_decision = 1; } else if (next_edl_record->action == EDL_MUTE) { mpctx->edl_muted = !mpctx->edl_muted; @@ -2458,6 +2493,48 @@ static void edl_update(MPContext *mpctx) } } +static void reinit_decoders(struct MPContext *mpctx) +{ + reinit_video_chain(mpctx); + reinit_audio_chain(mpctx); + mp_property_do("sub", M_PROPERTY_SET, &mpctx->global_sub_pos, mpctx); +} + +static bool timeline_set_part(struct MPContext *mpctx, int i) +{ + struct timeline_part *p = mpctx->timeline + mpctx->timeline_part; + struct timeline_part *n = mpctx->timeline + i; + mpctx->timeline_part = i; + mpctx->video_offset = n->start - n->source_start; + if (n->source == p->source) + return false; + uninit_player(mpctx, INITIALIZED_VCODEC | (mpctx->opts.fixed_vo && mpctx->opts.video_id != -2 ? 0 : INITIALIZED_VO) | INITIALIZED_AO | INITIALIZED_ACODEC); + mpctx->demuxer = n->source->demuxer; + mpctx->d_video = mpctx->demuxer->video; + mpctx->d_audio = mpctx->demuxer->audio; + mpctx->d_sub = mpctx->demuxer->sub; + mpctx->sh_video = mpctx->d_video->sh; + mpctx->sh_audio = mpctx->d_audio->sh; + return true; +} + +// Given pts, switch playback to the corresponding part. +// Return offset within that part. +static double timeline_set_from_time(struct MPContext *mpctx, double pts, + bool *need_reset) +{ + if (pts < 0) + pts = 0; + for (int i = 0; i < mpctx->num_timeline_parts; i++) { + struct timeline_part *p = mpctx->timeline + i; + if (pts < (p+1)->start) { + *need_reset = timeline_set_part(mpctx, i); + return pts - p->start + p->source_start; + } + } + return -1; +} + // style & SEEK_ABSOLUTE == 0 means seek relative to current position, == 1 means absolute // style & SEEK_FACTOR == 0 means amount in seconds, == 2 means fraction of file length @@ -2465,7 +2542,43 @@ static void edl_update(MPContext *mpctx) static int seek(MPContext *mpctx, double amount, int style) { current_module = "seek"; - if (demux_seek(mpctx->demuxer, amount, audio_delay, style) == 0) + if (mpctx->stop_play == AT_END_OF_FILE) + mpctx->stop_play = KEEP_PLAYING; + if (mpctx->timeline && style & SEEK_FACTOR) { + amount *= mpctx->timeline[mpctx->num_timeline_parts].start; + style &= ~SEEK_FACTOR; + } + if ((mpctx->demuxer->accurate_seek || mpctx->timeline) && mpctx->sh_video + && !(style & (SEEK_ABSOLUTE | SEEK_FACTOR))) { + style |= SEEK_ABSOLUTE; + if (amount > 0) + style |= SEEK_FORWARD; + else + style |= SEEK_BACKWARD; + amount += mpctx->sh_video->pts; + } + + /* At least the liba52 decoder wants to read from the input stream + * during initialization, so reinit must be done after the demux_seek() + * call that clears possible stream EOF. */ + bool need_reset = false; + if (mpctx->timeline) { + amount = timeline_set_from_time(mpctx, amount, &need_reset); + if (amount == -1) { + mpctx->stop_play = AT_END_OF_FILE; + // Clear audio from current position + if (mpctx->sh_audio) { + mpctx->audio_out->reset(); + mpctx->sh_audio->a_buffer_len = 0; + mpctx->sh_audio->a_out_buffer_len = 0; + } + return -1; + } + } + int seekresult = demux_seek(mpctx->demuxer, amount, audio_delay, style); + if (need_reset) + reinit_decoders(mpctx); + if (seekresult == 0) return -1; if (mpctx->sh_video) { @@ -2482,8 +2595,8 @@ static int seek(MPContext *mpctx, double amount, int style) // Not all demuxers set d_video->pts during seek, so this value // (which is used by at least vobsub and edl code below) may // be completely wrong (probably 0). - mpctx->sh_video->pts = mpctx->d_video->pts; - update_subtitles(mpctx->sh_video, mpctx->d_sub, 1); + mpctx->sh_video->pts = mpctx->d_video->pts + mpctx->video_offset; + update_subtitles(mpctx->sh_video, mpctx->d_sub, mpctx->video_offset, 1); update_teletext(mpctx->sh_video, mpctx->demuxer, 1); } @@ -2509,6 +2622,230 @@ static int seek(MPContext *mpctx, double amount, int style) return 0; } +int get_current_chapter(struct MPContext *mpctx) +{ + if (!mpctx->chapters || !mpctx->sh_video) + return demuxer_get_current_chapter(mpctx->demuxer); + + int i; + double current_pts = mpctx->sh_video->pts; + for (i = 1; i < mpctx->num_chapters; i++) + if (current_pts < mpctx->chapters[i].start) + break; + return i - 1; +} + +// currently returns a string allocated with malloc, not talloc +char *chapter_display_name(struct MPContext *mpctx, int chapter) +{ + if (!mpctx->chapters || !mpctx->sh_video) + return demuxer_chapter_display_name(mpctx->demuxer, chapter); + return strdup(mpctx->chapters[chapter].name); +} + +int seek_chapter(struct MPContext *mpctx, int chapter, double *seek_pts, + char **chapter_name) +{ + if (!mpctx->chapters || !mpctx->sh_video) + return demuxer_seek_chapter(mpctx->demuxer, chapter, seek_pts, + chapter_name); + if (chapter >= mpctx->num_chapters) + return -1; + if (chapter < 0) + chapter = 0; + *seek_pts = mpctx->chapters[chapter].start; + if (chapter_name) + *chapter_name = talloc_strdup(NULL, mpctx->chapters[chapter].name); + return chapter; +} + +static int find_ordered_chapter_sources(struct MPContext *mpctx, + struct content_source *sources, + int num_sources, + unsigned char uid_map[][16]) +{ + int num_filenames = 0; + char **filenames = NULL; + if (num_sources > 1) { + mp_msg(MSGT_CPLAYER, MSGL_INFO, "This file references data from " + "other sources.\n"); + if (mpctx->stream->type != STREAMTYPE_FILE) { + mp_msg(MSGT_CPLAYER, MSGL_WARN, "Playback source is not a " + "normal disk file. Will not search for related files.\n"); + } else { + mp_msg(MSGT_CPLAYER, MSGL_INFO, "Will scan other files in the " + "same directory to find referenced sources.\n"); + filenames = find_files(mpctx->demuxer->filename, ".mkv", + &num_filenames); + } + } + + int num_left = num_sources - 1; + for (int i = 0; i < num_filenames && num_left > 0; i++) { + mp_msg(MSGT_CPLAYER, MSGL_INFO, "Checking file %s\n", + filename_recode(filenames[i])); + int format; + struct stream *s = open_stream(filenames[i], &mpctx->opts, &format); + if (!s) + continue; + struct demuxer *d = demux_open(&mpctx->opts, s, DEMUXER_TYPE_MATROSKA, + mpctx->opts.audio_id, + mpctx->opts.video_id, + mpctx->opts.sub_id, filenames[i]); + if (!d) { + free_stream(s); + continue; + } + if (d->file_format == DEMUXER_TYPE_MATROSKA) { + for (int i = 1; i < num_sources; i++) { + if (sources[i].demuxer) + continue; + if (!memcmp(uid_map[i], d->matroska_data.segment_uid, 16)) { + mp_msg(MSGT_CPLAYER, MSGL_INFO,"Match for source %d: %s\n", + i, filename_recode(d->filename)); + sources[i].stream = s; + sources[i].demuxer = d; + num_left--; + goto match; + } + } + } + free_demuxer(d); + free_stream(s); + continue; + match: + ; + } + talloc_free(filenames); + if (num_left) { + mp_msg(MSGT_CPLAYER, MSGL_ERR, "Failed to find ordered chapter part!\n" + "There will be parts MISSING from the video!\n"); + for (int i = 1, j = 1; i < num_sources; i++) + if (sources[i].demuxer) { + sources[j] = sources[i]; + memcpy(uid_map[j], uid_map[i], 16); + j++; + } + } + return num_sources - num_left; +} + +static void build_ordered_chapter_timeline(struct MPContext *mpctx) +{ + if (!mpctx->opts.ordered_chapters) { + mp_msg(MSGT_CPLAYER, MSGL_INFO, "File uses ordered chapters, but " + "you have disabled support for them. Ignoring.\n"); + return; + } + + mp_msg(MSGT_CPLAYER, MSGL_INFO, "File uses ordered chapters, will build " + "edit timeline.\n"); + + struct demuxer *demuxer = mpctx->demuxer; + struct matroska_data *m = &demuxer->matroska_data; + + struct content_source *sources = talloc_array_ptrtype(NULL, sources, + m->num_ordered_chapters); + sources[0].stream = mpctx->stream; + sources[0].demuxer = mpctx->demuxer; + unsigned char uid_map[m->num_ordered_chapters][16]; + int num_sources = 1; + memcpy(uid_map[0], m->segment_uid, 16); + + for (int i = 0; i < m->num_ordered_chapters; i++) { + struct matroska_chapter *c = m->ordered_chapters + i; + if (!c->has_segment_uid) + memcpy(c->segment_uid, m->segment_uid, 16); + + for (int j = 0; j < num_sources; j++) + if (!memcmp(c->segment_uid, uid_map[j], 16)) + goto found1; + memcpy(uid_map[num_sources], c->segment_uid, 16); + sources[num_sources] = (struct content_source){}; + num_sources++; + found1: + ; + } + + num_sources = find_ordered_chapter_sources(mpctx, sources, num_sources, + uid_map); + + + struct timeline_part *timeline = talloc_array_ptrtype(NULL, timeline, + m->num_ordered_chapters + 1); + struct chapter *chapters = talloc_array_ptrtype(NULL, chapters, + m->num_ordered_chapters); + uint64_t starttime = 0; + uint64_t missing_time = 0; + int part_count = 0; + int num_chapters = 0; + for (int i = 0; i < m->num_ordered_chapters; i++) { + struct matroska_chapter *c = m->ordered_chapters + i; + + int j; + for (j = 0; j < num_sources; j++) { + if (!memcmp(c->segment_uid, uid_map[j], 16)) + goto found2; + } + missing_time += c->end - c->start; + continue; + found2:; + chapters[num_chapters].start = starttime / 1000.; + chapters[num_chapters].name = talloc_strdup(chapters, c->name); + // Only add a separate part if the time or file actually changes + uint64_t prev_end = !part_count ? 0 : starttime + - timeline[part_count - 1].start + + timeline[part_count - 1].source_start; + if (part_count == 0 || c->start != prev_end + || sources + j != timeline[part_count - 1].source) { + timeline[part_count].source = sources + j; + timeline[part_count].start = chapters[num_chapters].start; + timeline[part_count].source_start = c->start / 1000.; + part_count++; + } + starttime += c->end - c->start; + num_chapters++; + } + timeline[part_count].start = starttime / 1000.; + + if (!part_count) { + // None of the parts come from the file itself??? + talloc_free(sources); + talloc_free(timeline); + talloc_free(chapters); + return; + } + + mp_msg(MSGT_CPLAYER, MSGL_V, "Timeline contains %d parts from %d " + "sources. Total length %.3f seconds.\n", part_count, num_sources, + timeline[part_count].start); + if (missing_time) + mp_msg(MSGT_CPLAYER, MSGL_ERR, "There are %.3f seconds missing " + "from the timeline!\n", missing_time / 1000.); + mp_msg(MSGT_CPLAYER, MSGL_V, "Source files:\n"); + for (int i = 0; i < num_sources; i++) + mp_msg(MSGT_CPLAYER, MSGL_V, "%d: %s\n", i, + filename_recode(sources[i].demuxer->filename)); + mp_msg(MSGT_CPLAYER, MSGL_V, "Timeline parts: (number, start, " + "source_start, source):\n"); + for (int i = 0; i < part_count; i++) { + struct timeline_part *p = timeline + i; + mp_msg(MSGT_CPLAYER, MSGL_V, "%3d %9.3f %9.3f %3td\n", i, p->start, + p->source_start, p->source - sources); + } + mp_msg(MSGT_CPLAYER, MSGL_V, "END %9.3f\n", timeline[part_count].start); + mpctx->sources = sources; + mpctx->num_sources = num_sources; + mpctx->timeline = timeline; + mpctx->num_timeline_parts = part_count; + mpctx->num_chapters = num_chapters; + mpctx->chapters = chapters; + + mpctx->timeline_part = 0; + mpctx->video_offset = timeline[0].source_start; + mpctx->demuxer = timeline[0].source->demuxer; +} + static int read_keys(void *ctx, int fd) { @@ -3301,9 +3638,20 @@ if (mpctx->demuxer && mpctx->demuxer->type==DEMUXER_TYPE_PLAYLIST) if(!mpctx->demuxer) goto goto_next_file; + + if (mpctx->demuxer->matroska_data.ordered_chapters) + build_ordered_chapter_timeline(mpctx); + + if (!mpctx->sources) { + mpctx->sources = talloc_ptrtype(NULL, mpctx->sources); + *mpctx->sources = (struct content_source){.stream = mpctx->stream, + .demuxer = mpctx->demuxer}; + mpctx->num_sources = 1; + } + if(dvd_chapter>1) { - float pts; - if (demuxer_seek_chapter(mpctx->demuxer, dvd_chapter-1, 1, &pts, NULL, NULL) >= 0 && pts > -1.0) + double pts; + if (seek_chapter(mpctx, dvd_chapter-1, &pts, NULL) >= 0 && pts > -1.0) seek(mpctx, pts, SEEK_ABSOLUTE); } @@ -3325,14 +3673,17 @@ if (mpctx->global_sub_size <= mpctx->global_sub_indices[SUB_SOURCE_DEMUX] + opts #ifdef CONFIG_ASS if (ass_enabled && ass_library) { - for (i = 0; i < mpctx->demuxer->num_attachments; ++i) { - demux_attachment_t* att = mpctx->demuxer->attachments + i; - if (extract_embedded_fonts && - att->name && att->type && att->data && att->data_size && - (strcmp(att->type, "application/x-truetype-font") == 0 || - strcmp(att->type, "application/x-font") == 0)) - ass_add_font(ass_library, att->name, att->data, att->data_size); - } + for (int j = 0; j < mpctx->num_sources; j++) { + struct demuxer *d = mpctx->sources[j].demuxer; + for (int i = 0; i < d->num_attachments; i++) { + struct demux_attachment *att = d->attachments + i; + if (extract_embedded_fonts + && att->name && att->type && att->data && att->data_size + && (strcmp(att->type, "application/x-truetype-font") == 0 + || strcmp(att->type, "application/x-font") == 0)) + ass_add_font(ass_library, att->name, att->data, att->data_size); + } + } } #endif @@ -3691,12 +4042,16 @@ if (mpctx->stream->type == STREAMTYPE_DVDNAV) { mpctx->drop_message_shown = 0; mpctx->update_video_immediately = true; mpctx->total_avsync_change = 0; + // Make sure VO knows current pause state + if (mpctx->sh_video) + vo_control(mpctx->video_out, mpctx->paused ? VOCTRL_PAUSE : VOCTRL_RESUME, + NULL); while(!mpctx->stop_play){ float aq_sleep_time=0; if(dvd_last_chapter>0) { - int cur_chapter = demuxer_get_current_chapter(mpctx->demuxer); + int cur_chapter = get_current_chapter(mpctx); if(cur_chapter!=-1 && cur_chapter+1>dvd_last_chapter) goto goto_next_file; } @@ -3765,6 +4120,15 @@ if(!mpctx->sh_video) { } } } + if (mpctx->timeline) { + struct timeline_part *next = mpctx->timeline + mpctx->timeline_part + 1; + if (mpctx->sh_video->pts >= next->start + || mpctx->stop_play == AT_END_OF_FILE + && mpctx->timeline_part + 1 < mpctx->num_timeline_parts) { + seek(mpctx, next->start, SEEK_ABSOLUTE); + continue; + } + } // ========================================================================== @@ -3918,22 +4282,13 @@ if (step_sec > 0 && !mpctx->paused) { play_n_frames=play_n_frames_mf; mpctx->stop_play=0; mpctx->abs_seek_pos=SEEK_ABSOLUTE; mpctx->rel_seek_secs=seek_to_sec; - loop_seek = 1; } if(mpctx->rel_seek_secs || mpctx->abs_seek_pos){ - if (seek(mpctx, mpctx->rel_seek_secs, mpctx->abs_seek_pos) >= 0) { - // Set OSD: - if(!loop_seek){ - if( !edl_decision ) - set_osd_bar(mpctx, 0,"Position",0,100,demuxer_get_percent_pos(mpctx->demuxer)); - } - } + seek(mpctx, mpctx->rel_seek_secs, mpctx->abs_seek_pos); mpctx->rel_seek_secs=0; mpctx->abs_seek_pos=0; - loop_seek=0; - edl_decision = 0; } #ifdef CONFIG_GUI |