続々 xine

サンプルソース

#include <sys/param.h>
#include <sys/stat.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/extensions/XShm.h>

#include <xine.h>
#include <xine/xineutils.h>

#define SCREEN_WIDTH    640
#define SCREEN_HEIGHT   480

struct wininfo {
    int x, y;
    int width, height;
    double aspect;
};

static int running = 0;


static void
dest_size_cb(void *user_data,
             int video_width, int video_height, double video_pixel_aspect,
             int *dest_width, int *dest_height, double *dest_pixel_aspect)
{
    struct wininfo *wi = (struct wininfo *)user_data;

    (void)video_width;
    (void)video_height;
    (void)video_pixel_aspect;

    *dest_width = wi->width;
    *dest_height = wi->height;
    *dest_pixel_aspect = wi->aspect;
}

static void
frame_output_cb(void *user_data,
                int video_width, int video_height, double video_pixel_aspect,
                int *dest_x, int *dest_y,
                int *dest_width, int *dest_height, double *dest_pixel_aspect,
                int *win_x, int *win_y)
{
    struct wininfo *wi = (struct wininfo *)user_data;

    (void)video_width;
    (void)video_height;
    (void)video_pixel_aspect;

    *dest_x = 0;
    *dest_y = 0;
    *win_x = wi->x;
    *win_y = wi->y;
    *dest_width = wi->width;
    *dest_height = wi->height;
    *dest_pixel_aspect = wi->aspect;
}

static void
xine_event_handler(void *user_data, const xine_event_t *event)
{

    (void)user_data;

    switch (event->type) { 
    case XINE_EVENT_UI_PLAYBACK_FINISHED:
        running = 0;
        break;
    }
}


static char *progname;

static void
usage(void)
{

    fprintf(stderr, "Usage: %s [filename]\n", progname);

    exit(1);
}

