1
by Grevutiu Gabriel
original source code upstream |
1 |
/*
|
2 |
* This file is part of MPlayer.
|
|
3 |
*
|
|
4 |
* MPlayer is free software; you can redistribute it and/or modify
|
|
5 |
* it under the terms of the GNU General Public License as published by
|
|
6 |
* the Free Software Foundation; either version 2 of the License, or
|
|
7 |
* (at your option) any later version.
|
|
8 |
*
|
|
9 |
* MPlayer is distributed in the hope that it will be useful,
|
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 |
* GNU General Public License for more details.
|
|
13 |
*
|
|
14 |
* You should have received a copy of the GNU General Public License along
|
|
15 |
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
|
16 |
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
17 |
*/
|
|
18 |
||
19 |
#define _BSD_SOURCE
|
|
20 |
||
21 |
#include <stdlib.h> |
|
22 |
#include <inttypes.h> |
|
23 |
#include <unistd.h> |
|
24 |
#include <string.h> |
|
25 |
#include <strings.h> |
|
26 |
||
27 |
#include "config.h" |
|
28 |
#include "command.h" |
|
29 |
#include "input/input.h" |
|
30 |
#include "stream/stream.h" |
|
31 |
#include "libmpdemux/demuxer.h" |
|
32 |
#include "libmpdemux/stheader.h" |
|
33 |
#include "codec-cfg.h" |
|
34 |
#include "mp_msg.h" |
|
35 |
#include "mplayer.h" |
|
36 |
#include "sub/sub.h" |
|
37 |
#include "m_option.h" |
|
38 |
#include "m_property.h" |
|
39 |
#include "help_mp.h" |
|
40 |
#include "metadata.h" |
|
41 |
#include "libmpcodecs/vf.h" |
|
42 |
#include "libmpcodecs/vd.h" |
|
43 |
#include "libvo/video_out.h" |
|
44 |
#include "libvo/aspect.h" |
|
45 |
#include "sub/font_load.h" |
|
46 |
#include "playtree.h" |
|
47 |
#include "libao2/audio_out.h" |
|
48 |
#include "mpcommon.h" |
|
49 |
#include "mixer.h" |
|
50 |
#include "libmpcodecs/dec_video.h" |
|
51 |
#include "libmpcodecs/dec_teletext.h" |
|
52 |
#include "osdep/strsep.h" |
|
53 |
#include "sub/vobsub.h" |
|
54 |
#include "sub/spudec.h" |
|
55 |
#include "path.h" |
|
56 |
#include "stream/tv.h" |
|
57 |
#include "stream/stream_radio.h" |
|
58 |
#include "stream/pvr.h" |
|
59 |
#ifdef CONFIG_DVBIN
|
|
60 |
#include "stream/dvbin.h" |
|
61 |
#endif
|
|
62 |
#include "stream/stream_bd.h" |
|
63 |
#ifdef CONFIG_DVDREAD
|
|
64 |
#include "stream/stream_dvd.h" |
|
65 |
#endif
|
|
66 |
#include "stream/stream_dvdnav.h" |
|
67 |
#include "sub/ass_mp.h" |
|
68 |
#include "m_struct.h" |
|
69 |
#include "libmenu/menu.h" |
|
70 |
#include "gui/interface.h" |
|
71 |
#include "sub/eosd.h" |
|
72 |
#include "pnm_loader.h" |
|
73 |
||
74 |
#include "mp_core.h" |
|
75 |
#include "mp_fifo.h" |
|
76 |
#include "libavutil/avstring.h" |
|
77 |
#include "edl.h" |
|
78 |
||
79 |
#define IS_STREAMTYPE(t) (mpctx->stream && mpctx->stream->type == STREAMTYPE_##t)
|
|
80 |
||
81 |
static void rescale_input_coordinates(int ix, int iy, double *dx, double *dy) |
|
82 |
{
|
|
83 |
//remove the borders, if any, and rescale to the range [0,1],[0,1]
|
|
84 |
int w = vo_dwidth, h = vo_dheight; |
|
85 |
if (aspect_scaling()) { |
|
86 |
aspect(&w, &h, A_WINZOOM); |
|
87 |
panscan_calc_windowed(); |
|
88 |
w += vo_panscan_x; |
|
89 |
h += vo_panscan_y; |
|
90 |
ix -= (vo_dwidth - w) / 2; |
|
91 |
iy -= (vo_dheight - h) / 2; |
|
92 |
}
|
|
93 |
if (ix < 0 || ix > w || iy < 0 || iy > h) { |
|
94 |
// ignore movements outside movie area
|
|
95 |
*dx = *dy = -1.0; |
|
96 |
return; |
|
97 |
}
|
|
98 |
||
99 |
*dx = (double) ix / (double) w; |
|
100 |
*dy = (double) iy / (double) h; |
|
101 |
||
102 |
mp_msg(MSGT_CPLAYER, MSGL_V, |
|
103 |
"\r\nrescaled coordinates: %.3f, %.3f, screen (%d x %d), vodisplay: (%d, %d), fullscreen: %d\r\n", |
|
104 |
*dx, *dy, vo_screenwidth, vo_screenheight, vo_dwidth, |
|
105 |
vo_dheight, vo_fs); |
|
106 |
}
|
|
107 |
||
108 |
static int sub_pos_by_source(MPContext *mpctx, int src) |
|
109 |
{
|
|
110 |
int i, cnt = 0; |
|
111 |
if (src >= SUB_SOURCES || mpctx->sub_counts[src] == 0) |
|
112 |
return -1; |
|
113 |
for (i = 0; i < src; i++) |
|
114 |
cnt += mpctx->sub_counts[i]; |
|
115 |
return cnt; |
|
116 |
}
|
|
117 |
||
118 |
static int sub_source_and_index_by_pos(MPContext *mpctx, int *pos) |
|
119 |
{
|
|
120 |
int start = 0; |
|
121 |
int i; |
|
122 |
for (i = 0; i < SUB_SOURCES; i++) { |
|
123 |
int cnt = mpctx->sub_counts[i]; |
|
124 |
if (*pos >= start && *pos < start + cnt) { |
|
125 |
*pos -= start; |
|
126 |
return i; |
|
127 |
}
|
|
128 |
start += cnt; |
|
129 |
}
|
|
130 |
*pos = -1; |
|
131 |
return -1; |
|
132 |
}
|
|
133 |
||
134 |
static int sub_source_by_pos(MPContext *mpctx, int pos) |
|
135 |
{
|
|
136 |
return sub_source_and_index_by_pos(mpctx, &pos); |
|
137 |
}
|
|
138 |
||
139 |
static int sub_source_pos(MPContext *mpctx) |
|
140 |
{
|
|
141 |
int pos = mpctx->global_sub_pos; |
|
142 |
sub_source_and_index_by_pos(mpctx, &pos); |
|
143 |
return pos; |
|
144 |
}
|
|
145 |
||
146 |
static int sub_source(MPContext *mpctx) |
|
147 |
{
|
|
148 |
return sub_source_by_pos(mpctx, mpctx->global_sub_pos); |
|
149 |
}
|
|
150 |
||
151 |
static void update_global_sub_size(MPContext *mpctx) |
|
152 |
{
|
|
153 |
int i; |
|
154 |
int cnt = 0; |
|
155 |
||
156 |
// update number of demuxer sub streams
|
|
157 |
for (i = 0; i < MAX_S_STREAMS; i++) |
|
158 |
if (mpctx->demuxer->s_streams[i]) |
|
159 |
cnt++; |
|
160 |
if (cnt > mpctx->sub_counts[SUB_SOURCE_DEMUX]) |
|
161 |
mpctx->sub_counts[SUB_SOURCE_DEMUX] = cnt; |
|
162 |
||
163 |
// update global size
|
|
164 |
mpctx->global_sub_size = 0; |
|
165 |
for (i = 0; i < SUB_SOURCES; i++) |
|
166 |
mpctx->global_sub_size += mpctx->sub_counts[i]; |
|
167 |
||
168 |
// update global_sub_pos if we auto-detected a demuxer sub
|
|
169 |
if (mpctx->global_sub_pos == -1) { |
|
170 |
int sub_id = -1; |
|
171 |
if (mpctx->demuxer->sub) |
|
172 |
sub_id = mpctx->demuxer->sub->id; |
|
173 |
if (sub_id < 0) |
|
174 |
sub_id = dvdsub_id; |
|
175 |
if (sub_id >= 0 && sub_id < mpctx->sub_counts[SUB_SOURCE_DEMUX]) |
|
176 |
mpctx->global_sub_pos = sub_pos_by_source(mpctx, SUB_SOURCE_DEMUX) + |
|
177 |
sub_id; |
|
178 |
}
|
|
179 |
}
|
|
180 |
||
181 |
/**
|
|
182 |
* \brief Log the currently displayed subtitle to a file
|
|
183 |
*
|
|
184 |
* Logs the current or last displayed subtitle together with filename
|
|
185 |
* and time information to ~/.mplayer/subtitle_log
|
|
186 |
*
|
|
187 |
* Intended purpose is to allow convenient marking of bogus subtitles
|
|
188 |
* which need to be fixed while watching the movie.
|
|
189 |
*/
|
|
190 |
||
191 |
static void log_sub(void) |
|
192 |
{
|
|
193 |
char *fname; |
|
194 |
FILE *f; |
|
195 |
int i; |
|
196 |
||
197 |
if (subdata == NULL || vo_sub_last == NULL) |
|
198 |
return; |
|
199 |
fname = get_path("subtitle_log"); |
|
200 |
f = fopen(fname, "a"); |
|
201 |
if (!f) |
|
202 |
goto out; |
|
203 |
fprintf(f, "----------------------------------------------------------\n"); |
|
204 |
if (subdata->sub_uses_time) { |
|
205 |
fprintf(f, |
|
206 |
"N: %s S: %02ld:%02ld:%02ld.%02ld E: %02ld:%02ld:%02ld.%02ld\n", |
|
207 |
filename, vo_sub_last->start / 360000, |
|
208 |
(vo_sub_last->start / 6000) % 60, |
|
209 |
(vo_sub_last->start / 100) % 60, vo_sub_last->start % 100, |
|
210 |
vo_sub_last->end / 360000, (vo_sub_last->end / 6000) % 60, |
|
211 |
(vo_sub_last->end / 100) % 60, vo_sub_last->end % 100); |
|
212 |
} else { |
|
213 |
fprintf(f, "N: %s S: %ld E: %ld\n", filename, vo_sub_last->start, |
|
214 |
vo_sub_last->end); |
|
215 |
}
|
|
216 |
for (i = 0; i < vo_sub_last->lines; i++) { |
|
217 |
fprintf(f, "%s\n", vo_sub_last->text[i]); |
|
218 |
}
|
|
219 |
fclose(f); |
|
220 |
out: |
|
221 |
free(fname); |
|
222 |
}
|
|
223 |
||
224 |
||
225 |
/// \defgroup properties Properties
|
|
226 |
///@{
|
|
227 |
||
228 |
/// \defgroup GeneralProperties General properties
|
|
229 |
/// \ingroup Properties
|
|
230 |
///@{
|
|
231 |
||
232 |
/// OSD level (RW)
|
|
233 |
static int mp_property_osdlevel(m_option_t *prop, int action, void *arg, |
|
234 |
MPContext *mpctx) |
|
235 |
{
|
|
236 |
return m_property_choice(prop, action, arg, &osd_level); |
|
237 |
}
|
|
238 |
||
239 |
/// Loop (RW)
|
|
240 |
static int mp_property_loop(m_option_t *prop, int action, void *arg, |
|
241 |
MPContext *mpctx) |
|
242 |
{
|
|
243 |
switch (action) { |
|
244 |
case M_PROPERTY_PRINT: |
|
245 |
if (!arg) return M_PROPERTY_ERROR; |
|
246 |
if (mpctx->loop_times < 0) |
|
247 |
*(char**)arg = strdup("off"); |
|
248 |
else if (mpctx->loop_times == 0) |
|
249 |
*(char**)arg = strdup("inf"); |
|
250 |
else
|
|
251 |
break; |
|
252 |
return M_PROPERTY_OK; |
|
253 |
}
|
|
254 |
return m_property_int_range(prop, action, arg, &mpctx->loop_times); |
|
255 |
}
|
|
256 |
||
257 |
/// Playback speed (RW)
|
|
258 |
static int mp_property_playback_speed(m_option_t *prop, int action, |
|
259 |
void *arg, MPContext *mpctx) |
|
260 |
{
|
|
261 |
switch (action) { |
|
262 |
case M_PROPERTY_SET: |
|
263 |
if (!arg) |
|
264 |
return M_PROPERTY_ERROR; |
|
265 |
M_PROPERTY_CLAMP(prop, *(float *) arg); |
|
266 |
playback_speed = *(float *) arg; |
|
267 |
reinit_audio_chain(); |
|
268 |
return M_PROPERTY_OK; |
|
269 |
case M_PROPERTY_STEP_UP: |
|
270 |
case M_PROPERTY_STEP_DOWN: |
|
271 |
playback_speed += (arg ? *(float *) arg : 0.1) * |
|
272 |
(action == M_PROPERTY_STEP_DOWN ? -1 : 1); |
|
273 |
M_PROPERTY_CLAMP(prop, playback_speed); |
|
274 |
reinit_audio_chain(); |
|
275 |
return M_PROPERTY_OK; |
|
276 |
}
|
|
277 |
return m_property_float_range(prop, action, arg, &playback_speed); |
|
278 |
}
|
|
279 |
||
280 |
/// filename with path (RO)
|
|
281 |
static int mp_property_path(m_option_t *prop, int action, void *arg, |
|
282 |
MPContext *mpctx) |
|
283 |
{
|
|
284 |
return m_property_string_ro(prop, action, arg, filename); |
|
285 |
}
|
|
286 |
||
287 |
/// filename without path (RO)
|
|
288 |
static int mp_property_filename(m_option_t *prop, int action, void *arg, |
|
289 |
MPContext *mpctx) |
|
290 |
{
|
|
291 |
char *f; |
|
292 |
if (!filename) |
|
293 |
return M_PROPERTY_UNAVAILABLE; |
|
294 |
f = (char *)mp_basename(filename); |
|
295 |
if (!*f) |
|
296 |
f = filename; |
|
297 |
return m_property_string_ro(prop, action, arg, f); |
|
298 |
}
|
|
299 |
||
300 |
/// Demuxer name (RO)
|
|
301 |
static int mp_property_demuxer(m_option_t *prop, int action, void *arg, |
|
302 |
MPContext *mpctx) |
|
303 |
{
|
|
304 |
if (!mpctx->demuxer) |
|
305 |
return M_PROPERTY_UNAVAILABLE; |
|
306 |
return m_property_string_ro(prop, action, arg, |
|
307 |
(char *) mpctx->demuxer->desc->name); |
|
308 |
}
|
|
309 |
||
310 |
/// Position in the stream (RW)
|
|
311 |
static int mp_property_stream_pos(m_option_t *prop, int action, void *arg, |
|
312 |
MPContext *mpctx) |
|
313 |
{
|
|
314 |
if (!mpctx->demuxer || !mpctx->demuxer->stream) |
|
315 |
return M_PROPERTY_UNAVAILABLE; |
|
316 |
if (!arg) |
|
317 |
return M_PROPERTY_ERROR; |
|
318 |
switch (action) { |
|
319 |
case M_PROPERTY_GET: |
|
320 |
*(off_t *) arg = stream_tell(mpctx->demuxer->stream); |
|
321 |
return M_PROPERTY_OK; |
|
322 |
case M_PROPERTY_SET: |
|
323 |
M_PROPERTY_CLAMP(prop, *(off_t *) arg); |
|
324 |
stream_seek(mpctx->demuxer->stream, *(off_t *) arg); |
|
325 |
return M_PROPERTY_OK; |
|
326 |
}
|
|
327 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
328 |
}
|
|
329 |
||
330 |
/// Stream start offset (RO)
|
|
331 |
static int mp_property_stream_start(m_option_t *prop, int action, |
|
332 |
void *arg, MPContext *mpctx) |
|
333 |
{
|
|
334 |
if (!mpctx->demuxer || !mpctx->demuxer->stream) |
|
335 |
return M_PROPERTY_UNAVAILABLE; |
|
336 |
switch (action) { |
|
337 |
case M_PROPERTY_GET: |
|
338 |
*(off_t *) arg = mpctx->demuxer->stream->start_pos; |
|
339 |
return M_PROPERTY_OK; |
|
340 |
}
|
|
341 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
342 |
}
|
|
343 |
||
344 |
/// Stream end offset (RO)
|
|
345 |
static int mp_property_stream_end(m_option_t *prop, int action, void *arg, |
|
346 |
MPContext *mpctx) |
|
347 |
{
|
|
348 |
if (!mpctx->demuxer || !mpctx->demuxer->stream) |
|
349 |
return M_PROPERTY_UNAVAILABLE; |
|
350 |
switch (action) { |
|
351 |
case M_PROPERTY_GET: |
|
352 |
*(off_t *) arg = mpctx->demuxer->stream->end_pos; |
|
353 |
return M_PROPERTY_OK; |
|
354 |
}
|
|
355 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
356 |
}
|
|
357 |
||
358 |
/// Stream length (RO)
|
|
359 |
static int mp_property_stream_length(m_option_t *prop, int action, |
|
360 |
void *arg, MPContext *mpctx) |
|
361 |
{
|
|
362 |
if (!mpctx->demuxer || !mpctx->demuxer->stream) |
|
363 |
return M_PROPERTY_UNAVAILABLE; |
|
364 |
switch (action) { |
|
365 |
case M_PROPERTY_GET: |
|
366 |
*(off_t *) arg = |
|
367 |
mpctx->demuxer->stream->end_pos - mpctx->demuxer->stream->start_pos; |
|
368 |
return M_PROPERTY_OK; |
|
369 |
}
|
|
370 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
371 |
}
|
|
372 |
||
373 |
/// Current stream position in seconds (RO)
|
|
374 |
static int mp_property_stream_time_pos(m_option_t *prop, int action, |
|
375 |
void *arg, MPContext *mpctx) |
|
376 |
{
|
|
377 |
if (!mpctx->demuxer || mpctx->demuxer->stream_pts == MP_NOPTS_VALUE) |
|
378 |
return M_PROPERTY_UNAVAILABLE; |
|
379 |
||
380 |
return m_property_time_ro(prop, action, arg, mpctx->demuxer->stream_pts); |
|
381 |
}
|
|
382 |
||
383 |
||
384 |
/// Media length in seconds (RO)
|
|
385 |
static int mp_property_length(m_option_t *prop, int action, void *arg, |
|
386 |
MPContext *mpctx) |
|
387 |
{
|
|
388 |
double len; |
|
389 |
||
390 |
if (!mpctx->demuxer || |
|
391 |
!(int) (len = demuxer_get_time_length(mpctx->demuxer))) |
|
392 |
return M_PROPERTY_UNAVAILABLE; |
|
393 |
||
394 |
return m_property_time_ro(prop, action, arg, len); |
|
395 |
}
|
|
396 |
||
397 |
/// Current position in percent (RW)
|
|
398 |
static int mp_property_percent_pos(m_option_t *prop, int action, |
|
399 |
void *arg, MPContext *mpctx) { |
|
400 |
int pos; |
|
401 |
||
402 |
if (!mpctx->demuxer) |
|
403 |
return M_PROPERTY_UNAVAILABLE; |
|
404 |
||
405 |
switch(action) { |
|
406 |
case M_PROPERTY_SET: |
|
407 |
if(!arg) return M_PROPERTY_ERROR; |
|
408 |
M_PROPERTY_CLAMP(prop, *(int*)arg); |
|
409 |
pos = *(int*)arg; |
|
410 |
break; |
|
411 |
case M_PROPERTY_STEP_UP: |
|
412 |
case M_PROPERTY_STEP_DOWN: |
|
413 |
pos = demuxer_get_percent_pos(mpctx->demuxer); |
|
414 |
pos += (arg ? *(int*)arg : 10) * |
|
415 |
(action == M_PROPERTY_STEP_UP ? 1 : -1); |
|
416 |
M_PROPERTY_CLAMP(prop, pos); |
|
417 |
break; |
|
418 |
default: |
|
419 |
return m_property_int_ro(prop, action, arg, |
|
420 |
demuxer_get_percent_pos(mpctx->demuxer)); |
|
421 |
}
|
|
422 |
||
423 |
abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR; |
|
424 |
rel_seek_secs = pos / 100.0; |
|
425 |
return M_PROPERTY_OK; |
|
426 |
}
|
|
427 |
||
428 |
/// Current position in seconds (RW)
|
|
429 |
static int mp_property_time_pos(m_option_t *prop, int action, |
|
430 |
void *arg, MPContext *mpctx) { |
|
431 |
if (!(mpctx->sh_video || (mpctx->sh_audio && mpctx->audio_out))) |
|
432 |
return M_PROPERTY_UNAVAILABLE; |
|
433 |
||
434 |
switch(action) { |
|
435 |
case M_PROPERTY_SET: |
|
436 |
if(!arg) return M_PROPERTY_ERROR; |
|
437 |
M_PROPERTY_CLAMP(prop, *(double*)arg); |
|
438 |
abs_seek_pos = SEEK_ABSOLUTE; |
|
439 |
rel_seek_secs = *(double*)arg; |
|
440 |
return M_PROPERTY_OK; |
|
441 |
case M_PROPERTY_STEP_UP: |
|
442 |
case M_PROPERTY_STEP_DOWN: |
|
443 |
rel_seek_secs += (arg ? *(double*)arg : 10.0) * |
|
444 |
(action == M_PROPERTY_STEP_UP ? 1.0 : -1.0); |
|
445 |
return M_PROPERTY_OK; |
|
446 |
}
|
|
447 |
return m_property_time_ro(prop, action, arg, |
|
448 |
mpctx->sh_video ? mpctx->sh_video->pts : |
|
449 |
playing_audio_pts(mpctx->sh_audio, |
|
450 |
mpctx->d_audio, |
|
451 |
mpctx->audio_out)); |
|
452 |
}
|
|
453 |
||
454 |
/// Current chapter (RW)
|
|
455 |
static int mp_property_chapter(m_option_t *prop, int action, void *arg, |
|
456 |
MPContext *mpctx) |
|
457 |
{
|
|
458 |
int chapter = -1; |
|
459 |
float next_pts = 0; |
|
460 |
int chapter_num; |
|
461 |
int step_all; |
|
462 |
char *chapter_name = NULL; |
|
463 |
||
464 |
if (mpctx->demuxer) |
|
465 |
chapter = demuxer_get_current_chapter(mpctx->demuxer); |
|
466 |
if (chapter < 0) |
|
467 |
return M_PROPERTY_UNAVAILABLE; |
|
468 |
||
469 |
switch (action) { |
|
470 |
case M_PROPERTY_GET: |
|
471 |
if (!arg) |
|
472 |
return M_PROPERTY_ERROR; |
|
473 |
*(int *) arg = chapter; |
|
474 |
return M_PROPERTY_OK; |
|
475 |
case M_PROPERTY_PRINT: { |
|
476 |
if (!arg) |
|
477 |
return M_PROPERTY_ERROR; |
|
478 |
chapter_name = demuxer_chapter_display_name(mpctx->demuxer, chapter); |
|
479 |
if (!chapter_name) |
|
480 |
return M_PROPERTY_UNAVAILABLE; |
|
481 |
*(char **) arg = chapter_name; |
|
482 |
return M_PROPERTY_OK; |
|
483 |
}
|
|
484 |
case M_PROPERTY_SET: |
|
485 |
if (!arg) |
|
486 |
return M_PROPERTY_ERROR; |
|
487 |
M_PROPERTY_CLAMP(prop, *(int*)arg); |
|
488 |
step_all = *(int *)arg - chapter; |
|
489 |
chapter += step_all; |
|
490 |
break; |
|
491 |
case M_PROPERTY_STEP_UP: |
|
492 |
case M_PROPERTY_STEP_DOWN: { |
|
493 |
step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1) |
|
494 |
* (action == M_PROPERTY_STEP_UP ? 1 : -1); |
|
495 |
chapter += step_all; |
|
496 |
if (chapter < 0) |
|
497 |
chapter = 0; |
|
498 |
break; |
|
499 |
}
|
|
500 |
default: |
|
501 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
502 |
}
|
|
503 |
rel_seek_secs = 0; |
|
504 |
abs_seek_pos = 0; |
|
505 |
chapter = demuxer_seek_chapter(mpctx->demuxer, chapter, 1, |
|
506 |
&next_pts, &chapter_num, &chapter_name); |
|
507 |
if (chapter >= 0) { |
|
508 |
if (next_pts > -1.0) { |
|
509 |
abs_seek_pos = SEEK_ABSOLUTE; |
|
510 |
rel_seek_secs = next_pts; |
|
511 |
}
|
|
512 |
if (chapter_name) |
|
513 |
set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, |
|
514 |
MSGTR_OSDChapter, chapter + 1, chapter_name); |
|
515 |
}
|
|
516 |
else if (step_all > 0) |
|
517 |
rel_seek_secs = 1000000000.; |
|
518 |
else
|
|
519 |
set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, |
|
520 |
MSGTR_OSDChapter, 0, MSGTR_Unknown); |
|
521 |
free(chapter_name); |
|
522 |
return M_PROPERTY_OK; |
|
523 |
}
|
|
524 |
||
525 |
/// Number of titles in file
|
|
526 |
static int mp_property_titles(m_option_t *prop, int action, void *arg, |
|
527 |
MPContext *mpctx) |
|
528 |
{
|
|
529 |
if (!mpctx->demuxer) |
|
530 |
return M_PROPERTY_UNAVAILABLE; |
|
531 |
if (mpctx->demuxer->num_titles == 0) |
|
532 |
stream_control(mpctx->demuxer->stream, STREAM_CTRL_GET_NUM_TITLES, &mpctx->demuxer->num_titles); |
|
533 |
return m_property_int_ro(prop, action, arg, mpctx->demuxer->num_titles); |
|
534 |
}
|
|
535 |
||
536 |
/// Number of chapters in file
|
|
537 |
static int mp_property_chapters(m_option_t *prop, int action, void *arg, |
|
538 |
MPContext *mpctx) |
|
539 |
{
|
|
540 |
if (!mpctx->demuxer) |
|
541 |
return M_PROPERTY_UNAVAILABLE; |
|
542 |
if (mpctx->demuxer->num_chapters == 0) |
|
543 |
stream_control(mpctx->demuxer->stream, STREAM_CTRL_GET_NUM_CHAPTERS, &mpctx->demuxer->num_chapters); |
|
544 |
return m_property_int_ro(prop, action, arg, mpctx->demuxer->num_chapters); |
|
545 |
}
|
|
546 |
||
547 |
/// Current dvd angle (RW)
|
|
548 |
static int mp_property_angle(m_option_t *prop, int action, void *arg, |
|
549 |
MPContext *mpctx) |
|
550 |
{
|
|
551 |
int angle = -1; |
|
552 |
int angles; |
|
553 |
char *angle_name = NULL; |
|
554 |
||
555 |
if (mpctx->demuxer) |
|
556 |
angle = demuxer_get_current_angle(mpctx->demuxer); |
|
557 |
if (angle < 0) |
|
558 |
return M_PROPERTY_UNAVAILABLE; |
|
559 |
angles = demuxer_angles_count(mpctx->demuxer); |
|
560 |
if (angles <= 1) |
|
561 |
return M_PROPERTY_UNAVAILABLE; |
|
562 |
||
563 |
switch (action) { |
|
564 |
case M_PROPERTY_GET: |
|
565 |
if (!arg) |
|
566 |
return M_PROPERTY_ERROR; |
|
567 |
*(int *) arg = angle; |
|
568 |
return M_PROPERTY_OK; |
|
569 |
case M_PROPERTY_PRINT: { |
|
570 |
if (!arg) |
|
571 |
return M_PROPERTY_ERROR; |
|
572 |
angle_name = calloc(1, 64); |
|
573 |
if (!angle_name) |
|
574 |
return M_PROPERTY_UNAVAILABLE; |
|
575 |
snprintf(angle_name, 64, "%d/%d", angle, angles); |
|
576 |
*(char **) arg = angle_name; |
|
577 |
return M_PROPERTY_OK; |
|
578 |
}
|
|
579 |
case M_PROPERTY_SET: |
|
580 |
if (!arg) |
|
581 |
return M_PROPERTY_ERROR; |
|
582 |
angle = *(int *)arg; |
|
583 |
M_PROPERTY_CLAMP(prop, angle); |
|
584 |
break; |
|
585 |
case M_PROPERTY_STEP_UP: |
|
586 |
case M_PROPERTY_STEP_DOWN: { |
|
587 |
int step = 0; |
|
588 |
if(arg) |
|
589 |
step = *(int*)arg; |
|
590 |
if(!step) |
|
591 |
step = 1; |
|
592 |
step *= (action == M_PROPERTY_STEP_UP ? 1 : -1); |
|
593 |
angle += step; |
|
594 |
if (angle < 1) //cycle |
|
595 |
angle = angles; |
|
596 |
else if (angle > angles) |
|
597 |
angle = 1; |
|
598 |
break; |
|
599 |
}
|
|
600 |
default: |
|
601 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
602 |
}
|
|
603 |
angle = demuxer_set_angle(mpctx->demuxer, angle); |
|
604 |
set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, |
|
605 |
MSGTR_OSDAngle, angle, angles); |
|
606 |
free(angle_name); |
|
607 |
return M_PROPERTY_OK; |
|
608 |
}
|
|
609 |
||
610 |
/// Demuxer meta data
|
|
611 |
static int mp_property_metadata(m_option_t *prop, int action, void *arg, |
|
612 |
MPContext *mpctx) { |
|
613 |
m_property_action_t* ka; |
|
614 |
char* meta; |
|
615 |
static const m_option_t key_type = |
|
616 |
{ "metadata", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL }; |
|
617 |
if (!mpctx->demuxer) |
|
618 |
return M_PROPERTY_UNAVAILABLE; |
|
619 |
||
620 |
switch(action) { |
|
621 |
case M_PROPERTY_GET: |
|
622 |
if(!arg) return M_PROPERTY_ERROR; |
|
623 |
*(char***)arg = mpctx->demuxer->info; |
|
624 |
return M_PROPERTY_OK; |
|
625 |
case M_PROPERTY_KEY_ACTION: |
|
626 |
if(!arg) return M_PROPERTY_ERROR; |
|
627 |
ka = arg; |
|
628 |
if(!(meta = demux_info_get(mpctx->demuxer,ka->key))) |
|
629 |
return M_PROPERTY_UNKNOWN; |
|
630 |
switch(ka->action) { |
|
631 |
case M_PROPERTY_GET: |
|
632 |
if(!ka->arg) return M_PROPERTY_ERROR; |
|
633 |
*(char**)ka->arg = meta; |
|
634 |
return M_PROPERTY_OK; |
|
635 |
case M_PROPERTY_GET_TYPE: |
|
636 |
if(!ka->arg) return M_PROPERTY_ERROR; |
|
637 |
*(const m_option_t**)ka->arg = &key_type; |
|
638 |
return M_PROPERTY_OK; |
|
639 |
}
|
|
640 |
}
|
|
641 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
642 |
}
|
|
643 |
||
644 |
static int mp_property_pause(m_option_t *prop, int action, void *arg, |
|
645 |
MPContext *mpctx) |
|
646 |
{
|
|
647 |
return m_property_flag_ro(prop, action, arg, mpctx->osd_function == OSD_PAUSE); |
|
648 |
}
|
|
649 |
||
650 |
||
651 |
///@}
|
|
652 |
||
653 |
/// \defgroup AudioProperties Audio properties
|
|
654 |
/// \ingroup Properties
|
|
655 |
///@{
|
|
656 |
||
657 |
/// Volume (RW)
|
|
658 |
static int mp_property_volume(m_option_t *prop, int action, void *arg, |
|
659 |
MPContext *mpctx) |
|
660 |
{
|
|
661 |
||
662 |
if (!mpctx->sh_audio) |
|
663 |
return M_PROPERTY_UNAVAILABLE; |
|
664 |
||
665 |
switch (action) { |
|
666 |
case M_PROPERTY_GET: |
|
667 |
if (!arg) |
|
668 |
return M_PROPERTY_ERROR; |
|
669 |
mixer_getbothvolume(&mpctx->mixer, arg); |
|
670 |
return M_PROPERTY_OK; |
|
671 |
case M_PROPERTY_PRINT:{ |
|
672 |
float vol; |
|
673 |
if (!arg) |
|
674 |
return M_PROPERTY_ERROR; |
|
675 |
mixer_getbothvolume(&mpctx->mixer, &vol); |
|
676 |
return m_property_float_range(prop, action, arg, &vol); |
|
677 |
}
|
|
678 |
case M_PROPERTY_STEP_UP: |
|
679 |
case M_PROPERTY_STEP_DOWN: |
|
680 |
case M_PROPERTY_SET: |
|
681 |
break; |
|
682 |
default: |
|
683 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
684 |
}
|
|
685 |
||
686 |
if (mpctx->edl_muted) |
|
687 |
return M_PROPERTY_DISABLED; |
|
688 |
mpctx->user_muted = 0; |
|
689 |
||
690 |
switch (action) { |
|
691 |
case M_PROPERTY_SET: |
|
692 |
if (!arg) |
|
693 |
return M_PROPERTY_ERROR; |
|
694 |
M_PROPERTY_CLAMP(prop, *(float *) arg); |
|
695 |
mixer_setvolume(&mpctx->mixer, *(float *) arg, *(float *) arg); |
|
696 |
return M_PROPERTY_OK; |
|
697 |
case M_PROPERTY_STEP_UP: |
|
698 |
if (arg && *(float *) arg <= 0) |
|
699 |
mixer_decvolume(&mpctx->mixer); |
|
700 |
else
|
|
701 |
mixer_incvolume(&mpctx->mixer); |
|
702 |
return M_PROPERTY_OK; |
|
703 |
case M_PROPERTY_STEP_DOWN: |
|
704 |
if (arg && *(float *) arg <= 0) |
|
705 |
mixer_incvolume(&mpctx->mixer); |
|
706 |
else
|
|
707 |
mixer_decvolume(&mpctx->mixer); |
|
708 |
return M_PROPERTY_OK; |
|
709 |
}
|
|
710 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
711 |
}
|
|
712 |
||
713 |
/// Mute (RW)
|
|
714 |
static int mp_property_mute(m_option_t *prop, int action, void *arg, |
|
715 |
MPContext *mpctx) |
|
716 |
{
|
|
717 |
||
718 |
if (!mpctx->sh_audio) |
|
719 |
return M_PROPERTY_UNAVAILABLE; |
|
720 |
||
721 |
switch (action) { |
|
722 |
case M_PROPERTY_SET: |
|
723 |
if (mpctx->edl_muted) |
|
724 |
return M_PROPERTY_DISABLED; |
|
725 |
if (!arg) |
|
726 |
return M_PROPERTY_ERROR; |
|
727 |
if ((!!*(int *) arg) != mpctx->mixer.muted) |
|
728 |
mixer_mute(&mpctx->mixer); |
|
729 |
mpctx->user_muted = mpctx->mixer.muted; |
|
730 |
return M_PROPERTY_OK; |
|
731 |
case M_PROPERTY_STEP_UP: |
|
732 |
case M_PROPERTY_STEP_DOWN: |
|
733 |
if (mpctx->edl_muted) |
|
734 |
return M_PROPERTY_DISABLED; |
|
735 |
mixer_mute(&mpctx->mixer); |
|
736 |
mpctx->user_muted = mpctx->mixer.muted; |
|
737 |
return M_PROPERTY_OK; |
|
738 |
case M_PROPERTY_PRINT: |
|
739 |
if (!arg) |
|
740 |
return M_PROPERTY_ERROR; |
|
741 |
if (mpctx->edl_muted) { |
|
742 |
*(char **) arg = strdup(MSGTR_EnabledEdl); |
|
743 |
return M_PROPERTY_OK; |
|
744 |
}
|
|
745 |
default: |
|
746 |
return m_property_flag(prop, action, arg, &mpctx->mixer.muted); |
|
747 |
||
748 |
}
|
|
749 |
}
|
|
750 |
||
751 |
/// Audio delay (RW)
|
|
752 |
static int mp_property_audio_delay(m_option_t *prop, int action, |
|
753 |
void *arg, MPContext *mpctx) |
|
754 |
{
|
|
755 |
if (!(mpctx->sh_audio && mpctx->sh_video)) |
|
756 |
return M_PROPERTY_UNAVAILABLE; |
|
757 |
switch (action) { |
|
758 |
case M_PROPERTY_SET: |
|
759 |
case M_PROPERTY_STEP_UP: |
|
760 |
case M_PROPERTY_STEP_DOWN: { |
|
761 |
int ret; |
|
762 |
float delay = audio_delay; |
|
763 |
ret = m_property_delay(prop, action, arg, &audio_delay); |
|
764 |
if (ret != M_PROPERTY_OK) |
|
765 |
return ret; |
|
766 |
if (mpctx->sh_audio) |
|
767 |
mpctx->delay -= audio_delay - delay; |
|
768 |
}
|
|
769 |
return M_PROPERTY_OK; |
|
770 |
default: |
|
771 |
return m_property_delay(prop, action, arg, &audio_delay); |
|
772 |
}
|
|
773 |
}
|
|
774 |
||
775 |
/// Audio codec tag (RO)
|
|
776 |
static int mp_property_audio_format(m_option_t *prop, int action, |
|
777 |
void *arg, MPContext *mpctx) |
|
778 |
{
|
|
779 |
if (!mpctx->sh_audio) |
|
780 |
return M_PROPERTY_UNAVAILABLE; |
|
781 |
return m_property_int_ro(prop, action, arg, mpctx->sh_audio->format); |
|
782 |
}
|
|
783 |
||
784 |
/// Audio codec name (RO)
|
|
785 |
static int mp_property_audio_codec(m_option_t *prop, int action, |
|
786 |
void *arg, MPContext *mpctx) |
|
787 |
{
|
|
788 |
if (!mpctx->sh_audio || !mpctx->sh_audio->codec) |
|
789 |
return M_PROPERTY_UNAVAILABLE; |
|
790 |
return m_property_string_ro(prop, action, arg, mpctx->sh_audio->codec->name); |
|
791 |
}
|
|
792 |
||
793 |
/// Audio bitrate (RO)
|
|
794 |
static int mp_property_audio_bitrate(m_option_t *prop, int action, |
|
795 |
void *arg, MPContext *mpctx) |
|
796 |
{
|
|
797 |
if (!mpctx->sh_audio) |
|
798 |
return M_PROPERTY_UNAVAILABLE; |
|
799 |
return m_property_bitrate(prop, action, arg, mpctx->sh_audio->i_bps); |
|
800 |
}
|
|
801 |
||
802 |
/// Samplerate (RO)
|
|
803 |
static int mp_property_samplerate(m_option_t *prop, int action, void *arg, |
|
804 |
MPContext *mpctx) |
|
805 |
{
|
|
806 |
if (!mpctx->sh_audio) |
|
807 |
return M_PROPERTY_UNAVAILABLE; |
|
808 |
switch(action) { |
|
809 |
case M_PROPERTY_PRINT: |
|
810 |
if(!arg) return M_PROPERTY_ERROR; |
|
811 |
*(char**)arg = malloc(16); |
|
812 |
sprintf(*(char**)arg,"%d kHz",mpctx->sh_audio->samplerate/1000); |
|
813 |
return M_PROPERTY_OK; |
|
814 |
}
|
|
815 |
return m_property_int_ro(prop, action, arg, mpctx->sh_audio->samplerate); |
|
816 |
}
|
|
817 |
||
818 |
/// Number of channels (RO)
|
|
819 |
static int mp_property_channels(m_option_t *prop, int action, void *arg, |
|
820 |
MPContext *mpctx) |
|
821 |
{
|
|
822 |
if (!mpctx->sh_audio) |
|
823 |
return M_PROPERTY_UNAVAILABLE; |
|
824 |
switch (action) { |
|
825 |
case M_PROPERTY_PRINT: |
|
826 |
if (!arg) |
|
827 |
return M_PROPERTY_ERROR; |
|
828 |
switch (mpctx->sh_audio->channels) { |
|
829 |
case 1: |
|
830 |
*(char **) arg = strdup("mono"); |
|
831 |
break; |
|
832 |
case 2: |
|
833 |
*(char **) arg = strdup("stereo"); |
|
834 |
break; |
|
835 |
default: |
|
836 |
*(char **) arg = malloc(32); |
|
837 |
sprintf(*(char **) arg, "%d channels", mpctx->sh_audio->channels); |
|
838 |
}
|
|
839 |
return M_PROPERTY_OK; |
|
840 |
}
|
|
841 |
return m_property_int_ro(prop, action, arg, mpctx->sh_audio->channels); |
|
842 |
}
|
|
843 |
||
844 |
/// Balance (RW)
|
|
845 |
static int mp_property_balance(m_option_t *prop, int action, void *arg, |
|
846 |
MPContext *mpctx) |
|
847 |
{
|
|
848 |
float bal; |
|
849 |
||
850 |
if (!mpctx->sh_audio || mpctx->sh_audio->channels < 2) |
|
851 |
return M_PROPERTY_UNAVAILABLE; |
|
852 |
||
853 |
switch (action) { |
|
854 |
case M_PROPERTY_GET: |
|
855 |
if (!arg) |
|
856 |
return M_PROPERTY_ERROR; |
|
857 |
mixer_getbalance(&mpctx->mixer, arg); |
|
858 |
return M_PROPERTY_OK; |
|
859 |
case M_PROPERTY_PRINT: { |
|
860 |
char** str = arg; |
|
861 |
if (!arg) |
|
862 |
return M_PROPERTY_ERROR; |
|
863 |
mixer_getbalance(&mpctx->mixer, &bal); |
|
864 |
if (bal == 0.f) |
|
865 |
*str = strdup("center"); |
|
866 |
else if (bal == -1.f) |
|
867 |
*str = strdup("left only"); |
|
868 |
else if (bal == 1.f) |
|
869 |
*str = strdup("right only"); |
|
870 |
else { |
|
871 |
unsigned right = (bal + 1.f) / 2.f * 100.f; |
|
872 |
*str = malloc(sizeof("left xxx%, right xxx%")); |
|
873 |
sprintf(*str, "left %d%%, right %d%%", 100 - right, right); |
|
874 |
}
|
|
875 |
return M_PROPERTY_OK; |
|
876 |
}
|
|
877 |
case M_PROPERTY_STEP_UP: |
|
878 |
case M_PROPERTY_STEP_DOWN: |
|
879 |
mixer_getbalance(&mpctx->mixer, &bal); |
|
880 |
bal += (arg ? *(float*)arg : .1f) * |
|
881 |
(action == M_PROPERTY_STEP_UP ? 1.f : -1.f); |
|
882 |
M_PROPERTY_CLAMP(prop, bal); |
|
883 |
mixer_setbalance(&mpctx->mixer, bal); |
|
884 |
return M_PROPERTY_OK; |
|
885 |
case M_PROPERTY_SET: |
|
886 |
if (!arg) |
|
887 |
return M_PROPERTY_ERROR; |
|
888 |
M_PROPERTY_CLAMP(prop, *(float*)arg); |
|
889 |
mixer_setbalance(&mpctx->mixer, *(float*)arg); |
|
890 |
return M_PROPERTY_OK; |
|
891 |
}
|
|
892 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
893 |
}
|
|
894 |
||
895 |
/// Selected audio id (RW)
|
|
896 |
static int mp_property_audio(m_option_t *prop, int action, void *arg, |
|
897 |
MPContext *mpctx) |
|
898 |
{
|
|
899 |
int current_id, tmp; |
|
900 |
if (!mpctx->demuxer || !mpctx->demuxer->audio) |
|
901 |
return M_PROPERTY_UNAVAILABLE; |
|
902 |
current_id = mpctx->demuxer->audio->id; |
|
903 |
if (current_id >= 0) |
|
904 |
audio_id = ((sh_audio_t *)mpctx->demuxer->a_streams[current_id])->aid; |
|
905 |
||
906 |
switch (action) { |
|
907 |
case M_PROPERTY_GET: |
|
908 |
if (!arg) |
|
909 |
return M_PROPERTY_ERROR; |
|
910 |
*(int *) arg = audio_id; |
|
911 |
return M_PROPERTY_OK; |
|
912 |
case M_PROPERTY_PRINT: |
|
913 |
if (!arg) |
|
914 |
return M_PROPERTY_ERROR; |
|
915 |
||
916 |
if (current_id < 0) |
|
917 |
*(char **) arg = strdup(MSGTR_Disabled); |
|
918 |
else { |
|
919 |
char lang[40] = MSGTR_Unknown; |
|
920 |
demuxer_audio_lang(mpctx->demuxer, current_id, lang, sizeof(lang)); |
|
921 |
*(char **) arg = malloc(64); |
|
922 |
snprintf(*(char **) arg, 64, "(%d) %s", audio_id, lang); |
|
923 |
}
|
|
924 |
return M_PROPERTY_OK; |
|
925 |
||
926 |
case M_PROPERTY_STEP_UP: |
|
927 |
case M_PROPERTY_SET: |
|
928 |
if (action == M_PROPERTY_SET && arg) |
|
929 |
tmp = *((int *) arg); |
|
930 |
else
|
|
931 |
tmp = -1; |
|
932 |
tmp = demuxer_switch_audio(mpctx->demuxer, tmp); |
|
933 |
if (tmp == -2 |
|
934 |
|| (tmp > -1 |
|
935 |
&& mpctx->demuxer->audio->id != current_id && current_id != -2)) { |
|
936 |
uninit_player(INITIALIZED_AO | INITIALIZED_ACODEC); |
|
937 |
audio_id = tmp; |
|
938 |
}
|
|
939 |
if (tmp > -1 && mpctx->demuxer->audio->id != current_id) { |
|
940 |
sh_audio_t *sh2; |
|
941 |
sh2 = mpctx->demuxer->a_streams[mpctx->demuxer->audio->id]; |
|
942 |
if (sh2) { |
|
943 |
audio_id = sh2->aid; |
|
944 |
sh2->ds = mpctx->demuxer->audio; |
|
945 |
mpctx->sh_audio = sh2; |
|
946 |
reinit_audio_chain(); |
|
947 |
}
|
|
948 |
}
|
|
949 |
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_TRACK=%d\n", audio_id); |
|
950 |
return M_PROPERTY_OK; |
|
951 |
default: |
|
952 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
953 |
}
|
|
954 |
||
955 |
}
|
|
956 |
||
957 |
/// Selected video id (RW)
|
|
958 |
static int mp_property_video(m_option_t *prop, int action, void *arg, |
|
959 |
MPContext *mpctx) |
|
960 |
{
|
|
961 |
int current_id, tmp; |
|
962 |
if (!mpctx->demuxer || !mpctx->demuxer->video) |
|
963 |
return M_PROPERTY_UNAVAILABLE; |
|
964 |
current_id = mpctx->demuxer->video->id; |
|
965 |
if (current_id >= 0) |
|
966 |
video_id = ((sh_video_t *)mpctx->demuxer->v_streams[current_id])->vid; |
|
967 |
||
968 |
switch (action) { |
|
969 |
case M_PROPERTY_GET: |
|
970 |
if (!arg) |
|
971 |
return M_PROPERTY_ERROR; |
|
972 |
*(int *) arg = video_id; |
|
973 |
return M_PROPERTY_OK; |
|
974 |
case M_PROPERTY_PRINT: |
|
975 |
if (!arg) |
|
976 |
return M_PROPERTY_ERROR; |
|
977 |
||
978 |
if (current_id < 0) |
|
979 |
*(char **) arg = strdup(MSGTR_Disabled); |
|
980 |
else { |
|
981 |
char lang[40] = MSGTR_Unknown; |
|
982 |
*(char **) arg = malloc(64); |
|
983 |
snprintf(*(char **) arg, 64, "(%d) %s", video_id, lang); |
|
984 |
}
|
|
985 |
return M_PROPERTY_OK; |
|
986 |
||
987 |
case M_PROPERTY_STEP_UP: |
|
988 |
case M_PROPERTY_SET: |
|
989 |
if (action == M_PROPERTY_SET && arg) |
|
990 |
tmp = *((int *) arg); |
|
991 |
else
|
|
992 |
tmp = -1; |
|
993 |
tmp = demuxer_switch_video(mpctx->demuxer, tmp); |
|
994 |
if (tmp == -2 |
|
995 |
|| (tmp > -1 && mpctx->demuxer->video->id != current_id |
|
996 |
&& current_id != -2)) { |
|
997 |
uninit_player(INITIALIZED_VCODEC | |
|
998 |
(fixed_vo && tmp != -2 ? 0 : INITIALIZED_VO)); |
|
999 |
video_id = tmp; |
|
1000 |
}
|
|
1001 |
if (tmp > -1 && mpctx->demuxer->video->id != current_id) { |
|
1002 |
sh_video_t *sh2; |
|
1003 |
sh2 = mpctx->demuxer->v_streams[mpctx->demuxer->video->id]; |
|
1004 |
if (sh2) { |
|
1005 |
video_id = sh2->vid; |
|
1006 |
sh2->ds = mpctx->demuxer->video; |
|
1007 |
mpctx->sh_video = sh2; |
|
1008 |
reinit_video_chain(); |
|
1009 |
}
|
|
1010 |
}
|
|
1011 |
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_TRACK=%d\n", video_id); |
|
1012 |
return M_PROPERTY_OK; |
|
1013 |
||
1014 |
default: |
|
1015 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
1016 |
}
|
|
1017 |
}
|
|
1018 |
||
1019 |
static int mp_property_program(m_option_t *prop, int action, void *arg, |
|
1020 |
MPContext *mpctx) |
|
1021 |
{
|
|
1022 |
demux_program_t prog; |
|
1023 |
||
1024 |
switch (action) { |
|
1025 |
case M_PROPERTY_STEP_UP: |
|
1026 |
case M_PROPERTY_SET: |
|
1027 |
if (action == M_PROPERTY_SET && arg) |
|
1028 |
prog.progid = *((int *) arg); |
|
1029 |
else
|
|
1030 |
prog.progid = -1; |
|
1031 |
if (demux_control |
|
1032 |
(mpctx->demuxer, DEMUXER_CTRL_IDENTIFY_PROGRAM, |
|
1033 |
&prog) == DEMUXER_CTRL_NOTIMPL) |
|
1034 |
return M_PROPERTY_ERROR; |
|
1035 |
||
1036 |
if (prog.aid < 0 && prog.vid < 0) { |
|
1037 |
mp_msg(MSGT_CPLAYER, MSGL_ERR, "Selected program contains no audio or video streams!\n"); |
|
1038 |
return M_PROPERTY_ERROR; |
|
1039 |
}
|
|
1040 |
mp_property_do("switch_audio", M_PROPERTY_SET, &prog.aid, mpctx); |
|
1041 |
mp_property_do("switch_video", M_PROPERTY_SET, &prog.vid, mpctx); |
|
1042 |
return M_PROPERTY_OK; |
|
1043 |
||
1044 |
default: |
|
1045 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
1046 |
}
|
|
1047 |
}
|
|
1048 |
||
1049 |
///@}
|
|
1050 |
||
1051 |
/// \defgroup VideoProperties Video properties
|
|
1052 |
/// \ingroup Properties
|
|
1053 |
///@{
|
|
1054 |
||
1055 |
/// Fullscreen state (RW)
|
|
1056 |
static int mp_property_fullscreen(m_option_t *prop, int action, void *arg, |
|
1057 |
MPContext *mpctx) |
|
1058 |
{
|
|
1059 |
||
1060 |
if (!mpctx->video_out) |
|
1061 |
return M_PROPERTY_UNAVAILABLE; |
|
1062 |
||
1063 |
switch (action) { |
|
1064 |
case M_PROPERTY_SET: |
|
1065 |
if (!arg) |
|
1066 |
return M_PROPERTY_ERROR; |
|
1067 |
M_PROPERTY_CLAMP(prop, *(int *) arg); |
|
1068 |
if (vo_fs == !!*(int *) arg) |
|
1069 |
return M_PROPERTY_OK; |
|
1070 |
case M_PROPERTY_STEP_UP: |
|
1071 |
case M_PROPERTY_STEP_DOWN: |
|
1072 |
#ifdef CONFIG_GUI
|
|
1073 |
if (use_gui) |
|
1074 |
gui(GUI_RUN_COMMAND, (void *) MP_CMD_VO_FULLSCREEN); |
|
1075 |
else
|
|
1076 |
#endif
|
|
1077 |
if (vo_config_count) |
|
1078 |
mpctx->video_out->control(VOCTRL_FULLSCREEN, 0); |
|
1079 |
return M_PROPERTY_OK; |
|
1080 |
default: |
|
1081 |
return m_property_flag(prop, action, arg, &vo_fs); |
|
1082 |
}
|
|
1083 |
}
|
|
1084 |
||
1085 |
static int mp_property_deinterlace(m_option_t *prop, int action, |
|
1086 |
void *arg, MPContext *mpctx) |
|
1087 |
{
|
|
1088 |
int deinterlace, deinterlace_old; |
|
1089 |
int result; |
|
1090 |
vf_instance_t *vf; |
|
1091 |
if (!mpctx->sh_video || !mpctx->sh_video->vfilter) |
|
1092 |
return M_PROPERTY_UNAVAILABLE; |
|
1093 |
vf = mpctx->sh_video->vfilter; |
|
1094 |
switch (action) { |
|
1095 |
case M_PROPERTY_GET: |
|
1096 |
if (!arg) |
|
1097 |
return M_PROPERTY_ERROR; |
|
1098 |
vf->control(vf, VFCTRL_GET_DEINTERLACE, arg); |
|
1099 |
return M_PROPERTY_OK; |
|
1100 |
case M_PROPERTY_SET: |
|
1101 |
if (!arg) |
|
1102 |
return M_PROPERTY_ERROR; |
|
1103 |
M_PROPERTY_CLAMP(prop, *(int *) arg); |
|
1104 |
result = vf->control(vf, VFCTRL_SET_DEINTERLACE, arg); |
|
1105 |
return (result == CONTROL_OK) ? M_PROPERTY_OK : M_PROPERTY_UNAVAILABLE; |
|
1106 |
case M_PROPERTY_STEP_UP: |
|
1107 |
case M_PROPERTY_STEP_DOWN: |
|
1108 |
vf->control(vf, VFCTRL_GET_DEINTERLACE, &deinterlace_old); |
|
1109 |
deinterlace = !deinterlace_old; |
|
1110 |
result = vf->control(vf, VFCTRL_SET_DEINTERLACE, &deinterlace); |
|
1111 |
if (result != CONTROL_OK) { |
|
1112 |
deinterlace = deinterlace_old; |
|
1113 |
}
|
|
1114 |
set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDDeinterlace, |
|
1115 |
deinterlace ? MSGTR_Enabled : MSGTR_Disabled); |
|
1116 |
return (result == CONTROL_OK) ? M_PROPERTY_OK : M_PROPERTY_UNAVAILABLE; |
|
1117 |
}
|
|
1118 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
1119 |
}
|
|
1120 |
||
1121 |
static int mp_property_capture(m_option_t *prop, int action, |
|
1122 |
void *arg, MPContext *mpctx) |
|
1123 |
{
|
|
1124 |
int ret; |
|
1125 |
int capturing = mpctx->stream && mpctx->stream->capture_file; |
|
1126 |
||
1127 |
if (!mpctx->stream) |
|
1128 |
return M_PROPERTY_UNAVAILABLE; |
|
1129 |
if (!capture_dump) { |
|
1130 |
mp_msg(MSGT_GLOBAL, MSGL_ERR, |
|
1131 |
"Capturing not enabled (forgot -capture parameter?)\n"); |
|
1132 |
return M_PROPERTY_ERROR; |
|
1133 |
}
|
|
1134 |
||
1135 |
ret = m_property_flag(prop, action, arg, &capturing); |
|
1136 |
if (ret == M_PROPERTY_OK && capturing != !!mpctx->stream->capture_file) { |
|
1137 |
if (capturing) { |
|
1138 |
mpctx->stream->capture_file = fopen(stream_dump_name, "ab"); |
|
1139 |
if (!mpctx->stream->capture_file) { |
|
1140 |
mp_msg(MSGT_GLOBAL, MSGL_ERR, |
|
1141 |
"Error opening capture file: %s\n", strerror(errno)); |
|
1142 |
ret = M_PROPERTY_ERROR; |
|
1143 |
}
|
|
1144 |
} else { |
|
1145 |
fclose(mpctx->stream->capture_file); |
|
1146 |
mpctx->stream->capture_file = NULL; |
|
1147 |
}
|
|
1148 |
}
|
|
1149 |
||
1150 |
switch (ret) { |
|
1151 |
case M_PROPERTY_ERROR: |
|
1152 |
set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDCapturingFailure); |
|
1153 |
break; |
|
1154 |
case M_PROPERTY_OK: |
|
1155 |
set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDCapturing, |
|
1156 |
mpctx->stream->capture_file ? MSGTR_Enabled : MSGTR_Disabled); |
|
1157 |
break; |
|
1158 |
default: |
|
1159 |
break; |
|
1160 |
}
|
|
1161 |
||
1162 |
return ret; |
|
1163 |
}
|
|
1164 |
||
1165 |
/// Panscan (RW)
|
|
1166 |
static int mp_property_panscan(m_option_t *prop, int action, void *arg, |
|
1167 |
MPContext *mpctx) |
|
1168 |
{
|
|
1169 |
||
1170 |
if (!mpctx->video_out |
|
1171 |
|| mpctx->video_out->control(VOCTRL_GET_PANSCAN, NULL) != VO_TRUE) |
|
1172 |
return M_PROPERTY_UNAVAILABLE; |
|
1173 |
||
1174 |
switch (action) { |
|
1175 |
case M_PROPERTY_SET: |
|
1176 |
if (!arg) |
|
1177 |
return M_PROPERTY_ERROR; |
|
1178 |
M_PROPERTY_CLAMP(prop, *(float *) arg); |
|
1179 |
vo_panscan = *(float *) arg; |
|
1180 |
mpctx->video_out->control(VOCTRL_SET_PANSCAN, NULL); |
|
1181 |
return M_PROPERTY_OK; |
|
1182 |
case M_PROPERTY_STEP_UP: |
|
1183 |
case M_PROPERTY_STEP_DOWN: |
|
1184 |
vo_panscan += (arg ? *(float *) arg : 0.1) * |
|
1185 |
(action == M_PROPERTY_STEP_DOWN ? -1 : 1); |
|
1186 |
if (vo_panscan > 1) |
|
1187 |
vo_panscan = 1; |
|
1188 |
else if (vo_panscan < 0) |
|
1189 |
vo_panscan = 0; |
|
1190 |
mpctx->video_out->control(VOCTRL_SET_PANSCAN, NULL); |
|
1191 |
return M_PROPERTY_OK; |
|
1192 |
default: |
|
1193 |
return m_property_float_range(prop, action, arg, &vo_panscan); |
|
1194 |
}
|
|
1195 |
}
|
|
1196 |
||
1197 |
/// Helper to set vo flags.
|
|
1198 |
/** \ingroup PropertyImplHelper
|
|
1199 |
*/
|
|
1200 |
static int mp_property_vo_flag(m_option_t *prop, int action, void *arg, |
|
1201 |
int vo_ctrl, int *vo_var, MPContext *mpctx) |
|
1202 |
{
|
|
1203 |
||
1204 |
if (!mpctx->video_out) |
|
1205 |
return M_PROPERTY_UNAVAILABLE; |
|
1206 |
||
1207 |
switch (action) { |
|
1208 |
case M_PROPERTY_SET: |
|
1209 |
if (!arg) |
|
1210 |
return M_PROPERTY_ERROR; |
|
1211 |
M_PROPERTY_CLAMP(prop, *(int *) arg); |
|
1212 |
if (*vo_var == !!*(int *) arg) |
|
1213 |
return M_PROPERTY_OK; |
|
1214 |
case M_PROPERTY_STEP_UP: |
|
1215 |
case M_PROPERTY_STEP_DOWN: |
|
1216 |
if (vo_config_count) |
|
1217 |
mpctx->video_out->control(vo_ctrl, 0); |
|
1218 |
return M_PROPERTY_OK; |
|
1219 |
default: |
|
1220 |
return m_property_flag(prop, action, arg, vo_var); |
|
1221 |
}
|
|
1222 |
}
|
|
1223 |
||
1224 |
/// Window always on top (RW)
|
|
1225 |
static int mp_property_ontop(m_option_t *prop, int action, void *arg, |
|
1226 |
MPContext *mpctx) |
|
1227 |
{
|
|
1228 |
return mp_property_vo_flag(prop, action, arg, VOCTRL_ONTOP, &vo_ontop, |
|
1229 |
mpctx); |
|
1230 |
}
|
|
1231 |
||
1232 |
/// Display in the root window (RW)
|
|
1233 |
static int mp_property_rootwin(m_option_t *prop, int action, void *arg, |
|
1234 |
MPContext *mpctx) |
|
1235 |
{
|
|
1236 |
return mp_property_vo_flag(prop, action, arg, VOCTRL_ROOTWIN, |
|
1237 |
&vo_rootwin, mpctx); |
|
1238 |
}
|
|
1239 |
||
1240 |
/// Show window borders (RW)
|
|
1241 |
static int mp_property_border(m_option_t *prop, int action, void *arg, |
|
1242 |
MPContext *mpctx) |
|
1243 |
{
|
|
1244 |
return mp_property_vo_flag(prop, action, arg, VOCTRL_BORDER, |
|
1245 |
&vo_border, mpctx); |
|
1246 |
}
|
|
1247 |
||
1248 |
/// Framedropping state (RW)
|
|
1249 |
static int mp_property_framedropping(m_option_t *prop, int action, |
|
1250 |
void *arg, MPContext *mpctx) |
|
1251 |
{
|
|
1252 |
||
1253 |
if (!mpctx->sh_video) |
|
1254 |
return M_PROPERTY_UNAVAILABLE; |
|
1255 |
||
1256 |
switch (action) { |
|
1257 |
case M_PROPERTY_PRINT: |
|
1258 |
if (!arg) |
|
1259 |
return M_PROPERTY_ERROR; |
|
1260 |
*(char **) arg = strdup(frame_dropping == 1 ? MSGTR_Enabled : |
|
1261 |
(frame_dropping == 2 ? MSGTR_HardFrameDrop : |
|
1262 |
MSGTR_Disabled)); |
|
1263 |
return M_PROPERTY_OK; |
|
1264 |
default: |
|
1265 |
return m_property_choice(prop, action, arg, &frame_dropping); |
|
1266 |
}
|
|
1267 |
}
|
|
1268 |
||
1269 |
/// Color settings, try to use vf/vo then fall back on TV. (RW)
|
|
1270 |
static int mp_property_gamma(m_option_t *prop, int action, void *arg, |
|
1271 |
MPContext *mpctx) |
|
1272 |
{
|
|
1273 |
int *gamma = prop->priv, r, val; |
|
1274 |
||
1275 |
if (!mpctx->sh_video) |
|
1276 |
return M_PROPERTY_UNAVAILABLE; |
|
1277 |
||
1278 |
if (gamma[0] == 1000) { |
|
1279 |
gamma[0] = 0; |
|
1280 |
get_video_colors(mpctx->sh_video, prop->name, gamma); |
|
1281 |
}
|
|
1282 |
||
1283 |
switch (action) { |
|
1284 |
case M_PROPERTY_SET: |
|
1285 |
if (!arg) |
|
1286 |
return M_PROPERTY_ERROR; |
|
1287 |
M_PROPERTY_CLAMP(prop, *(int *) arg); |
|
1288 |
*gamma = *(int *) arg; |
|
1289 |
r = set_video_colors(mpctx->sh_video, prop->name, *gamma); |
|
1290 |
if (r <= 0) |
|
1291 |
break; |
|
1292 |
return r; |
|
1293 |
case M_PROPERTY_GET: |
|
1294 |
if (get_video_colors(mpctx->sh_video, prop->name, &val) > 0) { |
|
1295 |
if (!arg) |
|
1296 |
return M_PROPERTY_ERROR; |
|
1297 |
*(int *)arg = val; |
|
1298 |
return M_PROPERTY_OK; |
|
1299 |
}
|
|
1300 |
break; |
|
1301 |
case M_PROPERTY_STEP_UP: |
|
1302 |
case M_PROPERTY_STEP_DOWN: |
|
1303 |
*gamma += (arg ? *(int *) arg : 1) * |
|
1304 |
(action == M_PROPERTY_STEP_DOWN ? -1 : 1); |
|
1305 |
M_PROPERTY_CLAMP(prop, *gamma); |
|
1306 |
r = set_video_colors(mpctx->sh_video, prop->name, *gamma); |
|
1307 |
if (r <= 0) |
|
1308 |
break; |
|
1309 |
return r; |
|
1310 |
default: |
|
1311 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
1312 |
}
|
|
1313 |
||
1314 |
#ifdef CONFIG_TV
|
|
1315 |
if (mpctx->demuxer->type == DEMUXER_TYPE_TV) { |
|
1316 |
int l = strlen(prop->name); |
|
1317 |
char tv_prop[3 + l + 1]; |
|
1318 |
sprintf(tv_prop, "tv_%s", prop->name); |
|
1319 |
return mp_property_do(tv_prop, action, arg, mpctx); |
|
1320 |
}
|
|
1321 |
#endif
|
|
1322 |
||
1323 |
return M_PROPERTY_UNAVAILABLE; |
|
1324 |
}
|
|
1325 |
||
1326 |
/// VSync (RW)
|
|
1327 |
static int mp_property_vsync(m_option_t *prop, int action, void *arg, |
|
1328 |
MPContext *mpctx) |
|
1329 |
{
|
|
1330 |
return m_property_flag(prop, action, arg, &vo_vsync); |
|
1331 |
}
|
|
1332 |
||
1333 |
/// Video codec tag (RO)
|
|
1334 |
static int mp_property_video_format(m_option_t *prop, int action, |
|
1335 |
void *arg, MPContext *mpctx) |
|
1336 |
{
|
|
1337 |
char* meta; |
|
1338 |
if (!mpctx->sh_video) |
|
1339 |
return M_PROPERTY_UNAVAILABLE; |
|
1340 |
switch(action) { |
|
1341 |
case M_PROPERTY_PRINT: |
|
1342 |
if (!arg) |
|
1343 |
return M_PROPERTY_ERROR; |
|
1344 |
switch(mpctx->sh_video->format) { |
|
1345 |
case 0x10000001: |
|
1346 |
meta = strdup ("mpeg1"); break; |
|
1347 |
case 0x10000002: |
|
1348 |
meta = strdup ("mpeg2"); break; |
|
1349 |
case 0x10000004: |
|
1350 |
meta = strdup ("mpeg4"); break; |
|
1351 |
case 0x10000005: |
|
1352 |
meta = strdup ("h264"); break; |
|
1353 |
default: |
|
1354 |
if(mpctx->sh_video->format >= 0x20202020) { |
|
1355 |
meta = malloc(5); |
|
1356 |
sprintf (meta, "%.4s", (char *) &mpctx->sh_video->format); |
|
1357 |
} else { |
|
1358 |
meta = malloc(20); |
|
1359 |
sprintf (meta, "0x%08X", mpctx->sh_video->format); |
|
1360 |
}
|
|
1361 |
}
|
|
1362 |
*(char**)arg = meta; |
|
1363 |
return M_PROPERTY_OK; |
|
1364 |
}
|
|
1365 |
return m_property_int_ro(prop, action, arg, mpctx->sh_video->format); |
|
1366 |
}
|
|
1367 |
||
1368 |
/// Video codec name (RO)
|
|
1369 |
static int mp_property_video_codec(m_option_t *prop, int action, |
|
1370 |
void *arg, MPContext *mpctx) |
|
1371 |
{
|
|
1372 |
if (!mpctx->sh_video || !mpctx->sh_video->codec) |
|
1373 |
return M_PROPERTY_UNAVAILABLE; |
|
1374 |
return m_property_string_ro(prop, action, arg, mpctx->sh_video->codec->name); |
|
1375 |
}
|
|
1376 |
||
1377 |
||
1378 |
/// Video bitrate (RO)
|
|
1379 |
static int mp_property_video_bitrate(m_option_t *prop, int action, |
|
1380 |
void *arg, MPContext *mpctx) |
|
1381 |
{
|
|
1382 |
if (!mpctx->sh_video) |
|
1383 |
return M_PROPERTY_UNAVAILABLE; |
|
1384 |
return m_property_bitrate(prop, action, arg, mpctx->sh_video->i_bps); |
|
1385 |
}
|
|
1386 |
||
1387 |
/// Video display width (RO)
|
|
1388 |
static int mp_property_width(m_option_t *prop, int action, void *arg, |
|
1389 |
MPContext *mpctx) |
|
1390 |
{
|
|
1391 |
if (!mpctx->sh_video) |
|
1392 |
return M_PROPERTY_UNAVAILABLE; |
|
1393 |
return m_property_int_ro(prop, action, arg, mpctx->sh_video->disp_w); |
|
1394 |
}
|
|
1395 |
||
1396 |
/// Video display height (RO)
|
|
1397 |
static int mp_property_height(m_option_t *prop, int action, void *arg, |
|
1398 |
MPContext *mpctx) |
|
1399 |
{
|
|
1400 |
if (!mpctx->sh_video) |
|
1401 |
return M_PROPERTY_UNAVAILABLE; |
|
1402 |
return m_property_int_ro(prop, action, arg, mpctx->sh_video->disp_h); |
|
1403 |
}
|
|
1404 |
||
1405 |
/// Video fps (RO)
|
|
1406 |
static int mp_property_fps(m_option_t *prop, int action, void *arg, |
|
1407 |
MPContext *mpctx) |
|
1408 |
{
|
|
1409 |
if (!mpctx->sh_video) |
|
1410 |
return M_PROPERTY_UNAVAILABLE; |
|
1411 |
return m_property_float_ro(prop, action, arg, mpctx->sh_video->fps); |
|
1412 |
}
|
|
1413 |
||
1414 |
/// Video aspect (RO)
|
|
1415 |
static int mp_property_aspect(m_option_t *prop, int action, void *arg, |
|
1416 |
MPContext *mpctx) |
|
1417 |
{
|
|
1418 |
if (!mpctx->sh_video) |
|
1419 |
return M_PROPERTY_UNAVAILABLE; |
|
1420 |
return m_property_float_ro(prop, action, arg, mpctx->sh_video->aspect); |
|
1421 |
}
|
|
1422 |
||
1423 |
///@}
|
|
1424 |
||
1425 |
/// \defgroup SubProprties Subtitles properties
|
|
1426 |
/// \ingroup Properties
|
|
1427 |
///@{
|
|
1428 |
||
1429 |
/// Text subtitle position (RW)
|
|
1430 |
static int mp_property_sub_pos(m_option_t *prop, int action, void *arg, |
|
1431 |
MPContext *mpctx) |
|
1432 |
{
|
|
1433 |
switch (action) { |
|
1434 |
case M_PROPERTY_SET: |
|
1435 |
if (!arg) |
|
1436 |
return M_PROPERTY_ERROR; |
|
1437 |
case M_PROPERTY_STEP_UP: |
|
1438 |
case M_PROPERTY_STEP_DOWN: |
|
1439 |
vo_osd_changed(OSDTYPE_SUBTITLE); |
|
1440 |
default: |
|
1441 |
return m_property_int_range(prop, action, arg, &sub_pos); |
|
1442 |
}
|
|
1443 |
}
|
|
1444 |
||
1445 |
/// Selected subtitles (RW)
|
|
1446 |
static int mp_property_sub(m_option_t *prop, int action, void *arg, |
|
1447 |
MPContext *mpctx) |
|
1448 |
{
|
|
1449 |
demux_stream_t *const d_sub = mpctx->d_sub; |
|
1450 |
int global_sub_size; |
|
1451 |
int source = -1, reset_spu = 0; |
|
1452 |
int source_pos = -1; |
|
1453 |
double pts = 0; |
|
1454 |
char *sub_name; |
|
1455 |
||
1456 |
update_global_sub_size(mpctx); |
|
1457 |
global_sub_size = mpctx->global_sub_size; |
|
1458 |
if (global_sub_size <= 0) |
|
1459 |
return M_PROPERTY_UNAVAILABLE; |
|
1460 |
||
1461 |
switch (action) { |
|
1462 |
case M_PROPERTY_GET: |
|
1463 |
if (!arg) |
|
1464 |
return M_PROPERTY_ERROR; |
|
1465 |
*(int *) arg = mpctx->global_sub_pos; |
|
1466 |
return M_PROPERTY_OK; |
|
1467 |
case M_PROPERTY_PRINT: |
|
1468 |
if (!arg) |
|
1469 |
return M_PROPERTY_ERROR; |
|
1470 |
*(char **) arg = malloc(64); |
|
1471 |
(*(char **) arg)[63] = 0; |
|
1472 |
sub_name = 0; |
|
1473 |
if (subdata) |
|
1474 |
sub_name = subdata->filename; |
|
1475 |
#ifdef CONFIG_ASS
|
|
1476 |
if (ass_track && ass_track->name) |
|
1477 |
sub_name = ass_track->name; |
|
1478 |
#endif
|
|
1479 |
if (sub_name) { |
|
1480 |
const char *tmp = mp_basename(sub_name); |
|
1481 |
||
1482 |
snprintf(*(char **) arg, 63, "(%d) %s%s", |
|
1483 |
mpctx->set_of_sub_pos + 1, |
|
1484 |
strlen(tmp) < 20 ? "" : "...", |
|
1485 |
strlen(tmp) < 20 ? tmp : tmp + strlen(tmp) - 19); |
|
1486 |
return M_PROPERTY_OK; |
|
1487 |
}
|
|
1488 |
||
1489 |
if (vo_vobsub && vobsub_id >= 0) { |
|
1490 |
const char *language = MSGTR_Unknown; |
|
1491 |
language = vobsub_get_id(vo_vobsub, (unsigned int) vobsub_id); |
|
1492 |
snprintf(*(char **) arg, 63, "(%d) %s", |
|
1493 |
vobsub_id, language ? language : MSGTR_Unknown); |
|
1494 |
return M_PROPERTY_OK; |
|
1495 |
}
|
|
1496 |
if (dvdsub_id >= 0) { |
|
1497 |
char lang[40] = MSGTR_Unknown; |
|
1498 |
int id = dvdsub_id; |
|
1499 |
// HACK: for DVDs sub->sh/id will be invalid until
|
|
1500 |
// we actually get the first packet
|
|
1501 |
if (d_sub && d_sub->sh) |
|
1502 |
id = d_sub->id; |
|
1503 |
demuxer_sub_lang(mpctx->demuxer, id, lang, sizeof(lang)); |
|
1504 |
snprintf(*(char **) arg, 63, "(%d) %s", dvdsub_id, lang); |
|
1505 |
return M_PROPERTY_OK; |
|
1506 |
}
|
|
1507 |
snprintf(*(char **) arg, 63, MSGTR_Disabled); |
|
1508 |
return M_PROPERTY_OK; |
|
1509 |
||
1510 |
case M_PROPERTY_SET: |
|
1511 |
if (!arg) |
|
1512 |
return M_PROPERTY_ERROR; |
|
1513 |
if (*(int *) arg < -1) |
|
1514 |
*(int *) arg = -1; |
|
1515 |
else if (*(int *) arg >= global_sub_size) |
|
1516 |
*(int *) arg = global_sub_size - 1; |
|
1517 |
mpctx->global_sub_pos = *(int *) arg; |
|
1518 |
break; |
|
1519 |
case M_PROPERTY_STEP_UP: |
|
1520 |
mpctx->global_sub_pos += 2; |
|
1521 |
mpctx->global_sub_pos = |
|
1522 |
(mpctx->global_sub_pos % (global_sub_size + 1)) - 1; |
|
1523 |
break; |
|
1524 |
case M_PROPERTY_STEP_DOWN: |
|
1525 |
mpctx->global_sub_pos += global_sub_size + 1; |
|
1526 |
mpctx->global_sub_pos = |
|
1527 |
(mpctx->global_sub_pos % (global_sub_size + 1)) - 1; |
|
1528 |
break; |
|
1529 |
default: |
|
1530 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
1531 |
}
|
|
1532 |
||
1533 |
if (mpctx->global_sub_pos >= 0) { |
|
1534 |
source = sub_source(mpctx); |
|
1535 |
source_pos = sub_source_pos(mpctx); |
|
1536 |
}
|
|
1537 |
||
1538 |
mp_msg(MSGT_CPLAYER, MSGL_DBG3, |
|
1539 |
"subtitles: %d subs, (v@%d s@%d d@%d), @%d, source @%d\n", |
|
1540 |
global_sub_size, |
|
1541 |
mpctx->sub_counts[SUB_SOURCE_VOBSUB], |
|
1542 |
mpctx->sub_counts[SUB_SOURCE_SUBS], |
|
1543 |
mpctx->sub_counts[SUB_SOURCE_DEMUX], |
|
1544 |
mpctx->global_sub_pos, source); |
|
1545 |
||
1546 |
mpctx->set_of_sub_pos = -1; |
|
1547 |
subdata = NULL; |
|
1548 |
||
1549 |
vobsub_id = -1; |
|
1550 |
dvdsub_id = -1; |
|
1551 |
if (d_sub) { |
|
1552 |
if (d_sub->id > -2) |
|
1553 |
reset_spu = 1; |
|
1554 |
d_sub->id = -2; |
|
1555 |
}
|
|
1556 |
#ifdef CONFIG_ASS
|
|
1557 |
ass_track = 0; |
|
1558 |
#endif
|
|
1559 |
||
1560 |
if (source == SUB_SOURCE_VOBSUB) { |
|
1561 |
vobsub_id = vobsub_get_id_by_index(vo_vobsub, source_pos); |
|
1562 |
} else if (source == SUB_SOURCE_SUBS) { |
|
1563 |
mpctx->set_of_sub_pos = source_pos; |
|
1564 |
#ifdef CONFIG_ASS
|
|
1565 |
if (ass_enabled && mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos]) |
|
1566 |
ass_track = mpctx->set_of_ass_tracks[mpctx->set_of_sub_pos]; |
|
1567 |
else
|
|
1568 |
#endif
|
|
1569 |
{
|
|
1570 |
subdata = mpctx->set_of_subtitles[mpctx->set_of_sub_pos]; |
|
1571 |
vo_osd_changed(OSDTYPE_SUBTITLE); |
|
1572 |
}
|
|
1573 |
} else if (source == SUB_SOURCE_DEMUX) { |
|
1574 |
dvdsub_id = source_pos; |
|
1575 |
if (d_sub && dvdsub_id < MAX_S_STREAMS) { |
|
1576 |
int i = 0; |
|
1577 |
// default: assume 1:1 mapping of sid and stream id
|
|
1578 |
d_sub->id = dvdsub_id; |
|
1579 |
d_sub->sh = mpctx->demuxer->s_streams[d_sub->id]; |
|
1580 |
ds_free_packs(d_sub); |
|
1581 |
for (i = 0; i < MAX_S_STREAMS; i++) { |
|
1582 |
sh_sub_t *sh = mpctx->demuxer->s_streams[i]; |
|
1583 |
if (sh && sh->sid == dvdsub_id) { |
|
1584 |
d_sub->id = i; |
|
1585 |
d_sub->sh = sh; |
|
1586 |
break; |
|
1587 |
}
|
|
1588 |
}
|
|
1589 |
if (d_sub->sh && d_sub->id >= 0) { |
|
1590 |
sh_sub_t *sh = d_sub->sh; |
|
1591 |
if (sh->type == 'v') |
|
1592 |
init_vo_spudec(mpctx->stream, mpctx->sh_video, sh); |
|
1593 |
#ifdef CONFIG_ASS
|
|
1594 |
else if (ass_enabled) |
|
1595 |
ass_track = sh->ass_track; |
|
1596 |
#endif
|
|
1597 |
} else { |
|
1598 |
d_sub->id = -2; |
|
1599 |
d_sub->sh = NULL; |
|
1600 |
}
|
|
1601 |
}
|
|
1602 |
}
|
|
1603 |
#ifdef CONFIG_DVDREAD
|
|
1604 |
if (vo_spudec |
|
1605 |
&& (IS_STREAMTYPE(DVD) |
|
1606 |
|| IS_STREAMTYPE(DVDNAV)) |
|
1607 |
&& dvdsub_id < 0 && reset_spu) { |
|
1608 |
d_sub->id = -2; |
|
1609 |
d_sub->sh = NULL; |
|
1610 |
}
|
|
1611 |
#endif
|
|
1612 |
if (mpctx->sh_audio) |
|
1613 |
pts = mpctx->sh_audio->pts; |
|
1614 |
if (mpctx->sh_video) |
|
1615 |
pts = mpctx->sh_video->pts; |
|
1616 |
update_subtitles(mpctx->sh_video, pts, d_sub, 1); |
|
1617 |
||
1618 |
return M_PROPERTY_OK; |
|
1619 |
}
|
|
1620 |
||
1621 |
/// Selected sub source (RW)
|
|
1622 |
static int mp_property_sub_source(m_option_t *prop, int action, void *arg, |
|
1623 |
MPContext *mpctx) |
|
1624 |
{
|
|
1625 |
int source; |
|
1626 |
update_global_sub_size(mpctx); |
|
1627 |
if (!mpctx->sh_video || mpctx->global_sub_size <= 0) |
|
1628 |
return M_PROPERTY_UNAVAILABLE; |
|
1629 |
||
1630 |
switch (action) { |
|
1631 |
case M_PROPERTY_GET: |
|
1632 |
if (!arg) |
|
1633 |
return M_PROPERTY_ERROR; |
|
1634 |
*(int *) arg = sub_source(mpctx); |
|
1635 |
return M_PROPERTY_OK; |
|
1636 |
case M_PROPERTY_PRINT: |
|
1637 |
if (!arg) |
|
1638 |
return M_PROPERTY_ERROR; |
|
1639 |
*(char **) arg = malloc(64); |
|
1640 |
(*(char **) arg)[63] = 0; |
|
1641 |
switch (sub_source(mpctx)) |
|
1642 |
{
|
|
1643 |
case SUB_SOURCE_SUBS: |
|
1644 |
snprintf(*(char **) arg, 63, MSGTR_SubSourceFile); |
|
1645 |
break; |
|
1646 |
case SUB_SOURCE_VOBSUB: |
|
1647 |
snprintf(*(char **) arg, 63, MSGTR_SubSourceVobsub); |
|
1648 |
break; |
|
1649 |
case SUB_SOURCE_DEMUX: |
|
1650 |
snprintf(*(char **) arg, 63, MSGTR_SubSourceDemux); |
|
1651 |
break; |
|
1652 |
default: |
|
1653 |
snprintf(*(char **) arg, 63, MSGTR_Disabled); |
|
1654 |
}
|
|
1655 |
return M_PROPERTY_OK; |
|
1656 |
case M_PROPERTY_SET: |
|
1657 |
if (!arg) |
|
1658 |
return M_PROPERTY_ERROR; |
|
1659 |
M_PROPERTY_CLAMP(prop, *(int*)arg); |
|
1660 |
if (*(int *) arg < 0) |
|
1661 |
mpctx->global_sub_pos = -1; |
|
1662 |
else if (*(int *) arg != sub_source(mpctx)) { |
|
1663 |
int new_pos = sub_pos_by_source(mpctx, *(int *)arg); |
|
1664 |
if (new_pos == -1) |
|
1665 |
return M_PROPERTY_UNAVAILABLE; |
|
1666 |
mpctx->global_sub_pos = new_pos; |
|
1667 |
}
|
|
1668 |
break; |
|
1669 |
case M_PROPERTY_STEP_UP: |
|
1670 |
case M_PROPERTY_STEP_DOWN: { |
|
1671 |
int step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1) |
|
1672 |
* (action == M_PROPERTY_STEP_UP ? 1 : -1); |
|
1673 |
int step = (step_all > 0) ? 1 : -1; |
|
1674 |
int cur_source = sub_source(mpctx); |
|
1675 |
source = cur_source; |
|
1676 |
while (step_all) { |
|
1677 |
source += step; |
|
1678 |
if (source >= SUB_SOURCES) |
|
1679 |
source = -1; |
|
1680 |
else if (source < -1) |
|
1681 |
source = SUB_SOURCES - 1; |
|
1682 |
if (source == cur_source || source == -1 || |
|
1683 |
mpctx->sub_counts[source]) |
|
1684 |
step_all -= step; |
|
1685 |
}
|
|
1686 |
if (source == cur_source) |
|
1687 |
return M_PROPERTY_OK; |
|
1688 |
if (source == -1) |
|
1689 |
mpctx->global_sub_pos = -1; |
|
1690 |
else
|
|
1691 |
mpctx->global_sub_pos = sub_pos_by_source(mpctx, source); |
|
1692 |
break; |
|
1693 |
}
|
|
1694 |
default: |
|
1695 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
1696 |
}
|
|
1697 |
--mpctx->global_sub_pos; |
|
1698 |
return mp_property_sub(prop, M_PROPERTY_STEP_UP, NULL, mpctx); |
|
1699 |
}
|
|
1700 |
||
1701 |
/// Selected subtitles from specific source (RW)
|
|
1702 |
static int mp_property_sub_by_type(m_option_t *prop, int action, void *arg, |
|
1703 |
MPContext *mpctx) |
|
1704 |
{
|
|
1705 |
int source, is_cur_source, offset, new_pos; |
|
1706 |
update_global_sub_size(mpctx); |
|
1707 |
if (!mpctx->sh_video || mpctx->global_sub_size <= 0) |
|
1708 |
return M_PROPERTY_UNAVAILABLE; |
|
1709 |
||
1710 |
if (!strcmp(prop->name, "sub_file")) |
|
1711 |
source = SUB_SOURCE_SUBS; |
|
1712 |
else if (!strcmp(prop->name, "sub_vob")) |
|
1713 |
source = SUB_SOURCE_VOBSUB; |
|
1714 |
else if (!strcmp(prop->name, "sub_demux")) |
|
1715 |
source = SUB_SOURCE_DEMUX; |
|
1716 |
else
|
|
1717 |
return M_PROPERTY_ERROR; |
|
1718 |
||
1719 |
offset = sub_pos_by_source(mpctx, source); |
|
1720 |
if (offset < 0) |
|
1721 |
return M_PROPERTY_UNAVAILABLE; |
|
1722 |
||
1723 |
is_cur_source = sub_source(mpctx) == source; |
|
1724 |
new_pos = mpctx->global_sub_pos; |
|
1725 |
switch (action) { |
|
1726 |
case M_PROPERTY_GET: |
|
1727 |
if (!arg) |
|
1728 |
return M_PROPERTY_ERROR; |
|
1729 |
if (is_cur_source) { |
|
1730 |
*(int *) arg = sub_source_pos(mpctx); |
|
1731 |
if (source == SUB_SOURCE_VOBSUB) |
|
1732 |
*(int *) arg = vobsub_get_id_by_index(vo_vobsub, *(int *) arg); |
|
1733 |
}
|
|
1734 |
else
|
|
1735 |
*(int *) arg = -1; |
|
1736 |
return M_PROPERTY_OK; |
|
1737 |
case M_PROPERTY_PRINT: |
|
1738 |
if (!arg) |
|
1739 |
return M_PROPERTY_ERROR; |
|
1740 |
if (is_cur_source) |
|
1741 |
return mp_property_sub(prop, M_PROPERTY_PRINT, arg, mpctx); |
|
1742 |
*(char **) arg = malloc(64); |
|
1743 |
(*(char **) arg)[63] = 0; |
|
1744 |
snprintf(*(char **) arg, 63, MSGTR_Disabled); |
|
1745 |
return M_PROPERTY_OK; |
|
1746 |
case M_PROPERTY_SET: |
|
1747 |
if (!arg) |
|
1748 |
return M_PROPERTY_ERROR; |
|
1749 |
if (*(int *) arg >= 0) { |
|
1750 |
int index = *(int *)arg; |
|
1751 |
if (source == SUB_SOURCE_VOBSUB) |
|
1752 |
index = vobsub_get_index_by_id(vo_vobsub, index); |
|
1753 |
new_pos = offset + index; |
|
1754 |
if (index < 0 || index > mpctx->sub_counts[source]) { |
|
1755 |
new_pos = -1; |
|
1756 |
*(int *) arg = -1; |
|
1757 |
}
|
|
1758 |
}
|
|
1759 |
else
|
|
1760 |
new_pos = -1; |
|
1761 |
break; |
|
1762 |
case M_PROPERTY_STEP_UP: |
|
1763 |
case M_PROPERTY_STEP_DOWN: { |
|
1764 |
int step_all = (arg && *(int*)arg != 0 ? *(int*)arg : 1) |
|
1765 |
* (action == M_PROPERTY_STEP_UP ? 1 : -1); |
|
1766 |
int step = (step_all > 0) ? 1 : -1; |
|
1767 |
int max_sub_pos_for_source = -1; |
|
1768 |
if (!is_cur_source) |
|
1769 |
new_pos = -1; |
|
1770 |
while (step_all) { |
|
1771 |
if (new_pos == -1) { |
|
1772 |
if (step > 0) |
|
1773 |
new_pos = offset; |
|
1774 |
else if (max_sub_pos_for_source == -1) { |
|
1775 |
// Find max pos for specific source
|
|
1776 |
new_pos = mpctx->global_sub_size - 1; |
|
1777 |
while (new_pos >= 0 |
|
1778 |
&& sub_source(mpctx) != source) |
|
1779 |
new_pos--; |
|
1780 |
// cache for next time
|
|
1781 |
max_sub_pos_for_source = new_pos; |
|
1782 |
}
|
|
1783 |
else
|
|
1784 |
new_pos = max_sub_pos_for_source; |
|
1785 |
}
|
|
1786 |
else { |
|
1787 |
new_pos += step; |
|
1788 |
if (new_pos < offset || |
|
1789 |
new_pos >= mpctx->global_sub_size || |
|
1790 |
sub_source(mpctx) != source) |
|
1791 |
new_pos = -1; |
|
1792 |
}
|
|
1793 |
step_all -= step; |
|
1794 |
}
|
|
1795 |
break; |
|
1796 |
}
|
|
1797 |
default: |
|
1798 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
1799 |
}
|
|
1800 |
return mp_property_sub(prop, M_PROPERTY_SET, &new_pos, mpctx); |
|
1801 |
}
|
|
1802 |
||
1803 |
/// Subtitle delay (RW)
|
|
1804 |
static int mp_property_sub_delay(m_option_t *prop, int action, void *arg, |
|
1805 |
MPContext *mpctx) |
|
1806 |
{
|
|
1807 |
if (!mpctx->sh_video) |
|
1808 |
return M_PROPERTY_UNAVAILABLE; |
|
1809 |
return m_property_delay(prop, action, arg, &sub_delay); |
|
1810 |
}
|
|
1811 |
||
1812 |
/// Alignment of text subtitles (RW)
|
|
1813 |
static int mp_property_sub_alignment(m_option_t *prop, int action, |
|
1814 |
void *arg, MPContext *mpctx) |
|
1815 |
{
|
|
1816 |
char *name[] = { MSGTR_Top, MSGTR_Center, MSGTR_Bottom }; |
|
1817 |
||
1818 |
if (!mpctx->sh_video || mpctx->global_sub_pos < 0 |
|
1819 |
|| sub_source(mpctx) != SUB_SOURCE_SUBS) |
|
1820 |
return M_PROPERTY_UNAVAILABLE; |
|
1821 |
||
1822 |
switch (action) { |
|
1823 |
case M_PROPERTY_PRINT: |
|
1824 |
if (!arg) |
|
1825 |
return M_PROPERTY_ERROR; |
|
1826 |
M_PROPERTY_CLAMP(prop, sub_alignment); |
|
1827 |
*(char **) arg = strdup(name[sub_alignment]); |
|
1828 |
return M_PROPERTY_OK; |
|
1829 |
case M_PROPERTY_SET: |
|
1830 |
if (!arg) |
|
1831 |
return M_PROPERTY_ERROR; |
|
1832 |
case M_PROPERTY_STEP_UP: |
|
1833 |
case M_PROPERTY_STEP_DOWN: |
|
1834 |
vo_osd_changed(OSDTYPE_SUBTITLE); |
|
1835 |
default: |
|
1836 |
return m_property_choice(prop, action, arg, &sub_alignment); |
|
1837 |
}
|
|
1838 |
}
|
|
1839 |
||
1840 |
/// Subtitle visibility (RW)
|
|
1841 |
static int mp_property_sub_visibility(m_option_t *prop, int action, |
|
1842 |
void *arg, MPContext *mpctx) |
|
1843 |
{
|
|
1844 |
if (!mpctx->sh_video) |
|
1845 |
return M_PROPERTY_UNAVAILABLE; |
|
1846 |
||
1847 |
switch (action) { |
|
1848 |
case M_PROPERTY_SET: |
|
1849 |
if (!arg) |
|
1850 |
return M_PROPERTY_ERROR; |
|
1851 |
case M_PROPERTY_STEP_UP: |
|
1852 |
case M_PROPERTY_STEP_DOWN: |
|
1853 |
vo_osd_changed(OSDTYPE_SUBTITLE); |
|
1854 |
if (vo_spudec) |
|
1855 |
vo_osd_changed(OSDTYPE_SPU); |
|
1856 |
default: |
|
1857 |
return m_property_flag(prop, action, arg, &sub_visibility); |
|
1858 |
}
|
|
1859 |
}
|
|
1860 |
||
1861 |
#ifdef CONFIG_ASS
|
|
1862 |
/// Use margins for libass subtitles (RW)
|
|
1863 |
static int mp_property_ass_use_margins(m_option_t *prop, int action, |
|
1864 |
void *arg, MPContext *mpctx) |
|
1865 |
{
|
|
1866 |
if (!mpctx->sh_video) |
|
1867 |
return M_PROPERTY_UNAVAILABLE; |
|
1868 |
||
1869 |
switch (action) { |
|
1870 |
case M_PROPERTY_SET: |
|
1871 |
if (!arg) |
|
1872 |
return M_PROPERTY_ERROR; |
|
1873 |
case M_PROPERTY_STEP_UP: |
|
1874 |
case M_PROPERTY_STEP_DOWN: |
|
1875 |
ass_force_reload = 1; |
|
1876 |
default: |
|
1877 |
return m_property_flag(prop, action, arg, &ass_use_margins); |
|
1878 |
}
|
|
1879 |
}
|
|
1880 |
#endif
|
|
1881 |
||
1882 |
/// Show only forced subtitles (RW)
|
|
1883 |
static int mp_property_sub_forced_only(m_option_t *prop, int action, |
|
1884 |
void *arg, MPContext *mpctx) |
|
1885 |
{
|
|
1886 |
if (!vo_spudec) |
|
1887 |
return M_PROPERTY_UNAVAILABLE; |
|
1888 |
||
1889 |
switch (action) { |
|
1890 |
case M_PROPERTY_SET: |
|
1891 |
if (!arg) |
|
1892 |
return M_PROPERTY_ERROR; |
|
1893 |
case M_PROPERTY_STEP_UP: |
|
1894 |
case M_PROPERTY_STEP_DOWN: |
|
1895 |
m_property_flag(prop, action, arg, &forced_subs_only); |
|
1896 |
spudec_set_forced_subs_only(vo_spudec, forced_subs_only); |
|
1897 |
return M_PROPERTY_OK; |
|
1898 |
default: |
|
1899 |
return m_property_flag(prop, action, arg, &forced_subs_only); |
|
1900 |
}
|
|
1901 |
||
1902 |
}
|
|
1903 |
||
1904 |
#ifdef CONFIG_FREETYPE
|
|
1905 |
/// Subtitle scale (RW)
|
|
1906 |
static int mp_property_sub_scale(m_option_t *prop, int action, void *arg, |
|
1907 |
MPContext *mpctx) |
|
1908 |
{
|
|
1909 |
||
1910 |
switch (action) { |
|
1911 |
case M_PROPERTY_SET: |
|
1912 |
if (!arg) |
|
1913 |
return M_PROPERTY_ERROR; |
|
1914 |
M_PROPERTY_CLAMP(prop, *(float *) arg); |
|
1915 |
#ifdef CONFIG_ASS
|
|
1916 |
if (ass_enabled) { |
|
1917 |
ass_font_scale = *(float *) arg; |
|
1918 |
ass_force_reload = 1; |
|
1919 |
}
|
|
1920 |
#endif
|
|
1921 |
text_font_scale_factor = *(float *) arg; |
|
1922 |
force_load_font = 1; |
|
1923 |
vo_osd_changed(OSDTYPE_SUBTITLE); |
|
1924 |
return M_PROPERTY_OK; |
|
1925 |
case M_PROPERTY_STEP_UP: |
|
1926 |
case M_PROPERTY_STEP_DOWN: |
|
1927 |
#ifdef CONFIG_ASS
|
|
1928 |
if (ass_enabled) { |
|
1929 |
ass_font_scale += (arg ? *(float *) arg : 0.1)* |
|
1930 |
(action == M_PROPERTY_STEP_UP ? 1.0 : -1.0); |
|
1931 |
M_PROPERTY_CLAMP(prop, ass_font_scale); |
|
1932 |
ass_force_reload = 1; |
|
1933 |
}
|
|
1934 |
#endif
|
|
1935 |
text_font_scale_factor += (arg ? *(float *) arg : 0.1)* |
|
1936 |
(action == M_PROPERTY_STEP_UP ? 1.0 : -1.0); |
|
1937 |
M_PROPERTY_CLAMP(prop, text_font_scale_factor); |
|
1938 |
force_load_font = 1; |
|
1939 |
vo_osd_changed(OSDTYPE_SUBTITLE); |
|
1940 |
return M_PROPERTY_OK; |
|
1941 |
default: |
|
1942 |
#ifdef CONFIG_ASS
|
|
1943 |
if (ass_enabled) |
|
1944 |
return m_property_float_ro(prop, action, arg, ass_font_scale); |
|
1945 |
else
|
|
1946 |
#endif
|
|
1947 |
return m_property_float_ro(prop, action, arg, text_font_scale_factor); |
|
1948 |
}
|
|
1949 |
}
|
|
1950 |
#endif
|
|
1951 |
||
1952 |
///@}
|
|
1953 |
||
1954 |
/// \defgroup TVProperties TV properties
|
|
1955 |
/// \ingroup Properties
|
|
1956 |
///@{
|
|
1957 |
||
1958 |
#ifdef CONFIG_TV
|
|
1959 |
||
1960 |
/// TV color settings (RW)
|
|
1961 |
static int mp_property_tv_color(m_option_t *prop, int action, void *arg, |
|
1962 |
MPContext *mpctx) |
|
1963 |
{
|
|
1964 |
int r, val; |
|
1965 |
tvi_handle_t *tvh = mpctx->demuxer->priv; |
|
1966 |
if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh) |
|
1967 |
return M_PROPERTY_UNAVAILABLE; |
|
1968 |
||
1969 |
switch (action) { |
|
1970 |
case M_PROPERTY_SET: |
|
1971 |
if (!arg) |
|
1972 |
return M_PROPERTY_ERROR; |
|
1973 |
M_PROPERTY_CLAMP(prop, *(int *) arg); |
|
1974 |
return tv_set_color_options(tvh, (intptr_t) prop->priv, *(int *) arg); |
|
1975 |
case M_PROPERTY_GET: |
|
1976 |
return tv_get_color_options(tvh, (intptr_t) prop->priv, arg); |
|
1977 |
case M_PROPERTY_STEP_UP: |
|
1978 |
case M_PROPERTY_STEP_DOWN: |
|
1979 |
if ((r = tv_get_color_options(tvh, (intptr_t) prop->priv, &val)) >= 0) { |
|
1980 |
if (!r) |
|
1981 |
return M_PROPERTY_ERROR; |
|
1982 |
val += (arg ? *(int *) arg : 1) * |
|
1983 |
(action == M_PROPERTY_STEP_DOWN ? -1 : 1); |
|
1984 |
M_PROPERTY_CLAMP(prop, val); |
|
1985 |
return tv_set_color_options(tvh, (intptr_t) prop->priv, val); |
|
1986 |
}
|
|
1987 |
return M_PROPERTY_ERROR; |
|
1988 |
}
|
|
1989 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
1990 |
}
|
|
1991 |
||
1992 |
#endif
|
|
1993 |
||
1994 |
static int mp_property_teletext_common(m_option_t *prop, int action, void *arg, |
|
1995 |
MPContext *mpctx) |
|
1996 |
{
|
|
1997 |
int val,result; |
|
1998 |
int base_ioctl=(intptr_t)prop->priv; |
|
1999 |
/*
|
|
2000 |
for teletext's GET,SET,STEP ioctls this is not 0
|
|
2001 |
SET is GET+1
|
|
2002 |
STEP is GET+2
|
|
2003 |
*/
|
|
2004 |
if (!mpctx->demuxer || !mpctx->demuxer->teletext) |
|
2005 |
return M_PROPERTY_UNAVAILABLE; |
|
2006 |
if(!base_ioctl) |
|
2007 |
return M_PROPERTY_ERROR; |
|
2008 |
||
2009 |
switch (action) { |
|
2010 |
case M_PROPERTY_GET: |
|
2011 |
if (!arg) |
|
2012 |
return M_PROPERTY_ERROR; |
|
2013 |
result=teletext_control(mpctx->demuxer->teletext, base_ioctl, arg); |
|
2014 |
break; |
|
2015 |
case M_PROPERTY_SET: |
|
2016 |
if (!arg) |
|
2017 |
return M_PROPERTY_ERROR; |
|
2018 |
M_PROPERTY_CLAMP(prop, *(int *) arg); |
|
2019 |
result=teletext_control(mpctx->demuxer->teletext, base_ioctl+1, arg); |
|
2020 |
break; |
|
2021 |
case M_PROPERTY_STEP_UP: |
|
2022 |
case M_PROPERTY_STEP_DOWN: |
|
2023 |
result=teletext_control(mpctx->demuxer->teletext, base_ioctl, &val); |
|
2024 |
val += (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1); |
|
2025 |
result=teletext_control(mpctx->demuxer->teletext, base_ioctl+1, &val); |
|
2026 |
break; |
|
2027 |
default: |
|
2028 |
return M_PROPERTY_NOT_IMPLEMENTED; |
|
2029 |
}
|
|
2030 |
||
2031 |
return result == VBI_CONTROL_TRUE ? M_PROPERTY_OK : M_PROPERTY_ERROR; |
|
2032 |
}
|
|
2033 |
||
2034 |
static int mp_property_teletext_mode(m_option_t *prop, int action, void *arg, |
|
2035 |
MPContext *mpctx) |
|
2036 |
{
|
|
2037 |
int result; |
|
2038 |
int val; |
|
2039 |
||
2040 |
//with tvh==NULL will fail too
|
|
2041 |
result=mp_property_teletext_common(prop,action,arg,mpctx); |
|
2042 |
if(result!=M_PROPERTY_OK) |
|
2043 |
return result; |
|
2044 |
||
2045 |
if(teletext_control(mpctx->demuxer->teletext, |
|
2046 |
(intptr_t)prop->priv, &val)==VBI_CONTROL_TRUE && val) |
|
2047 |
mp_input_set_section("teletext"); |
|
2048 |
else
|
|
2049 |
mp_input_set_section("tv"); |
|
2050 |
return M_PROPERTY_OK; |
|
2051 |
}
|
|
2052 |
||
2053 |
static int mp_property_teletext_page(m_option_t *prop, int action, void *arg, |
|
2054 |
MPContext *mpctx) |
|
2055 |
{
|
|
2056 |
int result; |
|
2057 |
int val; |
|
2058 |
if (!mpctx->demuxer->teletext) |
|
2059 |
return M_PROPERTY_UNAVAILABLE; |
|
2060 |
switch(action){ |
|
2061 |
case M_PROPERTY_STEP_UP: |
|
2062 |
case M_PROPERTY_STEP_DOWN: |
|
2063 |
//This should be handled separately
|
|
2064 |
val = (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1); |
|
2065 |
result=teletext_control(mpctx->demuxer->teletext, |
|
2066 |
TV_VBI_CONTROL_STEP_PAGE, &val); |
|
2067 |
break; |
|
2068 |
default: |
|
2069 |
result=mp_property_teletext_common(prop,action,arg,mpctx); |
|
2070 |
}
|
|
2071 |
return result; |
|
2072 |
}
|
|
2073 |
||
2074 |
///@}
|
|
2075 |
||
2076 |
/// All properties available in MPlayer.
|
|
2077 |
/** \ingroup Properties
|
|
2078 |
*/
|
|
2079 |
static const m_option_t mp_properties[] = { |
|
2080 |
// General
|
|
2081 |
{ "osdlevel", mp_property_osdlevel, CONF_TYPE_INT, |
|
2082 |
M_OPT_RANGE, 0, 3, NULL }, |
|
2083 |
{ "loop", mp_property_loop, CONF_TYPE_INT, |
|
2084 |
M_OPT_MIN, -1, 0, NULL }, |
|
2085 |
{ "speed", mp_property_playback_speed, CONF_TYPE_FLOAT, |
|
2086 |
M_OPT_RANGE, 0.01, 100.0, NULL }, |
|
2087 |
{ "filename", mp_property_filename, CONF_TYPE_STRING, |
|
2088 |
0, 0, 0, NULL }, |
|
2089 |
{ "path", mp_property_path, CONF_TYPE_STRING, |
|
2090 |
0, 0, 0, NULL }, |
|
2091 |
{ "demuxer", mp_property_demuxer, CONF_TYPE_STRING, |
|
2092 |
0, 0, 0, NULL }, |
|
2093 |
{ "stream_pos", mp_property_stream_pos, CONF_TYPE_POSITION, |
|
2094 |
M_OPT_MIN, 0, 0, NULL }, |
|
2095 |
{ "stream_start", mp_property_stream_start, CONF_TYPE_POSITION, |
|
2096 |
M_OPT_MIN, 0, 0, NULL }, |
|
2097 |
{ "stream_end", mp_property_stream_end, CONF_TYPE_POSITION, |
|
2098 |
M_OPT_MIN, 0, 0, NULL }, |
|
2099 |
{ "stream_length", mp_property_stream_length, CONF_TYPE_POSITION, |
|
2100 |
M_OPT_MIN, 0, 0, NULL }, |
|
2101 |
{ "stream_time_pos", mp_property_stream_time_pos, CONF_TYPE_TIME, |
|
2102 |
M_OPT_MIN, 0, 0, NULL }, |
|
2103 |
{ "length", mp_property_length, CONF_TYPE_TIME, |
|
2104 |
M_OPT_MIN, 0, 0, NULL }, |
|
2105 |
{ "percent_pos", mp_property_percent_pos, CONF_TYPE_INT, |
|
2106 |
M_OPT_RANGE, 0, 100, NULL }, |
|
2107 |
{ "time_pos", mp_property_time_pos, CONF_TYPE_TIME, |
|
2108 |
M_OPT_MIN, 0, 0, NULL }, |
|
2109 |
{ "chapter", mp_property_chapter, CONF_TYPE_INT, |
|
2110 |
M_OPT_MIN, 0, 0, NULL }, |
|
2111 |
{ "titles", mp_property_titles, CONF_TYPE_INT, |
|
2112 |
0, 0, 0, NULL }, |
|
2113 |
{ "chapters", mp_property_chapters, CONF_TYPE_INT, |
|
2114 |
0, 0, 0, NULL }, |
|
2115 |
{ "angle", mp_property_angle, CONF_TYPE_INT, |
|
2116 |
CONF_RANGE, -2, 10, NULL }, |
|
2117 |
{ "metadata", mp_property_metadata, CONF_TYPE_STRING_LIST, |
|
2118 |
0, 0, 0, NULL }, |
|
2119 |
{ "pause", mp_property_pause, CONF_TYPE_FLAG, |
|
2120 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2121 |
{ "capturing", mp_property_capture, CONF_TYPE_FLAG, |
|
2122 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2123 |
||
2124 |
// Audio
|
|
2125 |
{ "volume", mp_property_volume, CONF_TYPE_FLOAT, |
|
2126 |
M_OPT_RANGE, 0, 100, NULL }, |
|
2127 |
{ "mute", mp_property_mute, CONF_TYPE_FLAG, |
|
2128 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2129 |
{ "audio_delay", mp_property_audio_delay, CONF_TYPE_FLOAT, |
|
2130 |
M_OPT_RANGE, -100, 100, NULL }, |
|
2131 |
{ "audio_format", mp_property_audio_format, CONF_TYPE_INT, |
|
2132 |
0, 0, 0, NULL }, |
|
2133 |
{ "audio_codec", mp_property_audio_codec, CONF_TYPE_STRING, |
|
2134 |
0, 0, 0, NULL }, |
|
2135 |
{ "audio_bitrate", mp_property_audio_bitrate, CONF_TYPE_INT, |
|
2136 |
0, 0, 0, NULL }, |
|
2137 |
{ "samplerate", mp_property_samplerate, CONF_TYPE_INT, |
|
2138 |
0, 0, 0, NULL }, |
|
2139 |
{ "channels", mp_property_channels, CONF_TYPE_INT, |
|
2140 |
0, 0, 0, NULL }, |
|
2141 |
{ "switch_audio", mp_property_audio, CONF_TYPE_INT, |
|
2142 |
CONF_RANGE, -2, 65535, NULL }, |
|
2143 |
{ "balance", mp_property_balance, CONF_TYPE_FLOAT, |
|
2144 |
M_OPT_RANGE, -1, 1, NULL }, |
|
2145 |
||
2146 |
// Video
|
|
2147 |
{ "fullscreen", mp_property_fullscreen, CONF_TYPE_FLAG, |
|
2148 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2149 |
{ "deinterlace", mp_property_deinterlace, CONF_TYPE_FLAG, |
|
2150 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2151 |
{ "ontop", mp_property_ontop, CONF_TYPE_FLAG, |
|
2152 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2153 |
{ "rootwin", mp_property_rootwin, CONF_TYPE_FLAG, |
|
2154 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2155 |
{ "border", mp_property_border, CONF_TYPE_FLAG, |
|
2156 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2157 |
{ "framedropping", mp_property_framedropping, CONF_TYPE_INT, |
|
2158 |
M_OPT_RANGE, 0, 2, NULL }, |
|
2159 |
{ "gamma", mp_property_gamma, CONF_TYPE_INT, |
|
2160 |
M_OPT_RANGE, -100, 100, &vo_gamma_gamma }, |
|
2161 |
{ "brightness", mp_property_gamma, CONF_TYPE_INT, |
|
2162 |
M_OPT_RANGE, -100, 100, &vo_gamma_brightness }, |
|
2163 |
{ "contrast", mp_property_gamma, CONF_TYPE_INT, |
|
2164 |
M_OPT_RANGE, -100, 100, &vo_gamma_contrast }, |
|
2165 |
{ "saturation", mp_property_gamma, CONF_TYPE_INT, |
|
2166 |
M_OPT_RANGE, -100, 100, &vo_gamma_saturation }, |
|
2167 |
{ "hue", mp_property_gamma, CONF_TYPE_INT, |
|
2168 |
M_OPT_RANGE, -100, 100, &vo_gamma_hue }, |
|
2169 |
{ "panscan", mp_property_panscan, CONF_TYPE_FLOAT, |
|
2170 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2171 |
{ "vsync", mp_property_vsync, CONF_TYPE_FLAG, |
|
2172 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2173 |
{ "video_format", mp_property_video_format, CONF_TYPE_INT, |
|
2174 |
0, 0, 0, NULL }, |
|
2175 |
{ "video_codec", mp_property_video_codec, CONF_TYPE_STRING, |
|
2176 |
0, 0, 0, NULL }, |
|
2177 |
{ "video_bitrate", mp_property_video_bitrate, CONF_TYPE_INT, |
|
2178 |
0, 0, 0, NULL }, |
|
2179 |
{ "width", mp_property_width, CONF_TYPE_INT, |
|
2180 |
0, 0, 0, NULL }, |
|
2181 |
{ "height", mp_property_height, CONF_TYPE_INT, |
|
2182 |
0, 0, 0, NULL }, |
|
2183 |
{ "fps", mp_property_fps, CONF_TYPE_FLOAT, |
|
2184 |
0, 0, 0, NULL }, |
|
2185 |
{ "aspect", mp_property_aspect, CONF_TYPE_FLOAT, |
|
2186 |
0, 0, 0, NULL }, |
|
2187 |
{ "switch_video", mp_property_video, CONF_TYPE_INT, |
|
2188 |
CONF_RANGE, -2, 65535, NULL }, |
|
2189 |
{ "switch_program", mp_property_program, CONF_TYPE_INT, |
|
2190 |
CONF_RANGE, -1, 65535, NULL }, |
|
2191 |
||
2192 |
// Subs
|
|
2193 |
{ "sub", mp_property_sub, CONF_TYPE_INT, |
|
2194 |
M_OPT_MIN, -1, 0, NULL }, |
|
2195 |
{ "sub_source", mp_property_sub_source, CONF_TYPE_INT, |
|
2196 |
M_OPT_RANGE, -1, SUB_SOURCES - 1, NULL }, |
|
2197 |
{ "sub_vob", mp_property_sub_by_type, CONF_TYPE_INT, |
|
2198 |
M_OPT_MIN, -1, 0, NULL }, |
|
2199 |
{ "sub_demux", mp_property_sub_by_type, CONF_TYPE_INT, |
|
2200 |
M_OPT_MIN, -1, 0, NULL }, |
|
2201 |
{ "sub_file", mp_property_sub_by_type, CONF_TYPE_INT, |
|
2202 |
M_OPT_MIN, -1, 0, NULL }, |
|
2203 |
{ "sub_delay", mp_property_sub_delay, CONF_TYPE_FLOAT, |
|
2204 |
0, 0, 0, NULL }, |
|
2205 |
{ "sub_pos", mp_property_sub_pos, CONF_TYPE_INT, |
|
2206 |
M_OPT_RANGE, 0, 100, NULL }, |
|
2207 |
{ "sub_alignment", mp_property_sub_alignment, CONF_TYPE_INT, |
|
2208 |
M_OPT_RANGE, 0, 2, NULL }, |
|
2209 |
{ "sub_visibility", mp_property_sub_visibility, CONF_TYPE_FLAG, |
|
2210 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2211 |
{ "sub_forced_only", mp_property_sub_forced_only, CONF_TYPE_FLAG, |
|
2212 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2213 |
#ifdef CONFIG_FREETYPE
|
|
2214 |
{ "sub_scale", mp_property_sub_scale, CONF_TYPE_FLOAT, |
|
2215 |
M_OPT_RANGE, 0, 100, NULL }, |
|
2216 |
#endif
|
|
2217 |
#ifdef CONFIG_ASS
|
|
2218 |
{ "ass_use_margins", mp_property_ass_use_margins, CONF_TYPE_FLAG, |
|
2219 |
M_OPT_RANGE, 0, 1, NULL }, |
|
2220 |
#endif
|
|
2221 |
||
2222 |
#ifdef CONFIG_TV
|
|
2223 |
{ "tv_brightness", mp_property_tv_color, CONF_TYPE_INT, |
|
2224 |
M_OPT_RANGE, -100, 100, (void *) TV_COLOR_BRIGHTNESS }, |
|
2225 |
{ "tv_contrast", mp_property_tv_color, CONF_TYPE_INT, |
|
2226 |
M_OPT_RANGE, -100, 100, (void *) TV_COLOR_CONTRAST }, |
|
2227 |
{ "tv_saturation", mp_property_tv_color, CONF_TYPE_INT, |
|
2228 |
M_OPT_RANGE, -100, 100, (void *) TV_COLOR_SATURATION }, |
|
2229 |
{ "tv_hue", mp_property_tv_color, CONF_TYPE_INT, |
|
2230 |
M_OPT_RANGE, -100, 100, (void *) TV_COLOR_HUE }, |
|
2231 |
#endif
|
|
2232 |
{ "teletext_page", mp_property_teletext_page, CONF_TYPE_INT, |
|
2233 |
M_OPT_RANGE, 100, 899, (void*)TV_VBI_CONTROL_GET_PAGE }, |
|
2234 |
{ "teletext_subpage", mp_property_teletext_common, CONF_TYPE_INT, |
|
2235 |
M_OPT_RANGE, 0, 64, (void*)TV_VBI_CONTROL_GET_SUBPAGE }, |
|
2236 |
{ "teletext_mode", mp_property_teletext_mode, CONF_TYPE_FLAG, |
|
2237 |
M_OPT_RANGE, 0, 1, (void*)TV_VBI_CONTROL_GET_MODE }, |
|
2238 |
{ "teletext_format", mp_property_teletext_common, CONF_TYPE_INT, |
|
2239 |
M_OPT_RANGE, 0, 3, (void*)TV_VBI_CONTROL_GET_FORMAT }, |
|
2240 |
{ "teletext_half_page", mp_property_teletext_common, CONF_TYPE_INT, |
|
2241 |
M_OPT_RANGE, 0, 2, (void*)TV_VBI_CONTROL_GET_HALF_PAGE }, |
|
2242 |
{ NULL, NULL, NULL, 0, 0, 0, NULL } |
|
2243 |
};
|
|
2244 |
||
2245 |
||
2246 |
int mp_property_do(const char *name, int action, void *val, void *ctx) |
|
2247 |
{
|
|
2248 |
return m_property_do(mp_properties, name, action, val, ctx); |
|
2249 |
}
|
|
2250 |
||
2251 |
char* mp_property_print(const char *name, void* ctx) |
|
2252 |
{
|
|
2253 |
char* ret = NULL; |
|
2254 |
if(mp_property_do(name,M_PROPERTY_PRINT,&ret,ctx) <= 0) |
|
2255 |
return NULL; |
|
2256 |
return ret; |
|
2257 |
}
|
|
2258 |
||
2259 |
char *property_expand_string(MPContext *mpctx, char *str) |
|
2260 |
{
|
|
2261 |
return m_properties_expand_string(mp_properties, str, mpctx); |
|
2262 |
}
|
|
2263 |
||
2264 |
void property_print_help(void) |
|
2265 |
{
|
|
2266 |
m_properties_print_help_list(mp_properties); |
|
2267 |
}
|
|
2268 |
||
2269 |
||
2270 |
///@}
|
|
2271 |
// Properties group
|
|
2272 |
||
2273 |
||
2274 |
/**
|
|
2275 |
* \defgroup Command2Property Command to property bridge
|
|
2276 |
*
|
|
2277 |
* It is used to handle most commands that just set a property
|
|
2278 |
* and optionally display something on the OSD.
|
|
2279 |
* Two kinds of commands are handled: adjust or toggle.
|
|
2280 |
*
|
|
2281 |
* Adjust commands take 1 or 2 parameters: <value> <abs>
|
|
2282 |
* If <abs> is non-zero the property is set to the given value
|
|
2283 |
* otherwise it is adjusted.
|
|
2284 |
*
|
|
2285 |
* Toggle commands take 0 or 1 parameters. With no parameter
|
|
2286 |
* or a value less than the property minimum it just steps the
|
|
2287 |
* property to its next or previous value respectively.
|
|
2288 |
* Otherwise it sets it to the given value.
|
|
2289 |
*
|
|
2290 |
*@{
|
|
2291 |
*/
|
|
2292 |
||
2293 |
/// List of the commands that can be handled by setting a property.
|
|
2294 |
static struct { |
|
2295 |
/// property name
|
|
2296 |
const char *name; |
|
2297 |
/// cmd id
|
|
2298 |
int cmd; |
|
2299 |
/// set/adjust or toggle command
|
|
2300 |
int toggle; |
|
2301 |
/// progressbar type
|
|
2302 |
int osd_progbar; |
|
2303 |
/// osd msg id if it must be shared
|
|
2304 |
int osd_id; |
|
2305 |
/// osd msg template
|
|
2306 |
const char *osd_msg; |
|
2307 |
} set_prop_cmd[] = { |
|
2308 |
// general
|
|
2309 |
{ "loop", MP_CMD_LOOP, 0, 0, -1, MSGTR_LoopStatus }, |
|
2310 |
{ "chapter", MP_CMD_SEEK_CHAPTER, 0, 0, -1, NULL }, |
|
2311 |
{ "angle", MP_CMD_SWITCH_ANGLE, 0, 0, -1, NULL }, |
|
2312 |
{ "capturing", MP_CMD_CAPTURING, 1, 0, -1, NULL }, |
|
2313 |
// audio
|
|
2314 |
{ "volume", MP_CMD_VOLUME, 0, OSD_VOLUME, -1, MSGTR_Volume }, |
|
2315 |
{ "mute", MP_CMD_MUTE, 1, 0, -1, MSGTR_MuteStatus }, |
|
2316 |
{ "audio_delay", MP_CMD_AUDIO_DELAY, 0, 0, -1, MSGTR_AVDelayStatus }, |
|
2317 |
{ "switch_audio", MP_CMD_SWITCH_AUDIO, 1, 0, -1, MSGTR_OSDAudio }, |
|
2318 |
{ "balance", MP_CMD_BALANCE, 0, OSD_BALANCE, -1, MSGTR_Balance }, |
|
2319 |
// video
|
|
2320 |
{ "fullscreen", MP_CMD_VO_FULLSCREEN, 1, 0, -1, NULL }, |
|
2321 |
{ "panscan", MP_CMD_PANSCAN, 0, OSD_PANSCAN, -1, MSGTR_Panscan }, |
|
2322 |
{ "ontop", MP_CMD_VO_ONTOP, 1, 0, -1, MSGTR_OnTopStatus }, |
|
2323 |
{ "rootwin", MP_CMD_VO_ROOTWIN, 1, 0, -1, MSGTR_RootwinStatus }, |
|
2324 |
{ "border", MP_CMD_VO_BORDER, 1, 0, -1, MSGTR_BorderStatus }, |
|
2325 |
{ "framedropping", MP_CMD_FRAMEDROPPING, 1, 0, -1, MSGTR_FramedroppingStatus }, |
|
2326 |
{ "gamma", MP_CMD_GAMMA, 0, OSD_BRIGHTNESS, -1, MSGTR_Gamma }, |
|
2327 |
{ "brightness", MP_CMD_BRIGHTNESS, 0, OSD_BRIGHTNESS, -1, MSGTR_Brightness }, |
|
2328 |
{ "contrast", MP_CMD_CONTRAST, 0, OSD_CONTRAST, -1, MSGTR_Contrast }, |
|
2329 |
{ "saturation", MP_CMD_SATURATION, 0, OSD_SATURATION, -1, MSGTR_Saturation }, |
|
2330 |
{ "hue", MP_CMD_HUE, 0, OSD_HUE, -1, MSGTR_Hue }, |
|
2331 |
{ "vsync", MP_CMD_SWITCH_VSYNC, 1, 0, -1, MSGTR_VSyncStatus }, |
|
2332 |
// subs
|
|
2333 |
{ "sub", MP_CMD_SUB_SELECT, 1, 0, -1, MSGTR_SubSelectStatus }, |
|
2334 |
{ "sub_source", MP_CMD_SUB_SOURCE, 1, 0, -1, MSGTR_SubSourceStatus }, |
|
2335 |
{ "sub_vob", MP_CMD_SUB_VOB, 1, 0, -1, MSGTR_SubSelectStatus }, |
|
2336 |
{ "sub_demux", MP_CMD_SUB_DEMUX, 1, 0, -1, MSGTR_SubSelectStatus }, |
|
2337 |
{ "sub_file", MP_CMD_SUB_FILE, 1, 0, -1, MSGTR_SubSelectStatus }, |
|
2338 |
{ "sub_pos", MP_CMD_SUB_POS, 0, 0, -1, MSGTR_SubPosStatus }, |
|
2339 |
{ "sub_alignment", MP_CMD_SUB_ALIGNMENT, 1, 0, -1, MSGTR_SubAlignStatus }, |
|
2340 |
{ "sub_delay", MP_CMD_SUB_DELAY, 0, 0, OSD_MSG_SUB_DELAY, MSGTR_SubDelayStatus }, |
|
2341 |
{ "sub_visibility", MP_CMD_SUB_VISIBILITY, 1, 0, -1, MSGTR_SubVisibleStatus }, |
|
2342 |
{ "sub_forced_only", MP_CMD_SUB_FORCED_ONLY, 1, 0, -1, MSGTR_SubForcedOnlyStatus }, |
|
2343 |
#ifdef CONFIG_FREETYPE
|
|
2344 |
{ "sub_scale", MP_CMD_SUB_SCALE, 0, 0, -1, MSGTR_SubScale}, |
|
2345 |
#endif
|
|
2346 |
#ifdef CONFIG_ASS
|
|
2347 |
{ "ass_use_margins", MP_CMD_ASS_USE_MARGINS, 1, 0, -1, NULL }, |
|
2348 |
#endif
|
|
2349 |
#ifdef CONFIG_TV
|
|
2350 |
{ "tv_brightness", MP_CMD_TV_SET_BRIGHTNESS, 0, OSD_BRIGHTNESS, -1, MSGTR_Brightness }, |
|
2351 |
{ "tv_hue", MP_CMD_TV_SET_HUE, 0, OSD_HUE, -1, MSGTR_Hue }, |
|
2352 |
{ "tv_saturation", MP_CMD_TV_SET_SATURATION, 0, OSD_SATURATION, -1, MSGTR_Saturation }, |
|
2353 |
{ "tv_contrast", MP_CMD_TV_SET_CONTRAST, 0, OSD_CONTRAST, -1, MSGTR_Contrast }, |
|
2354 |
#endif
|
|
2355 |
{ NULL, 0, 0, 0, -1, NULL } |
|
2356 |
};
|
|
2357 |
||
2358 |
||
2359 |
/// Handle commands that set a property.
|
|
2360 |
static int set_property_command(MPContext *mpctx, mp_cmd_t *cmd) |
|
2361 |
{
|
|
2362 |
int i, r; |
|
2363 |
m_option_t *prop; |
|
2364 |
const char *pname; |
|
2365 |
||
2366 |
// look for the command
|
|
2367 |
for (i = 0; set_prop_cmd[i].name; i++) |
|
2368 |
if (set_prop_cmd[i].cmd == cmd->id) |
|
2369 |
break; |
|
2370 |
if (!(pname = set_prop_cmd[i].name)) |
|
2371 |
return 0; |
|
2372 |
||
2373 |
if (mp_property_do(pname,M_PROPERTY_GET_TYPE,&prop,mpctx) <= 0 || !prop) |
|
2374 |
return 0; |
|
2375 |
||
2376 |
// toggle command
|
|
2377 |
if (set_prop_cmd[i].toggle) { |
|
2378 |
// set to value
|
|
2379 |
if (cmd->nargs > 0 && cmd->args[0].v.i >= prop->min) |
|
2380 |
r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v.i, mpctx); |
|
2381 |
else if (cmd->nargs > 0) |
|
2382 |
r = mp_property_do(pname, M_PROPERTY_STEP_DOWN, NULL, mpctx); |
|
2383 |
else
|
|
2384 |
r = mp_property_do(pname, M_PROPERTY_STEP_UP, NULL, mpctx); |
|
2385 |
} else if (cmd->args[1].v.i) //set |
|
2386 |
r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v, mpctx); |
|
2387 |
else // adjust |
|
2388 |
r = mp_property_do(pname, M_PROPERTY_STEP_UP, &cmd->args[0].v, mpctx); |
|
2389 |
||
2390 |
if (r <= 0) |
|
2391 |
return 1; |
|
2392 |
||
2393 |
if (set_prop_cmd[i].osd_progbar) { |
|
2394 |
if (prop->type == CONF_TYPE_INT) { |
|
2395 |
if (mp_property_do(pname, M_PROPERTY_GET, &r, mpctx) > 0) |
|
2396 |
set_osd_bar(set_prop_cmd[i].osd_progbar, |
|
2397 |
set_prop_cmd[i].osd_msg, prop->min, prop->max, r); |
|
2398 |
} else if (prop->type == CONF_TYPE_FLOAT) { |
|
2399 |
float f; |
|
2400 |
if (mp_property_do(pname, M_PROPERTY_GET, &f, mpctx) > 0) |
|
2401 |
set_osd_bar(set_prop_cmd[i].osd_progbar, |
|
2402 |
set_prop_cmd[i].osd_msg, prop->min, prop->max, f); |
|
2403 |
} else |
|
2404 |
mp_msg(MSGT_CPLAYER, MSGL_ERR, |
|
2405 |
"Property use an unsupported type.\n"); |
|
2406 |
return 1; |
|
2407 |
}
|
|
2408 |
||
2409 |
if (set_prop_cmd[i].osd_msg) { |
|
2410 |
char *val = mp_property_print(pname, mpctx); |
|
2411 |
if (val) { |
|
2412 |
set_osd_msg(set_prop_cmd[i].osd_id >= |
|
2413 |
0 ? set_prop_cmd[i].osd_id : OSD_MSG_PROPERTY + i, |
|
2414 |
1, osd_duration, set_prop_cmd[i].osd_msg, val); |
|
2415 |
free(val); |
|
2416 |
}
|
|
2417 |
}
|
|
2418 |
return 1; |
|
2419 |
}
|
|
2420 |
||
2421 |
#ifdef CONFIG_DVDNAV
|
|
2422 |
static const struct { |
|
2423 |
const char *name; |
|
2424 |
const mp_command_type cmd; |
|
2425 |
} mp_dvdnav_bindings[] = { |
|
2426 |
{ "up", MP_CMD_DVDNAV_UP }, |
|
2427 |
{ "down", MP_CMD_DVDNAV_DOWN }, |
|
2428 |
{ "left", MP_CMD_DVDNAV_LEFT }, |
|
2429 |
{ "right", MP_CMD_DVDNAV_RIGHT }, |
|
2430 |
{ "menu", MP_CMD_DVDNAV_MENU }, |
|
2431 |
{ "select", MP_CMD_DVDNAV_SELECT }, |
|
2432 |
{ "prev", MP_CMD_DVDNAV_PREVMENU }, |
|
2433 |
{ "mouse", MP_CMD_DVDNAV_MOUSECLICK }, |
|
2434 |
||
2435 |
/*
|
|
2436 |
* keep old dvdnav sub-command options for a while in order not to
|
|
2437 |
* break slave-mode API too suddenly.
|
|
2438 |
*/
|
|
2439 |
{ "1", MP_CMD_DVDNAV_UP }, |
|
2440 |
{ "2", MP_CMD_DVDNAV_DOWN }, |
|
2441 |
{ "3", MP_CMD_DVDNAV_LEFT }, |
|
2442 |
{ "4", MP_CMD_DVDNAV_RIGHT }, |
|
2443 |
{ "5", MP_CMD_DVDNAV_MENU }, |
|
2444 |
{ "6", MP_CMD_DVDNAV_SELECT }, |
|
2445 |
{ "7", MP_CMD_DVDNAV_PREVMENU }, |
|
2446 |
{ "8", MP_CMD_DVDNAV_MOUSECLICK }, |
|
2447 |
{ NULL, 0 } |
|
2448 |
};
|
|
2449 |
#endif
|
|
2450 |
||
2451 |
static const char *property_error_string(int error_value) |
|
2452 |
{
|
|
2453 |
switch (error_value) { |
|
2454 |
case M_PROPERTY_ERROR: |
|
2455 |
return "ERROR"; |
|
2456 |
case M_PROPERTY_UNAVAILABLE: |
|
2457 |
return "PROPERTY_UNAVAILABLE"; |
|
2458 |
case M_PROPERTY_NOT_IMPLEMENTED: |
|
2459 |
return "NOT_IMPLEMENTED"; |
|
2460 |
case M_PROPERTY_UNKNOWN: |
|
2461 |
return "PROPERTY_UNKNOWN"; |
|
2462 |
case M_PROPERTY_DISABLED: |
|
2463 |
return "DISABLED"; |
|
2464 |
}
|
|
2465 |
return "UNKNOWN"; |
|
2466 |
}
|
|
2467 |
///@}
|
|
2468 |
||
2469 |
static void remove_subtitle_range(MPContext *mpctx, int start, int count) |
|
2470 |
{
|
|
2471 |
int idx; |
|
2472 |
int end = start + count; |
|
2473 |
int after = mpctx->set_of_sub_size - end; |
|
2474 |
sub_data **subs = mpctx->set_of_subtitles; |
|
2475 |
#ifdef CONFIG_ASS
|
|
2476 |
ASS_Track **ass_tracks = mpctx->set_of_ass_tracks; |
|
2477 |
#endif
|
|
2478 |
if (count < 0 || count > mpctx->set_of_sub_size || |
|
2479 |
start < 0 || start > mpctx->set_of_sub_size - count) { |
|
2480 |
mp_msg(MSGT_CPLAYER, MSGL_ERR, |
|
2481 |
"Cannot remove invalid subtitle range %i +%i\n", start, count); |
|
2482 |
return; |
|
2483 |
}
|
|
2484 |
for (idx = start; idx < end; idx++) { |
|
2485 |
sub_data *subd = subs[idx]; |
|
2486 |
mp_msg(MSGT_CPLAYER, MSGL_STATUS, |
|
2487 |
MSGTR_RemovedSubtitleFile, idx + 1, |
|
2488 |
filename_recode(subd->filename)); |
|
2489 |
sub_free(subd); |
|
2490 |
subs[idx] = NULL; |
|
2491 |
#ifdef CONFIG_ASS
|
|
2492 |
if (ass_tracks[idx]) |
|
2493 |
ass_free_track(ass_tracks[idx]); |
|
2494 |
ass_tracks[idx] = NULL; |
|
2495 |
#endif
|
|
2496 |
}
|
|
2497 |
||
2498 |
mpctx->global_sub_size -= count; |
|
2499 |
mpctx->set_of_sub_size -= count; |
|
2500 |
if (mpctx->set_of_sub_size <= 0) |
|
2501 |
mpctx->sub_counts[SUB_SOURCE_SUBS] = 0; |
|
2502 |
||
2503 |
memmove(subs + start, subs + end, after * sizeof(*subs)); |
|
2504 |
memset(subs + start + after, 0, count * sizeof(*subs)); |
|
2505 |
#ifdef CONFIG_ASS
|
|
2506 |
memmove(ass_tracks + start, ass_tracks + end, after * sizeof(*ass_tracks)); |
|
2507 |
memset(ass_tracks + start + after, 0, count * sizeof(*ass_tracks)); |
|
2508 |
#endif
|
|
2509 |
||
2510 |
if (mpctx->set_of_sub_pos >= start && mpctx->set_of_sub_pos < end) { |
|
2511 |
mpctx->global_sub_pos = -2; |
|
2512 |
subdata = NULL; |
|
2513 |
#ifdef CONFIG_ASS
|
|
2514 |
ass_track = NULL; |
|
2515 |
#endif
|
|
2516 |
mp_input_queue_cmd(mp_input_parse_cmd("sub_select")); |
|
2517 |
} else if (mpctx->set_of_sub_pos >= end) { |
|
2518 |
mpctx->set_of_sub_pos -= count; |
|
2519 |
mpctx->global_sub_pos -= count; |
|
2520 |
}
|
|
2521 |
}
|
|
2522 |
||
2523 |
static int overlay_source_registered = 0; |
|
2524 |
static struct mp_eosd_source overlay_source = { |
|
2525 |
.z_index = 5, |
|
2526 |
};
|
|
2527 |
||
2528 |
static void overlay_add(char *file, int id, int x, int y, unsigned col) |
|
2529 |
{
|
|
2530 |
FILE *f; |
|
2531 |
int w, h, bpp, maxval; |
|
2532 |
uint8_t *data; |
|
2533 |
struct mp_eosd_image *img; |
|
2534 |
||
2535 |
f = fopen(file, "rb"); |
|
2536 |
if (!f) { |
|
2537 |
mp_msg(MSGT_CPLAYER, MSGL_ERR, "overlay_add: unable to open file.\n"); |
|
2538 |
return; |
|
2539 |
}
|
|
2540 |
data = read_pnm(f, &w, &h, &bpp, &maxval); |
|
2541 |
fclose(f); |
|
2542 |
if (!data) { |
|
2543 |
mp_msg(MSGT_CPLAYER, MSGL_ERR, "overlay_add: unable to load file.\n"); |
|
2544 |
return; |
|
2545 |
}
|
|
2546 |
if (bpp != 1 || maxval != 255) { |
|
2547 |
mp_msg(MSGT_CPLAYER, MSGL_ERR, |
|
2548 |
"overlay_add: file format not supported.\n"); |
|
2549 |
return; |
|
2550 |
}
|
|
2551 |
if (!overlay_source_registered) { |
|
2552 |
eosd_register(&overlay_source); |
|
2553 |
eosd_image_remove_all(&overlay_source); |
|
2554 |
overlay_source_registered = 1; |
|
2555 |
}
|
|
2556 |
img = eosd_image_alloc(); |
|
2557 |
img->w = w; |
|
2558 |
img->h = h; |
|
2559 |
img->stride = w; |
|
2560 |
img->bitmap = data; |
|
2561 |
img->color = col ^ 0xFF; /* col is RGBA, img->color is RGBT */ |
|
2562 |
img->dst_x = x; |
|
2563 |
img->dst_y = y; |
|
2564 |
img->opaque = (void *)(intptr_t)id; |
|
2565 |
eosd_image_append(&overlay_source, img); |
|
2566 |
overlay_source.changed = EOSD_CHANGED_BITMAP; |
|
2567 |
}
|
|
2568 |
||
2569 |
static void overlay_remove(int id) |
|
2570 |
{
|
|
2571 |
struct mp_eosd_image *img, **prev, *next; |
|
2572 |
prev = &overlay_source.images; |
|
2573 |
img = overlay_source.images; |
|
2574 |
while (img) { |
|
2575 |
next = img->next; |
|
2576 |
if ((intptr_t)img->opaque == id) { |
|
2577 |
free(img->bitmap); |
|
2578 |
eosd_image_remove(&overlay_source, img, prev); |
|
2579 |
overlay_source.changed = EOSD_CHANGED_BITMAP; |
|
2580 |
} else { |
|
2581 |
prev = &img->next; |
|
2582 |
}
|
|
2583 |
img = next; |
|
2584 |
}
|
|
2585 |
}
|
|
2586 |
||
2587 |
int run_command(MPContext *mpctx, mp_cmd_t *cmd) |
|
2588 |
{
|
|
2589 |
sh_audio_t * const sh_audio = mpctx->sh_audio; |
|
2590 |
sh_video_t * const sh_video = mpctx->sh_video; |
|
2591 |
int brk_cmd = 0; |
|
2592 |
if (!set_property_command(mpctx, cmd)) |
|
2593 |
switch (cmd->id) { |
|
2594 |
case MP_CMD_SEEK:{ |
|
2595 |
float v; |
|
2596 |
int abs; |
|
2597 |
if (sh_video) |
|
2598 |
mpctx->osd_show_percentage = sh_video->fps; |
|
2599 |
v = cmd->args[0].v.f; |
|
2600 |
abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0; |
|
2601 |
if (abs == 2) { /* Absolute seek to a specific timestamp in seconds */ |
|
2602 |
abs_seek_pos = SEEK_ABSOLUTE; |
|
2603 |
if (sh_video) |
|
2604 |
mpctx->osd_function = |
|
2605 |
(v > sh_video->pts) ? OSD_FFW : OSD_REW; |
|
2606 |
rel_seek_secs = v; |
|
2607 |
} else if (abs) { /* Absolute seek by percentage */ |
|
2608 |
abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR; |
|
2609 |
if (sh_video) |
|
2610 |
mpctx->osd_function = OSD_FFW; // Direction isn't set correctly |
|
2611 |
rel_seek_secs = v / 100.0; |
|
2612 |
} else { |
|
2613 |
rel_seek_secs += v; |
|
2614 |
mpctx->osd_function = (v > 0) ? OSD_FFW : OSD_REW; |
|
2615 |
}
|
|
2616 |
brk_cmd = 1; |
|
2617 |
}
|
|
2618 |
break; |
|
2619 |
||
2620 |
case MP_CMD_SET_PROPERTY:{ |
|
2621 |
int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_PARSE, |
|
2622 |
cmd->args[1].v.s, mpctx); |
|
2623 |
if (r == M_PROPERTY_UNKNOWN) |
|
2624 |
mp_msg(MSGT_CPLAYER, MSGL_WARN, |
|
2625 |
"Unknown property: '%s'\n", cmd->args[0].v.s); |
|
2626 |
else if (r <= 0) |
|
2627 |
mp_msg(MSGT_CPLAYER, MSGL_WARN, |
|
2628 |
"Failed to set property '%s' to '%s'.\n", |
|
2629 |
cmd->args[0].v.s, cmd->args[1].v.s); |
|
2630 |
if (r <= 0) |
|
2631 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_ERROR=%s\n", property_error_string(r)); |
|
2632 |
}
|
|
2633 |
break; |
|
2634 |
||
2635 |
case MP_CMD_STEP_PROPERTY:{ |
|
2636 |
void* arg = NULL; |
|
2637 |
int r,i; |
|
2638 |
double d; |
|
2639 |
off_t o; |
|
2640 |
if (cmd->args[1].v.f) { |
|
2641 |
m_option_t *prop; |
|
2642 |
if((r = mp_property_do(cmd->args[0].v.s, |
|
2643 |
M_PROPERTY_GET_TYPE, |
|
2644 |
&prop, mpctx)) <= 0) |
|
2645 |
goto step_prop_err; |
|
2646 |
if(prop->type == CONF_TYPE_INT || |
|
2647 |
prop->type == CONF_TYPE_FLAG) |
|
2648 |
i = cmd->args[1].v.f, arg = &i; |
|
2649 |
else if(prop->type == CONF_TYPE_FLOAT) |
|
2650 |
arg = &cmd->args[1].v.f; |
|
2651 |
else if(prop->type == CONF_TYPE_DOUBLE || |
|
2652 |
prop->type == CONF_TYPE_TIME) |
|
2653 |
d = cmd->args[1].v.f, arg = &d; |
|
2654 |
else if(prop->type == CONF_TYPE_POSITION) |
|
2655 |
o = cmd->args[1].v.f, arg = &o; |
|
2656 |
else
|
|
2657 |
mp_msg(MSGT_CPLAYER, MSGL_WARN, |
|
2658 |
"Ignoring step size stepping property '%s'.\n", |
|
2659 |
cmd->args[0].v.s); |
|
2660 |
}
|
|
2661 |
r = mp_property_do(cmd->args[0].v.s, |
|
2662 |
cmd->args[2].v.i < 0 ? |
|
2663 |
M_PROPERTY_STEP_DOWN : M_PROPERTY_STEP_UP, |
|
2664 |
arg, mpctx); |
|
2665 |
step_prop_err: |
|
2666 |
if (r == M_PROPERTY_UNKNOWN) |
|
2667 |
mp_msg(MSGT_CPLAYER, MSGL_WARN, |
|
2668 |
"Unknown property: '%s'\n", cmd->args[0].v.s); |
|
2669 |
else if (r <= 0) |
|
2670 |
mp_msg(MSGT_CPLAYER, MSGL_WARN, |
|
2671 |
"Failed to increment property '%s' by %f.\n", |
|
2672 |
cmd->args[0].v.s, cmd->args[1].v.f); |
|
2673 |
if (r <= 0) |
|
2674 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_ERROR=%s\n", property_error_string(r)); |
|
2675 |
}
|
|
2676 |
break; |
|
2677 |
||
2678 |
case MP_CMD_GET_PROPERTY:{ |
|
2679 |
char *tmp; |
|
2680 |
int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_TO_STRING, |
|
2681 |
&tmp, mpctx); |
|
2682 |
if (r <= 0) { |
|
2683 |
mp_msg(MSGT_CPLAYER, MSGL_WARN, |
|
2684 |
"Failed to get value of property '%s'.\n", |
|
2685 |
cmd->args[0].v.s); |
|
2686 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_ERROR=%s\n", property_error_string(r)); |
|
2687 |
break; |
|
2688 |
}
|
|
2689 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_%s=%s\n", |
|
2690 |
cmd->args[0].v.s, tmp); |
|
2691 |
free(tmp); |
|
2692 |
}
|
|
2693 |
break; |
|
2694 |
||
2695 |
case MP_CMD_EDL_MARK: |
|
2696 |
if (edl_fd) { |
|
2697 |
float v = sh_video ? sh_video->pts : |
|
2698 |
playing_audio_pts(sh_audio, mpctx->d_audio, |
|
2699 |
mpctx->audio_out); |
|
2700 |
||
2701 |
if (mpctx->begin_skip == MP_NOPTS_VALUE) { |
|
2702 |
mpctx->begin_skip = v; |
|
2703 |
mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_EdloutStartSkip); |
|
2704 |
} else { |
|
2705 |
if (mpctx->begin_skip > v) |
|
2706 |
mp_msg(MSGT_CPLAYER, MSGL_WARN, MSGTR_EdloutBadStop); |
|
2707 |
else { |
|
2708 |
double pts = edl_start_pts ? start_pts : 0; |
|
2709 |
fprintf(edl_fd, "%f %f %d\n", mpctx->begin_skip - pts, v - pts, 0); |
|
2710 |
mp_msg(MSGT_CPLAYER, MSGL_INFO, MSGTR_EdloutEndSkip); |
|
2711 |
}
|
|
2712 |
mpctx->begin_skip = MP_NOPTS_VALUE; |
|
2713 |
}
|
|
2714 |
}
|
|
2715 |
break; |
|
2716 |
||
2717 |
case MP_CMD_SWITCH_RATIO: |
|
2718 |
if (!sh_video) |
|
2719 |
break; |
|
2720 |
if (cmd->nargs == 0 || cmd->args[0].v.f == -1) |
|
2721 |
movie_aspect = (float) sh_video->disp_w / sh_video->disp_h; |
|
2722 |
else
|
|
2723 |
movie_aspect = cmd->args[0].v.f; |
|
2724 |
mpcodecs_config_vo(sh_video, sh_video->disp_w, sh_video->disp_h, 0); |
|
2725 |
break; |
|
2726 |
||
2727 |
case MP_CMD_SPEED_INCR:{ |
|
2728 |
float v = cmd->args[0].v.f; |
|
2729 |
playback_speed += v; |
|
2730 |
reinit_audio_chain(); |
|
2731 |
set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed, |
|
2732 |
playback_speed); |
|
2733 |
} break; |
|
2734 |
||
2735 |
case MP_CMD_SPEED_MULT:{ |
|
2736 |
float v = cmd->args[0].v.f; |
|
2737 |
playback_speed *= v; |
|
2738 |
reinit_audio_chain(); |
|
2739 |
set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed, |
|
2740 |
playback_speed); |
|
2741 |
} break; |
|
2742 |
||
2743 |
case MP_CMD_SPEED_SET:{ |
|
2744 |
float v = cmd->args[0].v.f; |
|
2745 |
playback_speed = v; |
|
2746 |
reinit_audio_chain(); |
|
2747 |
set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed, |
|
2748 |
playback_speed); |
|
2749 |
} break; |
|
2750 |
||
2751 |
case MP_CMD_FRAME_STEP: |
|
2752 |
case MP_CMD_PAUSE: |
|
2753 |
cmd->pausing = 1; |
|
2754 |
brk_cmd = 1; |
|
2755 |
break; |
|
2756 |
||
2757 |
case MP_CMD_FILE_FILTER: |
|
2758 |
file_filter = cmd->args[0].v.i; |
|
2759 |
break; |
|
2760 |
||
2761 |
case MP_CMD_QUIT: |
|
2762 |
exit_player_with_rc(EXIT_QUIT, |
|
2763 |
(cmd->nargs > 0) ? cmd->args[0].v.i : 0); |
|
2764 |
||
2765 |
case MP_CMD_PLAY_TREE_STEP:{ |
|
2766 |
int n = cmd->args[0].v.i == 0 ? 1 : cmd->args[0].v.i; |
|
2767 |
int force = cmd->args[1].v.i; |
|
2768 |
||
2769 |
#ifdef CONFIG_GUI
|
|
2770 |
if (use_gui) { |
|
2771 |
int i = 0; |
|
2772 |
if (n > 0) |
|
2773 |
for (i = 0; i < n; i++) |
|
2774 |
gui(GUI_RUN_COMMAND, (void *)MP_CMD_PLAY_TREE_STEP); |
|
2775 |
else
|
|
2776 |
for (i = 0; i < -1 * n; i++) |
|
2777 |
gui(GUI_RUN_COMMAND, (void *)-MP_CMD_PLAY_TREE_STEP); |
|
2778 |
} else |
|
2779 |
#endif
|
|
2780 |
{
|
|
2781 |
if (!force && mpctx->playtree_iter) { |
|
2782 |
play_tree_iter_t *i = |
|
2783 |
play_tree_iter_new_copy(mpctx->playtree_iter); |
|
2784 |
if (play_tree_iter_step(i, n, 0) == |
|
2785 |
PLAY_TREE_ITER_ENTRY) |
|
2786 |
mpctx->eof = |
|
2787 |
(n > 0) ? PT_NEXT_ENTRY : PT_PREV_ENTRY; |
|
2788 |
play_tree_iter_free(i); |
|
2789 |
} else |
|
2790 |
mpctx->eof = (n > 0) ? PT_NEXT_ENTRY : PT_PREV_ENTRY; |
|
2791 |
if (mpctx->eof) |
|
2792 |
mpctx->play_tree_step = n; |
|
2793 |
brk_cmd = 1; |
|
2794 |
}
|
|
2795 |
}
|
|
2796 |
break; |
|
2797 |
||
2798 |
case MP_CMD_PLAY_TREE_UP_STEP:{ |
|
2799 |
int n = cmd->args[0].v.i > 0 ? 1 : -1; |
|
2800 |
int force = cmd->args[1].v.i; |
|
2801 |
||
2802 |
if (!force && mpctx->playtree_iter) { |
|
2803 |
play_tree_iter_t *i = |
|
2804 |
play_tree_iter_new_copy(mpctx->playtree_iter); |
|
2805 |
if (play_tree_iter_up_step(i, n, 0) == PLAY_TREE_ITER_ENTRY) |
|
2806 |
mpctx->eof = (n > 0) ? PT_UP_NEXT : PT_UP_PREV; |
|
2807 |
play_tree_iter_free(i); |
|
2808 |
} else |
|
2809 |
mpctx->eof = (n > 0) ? PT_UP_NEXT : PT_UP_PREV; |
|
2810 |
brk_cmd = 1; |
|
2811 |
}
|
|
2812 |
break; |
|
2813 |
||
2814 |
case MP_CMD_PLAY_ALT_SRC_STEP: |
|
2815 |
if (mpctx->playtree_iter && mpctx->playtree_iter->num_files > 1) { |
|
2816 |
int v = cmd->args[0].v.i; |
|
2817 |
if (v > 0 |
|
2818 |
&& mpctx->playtree_iter->file < |
|
2819 |
mpctx->playtree_iter->num_files) |
|
2820 |
mpctx->eof = PT_NEXT_SRC; |
|
2821 |
else if (v < 0 && mpctx->playtree_iter->file > 1) |
|
2822 |
mpctx->eof = PT_PREV_SRC; |
|
2823 |
}
|
|
2824 |
brk_cmd = 1; |
|
2825 |
break; |
|
2826 |
||
2827 |
case MP_CMD_SUB_STEP: |
|
2828 |
if (sh_video) { |
|
2829 |
int movement = cmd->args[0].v.i; |
|
2830 |
step_sub(subdata, sh_video->pts, movement); |
|
2831 |
#ifdef CONFIG_ASS
|
|
2832 |
if (ass_track) |
|
2833 |
sub_delay += |
|
2834 |
ass_step_sub(ass_track, |
|
2835 |
(sh_video->pts + |
|
2836 |
sub_delay) * 1000 + .5, movement) / 1000.; |
|
2837 |
#endif
|
|
2838 |
set_osd_msg(OSD_MSG_SUB_DELAY, 1, osd_duration, |
|
2839 |
MSGTR_OSDSubDelay, ROUND(sub_delay * 1000)); |
|
2840 |
}
|
|
2841 |
break; |
|
2842 |
||
2843 |
case MP_CMD_SUB_LOG: |
|
2844 |
log_sub(); |
|
2845 |
break; |
|
2846 |
||
2847 |
case MP_CMD_OSD:{ |
|
2848 |
int v = cmd->args[0].v.i; |
|
2849 |
int max = (term_osd |
|
2850 |
&& !sh_video) ? MAX_TERM_OSD_LEVEL : MAX_OSD_LEVEL; |
|
2851 |
if (osd_level > max) |
|
2852 |
osd_level = max; |
|
2853 |
if (v < 0) |
|
2854 |
osd_level = (osd_level + 1) % (max + 1); |
|
2855 |
else
|
|
2856 |
osd_level = v > max ? max : v; |
|
2857 |
/* Show OSD state when disabled, but not when an explicit
|
|
2858 |
argument is given to the OSD command, i.e. in slave mode. */
|
|
2859 |
if (v == -1 && osd_level <= 1) |
|
2860 |
set_osd_msg(OSD_MSG_OSD_STATUS, 0, osd_duration, |
|
2861 |
MSGTR_OSDosd, |
|
2862 |
osd_level ? MSGTR_OSDenabled : |
|
2863 |
MSGTR_OSDdisabled); |
|
2864 |
else
|
|
2865 |
rm_osd_msg(OSD_MSG_OSD_STATUS); |
|
2866 |
}
|
|
2867 |
break; |
|
2868 |
||
2869 |
case MP_CMD_OSD_SHOW_TEXT: |
|
2870 |
set_osd_msg(OSD_MSG_TEXT, cmd->args[2].v.i, |
|
2871 |
(cmd->args[1].v.i < |
|
2872 |
0 ? osd_duration : cmd->args[1].v.i), |
|
2873 |
"%-.63s", cmd->args[0].v.s); |
|
2874 |
break; |
|
2875 |
||
2876 |
case MP_CMD_OSD_SHOW_PROPERTY_TEXT:{ |
|
2877 |
char *txt = m_properties_expand_string(mp_properties, |
|
2878 |
cmd->args[0].v.s, |
|
2879 |
mpctx); |
|
2880 |
/* if no argument supplied take default osd_duration, else <arg> ms. */
|
|
2881 |
if (txt) { |
|
2882 |
set_osd_msg(OSD_MSG_TEXT, cmd->args[2].v.i, |
|
2883 |
(cmd->args[1].v.i < |
|
2884 |
0 ? osd_duration : cmd->args[1].v.i), |
|
2885 |
"%-.63s", txt); |
|
2886 |
free(txt); |
|
2887 |
}
|
|
2888 |
}
|
|
2889 |
break; |
|
2890 |
||
2891 |
case MP_CMD_LOADFILE:{ |
|
2892 |
play_tree_t *e = play_tree_new(); |
|
2893 |
play_tree_add_file(e, cmd->args[0].v.s); |
|
2894 |
||
2895 |
if (cmd->args[1].v.i) // append |
|
2896 |
play_tree_append_entry(mpctx->playtree->child, e); |
|
2897 |
else { |
|
2898 |
// Go back to the starting point.
|
|
2899 |
while (play_tree_iter_up_step |
|
2900 |
(mpctx->playtree_iter, 0, 1) != PLAY_TREE_ITER_END) |
|
2901 |
/* NOP */ ; |
|
2902 |
play_tree_free_list(mpctx->playtree->child, 1); |
|
2903 |
play_tree_set_child(mpctx->playtree, e); |
|
2904 |
pt_iter_goto_head(mpctx->playtree_iter); |
|
2905 |
mpctx->eof = PT_NEXT_SRC; |
|
2906 |
}
|
|
2907 |
brk_cmd = 1; |
|
2908 |
}
|
|
2909 |
break; |
|
2910 |
||
2911 |
case MP_CMD_LOADLIST:{ |
|
2912 |
play_tree_t *e = parse_playlist_file(cmd->args[0].v.s); |
|
2913 |
if (!e) |
|
2914 |
mp_msg(MSGT_CPLAYER, MSGL_ERR, |
|
2915 |
MSGTR_PlaylistLoadUnable, cmd->args[0].v.s); |
|
2916 |
else { |
|
2917 |
if (cmd->args[1].v.i) // append |
|
2918 |
play_tree_append_entry(mpctx->playtree->child, e); |
|
2919 |
else { |
|
2920 |
// Go back to the starting point.
|
|
2921 |
while (play_tree_iter_up_step |
|
2922 |
(mpctx->playtree_iter, 0, 1) |
|
2923 |
!= PLAY_TREE_ITER_END) |
|
2924 |
/* NOP */ ; |
|
2925 |
play_tree_free_list(mpctx->playtree->child, 1); |
|
2926 |
play_tree_set_child(mpctx->playtree, e); |
|
2927 |
pt_iter_goto_head(mpctx->playtree_iter); |
|
2928 |
mpctx->eof = PT_NEXT_SRC; |
|
2929 |
}
|
|
2930 |
}
|
|
2931 |
brk_cmd = 1; |
|
2932 |
}
|
|
2933 |
break; |
|
2934 |
||
2935 |
case MP_CMD_STOP: |
|
2936 |
#ifdef CONFIG_GUI
|
|
2937 |
// playtree_iter isn't used by the GUI
|
|
2938 |
if (use_gui) |
|
2939 |
gui(GUI_RUN_COMMAND, (void *)MP_CMD_STOP); |
|
2940 |
else
|
|
2941 |
#endif
|
|
2942 |
// Go back to the starting point.
|
|
2943 |
while (play_tree_iter_up_step |
|
2944 |
(mpctx->playtree_iter, 0, 1) != PLAY_TREE_ITER_END) |
|
2945 |
/* NOP */ ; |
|
2946 |
mpctx->eof = PT_STOP; |
|
2947 |
brk_cmd = 1; |
|
2948 |
break; |
|
2949 |
||
2950 |
case MP_CMD_OSD_SHOW_PROGRESSION:{ |
|
2951 |
int len = demuxer_get_time_length(mpctx->demuxer); |
|
2952 |
int pts = demuxer_get_current_time(mpctx->demuxer); |
|
2953 |
set_osd_bar(0, "Position", 0, 100, demuxer_get_percent_pos(mpctx->demuxer)); |
|
2954 |
set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, |
|
2955 |
"%c %02d:%02d:%02d / %02d:%02d:%02d", |
|
2956 |
mpctx->osd_function, pts/3600, (pts/60)%60, pts%60, |
|
2957 |
len/3600, (len/60)%60, len%60); |
|
2958 |
}
|
|
2959 |
break; |
|
2960 |
||
2961 |
#ifdef CONFIG_RADIO
|
|
2962 |
case MP_CMD_RADIO_STEP_CHANNEL: |
|
2963 |
if (IS_STREAMTYPE(RADIO)) { |
|
2964 |
int v = cmd->args[0].v.i; |
|
2965 |
if (v > 0) |
|
2966 |
radio_step_channel(mpctx->demuxer->stream, |
|
2967 |
RADIO_CHANNEL_HIGHER); |
|
2968 |
else
|
|
2969 |
radio_step_channel(mpctx->demuxer->stream, |
|
2970 |
RADIO_CHANNEL_LOWER); |
|
2971 |
if (radio_get_channel_name(mpctx->demuxer->stream)) { |
|
2972 |
set_osd_msg(OSD_MSG_RADIO_CHANNEL, 1, osd_duration, |
|
2973 |
MSGTR_OSDChannel, |
|
2974 |
radio_get_channel_name(mpctx->demuxer->stream)); |
|
2975 |
}
|
|
2976 |
}
|
|
2977 |
break; |
|
2978 |
||
2979 |
case MP_CMD_RADIO_SET_CHANNEL: |
|
2980 |
if (IS_STREAMTYPE(RADIO)) { |
|
2981 |
radio_set_channel(mpctx->demuxer->stream, cmd->args[0].v.s); |
|
2982 |
if (radio_get_channel_name(mpctx->demuxer->stream)) { |
|
2983 |
set_osd_msg(OSD_MSG_RADIO_CHANNEL, 1, osd_duration, |
|
2984 |
MSGTR_OSDChannel, |
|
2985 |
radio_get_channel_name(mpctx->demuxer->stream)); |
|
2986 |
}
|
|
2987 |
}
|
|
2988 |
break; |
|
2989 |
||
2990 |
case MP_CMD_RADIO_SET_FREQ: |
|
2991 |
if (IS_STREAMTYPE(RADIO)) |
|
2992 |
radio_set_freq(mpctx->demuxer->stream, cmd->args[0].v.f); |
|
2993 |
break; |
|
2994 |
||
2995 |
case MP_CMD_RADIO_STEP_FREQ: |
|
2996 |
if (IS_STREAMTYPE(RADIO)) |
|
2997 |
radio_step_freq(mpctx->demuxer->stream, cmd->args[0].v.f); |
|
2998 |
break; |
|
2999 |
#endif
|
|
3000 |
||
3001 |
#ifdef CONFIG_TV
|
|
3002 |
case MP_CMD_TV_START_SCAN: |
|
3003 |
if (mpctx->file_format == DEMUXER_TYPE_TV) |
|
3004 |
tv_start_scan((tvi_handle_t *) (mpctx->demuxer->priv),1); |
|
3005 |
break; |
|
3006 |
case MP_CMD_TV_SET_FREQ: |
|
3007 |
if (mpctx->file_format == DEMUXER_TYPE_TV) |
|
3008 |
tv_set_freq((tvi_handle_t *) (mpctx->demuxer->priv), |
|
3009 |
cmd->args[0].v.f * 16.0); |
|
3010 |
#ifdef CONFIG_PVR
|
|
3011 |
else if (IS_STREAMTYPE(PVR)) { |
|
3012 |
pvr_set_freq (mpctx->stream, ROUND (cmd->args[0].v.f)); |
|
3013 |
set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s", |
|
3014 |
pvr_get_current_channelname (mpctx->stream), |
|
3015 |
pvr_get_current_stationname (mpctx->stream)); |
|
3016 |
}
|
|
3017 |
#endif /* CONFIG_PVR */ |
|
3018 |
break; |
|
3019 |
||
3020 |
case MP_CMD_TV_STEP_FREQ: |
|
3021 |
if (mpctx->file_format == DEMUXER_TYPE_TV) |
|
3022 |
tv_step_freq((tvi_handle_t *) (mpctx->demuxer->priv), |
|
3023 |
cmd->args[0].v.f * 16.0); |
|
3024 |
#ifdef CONFIG_PVR
|
|
3025 |
else if (IS_STREAMTYPE(PVR)) { |
|
3026 |
pvr_force_freq_step (mpctx->stream, ROUND (cmd->args[0].v.f)); |
|
3027 |
set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: f %d", |
|
3028 |
pvr_get_current_channelname (mpctx->stream), |
|
3029 |
pvr_get_current_frequency (mpctx->stream)); |
|
3030 |
}
|
|
3031 |
#endif /* CONFIG_PVR */ |
|
3032 |
break; |
|
3033 |
||
3034 |
case MP_CMD_TV_SET_NORM: |
|
3035 |
if (mpctx->file_format == DEMUXER_TYPE_TV) |
|
3036 |
tv_set_norm((tvi_handle_t *) (mpctx->demuxer->priv), |
|
3037 |
cmd->args[0].v.s); |
|
3038 |
break; |
|
3039 |
||
3040 |
case MP_CMD_TV_STEP_CHANNEL:{ |
|
3041 |
if (mpctx->file_format == DEMUXER_TYPE_TV) { |
|
3042 |
int v = cmd->args[0].v.i; |
|
3043 |
if (v > 0) { |
|
3044 |
tv_step_channel((tvi_handle_t *) (mpctx-> |
|
3045 |
demuxer->priv), |
|
3046 |
TV_CHANNEL_HIGHER); |
|
3047 |
} else { |
|
3048 |
tv_step_channel((tvi_handle_t *) (mpctx-> |
|
3049 |
demuxer->priv), |
|
3050 |
TV_CHANNEL_LOWER); |
|
3051 |
}
|
|
3052 |
if (tv_channel_list) { |
|
3053 |
set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration, |
|
3054 |
MSGTR_OSDChannel, tv_channel_current->name); |
|
3055 |
//vo_osd_changed(OSDTYPE_SUBTITLE);
|
|
3056 |
}
|
|
3057 |
}
|
|
3058 |
#ifdef CONFIG_PVR
|
|
3059 |
else if (IS_STREAMTYPE(PVR)) { |
|
3060 |
pvr_set_channel_step (mpctx->stream, cmd->args[0].v.i); |
|
3061 |
set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s", |
|
3062 |
pvr_get_current_channelname (mpctx->stream), |
|
3063 |
pvr_get_current_stationname (mpctx->stream)); |
|
3064 |
}
|
|
3065 |
#endif /* CONFIG_PVR */ |
|
3066 |
}
|
|
3067 |
#ifdef CONFIG_DVBIN
|
|
3068 |
if (IS_STREAMTYPE(DVB)) { |
|
3069 |
int dir; |
|
3070 |
int v = cmd->args[0].v.i; |
|
3071 |
||
3072 |
mpctx->last_dvb_step = v; |
|
3073 |
if (v > 0) |
|
3074 |
dir = DVB_CHANNEL_HIGHER; |
|
3075 |
else
|
|
3076 |
dir = DVB_CHANNEL_LOWER; |
|
3077 |
||
3078 |
||
3079 |
if (dvb_step_channel(mpctx->stream, dir)) |
|
3080 |
mpctx->eof = mpctx->dvbin_reopen = 1; |
|
3081 |
}
|
|
3082 |
#endif /* CONFIG_DVBIN */ |
|
3083 |
break; |
|
3084 |
||
3085 |
case MP_CMD_TV_SET_CHANNEL: |
|
3086 |
if (mpctx->file_format == DEMUXER_TYPE_TV) { |
|
3087 |
tv_set_channel((tvi_handle_t *) (mpctx->demuxer->priv), |
|
3088 |
cmd->args[0].v.s); |
|
3089 |
if (tv_channel_list) { |
|
3090 |
set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration, |
|
3091 |
MSGTR_OSDChannel, tv_channel_current->name); |
|
3092 |
//vo_osd_changed(OSDTYPE_SUBTITLE);
|
|
3093 |
}
|
|
3094 |
}
|
|
3095 |
#ifdef CONFIG_PVR
|
|
3096 |
else if (IS_STREAMTYPE(PVR)) { |
|
3097 |
pvr_set_channel (mpctx->stream, cmd->args[0].v.s); |
|
3098 |
set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s", |
|
3099 |
pvr_get_current_channelname (mpctx->stream), |
|
3100 |
pvr_get_current_stationname (mpctx->stream)); |
|
3101 |
}
|
|
3102 |
#endif /* CONFIG_PVR */ |
|
3103 |
break; |
|
3104 |
||
3105 |
#ifdef CONFIG_DVBIN
|
|
3106 |
case MP_CMD_DVB_SET_CHANNEL: |
|
3107 |
if (IS_STREAMTYPE(DVB)) { |
|
3108 |
mpctx->last_dvb_step = 1; |
|
3109 |
||
3110 |
if (dvb_set_channel |
|
3111 |
(mpctx->stream, cmd->args[1].v.i, cmd->args[0].v.i)) |
|
3112 |
mpctx->eof = mpctx->dvbin_reopen = 1; |
|
3113 |
}
|
|
3114 |
break; |
|
3115 |
#endif /* CONFIG_DVBIN */ |
|
3116 |
||
3117 |
case MP_CMD_TV_LAST_CHANNEL: |
|
3118 |
if (mpctx->file_format == DEMUXER_TYPE_TV) { |
|
3119 |
tv_last_channel((tvi_handle_t *) (mpctx->demuxer->priv)); |
|
3120 |
if (tv_channel_list) { |
|
3121 |
set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration, |
|
3122 |
MSGTR_OSDChannel, tv_channel_current->name); |
|
3123 |
//vo_osd_changed(OSDTYPE_SUBTITLE);
|
|
3124 |
}
|
|
3125 |
}
|
|
3126 |
#ifdef CONFIG_PVR
|
|
3127 |
else if (IS_STREAMTYPE(PVR)) { |
|
3128 |
pvr_set_lastchannel (mpctx->stream); |
|
3129 |
set_osd_msg (OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s", |
|
3130 |
pvr_get_current_channelname (mpctx->stream), |
|
3131 |
pvr_get_current_stationname (mpctx->stream)); |
|
3132 |
}
|
|
3133 |
#endif /* CONFIG_PVR */ |
|
3134 |
break; |
|
3135 |
||
3136 |
case MP_CMD_TV_STEP_NORM: |
|
3137 |
if (mpctx->file_format == DEMUXER_TYPE_TV) |
|
3138 |
tv_step_norm((tvi_handle_t *) (mpctx->demuxer->priv)); |
|
3139 |
break; |
|
3140 |
||
3141 |
case MP_CMD_TV_STEP_CHANNEL_LIST: |
|
3142 |
if (mpctx->file_format == DEMUXER_TYPE_TV) |
|
3143 |
tv_step_chanlist((tvi_handle_t *) (mpctx->demuxer->priv)); |
|
3144 |
break; |
|
3145 |
#endif /* CONFIG_TV */ |
|
3146 |
case MP_CMD_TV_TELETEXT_ADD_DEC: |
|
3147 |
if (mpctx->demuxer->teletext) |
|
3148 |
teletext_control(mpctx->demuxer->teletext,TV_VBI_CONTROL_ADD_DEC, |
|
3149 |
&(cmd->args[0].v.s)); |
|
3150 |
break; |
|
3151 |
case MP_CMD_TV_TELETEXT_GO_LINK: |
|
3152 |
if (mpctx->demuxer->teletext) |
|
3153 |
teletext_control(mpctx->demuxer->teletext,TV_VBI_CONTROL_GO_LINK, |
|
3154 |
&(cmd->args[0].v.i)); |
|
3155 |
break; |
|
3156 |
||
3157 |
case MP_CMD_OVERLAY_ADD: |
|
3158 |
overlay_add(cmd->args[0].v.s, cmd->args[1].v.i, |
|
3159 |
cmd->args[2].v.i, cmd->args[3].v.i, cmd->args[4].v.i); |
|
3160 |
break; |
|
3161 |
case MP_CMD_OVERLAY_REMOVE: |
|
3162 |
overlay_remove(cmd->args[0].v.i); |
|
3163 |
break; |
|
3164 |
||
3165 |
case MP_CMD_SUB_LOAD: |
|
3166 |
if (sh_video) { |
|
3167 |
int n = mpctx->set_of_sub_size; |
|
3168 |
add_subtitles(cmd->args[0].v.s, sh_video->fps, 0); |
|
3169 |
if (n != mpctx->set_of_sub_size) { |
|
3170 |
mpctx->sub_counts[SUB_SOURCE_SUBS]++; |
|
3171 |
++mpctx->global_sub_size; |
|
3172 |
}
|
|
3173 |
}
|
|
3174 |
break; |
|
3175 |
||
3176 |
case MP_CMD_SUB_REMOVE: |
|
3177 |
if (sh_video) { |
|
3178 |
int v = cmd->args[0].v.i; |
|
3179 |
if (v < 0) { |
|
3180 |
remove_subtitle_range(mpctx, 0, mpctx->set_of_sub_size); |
|
3181 |
} else if (v < mpctx->set_of_sub_size) { |
|
3182 |
remove_subtitle_range(mpctx, v, 1); |
|
3183 |
}
|
|
3184 |
}
|
|
3185 |
break; |
|
3186 |
||
3187 |
case MP_CMD_GET_SUB_VISIBILITY: |
|
3188 |
if (sh_video) { |
|
3189 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, |
|
3190 |
"ANS_SUB_VISIBILITY=%d\n", sub_visibility); |
|
3191 |
}
|
|
3192 |
break; |
|
3193 |
||
3194 |
case MP_CMD_SCREENSHOT: |
|
3195 |
if (vo_config_count) { |
|
3196 |
mp_msg(MSGT_CPLAYER, MSGL_INFO, "sending VFCTRL_SCREENSHOT!\n"); |
|
3197 |
if (CONTROL_OK != |
|
3198 |
((vf_instance_t *) sh_video->vfilter)-> |
|
3199 |
control(sh_video->vfilter, VFCTRL_SCREENSHOT, |
|
3200 |
&cmd->args[0].v.i)) |
|
3201 |
mp_msg(MSGT_CPLAYER, MSGL_INFO, "failed (forgot -vf screenshot?)\n"); |
|
3202 |
}
|
|
3203 |
break; |
|
3204 |
||
3205 |
case MP_CMD_VF_CHANGE_RECTANGLE: |
|
3206 |
if (!sh_video) |
|
3207 |
break; |
|
3208 |
set_rectangle(sh_video, cmd->args[0].v.i, cmd->args[1].v.i); |
|
3209 |
break; |
|
3210 |
||
3211 |
case MP_CMD_GET_TIME_LENGTH:{ |
|
3212 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_LENGTH=%.2f\n", |
|
3213 |
demuxer_get_time_length(mpctx->demuxer)); |
|
3214 |
}
|
|
3215 |
break; |
|
3216 |
||
3217 |
case MP_CMD_GET_FILENAME:{ |
|
3218 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_FILENAME='%s'\n", |
|
3219 |
get_metadata(META_NAME)); |
|
3220 |
}
|
|
3221 |
break; |
|
3222 |
||
3223 |
case MP_CMD_GET_VIDEO_CODEC:{ |
|
3224 |
char *inf = get_metadata(META_VIDEO_CODEC); |
|
3225 |
if (!inf) |
|
3226 |
inf = strdup(""); |
|
3227 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VIDEO_CODEC='%s'\n", inf); |
|
3228 |
free(inf); |
|
3229 |
}
|
|
3230 |
break; |
|
3231 |
||
3232 |
case MP_CMD_GET_VIDEO_BITRATE:{ |
|
3233 |
char *inf = get_metadata(META_VIDEO_BITRATE); |
|
3234 |
if (!inf) |
|
3235 |
inf = strdup(""); |
|
3236 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VIDEO_BITRATE='%s'\n", inf); |
|
3237 |
free(inf); |
|
3238 |
}
|
|
3239 |
break; |
|
3240 |
||
3241 |
case MP_CMD_GET_VIDEO_RESOLUTION:{ |
|
3242 |
char *inf = get_metadata(META_VIDEO_RESOLUTION); |
|
3243 |
if (!inf) |
|
3244 |
inf = strdup(""); |
|
3245 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, |
|
3246 |
"ANS_VIDEO_RESOLUTION='%s'\n", inf); |
|
3247 |
free(inf); |
|
3248 |
}
|
|
3249 |
break; |
|
3250 |
||
3251 |
case MP_CMD_GET_AUDIO_CODEC:{ |
|
3252 |
char *inf = get_metadata(META_AUDIO_CODEC); |
|
3253 |
if (!inf) |
|
3254 |
inf = strdup(""); |
|
3255 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_CODEC='%s'\n", inf); |
|
3256 |
free(inf); |
|
3257 |
}
|
|
3258 |
break; |
|
3259 |
||
3260 |
case MP_CMD_GET_AUDIO_BITRATE:{ |
|
3261 |
char *inf = get_metadata(META_AUDIO_BITRATE); |
|
3262 |
if (!inf) |
|
3263 |
inf = strdup(""); |
|
3264 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_BITRATE='%s'\n", inf); |
|
3265 |
free(inf); |
|
3266 |
}
|
|
3267 |
break; |
|
3268 |
||
3269 |
case MP_CMD_GET_AUDIO_SAMPLES:{ |
|
3270 |
char *inf = get_metadata(META_AUDIO_SAMPLES); |
|
3271 |
if (!inf) |
|
3272 |
inf = strdup(""); |
|
3273 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_SAMPLES='%s'\n", inf); |
|
3274 |
free(inf); |
|
3275 |
}
|
|
3276 |
break; |
|
3277 |
||
3278 |
case MP_CMD_GET_META_TITLE:{ |
|
3279 |
char *inf = get_metadata(META_INFO_TITLE); |
|
3280 |
if (!inf) |
|
3281 |
inf = strdup(""); |
|
3282 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_TITLE='%s'\n", inf); |
|
3283 |
free(inf); |
|
3284 |
}
|
|
3285 |
break; |
|
3286 |
||
3287 |
case MP_CMD_GET_META_ARTIST:{ |
|
3288 |
char *inf = get_metadata(META_INFO_ARTIST); |
|
3289 |
if (!inf) |
|
3290 |
inf = strdup(""); |
|
3291 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_ARTIST='%s'\n", inf); |
|
3292 |
free(inf); |
|
3293 |
}
|
|
3294 |
break; |
|
3295 |
||
3296 |
case MP_CMD_GET_META_ALBUM:{ |
|
3297 |
char *inf = get_metadata(META_INFO_ALBUM); |
|
3298 |
if (!inf) |
|
3299 |
inf = strdup(""); |
|
3300 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_ALBUM='%s'\n", inf); |
|
3301 |
free(inf); |
|
3302 |
}
|
|
3303 |
break; |
|
3304 |
||
3305 |
case MP_CMD_GET_META_YEAR:{ |
|
3306 |
char *inf = get_metadata(META_INFO_YEAR); |
|
3307 |
if (!inf) |
|
3308 |
inf = strdup(""); |
|
3309 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_YEAR='%s'\n", inf); |
|
3310 |
free(inf); |
|
3311 |
}
|
|
3312 |
break; |
|
3313 |
||
3314 |
case MP_CMD_GET_META_COMMENT:{ |
|
3315 |
char *inf = get_metadata(META_INFO_COMMENT); |
|
3316 |
if (!inf) |
|
3317 |
inf = strdup(""); |
|
3318 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_COMMENT='%s'\n", inf); |
|
3319 |
free(inf); |
|
3320 |
}
|
|
3321 |
break; |
|
3322 |
||
3323 |
case MP_CMD_GET_META_TRACK:{ |
|
3324 |
char *inf = get_metadata(META_INFO_TRACK); |
|
3325 |
if (!inf) |
|
3326 |
inf = strdup(""); |
|
3327 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_TRACK='%s'\n", inf); |
|
3328 |
free(inf); |
|
3329 |
}
|
|
3330 |
break; |
|
3331 |
||
3332 |
case MP_CMD_GET_META_GENRE:{ |
|
3333 |
char *inf = get_metadata(META_INFO_GENRE); |
|
3334 |
if (!inf) |
|
3335 |
inf = strdup(""); |
|
3336 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_GENRE='%s'\n", inf); |
|
3337 |
free(inf); |
|
3338 |
}
|
|
3339 |
break; |
|
3340 |
||
3341 |
case MP_CMD_GET_VO_FULLSCREEN: |
|
3342 |
if (mpctx->video_out && vo_config_count) |
|
3343 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VO_FULLSCREEN=%d\n", vo_fs); |
|
3344 |
break; |
|
3345 |
||
3346 |
case MP_CMD_GET_PERCENT_POS: |
|
3347 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_PERCENT_POSITION=%d\n", |
|
3348 |
demuxer_get_percent_pos(mpctx->demuxer)); |
|
3349 |
break; |
|
3350 |
||
3351 |
case MP_CMD_GET_TIME_POS:{ |
|
3352 |
float pos = 0; |
|
3353 |
if (sh_video) |
|
3354 |
pos = sh_video->pts; |
|
3355 |
else if (sh_audio && mpctx->audio_out) |
|
3356 |
pos = |
|
3357 |
playing_audio_pts(sh_audio, mpctx->d_audio, |
|
3358 |
mpctx->audio_out); |
|
3359 |
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_TIME_POSITION=%.1f\n", pos); |
|
3360 |
}
|
|
3361 |
break; |
|
3362 |
||
3363 |
case MP_CMD_RUN: |
|
3364 |
#ifndef __MINGW32__
|
|
3365 |
if (!fork()) { |
|
3366 |
char *exp_cmd = property_expand_string(mpctx, cmd->args[0].v.s); |
|
3367 |
if (exp_cmd) { |
|
3368 |
execl("/bin/sh", "sh", "-c", exp_cmd, NULL); |
|
3369 |
free(exp_cmd); |
|
3370 |
}
|
|
3371 |
exit(0); |
|
3372 |
}
|
|
3373 |
#endif
|
|
3374 |
break; |
|
3375 |
||
3376 |
case MP_CMD_KEYDOWN_EVENTS: |
|
3377 |
mplayer_put_key(cmd->args[0].v.i); |
|
3378 |
break; |
|
3379 |
||
3380 |
case MP_CMD_SET_MOUSE_POS:{ |
|
3381 |
int pointer_x, pointer_y; |
|
3382 |
double dx, dy; |
|
3383 |
pointer_x = cmd->args[0].v.i; |
|
3384 |
pointer_y = cmd->args[1].v.i; |
|
3385 |
rescale_input_coordinates(pointer_x, pointer_y, &dx, &dy); |
|
3386 |
#ifdef CONFIG_DVDNAV
|
|
3387 |
if (IS_STREAMTYPE(DVDNAV) |
|
3388 |
&& dx > 0.0 && dy > 0.0) { |
|
3389 |
int button = -1; |
|
3390 |
pointer_x = (int) (dx * (double) sh_video->disp_w); |
|
3391 |
pointer_y = (int) (dy * (double) sh_video->disp_h); |
|
3392 |
mp_dvdnav_update_mouse_pos(mpctx->stream, |
|
3393 |
pointer_x, pointer_y, &button); |
|
3394 |
if (osd_level > 1 && button > 0) |
|
3395 |
set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, |
|
3396 |
"Selected button number %d", button); |
|
3397 |
}
|
|
3398 |
#endif
|
|
3399 |
#ifdef CONFIG_MENU
|
|
3400 |
if (use_menu && dx >= 0.0 && dy >= 0.0) |
|
3401 |
menu_update_mouse_pos(dx, dy); |
|
3402 |
#endif
|
|
3403 |
}
|
|
3404 |
break; |
|
3405 |
||
3406 |
#ifdef CONFIG_DVDNAV
|
|
3407 |
case MP_CMD_DVDNAV:{ |
|
3408 |
int button = -1; |
|
3409 |
int i; |
|
3410 |
mp_command_type command = 0; |
|
3411 |
if (!IS_STREAMTYPE(DVDNAV)) |
|
3412 |
break; |
|
3413 |
||
3414 |
for (i = 0; mp_dvdnav_bindings[i].name; i++) |
|
3415 |
if (cmd->args[0].v.s && |
|
3416 |
!strcasecmp (cmd->args[0].v.s, |
|
3417 |
mp_dvdnav_bindings[i].name)) |
|
3418 |
command = mp_dvdnav_bindings[i].cmd; |
|
3419 |
||
3420 |
mp_dvdnav_handle_input(mpctx->stream,command,&button); |
|
3421 |
if (osd_level > 1 && button > 0) |
|
3422 |
set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, |
|
3423 |
"Selected button number %d", button); |
|
3424 |
}
|
|
3425 |
break; |
|
3426 |
||
3427 |
case MP_CMD_SWITCH_TITLE: |
|
3428 |
if (IS_STREAMTYPE(DVDNAV)) |
|
3429 |
mp_dvdnav_switch_title(mpctx->stream, cmd->args[0].v.i); |
|
3430 |
break; |
|
3431 |
||
3432 |
#endif
|
|
3433 |
||
3434 |
case MP_CMD_AF_SWITCH: |
|
3435 |
if (sh_audio) |
|
3436 |
{
|
|
3437 |
af_uninit(mpctx->mixer.afilter); |
|
3438 |
af_init(mpctx->mixer.afilter); |
|
3439 |
}
|
|
3440 |
case MP_CMD_AF_ADD: |
|
3441 |
case MP_CMD_AF_DEL: |
|
3442 |
if (!sh_audio) |
|
3443 |
break; |
|
3444 |
{
|
|
3445 |
char* af_args = strdup(cmd->args[0].v.s); |
|
3446 |
char* af_commands = af_args; |
|
3447 |
char* af_command; |
|
3448 |
af_instance_t* af; |
|
3449 |
while ((af_command = strsep(&af_commands, ",")) != NULL) |
|
3450 |
{
|
|
3451 |
if (cmd->id == MP_CMD_AF_DEL) |
|
3452 |
{
|
|
3453 |
af = af_get(mpctx->mixer.afilter, af_command); |
|
3454 |
if (af != NULL) |
|
3455 |
af_remove(mpctx->mixer.afilter, af); |
|
3456 |
}
|
|
3457 |
else
|
|
3458 |
af_add(mpctx->mixer.afilter, af_command); |
|
3459 |
}
|
|
3460 |
reinit_audio_chain(); |
|
3461 |
free(af_args); |
|
3462 |
}
|
|
3463 |
break; |
|
3464 |
case MP_CMD_AF_CLR: |
|
3465 |
if (!sh_audio) |
|
3466 |
break; |
|
3467 |
af_uninit(mpctx->mixer.afilter); |
|
3468 |
af_init(mpctx->mixer.afilter); |
|
3469 |
reinit_audio_chain(); |
|
3470 |
break; |
|
3471 |
case MP_CMD_AF_CMDLINE: |
|
3472 |
if (sh_audio) { |
|
3473 |
af_instance_t *af = af_get(sh_audio->afilter, cmd->args[0].v.s); |
|
3474 |
if (!af) { |
|
3475 |
mp_msg(MSGT_CPLAYER, MSGL_WARN, |
|
3476 |
"Filter '%s' not found in chain.\n", cmd->args[0].v.s); |
|
3477 |
break; |
|
3478 |
}
|
|
3479 |
af->control(af, AF_CONTROL_COMMAND_LINE, cmd->args[1].v.s); |
|
3480 |
af_reinit(sh_audio->afilter, af); |
|
3481 |
}
|
|
3482 |
break; |
|
3483 |
||
3484 |
default: |
|
3485 |
#ifdef CONFIG_GUI
|
|
3486 |
if (use_gui && cmd->id == MP_CMD_GUI) |
|
3487 |
gui(GUI_RUN_MESSAGE, cmd->args[0].v.s); |
|
3488 |
else
|
|
3489 |
#endif
|
|
3490 |
mp_msg(MSGT_CPLAYER, MSGL_V, |
|
3491 |
"Received unknown cmd %s\n", cmd->name); |
|
3492 |
}
|
|
3493 |
||
3494 |
switch (cmd->pausing) { |
|
3495 |
case 1: // "pausing" |
|
3496 |
mpctx->osd_function = OSD_PAUSE; |
|
3497 |
break; |
|
3498 |
case 3: // "pausing_toggle" |
|
3499 |
mpctx->was_paused = !mpctx->was_paused; |
|
3500 |
if (mpctx->was_paused) |
|
3501 |
mpctx->osd_function = OSD_PAUSE; |
|
3502 |
else if (mpctx->osd_function == OSD_PAUSE) |
|
3503 |
mpctx->osd_function = OSD_PLAY; |
|
3504 |
break; |
|
3505 |
case 2: // "pausing_keep" |
|
3506 |
if (mpctx->was_paused) |
|
3507 |
mpctx->osd_function = OSD_PAUSE; |
|
3508 |
}
|
|
3509 |
return brk_cmd; |
|
3510 |
}
|