1710 lines
46 KiB
C
1710 lines
46 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <Eina.h>
|
|
#include <Evas.h>
|
|
#include <Ecore.h>
|
|
|
|
#include "Emotion.h"
|
|
#include "emotion_private.h"
|
|
#include "emotion_xine.h"
|
|
|
|
int _emotion_xine_log_domain = -1;
|
|
|
|
/* module api */
|
|
static unsigned char em_init (Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt);
|
|
static int em_shutdown (void *ef);
|
|
static unsigned char em_file_open (const char *file, Evas_Object *obj, void *ef);
|
|
static void em_file_close (void *ef);
|
|
static void em_play (void *ef, double pos);
|
|
static void em_stop (void *ef);
|
|
static void em_size_get (void *ef, int *w, int *h);
|
|
static void em_pos_set (void *ef, double pos);
|
|
static double em_len_get (void *ef);
|
|
static int em_fps_num_get (void *ef);
|
|
static int em_fps_den_get (void *ef);
|
|
static double em_fps_get (void *ef);
|
|
static double em_pos_get (void *ef);
|
|
static void em_vis_set (void *ef, Emotion_Vis vis);
|
|
static Emotion_Vis em_vis_get (void *ef);
|
|
static Eina_Bool em_vis_supported (void *ef, Emotion_Vis vis);
|
|
static double em_ratio_get (void *ef);
|
|
static int em_seekable (void *ef);
|
|
static void em_frame_done (void *ef);
|
|
static Emotion_Format em_format_get (void *ef);
|
|
static void em_video_data_size_get (void *ef, int *w, int *h);
|
|
static int em_yuv_rows_get (void *ef, int w, int h, unsigned char **yrows, unsigned char **urows, unsigned char **vrows);
|
|
static int em_bgra_data_get (void *ef, unsigned char **bgra_data);
|
|
static void em_event_feed (void *ef, int event);
|
|
static void em_event_mouse_button_feed (void *ef, int button, int x, int y);
|
|
static void em_event_mouse_move_feed (void *ef, int x, int y);
|
|
static int em_video_channel_count (void *ef);
|
|
static void em_video_channel_set (void *ef, int channel);
|
|
static int em_video_channel_get (void *ef);
|
|
static const char *em_video_channel_name_get (void *ef, int channel);
|
|
static void em_video_channel_mute_set (void *ef, int mute);
|
|
static int em_video_channel_mute_get (void *ef);
|
|
static int em_audio_channel_count (void *ef);
|
|
static void em_audio_channel_set (void *ef, int channel);
|
|
static int em_audio_channel_get (void *ef);
|
|
static const char *em_audio_channel_name_get (void *ef, int channel);
|
|
static void em_audio_channel_mute_set (void *ef, int mute);
|
|
static int em_audio_channel_mute_get (void *ef);
|
|
static void em_audio_channel_volume_set(void *ef, double vol);
|
|
static double em_audio_channel_volume_get(void *ef);
|
|
static int em_spu_channel_count (void *ef);
|
|
static void em_spu_channel_set (void *ef, int channel);
|
|
static int em_spu_channel_get (void *ef);
|
|
static const char *em_spu_channel_name_get (void *ef, int channel);
|
|
static void em_spu_channel_mute_set (void *ef, int mute);
|
|
static int em_spu_channel_mute_get (void *ef);
|
|
static int em_chapter_count (void *ef);
|
|
static void em_chapter_set (void *ef, int chapter);
|
|
static int em_chapter_get (void *ef);
|
|
static const char *em_chapter_name_get (void *ef, int chapter);
|
|
static void em_speed_set (void *ef, double speed);
|
|
static double em_speed_get (void *ef);
|
|
static int em_eject (void *ef);
|
|
static const char *em_meta_get (void *ef, int meta);
|
|
|
|
/* internal util calls */
|
|
static void *_em_slave (void *par);
|
|
static void _em_slave_event (void *data, int type, void *arg);
|
|
static Eina_Bool _em_fd_active (void *data, Ecore_Fd_Handler *fdh);
|
|
static void _em_event (void *data, const xine_event_t *event);
|
|
static void _em_module_event (void *data, int type);
|
|
static Eina_Bool _em_fd_ev_active (void *data, Ecore_Fd_Handler *fdh);
|
|
//static int _em_timer (void *data);
|
|
static void *_em_get_pos_len_th(void *par);
|
|
static void _em_get_pos_len (Emotion_Xine_Video *ev);
|
|
|
|
extern plugin_info_t emotion_xine_plugin_info[];
|
|
|
|
/* this is a slave controller thread for the xine module - libxine loves
|
|
* to deadlock, internally stall and otherwise have unpredictable behavior
|
|
* if we use the main process thread for many things - so a lot will be
|
|
* farmed off to this slave. its job is to handle opening, closing, file
|
|
* opening, recoder init etc. and all sorts of things can that often block.
|
|
* anything this thread needs to return, it will return via the event pipe.
|
|
*/
|
|
static void *
|
|
_em_slave(void *par)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
void *buf[2];
|
|
int len;
|
|
|
|
ev = (Emotion_Xine_Video *)par;
|
|
while ((len = read(ev->fd_slave_read, buf, sizeof(buf))) > 0)
|
|
{
|
|
if (len == sizeof(buf))
|
|
{
|
|
Emotion_Xine_Event *eev;
|
|
|
|
ev = buf[0];
|
|
eev = buf[1];
|
|
switch (eev->mtype)
|
|
{
|
|
case 0: /* noop */
|
|
break;
|
|
case 1: /* init */
|
|
{
|
|
ev->decoder = xine_new();
|
|
xine_init(ev->decoder);
|
|
xine_register_plugins(ev->decoder, emotion_xine_plugin_info);
|
|
if (1)
|
|
{
|
|
xine_cfg_entry_t cf;
|
|
if (xine_config_lookup_entry(ev->decoder, "input.dvd_use_readahead", &cf))
|
|
{
|
|
cf.num_value = 1; // 0 or 1
|
|
xine_config_update_entry(ev->decoder, &cf);
|
|
}
|
|
}
|
|
DBG("OPEN VIDEO PLUGIN...");
|
|
if (!ev->opt_no_video)
|
|
ev->video = xine_open_video_driver(ev->decoder, "emotion",
|
|
XINE_VISUAL_TYPE_NONE, ev);
|
|
DBG("RESULT: xine_open_video_driver() = %p", ev->video);
|
|
// Let xine autodetect the best audio output driver
|
|
if (!ev->opt_no_audio)
|
|
ev->audio = xine_open_audio_driver(ev->decoder, NULL, ev);
|
|
// ev->audio = xine_open_audio_driver(ev->decoder, "oss", ev);
|
|
// dont use alsa - alsa has oss emulation.
|
|
// ev->audio = xine_open_audio_driver(ev->decoder, "alsa", ev);
|
|
// ev->audio = xine_open_audio_driver(ev->decoder, "arts", ev);
|
|
// ev->audio = xine_open_audio_driver(ev->decoder, "esd", ev);
|
|
ev->stream = xine_stream_new(ev->decoder, ev->audio, ev->video);
|
|
ev->queue = xine_event_new_queue(ev->stream);
|
|
xine_event_create_listener_thread(ev->queue, _em_event, ev);
|
|
ev->opening = 0;
|
|
ev->play_ok = 1;
|
|
_em_module_event(ev, 1); /* event - open done */
|
|
}
|
|
break;
|
|
case 3: /* shutdown */
|
|
{
|
|
_em_module_event(ev, 3);
|
|
DBG("shutdown stop");
|
|
xine_stop(ev->stream);
|
|
// pthread_mutex_lock(&(ev->get_pos_len_mutex));
|
|
if (!ev->get_pos_thread_deleted)
|
|
{
|
|
DBG("closing get_pos thread, %p", ev);
|
|
pthread_mutex_lock(&(ev->get_pos_len_mutex));
|
|
pthread_cond_broadcast(&(ev->get_pos_len_cond));
|
|
pthread_mutex_unlock(&(ev->get_pos_len_mutex));
|
|
while (ev->get_poslen);
|
|
}
|
|
DBG("dispose %p", ev);
|
|
xine_dispose(ev->stream);
|
|
DBG("dispose evq %p", ev);
|
|
xine_event_dispose_queue(ev->queue);
|
|
DBG("close video drv %p", ev);
|
|
if (ev->video) xine_close_video_driver(ev->decoder, ev->video);
|
|
DBG("wait for vo to go");
|
|
while (ev->have_vo);
|
|
DBG("vo gone");
|
|
DBG("close audio drv %p", ev);
|
|
if (ev->audio) xine_close_audio_driver(ev->decoder, ev->audio);
|
|
DBG("xine exit %p", ev);
|
|
xine_exit(ev->decoder);
|
|
DBG("DONE %p", ev);
|
|
close(ev->fd_write);
|
|
close(ev->fd_read);
|
|
close(ev->fd_ev_write);
|
|
close(ev->fd_ev_read);
|
|
close(ev->fd_slave_write);
|
|
close(ev->fd_slave_read);
|
|
ev->closing = 0;
|
|
if (eev->xine_event) free(eev->xine_event);
|
|
free(eev);
|
|
free(ev);
|
|
return NULL;
|
|
}
|
|
break;
|
|
case 2: /* file open */
|
|
{
|
|
int pos_stream = 0;
|
|
int pos_time = 0;
|
|
int length_time = 0;
|
|
uint32_t v;
|
|
char *file;
|
|
|
|
file = eev->xine_event;
|
|
DBG("OPEN STREAM %s", file);
|
|
if (xine_open(ev->stream, file))
|
|
{
|
|
if (xine_get_pos_length(ev->stream, &pos_stream, &pos_time, &length_time))
|
|
{
|
|
if (length_time == 0)
|
|
{
|
|
ev->pos = (double)pos_stream / 65535;
|
|
ev->len = 1.0;
|
|
ev->no_time = 1;
|
|
}
|
|
else
|
|
{
|
|
ev->pos = 0.0;
|
|
ev->len = (double)length_time / 1000.0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ev->pos = 0.0;
|
|
ev->len = 1.0;
|
|
}
|
|
v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_FRAME_DURATION);
|
|
if (v > 0) ev->fps = 90000.0 / (double)v;
|
|
v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_WIDTH);
|
|
ev->w = v;
|
|
v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HEIGHT);
|
|
ev->h = v;
|
|
v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_RATIO);
|
|
ev->ratio = (double)v / 10000.0;
|
|
ev->just_loaded = 1;
|
|
ev->get_poslen = 0;
|
|
xine_set_param(ev->stream, XINE_PARAM_AUDIO_VOLUME, ev->volume * 100);
|
|
}
|
|
_em_module_event(ev, 2); /* event - open done */
|
|
}
|
|
break;
|
|
case 11: /* file close */
|
|
{
|
|
DBG("done %p", ev);
|
|
em_frame_done(ev);
|
|
DBG("stop %p", ev);
|
|
xine_stop(ev->stream);
|
|
DBG("close %p", ev);
|
|
xine_close(ev->stream);
|
|
DBG("close done %p", ev);
|
|
_em_module_event(ev, 11);
|
|
}
|
|
break;
|
|
case 4: /* play */
|
|
{
|
|
double pos;
|
|
int pos_stream, pos_time, length_time;
|
|
|
|
pos = *((double *)eev->xine_event);
|
|
if ((xine_get_param(ev->stream, XINE_PARAM_SPEED) == XINE_SPEED_PAUSE) &&
|
|
(pos == ev->pos) &&
|
|
(!ev->just_loaded))
|
|
{
|
|
xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
|
|
}
|
|
else
|
|
{
|
|
if (ev->no_time)
|
|
xine_play(ev->stream, pos * 65535, 0);
|
|
else
|
|
xine_play(ev->stream, 0, pos * 1000);
|
|
}
|
|
ev->just_loaded = 0;
|
|
|
|
if (xine_get_pos_length(ev->stream,
|
|
&pos_stream,
|
|
&pos_time,
|
|
&length_time))
|
|
{
|
|
if (length_time == 0)
|
|
{
|
|
ev->pos = (double)pos_stream / 65535;
|
|
ev->len = 1.0;
|
|
ev->no_time = 1;
|
|
}
|
|
else
|
|
{
|
|
ev->pos = (double)pos_time / 1000.0;
|
|
ev->len = (double)length_time / 1000.0;
|
|
}
|
|
}
|
|
_em_module_event(ev, 4);
|
|
}
|
|
break;
|
|
case 5: /* stop */
|
|
{
|
|
xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
|
|
_em_module_event(ev, 5);
|
|
}
|
|
break;
|
|
case 6: /* seek */
|
|
{
|
|
double pos;
|
|
|
|
pos = *((double *)eev->xine_event);
|
|
if (ev->no_time)
|
|
xine_play(ev->stream, pos * 65535, 0);
|
|
else
|
|
xine_play(ev->stream, 0, pos * 1000);
|
|
if (!ev->play)
|
|
xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
|
|
_em_module_event(ev, 6);
|
|
}
|
|
break;
|
|
case 7: /* eject */
|
|
{
|
|
xine_eject(ev->stream);
|
|
_em_module_event(ev, 7);
|
|
}
|
|
break;
|
|
case 8: /* spu mute */
|
|
{
|
|
xine_set_param(ev->stream, XINE_PARAM_IGNORE_SPU, ev->spu_mute);
|
|
_em_module_event(ev, 8);
|
|
}
|
|
break;
|
|
case 9: /* channel */
|
|
{
|
|
xine_set_param(ev->stream, XINE_PARAM_SPU_CHANNEL, ev->spu_channel);
|
|
_em_module_event(ev, 9);
|
|
}
|
|
break;
|
|
case 10: /* vol */
|
|
{
|
|
xine_set_param(ev->stream, XINE_PARAM_AUDIO_VOLUME, ev->volume * 100);
|
|
_em_module_event(ev, 10);
|
|
}
|
|
break;
|
|
case 12: /* audio mute */
|
|
{
|
|
xine_set_param(ev->stream, XINE_PARAM_AUDIO_MUTE, ev->audio_mute);
|
|
}
|
|
break;
|
|
case 13: /* audio mute */
|
|
{
|
|
xine_set_param(ev->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, ev->audio_channel);
|
|
}
|
|
break;
|
|
case 14: /* audio mute */
|
|
{
|
|
xine_set_param(ev->stream, XINE_PARAM_VIDEO_CHANNEL, ev->video_channel);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (eev->xine_event) free(eev->xine_event);
|
|
free(eev);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
static void
|
|
_em_slave_event(void *data, int type, void *arg)
|
|
{
|
|
void *buf[2];
|
|
Emotion_Xine_Event *new_ev;
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = data;
|
|
new_ev = calloc(1, sizeof(Emotion_Xine_Event));
|
|
if (!new_ev) return;
|
|
new_ev->mtype = type;
|
|
new_ev->type = -1;
|
|
new_ev->xine_event = arg;
|
|
buf[0] = data;
|
|
buf[1] = new_ev;
|
|
if (write(ev->fd_slave_write, buf, sizeof(buf)) < 0) perror("write");
|
|
}
|
|
|
|
static unsigned char
|
|
em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
int fds[2];
|
|
|
|
if (!emotion_video) return 0;
|
|
|
|
ev = calloc(1, sizeof(Emotion_Xine_Video));
|
|
if (!ev) return 0;
|
|
ev->obj = obj;
|
|
|
|
if (pipe(fds) == 0)
|
|
{
|
|
ev->fd_read = fds[0];
|
|
ev->fd_write = fds[1];
|
|
fcntl(ev->fd_read, F_SETFL, O_NONBLOCK);
|
|
ev->fd_handler = ecore_main_fd_handler_add(ev->fd_read, ECORE_FD_READ,
|
|
_em_fd_active, ev,
|
|
NULL, NULL);
|
|
ecore_main_fd_handler_active_set(ev->fd_handler, ECORE_FD_READ);
|
|
}
|
|
if (pipe(fds) == 0)
|
|
{
|
|
ev->fd_ev_read = fds[0];
|
|
ev->fd_ev_write = fds[1];
|
|
fcntl(ev->fd_ev_read, F_SETFL, O_NONBLOCK);
|
|
ev->fd_ev_handler = ecore_main_fd_handler_add(ev->fd_ev_read,
|
|
ECORE_FD_READ, _em_fd_ev_active, ev, NULL, NULL);
|
|
ecore_main_fd_handler_active_set(ev->fd_ev_handler, ECORE_FD_READ);
|
|
}
|
|
if (pipe(fds) == 0)
|
|
{
|
|
ev->fd_slave_read = fds[0];
|
|
ev->fd_slave_write = fds[1];
|
|
fcntl(ev->fd_slave_write, F_SETFL, O_NONBLOCK);
|
|
}
|
|
ev->volume = 0.8;
|
|
ev->delete_me = 0;
|
|
ev->get_pos_thread_deleted = 0;
|
|
ev->opening = 1;
|
|
ev->play_ok = 0;
|
|
|
|
if (opt)
|
|
{
|
|
ev->opt_no_audio = opt->no_audio;
|
|
ev->opt_no_video = opt->no_video;
|
|
}
|
|
|
|
pthread_cond_init(&(ev->get_pos_len_cond), NULL);
|
|
pthread_mutex_init(&(ev->get_pos_len_mutex), NULL);
|
|
pthread_create(&ev->get_pos_len_th, NULL, _em_get_pos_len_th, ev);
|
|
|
|
pthread_create(&ev->slave_th, NULL, _em_slave, ev);
|
|
pthread_detach(ev->slave_th);
|
|
_em_slave_event(ev, 1, NULL);
|
|
|
|
*emotion_video = ev;
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
em_shutdown(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
ev->closing = 1;
|
|
ev->delete_me = 1;
|
|
DBG("del fds %p", ev);
|
|
ecore_main_fd_handler_del(ev->fd_handler);
|
|
ev->fd_handler = NULL;
|
|
ecore_main_fd_handler_del(ev->fd_ev_handler);
|
|
ev->fd_ev_handler = NULL;
|
|
if (ev->anim)
|
|
{
|
|
ecore_animator_del(ev->anim);
|
|
ev->anim = NULL;
|
|
}
|
|
|
|
ev->closing = 1;
|
|
_em_slave_event(ev, 3, NULL);
|
|
DBG("done %p", ev);
|
|
return 1;
|
|
}
|
|
|
|
static unsigned char
|
|
em_file_open(const char *file, Evas_Object *obj __UNUSED__, void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (!ev) return 0;
|
|
_em_slave_event(ev, 2, strdup(file));
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
em_file_close(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (!ev) return;
|
|
_em_slave_event(ev, 11, NULL);
|
|
}
|
|
|
|
static void
|
|
em_play(void *ef, double pos)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
double *ppos;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
ev->play = 1;
|
|
ev->play_ok = 0;
|
|
ppos = malloc(sizeof(double));
|
|
*ppos = pos;
|
|
_em_slave_event(ev, 4, ppos);
|
|
}
|
|
|
|
static void
|
|
em_stop(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
ev->play = 0;
|
|
ev->play_ok = 0;
|
|
_em_slave_event(ev, 5, NULL);
|
|
}
|
|
|
|
static void
|
|
em_size_get(void *ef, int *w, int *h)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (w) *w = ev->w;
|
|
if (h) *h = ev->h;
|
|
}
|
|
|
|
static void
|
|
em_pos_set(void *ef, double pos)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
double *ppos;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
ppos = malloc(sizeof(double));
|
|
*ppos = pos;
|
|
_em_slave_event(ev, 6, ppos);
|
|
}
|
|
|
|
static double
|
|
em_len_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
return ev->len;
|
|
}
|
|
|
|
static int
|
|
em_fps_num_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
return (int)(ev->fps * 10000.0);
|
|
}
|
|
|
|
static int
|
|
em_fps_den_get(void *ef __UNUSED__)
|
|
{
|
|
return 10000;
|
|
}
|
|
|
|
static double
|
|
em_fps_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
return ev->fps;
|
|
}
|
|
|
|
static double
|
|
em_pos_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
_em_get_pos_len(ev);
|
|
return ev->pos;
|
|
}
|
|
|
|
static void
|
|
em_vis_set(void *ef, Emotion_Vis vis)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->vis == vis) return;
|
|
ev->vis = vis;
|
|
}
|
|
|
|
static Emotion_Vis
|
|
em_vis_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
|
|
return ev->vis;
|
|
}
|
|
|
|
static Eina_Bool
|
|
em_vis_supported(void *ef __UNUSED__, Emotion_Vis vis __UNUSED__)
|
|
{
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
static double
|
|
em_ratio_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
return ev->ratio;
|
|
}
|
|
|
|
static int
|
|
em_video_handled(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening || (!ev->play_ok)) return 0;
|
|
return (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO) &&
|
|
xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HANDLED));
|
|
}
|
|
|
|
static int
|
|
em_audio_handled(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening || (!ev->play_ok)) return 0;
|
|
return (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_AUDIO) &&
|
|
xine_get_stream_info(ev->stream, XINE_STREAM_INFO_AUDIO_HANDLED));
|
|
}
|
|
|
|
static int
|
|
em_seekable(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening || (!ev->play_ok)) return 0;
|
|
return xine_get_stream_info(ev->stream, XINE_STREAM_INFO_SEEKABLE);
|
|
}
|
|
|
|
static void
|
|
em_frame_done(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->cur_frame)
|
|
{
|
|
ev->fq--;
|
|
if (ev->cur_frame->done_func)
|
|
ev->cur_frame->done_func(ev->cur_frame->done_data);
|
|
ev->cur_frame = NULL;
|
|
}
|
|
}
|
|
|
|
static Emotion_Format
|
|
em_format_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
volatile Emotion_Xine_Video_Frame *fr;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
fr = ev->cur_frame;
|
|
if (fr) return fr->format;
|
|
return EMOTION_FORMAT_YV12;
|
|
}
|
|
|
|
static void
|
|
em_video_data_size_get(void *ef, int *w, int *h)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
volatile Emotion_Xine_Video_Frame *fr;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
fr = ev->cur_frame;
|
|
if (!fr)
|
|
{
|
|
if (w) *w = 0;
|
|
if (h) *h = 0;
|
|
return;
|
|
}
|
|
if (w) *w = fr->w;
|
|
if (h) *h = fr->h;
|
|
}
|
|
|
|
static int
|
|
em_yuv_rows_get(void *ef, int w __UNUSED__, int h, unsigned char **yrows, unsigned char **urows, unsigned char **vrows)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
volatile Emotion_Xine_Video_Frame *fr;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
fr = ev->cur_frame;
|
|
if (!fr) return 0;
|
|
if (fr->y)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < h; i++) yrows[i] = fr->y + (i * fr->y_stride);
|
|
for (i = 0; i < (h / 2); i++) urows[i] = fr->u + (i * fr->u_stride);
|
|
for (i = 0; i < (h / 2); i++) vrows[i] = fr->v + (i * fr->v_stride);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
em_bgra_data_get(void *ef, unsigned char **bgra_data)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
volatile Emotion_Xine_Video_Frame *fr;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
fr = ev->cur_frame;
|
|
if (!fr) return 0;
|
|
if (fr->bgra_data)
|
|
{
|
|
*bgra_data = fr->bgra_data;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
em_event_feed(void *ef, int event)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
xine_event_t xine_event;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if ((ev->opening) || (!ev->play_ok)) return;
|
|
xine_event.data_length = 0;
|
|
xine_event.data = NULL;
|
|
xine_event.stream = ev->stream;
|
|
gettimeofday(&xine_event.tv, NULL);
|
|
switch (event)
|
|
{
|
|
case EMOTION_EVENT_MENU1:
|
|
xine_event.type = XINE_EVENT_INPUT_MENU1;
|
|
break;
|
|
case EMOTION_EVENT_MENU2:
|
|
xine_event.type = XINE_EVENT_INPUT_MENU2;
|
|
break;
|
|
case EMOTION_EVENT_MENU3:
|
|
xine_event.type = XINE_EVENT_INPUT_MENU3;
|
|
break;
|
|
case EMOTION_EVENT_MENU4:
|
|
xine_event.type = XINE_EVENT_INPUT_MENU4;
|
|
break;
|
|
case EMOTION_EVENT_MENU5:
|
|
xine_event.type = XINE_EVENT_INPUT_MENU5;
|
|
break;
|
|
case EMOTION_EVENT_MENU6:
|
|
xine_event.type = XINE_EVENT_INPUT_MENU6;
|
|
break;
|
|
case EMOTION_EVENT_MENU7:
|
|
xine_event.type = XINE_EVENT_INPUT_MENU7;
|
|
break;
|
|
case EMOTION_EVENT_UP:
|
|
xine_event.type = XINE_EVENT_INPUT_UP;
|
|
break;
|
|
case EMOTION_EVENT_DOWN:
|
|
xine_event.type = XINE_EVENT_INPUT_DOWN;
|
|
break;
|
|
case EMOTION_EVENT_LEFT:
|
|
xine_event.type = XINE_EVENT_INPUT_LEFT;
|
|
break;
|
|
case EMOTION_EVENT_RIGHT:
|
|
xine_event.type = XINE_EVENT_INPUT_RIGHT;
|
|
break;
|
|
case EMOTION_EVENT_SELECT:
|
|
xine_event.type = XINE_EVENT_INPUT_SELECT;
|
|
break;
|
|
case EMOTION_EVENT_NEXT:
|
|
xine_event.type = XINE_EVENT_INPUT_NEXT;
|
|
break;
|
|
case EMOTION_EVENT_PREV:
|
|
xine_event.type = XINE_EVENT_INPUT_PREVIOUS;
|
|
break;
|
|
case EMOTION_EVENT_ANGLE_NEXT:
|
|
xine_event.type = XINE_EVENT_INPUT_ANGLE_NEXT;
|
|
break;
|
|
case EMOTION_EVENT_ANGLE_PREV:
|
|
xine_event.type = XINE_EVENT_INPUT_ANGLE_PREVIOUS;
|
|
break;
|
|
case EMOTION_EVENT_FORCE:
|
|
xine_event.type = XINE_EVENT_INPUT_BUTTON_FORCE;
|
|
break;
|
|
case EMOTION_EVENT_0:
|
|
xine_event.type = XINE_EVENT_INPUT_NUMBER_0;
|
|
break;
|
|
case EMOTION_EVENT_1:
|
|
xine_event.type = XINE_EVENT_INPUT_NUMBER_1;
|
|
break;
|
|
case EMOTION_EVENT_2:
|
|
xine_event.type = XINE_EVENT_INPUT_NUMBER_2;
|
|
break;
|
|
case EMOTION_EVENT_3:
|
|
xine_event.type = XINE_EVENT_INPUT_NUMBER_3;
|
|
break;
|
|
case EMOTION_EVENT_4:
|
|
xine_event.type = XINE_EVENT_INPUT_NUMBER_4;
|
|
break;
|
|
case EMOTION_EVENT_5:
|
|
xine_event.type = XINE_EVENT_INPUT_NUMBER_5;
|
|
break;
|
|
case EMOTION_EVENT_6:
|
|
xine_event.type = XINE_EVENT_INPUT_NUMBER_6;
|
|
break;
|
|
case EMOTION_EVENT_7:
|
|
xine_event.type = XINE_EVENT_INPUT_NUMBER_7;
|
|
break;
|
|
case EMOTION_EVENT_8:
|
|
xine_event.type = XINE_EVENT_INPUT_NUMBER_8;
|
|
break;
|
|
case EMOTION_EVENT_9:
|
|
xine_event.type = XINE_EVENT_INPUT_NUMBER_9;
|
|
break;
|
|
case EMOTION_EVENT_10:
|
|
xine_event.type = XINE_EVENT_INPUT_NUMBER_10_ADD;
|
|
break;
|
|
default:
|
|
return;
|
|
break;
|
|
}
|
|
xine_event_send(ev->stream, &xine_event);
|
|
}
|
|
|
|
static void
|
|
em_event_mouse_button_feed(void *ef, int button __UNUSED__, int x, int y)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
xine_event_t xine_event;
|
|
xine_input_data_t xine_input;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if ((ev->opening) || (!ev->play_ok)) return;
|
|
xine_event.stream = ev->stream;
|
|
gettimeofday(&xine_event.tv, NULL);
|
|
xine_event.type = XINE_EVENT_INPUT_MOUSE_BUTTON;
|
|
xine_input.button = 1;
|
|
xine_input.x = x;
|
|
xine_input.y = y;
|
|
xine_event.data = &xine_input;
|
|
xine_event.data_length = sizeof(xine_input);
|
|
xine_event_send(ev->stream, &xine_event);
|
|
}
|
|
|
|
static void
|
|
em_event_mouse_move_feed(void *ef, int x, int y)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
xine_event_t xine_event;
|
|
xine_input_data_t xine_input;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if ((ev->opening) || (!ev->play_ok)) return;
|
|
xine_event.stream = ev->stream;
|
|
gettimeofday(&xine_event.tv, NULL);
|
|
xine_event.type = XINE_EVENT_INPUT_MOUSE_MOVE;
|
|
xine_input.button = 0;
|
|
xine_input.x = x;
|
|
xine_input.y = y;
|
|
xine_event.data = &xine_input;
|
|
xine_event.data_length = sizeof(xine_input);
|
|
xine_event_send(ev->stream, &xine_event);
|
|
}
|
|
|
|
static int
|
|
em_video_channel_count(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
int v;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening || (!ev->play_ok)) return 0;
|
|
v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_CHANNELS);
|
|
if ((v < 1) &&
|
|
xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO)) return 1;
|
|
return v;
|
|
}
|
|
|
|
static void
|
|
em_video_channel_set(void *ef, int channel)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (channel < 0) channel = 0;
|
|
ev->video_channel = channel;
|
|
_em_slave_event(ev, 14, NULL);
|
|
}
|
|
|
|
static int
|
|
em_video_channel_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening || (!ev->play_ok)) return 0;
|
|
return xine_get_param(ev->stream, XINE_PARAM_VIDEO_CHANNEL);
|
|
}
|
|
|
|
static const char *
|
|
em_video_channel_name_get(void *ef __UNUSED__, int channel __UNUSED__)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
em_video_channel_mute_set(void *ef, int mute)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
ev->video_mute = mute;
|
|
}
|
|
|
|
static int
|
|
em_video_channel_mute_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
return ev->video_mute;
|
|
}
|
|
|
|
static int
|
|
em_audio_channel_count(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening || (!ev->play_ok)) return 0;
|
|
return xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
|
|
}
|
|
|
|
static void
|
|
em_audio_channel_set(void *ef, int channel)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (channel < -1) channel = -1;
|
|
ev->audio_channel = channel;
|
|
_em_slave_event(ev, 13, NULL);
|
|
}
|
|
|
|
static int
|
|
em_audio_channel_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening || (!ev->play_ok)) return 0;
|
|
return xine_get_param(ev->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
|
|
}
|
|
|
|
static const char *
|
|
em_audio_channel_name_get(void *ef, int channel)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
static char lang[XINE_LANG_MAX + 1];
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening) return NULL;
|
|
lang[0] = 0;
|
|
if (xine_get_audio_lang(ev->stream, channel, lang)) return lang;
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
em_audio_channel_mute_set(void *ef, int mute)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
ev->audio_mute = mute;
|
|
_em_slave_event(ev, 12, NULL);
|
|
}
|
|
|
|
static int
|
|
em_audio_channel_mute_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
return ev->audio_mute;
|
|
}
|
|
|
|
static void
|
|
em_audio_channel_volume_set(void *ef, double vol)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
if (vol < 0.0) vol = 0.0;
|
|
else if (vol > 1.0) vol = 1.0;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
ev->volume = vol;
|
|
_em_slave_event(ev, 10, NULL);
|
|
}
|
|
|
|
static double
|
|
em_audio_channel_volume_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening || (!ev->play_ok)) return ev->volume;
|
|
ev->volume = xine_get_param(ev->stream, XINE_PARAM_AUDIO_VOLUME) / 100.0;
|
|
return ev->volume;
|
|
}
|
|
|
|
static int
|
|
em_spu_channel_count(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening || (!ev->play_ok)) return 0;
|
|
return xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL);
|
|
}
|
|
|
|
static void
|
|
em_spu_channel_set(void *ef, int channel)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (channel < 0) channel = 0;
|
|
ev->spu_channel = channel;
|
|
_em_slave_event(ev, 9, NULL);
|
|
}
|
|
|
|
static int
|
|
em_spu_channel_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening || (!ev->play_ok)) return 0;
|
|
return xine_get_param(ev->stream, XINE_PARAM_SPU_CHANNEL);
|
|
}
|
|
|
|
static const char *
|
|
em_spu_channel_name_get(void *ef, int channel)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
static char lang[XINE_LANG_MAX + 1];
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening) return NULL;
|
|
lang[0] = 0;
|
|
if (xine_get_spu_lang(ev->stream, channel, lang)) return lang;
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
em_spu_channel_mute_set(void *ef, int mute)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
ev->spu_mute = mute;
|
|
_em_slave_event(ev, 8, NULL);
|
|
}
|
|
|
|
static int
|
|
em_spu_channel_mute_get(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
return ev->spu_mute;
|
|
}
|
|
|
|
static int
|
|
em_chapter_count(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if (ev->opening || (!ev->play_ok)) return 0;
|
|
if (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_CHAPTERS))
|
|
return 99;
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
em_chapter_set(void *ef __UNUSED__, int chapter __UNUSED__)
|
|
{
|
|
}
|
|
|
|
static int
|
|
em_chapter_get(void *ef __UNUSED__)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static const char *
|
|
em_chapter_name_get(void *ef __UNUSED__, int chapter __UNUSED__)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
em_speed_set(void *ef __UNUSED__, double speed __UNUSED__)
|
|
{
|
|
}
|
|
|
|
static double
|
|
em_speed_get(void *ef __UNUSED__)
|
|
{
|
|
return 1.0;
|
|
}
|
|
|
|
static int
|
|
em_eject(void *ef)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
_em_slave_event(ev, 7, NULL);
|
|
return 1;
|
|
}
|
|
|
|
static const char *
|
|
em_meta_get(void *ef, int meta)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)ef;
|
|
if ((ev->opening) || (!ev->play_ok)) return NULL;
|
|
switch (meta)
|
|
{
|
|
case META_TRACK_TITLE:
|
|
return xine_get_meta_info(ev->stream, XINE_META_INFO_TITLE);
|
|
break;
|
|
case META_TRACK_ARTIST:
|
|
return xine_get_meta_info(ev->stream, XINE_META_INFO_ARTIST);
|
|
break;
|
|
case META_TRACK_GENRE:
|
|
return xine_get_meta_info(ev->stream, XINE_META_INFO_GENRE);
|
|
break;
|
|
case META_TRACK_COMMENT:
|
|
return xine_get_meta_info(ev->stream, XINE_META_INFO_COMMENT);
|
|
break;
|
|
case META_TRACK_ALBUM:
|
|
return xine_get_meta_info(ev->stream, XINE_META_INFO_ALBUM);
|
|
break;
|
|
case META_TRACK_YEAR:
|
|
return xine_get_meta_info(ev->stream, XINE_META_INFO_YEAR);
|
|
break;
|
|
case META_TRACK_DISCID:
|
|
return xine_get_meta_info(ev->stream, XINE_META_INFO_CDINDEX_DISCID);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_em_fd_active(void *data, Ecore_Fd_Handler *fdh)
|
|
{
|
|
void *buf;
|
|
int fd, len;
|
|
Emotion_Xine_Video_Frame *fr;
|
|
|
|
fd = ecore_main_fd_handler_fd_get(fdh);
|
|
while ((len = read(fd, &buf, sizeof(buf))) > 0)
|
|
{
|
|
if (len == sizeof(buf))
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
fr = buf;
|
|
ev = _emotion_video_get(fr->obj);
|
|
if (ev)
|
|
{
|
|
em_frame_done(ev);
|
|
ev->cur_frame = fr;
|
|
_em_get_pos_len(ev);
|
|
if ((xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO)) &&
|
|
(xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HANDLED)))
|
|
{
|
|
if (ev->video_mute) em_frame_done(ev);
|
|
else _emotion_frame_new(fr->obj);
|
|
}
|
|
_emotion_frame_resize(fr->obj, fr->w, fr->h, fr->ratio);
|
|
_emotion_video_pos_update(fr->obj, ev->pos, ev->len);
|
|
}
|
|
}
|
|
}
|
|
return EINA_TRUE;
|
|
data = NULL;
|
|
}
|
|
|
|
static void
|
|
_em_event(void *data, const xine_event_t *event)
|
|
{
|
|
void *buf[2];
|
|
Emotion_Xine_Event *new_ev;
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = data;
|
|
new_ev = calloc(1, sizeof(Emotion_Xine_Event));
|
|
if (!new_ev) return;
|
|
new_ev->mtype = 0;
|
|
new_ev->type = event->type;
|
|
if (event->data)
|
|
{
|
|
new_ev->xine_event = malloc(event->data_length);
|
|
if (!new_ev->xine_event)
|
|
{
|
|
free(new_ev);
|
|
return;
|
|
}
|
|
memcpy(new_ev->xine_event, event->data, event->data_length);
|
|
}
|
|
buf[0] = data;
|
|
buf[1] = new_ev;
|
|
if (write(ev->fd_ev_write, buf, sizeof(buf)) < 0) perror("write");
|
|
}
|
|
|
|
static void
|
|
_em_module_event(void *data, int type)
|
|
{
|
|
void *buf[2];
|
|
Emotion_Xine_Event *new_ev;
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = data;
|
|
new_ev = calloc(1, sizeof(Emotion_Xine_Event));
|
|
if (!new_ev) return;
|
|
new_ev->mtype = type;
|
|
new_ev->type = -1;
|
|
buf[0] = data;
|
|
buf[1] = new_ev;
|
|
if (write(ev->fd_ev_write, buf, sizeof(buf)) < 0) perror("write");
|
|
}
|
|
|
|
static Eina_Bool
|
|
_em_audio_only_poller(void *data)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = data;
|
|
_em_get_pos_len(ev);
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_em_fd_ev_active(void *data __UNUSED__, Ecore_Fd_Handler *fdh)
|
|
{
|
|
int fd, len;
|
|
void *buf[2];
|
|
|
|
fd = ecore_main_fd_handler_fd_get(fdh);
|
|
while ((len = read(fd, buf, sizeof(buf))) > 0)
|
|
{
|
|
if (len == sizeof(buf))
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
Emotion_Xine_Event *eev;
|
|
|
|
ev = buf[0];
|
|
eev = buf[1];
|
|
if (eev->mtype != 0)
|
|
{
|
|
switch (eev->mtype)
|
|
{
|
|
case 1: /* init done */
|
|
ev->play_ok = 1;
|
|
break;
|
|
case 2: /* open done */
|
|
ev->play_ok = 1;
|
|
if (ev->anim)
|
|
{
|
|
ecore_animator_del(ev->anim);
|
|
ev->anim = NULL;
|
|
}
|
|
_emotion_open_done(ev->obj);
|
|
_emotion_frame_resize(ev->obj, ev->w, ev->h, ev->ratio);
|
|
break;
|
|
case 3: /* shutdown done */
|
|
if (ev->anim)
|
|
{
|
|
ecore_animator_del(ev->anim);
|
|
ev->anim = NULL;
|
|
}
|
|
ev->play_ok = 1;
|
|
break;
|
|
case 4: /* play done */
|
|
ev->play_ok = 1;
|
|
if (ev->anim)
|
|
{
|
|
ecore_animator_del(ev->anim);
|
|
ev->anim = NULL;
|
|
}
|
|
if ((!(xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO) &&
|
|
xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HANDLED))) &&
|
|
(xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_AUDIO) &&
|
|
xine_get_stream_info(ev->stream, XINE_STREAM_INFO_AUDIO_HANDLED)))
|
|
ev->anim = ecore_animator_add(_em_audio_only_poller, ev);
|
|
_emotion_playback_started(ev->obj);
|
|
break;
|
|
case 5: /* stop done */
|
|
if (ev->anim)
|
|
{
|
|
ecore_animator_del(ev->anim);
|
|
ev->anim = NULL;
|
|
}
|
|
ev->play_ok = 1;
|
|
break;
|
|
case 6: /* seek done */
|
|
ev->play_ok = 1;
|
|
_emotion_seek_done(ev->obj);
|
|
_em_get_pos_len(ev);
|
|
_emotion_video_pos_update(ev->obj, ev->pos, ev->len);
|
|
break;
|
|
case 7: /* eject done */
|
|
if (ev->anim)
|
|
{
|
|
ecore_animator_del(ev->anim);
|
|
ev->anim = NULL;
|
|
}
|
|
ev->play_ok = 1;
|
|
break;
|
|
case 8: /* spu mute done */
|
|
ev->play_ok = 1;
|
|
break;
|
|
case 9: /* channel done */
|
|
ev->play_ok = 1;
|
|
break;
|
|
case 10: /* volume done */
|
|
ev->play_ok = 1;
|
|
break;
|
|
case 11: /* close done */
|
|
if (ev->anim)
|
|
{
|
|
ecore_animator_del(ev->anim);
|
|
ev->anim = NULL;
|
|
}
|
|
ev->play_ok = 1;
|
|
break;
|
|
case 15: /* get pos done */
|
|
if (ev->last_pos != ev->pos)
|
|
{
|
|
ev->last_pos = ev->pos;
|
|
_emotion_video_pos_update(ev->obj, ev->pos, ev->len);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (eev->type)
|
|
{
|
|
case XINE_EVENT_UI_PLAYBACK_FINISHED:
|
|
{
|
|
ev->play = 0;
|
|
_emotion_decode_stop(ev->obj);
|
|
_emotion_playback_finished(ev->obj);
|
|
}
|
|
break;
|
|
case XINE_EVENT_UI_CHANNELS_CHANGED:
|
|
{
|
|
_emotion_channels_change(ev->obj);
|
|
}
|
|
break;
|
|
case XINE_EVENT_UI_SET_TITLE:
|
|
{
|
|
xine_ui_data_t *e;
|
|
|
|
e = (xine_ui_data_t *)eev->xine_event;
|
|
_emotion_title_set(ev->obj, e->str);
|
|
}
|
|
break;
|
|
case XINE_EVENT_FRAME_FORMAT_CHANGE:
|
|
break;
|
|
case XINE_EVENT_UI_MESSAGE:
|
|
{
|
|
WRN("UI Message [FIXME: break this out to emotion api]");
|
|
// e->type = error type(XINE_MSG_NO_ERROR, XINE_MSG_GENERAL_WARNING, XINE_MSG_UNKNOWN_HOST etc.)
|
|
// e->messages is a list of messages DOUBLE null terminated
|
|
}
|
|
break;
|
|
case XINE_EVENT_AUDIO_LEVEL:
|
|
{
|
|
_emotion_audio_level_change(ev->obj);
|
|
WRN("Audio Level [FIXME: break this out to emotion api]");
|
|
// e->left (0->100)
|
|
// e->right
|
|
// e->mute
|
|
}
|
|
break;
|
|
case XINE_EVENT_PROGRESS:
|
|
{
|
|
xine_progress_data_t *e;
|
|
|
|
e = (xine_progress_data_t *)eev->xine_event;
|
|
DBG("PROGRESS: %i", e->percent);
|
|
_emotion_progress_set(ev->obj, (char *)e->description, (double)e->percent / 100.0);
|
|
}
|
|
break;
|
|
case XINE_EVENT_MRL_REFERENCE_EXT:
|
|
{
|
|
xine_mrl_reference_data_ext_t *e;
|
|
|
|
e = (xine_mrl_reference_data_ext_t *)eev->xine_event;
|
|
_emotion_file_ref_set(ev->obj, e->mrl, e->alternative);
|
|
}
|
|
break;
|
|
case XINE_EVENT_UI_NUM_BUTTONS:
|
|
{
|
|
xine_ui_data_t *e;
|
|
|
|
e = (xine_ui_data_t *)eev->xine_event;
|
|
_emotion_spu_button_num_set(ev->obj, e->num_buttons);
|
|
}
|
|
break;
|
|
case XINE_EVENT_SPU_BUTTON:
|
|
{
|
|
xine_spu_button_t *e;
|
|
|
|
e = (xine_spu_button_t *)eev->xine_event;
|
|
if (e->direction == 1)
|
|
_emotion_spu_button_set(ev->obj, e->button);
|
|
else
|
|
_emotion_spu_button_set(ev->obj, -1);
|
|
}
|
|
break;
|
|
case XINE_EVENT_DROPPED_FRAMES:
|
|
{
|
|
xine_dropped_frames_t *e;
|
|
|
|
e = (xine_dropped_frames_t *)eev->xine_event;
|
|
WRN("Dropped Frames (skipped %i) (discarded %i) [FIXME: break this out to the emotion api]", e->skipped_frames, e->discarded_frames);
|
|
// e->skipped_frames = % frames skipped * 10
|
|
// e->discarded_frames = % frames skipped * 10
|
|
}
|
|
break;
|
|
default:
|
|
// DBG("unknown event type %i", eev->type);
|
|
break;
|
|
}
|
|
}
|
|
if (eev->xine_event) free(eev->xine_event);
|
|
free(eev);
|
|
}
|
|
}
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static void *
|
|
_em_get_pos_len_th(void *par)
|
|
{
|
|
Emotion_Xine_Video *ev;
|
|
|
|
ev = (Emotion_Xine_Video *)par;
|
|
|
|
for (;;)
|
|
{
|
|
pthread_mutex_lock(&(ev->get_pos_len_mutex));
|
|
pthread_cond_wait(&(ev->get_pos_len_cond), &(ev->get_pos_len_mutex));
|
|
pthread_mutex_unlock(&(ev->get_pos_len_mutex));
|
|
if (ev->get_poslen)
|
|
{
|
|
int pos_stream = 0;
|
|
int pos_time = 0;
|
|
int length_time = 0;
|
|
|
|
if (xine_get_pos_length(ev->stream, &pos_stream, &pos_time, &length_time))
|
|
{
|
|
if (length_time == 0)
|
|
{
|
|
ev->pos = (double)pos_stream / 65535;
|
|
ev->len = 1.0;
|
|
ev->no_time = 1;
|
|
}
|
|
else
|
|
{
|
|
ev->pos = (double)pos_time / 1000.0;
|
|
ev->len = (double)length_time / 1000.0;
|
|
ev->no_time = 0;
|
|
}
|
|
}
|
|
ev->get_poslen = 0;
|
|
_em_module_event(ev, 15); /* event - getpos done */
|
|
//DBG("get pos %3.3f", ev->pos);
|
|
}
|
|
if (ev->delete_me)
|
|
{
|
|
ev->get_pos_thread_deleted = 1;
|
|
return NULL;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
_em_get_pos_len(Emotion_Xine_Video *ev)
|
|
{
|
|
if (!ev->play_ok) return;
|
|
ev->get_poslen = 1;
|
|
pthread_mutex_lock(&(ev->get_pos_len_mutex));
|
|
pthread_cond_broadcast(&(ev->get_pos_len_cond));
|
|
pthread_mutex_unlock(&(ev->get_pos_len_mutex));
|
|
}
|
|
|
|
static Emotion_Video_Module em_module =
|
|
{
|
|
em_init, /* init */
|
|
em_shutdown, /* shutdown */
|
|
em_file_open, /* file_open */
|
|
em_file_close, /* file_close */
|
|
em_play, /* play */
|
|
em_stop, /* stop */
|
|
em_size_get, /* size_get */
|
|
em_pos_set, /* pos_set */
|
|
em_len_get, /* len_get */
|
|
em_fps_num_get, /* fps_num_get */
|
|
em_fps_den_get, /* fps_den_get */
|
|
em_fps_get, /* fps_get */
|
|
em_pos_get, /* pos_get */
|
|
em_vis_set, /* vis_set */
|
|
em_vis_get, /* vis_get */
|
|
em_vis_supported, /* vis_supported */
|
|
em_ratio_get, /* ratio_get */
|
|
em_video_handled, /* video_handled */
|
|
em_audio_handled, /* audio_handled */
|
|
em_seekable, /* seekable */
|
|
em_frame_done, /* frame_done */
|
|
em_format_get, /* format_get */
|
|
em_video_data_size_get, /* video_data_size_get */
|
|
em_yuv_rows_get, /* yuv_rows_get */
|
|
em_bgra_data_get, /* bgra_data_get */
|
|
em_event_feed, /* event_feed */
|
|
em_event_mouse_button_feed, /* event_mouse_button_feed */
|
|
em_event_mouse_move_feed, /* event_mouse_move_feed */
|
|
em_video_channel_count, /* video_channel_count */
|
|
em_video_channel_set, /* video_channel_set */
|
|
em_video_channel_get, /* video_channel_get */
|
|
em_video_channel_name_get, /* video_channel_name_get */
|
|
em_video_channel_mute_set, /* video_channel_mute_set */
|
|
em_video_channel_mute_get, /* video_channel_mute_get */
|
|
em_audio_channel_count, /* audio_channel_count */
|
|
em_audio_channel_set, /* audio_channel_set */
|
|
em_audio_channel_get, /* audio_channel_get */
|
|
em_audio_channel_name_get, /* audio_channel_name_get */
|
|
em_audio_channel_mute_set, /* audio_channel_mute_set */
|
|
em_audio_channel_mute_get, /* audio_channel_mute_get */
|
|
em_audio_channel_volume_set, /* audio_channel_volume_set */
|
|
em_audio_channel_volume_get, /* audio_channel_volume_get */
|
|
em_spu_channel_count, /* spu_channel_count */
|
|
em_spu_channel_set, /* spu_channel_set */
|
|
em_spu_channel_get, /* spu_channel_get */
|
|
em_spu_channel_name_get, /* spu_channel_name_get */
|
|
em_spu_channel_mute_set, /* spu_channel_mute_set */
|
|
em_spu_channel_mute_get, /* spu_channel_mute_get */
|
|
em_chapter_count, /* chapter_count */
|
|
em_chapter_set, /* chapter_set */
|
|
em_chapter_get, /* chapter_get */
|
|
em_chapter_name_get, /* chapter_name_get */
|
|
em_speed_set, /* speed_set */
|
|
em_speed_get, /* speed_get */
|
|
em_eject, /* eject */
|
|
em_meta_get, /* meta_get */
|
|
NULL, /* priority_set */
|
|
NULL, /* priority_get */
|
|
NULL /* handle */
|
|
};
|
|
|
|
static Eina_Bool
|
|
module_open(Evas_Object *obj, const Emotion_Video_Module **module, void **video, Emotion_Module_Options *opt)
|
|
{
|
|
if (!module)
|
|
return EINA_FALSE;
|
|
|
|
if (_emotion_xine_log_domain < 0)
|
|
{
|
|
eina_threads_init();
|
|
eina_log_threads_enable();
|
|
_emotion_xine_log_domain = eina_log_domain_register
|
|
("emotion-xine", EINA_COLOR_LIGHTCYAN);
|
|
if (_emotion_xine_log_domain < 0)
|
|
{
|
|
EINA_LOG_CRIT("Could not register log domain 'emotion-xine'");
|
|
return EINA_FALSE;
|
|
}
|
|
}
|
|
|
|
if (!em_module.init(obj, video, opt))
|
|
return EINA_FALSE;
|
|
|
|
*module = &em_module;
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static void
|
|
module_close(Emotion_Video_Module *module __UNUSED__, void *video)
|
|
{
|
|
em_module.shutdown(video);
|
|
}
|
|
|
|
Eina_Bool
|
|
xine_module_init(void)
|
|
{
|
|
return _emotion_module_register("xine", module_open, module_close);
|
|
}
|
|
|
|
void
|
|
xine_module_shutdown(void)
|
|
{
|
|
_emotion_module_unregister("xine");
|
|
}
|
|
|
|
#ifndef EMOTION_STATIC_BUILD_XINE
|
|
|
|
EINA_MODULE_INIT(xine_module_init);
|
|
EINA_MODULE_SHUTDOWN(xine_module_shutdown);
|
|
|
|
#endif
|
|
|
|
#if 0
|
|
void
|
|
em_debug(Emotion_Xine_Video *ev)
|
|
{
|
|
int has_chapters = 0;
|
|
int max_spu = 0;
|
|
int max_audio = 0;
|
|
int video_channels = 0;
|
|
int video_streams = 0;
|
|
int video_seekable = 0;
|
|
char *title;
|
|
char *comment;
|
|
char *artist;
|
|
char *genre;
|
|
char *album;
|
|
char *year;
|
|
char *cdindex_discid;
|
|
int video_channel = 0;
|
|
int audio_channel = 0;
|
|
int spu_channel = 0;
|
|
int video_ratio = 0;
|
|
int audio_mode = 0;
|
|
|
|
// return;
|
|
has_chapters = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_CHAPTERS);
|
|
max_spu = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL);
|
|
max_audio = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
|
|
video_channels = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_CHANNELS);
|
|
video_streams = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_STREAMS);
|
|
video_seekable = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_SEEKABLE);
|
|
title = xine_get_meta_info(ev->stream, XINE_META_INFO_TITLE);
|
|
comment = xine_get_meta_info(ev->stream, XINE_META_INFO_COMMENT);
|
|
artist = xine_get_meta_info(ev->stream, XINE_META_INFO_ARTIST);
|
|
genre = xine_get_meta_info(ev->stream, XINE_META_INFO_GENRE);
|
|
album = xine_get_meta_info(ev->stream, XINE_META_INFO_ALBUM);
|
|
year = xine_get_meta_info(ev->stream, XINE_META_INFO_YEAR);
|
|
cdindex_discid = xine_get_meta_info(ev->stream, XINE_META_INFO_CDINDEX_DISCID);
|
|
video_channel = xine_get_param(ev->stream, XINE_PARAM_VIDEO_CHANNEL);
|
|
audio_channel = xine_get_param(ev->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
|
|
spu_channel = xine_get_param(ev->stream, XINE_PARAM_SPU_CHANNEL);
|
|
video_ratio = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_RATIO);
|
|
audio_mode = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_AUDIO_MODE);
|
|
DBG("has_chapters = %i", has_chapters);
|
|
DBG("max_spu = %i", max_spu);
|
|
DBG("max_audio = %i", max_audio);
|
|
DBG("video_channels = %i", video_channels);
|
|
DBG("video_streams = %i", video_streams);
|
|
DBG("video_seekable = %i", video_seekable);
|
|
DBG("title = %s", title);
|
|
DBG("comment = %s", comment);
|
|
DBG("artist = %s", artist);
|
|
DBG("genre = %s", genre);
|
|
DBG("album = %s", album);
|
|
DBG("year = %s", year);
|
|
DBG("cdindex_discid = %s", cdindex_discid);
|
|
DBG("video_channel = %i", video_channel);
|
|
DBG("audio_channel = %i", audio_channel);
|
|
DBG("spu_channels = %i", spu_channel);
|
|
DBG("video_ratio = %i", video_ratio);
|
|
DBG("audio_mode = %i", audio_mode);
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i <= max_audio; i++)
|
|
{
|
|
char lang[XINE_LANG_MAX + 1];
|
|
char buf[128] = "NONE";
|
|
|
|
lang[0] = 0;
|
|
if (xine_get_audio_lang(ev->stream, i, lang))
|
|
eina_strlcpy(buf, lang, sizeof(buf));
|
|
DBG(" AUDIO %i = %s", i, buf);
|
|
}
|
|
for (i = 0; i <= max_spu; i++)
|
|
{
|
|
char lang[XINE_LANG_MAX + 1];
|
|
char buf[128] = "NONE";
|
|
|
|
lang[0] = 0;
|
|
if (xine_get_spu_lang(ev->stream, i, lang))
|
|
eina_strlcpy(buf, lang, sizeof(buf));
|
|
DBG(" SPU %i = %s", i, buf);
|
|
}
|
|
}
|
|
}
|
|
#endif
|