int demux_seek(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags) { if (!demuxer->seekable) { if (demuxer->file_format == DEMUXER_TYPE_AVI) mp_tmsg(MSGT_SEEK, MSGL_WARN, "Cannot seek in raw AVI streams. (Index required, try with the -idx switch.)\n"); #ifdef CONFIG_TV else if (demuxer->file_format == DEMUXER_TYPE_TV) mp_tmsg(MSGT_SEEK, MSGL_WARN, "TV input is not seekable! (Seeking will probably be for changing channels ;)\n"); #endif else mp_tmsg(MSGT_SEEK, MSGL_WARN, "Cannot seek in this file.\n"); return 0; } // clear demux buffers: demux_flush(demuxer); demuxer->video->eof = 0; demuxer->audio->eof = 0; demuxer->sub->eof = 0; /* HACK: assume any demuxer used with these streams can cope with * the stream layer suddenly seeking to a different position under it * (nothing actually implements DEMUXER_CTRL_RESYNC now). */ struct stream *stream = demuxer->stream; if (stream->type == STREAMTYPE_DVD || stream->type == STREAMTYPE_DVDNAV) { double pts; if (flags & SEEK_ABSOLUTE) pts = 0.0f; else { if (demuxer->stream_pts == MP_NOPTS_VALUE) goto dmx_seek; pts = demuxer->stream_pts; } if (flags & SEEK_FACTOR) { double tmp = 0; if (stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &tmp) == STREAM_UNSUPPORTED) goto dmx_seek; pts += tmp * rel_seek_secs; } else pts += rel_seek_secs; if (stream_control(demuxer->stream, STREAM_CTRL_SEEK_TO_TIME, &pts) != STREAM_UNSUPPORTED) { demux_control(demuxer, DEMUXER_CTRL_RESYNC, NULL); return 1; } } dmx_seek: if (demuxer->desc->seek) demuxer->desc->seek(demuxer, rel_seek_secs, audio_delay, flags); return 1; }
int mp_get_cache_percent(struct MPContext *mpctx) { if (mpctx->stream) { int64_t size = -1; int64_t fill = -1; stream_control(mpctx->stream, STREAM_CTRL_GET_CACHE_SIZE, &size); stream_control(mpctx->stream, STREAM_CTRL_GET_CACHE_FILL, &fill); if (size > 0 && fill >= 0) return fill / (size / 100); } return -1; }
static int64_t mp_seek(void *opaque, int64_t pos, int whence) { demuxer_t *demuxer = opaque; stream_t *stream = demuxer->stream; int64_t current_pos; mp_msg(MSGT_HEADER,MSGL_DBG2,"mp_seek(%p, %"PRId64", %d)\n", stream, pos, whence); if(whence == SEEK_CUR) pos +=stream_tell(stream); else if(whence == SEEK_END && stream->end_pos > 0) pos += stream->end_pos; else if(whence == SEEK_SET) pos += stream->start_pos; else if(whence == AVSEEK_SIZE && stream->end_pos > 0) { uint64_t size; stream_control(stream, STREAM_CTRL_GET_SIZE, &size); if (size > stream->end_pos) stream->end_pos = size; return stream->end_pos - stream->start_pos; } else return -1; if(pos<0) return -1; current_pos = stream_tell(stream); if(stream_seek(stream, pos)==0) { stream_reset(stream); stream_seek(stream, current_pos); return -1; } return pos - stream->start_pos; }
int demuxer_seek_chapter(demuxer_t *demuxer, int chapter, double *seek_pts) { int ris; if (!demuxer->num_chapters || !demuxer->chapters) { demux_flush(demuxer); ris = stream_control(demuxer->stream, STREAM_CTRL_SEEK_TO_CHAPTER, &chapter); if (ris != STREAM_UNSUPPORTED) demux_control(demuxer, DEMUXER_CTRL_RESYNC, NULL); // exit status may be ok, but main() doesn't have to seek itself // (because e.g. dvds depend on sectors, not on pts) *seek_pts = -1.0; return ris != STREAM_UNSUPPORTED ? chapter : -1; } else { // chapters structure is set in the demuxer if (chapter >= demuxer->num_chapters) return -1; if (chapter < 0) chapter = 0; *seek_pts = demuxer->chapters[chapter].start / 1e9; return chapter; } }
static int open_f(stream_t *stream) { stream->fill_buffer = fill_buffer; stream->seek = seek; stream->seekable = true; stream->control = control; stream->read_chunk = 1024 * 1024; struct priv *p = talloc_zero(stream, struct priv); stream->priv = p; // Initial data bstr data = bstr0(stream->url); bool use_hex = bstr_eatstart0(&data, "hex://"); if (!use_hex) bstr_eatstart0(&data, "memory://"); stream_control(stream, STREAM_CTRL_SET_CONTENTS, &data); if (use_hex && !bstr_decode_hex(stream, p->data, &p->data)) { MP_FATAL(stream, "Invalid data.\n"); return STREAM_ERROR; } return STREAM_OK; }
bool mp_get_cache_idle(struct MPContext *mpctx) { int idle = 0; if (mpctx->stream) stream_control(mpctx->stream, STREAM_CTRL_GET_CACHE_IDLE, &idle); return idle; }
// Runs in the cache thread static void cache_execute_control(struct priv *s) { uint64_t old_pos = stream_tell(s->stream); s->control_flush = false; switch (s->control) { case STREAM_CTRL_SET_CACHE_SIZE: s->control_res = resize_cache(s, *(int64_t *)s->control_arg); break; default: s->control_res = stream_control(s->stream, s->control, s->control_arg); } bool pos_changed = old_pos != stream_tell(s->stream); bool ok = s->control_res == STREAM_OK; if (pos_changed && !ok) { MP_ERR(s, "STREAM_CTRL changed stream pos but " "returned error, this is not allowed!\n"); } else if (pos_changed || (ok && control_needs_flush(s->control))) { MP_VERBOSE(s, "Dropping cache due to control()\n"); s->read_filepos = stream_tell(s->stream); s->control_flush = true; cache_drop_contents(s); } update_cached_controls(s); s->control = CACHE_CTRL_NONE; pthread_cond_signal(&s->wakeup); }
void stream_dump(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; char *filename = opts->stream_dump; stream_t *stream = mpctx->stream; assert(stream && filename); int64_t size = 0; stream_control(stream, STREAM_CTRL_GET_SIZE, &size); stream_set_capture_file(stream, filename); while (mpctx->stop_play == KEEP_PLAYING && !stream->eof) { if (!opts->quiet && ((stream->pos / (1024 * 1024)) % 2) == 1) { uint64_t pos = stream->pos; MP_MSG(mpctx, MSGL_STATUS, "Dumping %lld/%lld...", (long long int)pos, (long long int)size); } stream_fill_buffer(stream); for (;;) { mp_cmd_t *cmd = mp_input_get_cmd(mpctx->input, 0, false); if (!cmd) break; run_command(mpctx, cmd); talloc_free(cmd); } } }
void mp_nav_reset(struct MPContext *mpctx) { struct mp_nav_state *nav = mpctx->nav_state; if (!nav) return; struct mp_nav_cmd inp = {MP_NAV_CMD_RESUME}; stream_control(mpctx->stream, STREAM_CTRL_NAV_CMD, &inp); osd_set_nav_highlight(mpctx->osd, NULL); nav->hi_visible = 0; nav->nav_menu = false; nav->nav_draining = false; nav->nav_still_frame = 0; mp_input_disable_section(mpctx->input, "discnav-menu"); // Prevent demuxer init code to seek to the "start" mpctx->stream->start_pos = stream_tell(mpctx->stream); stream_control(mpctx->stream, STREAM_CTRL_RESUME_CACHE, NULL); }
int demuxer_get_current_angle(demuxer_t *demuxer) { int ris, curr_angle = -1; ris = stream_control(demuxer->stream, STREAM_CTRL_GET_ANGLE, &curr_angle); if (ris == STREAM_UNSUPPORTED) return -1; return curr_angle; }
static void update_cached_controls(struct priv *s) { unsigned int ui; int64_t i64; double d; char **m; char *t; s->stream_time_length = 0; if (stream_control(s->stream, STREAM_CTRL_GET_TIME_LENGTH, &d) == STREAM_OK) s->stream_time_length = d; s->stream_start_time = MP_NOPTS_VALUE; if (stream_control(s->stream, STREAM_CTRL_GET_START_TIME, &d) == STREAM_OK) s->stream_start_time = d; s->stream_manages_timeline = false; if (stream_control(s->stream, STREAM_CTRL_MANAGES_TIMELINE, NULL) == STREAM_OK) s->stream_manages_timeline = true; s->stream_num_chapters = 0; if (stream_control(s->stream, STREAM_CTRL_GET_NUM_CHAPTERS, &ui) == STREAM_OK) s->stream_num_chapters = ui; if (stream_control(s->stream, STREAM_CTRL_GET_METADATA, &m) == STREAM_OK) { talloc_free(s->stream_metadata); s->stream_metadata = talloc_steal(s, m); } if (stream_control(s->stream, STREAM_CTRL_GET_DISC_NAME, &t) == STREAM_OK) { talloc_free(s->disc_name); s->disc_name = talloc_steal(s, t); } s->stream_size = -1; if (stream_control(s->stream, STREAM_CTRL_GET_SIZE, &i64) == STREAM_OK) s->stream_size = i64; }
// If a demuxer is accessing the stream, we have to use demux_stream_control() // to avoid synchronization issues; otherwise access it directly. static int run_stream_control(struct MPContext *mpctx, int cmd, void *arg) { if (mpctx->demuxer) { return demux_stream_control(mpctx->demuxer, cmd, arg); } else if (mpctx->stream) { return stream_control(mpctx->stream, cmd, arg); } return STREAM_ERROR; }
static void update_cached_controls(struct priv *s) { int64_t i64; double d; struct mp_tags *tags; s->stream_time_length = 0; if (stream_control(s->stream, STREAM_CTRL_GET_TIME_LENGTH, &d) == STREAM_OK) s->stream_time_length = d; if (stream_control(s->stream, STREAM_CTRL_GET_METADATA, &tags) == STREAM_OK) { talloc_free(s->stream_metadata); s->stream_metadata = talloc_steal(s, tags); } s->stream_size = s->eof_pos; i64 = stream_get_size(s->stream); if (i64 >= 0) s->stream_size = i64; s->has_avseek = stream_control(s->stream, STREAM_CTRL_HAS_AVSEEK, NULL) > 0; }
int demuxer_angles_count(demuxer_t *demuxer) { int ris, angles = -1; ris = stream_control(demuxer->stream, STREAM_CTRL_GET_NUM_ANGLES, &angles); if (ris == STREAM_UNSUPPORTED) return -1; return angles; }
int demuxer_chapter_count(demuxer_t *demuxer) { if (!demuxer->num_chapters || !demuxer->chapters) { int num_chapters = 0; if (stream_control(demuxer->stream, STREAM_CTRL_GET_NUM_CHAPTERS, &num_chapters) == STREAM_UNSUPPORTED) num_chapters = 0; return num_chapters; } else return demuxer->num_chapters; }
void mp_nav_user_input(struct MPContext *mpctx, char *command) { struct mp_nav_state *nav = mpctx->nav_state; if (!nav) return; if (strcmp(command, "mouse_move") == 0) { struct mp_image_params vid = {0}; if (mpctx->d_video) vid = mpctx->d_video->decoder_output; struct mp_nav_cmd inp = {MP_NAV_CMD_MOUSE_POS}; int x, y; mp_input_get_mouse_pos(mpctx->input, &x, &y); osd_coords_to_video(mpctx->osd, vid.w, vid.h, &x, &y); inp.u.mouse_pos.x = x; inp.u.mouse_pos.y = y; stream_control(mpctx->stream, STREAM_CTRL_NAV_CMD, &inp); } else { struct mp_nav_cmd inp = {MP_NAV_CMD_MENU}; inp.u.menu.action = command; stream_control(mpctx->stream, STREAM_CTRL_NAV_CMD, &inp); } }
static int64_t mp_read_seek(void *opaque, int stream_idx, int64_t ts, int flags) { demuxer_t *demuxer = opaque; stream_t *stream = demuxer->stream; lavf_priv_t *priv = demuxer->priv; AVStream *st = priv->avfc->streams[stream_idx]; int ret; double pts; pts = (double)ts * st->time_base.num / st->time_base.den; ret = stream_control(stream, STREAM_CTRL_SEEK_TO_TIME, &pts); if (ret < 0) ret = AVERROR(ENOSYS); return ret; }
int demuxer_get_current_chapter(demuxer_t *demuxer, double time_now) { int chapter = -2; if (!demuxer->num_chapters || !demuxer->chapters) { if (stream_control(demuxer->stream, STREAM_CTRL_GET_CURRENT_CHAPTER, &chapter) == STREAM_UNSUPPORTED) chapter = -2; } else { uint64_t now = time_now * 1e9 + 0.5; for (chapter = demuxer->num_chapters - 1; chapter >= 0; --chapter) { if (demuxer->chapters[chapter].start <= now) break; } } return chapter; }
static int fill_buffer(stream_t *s, char *buffer, int max_len) { struct priv *p = s->priv; if (s->pos < 0) return -1; if (s->pos >= p->max_size) { if (stream_seek(p->original, s->pos) < 1) return -1; return stream_read(p->original, buffer, max_len); } // Size of file changes -> invalidate last block if (s->pos >= p->size - BLOCK_SIZE) { int64_t new_size = -1; stream_control(s, STREAM_CTRL_GET_SIZE, &new_size); if (new_size != p->size) set_bit(p, BLOCK_ALIGN(p->size), 0); p->size = MPMIN(p->max_size, new_size); } int64_t aligned = BLOCK_ALIGN(s->pos); if (!test_bit(p, aligned)) { char tmp[BLOCK_SIZE]; stream_seek(p->original, aligned); int r = stream_read(p->original, tmp, BLOCK_SIZE); if (r < BLOCK_SIZE) { if (p->size < 0) { MP_WARN(s, "suspected EOF\n"); } else if (aligned + r < p->size) { MP_ERR(s, "unexpected EOF\n"); return -1; } } if (fseeko(p->cache_file, aligned, SEEK_SET)) return -1; if (fwrite(tmp, r, 1, p->cache_file) != 1) return -1; set_bit(p, aligned, 1); } if (fseeko(p->cache_file, s->pos, SEEK_SET)) return -1; // align/limit to blocks max_len = MPMIN(max_len, BLOCK_SIZE - (s->pos % BLOCK_SIZE)); // Limit to max. known file size max_len = MPMIN(max_len, p->size - s->pos); return fread(buffer, 1, max_len, p->cache_file); }
static int d_open(demuxer_t *demuxer, enum demux_check check) { struct priv *p = demuxer->priv = talloc_zero(demuxer, struct priv); if (check != DEMUX_CHECK_FORCE) return -1; char *demux = "+lavf"; if (demuxer->stream->uncached_type == STREAMTYPE_CDDA) demux = "+rawaudio"; char *t = NULL; stream_control(demuxer->stream, STREAM_CTRL_GET_DISC_NAME, &t); if (t) { mp_tags_set_bstr(demuxer->metadata, bstr0("TITLE"), bstr0(t)); talloc_free(t); } // Initialize the playback time. We need to read _some_ data to get the // correct stream-layer time (at least with libdvdnav). stream_peek(demuxer->stream, 1); reset_pts(demuxer); p->slave = demux_open(demuxer->stream, demux, NULL, demuxer->global); if (!p->slave) return -1; // So that we don't miss initial packets of delayed subtitle streams. demux_set_stream_autoselect(p->slave, true); // Can be seekable even if the stream isn't. demuxer->seekable = true; // With cache enabled, the stream can be seekable. This causes demux_lavf.c // (actually libavformat/mpegts.c) to seek sometimes when reading a packet. // It does this to seek back a bit in case the current file position points // into the middle of a packet. demuxer->stream->seekable = false; add_dvd_streams(demuxer); add_streams(demuxer); add_stream_chapters(demuxer); return 0; }
int demuxer_set_angle(demuxer_t *demuxer, int angle) { int ris, angles = -1; angles = demuxer_angles_count(demuxer); if ((angles < 1) || (angle > angles)) return -1; demux_flush(demuxer); ris = stream_control(demuxer->stream, STREAM_CTRL_SET_ANGLE, &angle); if (ris == STREAM_UNSUPPORTED) return -1; demux_control(demuxer, DEMUXER_CTRL_RESYNC, NULL); return angle; }
static int open_f(stream_t *stream, int mode, void* opts, int* file_format) { stream->type = STREAMTYPE_MEMORY; stream->fill_buffer = fill_buffer; stream->seek = seek; stream->control = control; stream->read_chunk = 1024 * 1024; struct priv *p = talloc_zero(stream, struct priv); stream->priv = p; // Initial data bstr data = bstr0(stream->url); bstr_eatstart0(&data, "memory://"); stream_control(stream, STREAM_CTRL_SET_CONTENTS, &data); return STREAM_OK; }
static int d_control(demuxer_t *demuxer, int cmd, void *arg) { struct priv *p = demuxer->priv; switch (cmd) { case DEMUXER_CTRL_GET_TIME_LENGTH: { double len; if (stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &len) < 1) break; *(double *)arg = len; return DEMUXER_CTRL_OK; } case DEMUXER_CTRL_RESYNC: demux_flush(p->slave); break; // relay to slave demuxer case DEMUXER_CTRL_SWITCHED_TRACKS: reselect_streams(demuxer); return DEMUXER_CTRL_OK; } return demux_control(p->slave, cmd, arg); }
// Allocate state and enable navigation features. Must happen before // initializing cache, because the cache would read data. Since stream_dvdnav is // in a mode which skips all transitions on reading data (before enabling // navigation), this would skip some menu screens. void mp_nav_init(struct MPContext *mpctx) { assert(!mpctx->nav_state); // dvdnav is interactive if (mpctx->encode_lavc_ctx) return; struct mp_nav_cmd inp = {MP_NAV_CMD_ENABLE}; if (stream_control(mpctx->stream, STREAM_CTRL_NAV_CMD, &inp) < 1) return; mpctx->nav_state = talloc_zero(NULL, struct mp_nav_state); mpctx->nav_state->log = mp_log_new(mpctx->nav_state, mpctx->log, "discnav"); MP_VERBOSE(mpctx->nav_state, "enabling\n"); mp_input_enable_section(mpctx->input, "discnav", 0); mp_input_set_section_mouse_area(mpctx->input, "discnav-menu", INT_MIN, INT_MIN, INT_MAX, INT_MAX); }
// Runs in the cache thread static void cache_execute_control(struct priv *s) { uint64_t old_pos = stream_tell(s->stream); s->control_res = stream_control(s->stream, s->control, s->control_arg); s->control_flush = false; bool pos_changed = old_pos != stream_tell(s->stream); bool ok = s->control_res == STREAM_OK; if (pos_changed && !ok) { mp_msg(MSGT_STREAM, MSGL_ERR, "STREAM_CTRL changed stream pos but " "returned error, this is not allowed!\n"); } else if (pos_changed || (ok && control_needs_flush(s->control))) { mp_msg(MSGT_CACHE, MSGL_V, "Dropping cache due to control()\n"); s->read_filepos = stream_tell(s->stream); s->control_flush = true; cache_drop_contents(s); } s->control = CACHE_CTRL_NONE; pthread_cond_signal(&s->wakeup); }
static int64_t mp_seek(void *opaque, int64_t pos, int whence) { muxer_t *muxer = opaque; if(whence == SEEK_CUR) { off_t cur = stream_tell(muxer->stream); if(cur == -1) return -1; pos += cur; } else if(whence == SEEK_END) { uint64_t size=0; if(stream_control(muxer->stream, STREAM_CTRL_GET_SIZE, &size) == STREAM_UNSUPPORTED || size < pos) return -1; pos = size - pos; } mp_msg(MSGT_MUXER, MSGL_DBG2, "SEEK %"PRIu64"\n", (int64_t)pos); if(!stream_seek(muxer->stream, pos)) return -1; return 0; }
void stream_dump(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; char *filename = opts->stream_dump; stream_t *stream = mpctx->stream; assert(stream && filename); int64_t size = 0; stream_control(stream, STREAM_CTRL_GET_SIZE, &size); stream_set_capture_file(stream, filename); while (mpctx->stop_play == KEEP_PLAYING && !stream->eof) { if (!opts->quiet && ((stream->pos / (1024 * 1024)) % 2) == 1) { uint64_t pos = stream->pos; MP_MSG(mpctx, MSGL_STATUS, "Dumping %lld/%lld...", (long long int)pos, (long long int)size); } stream_fill_buffer(stream); mp_process_input(mpctx); } }
static void set_dvdsub_fake_extradata(struct dec_sub *dec_sub, struct stream *st, int width, int height) { if (!st) return; struct stream_dvd_info_req info; if (stream_control(st, STREAM_CTRL_GET_DVD_INFO, &info) < 0) return; struct mp_csp_params csp = MP_CSP_PARAMS_DEFAULTS; csp.int_bits_in = 8; csp.int_bits_out = 8; float cmatrix[3][4]; mp_get_yuv2rgb_coeffs(&csp, cmatrix); if (width == 0 || height == 0) { width = 720; height = 480; } char *s = NULL; s = talloc_asprintf_append(s, "size: %dx%d\n", width, height); s = talloc_asprintf_append(s, "palette: "); for (int i = 0; i < 16; i++) { int color = info.palette[i]; int c[3] = {(color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff}; mp_map_int_color(cmatrix, 8, c); color = (c[2] << 16) | (c[1] << 8) | c[0]; if (i != 0) talloc_asprintf_append(s, ", "); s = talloc_asprintf_append(s, "%06x", color); } s = talloc_asprintf_append(s, "\n"); sub_set_extradata(dec_sub, s, strlen(s)); talloc_free(s); }
/* this function gets called by mplayer to update the gui */ int gui(int what, void *data) { stream_t *stream = data; #ifdef CONFIG_DVDREAD dvd_priv_t *dvdp; #endif if(!mygui || !mygui->skin) return 0; if(guiInfo.mpcontext) { audio_out = mpctx_get_audio_out(guiInfo.mpcontext); video_out = mpctx_get_video_out(guiInfo.mpcontext); mixer = mpctx_get_mixer(guiInfo.mpcontext); playtree = mpctx_get_playtree_iter(guiInfo.mpcontext); } switch (what) { case GUI_PREPARE: { audio_id = -1; video_id = -1; dvdsub_id = -1; vobsub_id = -1; stream_cache_size = -1; autosync = 0; force_fps = 0; if(!mygui->playlist->tracks) return 0; switch(guiInfo.StreamType) { case STREAMTYPE_FILE: case STREAMTYPE_STREAM: uiSetFileName(NULL, mygui->playlist->tracks[mygui->playlist->current]->filename, SAME_STREAMTYPE); guiInfo.Track = mygui->playlist->current + 1; break; case STREAMTYPE_DVD: { char tmp[512]; #ifdef CONFIG_DVDREAD dvd_chapter = guiInfo.Chapter; dvd_angle = guiInfo.Angle; #endif sprintf(tmp,"dvd://%d", guiInfo.Track); uiSetFileName(NULL, tmp, SAME_STREAMTYPE); break; } } guiInfo.VideoWindow = 1; if(gtkAONorm) listRepl(&af_cfg.list, "volnorm", "volnorm"); if(gtkAOExtraStereo) { char *name = malloc(12 + 20 + 1); snprintf(name, 12 + 20, "extrastereo=%f", gtkAOExtraStereoMul); name[12 + 20] = 0; listRepl(&af_cfg.list, "extrastereo", name); free(name); } if(gtkCacheOn) stream_cache_size = gtkCacheSize; if(gtkAutoSyncOn) autosync = gtkAutoSync; guiInfo.NewPlay = 0; break; } case GUI_SET_AUDIO: { if (data && !guiInfo.sh_video) guiInfo.VideoWindow = 0; if(IsWindowVisible(mygui->videowindow) && !guiInfo.VideoWindow) ShowWindow(mygui->videowindow, SW_HIDE); break; } case GUI_SET_CONTEXT: guiInfo.mpcontext = data; break; case GUI_SET_VIDEO: { guiInfo.sh_video = data; if (data) { sh_video_t *sh = data; codecname = sh->codec->name; /* we have video, show the video window */ if(!IsWindowVisible(mygui->videowindow) || IsIconic(mygui->videowindow)) ShowWindow(mygui->videowindow, SW_SHOWNORMAL); if(WinID == -1) update_videowindow(); } break; } case GUI_SETUP_VIDEO_WINDOW: { guiInfo.VideoWidth = vo_dwidth; guiInfo.VideoHeight = vo_dheight; video_aspect = (float)guiInfo.VideoWidth/guiInfo.VideoHeight; if(WinID != -1) update_videowindow(); break; } case GUI_SET_STREAM: { guiInfo.StreamType = stream->type; switch(stream->type) { case STREAMTYPE_DVD: guiInfo.Tracks = 0; stream_control(stream, STREAM_CTRL_GET_NUM_TITLES, &guiInfo.Tracks); guiInfo.Chapters = 0; stream_control(stream, STREAM_CTRL_GET_NUM_CHAPTERS, &guiInfo.Chapters); guiInfo.Angles = 0; stream_control(stream, STREAM_CTRL_GET_NUM_ANGLES, &guiInfo.Angles); guiInfo.Track = 0; stream_control(stream, STREAM_CTRL_GET_CURRENT_TITLE, &guiInfo.Track); guiInfo.Track++; // guiInfo.Chapter will be set by mplayer guiInfo.Angle = 1; stream_control(stream, STREAM_CTRL_GET_ANGLE, &guiInfo.Angle); #ifdef CONFIG_DVDREAD dvdp = stream->priv; guiInfo.AudioStreams = dvdp->nr_of_channels; memcpy(guiInfo.AudioStream, dvdp->audio_streams, sizeof(dvdp->audio_streams)); guiInfo.Subtitles = dvdp->nr_of_subtitles; memcpy(guiInfo.Subtitle, dvdp->subtitles, sizeof(dvdp->subtitles)); #endif break; } break; } case GUI_REDRAW: mygui->updatedisplay(mygui, mygui->mainwindow); break; case GUI_SET_AFILTER: guiInfo.afilter = data; break; case GUI_SET_STATE: { guiInfo.Playing = (int) data; switch (guiInfo.Playing) { case GUI_PLAY: { guiInfo.Playing = GUI_PLAY; break; } case GUI_STOP: { guiInfo.Playing = GUI_STOP; if(movie_aspect >= 0) movie_aspect = -1; update_videowindow(); break; } case GUI_PAUSE: guiInfo.Playing = GUI_PAUSE; break; } break; } case GUI_RUN_COMMAND: { mp_msg(MSGT_GPLAYER,MSGL_V, "cmd: %d\n", (int) data); /* MPlayer asks us to quit */ switch((int) data) { case MP_CMD_VO_FULLSCREEN: uiFullScreen(); break; case MP_CMD_QUIT: { mygui->uninit(mygui); nfree(mygui); exit_player(EXIT_QUIT); return 1; } case MP_CMD_PLAY_TREE_STEP: guiSetEvent(evNext); break; case -MP_CMD_PLAY_TREE_STEP: guiSetEvent(evPrev); break; case MP_CMD_STOP: guiSetEvent(evStop); break; default: break; } break; } case GUI_RUN_MESSAGE: break; case GUI_HANDLE_EVENTS: break; case GUI_SET_MIXER: { if(audio_out) { /* Some audio_out drivers do not support balance e.g. dsound */ /* FIXME this algo is not correct */ float l, r; mixer_getvolume(mixer, &l, &r); guiInfo.Volume = (r > l ? r : l); /* max(r,l) */ if (r != l) guiInfo.Balance = ((r-l) + 100.0f) * 0.5f; else guiInfo.Balance = 50.0f; } break; } case GUI_END_FILE: { if(!uiGotoTheNext && guiInfo.Playing) { uiGotoTheNext = 1; break; } if(uiGotoTheNext && guiInfo.Playing && (mygui->playlist->current < (mygui->playlist->trackcount - 1)) && guiInfo.StreamType != STREAMTYPE_DVD && guiInfo.StreamType != STREAMTYPE_DVDNAV) { /* we've finished this file, reset the aspect */ if(movie_aspect >= 0) movie_aspect = -1; uiGotoTheNext = 1; guiInfo.NewPlay = GUI_FILE_NEW; uiSetFileName(NULL, mygui->playlist->tracks[(mygui->playlist->current)++]->filename, STREAMTYPE_FILE); //sprintf(guiInfo.Filename, mygui->playlist->tracks[(mygui->playlist->current)++]->filename); } if(guiInfo.NewPlay == GUI_FILE_NEW) break; guiInfo.ElapsedTime = 0; guiInfo.Position = 0; guiInfo.AudioChannels = 0; guiInfo.Track = 1; guiInfo.Chapter = 1; guiInfo.Angle = 1; if (mygui->playlist->current == (mygui->playlist->trackcount - 1)) mygui->playlist->current = 0; fullscreen = 0; if(style == (WS_VISIBLE | WS_POPUP)) { style = WS_OVERLAPPEDWINDOW | WS_SIZEBOX; SetWindowLong(mygui->videowindow, GWL_STYLE, style); } gui(GUI_SET_STATE, (void *) GUI_STOP); break; } default: mp_msg(MSGT_GPLAYER, MSGL_ERR, "[GUI] GOT UNHANDLED EVENT %i\n", what); } return 1; }
/** * @brief Convert #guiInfo member Filename. * * @param how 0 (cut file path and extension), * 1 (additionally, convert lower case) or * 2 (additionally, convert upper case) or * 4 (unaltered title if available, otherwise like 0) * @param fname memory location of a buffer to receive the converted Filename * @param maxlen size of the @a fname buffer * * @return pointer to the @a fname buffer */ static char *TranslateFilename (int how, char *fname, size_t maxlen) { char *p; size_t len; stream_t *stream; switch (guiInfo.StreamType) { case STREAMTYPE_FILE: if ((how == 4) && guiInfo.Title) av_strlcpy(fname, guiInfo.Title, maxlen); else if (guiInfo.Filename && *guiInfo.Filename) { p = strrchr(guiInfo.Filename, '\\'); if (p) av_strlcpy(fname, p + 1, maxlen); else av_strlcpy(fname, guiInfo.Filename, maxlen); len = strlen(fname); if (len > 3 && fname[len - 3] == '.') fname[len - 3] = 0; else if (len > 4 && fname[len - 4] == '.') fname[len - 4] = 0; else if (len > 5 && fname[len - 5] == '.') fname[len - 5] = 0; } else av_strlcpy(fname, MSGTR_GUI_MSG_NoFileLoaded, maxlen); break; case STREAMTYPE_STREAM: av_strlcpy(fname, guiInfo.Filename, maxlen); break; case STREAMTYPE_CDDA: snprintf(fname, maxlen, MSGTR_GUI_TitleN, guiInfo.Track); break; case STREAMTYPE_VCD: snprintf(fname, maxlen, MSGTR_GUI_TitleN, guiInfo.Track - 1); break; case STREAMTYPE_DVD: if (guiInfo.Chapter) snprintf(fname, maxlen, MSGTR_GUI_ChapterN, guiInfo.Chapter); else av_strlcpy(fname, MSGTR_GUI_NoChapter, maxlen); break; case STREAMTYPE_TV: case STREAMTYPE_DVB: p = MSGTR_GUI_NoChannelName; stream = mpctx_get_stream(guiInfo.mpcontext); if (stream) stream_control(stream, STREAM_CTRL_GET_CURRENT_CHANNEL, &p); av_strlcpy(fname, p, maxlen); break; default: av_strlcpy(fname, MSGTR_GUI_MSG_NoMediaOpened, maxlen); break; } if (how == 1) strlower(fname); if (how == 2) strupper(fname); return fname; }