aboutsummaryrefslogtreecommitdiffhomepage
path: root/mplayer.c
diff options
context:
space:
mode:
Diffstat (limited to 'mplayer.c')
-rw-r--r--mplayer.c2598
1 files changed, 1490 insertions, 1108 deletions
diff --git a/mplayer.c b/mplayer.c
index 664fdb7ef0..af4fd37d1e 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -21,7 +21,9 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include "config.h"
+#include "talloc.h"
#if defined(__MINGW32__) || defined(__CYGWIN__)
#define _UWIN 1 /*disable Non-underscored versions of non-ANSI functions as otherwise int eof would conflict with eof()*/
@@ -54,21 +56,23 @@
#include <errno.h>
#include "mp_msg.h"
+#include "av_log.h"
-#define HELP_MP_DEFINE_STATIC
-#include "help_mp.h"
#include "m_option.h"
#include "m_config.h"
+#include "mplayer.h"
+#include "access_mpcontext.h"
#include "m_property.h"
#include "cfg-mplayer-def.h"
-#include "libavutil/intreadwrite.h"
+#include "ffmpeg_files/intreadwrite.h"
#include "libavutil/avstring.h"
#include "subreader.h"
+#include "mp_osd.h"
#include "libvo/video_out.h"
#include "libvo/font_load.h"
@@ -83,18 +87,17 @@
#include "codec-cfg.h"
#include "edl.h"
-#include "mplayer.h"
+
#include "spudec.h"
#include "vobsub.h"
-#include "access_mpcontext.h"
#include "osdep/getch2.h"
#include "osdep/timer.h"
-
-#include "gui/interface.h"
+#include "osdep/findfiles.h"
#include "input/input.h"
+const int under_mencoder = 0;
int slave_mode=0;
int player_idle_mode=0;
int quiet=0;
@@ -136,18 +139,12 @@ char *heartbeat_cmd;
#include "parser-cfg.h"
#include "parser-mpcmd.h"
-m_config_t* mconfig;
-
//**************************************************************************//
// Config file
//**************************************************************************//
static int cfg_inc_verbose(m_option_t *conf){ ++verbose; return 0;}
-static int cfg_include(m_option_t *conf, char *filename){
- return m_config_parse_config_file(mconfig, filename);
-}
-
#include "path.h"
//**************************************************************************//
@@ -175,6 +172,95 @@ static int max_framesize=0;
#include "mixer.h"
#include "mp_core.h"
+#include "options.h"
+#include "defaultopts.h"
+
+static const char help_text[]=_(
+"Usage: mplayer [options] [url|path/]filename\n"
+"\n"
+"Basic options: (complete list in the man page)\n"
+" -vo <drv> select video output driver ('-vo help' for a list)\n"
+" -ao <drv> select audio output driver ('-ao help' for a list)\n"
+#ifdef CONFIG_VCD
+" vcd://<trackno> play (S)VCD (Super Video CD) track (raw device, no mount)\n"
+#endif
+#ifdef CONFIG_DVDREAD
+" dvd://<titleno> play DVD title from device instead of plain file\n"
+#endif
+" -alang/-slang select DVD audio/subtitle language (by 2-char country code)\n"
+" -ss <position> seek to given (seconds or hh:mm:ss) position\n"
+" -nosound do not play sound\n"
+" -fs fullscreen playback (or -vm, -zoom, details in the man page)\n"
+" -x <x> -y <y> set display resolution (for use with -vm or -zoom)\n"
+" -sub <file> specify subtitle file to use (also see -subfps, -subdelay)\n"
+" -playlist <file> specify playlist file\n"
+" -vid x -aid y select video (x) and audio (y) stream to play\n"
+" -fps x -srate y change video (x fps) and audio (y Hz) rate\n"
+" -pp <quality> enable postprocessing filter (details in the man page)\n"
+" -framedrop enable frame dropping (for slow machines)\n"
+"\n"
+"Basic keys: (complete list in the man page, also check input.conf)\n"
+" <- or -> seek backward/forward 10 seconds\n"
+" down or up seek backward/forward 1 minute\n"
+" pgdown or pgup seek backward/forward 10 minutes\n"
+" < or > step backward/forward in playlist\n"
+" p or SPACE pause movie (press any key to continue)\n"
+" q or ESC stop playing and quit program\n"
+" + or - adjust audio delay by +/- 0.1 second\n"
+" o cycle OSD mode: none / seekbar / seekbar + timer\n"
+" * or / increase or decrease PCM volume\n"
+" x or z adjust subtitle delay by +/- 0.1 second\n"
+" r or t adjust subtitle position up/down, also see -vf expand\n"
+"\n"
+" * * * SEE THE MAN PAGE FOR DETAILS, FURTHER (ADVANCED) OPTIONS AND KEYS * * *\n"
+"\n");
+
+
+#define Exit_SIGILL_RTCpuSel _(\
+"- MPlayer crashed by an 'Illegal Instruction'.\n"\
+" It may be a bug in our new runtime CPU-detection code...\n"\
+" Please read DOCS/HTML/en/bugreports.html.\n")
+
+#define Exit_SIGILL _(\
+"- MPlayer crashed by an 'Illegal Instruction'.\n"\
+" It usually happens when you run it on a CPU different than the one it was\n"\
+" compiled/optimized for.\n"\
+" Verify this!\n")
+
+#define Exit_SIGSEGV_SIGFPE _(\
+"- MPlayer crashed by bad usage of CPU/FPU/RAM.\n"\
+" Recompile MPlayer with --enable-debug and make a 'gdb' backtrace and\n"\
+" disassembly. Details in DOCS/HTML/en/bugreports_what.html#bugreports_crash.\n")
+
+#define Exit_SIGCRASH _(\
+"- MPlayer crashed. This shouldn't happen.\n"\
+" It can be a bug in the MPlayer code _or_ in your drivers _or_ in your\n"\
+" gcc version. If you think it's MPlayer's fault, please read\n"\
+" DOCS/HTML/en/bugreports.html and follow the instructions there. We can't and\n"\
+" won't help unless you provide this information when reporting a possible bug.\n")
+
+#define SystemTooSlow _("\n\n"\
+" ************************************************\n"\
+" **** Your system is too SLOW to play this! ****\n"\
+" ************************************************\n\n"\
+"Possible reasons, problems, workarounds:\n"\
+"- Most common: broken/buggy _audio_ driver\n"\
+" - Try -ao sdl or use the OSS emulation of ALSA.\n"\
+" - Experiment with different values for -autosync, 30 is a good start.\n"\
+"- Slow video output\n"\
+" - Try a different -vo driver (-vo help for a list) or try -framedrop!\n"\
+"- Slow CPU\n"\
+" - Don't try to play a big DVD/DivX on a slow CPU! Try some of the lavdopts,\n"\
+" e.g. -vfm ffmpeg -lavdopts lowres=1:fast:skiploopfilter=all.\n"\
+"- Broken file\n"\
+" - Try various combinations of -nobps -ni -forceidx -mc 0.\n"\
+"- Slow media (NFS/SMB mounts, DVD, VCD etc)\n"\
+" - Try -cache 8192.\n"\
+"- Are you using -cache to play a non-interleaved AVI file?\n"\
+" - Try -nocache.\n"\
+"Read DOCS/HTML/en/video.html for tuning/speedup tips.\n"\
+"If none of this helps you, read DOCS/HTML/en/bugreports.html.\n\n")
+
//**************************************************************************//
//**************************************************************************//
@@ -184,24 +270,6 @@ static int max_framesize=0;
int noconsolecontrols=0;
//**************************************************************************//
-// Not all functions in mplayer.c take the context as an argument yet
-static MPContext mpctx_s = {
- .osd_function = OSD_PLAY,
- .begin_skip = MP_NOPTS_VALUE,
- .play_tree_step = 1,
- .global_sub_pos = -1,
- .set_of_sub_pos = -1,
- .file_format = DEMUXER_TYPE_UNKNOWN,
- .loop_times = -1,
-#ifdef CONFIG_DVBIN
- .last_dvb_step = 1,
-#endif
-};
-
-static MPContext *mpctx = &mpctx_s;
-
-int fixed_vo=0;
-
// benchmark:
double video_time_usage=0;
double vout_time_usage=0;
@@ -212,25 +280,11 @@ static int drop_frame_cnt=0; // total number of dropped frames
int benchmark=0;
// options:
-#define DEFAULT_STARTUP_DECODE_RETRY 8
int auto_quality=0;
static int output_quality=0;
-float playback_speed=1.0;
-
-int use_gui=0;
-
-#ifdef CONFIG_GUI
-int enqueue=0;
-#endif
-
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;
@@ -238,17 +292,12 @@ 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 };
// A/V sync:
int autosync=0; // 30 might be a good default value.
-// may be changed by GUI: (FIXME!)
-float rel_seek_secs=0;
-int abs_seek_pos=0;
-
// codecs:
char **audio_codec_list=NULL; // override audio codec
char **video_codec_list=NULL; // override video codec
@@ -260,10 +309,6 @@ extern char *demuxer_name; // override demuxer
extern char *audio_demuxer_name; // override audio demuxer
extern char *sub_demuxer_name; // override sub demuxer
-// streaming:
-int audio_id=-1;
-int video_id=-1;
-int dvdsub_id=-1;
// this dvdsub_id was selected via slang
// use this to allow dvdnav to follow -slang across stream resets,
// in particular the subtitle ID for a language changes
@@ -272,7 +317,6 @@ int vobsub_id=-1;
char* audio_lang=NULL;
char* dvdsub_lang=NULL;
static char* spudec_ifo=NULL;
-char* filename=NULL; //"MI2-Trailer.avi";
int forced_subs_only=0;
int file_filter=1;
@@ -293,8 +337,6 @@ static char *stream_dump_name="stream.dump";
// A-V sync:
static float default_max_pts_correction=-1;//0.01f;
-static float max_pts_correction=0;//default_max_pts_correction;
-static float c_total=0;
float audio_delay=0;
static int ignore_start=0;
@@ -307,10 +349,6 @@ static int audio_output_format=-1; // AF_FORMAT_UNKNOWN
static int play_n_frames=-1;
static int play_n_frames_mf=-1;
-// screen info:
-char** video_driver_list=NULL;
-char** audio_driver_list=NULL;
-
// sub:
char *font_name=NULL;
char *sub_font_name=NULL;
@@ -325,7 +363,7 @@ char *vobsub_name=NULL;
int subcc_enabled=0;
int suboverlap_enabled = 1;
-#include "libass/ass_mp.h"
+#include "ass_mp.h"
char* current_module=NULL; // for debugging
@@ -336,7 +374,7 @@ char* current_module=NULL; // for debugging
#include "m_struct.h"
#include "libmenu/menu.h"
extern vf_info_t vf_info_menu;
-static vf_info_t* libmenu_vfs[] = {
+static const vf_info_t* const libmenu_vfs[] = {
&vf_info_menu,
NULL
};
@@ -354,12 +392,10 @@ 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;
int use_filename_title;
-static unsigned int initialized_flags=0;
#include "mpcommon.h"
#include "command.h"
@@ -402,7 +438,15 @@ int mpctx_get_osd_function(MPContext *mpctx)
return mpctx->osd_function;
}
-static int is_valid_metadata_type (metadata_t type) {
+static float get_relative_time(struct MPContext *mpctx)
+{
+ unsigned int new_time = GetTimer();
+ unsigned int delta = new_time - mpctx->last_time;
+ mpctx->last_time = new_time;
+ return delta * 0.000001;
+}
+
+static int is_valid_metadata_type(struct MPContext *mpctx, metadata_t type) {
switch (type)
{
/* check for valid video stream */
@@ -446,7 +490,7 @@ static int is_valid_metadata_type (metadata_t type) {
return 1;
}
-static char *get_demuxer_info (char *tag) {
+static char *get_demuxer_info(struct MPContext *mpctx, char *tag) {
char **info = mpctx->demuxer->info;
int n;
@@ -460,19 +504,20 @@ static char *get_demuxer_info (char *tag) {
return info[2*n+1] ? strdup (info[2*n+1]) : NULL;
}
-char *get_metadata (metadata_t type) {
+char *get_metadata(struct MPContext *mpctx, metadata_t type)
+{
char *meta = NULL;
sh_audio_t * const sh_audio = mpctx->sh_audio;
sh_video_t * const sh_video = mpctx->sh_video;
- if (!is_valid_metadata_type (type))
+ if (!is_valid_metadata_type(mpctx, type))
return NULL;
switch (type)
{
case META_NAME:
{
- return strdup (mp_basename2 (filename));
+ return strdup (mp_basename2 (mpctx->filename));
}
case META_VIDEO_CODEC:
@@ -535,25 +580,25 @@ char *get_metadata (metadata_t type) {
/* check for valid demuxer */
case META_INFO_TITLE:
- return get_demuxer_info ("Title");
+ return get_demuxer_info(mpctx, "Title");
case META_INFO_ARTIST:
- return get_demuxer_info ("Artist");
+ return get_demuxer_info(mpctx, "Artist");
case META_INFO_ALBUM:
- return get_demuxer_info ("Album");
+ return get_demuxer_info(mpctx, "Album");
case META_INFO_YEAR:
- return get_demuxer_info ("Year");
+ return get_demuxer_info(mpctx, "Year");
case META_INFO_COMMENT:
- return get_demuxer_info ("Comment");
+ return get_demuxer_info(mpctx, "Comment");
case META_INFO_TRACK:
- return get_demuxer_info ("Track");
+ return get_demuxer_info(mpctx, "Track");
case META_INFO_GENRE:
- return get_demuxer_info ("Genre");
+ return get_demuxer_info(mpctx, "Genre");
default:
break;
@@ -576,24 +621,21 @@ static void mp_dvdnav_context_free(MPContext *ctx){
}
#endif
-void uninit_player(unsigned int mask){
- mask &= initialized_flags;
+void uninit_player(struct MPContext *mpctx, unsigned int mask){
+ mask &= mpctx->initialized_flags;
mp_msg(MSGT_CPLAYER,MSGL_DBG2,"\n*** uninit(0x%X)\n",mask);
if(mask&INITIALIZED_ACODEC){
- initialized_flags&=~INITIALIZED_ACODEC;
+ mpctx->initialized_flags&=~INITIALIZED_ACODEC;
current_module="uninit_acodec";
if(mpctx->sh_audio) uninit_audio(mpctx->sh_audio);
-#ifdef CONFIG_GUI
- if (use_gui) guiGetEvent(guiSetAfilter, (char *)NULL);
-#endif
mpctx->sh_audio=NULL;
mpctx->mixer.afilter = NULL;
}
if(mask&INITIALIZED_VCODEC){
- initialized_flags&=~INITIALIZED_VCODEC;
+ mpctx->initialized_flags&=~INITIALIZED_VCODEC;
current_module="uninit_vcodec";
if(mpctx->sh_video) uninit_video(mpctx->sh_video);
mpctx->sh_video=NULL;
@@ -603,8 +645,25 @@ void uninit_player(unsigned int mask){
}
if(mask&INITIALIZED_DEMUXER){
- initialized_flags&=~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->chapters = NULL;
+ mpctx->num_chapters = 0;
+ mpctx->video_offset = 0;
if(mpctx->demuxer){
mpctx->stream=mpctx->demuxer->stream;
free_demuxer(mpctx->demuxer);
@@ -614,16 +673,16 @@ void uninit_player(unsigned int mask){
// kill the cache process:
if(mask&INITIALIZED_STREAM){
- initialized_flags&=~INITIALIZED_STREAM;
+ mpctx->initialized_flags&=~INITIALIZED_STREAM;
current_module="uninit_stream";
if(mpctx->stream) free_stream(mpctx->stream);
mpctx->stream=NULL;
}
if(mask&INITIALIZED_VO){
- initialized_flags&=~INITIALIZED_VO;
+ mpctx->initialized_flags&=~INITIALIZED_VO;
current_module="uninit_vo";
- mpctx->video_out->uninit();
+ vo_destroy(mpctx->video_out);
mpctx->video_out=NULL;
#ifdef CONFIG_DVDNAV
mp_dvdnav_context_free(mpctx);
@@ -632,7 +691,7 @@ void uninit_player(unsigned int mask){
// Must be after libvo uninit, as few vo drivers (svgalib) have tty code.
if(mask&INITIALIZED_GETCH2){
- initialized_flags&=~INITIALIZED_GETCH2;
+ mpctx->initialized_flags&=~INITIALIZED_GETCH2;
current_module="uninit_getch2";
mp_msg(MSGT_CPLAYER,MSGL_DBG2,"\n[[[uninit getch2]]]\n");
// restore terminal:
@@ -640,72 +699,58 @@ void uninit_player(unsigned int mask){
}
if(mask&INITIALIZED_VOBSUB){
- initialized_flags&=~INITIALIZED_VOBSUB;
+ mpctx->initialized_flags&=~INITIALIZED_VOBSUB;
current_module="uninit_vobsub";
if(vo_vobsub) vobsub_close(vo_vobsub);
vo_vobsub=NULL;
}
if (mask&INITIALIZED_SPUDEC){
- initialized_flags&=~INITIALIZED_SPUDEC;
+ mpctx->initialized_flags&=~INITIALIZED_SPUDEC;
current_module="uninit_spudec";
spudec_free(vo_spudec);
vo_spudec=NULL;
}
if(mask&INITIALIZED_AO){
- initialized_flags&=~INITIALIZED_AO;
+ mpctx->initialized_flags&=~INITIALIZED_AO;
current_module="uninit_ao";
if (mpctx->edl_muted) mixer_mute(&mpctx->mixer);
- if (mpctx->audio_out) mpctx->audio_out->uninit(mpctx->eof?0:1);
+ if (mpctx->audio_out)
+ mpctx->audio_out->uninit(mpctx->stop_play != AT_END_OF_FILE);
mpctx->audio_out=NULL;
}
-#ifdef CONFIG_GUI
- if(mask&INITIALIZED_GUI){
- initialized_flags&=~INITIALIZED_GUI;
- current_module="uninit_gui";
- guiDone();
- }
-#endif
-
- if(mask&INITIALIZED_INPUT){
- initialized_flags&=~INITIALIZED_INPUT;
- current_module="uninit_input";
- mp_input_uninit();
-#ifdef CONFIG_MENU
- if (use_menu)
- menu_uninit();
-#endif
- }
-
current_module=NULL;
}
-void exit_player_with_rc(enum exit_reason how, int rc)
+void exit_player_with_rc(struct MPContext *mpctx, enum exit_reason how, int rc)
{
-
if (mpctx->user_muted && !mpctx->edl_muted) mixer_mute(&mpctx->mixer);
- uninit_player(INITIALIZED_ALL);
+ uninit_player(mpctx, INITIALIZED_ALL);
#if defined(__MINGW32__) || defined(__CYGWIN__)
timeEndPeriod(1);
#endif
#ifdef CONFIG_X11
-#ifdef CONFIG_GUI
- if ( !use_gui )
+ vo_uninit(mpctx->x11_state); // Close the X11 connection (if any is open).
#endif
- vo_uninit(); // Close the X11 connection (if any is open).
+
+ current_module="uninit_input";
+ mp_input_uninit(mpctx->input);
+#ifdef CONFIG_MENU
+ if (use_menu)
+ menu_uninit();
#endif
#ifdef CONFIG_FREETYPE
current_module="uninit_font";
- if (sub_font && sub_font != vo_font) free_font_desc(sub_font);
- sub_font = NULL;
- if (vo_font) free_font_desc(vo_font);
+ if (mpctx->osd && mpctx->osd->sub_font != vo_font)
+ free_font_desc(mpctx->osd->sub_font);
+ free_font_desc(vo_font);
vo_font = NULL;
done_freetype();
#endif
- free_osd_list();
+ osd_free(mpctx->osd);
#ifdef CONFIG_ASS
ass_library_done(ass_library);
@@ -715,9 +760,9 @@ void exit_player_with_rc(enum exit_reason how, int rc)
current_module="exit_player";
// free mplayer config
- if(mconfig)
- m_config_free(mconfig);
- mconfig = NULL;
+ if(mpctx->mconfig)
+ m_config_free(mpctx->mconfig);
+ mpctx->mconfig = NULL;
if(mpctx->playtree_iter)
play_tree_iter_free(mpctx->playtree_iter);
@@ -726,20 +771,21 @@ void exit_player_with_rc(enum exit_reason how, int rc)
play_tree_free(mpctx->playtree, 1);
mpctx->playtree = NULL;
+ talloc_free(mpctx->key_fifo);
if(edl_records != NULL) free(edl_records); // free mem allocated for EDL
edl_records = NULL;
switch(how) {
case EXIT_QUIT:
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_ExitingHow,MSGTR_Exit_quit);
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"\nExiting... (%s)\n","Quit");
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_EXIT=QUIT\n");
break;
case EXIT_EOF:
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_ExitingHow,MSGTR_Exit_eof);
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"\nExiting... (%s)\n","End of file");
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_EXIT=EOF\n");
break;
case EXIT_ERROR:
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_ExitingHow,MSGTR_Exit_error);
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"\nExiting... (%s)\n","Fatal error");
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_EXIT=ERROR\n");
break;
default:
@@ -750,9 +796,9 @@ void exit_player_with_rc(enum exit_reason how, int rc)
exit(rc);
}
-void exit_player(enum exit_reason how)
+static void exit_player(struct MPContext *mpctx, enum exit_reason how)
{
- exit_player_with_rc(how, 1);
+ exit_player_with_rc(mpctx, how, 1);
}
#ifndef __MINGW32__
@@ -773,7 +819,6 @@ static void exit_sighandler(int x){
if (!crash_debug || x != SIGTRAP)
#endif
++sig_count;
- if(initialized_flags==0 && sig_count>1) exit(1);
if(sig_count==5)
{
/* We're crashing bad and can't uninit cleanly :(
@@ -790,9 +835,10 @@ static void exit_sighandler(int x){
kill(getpid(),SIGKILL);
#endif
}
- mp_msg(MSGT_CPLAYER,MSGL_FATAL,"\n" MSGTR_IntBySignal,x,
- current_module?current_module:"unknown"
- );
+ mp_msg(MSGT_CPLAYER, MSGL_FATAL, "\n");
+ mp_tmsg(MSGT_CPLAYER,MSGL_FATAL,
+ "\nMPlayer interrupted by signal %d in module: %s\n", x,
+ current_module ? current_module : "unknown");
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SIGNAL=%d\n", x);
if(sig_count<=1)
switch(x){
@@ -804,15 +850,15 @@ static void exit_sighandler(int x){
return; // killed from keyboard (^C) or killed [-9]
case SIGILL:
#if CONFIG_RUNTIME_CPUDETECT
- mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_Exit_SIGILL_RTCpuSel);
+ mp_tmsg(MSGT_CPLAYER,MSGL_FATAL,Exit_SIGILL_RTCpuSel);
#else
- mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_Exit_SIGILL);
+ mp_tmsg(MSGT_CPLAYER,MSGL_FATAL,Exit_SIGILL);
#endif
case SIGFPE:
case SIGSEGV:
- mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_Exit_SIGSEGV_SIGFPE);
+ mp_tmsg(MSGT_CPLAYER,MSGL_FATAL,Exit_SIGSEGV_SIGFPE);
default:
- mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_Exit_SIGCRASH);
+ mp_tmsg(MSGT_CPLAYER,MSGL_FATAL,Exit_SIGCRASH);
#ifdef CONFIG_CRASH_DEBUG
if (crash_debug) {
int gdb_pid;
@@ -840,15 +886,20 @@ static void exit_sighandler(int x){
#include "cfg-mplayer.h"
-static void parse_cfgfiles( m_config_t* conf )
+static int cfg_include(m_option_t *conf, char *filename)
+{
+ return m_config_parse_config_file(conf->priv, filename);
+}
+
+static void parse_cfgfiles(struct MPContext *mpctx, m_config_t* conf)
{
char *conffile;
int conffile_fd;
if (!disable_system_conf &&
m_config_parse_config_file(conf, MPLAYER_CONFDIR "/mplayer.conf") < 0)
- exit_player(EXIT_NONE);
+ exit_player(mpctx, EXIT_NONE);
if ((conffile = get_path("")) == NULL) {
- mp_msg(MSGT_CPLAYER,MSGL_WARN,MSGTR_NoHomeDir);
+ mp_tmsg(MSGT_CPLAYER,MSGL_WARN,"Cannot find HOME directory.\n");
} else {
#ifdef __MINGW32__
mkdir(conffile);
@@ -857,16 +908,16 @@ if ((conffile = get_path("")) == NULL) {
#endif
free(conffile);
if ((conffile = get_path("config")) == NULL) {
- mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_GetpathProblem);
+ mp_tmsg(MSGT_CPLAYER,MSGL_ERR,"get_path(\"config\") problem\n");
} else {
if ((conffile_fd = open(conffile, O_CREAT | O_EXCL | O_WRONLY, 0666)) != -1) {
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_CreatingCfgFile, conffile);
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"Creating config file: %s\n", conffile);
write(conffile_fd, default_config, strlen(default_config));
close(conffile_fd);
}
if (!disable_user_conf &&
m_config_parse_config_file(conf, conffile) < 0)
- exit_player(EXIT_NONE);
+ exit_player(mpctx, EXIT_NONE);
free(conffile);
}
}
@@ -890,7 +941,7 @@ static void load_per_protocol_config (m_config_t* conf, const char *const file)
p = m_config_get_profile (conf, protocol);
if (p)
{
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_LoadingProtocolProfile, protocol);
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"Loading protocol-related profile '%s'\n", protocol);
m_config_set_profile(conf,p);
}
}
@@ -904,7 +955,7 @@ static void load_per_extension_config (m_config_t* conf, const char *const file)
m_profile_t *p;
/* does filename actually have an extension ? */
- str = strrchr (filename, '.');
+ str = strrchr (file, '.');
if (!str)
return;
@@ -913,7 +964,7 @@ static void load_per_extension_config (m_config_t* conf, const char *const file)
p = m_config_get_profile (conf, extension);
if (p)
{
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_LoadingExtensionProfile, extension);
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"Loading extension-related profile '%s'\n", extension);
m_config_set_profile(conf,p);
}
}
@@ -930,7 +981,7 @@ static void load_per_output_config (m_config_t* conf, char *cfg, char *out)
p = m_config_get_profile (conf, profile);
if (p)
{
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_LoadingExtensionProfile, profile);
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"Loading extension-related profile '%s'\n", profile);
m_config_set_profile(conf,p);
}
}
@@ -944,7 +995,7 @@ static int try_load_config(m_config_t *conf, const char *file)
struct stat st;
if (stat(file, &st))
return 0;
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_LoadingConfig, file);
+ mp_tmsg(MSGT_CPLAYER, MSGL_INFO, "Loading config '%s'\n", file);
m_config_parse_config_file (conf, file);
return 1;
}
@@ -997,42 +1048,35 @@ static void load_per_file_config (m_config_t* conf, const char *const file)
* cache filling) if the operation fails we use this function to check
* if it was interrupted by the user.
* The function returns a new value for eof. */
-static int libmpdemux_was_interrupted(int eof) {
+static int libmpdemux_was_interrupted(struct MPContext *mpctx, int stop_play)
+{
mp_cmd_t* cmd;
- if((cmd = mp_input_get_cmd(0,0,0)) != NULL) {
+ if((cmd = mp_input_get_cmd(mpctx->input, 0, 0)) != NULL) {
switch(cmd->id) {
case MP_CMD_QUIT:
- exit_player_with_rc(EXIT_QUIT, (cmd->nargs > 0)? cmd->args[0].v.i : 0);
+ exit_player_with_rc(mpctx, EXIT_QUIT, (cmd->nargs > 0)? cmd->args[0].v.i : 0);
case MP_CMD_PLAY_TREE_STEP: {
- eof = (cmd->args[0].v.i > 0) ? PT_NEXT_ENTRY : PT_PREV_ENTRY;
+ stop_play = (cmd->args[0].v.i > 0) ? PT_NEXT_ENTRY : PT_PREV_ENTRY;
mpctx->play_tree_step = (cmd->args[0].v.i == 0) ? 1 : cmd->args[0].v.i;
} break;
case MP_CMD_PLAY_TREE_UP_STEP: {
- eof = (cmd->args[0].v.i > 0) ? PT_UP_NEXT : PT_UP_PREV;
+ stop_play = (cmd->args[0].v.i > 0) ? PT_UP_NEXT : PT_UP_PREV;
} break;
case MP_CMD_PLAY_ALT_SRC_STEP: {
- eof = (cmd->args[0].v.i > 0) ? PT_NEXT_SRC : PT_PREV_SRC;
+ stop_play = (cmd->args[0].v.i > 0) ? PT_NEXT_SRC : PT_PREV_SRC;
} break;
}
mp_cmd_free(cmd);
}
- return eof;
+ return stop_play;
}
#define mp_basename(s) (strrchr(s,'\\')==NULL?(mp_basename2(s)):(strrchr(s,'\\')+1))
-static int playtree_add_playlist(play_tree_t* entry)
+static int playtree_add_playlist(struct MPContext *mpctx, play_tree_t* entry)
{
- play_tree_add_bpf(entry,filename);
+ play_tree_add_bpf(entry,mpctx->filename);
-#ifdef CONFIG_GUI
- if (use_gui) {
- if (entry) {
- import_playtree_playlist_into_gui(entry, mconfig);
- play_tree_free_list(entry,1);
- }
- } else
-#endif
{
if(!entry) {
entry = mpctx->playtree_iter->tree;
@@ -1058,76 +1102,59 @@ static int playtree_add_playlist(play_tree_t* entry)
return PT_NEXT_SRC;
}
-void add_subtitles(char *filename, float fps, int noerr)
+void add_subtitles(struct MPContext *mpctx, char *filename, float fps, int noerr)
{
- sub_data *subd;
-#ifdef CONFIG_ASS
- ass_track_t *asst = 0;
-#endif
+ struct MPOpts *opts = &mpctx->opts;
+ sub_data *subd = NULL;
+ struct ass_track *asst = NULL;
if (filename == NULL || mpctx->set_of_sub_size >= MAX_SUBTITLE_FILES) {
return;
}
- subd = sub_read_file(filename, fps);
#ifdef CONFIG_ASS
- if (ass_enabled)
+ if (opts->ass_enabled) {
#ifdef CONFIG_ICONV
asst = ass_read_stream(ass_library, filename, sub_cp);
#else
asst = ass_read_stream(ass_library, filename, 0);
#endif
- if (ass_enabled && subd && !asst)
- asst = ass_read_subdata(ass_library, subd, fps);
-
- if (!asst && !subd)
-#else
- if(!subd)
+ if (!asst) {
+ subd = sub_read_file(filename, fps);
+ if (subd) {
+ asst = ass_read_subdata(ass_library, subd, fps);
+ if (asst) {
+ sub_free(subd);
+ subd = NULL;
+ }
+ }
+ }
+ } else
#endif
- mp_msg(MSGT_CPLAYER, noerr ? MSGL_WARN : MSGL_ERR, MSGTR_CantLoadSub,
- filename_recode(filename));
+ subd = sub_read_file(filename, fps);
+
+
+ if (!asst && !subd) {
+ mp_tmsg(MSGT_CPLAYER, noerr ? MSGL_WARN : MSGL_ERR,
+ "Cannot load subtitles: %s\n", filename_recode(filename));
+ return;
+ }
-#ifdef CONFIG_ASS
- if (!asst && !subd) return;
mpctx->set_of_ass_tracks[mpctx->set_of_sub_size] = asst;
-#else
- if (!subd) return;
-#endif
mpctx->set_of_subtitles[mpctx->set_of_sub_size] = subd;
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_FILE_SUB_ID=%d\n", mpctx->set_of_sub_size);
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_FILE_SUB_FILENAME=%s\n",
filename_recode(filename));
++mpctx->set_of_sub_size;
- mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_AddedSubtitleFile, mpctx->set_of_sub_size,
+ mp_tmsg(MSGT_CPLAYER, MSGL_INFO, "SUB: Added subtitle file (%d): %s\n", mpctx->set_of_sub_size,
filename_recode(filename));
}
-// FIXME: if/when the GUI calls this, global sub numbering gets (potentially) broken.
-void update_set_of_subtitles(void)
- // subdata was changed, set_of_sub... have to be updated.
+void init_vo_spudec(struct MPContext *mpctx)
{
- sub_data ** const set_of_subtitles = mpctx->set_of_subtitles;
- int i;
- if (mpctx->set_of_sub_size > 0 && subdata == NULL) { // *subdata was deleted
- for (i = mpctx->set_of_sub_pos + 1; i < mpctx->set_of_sub_size; ++i)
- set_of_subtitles[i-1] = set_of_subtitles[i];
- set_of_subtitles[mpctx->set_of_sub_size-1] = NULL;
- --mpctx->set_of_sub_size;
- if (mpctx->set_of_sub_size > 0) subdata = set_of_subtitles[mpctx->set_of_sub_pos=0];
- }
- else if (mpctx->set_of_sub_size > 0 && subdata != NULL) { // *subdata was changed
- set_of_subtitles[mpctx->set_of_sub_pos] = subdata;
- }
- else if (mpctx->set_of_sub_size <= 0 && subdata != NULL) { // *subdata was added
- set_of_subtitles[mpctx->set_of_sub_pos=mpctx->set_of_sub_size] = subdata;
- ++mpctx->set_of_sub_size;
- }
-}
-
-void init_vo_spudec(void) {
if (vo_spudec)
spudec_free(vo_spudec);
- initialized_flags &= ~INITIALIZED_SPUDEC;
+ mpctx->initialized_flags &= ~INITIALIZED_SPUDEC;
vo_spudec = NULL;
// we currently can't work without video stream
@@ -1166,7 +1193,7 @@ void init_vo_spudec(void) {
}
if (vo_spudec!=NULL) {
- initialized_flags|=INITIALIZED_SPUDEC;
+ mpctx->initialized_flags|=INITIALIZED_SPUDEC;
mp_property_do("sub_forced_only", M_PROPERTY_SET, &forced_subs_only, mpctx);
}
}
@@ -1227,15 +1254,27 @@ static void sadd_hhmmssf(char *buf, unsigned *pos, int len, float time) {
saddf(buf, pos, len, "%02d.%1d", ss, f1);
}
-/**
- * \brief print the status line
- * \param a_pos audio position
- * \param a_v A-V desynchronization
- * \param corr amount out A-V synchronization
- */
-static void print_status(float a_pos, float a_v, float corr)
+static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame)
{
+ struct MPOpts *opts = &mpctx->opts;
sh_video_t * const sh_video = mpctx->sh_video;
+
+ if (mpctx->sh_audio && a_pos == MP_NOPTS_VALUE)
+ a_pos = playing_audio_pts(mpctx);
+ if (mpctx->sh_audio && sh_video && at_frame) {
+ mpctx->last_av_difference = a_pos - sh_video->pts - audio_delay;
+ if (mpctx->time_frame > 0)
+ mpctx->last_av_difference += mpctx->time_frame * opts->playback_speed;
+ if (mpctx->last_av_difference > 0.5 && drop_frame_cnt > 50
+ && !mpctx->drop_message_shown) {
+ mp_tmsg(MSGT_AVSYNC,MSGL_WARN,SystemTooSlow);
+ mpctx->drop_message_shown = true;
+ }
+ }
+ if (quiet)
+ return;
+
+
int width;
char *line;
unsigned pos = 0;
@@ -1270,7 +1309,8 @@ static void print_status(float a_pos, float a_v, float corr)
// A-V sync
if (mpctx->sh_audio && sh_video)
- saddf(line, &pos, width, "A-V:%7.3f ct:%7.3f ", a_v, corr);
+ saddf(line, &pos, width, "A-V:%7.3f ct:%7.3f ",
+ mpctx->last_av_difference, mpctx->total_avsync_change);
// Video stats
if (sh_video)
@@ -1282,9 +1322,9 @@ static void print_status(float a_pos, float a_v, float corr)
if (sh_video) {
if (sh_video->timer > 0.5)
saddf(line, &pos, width, "%2d%% %2d%% %4.1f%% ",
- (int)(100.0*video_time_usage*playback_speed/(double)sh_video->timer),
- (int)(100.0*vout_time_usage*playback_speed/(double)sh_video->timer),
- (100.0*audio_time_usage*playback_speed/(double)sh_video->timer));
+ (int)(100.0*video_time_usage*opts->playback_speed/(double)sh_video->timer),
+ (int)(100.0*vout_time_usage*opts->playback_speed/(double)sh_video->timer),
+ (100.0*audio_time_usage*opts->playback_speed/(double)sh_video->timer));
else
saddf(line, &pos, width, "??%% ??%% ??,?%% ");
} else if (mpctx->sh_audio) {
@@ -1306,8 +1346,8 @@ static void print_status(float a_pos, float a_v, float corr)
#endif
// other
- if (playback_speed != 1)
- saddf(line, &pos, width, "%4.2fx ", playback_speed);
+ if (opts->playback_speed != 1)
+ saddf(line, &pos, width, "%4.2fx ", opts->playback_speed);
// end
if (erase_to_end_of_line) {
@@ -1327,39 +1367,34 @@ static void print_status(float a_pos, float a_v, float corr)
* \param sh_audio describes the requested input format of the chain.
* \param ao_data describes the requested output format of the chain.
*/
-int build_afilter_chain(sh_audio_t *sh_audio, ao_data_t *ao_data)
+int build_afilter_chain(struct MPContext *mpctx, sh_audio_t *sh_audio, ao_data_t *ao_data)
{
+ struct MPOpts *opts = &mpctx->opts;
int new_srate;
int result;
if (!sh_audio)
{
-#ifdef CONFIG_GUI
- if (use_gui) guiGetEvent(guiSetAfilter, (char *)NULL);
-#endif
mpctx->mixer.afilter = NULL;
return 0;
}
if(af_control_any_rev(sh_audio->afilter,
AF_CONTROL_PLAYBACK_SPEED | AF_CONTROL_SET,
- &playback_speed)) {
+ &opts->playback_speed)) {
new_srate = sh_audio->samplerate;
} else {
- new_srate = sh_audio->samplerate * playback_speed;
+ new_srate = sh_audio->samplerate * opts->playback_speed;
if (new_srate != ao_data->samplerate) {
// limits are taken from libaf/af_resample.c
if (new_srate < 8000)
new_srate = 8000;
if (new_srate > 192000)
new_srate = 192000;
- playback_speed = (float)new_srate / (float)sh_audio->samplerate;
+ opts->playback_speed = (float)new_srate / (float)sh_audio->samplerate;
}
}
result = init_audio_filters(sh_audio, new_srate,
&ao_data->samplerate, &ao_data->channels, &ao_data->format);
mpctx->mixer.afilter = sh_audio->afilter;
-#ifdef CONFIG_GUI
- if (use_gui) guiGetEvent(guiSetAfilter, (char *)sh_audio->afilter);
-#endif
return result;
}
@@ -1385,10 +1420,10 @@ static mp_osd_msg_t* osd_msg_stack = NULL;
* it is pulled on top of the stack, otherwise a new message is created.
*
*/
-
-void set_osd_msg(int id, int level, int time, const char* fmt, ...) {
+static void set_osd_msg_va(int id, int level, int time, const char *fmt,
+ va_list ap)
+{
mp_osd_msg_t *msg,*last=NULL;
- va_list va;
int r;
// look if the id is already in the stack
@@ -1405,9 +1440,7 @@ void set_osd_msg(int id, int level, int time, const char* fmt, ...) {
osd_msg_stack = msg;
}
// write the msg
- va_start(va,fmt);
- r = vsnprintf(msg->msg, 128, fmt, va);
- va_end(va);
+ r = vsnprintf(msg->msg, 128, fmt, ap);
if(r >= 128) msg->msg[127] = 0;
// set id and time
msg->id = id;
@@ -1416,6 +1449,23 @@ void set_osd_msg(int id, int level, int time, const char* fmt, ...) {
}
+void set_osd_msg(int id, int level, int time, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ set_osd_msg_va(id, level, time, fmt, ap);
+ va_end(ap);
+}
+
+void set_osd_tmsg(int id, int level, int time, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ set_osd_msg_va(id, level, time, mp_gtext(fmt), ap);
+ va_end(ap);
+}
+
+
/**
* \brief Remove a message from the OSD stack
*
@@ -1462,24 +1512,27 @@ static void clear_osd_msgs(void) {
*
*/
-static mp_osd_msg_t* get_osd_msg(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);
- if (mpctx->osd_function != OSD_PAUSE)
- mpctx->osd_function = OSD_PLAY;
+ 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;
@@ -1489,14 +1542,16 @@ static mp_osd_msg_t* get_osd_msg(void) {
// 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;
}
@@ -1521,26 +1576,28 @@ static mp_osd_msg_t* get_osd_msg(void) {
*
*/
-void set_osd_bar(int type,const char* name,double min,double max,double val) {
-
- if(osd_level < 1) return;
+void set_osd_bar(struct MPContext *mpctx, int type,const char* name,double min,double max,double val) {
+ 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)));
}
/**
* \brief Display text subtitles on the OSD
*/
-void set_osd_subtitle(subtitle *subs) {
+void set_osd_subtitle(struct MPContext *mpctx, subtitle *subs)
+{
int i;
vo_sub = subs;
vo_osd_changed(OSDTYPE_SUBTITLE);
@@ -1567,18 +1624,30 @@ void set_osd_subtitle(subtitle *subs) {
*
*/
-static void update_osd_msg(void) {
+static void update_osd_msg(struct MPContext *mpctx)
+{
+ struct MPOpts *opts = &mpctx->opts;
mp_osd_msg_t *msg;
- static char osd_text[128] = "";
- static char osd_text_timer[128];
-
- // we need some mem for vo_osd_text
- vo_osd_text = (unsigned char*)osd_text;
+ 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())) {
- if(strcmp(osd_text,msg->msg)) {
- strncpy((char*)osd_text, msg->msg, 127);
+ if((msg = get_osd_msg(mpctx))) {
+ if (strcmp(osd->osd_text, msg->msg)) {
+ strncpy(osd->osd_text, msg->msg, 127);
if(mpctx->sh_video) vo_osd_changed(OSDTYPE_OSD); else
if(term_osd) mp_msg(MSGT_CPLAYER,MSGL_STATUS,"%s%s\n",term_osd_esc,msg->msg);
}
@@ -1587,21 +1656,30 @@ static void update_osd_msg(void) {
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,
@@ -1613,20 +1691,16 @@ static void update_osd_msg(void) {
} else
osd_text_timer[0]=0;
- // always decrement the percentage timer
- if(mpctx->osd_show_percentage)
- mpctx->osd_show_percentage--;
-
- if(strcmp(osd_text,osd_text_timer)) {
- strncpy(osd_text, osd_text_timer, 63);
+ if (strcmp(osd->osd_text, osd_text_timer)) {
+ strncpy(osd->osd_text, osd_text_timer, 63);
vo_osd_changed(OSDTYPE_OSD);
}
return;
}
// Clear the term osd line
- if(term_osd && osd_text[0]) {
- osd_text[0] = 0;
+ if (term_osd && osd->osd_text[0]) {
+ osd->osd_text[0] = 0;
printf("%s\n",term_osd_esc);
}
}
@@ -1635,7 +1709,9 @@ static void update_osd_msg(void) {
// OSDMsgStack
-void reinit_audio_chain(void) {
+void reinit_audio_chain(struct MPContext *mpctx)
+{
+ struct MPOpts *opts = &mpctx->opts;
if (!mpctx->sh_audio)
return;
current_module="init_audio_codec";
@@ -1643,7 +1719,7 @@ void reinit_audio_chain(void) {
if(!init_best_audio_codec(mpctx->sh_audio,audio_codec_list,audio_fm_list)){
goto init_error;
}
- initialized_flags|=INITIALIZED_ACODEC;
+ mpctx->initialized_flags|=INITIALIZED_ACODEC;
mp_msg(MSGT_CPLAYER,MSGL_INFO,"==========================================================================\n");
@@ -1657,20 +1733,21 @@ void reinit_audio_chain(void) {
mpctx->sh_audio->samplerate,
// output:
&ao_data.samplerate, &ao_data.channels, &ao_data.format)){
- mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_AudioFilterChainPreinitError);
- exit_player(EXIT_ERROR);
+ mp_tmsg(MSGT_CPLAYER,MSGL_ERR, "Error at audio filter chain "
+ "pre-init!\n");
+ exit_player(mpctx, EXIT_ERROR);
}
current_module="ao2_init";
- mpctx->audio_out = init_best_audio_out(audio_driver_list,
+ mpctx->audio_out = init_best_audio_out(opts->audio_driver_list,
0, // plugin flag
ao_data.samplerate,
ao_data.channels,
ao_data.format, 0);
if(!mpctx->audio_out){
- mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_CannotInitAO);
+ mp_tmsg(MSGT_CPLAYER,MSGL_ERR,"Could not open/initialize audio device -> no sound.\n");
goto init_error;
}
- initialized_flags|=INITIALIZED_AO;
+ mpctx->initialized_flags|=INITIALIZED_AO;
mp_msg(MSGT_CPLAYER,MSGL_INFO,"AO: [%s] %dHz %dch %s (%d bytes per sample)\n",
mpctx->audio_out->info->short_name,
ao_data.samplerate, ao_data.channels,
@@ -1682,8 +1759,8 @@ void reinit_audio_chain(void) {
mp_msg(MSGT_CPLAYER,MSGL_V,"AO: Comment: %s\n", mpctx->audio_out->info->comment);
// init audio filters:
current_module="af_init";
- if(!build_afilter_chain(mpctx->sh_audio, &ao_data)) {
- mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_NoMatchingFilter);
+ if(!build_afilter_chain(mpctx, mpctx->sh_audio, &ao_data)) {
+ mp_tmsg(MSGT_CPLAYER,MSGL_ERR,"Couldn't find matching filter/ao format!\n");
goto init_error;
}
mpctx->mixer.audio_out = mpctx->audio_out;
@@ -1691,7 +1768,7 @@ void reinit_audio_chain(void) {
return;
init_error:
- uninit_player(INITIALIZED_ACODEC|INITIALIZED_AO); // close codec and possibly AO
+ uninit_player(mpctx, INITIALIZED_ACODEC|INITIALIZED_AO); // close codec and possibly AO
mpctx->sh_audio=mpctx->d_audio->sh=NULL; // -> nosound
mpctx->d_audio->id = -2;
}
@@ -1703,8 +1780,10 @@ init_error:
// Return pts value corresponding to the end point of audio written to the
// ao so far.
-static double written_audio_pts(sh_audio_t *sh_audio, demux_stream_t *d_audio)
+static double written_audio_pts(struct MPContext *mpctx)
{
+ sh_audio_t *sh_audio = mpctx->sh_audio;
+ demux_stream_t *d_audio = mpctx->d_audio;
double buffered_output;
// first calculate the end pts of audio that has been output by decoder
double a_pts = sh_audio->pts;
@@ -1747,31 +1826,31 @@ static double written_audio_pts(sh_audio_t *sh_audio, demux_stream_t *d_audio)
// Filters divide audio length by playback_speed, so multiply by it
// to get the length in original units without speedup or slowdown
- a_pts -= buffered_output * playback_speed / ao_data.bps;
+ 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.
-double playing_audio_pts(sh_audio_t *sh_audio, demux_stream_t *d_audio,
- const ao_functions_t *audio_out)
+double playing_audio_pts(struct MPContext *mpctx)
{
- return written_audio_pts(sh_audio, d_audio) - playback_speed *
- audio_out->get_delay();
+ return written_audio_pts(mpctx) - mpctx->opts.playback_speed *
+ mpctx->audio_out->get_delay();
}
-static int check_framedrop(double frame_time) {
+static int check_framedrop(struct MPContext *mpctx, double frame_time) {
+ struct MPOpts *opts = &mpctx->opts;
// check for frame-drop:
current_module = "check_framedrop";
if (mpctx->sh_audio && !mpctx->d_audio->eof) {
static int dropped_frames;
- float delay = playback_speed*mpctx->audio_out->get_delay();
+ float delay = opts->playback_speed*mpctx->audio_out->get_delay();
float d = delay-mpctx->delay;
++total_frame_cnt;
// we should avoid dropping too many frames in sequence unless we
// are too late. and we allow 100ms A-V delay here:
- if (d < -dropped_frames*frame_time-0.100 &&
- mpctx->osd_function != OSD_PAUSE) {
+ if (d < -dropped_frames*frame_time-0.100 && !mpctx->paused
+ && !mpctx->update_video_immediately) {
++drop_frame_cnt;
++dropped_frames;
return frame_dropping;
@@ -1781,53 +1860,12 @@ static int check_framedrop(double frame_time) {
return 0;
}
-static int generate_video_frame(sh_video_t *sh_video, demux_stream_t *d_video)
-{
- unsigned char *start;
- int in_size;
- int hit_eof=0;
- double pts;
-
- while (1) {
- int drop_frame = check_framedrop(sh_video->frametime);
- void *decoded_frame;
- current_module = "decode video";
- // XXX Time used in this call is not counted in any performance
- // timer now, OSD is not updated correctly for filter-added frames
- if (vf_output_queued_frame(sh_video->vfilter))
- break;
- current_module = "video_read_frame";
- in_size = ds_get_packet_pts(d_video, &start, &pts);
- if (in_size < 0) {
- // try to extract last frames in case of decoder lag
- in_size = 0;
- pts = 1e300;
- hit_eof = 1;
- }
- if (in_size > max_framesize)
- max_framesize = in_size;
- current_module = "decode video";
- decoded_frame = decode_video(sh_video, start, in_size, drop_frame, pts);
- if (decoded_frame) {
- update_subtitles(sh_video, sh_video->pts, mpctx->d_sub, 0);
- update_teletext(sh_video, mpctx->demuxer, 0);
- update_osd_msg();
- current_module = "filter video";
- if (filter_video(sh_video, decoded_frame, sh_video->pts))
- break;
- } else if (drop_frame)
- return -1;
- if (hit_eof)
- return 0;
- }
- return 1;
-}
#ifdef HAVE_RTC
int rtc_fd = -1;
#endif
-static float timing_sleep(float time_frame)
+static float timing_sleep(struct MPContext *mpctx, float time_frame)
{
#ifdef HAVE_RTC
if (rtc_fd >= 0){
@@ -1836,8 +1874,8 @@ static float timing_sleep(float time_frame)
while (time_frame > 0.000) {
unsigned long rtc_ts;
if (read(rtc_fd, &rtc_ts, sizeof(rtc_ts)) <= 0)
- mp_msg(MSGT_CPLAYER, MSGL_ERR, MSGTR_LinuxRTCReadError, strerror(errno));
- time_frame -= GetRelativeTime();
+ mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "Linux RTC read error: %s\n", strerror(errno));
+ time_frame -= get_relative_time(mpctx);
}
} else
#endif
@@ -1848,40 +1886,42 @@ static float timing_sleep(float time_frame)
current_module = "sleep_timer";
while (time_frame > margin) {
usec_sleep(1000000 * (time_frame - margin));
- time_frame -= GetRelativeTime();
+ time_frame -= get_relative_time(mpctx);
}
if (softsleep){
current_module = "sleep_soft";
if (time_frame < 0)
- mp_msg(MSGT_AVSYNC, MSGL_WARN, MSGTR_SoftsleepUnderflow);
+ mp_tmsg(MSGT_AVSYNC, MSGL_WARN, "Warning! Softsleep underflow!\n");
while (time_frame > 0)
- time_frame-=GetRelativeTime(); // burn the CPU
+ time_frame -= get_relative_time(mpctx); // burn the CPU
}
}
return time_frame;
}
-static void select_subtitle(MPContext *mpctx) {
+static void select_subtitle(MPContext *mpctx)
+{
+ struct MPOpts *opts = &mpctx->opts;
// find the best sub to use
int vobsub_index_id = vobsub_get_index_by_id(vo_vobsub, vobsub_id);
mpctx->global_sub_pos = -1; // no subs by default
if (vobsub_index_id >= 0) {
// if user asks for a vobsub id, use that first.
mpctx->global_sub_pos = mpctx->global_sub_indices[SUB_SOURCE_VOBSUB] + vobsub_index_id;
- } else if (dvdsub_id >= 0 && mpctx->global_sub_indices[SUB_SOURCE_DEMUX] >= 0) {
+ } else if (opts->sub_id >= 0 && mpctx->global_sub_indices[SUB_SOURCE_DEMUX] >= 0) {
// if user asks for a dvd sub id, use that next.
- mpctx->global_sub_pos = mpctx->global_sub_indices[SUB_SOURCE_DEMUX] + dvdsub_id;
+ mpctx->global_sub_pos = mpctx->global_sub_indices[SUB_SOURCE_DEMUX] + opts->sub_id;
} else if (mpctx->global_sub_indices[SUB_SOURCE_SUBS] >= 0) {
// if there are text subs to use, use those. (autosubs come last here)
mpctx->global_sub_pos = mpctx->global_sub_indices[SUB_SOURCE_SUBS];
- } else if (dvdsub_id == -1 && mpctx->global_sub_indices[SUB_SOURCE_DEMUX] >= 0) {
+ } else if (opts->sub_id == -1 && mpctx->global_sub_indices[SUB_SOURCE_DEMUX] >= 0) {
// finally select subs by language and container hints
- if (dvdsub_id == -1 && dvdsub_lang)
- dvdsub_id = demuxer_sub_track_by_lang(mpctx->demuxer, dvdsub_lang);
- if (dvdsub_id == -1)
- dvdsub_id = demuxer_default_sub_track(mpctx->demuxer);
- if (dvdsub_id >= 0)
- mpctx->global_sub_pos = mpctx->global_sub_indices[SUB_SOURCE_DEMUX] + dvdsub_id;
+ if (opts->sub_id == -1 && dvdsub_lang)
+ opts->sub_id = demuxer_sub_track_by_lang(mpctx->demuxer, dvdsub_lang);
+ if (opts->sub_id == -1)
+ opts->sub_id = demuxer_default_sub_track(mpctx->demuxer);
+ if (opts->sub_id >= 0)
+ mpctx->global_sub_pos = mpctx->global_sub_indices[SUB_SOURCE_DEMUX] + opts->sub_id;
}
// rather than duplicate code, use the SUB_SELECT handler to init the right one.
mpctx->global_sub_pos--;
@@ -1919,6 +1959,7 @@ static mp_image_t * mp_dvdnav_copy_mpi(mp_image_t *to_mpi,
}
static void mp_dvdnav_reset_stream (MPContext *ctx) {
+ struct MPOpts *opts = &ctx->opts;
if (ctx->sh_video) {
/// clear video pts
ctx->d_video->pts = 0.0f;
@@ -1944,11 +1985,11 @@ static void mp_dvdnav_reset_stream (MPContext *ctx) {
}
audio_delay = 0.0f;
- mpctx->global_sub_size = mpctx->global_sub_indices[SUB_SOURCE_DEMUX] + mp_dvdnav_number_of_subs(mpctx->stream);
- if (dvdsub_lang && dvdsub_id == dvdsub_lang_id) {
+ ctx->global_sub_size = ctx->global_sub_indices[SUB_SOURCE_DEMUX] + mp_dvdnav_number_of_subs(ctx->stream);
+ if (dvdsub_lang && opts->sub_id == dvdsub_lang_id) {
dvdsub_lang_id = mp_dvdnav_sid_from_lang(ctx->stream, dvdsub_lang);
- if (dvdsub_lang_id != dvdsub_id) {
- dvdsub_id = dvdsub_lang_id;
+ if (dvdsub_lang_id != opts->sub_id) {
+ opts->sub_id = dvdsub_lang_id;
select_subtitle(ctx);
}
}
@@ -1958,7 +1999,8 @@ static void mp_dvdnav_reset_stream (MPContext *ctx) {
}
/// Restore last decoded DVDNAV (still frame)
-static mp_image_t *mp_dvdnav_restore_smpi(int *in_size,
+static mp_image_t *mp_dvdnav_restore_smpi(struct MPContext *mpctx,
+ int *in_size,
unsigned char **start,
mp_image_t *decoded_frame)
{
@@ -2002,7 +2044,7 @@ static mp_image_t *mp_dvdnav_restore_smpi(int *in_size,
}
/// Save last decoded DVDNAV (still frame)
-static void mp_dvdnav_save_smpi(int in_size,
+static void mp_dvdnav_save_smpi(struct MPContext *mpctx, int in_size,
unsigned char *start,
mp_image_t *decoded_frame)
{
@@ -2023,78 +2065,48 @@ static void mp_dvdnav_save_smpi(int in_size,
}
#endif /* CONFIG_DVDNAV */
-static void adjust_sync_and_print_status(int between_frames, float timing_error)
+/* Modify video timing to match the audio timeline. There are two main
+ * reasons this is needed. First, video and audio can start from different
+ * positions at beginning of file or after a seek (MPlayer starts both
+ * immediately even if they have different pts). Second, the file can have
+ * audio timestamps that are inconsistent with the duration of the audio
+ * packets, for example two consecutive timestamp values differing by
+ * one second but only a packet with enough samples for half a second
+ * of playback between them.
+ */
+static void adjust_sync(struct MPContext *mpctx, double frame_time)
{
- current_module="av_sync";
-
- if(mpctx->sh_audio){
- double a_pts, v_pts;
-
- if (autosync)
- /*
- * If autosync is enabled, the value for delay must be calculated
- * a bit differently. It is set only to the difference between
- * the audio and video timers. Any attempt to include the real
- * or corrected delay causes the pts_correction code below to
- * try to correct for the changes in delay which autosync is
- * trying to measure. This keeps the two from competing, but still
- * allows the code to correct for PTS drift *only*. (Using a delay
- * value here, even a "corrected" one, would be incompatible with
- * autosync mode.)
- */
- a_pts = written_audio_pts(mpctx->sh_audio, mpctx->d_audio) - mpctx->delay;
- else
- a_pts = playing_audio_pts(mpctx->sh_audio, mpctx->d_audio, mpctx->audio_out);
-
- v_pts = mpctx->sh_video->pts;
+ current_module = "av_sync";
- {
- static int drop_message=0;
- double AV_delay = a_pts - audio_delay - v_pts;
- double x;
- if (AV_delay>0.5 && drop_frame_cnt>50 && drop_message==0){
- ++drop_message;
- mp_msg(MSGT_AVSYNC,MSGL_WARN,MSGTR_SystemTooSlow);
- }
- if (autosync)
- x = AV_delay*0.1f;
- else
- /* Do not correct target time for the next frame if this frame
- * was late not because of wrong target time but because the
- * target time could not be met */
- x = (AV_delay + timing_error * playback_speed) * 0.1f;
- if (x < -max_pts_correction)
- x = -max_pts_correction;
- else if (x> max_pts_correction)
- x = max_pts_correction;
- if (default_max_pts_correction >= 0)
- max_pts_correction = default_max_pts_correction;
- else
- max_pts_correction = mpctx->sh_video->frametime*0.10; // +-10% of time
- if (!between_frames) {
- mpctx->delay+=x;
- c_total+=x;
- }
- if(!quiet)
- print_status(a_pts - audio_delay, AV_delay, c_total);
- }
-
- } else {
- // No audio:
+ if (!mpctx->sh_audio)
+ return;
- if (!quiet)
- print_status(0, 0, 0);
- }
+ double a_pts = written_audio_pts(mpctx) - mpctx->delay;
+ double v_pts = mpctx->sh_video->pts;
+ double av_delay = a_pts - v_pts;
+ // Try to sync vo_flip() so it will *finish* at given time
+ av_delay += mpctx->last_vo_flip_duration;
+ av_delay -= audio_delay; // This much pts difference is desired
+
+ double change = av_delay * 0.1;
+ double max_change = default_max_pts_correction >= 0 ?
+ default_max_pts_correction : frame_time * 0.1;
+ if (change < -max_change)
+ change = -max_change;
+ else if (change > max_change)
+ change = max_change;
+ mpctx->delay += change;
+ mpctx->total_avsync_change += change;
}
-static int fill_audio_out_buffers(void)
+static int fill_audio_out_buffers(struct MPContext *mpctx)
{
+ struct MPOpts *opts = &mpctx->opts;
unsigned int t;
double tt;
int playsize;
int playflags=0;
int audio_eof=0;
- int bytes_to_write;
sh_audio_t * const sh_audio = mpctx->sh_audio;
current_module="play_audio";
@@ -2105,74 +2117,70 @@ static int fill_audio_out_buffers(void)
// sync completely wrong; there should be no need to use ao_data.pts
// in get_space()
ao_data.pts = ((mpctx->sh_video?mpctx->sh_video->timer:0)+mpctx->delay)*90000.0;
- bytes_to_write = mpctx->audio_out->get_space();
- if (mpctx->sh_video || bytes_to_write >= ao_data.outburst)
+ playsize = mpctx->audio_out->get_space();
+ if (mpctx->sh_video || playsize >= ao_data.outburst)
break;
// handle audio-only case:
// this is where mplayer sleeps during audio-only playback
// to avoid 100% CPU use
- sleep_time = (ao_data.outburst - bytes_to_write) * 1000 / ao_data.bps;
+ sleep_time = (ao_data.outburst - playsize) * 1000 / ao_data.bps;
if (sleep_time < 10) sleep_time = 10; // limit to 100 wakeups per second
usec_sleep(sleep_time * 1000);
}
- while (bytes_to_write) {
- playsize = bytes_to_write;
- if (playsize > MAX_OUTBURST)
- playsize = MAX_OUTBURST;
- bytes_to_write -= playsize;
-
- // Fill buffer if needed:
- current_module="decode_audio";
- t = GetTimer();
- if (decode_audio(sh_audio, playsize) < 0) // EOF or error
- if (mpctx->d_audio->eof) {
- audio_eof = 1;
- if (sh_audio->a_out_buffer_len == 0)
- return 0;
- }
- t = GetTimer() - t;
- tt = t*0.000001f; audio_time_usage+=tt;
- if (playsize > sh_audio->a_out_buffer_len) {
- playsize = sh_audio->a_out_buffer_len;
- if (audio_eof)
- playflags |= AOPLAY_FINAL_CHUNK;
- }
- if (!playsize)
- break;
-
- // play audio:
- current_module="play_audio";
+ // Fill buffer if needed:
+ current_module="decode_audio";
+ t = GetTimer();
+ if (decode_audio(sh_audio, playsize) < 0) // EOF or error
+ if (mpctx->d_audio->eof) {
+ audio_eof = 1;
+ if (sh_audio->a_out_buffer_len == 0)
+ return 0;
+ }
+ t = GetTimer() - t;
+ tt = t*0.000001f; audio_time_usage+=tt;
+ if (playsize > sh_audio->a_out_buffer_len) {
+ playsize = sh_audio->a_out_buffer_len;
+ if (audio_eof)
+ playflags |= AOPLAY_FINAL_CHUNK;
+ }
+ if (!playsize)
+ return 1;
- // Is this pts value actually useful for the aos that access it?
- // They're obviously badly broken in the way they handle av sync;
- // would not having access to this make them more broken?
- ao_data.pts = ((mpctx->sh_video?mpctx->sh_video->timer:0)+mpctx->delay)*90000.0;
- playsize = mpctx->audio_out->play(sh_audio->a_out_buffer, playsize, playflags);
+ // play audio:
+ current_module="play_audio";
- if (playsize > 0) {
- sh_audio->a_out_buffer_len -= playsize;
- memmove(sh_audio->a_out_buffer, &sh_audio->a_out_buffer[playsize],
- sh_audio->a_out_buffer_len);
- mpctx->delay += playback_speed*playsize/(double)ao_data.bps;
- }
- else if (audio_eof && mpctx->audio_out->get_delay() < .04) {
- // Sanity check to avoid hanging in case current ao doesn't output
- // partial chunks and doesn't check for AOPLAY_FINAL_CHUNK
- mp_msg(MSGT_CPLAYER, MSGL_WARN, "Audio output truncated at end.\n");
- sh_audio->a_out_buffer_len = 0;
- }
+ // Is this pts value actually useful for the aos that access it?
+ // They're obviously badly broken in the way they handle av sync;
+ // would not having access to this make them more broken?
+ ao_data.pts = ((mpctx->sh_video?mpctx->sh_video->timer:0)+mpctx->delay)*90000.0;
+ playsize = mpctx->audio_out->play(sh_audio->a_out_buffer, playsize, playflags);
+
+ if (playsize > 0) {
+ sh_audio->a_out_buffer_len -= playsize;
+ memmove(sh_audio->a_out_buffer, &sh_audio->a_out_buffer[playsize],
+ sh_audio->a_out_buffer_len);
+ mpctx->delay += opts->playback_speed*playsize/(double)ao_data.bps;
}
+ else if (audio_eof && mpctx->audio_out->get_delay() < .04) {
+ // Sanity check to avoid hanging in case current ao doesn't output
+ // partial chunks and doesn't check for AOPLAY_FINAL_CHUNK
+ mp_msg(MSGT_CPLAYER, MSGL_WARN, "Audio output truncated at end.\n");
+ sh_audio->a_out_buffer_len = 0;
+ }
+
return 1;
}
-static int sleep_until_update(float *time_frame, float *aq_sleep_time)
+static int sleep_until_update(struct MPContext *mpctx, float *time_frame,
+ float *aq_sleep_time)
{
+ struct MPOpts *opts = &mpctx->opts;
int frame_time_remaining = 0;
current_module="calc_sleep_time";
- *time_frame -= GetRelativeTime(); // reset timer
+ *time_frame -= get_relative_time(mpctx); // reset timer
if (mpctx->sh_audio && !mpctx->d_audio->eof) {
float delay = mpctx->audio_out->get_delay();
@@ -2188,12 +2196,12 @@ static int sleep_until_update(float *time_frame, float *aq_sleep_time)
* sync to settle at the right value (but it eventually will.)
* This settling time is very short for values below 100.
*/
- float predicted = mpctx->delay / playback_speed + *time_frame;
+ float predicted = mpctx->delay / opts->playback_speed + *time_frame;
float difference = delay - predicted;
delay = predicted + difference / (float)autosync;
}
- *time_frame = delay - mpctx->delay / playback_speed;
+ *time_frame = delay - mpctx->delay / opts->playback_speed;
// delay = amount of audio buffered in soundcard/driver
if (delay > 0.25) delay=0.25; else
@@ -2217,27 +2225,30 @@ static int sleep_until_update(float *time_frame, float *aq_sleep_time)
//============================== SLEEP: ===================================
+ *time_frame -= mpctx->video_out->flip_queue_offset;
// flag 256 means: libvo driver does its timing (dvb card)
- if (*time_frame > 0.001 && !(vo_flags&256))
- *time_frame = timing_sleep(*time_frame);
+ if (*time_frame > 0.001 && !(mpctx->sh_video->output_flags&256))
+ *time_frame = timing_sleep(mpctx, *time_frame);
+ *time_frame += mpctx->video_out->flip_queue_offset;
return frame_time_remaining;
}
-int reinit_video_chain(void) {
+int reinit_video_chain(struct MPContext *mpctx)
+{
+ struct MPOpts *opts = &mpctx->opts;
sh_video_t * const sh_video = mpctx->sh_video;
double ar=-1.0;
//================== Init VIDEO (codec & libvo) ==========================
- if(!fixed_vo || !(initialized_flags&INITIALIZED_VO)){
+ if (!opts->fixed_vo || !(mpctx->initialized_flags & INITIALIZED_VO)) {
current_module="preinit_libvo";
//shouldn't we set dvideo->id=-2 when we fail?
- vo_config_count=0;
//if((mpctx->video_out->preinit(vo_subdevice))!=0){
- if(!(mpctx->video_out=init_best_video_out(video_driver_list))){
- mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_ErrorInitializingVODevice);
+ if(!(mpctx->video_out=init_best_video_out(opts, mpctx->x11_state, mpctx->key_fifo, mpctx->input))){
+ mp_tmsg(MSGT_CPLAYER,MSGL_FATAL,"Error opening/initializing the selected video_out (-vo) device.\n");
goto err_out;
}
- initialized_flags|=INITIALIZED_VO;
+ mpctx->initialized_flags|=INITIALIZED_VO;
}
if(stream_control(mpctx->demuxer->stream, STREAM_CTRL_GET_ASPECT_RATIO, &ar) != STREAM_UNSUPPORTED)
@@ -2245,28 +2256,28 @@ int reinit_video_chain(void) {
current_module="init_video_filters";
{
char* vf_arg[] = { "_oldargs_", (char*)mpctx->video_out , NULL };
- sh_video->vfilter=(void*)vf_open_filter(NULL,"vo",vf_arg);
+ sh_video->vfilter = vf_open_filter(opts, NULL,"vo",vf_arg);
}
#ifdef CONFIG_MENU
if(use_menu) {
char* vf_arg[] = { "_oldargs_", menu_root, NULL };
- vf_menu = vf_open_plugin(libmenu_vfs,sh_video->vfilter,"menu",vf_arg);
+ vf_menu = vf_open_plugin(opts,libmenu_vfs,sh_video->vfilter,"menu",vf_arg);
if(!vf_menu) {
- mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_CantOpenLibmenuFilterWithThisRootMenu,menu_root);
+ mp_tmsg(MSGT_CPLAYER,MSGL_ERR,"Can't open libmenu video filter with root menu %s.\n",menu_root);
use_menu = 0;
}
}
if(vf_menu)
- sh_video->vfilter=(void*)vf_menu;
+ sh_video->vfilter = vf_menu;
#endif
#ifdef CONFIG_ASS
- if(ass_enabled) {
+ if(opts->ass_enabled) {
int i;
int insert = 1;
- if (vf_settings)
- for (i = 0; vf_settings[i].name; ++i)
- if (strcmp(vf_settings[i].name, "ass") == 0) {
+ if (opts->vf_settings)
+ for (i = 0; opts->vf_settings[i].name; ++i)
+ if (strcmp(opts->vf_settings[i].name, "ass") == 0) {
insert = 0;
break;
}
@@ -2274,20 +2285,26 @@ int reinit_video_chain(void) {
extern vf_info_t vf_info_ass;
const vf_info_t* libass_vfs[] = {&vf_info_ass, NULL};
char* vf_arg[] = {"auto", "1", NULL};
- vf_instance_t* vf_ass = vf_open_plugin(libass_vfs,sh_video->vfilter,"ass",vf_arg);
+ int retcode = 0;
+ struct vf_instance *vf_ass = vf_open_plugin_noerr(opts, libass_vfs,
+ sh_video->vfilter,
+ "ass", vf_arg,
+ &retcode);
if (vf_ass)
- sh_video->vfilter=(void*)vf_ass;
+ sh_video->vfilter = vf_ass;
+ else if (retcode == -1) // vf_ass open() returns -1 if there's VO EOSD
+ mp_msg(MSGT_CPLAYER, MSGL_V, "[ass] vf_ass not needed\n");
else
mp_msg(MSGT_CPLAYER,MSGL_ERR, "ASS: cannot add video filter\n");
}
}
#endif
- sh_video->vfilter=(void*)append_filters(sh_video->vfilter);
+ sh_video->vfilter = append_filters(sh_video->vfilter, opts->vf_settings);
#ifdef CONFIG_ASS
- if (ass_enabled)
- ((vf_instance_t *)sh_video->vfilter)->control(sh_video->vfilter, VFCTRL_INIT_EOSD, ass_library);
+ if (opts->ass_enabled)
+ sh_video->vfilter->control(sh_video->vfilter, VFCTRL_INIT_EOSD, ass_library);
#endif
current_module="init_video_codec";
@@ -2297,11 +2314,11 @@ int reinit_video_chain(void) {
mp_msg(MSGT_CPLAYER,MSGL_INFO,"==========================================================================\n");
if(!sh_video->initialized){
- if(!fixed_vo) uninit_player(INITIALIZED_VO);
+ if(!opts->fixed_vo) uninit_player(mpctx, INITIALIZED_VO);
goto err_out;
}
- initialized_flags|=INITIALIZED_VCODEC;
+ mpctx->initialized_flags|=INITIALIZED_VCODEC;
if (sh_video->codec)
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_CODEC=%s\n", sh_video->codec->name);
@@ -2330,158 +2347,254 @@ err_out:
return 0;
}
-static double update_video(int *blit_frame)
+static double update_video_nocorrect_pts(struct MPContext *mpctx)
{
- sh_video_t * const sh_video = mpctx->sh_video;
- //-------------------- Decode a frame: -----------------------
- double frame_time;
- *blit_frame = 0; // Don't blit if we hit EOF
- if (!correct_pts) {
- unsigned char* start=NULL;
- void *decoded_frame = NULL;
- int drop_frame=0;
- int in_size;
-
- current_module = "video_read_frame";
- frame_time = sh_video->next_frame_time;
- in_size = video_read_frame(sh_video, &sh_video->next_frame_time,
- &start, force_fps);
+ struct sh_video *sh_video = mpctx->sh_video;
+ double frame_time = 0;
+ struct vo *video_out = mpctx->video_out;
+ while (!video_out->frame_loaded) {
+ current_module = "filter_video";
+ // In nocorrect-pts mode there is no way to properly time these frames
+ if (vo_get_buffered_frame(video_out, 0) >= 0)
+ break;
+ if (vf_output_queued_frame(sh_video->vfilter))
+ continue;
+ unsigned char *packet = NULL;
+ frame_time = sh_video->next_frame_time;
+ if (mpctx->update_video_immediately)
+ frame_time = 0;
+ int in_size = video_read_frame(sh_video, &sh_video->next_frame_time,
+ &packet, force_fps);
+ if (in_size < 0) {
#ifdef CONFIG_DVDNAV
- /// wait, still frame or EOF
- if (mpctx->stream->type == STREAMTYPE_DVDNAV && in_size < 0) {
- if (mp_dvdnav_is_eof(mpctx->stream)) return -1;
- if (mpctx->d_video) mpctx->d_video->eof = 0;
- if (mpctx->d_audio) mpctx->d_audio->eof = 0;
- mpctx->stream->eof = 0;
- } else
+ if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
+ if (mp_dvdnav_is_eof(mpctx->stream))
+ return -1;
+ if (mpctx->d_video)
+ mpctx->d_video->eof = 0;
+ if (mpctx->d_audio)
+ mpctx->d_audio->eof = 0;
+ mpctx->stream->eof = 0;
+ } else
#endif
- if (in_size < 0)
- return -1;
- if (in_size > max_framesize)
- max_framesize = in_size; // stats
- sh_video->timer += frame_time;
- if (mpctx->sh_audio)
- mpctx->delay -= frame_time;
- // video_read_frame can change fps (e.g. for ASF video)
- vo_fps = sh_video->fps;
- drop_frame = check_framedrop(frame_time);
- update_subtitles(sh_video, sh_video->pts, mpctx->d_sub, 0);
- update_teletext(sh_video, mpctx->demuxer, 0);
- update_osd_msg();
- current_module = "decode_video";
+ return -1;
+ }
+ if (in_size > max_framesize)
+ max_framesize = in_size;
+ sh_video->timer += frame_time;
+ if (mpctx->sh_audio)
+ mpctx->delay -= frame_time;
+ // video_read_frame can change fps (e.g. for ASF video)
+ vo_fps = sh_video->fps;
+ int framedrop_type = check_framedrop(mpctx, frame_time);
+ current_module = "decode video";
+
+ void *decoded_frame;
#ifdef CONFIG_DVDNAV
- decoded_frame = mp_dvdnav_restore_smpi(&in_size,&start,decoded_frame);
- /// still frame has been reached, no need to decode
- if (in_size > 0 && !decoded_frame)
+ decoded_frame = mp_dvdnav_restore_smpi(mpctx, &in_size, &packet, NULL);
+ if (in_size >= 0 && !decoded_frame)
#endif
- decoded_frame = decode_video(sh_video, start, in_size, drop_frame,
- sh_video->pts);
+ decoded_frame = decode_video(sh_video, packet, in_size, framedrop_type,
+ sh_video->pts);
#ifdef CONFIG_DVDNAV
- /// save back last still frame for future display
- mp_dvdnav_save_smpi(in_size,start,decoded_frame);
+ // Save last still frame for future display
+ mp_dvdnav_save_smpi(mpctx, in_size, packet, decoded_frame);
#endif
- current_module = "filter_video";
- *blit_frame = (decoded_frame && filter_video(sh_video, decoded_frame,
- sh_video->pts));
+ if (decoded_frame) {
+ current_module = "filter video";
+ if (filter_video(sh_video, decoded_frame, sh_video->pts))
+ if (!video_out->config_ok)
+ break;
+ }
}
- else {
- int res = generate_video_frame(sh_video, mpctx->d_video);
- if (!res)
- return -1;
- ((vf_instance_t *)sh_video->vfilter)->control(sh_video->vfilter,
- VFCTRL_GET_PTS, &sh_video->pts);
- if (sh_video->pts == MP_NOPTS_VALUE) {
- mp_msg(MSGT_CPLAYER, MSGL_ERR, "pts after filters MISSING\n");
- sh_video->pts = sh_video->last_pts;
- }
- if (sh_video->last_pts == MP_NOPTS_VALUE)
- sh_video->last_pts= sh_video->pts;
- else if (sh_video->last_pts > sh_video->pts) {
- sh_video->last_pts = sh_video->pts;
- mp_msg(MSGT_CPLAYER, MSGL_INFO, "pts value < previous\n");
- }
- frame_time = sh_video->pts - sh_video->last_pts;
- sh_video->last_pts = sh_video->pts;
- sh_video->timer += frame_time;
- if(mpctx->sh_audio)
- mpctx->delay -= frame_time;
- *blit_frame = res > 0;
+ return frame_time;
+}
+
+static void determine_frame_pts(struct MPContext *mpctx)
+{
+ struct sh_video *sh_video = mpctx->sh_video;
+ struct MPOpts *opts = &mpctx->opts;
+
+ if (opts->user_pts_assoc_mode) {
+ sh_video->pts_assoc_mode = opts->user_pts_assoc_mode;
+ } else if (sh_video->pts_assoc_mode == 0) {
+ if (sh_video->codec_reordered_pts != MP_NOPTS_VALUE)
+ sh_video->pts_assoc_mode = 1;
+ else
+ sh_video->pts_assoc_mode = 2;
+ } else {
+ int probcount1 = sh_video->num_reordered_pts_problems;
+ int probcount2 = sh_video->num_sorted_pts_problems;
+ if (sh_video->pts_assoc_mode == 2) {
+ int tmp = probcount1;
+ probcount1 = probcount2;
+ probcount2 = tmp;
+ }
+ if (probcount1 >= probcount2 * 1.5 + 2) {
+ sh_video->pts_assoc_mode = 3 - sh_video->pts_assoc_mode;
+ mp_msg(MSGT_CPLAYER, MSGL_V, "Switching to pts association mode "
+ "%d.\n", sh_video->pts_assoc_mode);
+ }
+ }
+ sh_video->pts = sh_video->pts_assoc_mode == 1 ?
+ sh_video->codec_reordered_pts : sh_video->sorted_pts;
+}
+
+static double update_video(struct MPContext *mpctx)
+{
+ struct sh_video *sh_video = mpctx->sh_video;
+ struct vo *video_out = mpctx->video_out;
+ sh_video->vfilter->control(sh_video->vfilter, VFCTRL_SET_OSD_OBJ,
+ mpctx->osd); // hack for vf_expand
+ if (!mpctx->opts.correct_pts)
+ return update_video_nocorrect_pts(mpctx);
+
+ double pts;
+
+ bool hit_eof = false;
+ while (!video_out->frame_loaded) {
+ current_module = "filter_video";
+ if (vo_get_buffered_frame(video_out, hit_eof) >= 0)
+ break;
+ // XXX Time used in this call is not counted in any performance
+ // timer now, OSD time is not updated correctly for filter-added frames
+ if (vf_output_queued_frame(sh_video->vfilter))
+ continue;
+ if (hit_eof)
+ return -1;
+ unsigned char *packet = NULL;
+ 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;
+ pts = 1e300;
+ hit_eof = true;
+ }
+ if (in_size > max_framesize)
+ max_framesize = in_size;
+ current_module = "decode video";
+ int framedrop_type = check_framedrop(mpctx, sh_video->frametime);
+ void *decoded_frame = decode_video(sh_video, packet, in_size,
+ framedrop_type, pts);
+ if (decoded_frame) {
+ determine_frame_pts(mpctx);
+ current_module = "filter video";
+ if (filter_video(sh_video, decoded_frame, sh_video->pts))
+ if (!video_out->config_ok)
+ break; // We'd likely hang in this loop otherwise
+ }
+ }
+
+ pts = video_out->next_pts;
+ if (pts == MP_NOPTS_VALUE) {
+ mp_msg(MSGT_CPLAYER, MSGL_ERR, "Video pts after filters MISSING\n");
+ // Try to use decoder pts from before filters
+ pts = sh_video->pts;
+ if (pts == MP_NOPTS_VALUE)
+ pts = sh_video->last_pts;
+ }
+ sh_video->pts = pts;
+ if (sh_video->last_pts == MP_NOPTS_VALUE)
+ sh_video->last_pts = sh_video->pts;
+ else if (sh_video->last_pts > sh_video->pts) {
+ mp_msg(MSGT_CPLAYER, MSGL_INFO, "Decreasing video pts: %f < %f\n",
+ sh_video->pts, sh_video->last_pts);
+ /* If the difference in pts is small treat it as jitter around the
+ * right value (possibly caused by incorrect timestamp ordering) and
+ * just show this frame immediately after the last one.
+ * Treat bigger differences as timestamp resets and start counting
+ * timing of later frames from the position of this one. */
+ if (sh_video->last_pts - sh_video->pts > 0.5)
+ sh_video->last_pts = sh_video->pts;
+ else
+ sh_video->pts = sh_video->last_pts;
}
+ double frame_time = sh_video->pts - sh_video->last_pts;
+ sh_video->last_pts = sh_video->pts;
+ sh_video->timer += frame_time;
+ if (mpctx->sh_audio)
+ mpctx->delay -= frame_time;
return frame_time;
}
-static void pause_loop(void)
+void pause_player(struct MPContext *mpctx)
+{
+ if (mpctx->paused)
+ return;
+ mpctx->paused = 1;
+ mpctx->step_frames = 0;
+ mpctx->time_frame -= get_relative_time(mpctx);
+
+ if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok)
+ vo_control(mpctx->video_out, VOCTRL_PAUSE, NULL);
+
+ if (mpctx->audio_out && mpctx->sh_audio)
+ mpctx->audio_out->pause(); // pause audio, keep data if possible
+}
+
+void unpause_player(struct MPContext *mpctx)
+{
+ if (!mpctx->paused)
+ return;
+ mpctx->paused = 0;
+
+ if (mpctx->audio_out && mpctx->sh_audio)
+ mpctx->audio_out->resume(); // resume audio
+ if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok
+ && !mpctx->step_frames)
+ vo_control(mpctx->video_out, VOCTRL_RESUME, NULL); // resume video
+ (void)get_relative_time(mpctx); // ignore time that passed during pause
+}
+
+void add_step_frame(struct MPContext *mpctx)
+{
+ mpctx->step_frames++;
+ if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok)
+ vo_control(mpctx->video_out, VOCTRL_PAUSE, NULL);
+ unpause_player(mpctx);
+}
+
+static void pause_loop(struct MPContext *mpctx)
{
mp_cmd_t* cmd;
if (!quiet) {
// Small hack to display the pause message on the OSD line.
// The pause string is: "\n == PAUSE == \r" so we need to
// take the first and the last char out
- if (term_osd && !mpctx->sh_video) {
- char msg[128] = MSGTR_Paused;
- int mlen = strlen(msg);
- msg[mlen-1] = '\0';
- set_osd_msg(OSD_MSG_PAUSE, 1, 0, "%s", msg+1);
- update_osd_msg();
- } else
- mp_msg(MSGT_CPLAYER,MSGL_STATUS,MSGTR_Paused);
+ if (term_osd && !mpctx->sh_video) {
+ char msg[128] = _("\n ===== PAUSE =====\r");
+ int mlen = strlen(msg);
+ msg[mlen-1] = '\0';
+ set_osd_msg(OSD_MSG_PAUSE, 1, 0, "%s", msg+1);
+ update_osd_msg(mpctx);
+ } else
+ mp_tmsg(MSGT_CPLAYER,MSGL_STATUS,"\n ===== PAUSE =====\r");
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_PAUSED\n");
}
-#ifdef CONFIG_GUI
- if (use_gui)
- guiGetEvent(guiCEvent, (char *)guiSetPause);
-#endif
- if (mpctx->video_out && mpctx->sh_video && vo_config_count)
- mpctx->video_out->control(VOCTRL_PAUSE, NULL);
- if (mpctx->audio_out && mpctx->sh_audio)
- mpctx->audio_out->pause(); // pause audio, keep data if possible
-
- while ( (cmd = mp_input_get_cmd(20, 1, 1)) == NULL || cmd->pausing == 4) {
- if (cmd) {
- cmd = mp_input_get_cmd(0,1,0);
- run_command(mpctx, cmd);
- mp_cmd_free(cmd);
- continue;
- }
- if (mpctx->sh_video && mpctx->video_out && vo_config_count)
- mpctx->video_out->check_events();
-#ifdef CONFIG_GUI
- if (use_gui) {
- guiEventHandling();
- guiGetEvent(guiReDraw, NULL);
- if (guiIntfStruct.Playing!=2 || (rel_seek_secs || abs_seek_pos))
- break;
- }
-#endif
+ while ( (cmd = mp_input_get_cmd(mpctx->input, 20, 1)) == NULL
+ || cmd->id == MP_CMD_SET_MOUSE_POS || cmd->pausing == 4) {
+ if (cmd) {
+ cmd = mp_input_get_cmd(mpctx->input, 0, 0);
+ run_command(mpctx, cmd);
+ mp_cmd_free(cmd);
+ continue;
+ }
+ if (mpctx->sh_video && mpctx->video_out)
+ vo_check_events(mpctx->video_out);
#ifdef CONFIG_MENU
if (vf_menu)
vf_menu_pause_update(vf_menu);
#endif
- usec_sleep(20000);
- }
- if (cmd && cmd->id == MP_CMD_PAUSE) {
- cmd = mp_input_get_cmd(0,1,0);
- mp_cmd_free(cmd);
- }
- mpctx->osd_function=OSD_PLAY;
- if (mpctx->audio_out && mpctx->sh_audio) {
- if (mpctx->eof) // do not play remaining audio if we e.g. switch to the next file
- mpctx->audio_out->reset();
- else
- mpctx->audio_out->resume(); // resume audio
- }
- if (mpctx->video_out && mpctx->sh_video && vo_config_count)
- mpctx->video_out->control(VOCTRL_RESUME, NULL); // resume video
- (void)GetRelativeTime(); // ignore time that passed during pause
-#ifdef CONFIG_GUI
- if (use_gui) {
- if (guiIntfStruct.Playing == guiSetStop)
- mpctx->eof = 1;
- else
- guiGetEvent(guiCEvent, (char *)guiSetPlay);
+ usec_sleep(20000);
+ update_osd_msg(mpctx);
+ int hack = vo_osd_changed(0);
+ vo_osd_changed(hack);
+ if (hack)
+ break;
}
-#endif
}
@@ -2511,7 +2624,7 @@ static void edl_update(MPContext *mpctx)
return;
if (!mpctx->sh_video) {
- mp_msg(MSGT_CPLAYER, MSGL_ERR, MSGTR_EdlNOsh_video);
+ mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "Cannot use EDL without video, disabling.\n");
free_edl(edl_records);
next_edl_record = NULL;
edl_records = NULL;
@@ -2521,12 +2634,11 @@ static void edl_update(MPContext *mpctx)
if (mpctx->sh_video->pts >= next_edl_record->start_sec) {
if (next_edl_record->action == EDL_SKIP) {
mpctx->osd_function = OSD_FFW;
- abs_seek_pos = 0;
- rel_seek_secs = next_edl_record->length_sec;
+ mpctx->abs_seek_pos = 0;
+ mpctx->rel_seek_secs = next_edl_record->length_sec;
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;
@@ -2539,37 +2651,45 @@ static void edl_update(MPContext *mpctx)
}
}
-
-// 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
-// return -1 if seek failed (non-seekable stream?), 0 otherwise
-static int seek(MPContext *mpctx, double amount, int style)
+static void reinit_decoders(struct MPContext *mpctx)
{
- current_module = "seek";
- if (demux_seek(mpctx->demuxer, amount, audio_delay, style) == 0)
- return -1;
+ reinit_video_chain(mpctx);
+ reinit_audio_chain(mpctx);
+ mp_property_do("sub", M_PROPERTY_SET, &mpctx->global_sub_pos, mpctx);
+}
- mpctx->startup_decode_retry = DEFAULT_STARTUP_DECODE_RETRY;
+static void seek_reset(struct MPContext *mpctx)
+{
if (mpctx->sh_video) {
current_module = "seek_video_reset";
- if (vo_config_count)
- mpctx->video_out->control(VOCTRL_RESET, NULL);
- mpctx->num_buffered_frames = 0;
+ resync_video_stream(mpctx->sh_video);
+ mpctx->sh_video->timer = 0;
+ vo_seek_reset(mpctx->video_out);
+ mpctx->sh_video->timer = 0;
+ mpctx->sh_video->num_buffered_pts = 0;
+ mpctx->sh_video->last_pts = MP_NOPTS_VALUE;
mpctx->delay = 0;
- mpctx->time_frame = 0;
+ mpctx->time_frame = 0;
+ mpctx->update_video_immediately = true;
// 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->sh_video->pts, mpctx->d_sub, 1);
+ mpctx->sh_video->pts = mpctx->d_video->pts + mpctx->video_offset;
+ update_subtitles(mpctx, &mpctx->opts, mpctx->sh_video,
+ mpctx->sh_video->pts, mpctx->video_offset,
+ mpctx->d_sub, 1);
update_teletext(mpctx->sh_video, mpctx->demuxer, 1);
}
if (mpctx->sh_audio) {
current_module = "seek_audio_reset";
+ resync_audio_stream(mpctx->sh_audio);
mpctx->audio_out->reset(); // stop audio, throwing away buffered data
+ mpctx->sh_audio->a_buffer_len = 0;
+ mpctx->sh_audio->a_out_buffer_len = 0;
if (!mpctx->sh_video)
- update_subtitles(NULL, mpctx->sh_audio->pts, mpctx->d_sub, 1);
+ update_subtitles(mpctx, &mpctx->opts, NULL, mpctx->sh_audio->pts,
+ mpctx->video_offset, mpctx->d_sub, 1);
}
if (vo_vobsub && mpctx->sh_video) {
@@ -2579,15 +2699,355 @@ static int seek(MPContext *mpctx, double amount, int style)
edl_seek_reset(mpctx);
- c_total = 0;
- max_pts_correction = 0.1;
+ mpctx->total_avsync_change = 0;
audio_time_usage = 0; video_time_usage = 0; vout_time_usage = 0;
drop_frame_cnt = 0;
current_module = NULL;
+}
+
+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
+// return -1 if seek failed (non-seekable stream?), 0 otherwise
+static int seek(MPContext *mpctx, double amount, int style)
+{
+ current_module = "seek";
+ if (mpctx->stop_play == AT_END_OF_FILE)
+ mpctx->stop_play = KEEP_PLAYING;
+ if (style & SEEK_FACTOR
+ || style & SEEK_ABSOLUTE && amount < mpctx->last_chapter_pts
+ || amount < 0)
+ mpctx->last_chapter_seek = -1;
+ 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;
+
+ seek_reset(mpctx);
return 0;
}
+// -2 is no chapters, -1 is before first chapter
+int get_current_chapter(struct MPContext *mpctx)
+{
+ if (!mpctx->chapters || !mpctx->sh_video)
+ return FFMAX(mpctx->last_chapter_seek,
+ 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 FFMAX(mpctx->last_chapter_seek, 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)
+{
+ mpctx->last_chapter_seek = -1;
+ if (!mpctx->chapters || !mpctx->sh_video) {
+ int res = demuxer_seek_chapter(mpctx->demuxer, chapter, seek_pts,
+ chapter_name);
+ if (res >= 0) {
+ if (*seek_pts == -1)
+ seek_reset(mpctx);
+ else {
+ mpctx->last_chapter_seek = res;
+ mpctx->last_chapter_pts = *seek_pts;
+ }
+ }
+ return res;
+ }
+
+ if (chapter >= mpctx->num_chapters)
+ return -1;
+ if (chapter < 0)
+ chapter = 0;
+ *seek_pts = mpctx->chapters[chapter].start;
+ mpctx->last_chapter_seek = chapter;
+ mpctx->last_chapter_pts = *seek_pts;
+ 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;
+
+ // +1 because sources/uid_map[0] is original file even if all chapters
+ // actually use other sources and need separate entries
+ struct content_source *sources = talloc_array_ptrtype(NULL, sources,
+ m->num_ordered_chapters+1);
+ sources[0].stream = mpctx->stream;
+ sources[0].demuxer = mpctx->demuxer;
+ unsigned char uid_map[m->num_ordered_chapters+1][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);
+
+
+ // +1 for terminating chapter with start time marking end of last real one
+ 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;
+ uint64_t prev_part_offset = 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.
+ * Matroska files have chapter divisions that are redundant from
+ * timeline point of view because the same chapter structure is used
+ * both to specify the timeline and for normal chapter information.
+ * Removing a missing inserted external chapter can also cause this. */
+ if (part_count == 0 || c->start != starttime + prev_part_offset
+ || 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.;
+ prev_part_offset = c->start - starttime;
+ 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->demuxer = timeline[0].source->demuxer;
+}
+
+
+static int read_keys(void *ctx, int fd)
+{
+ getch2(ctx);
+ return mplayer_get_key(ctx, 0);
+}
+
+
/* This preprocessor directive is a hack to generate a mplayer-nomain.o object
* file for some tools to link against. */
#ifndef DISABLE_MAIN
@@ -2605,20 +3065,34 @@ int opt_exit = 0;
int i;
-int gui_no_filename=0;
+ struct MPContext *mpctx = &(struct MPContext){
+ .osd_function = OSD_PLAY,
+ .begin_skip = MP_NOPTS_VALUE,
+ .play_tree_step = 1,
+ .global_sub_pos = -1,
+ .set_of_sub_pos = -1,
+ .file_format = DEMUXER_TYPE_UNKNOWN,
+ .last_dvb_step = 1,
+ };
InitTimer();
srand(GetTimerMS());
mp_msg_init();
+ set_av_log_callback();
+#ifdef CONFIG_X11
+ mpctx->x11_state = vo_x11_init_state();
+#endif
+ struct MPOpts *opts = &mpctx->opts;
+ set_default_mplayer_options(opts);
// Create the config context and register the options
- mconfig = m_config_new();
- m_config_register_options(mconfig,mplayer_opts);
- mp_input_register_options(mconfig);
+ mpctx->mconfig = m_config_new(opts, cfg_include);
+ m_config_register_options(mpctx->mconfig,mplayer_opts);
+ mp_input_register_options(mpctx->mconfig);
// Preparse the command line
- m_config_preparse_command_line(mconfig,argc,argv);
+ m_config_preparse_command_line(mpctx->mconfig,argc,argv);
#if (defined(__MINGW32__) || defined(__CYGWIN__)) && defined(CONFIG_WIN32DLL)
set_path_env();
@@ -2628,62 +3102,29 @@ int gui_no_filename=0;
stream_tv_defaults.immediate = 1;
#endif
- if (argc > 1 && argv[1] &&
- (!strcmp(argv[1], "-gui") || !strcmp(argv[1], "-nogui"))) {
- use_gui = !strcmp(argv[1], "-gui");
- } else
- if ( argv[0] )
- {
- char *base = strrchr(argv[0], '/');
- if (!base)
- base = strrchr(argv[0], '\\');
- if (!base)
- base = argv[0];
- if(strstr(base, "gmplayer"))
- use_gui=1;
- }
-
- parse_cfgfiles(mconfig);
+ parse_cfgfiles(mpctx, mpctx->mconfig);
-#ifdef CONFIG_GUI
- if ( use_gui ) cfg_read();
-#endif
-
- mpctx->playtree = m_config_parse_mp_command_line(mconfig, argc, argv);
+ mpctx->playtree = m_config_parse_mp_command_line(mpctx->mconfig, argc, argv);
if(mpctx->playtree == NULL)
opt_exit = 1;
else {
mpctx->playtree = play_tree_cleanup(mpctx->playtree);
if(mpctx->playtree) {
- mpctx->playtree_iter = play_tree_iter_new(mpctx->playtree,mconfig);
+ mpctx->playtree_iter = play_tree_iter_new(mpctx->playtree,mpctx->mconfig);
if(mpctx->playtree_iter) {
if(play_tree_iter_step(mpctx->playtree_iter,0,0) != PLAY_TREE_ITER_ENTRY) {
play_tree_iter_free(mpctx->playtree_iter);
mpctx->playtree_iter = NULL;
}
- filename = play_tree_iter_get_file(mpctx->playtree_iter,1);
+ mpctx->filename = play_tree_iter_get_file(mpctx->playtree_iter,1);
}
}
}
+ mpctx->key_fifo = mp_fifo_create(opts);
print_version("MPlayer");
#if defined(__MINGW32__) || defined(__CYGWIN__)
-#ifdef CONFIG_GUI
- void *runningmplayer = FindWindow("MPlayer GUI for Windows", "MPlayer for Windows");
- if(runningmplayer && filename && use_gui){
- COPYDATASTRUCT csData;
- char file[MAX_PATH];
- char *filepart = filename;
- if(GetFullPathName(filename, MAX_PATH, file, &filepart)){
- csData.dwData = 0;
- csData.cbData = strlen(file)*2;
- csData.lpData = file;
- SendMessage(runningmplayer, WM_COPYDATA, (WPARAM)runningmplayer, (LPARAM)&csData);
- }
- }
-#endif
-
{
HMODULE kernel32 = GetModuleHandle("Kernel32.dll");
BOOL WINAPI (*setDEP)(DWORD) = NULL;
@@ -2704,41 +3145,12 @@ int gui_no_filename=0;
if (codec_path)
set_codec_path(codec_path);
-#ifndef CONFIG_GUI
- if(use_gui){
- mp_msg(MSGT_CPLAYER,MSGL_WARN,MSGTR_NoGui);
- use_gui=0;
- }
-#else
-#if !defined(__MINGW32__) && !defined(__CYGWIN__)
- if(use_gui && !vo_init()){
- mp_msg(MSGT_CPLAYER,MSGL_WARN,MSGTR_GuiNeedsX);
- use_gui=0;
- }
-#endif
- if (use_gui && mpctx->playtree_iter){
- char cwd[PATH_MAX+2];
- // Free Playtree and Playtree-Iter as it's not used by the GUI.
- play_tree_iter_free(mpctx->playtree_iter);
- mpctx->playtree_iter=NULL;
-
- if (getcwd(cwd, PATH_MAX) != (char *)NULL)
- {
- strcat(cwd, "/");
- // Prefix relative paths with current working directory
- play_tree_add_bpf(mpctx->playtree, cwd);
- }
- // Import initital playtree into GUI.
- import_initial_playtree_into_gui(mpctx->playtree, mconfig, enqueue);
- }
-#endif /* CONFIG_GUI */
-
- if(video_driver_list && strcmp(video_driver_list[0],"help")==0){
+ if(opts->video_driver_list && strcmp(opts->video_driver_list[0],"help")==0){
list_video_out();
opt_exit = 1;
}
- if(audio_driver_list && strcmp(audio_driver_list[0],"help")==0){
+ if(opts->audio_driver_list && strcmp(opts->audio_driver_list[0],"help")==0){
list_audio_out();
opt_exit = 1;
}
@@ -2748,9 +3160,9 @@ if(!codecs_file || !parse_codec_cfg(codecs_file)){
if(!parse_codec_cfg(mem_ptr=get_path("codecs.conf"))){
if(!parse_codec_cfg(MPLAYER_CONFDIR "/codecs.conf")){
if(!parse_codec_cfg(NULL)){
- exit_player_with_rc(EXIT_NONE, 0);
+ exit_player_with_rc(mpctx, EXIT_NONE, 0);
}
- mp_msg(MSGT_CPLAYER,MSGL_V,MSGTR_BuiltinCodecsConf);
+ mp_tmsg(MSGT_CPLAYER,MSGL_V,"Using built-in default codecs.conf.\n");
}
}
free( mem_ptr ); // release the buffer created by get_path()
@@ -2765,14 +3177,14 @@ if(!codecs_file || !parse_codec_cfg(codecs_file)){
}
#endif
if(audio_codec_list && strcmp(audio_codec_list[0],"help")==0){
- mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_AvailableAudioCodecs);
+ mp_tmsg(MSGT_CPLAYER, MSGL_INFO, "Available audio codecs:\n");
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_CODECS\n");
list_codecs(1);
mp_msg(MSGT_FIXME, MSGL_FIXME, "\n");
opt_exit = 1;
}
if(video_codec_list && strcmp(video_codec_list[0],"help")==0){
- mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_AvailableVideoCodecs);
+ mp_tmsg(MSGT_CPLAYER, MSGL_INFO, "Available video codecs:\n");
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_CODECS\n");
list_codecs(0);
mp_msg(MSGT_FIXME, MSGL_FIXME, "\n");
@@ -2813,19 +3225,12 @@ if(!codecs_file || !parse_codec_cfg(codecs_file)){
}
if(opt_exit)
- exit_player(EXIT_NONE);
-
- if (player_idle_mode && use_gui) {
- mp_msg(MSGT_CPLAYER, MSGL_FATAL, MSGTR_NoIdleAndGui);
- exit_player_with_rc(EXIT_NONE, 1);
- }
+ exit_player(mpctx, EXIT_NONE);
- if(!filename && !player_idle_mode){
- if(!use_gui){
+ if(!mpctx->filename && !player_idle_mode){
// no file/vcd/dvd -> show HELP:
- mp_msg(MSGT_CPLAYER, MSGL_INFO, help_text);
- exit_player_with_rc(EXIT_NONE, 0);
- } else gui_no_filename=1;
+ mp_msg(MSGT_CPLAYER, MSGL_INFO, "%s", mp_gtext(help_text));
+ exit_player_with_rc(mpctx, EXIT_NONE, 0);
}
/* Display what configure line was used */
@@ -2833,13 +3238,15 @@ if(!codecs_file || !parse_codec_cfg(codecs_file)){
// Many users forget to include command line in bugreports...
if( mp_msg_test(MSGT_CPLAYER,MSGL_V) ){
- mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_CommandLine);
+ mp_tmsg(MSGT_CPLAYER, MSGL_INFO, "CommandLine:");
for(i=1;i<argc;i++)mp_msg(MSGT_CPLAYER, MSGL_INFO," '%s'",argv[i]);
mp_msg(MSGT_CPLAYER, MSGL_INFO, "\n");
}
//------ load global data first ------
+ mpctx->osd = osd_create();
+
// check font
#ifdef CONFIG_FREETYPE
init_freetype();
@@ -2851,7 +3258,7 @@ if(!codecs_file || !parse_codec_cfg(codecs_file)){
#ifdef CONFIG_BITMAP_FONT
if(font_name){
vo_font=read_font_desc(font_name,font_factor,verbose>1);
- if(!vo_font) mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_CantLoadFont,
+ if(!vo_font) mp_tmsg(MSGT_CPLAYER,MSGL_ERR,"Cannot load bitmap font: %s\n",
filename_recode(font_name));
} else {
// try default:
@@ -2861,16 +3268,14 @@ if(!codecs_file || !parse_codec_cfg(codecs_file)){
vo_font=read_font_desc(MPLAYER_DATADIR "/font/font.desc",font_factor,verbose>1);
}
if (sub_font_name)
- sub_font = read_font_desc(sub_font_name, font_factor, verbose>1);
+ mpctx->osd->sub_font = read_font_desc(sub_font_name, font_factor, verbose>1);
else
- sub_font = vo_font;
+ mpctx->osd->sub_font = vo_font;
#endif
#ifdef CONFIG_FONTCONFIG
}
#endif
- vo_init_osd();
-
#ifdef CONFIG_ASS
ass_library = ass_init();
#endif
@@ -2880,65 +3285,61 @@ if(!codecs_file || !parse_codec_cfg(codecs_file)){
{
// seteuid(0); /* Can't hurt to try to get root here */
if ((rtc_fd = open(rtc_device ? rtc_device : "/dev/rtc", O_RDONLY)) < 0)
- mp_msg(MSGT_CPLAYER, MSGL_WARN, MSGTR_RTCDeviceNotOpenable,
+ mp_tmsg(MSGT_CPLAYER, MSGL_WARN, "Failed to open %s: %s (it should be readable by the user.)\n",
rtc_device ? rtc_device : "/dev/rtc", strerror(errno));
else {
unsigned long irqp = 1024; /* 512 seemed OK. 128 is jerky. */
if (ioctl(rtc_fd, RTC_IRQP_SET, irqp) < 0) {
- mp_msg(MSGT_CPLAYER, MSGL_WARN, MSGTR_LinuxRTCInitErrorIrqpSet, irqp, strerror(errno));
- mp_msg(MSGT_CPLAYER, MSGL_HINT, MSGTR_IncreaseRTCMaxUserFreq, irqp);
+ mp_tmsg(MSGT_CPLAYER, MSGL_WARN, "Linux RTC init error in ioctl (rtc_irqp_set %lu): %s\n", irqp, strerror(errno));
+ mp_tmsg(MSGT_CPLAYER, MSGL_HINT, "Try adding \"echo %lu > /proc/sys/dev/rtc/max-user-freq\" to your system startup scripts.\n", irqp);
close (rtc_fd);
rtc_fd = -1;
} else if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) {
/* variable only by the root */
- mp_msg(MSGT_CPLAYER, MSGL_ERR, MSGTR_LinuxRTCInitErrorPieOn, strerror(errno));
+ mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "Linux RTC init error in ioctl (rtc_pie_on): %s\n", strerror(errno));
close (rtc_fd);
rtc_fd = -1;
} else
- mp_msg(MSGT_CPLAYER, MSGL_V, MSGTR_UsingRTCTiming, irqp);
+ mp_tmsg(MSGT_CPLAYER, MSGL_V, "Using Linux hardware RTC timing (%ldHz).\n", irqp);
}
}
-#ifdef CONFIG_GUI
-// breaks DGA and SVGAlib and VESA drivers: --A'rpi
-// and now ? -- Pontscho
- if(use_gui) setuid( getuid() ); // strongly test, please check this.
-#endif
if(rtc_fd<0)
#endif /* HAVE_RTC */
mp_msg(MSGT_CPLAYER, MSGL_V, "Using %s timing\n",
softsleep?"software":timer_name);
#ifdef HAVE_TERMCAP
- if ( !use_gui ) load_termcap(NULL); // load key-codes
+ load_termcap(NULL); // load key-codes
#endif
// ========== Init keyboard FIFO (connection to libvo) ============
// Init input system
current_module = "init_input";
-mp_input_init(use_gui);
- mp_input_add_key_fd(-1,0,mplayer_get_key,NULL);
+ mpctx->input = mp_input_init(&opts->input);
+ mp_input_add_key_fd(mpctx->input, -1,0,mplayer_get_key,NULL, mpctx->key_fifo);
if(slave_mode)
- mp_input_add_cmd_fd(0,USE_SELECT,MP_INPUT_SLAVE_CMD_FUNC,NULL);
+ mp_input_add_cmd_fd(mpctx->input, 0,USE_SELECT,MP_INPUT_SLAVE_CMD_FUNC,NULL);
else if(!noconsolecontrols)
- mp_input_add_event_fd(0, getch2);
+ mp_input_add_key_fd(mpctx->input, 0, 1, read_keys, NULL, mpctx->key_fifo);
// Set the libstream interrupt callback
-stream_set_interrupt_callback(mp_input_check_interrupt);
+stream_set_interrupt_callback(mp_input_check_interrupt, mpctx->input);
#ifdef CONFIG_MENU
if(use_menu) {
- if(menu_cfg && menu_init(mpctx, menu_cfg))
- mp_msg(MSGT_CPLAYER, MSGL_V, MSGTR_MenuInitialized, menu_cfg);
+ if(menu_cfg && menu_init(mpctx, mpctx->mconfig, mpctx->input, menu_cfg))
+ mp_tmsg(MSGT_CPLAYER, MSGL_V, "Menu initialized: %s\n", menu_cfg);
else {
menu_cfg = get_path("menu.conf");
- if(menu_init(mpctx, menu_cfg))
- mp_msg(MSGT_CPLAYER, MSGL_V, MSGTR_MenuInitialized, menu_cfg);
+ if(menu_init(mpctx, mpctx->mconfig, mpctx->input, menu_cfg))
+ mp_tmsg(MSGT_CPLAYER, MSGL_V, "Menu initialized: %s\n", menu_cfg);
else {
- if(menu_init(mpctx, MPLAYER_CONFDIR "/menu.conf"))
- mp_msg(MSGT_CPLAYER, MSGL_V, MSGTR_MenuInitialized, MPLAYER_CONFDIR"/menu.conf");
+ if(menu_init(mpctx, mpctx->mconfig, mpctx->input,
+ MPLAYER_CONFDIR "/menu.conf"))
+ mp_tmsg(MSGT_CPLAYER, MSGL_V, "Menu initialized: %s\n", MPLAYER_CONFDIR"/menu.conf");
else {
- mp_msg(MSGT_CPLAYER, MSGL_ERR, MSGTR_MenuInitFailed);
+ mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "Menu init failed.\n");
use_menu = 0;
}
}
@@ -2946,7 +3347,6 @@ stream_set_interrupt_callback(mp_input_check_interrupt);
}
#endif
-initialized_flags|=INITIALIZED_INPUT;
current_module = NULL;
/// Catch signals
@@ -2979,15 +3379,6 @@ current_module = NULL;
#endif
#endif
-#ifdef CONFIG_GUI
- if(use_gui){
- guiInit();
- guiGetEvent(guiSetContext, mpctx);
- initialized_flags|=INITIALIZED_GUI;
- guiGetEvent( guiCEvent,(char *)((gui_no_filename) ? 0 : 1) );
- }
-#endif
-
// ******************* Now, let's see the per-file stuff ********************
play_next_file:
@@ -2996,76 +3387,37 @@ play_next_file:
mpctx->global_sub_size = 0;
{ int i; for (i = 0; i < SUB_SOURCES; i++) mpctx->global_sub_indices[i] = -1; }
- if (filename) {
- load_per_protocol_config (mconfig, filename);
- load_per_extension_config (mconfig, filename);
- load_per_file_config (mconfig, filename);
+ if (mpctx->filename) {
+ load_per_protocol_config (mpctx->mconfig, mpctx->filename);
+ load_per_extension_config (mpctx->mconfig, mpctx->filename);
+ load_per_file_config (mpctx->mconfig, mpctx->filename);
}
- if (video_driver_list)
- load_per_output_config (mconfig, PROFILE_CFG_VO, video_driver_list[0]);
- if (audio_driver_list)
- load_per_output_config (mconfig, PROFILE_CFG_AO, audio_driver_list[0]);
+ if (opts->video_driver_list)
+ load_per_output_config (mpctx->mconfig, PROFILE_CFG_VO, opts->video_driver_list[0]);
+ if (opts->audio_driver_list)
+ load_per_output_config (mpctx->mconfig, PROFILE_CFG_AO, opts->audio_driver_list[0]);
// We must enable getch2 here to be able to interrupt network connection
// or cache filling
if(!noconsolecontrols && !slave_mode){
- if(initialized_flags&INITIALIZED_GETCH2)
- mp_msg(MSGT_CPLAYER,MSGL_WARN,MSGTR_Getch2InitializedTwice);
+ if(mpctx->initialized_flags&INITIALIZED_GETCH2)
+ mp_tmsg(MSGT_CPLAYER,MSGL_WARN,"WARNING: getch2_init called twice!\n");
else
getch2_enable(); // prepare stdin for hotkeys...
- initialized_flags|=INITIALIZED_GETCH2;
+ mpctx->initialized_flags|=INITIALIZED_GETCH2;
mp_msg(MSGT_CPLAYER,MSGL_DBG2,"\n[[[init getch2]]]\n");
}
// =================== GUI idle loop (STOP state) ===========================
-#ifdef CONFIG_GUI
- if ( use_gui ) {
- mpctx->file_format=DEMUXER_TYPE_UNKNOWN;
- guiGetEvent( guiSetDefaults,0 );
- while ( guiIntfStruct.Playing != 1 )
- {
- mp_cmd_t* cmd;
- usec_sleep(20000);
- guiEventHandling();
- guiGetEvent( guiReDraw,NULL );
- if ( (cmd = mp_input_get_cmd(0,0,0)) != NULL) {
- guiGetEvent(guiIEvent, (char *)cmd->id);
- mp_cmd_free(cmd);
- }
- }
- guiGetEvent( guiSetParameters,NULL );
- if ( guiIntfStruct.StreamType == STREAMTYPE_STREAM )
- {
- play_tree_t * entry = play_tree_new();
- play_tree_add_file( entry,guiIntfStruct.Filename );
- if ( mpctx->playtree ) play_tree_free_list( mpctx->playtree->child,1 );
- else mpctx->playtree=play_tree_new();
- play_tree_set_child( mpctx->playtree,entry );
- if(mpctx->playtree)
- {
- mpctx->playtree_iter = play_tree_iter_new(mpctx->playtree,mconfig);
- if(mpctx->playtree_iter)
- {
- if(play_tree_iter_step(mpctx->playtree_iter,0,0) != PLAY_TREE_ITER_ENTRY)
- {
- play_tree_iter_free(mpctx->playtree_iter);
- mpctx->playtree_iter = NULL;
- }
- filename = play_tree_iter_get_file(mpctx->playtree_iter,1);
- }
- }
- }
- }
-#endif /* CONFIG_GUI */
-
-while (player_idle_mode && !filename) {
+while (player_idle_mode && !mpctx->filename) {
play_tree_t * entry = NULL;
mp_cmd_t * cmd;
- if (mpctx->video_out && vo_config_count)
- mpctx->video_out->control(VOCTRL_PAUSE, NULL);
- while (!(cmd = mp_input_get_cmd(0,1,0))) { // wait for command
- if (mpctx->video_out && vo_config_count) mpctx->video_out->check_events();
+ if (mpctx->video_out && mpctx->video_out->config_ok)
+ vo_control(mpctx->video_out, VOCTRL_PAUSE, NULL);
+ while (!(cmd = mp_input_get_cmd(mpctx->input, 0, 0))) { // wait for command
+ if (mpctx->video_out)
+ vo_check_events(mpctx->video_out);
usec_sleep(20000);
}
switch (cmd->id) {
@@ -3076,10 +3428,10 @@ while (player_idle_mode && !filename) {
// The entry is added to the main playtree after the switch().
break;
case MP_CMD_LOADLIST:
- entry = parse_playlist_file(cmd->args[0].v.s);
+ entry = parse_playlist_file(mpctx->mconfig, cmd->args[0].v.s);
break;
case MP_CMD_QUIT:
- exit_player_with_rc(EXIT_QUIT, (cmd->nargs > 0)? cmd->args[0].v.i : 0);
+ exit_player_with_rc(mpctx, EXIT_QUIT, (cmd->nargs > 0)? cmd->args[0].v.i : 0);
break;
case MP_CMD_GET_PROPERTY:
case MP_CMD_SET_PROPERTY:
@@ -3100,7 +3452,7 @@ while (player_idle_mode && !filename) {
play_tree_set_child(mpctx->playtree, entry);
/* Make iterator start at the top the of tree. */
- mpctx->playtree_iter = play_tree_iter_new(mpctx->playtree, mconfig);
+ mpctx->playtree_iter = play_tree_iter_new(mpctx->playtree, mpctx->mconfig);
if (!mpctx->playtree_iter) continue;
// find the first real item in the tree
@@ -3110,19 +3462,19 @@ while (player_idle_mode && !filename) {
mpctx->playtree_iter = NULL;
continue; // wait for next command
}
- filename = play_tree_iter_get_file(mpctx->playtree_iter, 1);
+ mpctx->filename = play_tree_iter_get_file(mpctx->playtree_iter, 1);
}
}
//---------------------------------------------------------------------------
- if (mpctx->video_out && vo_config_count)
- mpctx->video_out->control(VOCTRL_RESUME, NULL);
+ if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok)
+ vo_control(mpctx->video_out, VOCTRL_RESUME, NULL);
- if(filename) {
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_Playing,
- filename_recode(filename));
+ if (mpctx->filename) {
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"\nPlaying %s.\n",
+ filename_recode(mpctx->filename));
if(use_filename_title && vo_wintitle == NULL)
- vo_wintitle = strdup ( mp_basename2 (filename));
+ vo_wintitle = strdup(mp_basename2(mpctx->filename));
}
if (edl_filename) {
@@ -3133,7 +3485,7 @@ if (edl_output_filename) {
if (edl_fd) fclose(edl_fd);
if ((edl_fd = fopen(edl_output_filename, "w")) == NULL)
{
- mp_msg(MSGT_CPLAYER, MSGL_ERR, MSGTR_EdlCantOpenForWrite,
+ mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "Can't open EDL file [%s] for writing.\n",
filename_recode(edl_output_filename));
}
}
@@ -3144,11 +3496,11 @@ if (edl_output_filename) {
if (vobsub_name){
vo_vobsub=vobsub_open(vobsub_name,spudec_ifo,1,&vo_spudec);
if(vo_vobsub==NULL)
- mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_CantLoadSub,
+ mp_tmsg(MSGT_CPLAYER,MSGL_ERR,"Cannot load subtitles: %s\n",
filename_recode(vobsub_name));
- } else if (sub_auto && filename){
+ } else if (sub_auto && mpctx->filename){
/* try to autodetect vobsub from movie filename ::atmos */
- char *buf = strdup(filename), *psub;
+ char *buf = strdup(mpctx->filename), *psub;
char *pdot = strrchr(buf, '.');
char *pslash = strrchr(buf, '/');
#if defined(__MINGW32__) || defined(__CYGWIN__)
@@ -3176,7 +3528,7 @@ if (edl_output_filename) {
free(buf);
}
if(vo_vobsub){
- initialized_flags|=INITIALIZED_VOBSUB;
+ mpctx->initialized_flags|=INITIALIZED_VOBSUB;
vobsub_set_from_lang(vo_vobsub, dvdsub_lang);
mp_property_do("sub_forced_only", M_PROPERTY_SET, &forced_subs_only, mpctx);
@@ -3201,26 +3553,28 @@ if (edl_output_filename) {
mpctx->sh_video=NULL;
current_module="open_stream";
- mpctx->stream=open_stream(filename,0,&mpctx->file_format);
+ mpctx->stream = open_stream(mpctx->filename, opts, &mpctx->file_format);
if(!mpctx->stream) { // error...
- mpctx->eof = libmpdemux_was_interrupted(PT_NEXT_ENTRY);
+ mpctx->stop_play = libmpdemux_was_interrupted(mpctx, PT_NEXT_ENTRY);
goto goto_next_file;
}
- initialized_flags|=INITIALIZED_STREAM;
-
-#ifdef CONFIG_GUI
- if ( use_gui ) guiGetEvent( guiSetStream,(char *)mpctx->stream );
-#endif
+ mpctx->initialized_flags|=INITIALIZED_STREAM;
if(mpctx->file_format == DEMUXER_TYPE_PLAYLIST) {
+ mp_msg(MSGT_CPLAYER, MSGL_ERR, "\nThis looks like a playlist, but "
+ "playlist support will not be used automatically.\n"
+ "MPlayer's playlist code is unsafe and should only be used with "
+ "trusted sources.\nPlayback will probably fail.\n\n");
+#if 0
play_tree_t* entry;
// Handle playlist
current_module="handle_playlist";
mp_msg(MSGT_CPLAYER,MSGL_V,"Parsing playlist %s...\n",
- filename_recode(filename));
- entry = parse_playtree(mpctx->stream,0);
- mpctx->eof=playtree_add_playlist(entry);
+ filename_recode(mpctx->filename));
+ entry = parse_playtree(mpctx->stream, mpctx->mconfig, 0);
+ mpctx->eof=playtree_add_playlist(mpctx, entry);
goto goto_next_file;
+#endif
}
mpctx->stream->start_pos+=seek_to_byte;
@@ -3233,41 +3587,42 @@ if(stream_dump_type==5){
stream_seek(mpctx->stream,mpctx->stream->start_pos);
f=fopen(stream_dump_name,"wb");
if(!f){
- mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_CantOpenDumpfile);
- exit_player(EXIT_ERROR);
+ mp_tmsg(MSGT_CPLAYER,MSGL_FATAL,"Cannot open dump file.\n");
+ exit_player(mpctx, EXIT_ERROR);
}
- if (dvd_chapter > 1) {
- int chapter = dvd_chapter - 1;
+ if (opts->chapterrange[0] > 1) {
+ int chapter = opts->chapterrange[0] - 1;
stream_control(mpctx->stream, STREAM_CTRL_SEEK_TO_CHAPTER, &chapter);
}
while(!mpctx->stream->eof && !async_quit_request){
len=stream_read(mpctx->stream,buf,4096);
if(len>0) {
if(fwrite(buf,len,1,f) != 1) {
- mp_msg(MSGT_MENCODER,MSGL_FATAL,MSGTR_ErrorWritingFile,stream_dump_name);
- exit_player(EXIT_ERROR);
+ mp_tmsg(MSGT_MENCODER,MSGL_FATAL,"%s: Error writing file.\n",stream_dump_name);
+ exit_player(mpctx, EXIT_ERROR);
}
}
- if(dvd_last_chapter > 0) {
+ if (opts->chapterrange[1] > 0) {
int chapter = -1;
if (stream_control(mpctx->stream, STREAM_CTRL_GET_CURRENT_CHAPTER,
- &chapter) == STREAM_OK && chapter + 1 > dvd_last_chapter)
+ &chapter) == STREAM_OK
+ && chapter + 1 > opts->chapterrange[1])
break;
}
}
if(fclose(f)) {
- mp_msg(MSGT_MENCODER,MSGL_FATAL,MSGTR_ErrorWritingFile,stream_dump_name);
- exit_player(EXIT_ERROR);
+ mp_tmsg(MSGT_MENCODER,MSGL_FATAL,"%s: Error writing file.\n",stream_dump_name);
+ exit_player(mpctx, EXIT_ERROR);
}
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_CoreDumped);
- exit_player_with_rc(EXIT_EOF, 0);
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"Core dumped ;)\n");
+ exit_player_with_rc(mpctx, EXIT_EOF, 0);
}
#ifdef CONFIG_DVDREAD
if(mpctx->stream->type==STREAMTYPE_DVD){
current_module="dvd lang->id";
- if(audio_id==-1) audio_id=dvd_aid_from_lang(mpctx->stream,audio_lang);
- if(dvdsub_lang && dvdsub_id==-1) dvdsub_id=dvd_sid_from_lang(mpctx->stream,dvdsub_lang);
+ if(opts->audio_id==-1) opts->audio_id=dvd_aid_from_lang(mpctx->stream,audio_lang);
+ if(dvdsub_lang && opts->sub_id==-1) opts->sub_id=dvd_sid_from_lang(mpctx->stream,dvdsub_lang);
// setup global sub numbering
mpctx->global_sub_indices[SUB_SOURCE_DEMUX] = mpctx->global_sub_size; // the global # of the first demux-specific sub.
mpctx->global_sub_size += dvd_number_of_subs(mpctx->stream);
@@ -3278,10 +3633,10 @@ if(mpctx->stream->type==STREAMTYPE_DVD){
#ifdef CONFIG_DVDNAV
if(mpctx->stream->type==STREAMTYPE_DVDNAV){
current_module="dvdnav lang->id";
- if(audio_id==-1) audio_id=mp_dvdnav_aid_from_lang(mpctx->stream,audio_lang);
+ if(opts->audio_id==-1) opts->audio_id=mp_dvdnav_aid_from_lang(mpctx->stream,audio_lang);
dvdsub_lang_id = -3;
- if(dvdsub_lang && dvdsub_id==-1)
- dvdsub_lang_id=dvdsub_id=mp_dvdnav_sid_from_lang(mpctx->stream,dvdsub_lang);
+ if(dvdsub_lang && opts->sub_id==-1)
+ dvdsub_lang_id = opts->sub_id = mp_dvdnav_sid_from_lang(mpctx->stream,dvdsub_lang);
// setup global sub numbering
mpctx->global_sub_indices[SUB_SOURCE_DEMUX] = mpctx->global_sub_size; // the global # of the first demux-specific sub.
mpctx->global_sub_size += mp_dvdnav_number_of_subs(mpctx->stream);
@@ -3298,13 +3653,13 @@ if(stream_cache_size>0){
stream_cache_size*1024*(stream_cache_min_percent / 100.0),
stream_cache_size*1024*(stream_cache_seek_min_percent / 100.0));
if(res == 0)
- if((mpctx->eof = libmpdemux_was_interrupted(PT_NEXT_ENTRY))) goto goto_next_file;
+ if((mpctx->stop_play = libmpdemux_was_interrupted(mpctx, PT_NEXT_ENTRY))) goto goto_next_file;
}
//============ Open DEMUXERS --- DETECT file type =======================
current_module="demux_open";
-mpctx->demuxer=demux_open(mpctx->stream,mpctx->file_format,audio_id,video_id,dvdsub_id,filename);
+mpctx->demuxer=demux_open(opts, mpctx->stream,mpctx->file_format,opts->audio_id,opts->video_id,opts->sub_id,mpctx->filename);
// HACK to get MOV Reference Files working
@@ -3325,20 +3680,20 @@ if (mpctx->demuxer && mpctx->demuxer->type==DEMUXER_TYPE_PLAYLIST)
if ((strlen(bname)>10) && !strncmp(bname,"qt",2) && !strncmp(bname+3,"gateQT",6))
continue;
- if (!strcmp(playlist_entry,filename)) // ignoring self-reference
+ if (!strcmp(playlist_entry, mpctx->filename)) // ignoring self-reference
continue;
entry = play_tree_new();
- if (filename && !strcmp(mp_basename(playlist_entry),playlist_entry)) // add reference path of current file
+ if (mpctx->filename && !strcmp(mp_basename(playlist_entry),playlist_entry)) // add reference path of current file
{
- temp=malloc((strlen(filename)-strlen(mp_basename(filename))+strlen(playlist_entry)+1));
+ temp=malloc((strlen(mpctx->filename)-strlen(mp_basename(mpctx->filename))+strlen(playlist_entry)+1));
if (temp)
{
- strncpy(temp, filename, strlen(filename)-strlen(mp_basename(filename)));
- temp[strlen(filename)-strlen(mp_basename(filename))]='\0';
+ strncpy(temp, mpctx->filename, strlen(mpctx->filename)-strlen(mp_basename(mpctx->filename)));
+ temp[strlen(mpctx->filename)-strlen(mp_basename(mpctx->filename))]='\0';
strcat(temp, playlist_entry);
- if (!strcmp(temp, filename)) {
+ if (!strcmp(temp, mpctx->filename)) {
free(temp);
continue;
}
@@ -3362,20 +3717,25 @@ if (mpctx->demuxer && mpctx->demuxer->type==DEMUXER_TYPE_PLAYLIST)
{
entry = play_tree_new();
play_tree_set_child(entry,list);
- mpctx->eof=playtree_add_playlist(entry);
+ mpctx->stop_play = playtree_add_playlist(mpctx, entry);
goto goto_next_file;
}
}
if(!mpctx->demuxer)
goto goto_next_file;
-if(dvd_chapter>1) {
- float pts;
- if (demuxer_seek_chapter(mpctx->demuxer, dvd_chapter-1, 1, &pts, NULL, NULL) >= 0 && pts > -1.0)
- seek(mpctx, pts, SEEK_ABSOLUTE);
-}
-initialized_flags|=INITIALIZED_DEMUXER;
+ 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;
+ }
+
+mpctx->initialized_flags|=INITIALIZED_DEMUXER;
if (mpctx->stream->type != STREAMTYPE_DVD && mpctx->stream->type != STREAMTYPE_DVDNAV) {
int i;
@@ -3384,23 +3744,26 @@ if (mpctx->stream->type != STREAMTYPE_DVD && mpctx->stream->type != STREAMTYPE_D
mpctx->global_sub_indices[SUB_SOURCE_DEMUX] = mpctx->global_sub_size; // the global # of the first demux-specific sub.
for (i = 0; i < MAX_S_STREAMS; i++)
if (mpctx->demuxer->s_streams[i])
- maxid = FFMAX(maxid, ((sh_sub_t *)mpctx->demuxer->s_streams[i])->sid);
+ maxid = FFMAX(maxid, mpctx->demuxer->s_streams[i]->sid);
mpctx->global_sub_size += maxid + 1;
}
-// Make dvdsub_id always selectable if set.
-if (mpctx->global_sub_size <= mpctx->global_sub_indices[SUB_SOURCE_DEMUX] + dvdsub_id)
- mpctx->global_sub_size = mpctx->global_sub_indices[SUB_SOURCE_DEMUX] + dvdsub_id + 1;
+// Make opts->sub_id always selectable if set.
+if (mpctx->global_sub_size <= mpctx->global_sub_indices[SUB_SOURCE_DEMUX] + opts->sub_id)
+ mpctx->global_sub_size = mpctx->global_sub_indices[SUB_SOURCE_DEMUX] + opts->sub_id + 1;
#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);
- }
+if (opts->ass_enabled && ass_library) {
+ 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 (use_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
@@ -3417,7 +3780,7 @@ if (ts_prog) {
mp_property_do("switch_program", M_PROPERTY_SET, &tmp, mpctx);
}
// select audio stream
-select_audio(mpctx->demuxer, audio_id, audio_lang);
+select_audio(mpctx->demuxer, opts->audio_id, audio_lang);
// DUMP STREAMS:
if((stream_dump_type)&&(stream_dump_type<4)){
@@ -3431,8 +3794,8 @@ if((stream_dump_type)&&(stream_dump_type<4)){
case 3: ds=mpctx->d_sub;break;
}
if(!ds){
- mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_DumpSelectedStreamMissing);
- exit_player(EXIT_ERROR);
+ mp_tmsg(MSGT_CPLAYER,MSGL_FATAL,"dump: FATAL: Selected stream missing!\n");
+ exit_player(mpctx, EXIT_ERROR);
}
// disable other streams:
if(mpctx->d_audio && mpctx->d_audio!=ds) {ds_free_packs(mpctx->d_audio); mpctx->d_audio->id=-2; }
@@ -3441,8 +3804,8 @@ if((stream_dump_type)&&(stream_dump_type<4)){
// let's dump it!
f=fopen(stream_dump_name,"wb");
if(!f){
- mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_CantOpenDumpfile);
- exit_player(EXIT_ERROR);
+ mp_tmsg(MSGT_CPLAYER,MSGL_FATAL,"Cannot open dump file.\n");
+ exit_player(mpctx, EXIT_ERROR);
}
while(!ds->eof){
unsigned char* start;
@@ -3450,15 +3813,15 @@ if((stream_dump_type)&&(stream_dump_type<4)){
if( (mpctx->demuxer->file_format==DEMUXER_TYPE_AVI || mpctx->demuxer->file_format==DEMUXER_TYPE_ASF || mpctx->demuxer->file_format==DEMUXER_TYPE_MOV)
&& stream_dump_type==2) fwrite(&in_size,1,4,f);
if(in_size>0) fwrite(start,in_size,1,f);
- if(dvd_last_chapter>0) {
+ if (opts->chapterrange[1] > 0) {
int cur_chapter = demuxer_get_current_chapter(mpctx->demuxer);
- if(cur_chapter!=-1 && cur_chapter+1>dvd_last_chapter)
+ if(cur_chapter!=-1 && cur_chapter+1 > opts->chapterrange[1])
break;
}
}
fclose(f);
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_CoreDumped);
- exit_player_with_rc(EXIT_EOF, 0);
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"Core dumped ;)\n");
+ exit_player_with_rc(mpctx, EXIT_EOF, 0);
}
mpctx->sh_audio=mpctx->d_audio->sh;
@@ -3468,10 +3831,10 @@ if(mpctx->sh_video){
current_module="video_read_properties";
if(!video_read_properties(mpctx->sh_video)) {
- mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_CannotReadVideoProperties);
+ mp_tmsg(MSGT_CPLAYER,MSGL_ERR,"Video: Cannot read properties.\n");
mpctx->sh_video=mpctx->d_video->sh=NULL;
} else {
- mp_msg(MSGT_CPLAYER,MSGL_V,MSGTR_FilefmtFourccSizeFpsFtime,
+ mp_tmsg(MSGT_CPLAYER,MSGL_V,"[V] filefmt:%d fourcc:0x%X size:%dx%d fps:%5.3f ftime:=%6.4f\n",
mpctx->demuxer->file_format,mpctx->sh_video->format, mpctx->sh_video->disp_w,mpctx->sh_video->disp_h,
mpctx->sh_video->fps,mpctx->sh_video->frametime
);
@@ -3484,7 +3847,7 @@ if(mpctx->sh_video){
vo_fps = mpctx->sh_video->fps;
if(!mpctx->sh_video->fps && !force_fps){
- mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_FPSnotspecified);
+ mp_tmsg(MSGT_CPLAYER,MSGL_ERR,"FPS not specified in the header or invalid, use the -fps option.\n");
mpctx->sh_video=mpctx->d_video->sh=NULL;
}
}
@@ -3492,7 +3855,7 @@ if(mpctx->sh_video){
}
if(!mpctx->sh_video && !mpctx->sh_audio){
- mp_msg(MSGT_CPLAYER,MSGL_FATAL, MSGTR_NoStreamFound);
+ mp_tmsg(MSGT_CPLAYER,MSGL_FATAL, "No stream found.\n");
#ifdef CONFIG_DVBIN
if(mpctx->stream->type == STREAMTYPE_DVB)
{
@@ -3503,11 +3866,13 @@ if(!mpctx->sh_video && !mpctx->sh_audio){
else
dir = DVB_CHANNEL_LOWER;
- if(dvb_step_channel(mpctx->stream, dir))
- mpctx->eof = mpctx->dvbin_reopen = 1;
+ if(dvb_step_channel(mpctx->stream, dir)) {
+ mpctx->stop_play = PT_NEXT_ENTRY;
+ mpctx->dvbin_reopen = 1;
+ }
}
#endif
- goto goto_next_file; // exit_player(MSGTR_Exit_error);
+ goto goto_next_file; // exit_player(_("Fatal error"));
}
/* display clip info */
@@ -3516,26 +3881,25 @@ demux_info_print(mpctx->demuxer);
//================== Read SUBTITLES (DVD & TEXT) ==========================
if(vo_spudec==NULL &&
(mpctx->stream->type==STREAMTYPE_DVD || mpctx->stream->type == STREAMTYPE_DVDNAV)){
- init_vo_spudec();
+ init_vo_spudec(mpctx);
}
-if(1 || mpctx->sh_video) {
// after reading video params we should load subtitles because
// we know fps so now we can adjust subtitle time to ~6 seconds AST
// check .sub
- double fps = mpctx->sh_video ? mpctx->sh_video->fps : 25;
current_module="read_subtitles_file";
+ double sub_fps = mpctx->sh_video ? mpctx->sh_video->fps : 25;
if(sub_name){
for (i = 0; sub_name[i] != NULL; ++i)
- add_subtitles (sub_name[i], fps, 0);
+ add_subtitles(mpctx, sub_name[i], sub_fps, 0);
}
if(sub_auto) { // auto load sub file ...
char *psub = get_path( "sub/" );
- char **tmp = sub_filenames((psub ? psub : ""), filename);
+ char **tmp = sub_filenames((psub ? psub : ""), mpctx->filename);
int i = 0;
free(psub); // release the buffer created by get_path() above
while (tmp[i]) {
- add_subtitles (tmp[i], fps, 1);
+ add_subtitles(mpctx, tmp[i], sub_fps, 1);
free(tmp[i++]);
}
free(tmp);
@@ -3545,7 +3909,7 @@ if(1 || mpctx->sh_video) {
mpctx->global_sub_indices[SUB_SOURCE_SUBS] = mpctx->global_sub_size; // the global # of the first sub.
mpctx->global_sub_size += mpctx->set_of_sub_size;
}
-}
+
if (mpctx->global_sub_size) {
select_subtitle(mpctx);
@@ -3561,7 +3925,7 @@ if (mpctx->global_sub_size) {
}
mp_msg(MSGT_IDENTIFY,MSGL_INFO,"ID_FILENAME=%s\n",
- filename_recode(filename));
+ filename_recode(mpctx->filename));
mp_msg(MSGT_IDENTIFY,MSGL_INFO,"ID_DEMUXER=%s\n", mpctx->demuxer->desc->name);
if (mpctx->sh_video) {
/* Assume FOURCC if all bytes >= 0x20 (' ') */
@@ -3585,7 +3949,9 @@ if (mpctx->global_sub_size) {
mp_msg(MSGT_IDENTIFY,MSGL_INFO,"ID_AUDIO_RATE=%d\n", mpctx->sh_audio->samplerate);
mp_msg(MSGT_IDENTIFY,MSGL_INFO,"ID_AUDIO_NCH=%d\n", mpctx->sh_audio->channels);
}
- mp_msg(MSGT_IDENTIFY,MSGL_INFO,"ID_LENGTH=%.2lf\n", demuxer_get_time_length(mpctx->demuxer));
+ mp_msg(MSGT_IDENTIFY,MSGL_INFO,"ID_LENGTH=%.2f\n", mpctx->timeline ?
+ mpctx->timeline[mpctx->num_timeline_parts].start :
+ demuxer_get_time_length(mpctx->demuxer));
mp_msg(MSGT_IDENTIFY,MSGL_INFO,"ID_SEEKABLE=%d\n",
mpctx->stream->seek && (!mpctx->demuxer || mpctx->demuxer->seekable));
if (mpctx->demuxer) {
@@ -3596,14 +3962,14 @@ if (mpctx->global_sub_size) {
if(!mpctx->sh_video) goto main; // audio-only
-if(!reinit_video_chain()) {
+if(!reinit_video_chain(mpctx)) {
if(!mpctx->sh_video){
if(!mpctx->sh_audio) goto goto_next_file;
- goto main; // exit_player(MSGTR_Exit_error);
+ goto main; // exit_player(_("Fatal error"));
}
}
- if(vo_flags & 0x08 && vo_spudec)
+ if(mpctx->sh_video->output_flags & 0x08 && vo_spudec)
spudec_set_hw_spu(vo_spudec,mpctx->video_out);
#ifdef CONFIG_FREETYPE
@@ -3631,17 +3997,16 @@ if(verbose) term_osd = 0;
int frame_time_remaining=0; // flag
int blit_frame=0;
-mpctx->num_buffered_frames=0;
// Make sure old OSD does not stay around,
// e.g. with -fixed-vo and same-resolution files
clear_osd_msgs();
-update_osd_msg();
+update_osd_msg(mpctx);
//================ SETUP AUDIO ==========================
if(mpctx->sh_audio){
- reinit_audio_chain();
+ reinit_audio_chain(mpctx);
if (mpctx->sh_audio && mpctx->sh_audio->codec)
mp_msg(MSGT_IDENTIFY,MSGL_INFO, "ID_AUDIO_CODEC=%s\n", mpctx->sh_audio->codec->name);
}
@@ -3662,18 +4027,18 @@ if(mpctx->sh_audio){
}
if(!mpctx->sh_audio){
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_NoSound);
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"Audio: no sound\n");
mp_msg(MSGT_CPLAYER,MSGL_V,"Freeing %d unused audio chunks.\n",mpctx->d_audio->packs);
ds_free_packs(mpctx->d_audio); // free buffered chunks
//mpctx->d_audio->id=-2; // do not read audio chunks
- //uninit_player(INITIALIZED_AO); // close device
+ //uninit_player(mpctx, INITIALIZED_AO); // close device
}
if(!mpctx->sh_video){
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_Video_NoVideo);
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"Video: no video\n");
mp_msg(MSGT_CPLAYER,MSGL_V,"Freeing %d unused video chunks.\n",mpctx->d_video->packs);
ds_free_packs(mpctx->d_video);
mpctx->d_video->id=-2;
- //if(!fixed_vo) uninit_player(INITIALIZED_VO);
+ //if(!fixed_vo) uninit_player(mpctx, INITIALIZED_VO);
}
if (!mpctx->sh_video && !mpctx->sh_audio)
@@ -3683,48 +4048,44 @@ if (!mpctx->sh_video && !mpctx->sh_audio)
if(force_fps && mpctx->sh_video){
vo_fps = mpctx->sh_video->fps=force_fps;
mpctx->sh_video->frametime=1.0f/mpctx->sh_video->fps;
- mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_FPSforced,mpctx->sh_video->fps,mpctx->sh_video->frametime);
-}
-
-#ifdef CONFIG_GUI
-if ( use_gui ) {
- if ( mpctx->sh_audio ) guiIntfStruct.AudioType=mpctx->sh_audio->channels; else guiIntfStruct.AudioType=0;
- if ( !mpctx->sh_video && mpctx->sh_audio ) guiGetEvent( guiSetAudioOnly,(char *)1 ); else guiGetEvent( guiSetAudioOnly,(char *)0 );
- guiGetEvent( guiSetFileFormat,(char *)mpctx->demuxer->file_format );
- if ( guiGetEvent( guiSetValues,(char *)mpctx->sh_video ) ) goto goto_next_file;
- guiGetEvent( guiSetDemuxer,(char *)mpctx->demuxer );
+ mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"FPS forced to be %5.3f (ftime: %5.3f).\n",mpctx->sh_video->fps,mpctx->sh_video->frametime);
}
-#endif
-mp_input_set_section(NULL);
+ mp_input_set_section(mpctx->input, NULL);
//TODO: add desired (stream-based) sections here
-if (mpctx->stream->type==STREAMTYPE_TV) mp_input_set_section("tv");
-if (mpctx->stream->type==STREAMTYPE_DVDNAV) mp_input_set_section("dvdnav");
+ if (mpctx->stream->type==STREAMTYPE_TV) mp_input_set_section(mpctx->input, "tv");
+ if (mpctx->stream->type==STREAMTYPE_DVDNAV) mp_input_set_section(mpctx->input, "dvdnav");
//==================== START PLAYING =======================
-if(mpctx->loop_times>1) mpctx->loop_times--; else
-if(mpctx->loop_times==1) mpctx->loop_times = -1;
+if(opts->loop_times>1) opts->loop_times--; else
+if(opts->loop_times==1) opts->loop_times = -1;
-mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_StartPlaying);
+mp_tmsg(MSGT_CPLAYER,MSGL_INFO,"Starting playback...\n");
total_time_usage_start=GetTimer();
audio_time_usage=0; video_time_usage=0; vout_time_usage=0;
total_frame_cnt=0; drop_frame_cnt=0; // fix for multifile fps benchmark
play_n_frames=play_n_frames_mf;
-mpctx->startup_decode_retry = DEFAULT_STARTUP_DECODE_RETRY;
if(play_n_frames==0){
- mpctx->eof=PT_NEXT_ENTRY; goto goto_next_file;
+ mpctx->stop_play=PT_NEXT_ENTRY; goto goto_next_file;
}
-if (seek_to_sec) {
+// If there's a timeline force an absolute seek to initialize state
+if (seek_to_sec || mpctx->timeline) {
seek(mpctx, seek_to_sec, SEEK_ABSOLUTE);
end_at.pos += seek_to_sec;
}
+if (opts->chapterrange[0] > 0) {
+ double pts;
+ if (seek_chapter(mpctx, opts->chapterrange[0]-1, &pts, NULL) >= 0
+ && pts > -1.0)
+ seek(mpctx, pts, SEEK_ABSOLUTE);
+}
if (end_at.type == END_AT_SIZE) {
- mp_msg(MSGT_CPLAYER, MSGL_WARN, MSGTR_MPEndposNoSizeBased);
+ mp_tmsg(MSGT_CPLAYER, MSGL_WARN, "Option -endpos in MPlayer does not yet support size units.\n");
end_at.type = END_AT_NONE;
}
@@ -3736,28 +4097,39 @@ if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
}
#endif
-while(!mpctx->eof){
+ get_relative_time(mpctx); // reset current delta
+ mpctx->time_frame = 0;
+ mpctx->drop_message_shown = 0;
+ mpctx->update_video_immediately = true;
+ mpctx->total_avsync_change = 0;
+ mpctx->last_chapter_seek = -1;
+ // 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);
- if(cur_chapter!=-1 && cur_chapter+1>dvd_last_chapter)
+if (opts->chapterrange[1] > 0) {
+ int cur_chapter = get_current_chapter(mpctx);
+ if(cur_chapter!=-1 && cur_chapter+1 > opts->chapterrange[1])
goto goto_next_file;
}
if(!mpctx->sh_audio && mpctx->d_audio->sh) {
mpctx->sh_audio = mpctx->d_audio->sh;
mpctx->sh_audio->ds = mpctx->d_audio;
- reinit_audio_chain();
+ reinit_audio_chain(mpctx);
}
/*========================== PLAY AUDIO ============================*/
-if (mpctx->sh_audio)
- if (!fill_audio_out_buffers())
+if (mpctx->sh_audio && !mpctx->paused)
+ if (!fill_audio_out_buffers(mpctx))
// at eof, all audio at least written to ao
if (!mpctx->sh_video)
- mpctx->eof = PT_NEXT_ENTRY;
+ mpctx->stop_play = AT_END_OF_FILE;
if(!mpctx->sh_video) {
@@ -3765,16 +4137,16 @@ if(!mpctx->sh_video) {
double a_pos=0;
// sh_audio can be NULL due to video stream switching
// TODO: handle this better
- if((!quiet || end_at.type == END_AT_TIME) && mpctx->sh_audio)
- a_pos = playing_audio_pts(mpctx->sh_audio, mpctx->d_audio, mpctx->audio_out);
+ if (mpctx->sh_audio)
+ a_pos = playing_audio_pts(mpctx);
- if(!quiet)
- print_status(a_pos, 0, 0);
+ print_status(mpctx, a_pos, false);
if(end_at.type == END_AT_TIME && end_at.pos < a_pos)
- mpctx->eof = PT_NEXT_ENTRY;
- update_subtitles(NULL, a_pos, mpctx->d_sub, 0);
- update_osd_msg();
+ mpctx->stop_play = PT_NEXT_ENTRY;
+ update_subtitles(mpctx, &mpctx->opts, NULL, a_pos, mpctx->video_offset,
+ mpctx->d_sub, 0);
+ update_osd_msg(mpctx);
} else {
@@ -3783,28 +4155,46 @@ if(!mpctx->sh_video) {
vo_pts=mpctx->sh_video->timer*90000.0;
vo_fps=mpctx->sh_video->fps;
- if (!mpctx->num_buffered_frames) {
- double frame_time = update_video(&blit_frame);
- while (!blit_frame && mpctx->startup_decode_retry > 0) {
- double delay = mpctx->delay;
- // these initial decode failures are probably due to codec delay,
- // ignore them and also their probably nonsense durations
- update_video(&blit_frame);
- mpctx->delay = delay;
- mpctx->startup_decode_retry--;
- }
- mpctx->startup_decode_retry = 0;
+ blit_frame = mpctx->video_out->frame_loaded;
+ if (!blit_frame) {
+ double frame_time = update_video(mpctx);
+ blit_frame = mpctx->video_out->frame_loaded;
mp_dbg(MSGT_AVSYNC,MSGL_DBG2,"*** ftime=%5.3f ***\n",frame_time);
if (mpctx->sh_video->vf_initialized < 0) {
- mp_msg(MSGT_CPLAYER,MSGL_FATAL, MSGTR_NotInitializeVOPorVO);
- mpctx->eof = 1; goto goto_next_file;
+ mp_tmsg(MSGT_CPLAYER,MSGL_FATAL, "\nFATAL: Could not initialize video filters (-vf) or video output (-vo).\n");
+ mpctx->stop_play = PT_NEXT_ENTRY;
+ goto goto_next_file;
+ }
+ if (blit_frame) {
+ struct sh_video *sh_video = mpctx->sh_video;
+ update_subtitles(mpctx, &mpctx->opts, sh_video, sh_video->pts,
+ mpctx->video_offset, mpctx->d_sub, 0);
+ update_teletext(sh_video, mpctx->demuxer, 0);
+ update_osd_msg(mpctx);
+ struct vf_instance *vf = mpctx->sh_video->vfilter;
+ vf->control(vf, VFCTRL_DRAW_EOSD, NULL);
+ vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd);
+ vo_osd_changed(0);
}
if (frame_time < 0)
- mpctx->eof = 1;
+ mpctx->stop_play = AT_END_OF_FILE;
else {
- // might return with !eof && !blit_frame if !correct_pts
- mpctx->num_buffered_frames += blit_frame;
- mpctx->time_frame += frame_time / playback_speed; // for nosound
+ if (mpctx->update_video_immediately) {
+ // Show this frame immediately, rest normally
+ mpctx->update_video_immediately = false;
+ } else {
+ mpctx->time_frame += frame_time / opts->playback_speed;
+ adjust_sync(mpctx, frame_time);
+ }
+ }
+ }
+ 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;
}
}
@@ -3813,17 +4203,13 @@ if(!mpctx->sh_video) {
// current_module="draw_osd";
// if(vo_config_count) mpctx->video_out->draw_osd();
-#ifdef CONFIG_GUI
- if(use_gui) guiEventHandling();
-#endif
-
current_module="vo_check_events";
- if (vo_config_count) mpctx->video_out->check_events();
+ vo_check_events(mpctx->video_out);
#ifdef CONFIG_X11
if (stop_xscreensaver) {
current_module = "stop_xscreensaver";
- xscreensaver_heartbeat();
+ xscreensaver_heartbeat(mpctx->x11_state);
}
#endif
if (heartbeat_cmd) {
@@ -3835,22 +4221,42 @@ if(!mpctx->sh_video) {
}
}
- frame_time_remaining = sleep_until_update(&mpctx->time_frame, &aq_sleep_time);
+ frame_time_remaining = sleep_until_update(mpctx, &mpctx->time_frame, &aq_sleep_time);
//====================== FLIP PAGE (VIDEO BLT): =========================
current_module="flip_page";
if (!frame_time_remaining && blit_frame) {
unsigned int t2=GetTimer();
-
- if(vo_config_count) mpctx->video_out->flip_page();
- mpctx->num_buffered_frames--;
-
- vout_time_usage += (GetTimer() - t2) * 0.000001;
+ unsigned int pts_us = mpctx->last_time + mpctx->time_frame * 1e6;
+ int duration = -1;
+ double pts2 = mpctx->video_out->next_pts2;
+ if (pts2 != MP_NOPTS_VALUE && opts->correct_pts) {
+ // expected A/V sync correction is ignored
+ double diff = (pts2 - mpctx->sh_video->pts);
+ diff /= opts->playback_speed;
+ if (mpctx->time_frame < 0)
+ diff += mpctx->time_frame;
+ if (diff < 0)
+ diff = 0;
+ if (diff > 10)
+ diff = 10;
+ duration = diff * 1e6;
+ }
+ vo_flip_page(mpctx->video_out, pts_us|1, duration);
+
+ mpctx->last_vo_flip_duration = (GetTimer() - t2) * 0.000001;
+ vout_time_usage += mpctx->last_vo_flip_duration;
+ if (mpctx->video_out->driver->flip_page_timed) {
+ // No need to adjust sync based on flip speed
+ mpctx->last_vo_flip_duration = 0;
+ // For print_status - VO call finishing early is OK for sync
+ mpctx->time_frame -= get_relative_time(mpctx);
+ }
+ print_status(mpctx, MP_NOPTS_VALUE, true);
}
-//====================== A-V TIMESTAMP CORRECTION: =========================
-
- adjust_sync_and_print_status(frame_time_remaining, mpctx->time_frame);
+ else
+ print_status(mpctx, MP_NOPTS_VALUE, false);
//============================ Auto QUALITY ============================
@@ -3872,16 +4278,24 @@ if(auto_quality>0){
set_video_quality(mpctx->sh_video,output_quality);
}
- if (play_n_frames >= 0 && !frame_time_remaining && blit_frame) {
- --play_n_frames;
- if (play_n_frames <= 0) mpctx->eof = PT_NEXT_ENTRY;
+ if (!frame_time_remaining && blit_frame) {
+ if (play_n_frames >= 0) {
+ --play_n_frames;
+ if (play_n_frames <= 0)
+ mpctx->stop_play = PT_NEXT_ENTRY;
+ }
+ if (mpctx->step_frames > 0) {
+ mpctx->step_frames--;
+ if (mpctx->step_frames == 0)
+ pause_player(mpctx);
+ }
}
// FIXME: add size based support for -endpos
if (end_at.type == END_AT_TIME &&
!frame_time_remaining && end_at.pos <= mpctx->sh_video->pts)
- mpctx->eof = PT_NEXT_ENTRY;
+ mpctx->stop_play = PT_NEXT_ENTRY;
} // end if(mpctx->sh_video)
@@ -3902,102 +4316,81 @@ if(auto_quality>0){
}
#endif
-//============================ Handle PAUSE ===============================
-
- current_module="pause";
-
- if (mpctx->osd_function == OSD_PAUSE) {
- mpctx->was_paused = 1;
- pause_loop();
- }
-
-// handle -sstep
-if(step_sec>0) {
- mpctx->osd_function=OSD_FFW;
- rel_seek_secs+=step_sec;
-}
-
- edl_update(mpctx);
-
//================= Keyboard events, SEEKing ====================
current_module="key_events";
{
+ while (1) {
mp_cmd_t* cmd;
- int brk_cmd = 0;
- while( !brk_cmd && (cmd = mp_input_get_cmd(0,0,0)) != NULL) {
- brk_cmd = run_command(mpctx, cmd);
+ while ((cmd = mp_input_get_cmd(mpctx->input, 0, 0)) != NULL) {
+ run_command(mpctx, cmd);
mp_cmd_free(cmd);
- if (brk_cmd == 2)
- goto goto_enable_cache;
+ if (mpctx->stop_play)
+ break;
+ if (mpctx->rel_seek_secs || mpctx->abs_seek_pos) {
+ cmd = mp_input_get_cmd(mpctx->input, 0, 1);
+ /* Allow seek commands to be combined, but execute the real seek
+ * before processing other commands */
+ if (!cmd || cmd->id != MP_CMD_SEEK)
+ break;
+ }
+ }
+ if (!mpctx->paused || mpctx->stop_play || mpctx->rel_seek_secs
+ || mpctx->abs_seek_pos)
+ break;
+ if (mpctx->sh_video) {
+ update_osd_msg(mpctx);
+ int hack = vo_osd_changed(0);
+ vo_osd_changed(hack);
+ if (hack) {
+ if (redraw_osd(mpctx->sh_video, mpctx->osd) < 0) {
+ add_step_frame(mpctx);
+ break;
+ }
+ else
+ vo_osd_changed(0);
+ }
+ }
+ pause_loop(mpctx);
}
}
- mpctx->was_paused = 0;
+
+// handle -sstep
+if (step_sec > 0 && !mpctx->paused) {
+ mpctx->osd_function=OSD_FFW;
+ mpctx->rel_seek_secs+=step_sec;
+}
+
+ edl_update(mpctx);
/* Looping. */
- if(mpctx->eof==1 && mpctx->loop_times>=0) {
- mp_msg(MSGT_CPLAYER,MSGL_V,"loop_times = %d, eof = %d\n", mpctx->loop_times,mpctx->eof);
+ if(mpctx->stop_play==AT_END_OF_FILE && opts->loop_times>=0) {
+ mp_msg(MSGT_CPLAYER,MSGL_V,"loop_times = %d\n", opts->loop_times);
- if(mpctx->loop_times>1) mpctx->loop_times--; else
- if(mpctx->loop_times==1) mpctx->loop_times=-1;
+ if(opts->loop_times>1) opts->loop_times--; else
+ if(opts->loop_times==1) opts->loop_times=-1;
play_n_frames=play_n_frames_mf;
- mpctx->eof=0;
- abs_seek_pos=SEEK_ABSOLUTE; rel_seek_secs=seek_to_sec;
- loop_seek = 1;
+ mpctx->stop_play=0;
+ mpctx->abs_seek_pos=SEEK_ABSOLUTE; mpctx->rel_seek_secs=seek_to_sec;
}
-if(rel_seek_secs || abs_seek_pos){
- if (seek(mpctx, rel_seek_secs, abs_seek_pos) >= 0) {
- // Set OSD:
- if(!loop_seek){
- if( !edl_decision )
- set_osd_bar(0,"Position",0,100,demuxer_get_percent_pos(mpctx->demuxer));
- }
- }
+if(mpctx->rel_seek_secs || mpctx->abs_seek_pos){
+ seek(mpctx, mpctx->rel_seek_secs, mpctx->abs_seek_pos);
- rel_seek_secs=0;
- abs_seek_pos=0;
- loop_seek=0;
- edl_decision = 0;
+ mpctx->rel_seek_secs=0;
+ mpctx->abs_seek_pos=0;
}
-#ifdef CONFIG_GUI
- if(use_gui){
- guiEventHandling();
- if(mpctx->demuxer->file_format==DEMUXER_TYPE_AVI && mpctx->sh_video && mpctx->sh_video->video.dwLength>2){
- // get pos from frame number / total frames
- guiIntfStruct.Position=(float)mpctx->d_video->pack_no*100.0f/mpctx->sh_video->video.dwLength;
- } else {
- guiIntfStruct.Position=demuxer_get_percent_pos(mpctx->demuxer);
- }
- if ( mpctx->sh_video ) guiIntfStruct.TimeSec=mpctx->sh_video->pts;
- else if ( mpctx->sh_audio ) guiIntfStruct.TimeSec=playing_audio_pts(mpctx->sh_audio, mpctx->d_audio, mpctx->audio_out);
- guiIntfStruct.LengthInSec=demuxer_get_time_length(mpctx->demuxer);
- guiGetEvent( guiReDraw,NULL );
- guiGetEvent( guiSetVolume,NULL );
- if(guiIntfStruct.Playing==0) break; // STOP
- if(guiIntfStruct.Playing==2) mpctx->osd_function=OSD_PAUSE;
- if ( guiIntfStruct.DiskChanged || guiIntfStruct.NewPlay ) goto goto_next_file;
-#ifdef CONFIG_DVDREAD
- if ( mpctx->stream->type == STREAMTYPE_DVD )
- {
- dvd_priv_t * dvdp = mpctx->stream->priv;
- guiIntfStruct.DVD.current_chapter=dvd_chapter_from_cell(dvdp,guiIntfStruct.DVD.current_title-1, dvdp->cur_cell)+1;
- }
-#endif
- }
-#endif /* CONFIG_GUI */
-
-} // while(!mpctx->eof)
+} // while(!mpctx->stop_play)
-mp_msg(MSGT_GLOBAL,MSGL_V,"EOF code: %d \n",mpctx->eof);
+mp_msg(MSGT_GLOBAL,MSGL_V,"EOF code: %d \n",mpctx->stop_play);
#ifdef CONFIG_DVBIN
if(mpctx->dvbin_reopen)
{
- mpctx->eof = 0;
- uninit_player(INITIALIZED_ALL-(INITIALIZED_GUI|INITIALIZED_STREAM|INITIALIZED_INPUT|INITIALIZED_GETCH2|(fixed_vo?INITIALIZED_VO:0)));
+ mpctx->stop_play = 0;
+ uninit_player(mpctx, INITIALIZED_ALL-(INITIALIZED_STREAM|INITIALIZED_GETCH2|(opts->fixed_vo?INITIALIZED_VO:0)));
cache_uninit(mpctx->stream);
mpctx->dvbin_reopen = 0;
goto goto_enable_cache;
@@ -4035,7 +4428,7 @@ if(benchmark){
}
// time to uninit all, except global stuff:
-uninit_player(INITIALIZED_ALL-(INITIALIZED_GUI+INITIALIZED_INPUT+(fixed_vo?INITIALIZED_VO:0)));
+uninit_player(mpctx, INITIALIZED_ALL-(opts->fixed_vo?INITIALIZED_VO:0));
if(mpctx->set_of_sub_size > 0) {
current_module="sub_free";
@@ -4056,38 +4449,36 @@ if(ass_library)
ass_clear_fonts(ass_library);
#endif
-if(mpctx->eof == PT_NEXT_ENTRY || mpctx->eof == PT_PREV_ENTRY) {
- mpctx->eof = mpctx->eof == PT_NEXT_ENTRY ? 1 : -1;
- if(play_tree_iter_step(mpctx->playtree_iter,mpctx->play_tree_step,0) == PLAY_TREE_ITER_ENTRY) {
- mpctx->eof = 1;
- } else {
+ if (!mpctx->stop_play) // In case some goto jumped here...
+ mpctx->stop_play = PT_NEXT_ENTRY;
+
+int playtree_direction = 1;
+
+if(mpctx->stop_play == PT_NEXT_ENTRY || mpctx->stop_play == PT_PREV_ENTRY) {
+ if(play_tree_iter_step(mpctx->playtree_iter,mpctx->play_tree_step,0) != PLAY_TREE_ITER_ENTRY) {
play_tree_iter_free(mpctx->playtree_iter);
mpctx->playtree_iter = NULL;
}
mpctx->play_tree_step = 1;
-} else if(mpctx->eof == PT_UP_NEXT || mpctx->eof == PT_UP_PREV) {
- mpctx->eof = mpctx->eof == PT_UP_NEXT ? 1 : -1;
+} else if(mpctx->stop_play == PT_UP_NEXT || mpctx->stop_play == PT_UP_PREV) {
+ int direction = mpctx->stop_play == PT_UP_NEXT ? 1 : -1;
if(mpctx->playtree_iter) {
- if(play_tree_iter_up_step(mpctx->playtree_iter,mpctx->eof,0) == PLAY_TREE_ITER_ENTRY) {
- mpctx->eof = 1;
- } else {
+ if(play_tree_iter_up_step(mpctx->playtree_iter,direction,0) != PLAY_TREE_ITER_ENTRY) {
play_tree_iter_free(mpctx->playtree_iter);
mpctx->playtree_iter = NULL;
}
}
-} else if (mpctx->eof == PT_STOP) {
+} else if (mpctx->stop_play == PT_STOP) {
play_tree_iter_free(mpctx->playtree_iter);
mpctx->playtree_iter = NULL;
} else { // NEXT PREV SRC
- mpctx->eof = mpctx->eof == PT_PREV_SRC ? -1 : 1;
+ playtree_direction = mpctx->stop_play == PT_PREV_SRC ? -1 : 1;
}
-if(mpctx->eof == 0) mpctx->eof = 1;
-
while(mpctx->playtree_iter != NULL) {
- filename = play_tree_iter_get_file(mpctx->playtree_iter,mpctx->eof);
- if(filename == NULL) {
- if(play_tree_iter_step(mpctx->playtree_iter,mpctx->eof,0) != PLAY_TREE_ITER_ENTRY) {
+ mpctx->filename = play_tree_iter_get_file(mpctx->playtree_iter, playtree_direction);
+ if(mpctx->filename == NULL) {
+ if(play_tree_iter_step(mpctx->playtree_iter, playtree_direction, 0) != PLAY_TREE_ITER_ENTRY) {
play_tree_iter_free(mpctx->playtree_iter);
mpctx->playtree_iter = NULL;
};
@@ -4095,23 +4486,14 @@ while(mpctx->playtree_iter != NULL) {
break;
}
-#ifdef CONFIG_GUI
-if(use_gui && !mpctx->playtree_iter) {
-#ifdef CONFIG_DVDREAD
- if(!guiIntfStruct.DiskChanged)
-#endif
- mplEnd();
-}
-#endif
-
-if(use_gui || mpctx->playtree_iter != NULL || player_idle_mode){
- if(!mpctx->playtree_iter) filename = NULL;
- mpctx->eof = 0;
+if(mpctx->playtree_iter != NULL || player_idle_mode){
+ if(!mpctx->playtree_iter) mpctx->filename = NULL;
+ mpctx->stop_play = 0;
goto play_next_file;
}
-exit_player_with_rc(EXIT_EOF, 0);
+exit_player_with_rc(mpctx, EXIT_EOF, 0);
return 1;
}