int
main(int argc, char *argv[])
{
    /* xine */
    xine_t *xine;
    xine_video_port_t *video_port;
    xine_audio_port_t *audio_port;
    xine_stream_t *stream;
    xine_event_queue_t *evqueue;
    x11_visual_t visual;
    char config_path[MAXPATHLEN];

    /* X11 */
    Display *display;
    int screen;
    Window window, root_window, child_window;
    Atom proto, delwin;
    XEvent ev;
    KeySym ksym;
    XWindowAttributes attr;
    XSizeHints size;
    unsigned int width, height, border, depth;
    int x, y;
    int shmcomptype;

    /* misc */
    struct stat sb;
    struct wininfo wininfo;

    progname = argv[0];

    if ((argc < 2) || (stat(argv[1], &sb) < 0) || !S_ISREG(sb.st_mode)) {
        usage();
    }

    XInitThreads();

    display = XOpenDisplay(NULL);
    if (display == NULL) {
        fprintf(stderr, "Error: Can't open display\n");
        exit(1);
    }

    screen = DefaultScreen(display);
    window = XCreateSimpleWindow(display, DefaultRootWindow(display),
        0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0,
        WhitePixel(display, screen), BlackPixel(display, screen));

    size.flags = PMinSize | PMaxSize;
    size.min_width = SCREEN_WIDTH;
    size.min_height = SCREEN_HEIGHT;
    size.max_width = SCREEN_WIDTH;
    size.max_height = SCREEN_HEIGHT;
    XSetNormalHints(display, window, &size);
    XStoreName(display, window, argv[1]);

    proto = XInternAtom(display, "WM_PROTOCOLS", 0);
    delwin = XInternAtom(display, "WM_DELETE_WINDOW", 0);
    XSetWMProtocols(display, window, &delwin, 1);

    XSelectInput(display, window, KeyPressMask|ButtonPressMask|ExposureMask|StructureNotifyMask);

    if (XShmQueryExtension(display))
        shmcomptype = XShmGetEventBase(display) + ShmCompletion;
    else
        shmcomptype = -1;

    XMapRaised(display, window);
    XSync(display, False);

    XGetGeometry(display, window, &root_window, &x, &y, &width, &height, &border, &depth);
    XGetWindowAttributes(display, window, &attr);
    XTranslateCoordinates(display, window, attr.root, 0, 0, &x, &y, &child_window);

    memset(&visual, 0, sizeof(visual));
    visual.display = display;
    visual.screen = screen;
    visual.d = window;
    visual.dest_size_cb = dest_size_cb;
    visual.frame_output_cb = frame_output_cb;
    visual.user_data = &wininfo;

    wininfo.x = x;
    wininfo.y = y;
    wininfo.width = width;
    wininfo.height = height;
    wininfo.aspect = 1.0;    /* XXX */

    xine = xine_new();
    snprintf(config_path, sizeof(config_path), "%s/.xine/config", xine_get_homedir());
    xine_config_load(xine, config_path);
    xine_init(xine);

    video_port = xine_open_video_driver(xine, NULL, XINE_VISUAL_TYPE_X11, &visual);
    audio_port = xine_open_audio_driver(xine, NULL, NULL);
    stream = xine_stream_new(xine, audio_port, video_port);
    evqueue = xine_event_new_queue(stream);
    xine_event_create_listener_thread(evqueue, xine_event_handler, NULL);
    xine_port_send_gui_data(video_port, XINE_GUI_SEND_DRAWABLE_CHANGED, (void *)window);
    xine_port_send_gui_data(video_port, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *)1);

    running = 1;
    if (!xine_open(stream, argv[1]) || (!xine_play(stream, 0, 0)))
        running = 0;

    while (running) {
        if (XPending(display) > 0) {
            XNextEvent(display, &ev);
            switch (ev.type) {
            case Expose:
                if ((ev.xexpose.count == 0) && (ev.xexpose.window == window)) {
                    xine_gui_send_vo_data(stream, XINE_GUI_SEND_EXPOSE_EVENT, &ev);
                }
                break;

            case KeyPress:
                ksym = XLookupKeysym(&ev.xkey, 0);
                switch (ksym) {
                case XK_q:
                case XK_Q:
                case XK_space:
                case XK_Escape:
                case XK_Return:
                case XK_KP_Enter:
                    running = 0;
                    break;
                }
                break;

            case ButtonPress:
                switch (ev.xbutton.button) {
                case 1:
                case 2:
                case 3:
                    running = 0;
                    break;
                }
                break;

            case ConfigureNotify:
                if ((ev.xconfigure.x == 0) && (ev.xconfigure.y == 0)) {
                    XLockDisplay(display);
                    XGetWindowAttributes(display, ev.xconfigure.window, &attr);
                    XTranslateCoordinates(display, ev.xconfigure.window, attr.root, 0, 0, &x, &y, &child_window);
                    XUnlockDisplay(display);
                    wininfo.x = x;
                    wininfo.y = y;
                } else {
                    wininfo.x = ev.xconfigure.x;
                    wininfo.y = ev.xconfigure.y;
                }
                wininfo.width = ev.xconfigure.width;
                wininfo.height = ev.xconfigure.height;
                break;

            case ClientMessage:
                if ((ev.xclient.message_type == proto) && ((Atom)ev.xclient.data.l[0] == delwin)) {
                    running = 0;
                }
                break;

            default:
                if (ev.type == shmcomptype) {
                    xine_gui_send_vo_data(stream, XINE_GUI_SEND_COMPLETION_EVENT, &ev);
                }
                break;
            }
        } else {
            usleep(1);
        }
    }

    xine_close(stream);
    xine_event_dispose_queue(evqueue);
    xine_dispose(stream);
    xine_close_audio_driver(xine, audio_port);  
    xine_close_video_driver(xine, video_port);  
    xine_exit(xine);

    XUnmapWindow(display, window);
    XDestroyWindow(display, window);
    XCloseDisplay(display);

    return 0;
}