Beispiel #1
0
/*****************************************************************************
 * Close the current file and open another
 *****************************************************************************/
static bool SwitchFile( access_t *p_access, unsigned i_file )
{
    access_sys_t *p_sys = p_access->p_sys;

    /* requested file already open? */
    if( p_sys->fd != -1 && p_sys->i_current_file == i_file )
        return true;

    /* close old file */
    if( p_sys->fd != -1 )
    {
        vlc_close( p_sys->fd );
        p_sys->fd = -1;
    }

    /* switch */
    if( i_file >= FILE_COUNT )
        return false;
    p_sys->i_current_file = i_file;

    /* open new file */
    char *psz_path = GetFilePath( p_access, i_file );
    if( !psz_path )
        return false;
    p_sys->fd = vlc_open( psz_path, O_RDONLY );

    if( p_sys->fd == -1 )
    {
        msg_Err( p_access, "Failed to open %s: %s", psz_path,
                 vlc_strerror_c(errno) );
        goto error;
    }

    /* cannot handle anything except normal files */
    struct stat st;
    if( fstat( p_sys->fd, &st ) || !S_ISREG( st.st_mode ) )
    {
        msg_Err( p_access, "%s is not a regular file", psz_path );
        goto error;
    }

    OptimizeForRead( p_sys->fd );

    msg_Dbg( p_access, "opened %s", psz_path );
    free( psz_path );
    return true;

error:
    vlc_dialog_display_error (p_access, _("File reading failed"), _("VLC could not"
        " open the file \"%s\" (%s)."), psz_path, vlc_strerror(errno) );
    if( p_sys->fd != -1 )
    {
        vlc_close( p_sys->fd );
        p_sys->fd = -1;
    }
    free( psz_path );
    return false;
}
Beispiel #2
0
static void vlc_poll_i11e_cleanup(void *opaque)
{
    vlc_interrupt_t *ctx = opaque;
    int *fd = ctx->data;

    vlc_interrupt_finish(ctx);
    if (fd[1] != fd[0])
        vlc_close(fd[1]);
    vlc_close(fd[0]);
}
Beispiel #3
0
int tar_open( TAR **t, char *pathname, int oflags )
{
    (void)oflags;

    int fd = vlc_open( pathname, O_BINARY | O_RDONLY );
    if( fd == -1 )
    {
        fprintf( stderr, "Couldn't open %s\n", pathname );
        return -1;
    }
    gzFile f = gzdopen( fd, "rb" );
    if( f == NULL )
    {
        fprintf( stderr, "Couldn't gzopen %s\n", pathname );
        vlc_close( fd );
        return -1;
    }

    *t = (gzFile *)malloc( sizeof(gzFile) );
    if( *t == NULL )
    {
        gzclose( f );
        return -1;
    }
    **t = f;
    return 0;
}
Beispiel #4
0
Datei: cdrom.c Projekt: Geal/vlc
/*****************************************************************************
 * ioctl_Close: Closes an already opened VCD device or file.
 *****************************************************************************/
void ioctl_Close( vlc_object_t * p_this, vcddev_t *p_vcddev )
{
    free( p_vcddev->psz_dev );

    if( p_vcddev->i_vcdimage_handle != -1 )
    {
        /*
         *  vcd image mode
         */

        CloseVCDImage( p_this, p_vcddev );
        return;
    }

    /*
     *  vcd device mode
     */

#ifdef _WIN32
    if( p_vcddev->h_device_handle )
        CloseHandle( p_vcddev->h_device_handle );
#elif defined( __OS2__ )
    if( p_vcddev->hcd )
        DosClose( p_vcddev->hcd );
#else
    if( p_vcddev->i_device_handle != -1 )
        vlc_close( p_vcddev->i_device_handle );
#endif
    free( p_vcddev );
}
Beispiel #5
0
Datei: dbus.c Projekt: etix/vlc
static void Close   ( vlc_object_t *p_this )
{
    intf_thread_t   *p_intf     = (intf_thread_t*) p_this;
    intf_sys_t      *p_sys      = p_intf->p_sys;
    playlist_t      *p_playlist = p_sys->p_playlist;

    vlc_cancel( p_sys->thread );
    vlc_join( p_sys->thread, NULL );

    var_DelCallback( p_playlist, "input-current", AllCallback, p_intf );
    var_DelCallback( p_playlist, "volume", AllCallback, p_intf );
    var_DelCallback( p_playlist, "mute", AllCallback, p_intf );
    var_DelCallback( p_playlist, "playlist-item-append", AllCallback, p_intf );
    var_DelCallback( p_playlist, "playlist-item-deleted", AllCallback, p_intf );
    var_DelCallback( p_playlist, "random", AllCallback, p_intf );
    var_DelCallback( p_playlist, "repeat", AllCallback, p_intf );
    var_DelCallback( p_playlist, "loop", AllCallback, p_intf );
    var_DelCallback( p_playlist, "fullscreen", AllCallback, p_intf );

    if( p_sys->p_input )
    {
        var_DelCallback( p_sys->p_input, "intf-event", InputCallback, p_intf );
        var_DelCallback( p_sys->p_input, "can-pause", AllCallback, p_intf );
        var_DelCallback( p_sys->p_input, "can-seek", AllCallback, p_intf );
        vlc_object_release( p_sys->p_input );
    }

    /* The dbus connection is private, so we are responsible
     * for closing it */
    dbus_connection_close( p_sys->p_conn );
    dbus_connection_unref( p_sys->p_conn );

    // Free the events array
    for( int i = 0; i < vlc_array_count( p_sys->p_events ); i++ )
    {
        callback_info_t* info = vlc_array_item_at_index( p_sys->p_events, i );
        free( info );
    }
    vlc_mutex_destroy( &p_sys->lock );
    vlc_array_destroy( p_sys->p_events );
    vlc_array_destroy( p_sys->p_timeouts );
    vlc_array_destroy( p_sys->p_watches );
    vlc_close( p_sys->p_pipe_fds[1] );
    vlc_close( p_sys->p_pipe_fds[0] );
    free( p_sys );
}
Beispiel #6
0
void dvb_close (dvb_device_t *d)
{
#ifndef USE_DMX
    if (!d->budget)
    {
        for (size_t i = 0; i < MAX_PIDS; i++)
            if (d->pids[i].fd != -1)
                vlc_close (d->pids[i].fd);
    }
#endif
    if (d->cam != NULL)
        en50221_End (d->cam);
    if (d->frontend != -1)
        vlc_close (d->frontend);
    vlc_close (d->demux);
    vlc_close (d->dir);
    free (d);
}
Beispiel #7
0
void FBVLC::shutdown()
{
    // This will be called when it is time for the plugin to shut down;
    // any threads or anything else that may hold a shared_ptr to this
    // object should be released here so that this object can be safely
    // destroyed. This is the last point that shared_from_this and weak_ptr
    // references to this object will be valid
    vlc_close();
}
Beispiel #8
0
Datei: cdrom.c Projekt: Geal/vlc
/****************************************************************************
 * CloseVCDImage: closes a vcd image opened by OpenVCDImage
 ****************************************************************************/
static void CloseVCDImage( vlc_object_t * p_this, vcddev_t *p_vcddev )
{
    VLC_UNUSED( p_this );
    if( p_vcddev->i_vcdimage_handle != -1 )
        vlc_close( p_vcddev->i_vcdimage_handle );
    else
        return;

    free( p_vcddev->p_sectors );
}
Beispiel #9
0
static block_t *Shoot(demux_t *demux)
{
    demux_sys_t *sys = demux->p_sys;

    int fd = vlc_memfd();
    if (fd == -1)
    {
        msg_Err(demux, "buffer creation error: %s", vlc_strerror_c(errno));
        return NULL;
    }

    /* NOTE: one extra line for overflow if screen-left > 0 */
    uint32_t pitch = 4u * sys->width;
    size_t size = (pitch * (sys->height + 1) + sys->pagemask) & ~sys->pagemask;
    block_t *block = NULL;

    if (ftruncate(fd, size) < 0)
    {
        msg_Err(demux, "buffer allocation error: %s", vlc_strerror_c(errno));
        goto out;
    }

    struct wl_shm_pool *pool = wl_shm_create_pool(sys->shm, fd, size);
    if (pool == NULL)
        goto out;

    struct wl_buffer *buffer;
    buffer = wl_shm_pool_create_buffer(pool, 0, sys->width, sys->height,
                                       pitch, WL_SHM_FORMAT_XRGB8888);
    wl_shm_pool_destroy(pool);
    if (buffer == NULL)
        goto out;

    sys->done = false;
    screenshooter_shoot(sys->screenshooter, sys->output, buffer);

    while (!sys->done)
        wl_display_roundtrip(sys->display);

    wl_buffer_destroy(buffer);
    block = block_File(fd, true);

    if (block != NULL)
    {
        size_t skip = (sys->y * sys->width + sys->x) * 4;

        block->p_buffer += skip;
        block->i_buffer -= skip;
    }

out:
    vlc_close(fd);
    return block;
}
Beispiel #10
0
/**
 * Opens a FILE pointer.
 * @param filename file path, using UTF-8 encoding
 * @param mode fopen file open mode
 * @return NULL on error, an open FILE pointer on success.
 */
FILE *vlc_fopen (const char *filename, const char *mode)
{
    int rwflags = 0, oflags = 0;

    for (const char *ptr = mode; *ptr; ptr++)
    {
        switch (*ptr)
        {
            case 'r':
                rwflags = O_RDONLY;
                break;

            case 'a':
                rwflags = O_WRONLY;
                oflags |= O_CREAT | O_APPEND;
                break;

            case 'w':
                rwflags = O_WRONLY;
                oflags |= O_CREAT | O_TRUNC;
                break;

            case 'x':
                oflags |= O_EXCL;
                break;

            case '+':
                rwflags = O_RDWR;
                break;

#ifdef O_BINARY
            case 'b':
                oflags = (oflags & ~O_TEXT) | O_BINARY;
                break;

            case 't':
                oflags = (oflags & ~O_BINARY) | O_TEXT;
                break;
#endif
        }
    }

    int fd = vlc_open (filename, rwflags | oflags, 0666);
    if (fd == -1)
        return NULL;

    FILE *stream = fdopen (fd, mode);
    if (stream == NULL)
        vlc_close (fd);

    return stream;
}
Beispiel #11
0
struct vlc_vaapi_instance *
vlc_vaapi_InitializeInstanceDRM(vlc_object_t *o,
                                VADisplay (*pf_getDisplayDRM)(int),
                                VADisplay *pdpy, const char *device)
{
    static const char *default_drm_device_paths[] = {
        "/dev/dri/renderD128",
        "/dev/dri/card0",
        "/dev/dri/renderD129",
        "/dev/dri/card1",
    };

    const char *user_drm_device_paths[] = { device };
    const char **drm_device_paths;
    size_t drm_device_paths_count;

    if (device != NULL)
    {
        drm_device_paths = user_drm_device_paths;
        drm_device_paths_count = 1;
    }
    else
    {
        drm_device_paths = default_drm_device_paths;
        drm_device_paths_count = ARRAY_SIZE(default_drm_device_paths);
    }

    for (size_t i = 0; i < drm_device_paths_count; i++)
    {
        int drm_fd = vlc_open(drm_device_paths[i], O_RDWR);
        if (drm_fd < 0)
            continue;

        VADisplay dpy = pf_getDisplayDRM(drm_fd);
        if (dpy)
        {
            struct vlc_vaapi_instance *va_inst =
                vlc_vaapi_InitializeInstance(o, dpy,
                                             (VANativeDisplay)(intptr_t)drm_fd,
                                             native_drm_destroy_cb);
            if (va_inst)
            {
                *pdpy = dpy;
                return va_inst;
            }
        }
        else
            vlc_close(drm_fd);
    }
    return NULL;
}
Beispiel #12
0
/*****************************************************************************
 * Close files and free resources
 *****************************************************************************/
static void Close( vlc_object_t * p_this )
{
    access_t *p_access = (access_t*)p_this;
    access_sys_t *p_sys = p_access->p_sys;

    if( p_sys->fd != -1 )
        vlc_close( p_sys->fd );
    ARRAY_RESET( p_sys->file_sizes );

    if( p_sys->p_meta )
        vlc_meta_Delete( p_sys->p_meta );

    size_t count = p_sys->p_marks->i_seekpoint;
    TAB_CLEAN( count, p_sys->offsets );
    vlc_input_title_Delete( p_sys->p_marks );
}
Beispiel #13
0
static void *proxy_thread(void *data)
{
    int lfd = (intptr_t)data;

    for (;;)
    {
        int cfd = accept4(lfd, NULL, NULL, SOCK_CLOEXEC);
        if (cfd == -1)
            continue;

        int canc = vlc_savecancel();
        proxy_client_process(cfd);
        vlc_close(cfd);
        connection_count++;
        vlc_restorecancel(canc);
    }
    vlc_assert_unreachable();
}
Beispiel #14
0
int dvb_add_pid (dvb_device_t *d, uint16_t pid)
{
    if (d->budget)
        return 0;
#ifdef USE_DMX
    if (pid == 0 || ioctl (d->demux, DMX_ADD_PID, &pid) >= 0)
        return 0;
#else
    for (size_t i = 0; i < MAX_PIDS; i++)
    {
        if (d->pids[i].pid == pid)
            return 0;
        if (d->pids[i].fd != -1)
            continue;

        int fd = dvb_open_node (d, "demux", O_RDONLY);
        if (fd == -1)
            goto error;

       /* We need to filter at least one PID. The tap for TS demultiplexing
        * cannot be configured otherwise. So add the PAT. */
        struct dmx_pes_filter_params param;

        param.pid = pid;
        param.input = DMX_IN_FRONTEND;
        param.output = DMX_OUT_TS_TAP;
        param.pes_type = DMX_PES_OTHER;
        param.flags = DMX_IMMEDIATE_START;
        if (ioctl (fd, DMX_SET_PES_FILTER, &param) < 0)
        {
            vlc_close (fd);
            goto error;
        }
        d->pids[i].fd = fd;
        d->pids[i].pid = pid;
        return 0;
    }
    errno = EMFILE;
error:
#endif
    msg_Err (d->obj, "cannot add PID 0x%04"PRIu16": %s", pid,
             vlc_strerror_c(errno));
    return -1;
}
Beispiel #15
0
void dvb_remove_pid (dvb_device_t *d, uint16_t pid)
{
    if (d->budget)
        return;
#ifdef USE_DMX
    if (pid != 0)
        ioctl (d->demux, DMX_REMOVE_PID, &pid);
#else
    for (size_t i = 0; i < MAX_PIDS; i++)
    {
        if (d->pids[i].pid == pid)
        {
            vlc_close (d->pids[i].fd);
            d->pids[i].pid = d->pids[i].fd = -1;
            return;
        }
    }
#endif
}
Beispiel #16
0
int gzopen_frontend( const char *pathname, int oflags, int mode )
{
    (void)mode;

    const char *gzflags;
    gzFile gzf;

    switch( oflags )
    {
    case O_WRONLY:
        gzflags = "wb";
        break;
    case O_RDONLY:
        gzflags = "rb";
        break;
    case O_RDWR:
    default:
        errno = EINVAL;
        return -1;
    }
    int fd = vlc_open( pathname, oflags );
    if( fd == -1 )
    {
        fprintf( stderr, "Couldn't open %s\n", pathname );
        return -1;
    }
    gzf = gzdopen( fd, gzflags );
    if( !gzf )
    {
        errno = ENOMEM;
        vlc_close( fd );
        return -1;
    }

    /** Hum ... */
    currentGzFd = 42;
    currentGzVp = gzf;

    return currentGzFd;
}
Beispiel #17
0
static void *Thread (void *data)
{
    stream_t *stream = data;
    stream_sys_t *p_sys = stream->p_sys;
#ifdef HAVE_VMSPLICE
    const ssize_t page_mask = sysconf (_SC_PAGE_SIZE) - 1;
#endif
    int fd = p_sys->write_fd;
    bool error = false;
    sigset_t set;

    sigemptyset(&set);
    sigaddset(&set, SIGPIPE);
    pthread_sigmask(SIG_BLOCK, &set, NULL);

    do
    {
        ssize_t len;
        int canc = vlc_savecancel ();
#ifdef HAVE_VMSPLICE
        unsigned char *buf = mmap (NULL, bufsize, PROT_READ|PROT_WRITE,
                                   MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
        if (unlikely(buf == MAP_FAILED))
            break;
        vlc_cleanup_push (cleanup_mmap, buf);
#else
        unsigned char *buf = malloc (bufsize);
        if (unlikely(buf == NULL))
            break;
        vlc_cleanup_push (free, buf);
#endif

        vlc_mutex_lock (&p_sys->lock);
        while (p_sys->paused) /* practically always false, but... */
            vlc_cond_wait (&p_sys->wait, &p_sys->lock);
        len = vlc_stream_Read (stream->p_source, buf, bufsize);
        vlc_mutex_unlock (&p_sys->lock);

        vlc_restorecancel (canc);
        error = len <= 0;

        for (ssize_t i = 0, j; i < len; i += j)
        {
#ifdef HAVE_VMSPLICE
            if ((len - i) <= page_mask) /* incomplete last page */
                j = write (fd, buf + i, len - i);
            else
            {
                struct iovec iov = {
                    .iov_base = buf + i,
                    .iov_len = (len - i) & ~page_mask };

                j = vmsplice (fd, &iov, 1, SPLICE_F_GIFT);
            }
            if (j == -1 && errno == ENOSYS) /* vmsplice() not supported */
#endif
            j = write (fd, buf + i, len - i);
            if (j <= 0)
            {
                if (j == 0)
                    errno = EPIPE;
                msg_Err (stream, "cannot write data: %s",
                         vlc_strerror_c(errno));
                error = true;
                break;
            }
        }
        vlc_cleanup_pop ();
#ifdef HAVE_VMSPLICE
        munmap (buf, bufsize);
#else
        free (buf);
#endif
    }
    while (!error);

    msg_Dbg (stream, "compressed stream at EOF");
    /* Let child process know about EOF */
    p_sys->write_fd = -1;
    vlc_close (fd);
    return NULL;
}
Beispiel #18
0
static int server_socket(unsigned *port)
{
    int fd = socket(PF_INET6, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP);
    if (fd == -1)
        return -1;

    struct sockaddr_in6 addr = {
        .sin6_family = AF_INET6,
#ifdef HAVE_SA_LEN
        .sin6_len = sizeof (addr),
#endif
        .sin6_addr = in6addr_loopback,
    };
    socklen_t addrlen = sizeof (addr);

    if (bind(fd, (struct sockaddr *)&addr, addrlen)
     || getsockname(fd, (struct sockaddr *)&addr, &addrlen))
    {
        vlc_close(fd);
        return -1;
    }

    *port = ntohs(addr.sin6_port);
    return fd;
}

int main(void)
{
    char *url;
    unsigned port;
    bool two = false;

    /* Test bad URLs */
    vlc_https_connect_proxy(NULL, "www.example.com", 0, &two,
                            "/test");
    vlc_https_connect_proxy(NULL, "www.example.com", 0, &two,
                            "ftp://proxy.example.com/");

    int lfd = server_socket(&port);
    if (lfd == -1)
        return 77;

    if (asprintf(&url, "http://*****:*****@[::1]:%u", port) < 0)
        url = NULL;

    assert(url != NULL);

    /* Test connection failure */
    vlc_https_connect_proxy(NULL, "www.example.com", 0, &two, url);

    if (listen(lfd, 255))
    {
        vlc_close(lfd);
        return 77;
    }

    vlc_thread_t th;
    if (vlc_clone(&th, proxy_thread, (void*)(intptr_t)lfd,
                  VLC_THREAD_PRIORITY_LOW))
        assert(!"Thread error");

    /* Test proxy error */
    vlc_https_connect_proxy(NULL, "www.example.com", 0, &two, url);

    vlc_cancel(th);
    vlc_join(th, NULL);
    assert(connection_count > 0);
    free(url);
    vlc_close(lfd);
}
Beispiel #19
0
/**
 * Pipe data through an external executable.
 * @param stream the stream filter object.
 * @param path path to the executable.
 */
static int Open (stream_t *stream, const char *path)
{
    stream_sys_t *p_sys = stream->p_sys = malloc (sizeof (*p_sys));
    if (p_sys == NULL)
        return VLC_ENOMEM;

    vlc_cond_init (&p_sys->wait);
    vlc_mutex_init (&p_sys->lock);
    p_sys->paused = false;
    p_sys->pid = -1;
    vlc_stream_Control(stream->p_source, STREAM_CAN_PAUSE, &p_sys->can_pause);
    vlc_stream_Control(stream->p_source, STREAM_CAN_CONTROL_PACE,
                       &p_sys->can_pace);
    vlc_stream_Control(stream->p_source, STREAM_GET_PTS_DELAY,
                       &p_sys->pts_delay);

    /* I am not a big fan of the pyramid style, but I cannot think of anything
     * better here. There are too many failure cases. */
    int ret = VLC_EGENERIC;
    int comp[2];

    /* We use two pipes rather than one stream socket pair, so that we can
     * use vmsplice() on Linux. */
    if (vlc_pipe (comp) == 0)
    {
        p_sys->write_fd = comp[1];

        int uncomp[2];
        if (vlc_pipe (uncomp) == 0)
        {
            p_sys->read_fd = uncomp[0];

#if (_POSIX_SPAWN >= 0)
            posix_spawn_file_actions_t actions;
            if (posix_spawn_file_actions_init (&actions) == 0)
            {
                char *const argv[] = { (char *)path, NULL };

                if (!posix_spawn_file_actions_adddup2 (&actions, comp[0], 0)
                 && !posix_spawn_file_actions_adddup2 (&actions, uncomp[1], 1)
                 && !posix_spawnp (&p_sys->pid, path, &actions, NULL, argv,
                                   environ))
                {
                    if (vlc_clone (&p_sys->thread, Thread, stream,
                                   VLC_THREAD_PRIORITY_INPUT) == 0)
                        ret = VLC_SUCCESS;
                }
                else
                {
                    msg_Err (stream, "cannot execute %s", path);
                    p_sys->pid = -1;
                }
                posix_spawn_file_actions_destroy (&actions);
            }
#else /* _POSIX_SPAWN */
            switch (p_sys->pid = fork ())
            {
                case -1:
                    msg_Err (stream, "cannot fork: %s", vlc_strerror_c(errno));
                    break;
                case 0:
                    dup2 (comp[0], 0);
                    dup2 (uncomp[1], 1);
                    execlp (path, path, (const char *)NULL);
                    exit (1); /* if we get, execlp() failed! */
                default:
                    if (vlc_clone (&p_sys->thread, Thread, stream,
                                   VLC_THREAD_PRIORITY_INPUT) == 0)
                        ret = VLC_SUCCESS;
            }
#endif /* _POSIX_SPAWN < 0 */
            vlc_close (uncomp[1]);
            if (ret != VLC_SUCCESS)
                vlc_close (uncomp[0]);
        }
        vlc_close (comp[0]);
        if (ret != VLC_SUCCESS)
            vlc_close (comp[1]);
    }

    if (ret != VLC_SUCCESS)
    {
        if (p_sys->pid != -1)
            while (waitpid (p_sys->pid, &(int){ 0 }, 0) == -1);
        vlc_mutex_destroy (&p_sys->lock);
        vlc_cond_destroy (&p_sys->wait);
        free (p_sys);
        return ret;
    }
Beispiel #20
0
bool FBVLC::onWindowDetached(FB::DetachedEvent *evt, FB::PluginWindow *)
{
    vlc_close();
    return true;
}
Beispiel #21
0
/**
 * Saves the in-memory configuration into a file.
 * @return 0 on success, -1 on error.
 */
int config_SaveConfigFile (vlc_object_t *p_this)
{

    if( config_PrepareDir( p_this ) )
    {
        msg_Err( p_this, "no configuration directory" );
        return -1;
    }

    /*
     * Save module config in file
     */
    char *temporary;
    char *permanent = config_GetConfigFile (p_this);
    if (permanent == NULL)
        return -1;
    if (asprintf (&temporary, "%s.%u", permanent, getpid ()) == -1)
    {
        free (permanent);
        return -1;
    }
    else
    {
        struct stat st;

        /* Some users make vlcrc read-only to prevent changes.
         * The atomic replacement scheme breaks this "feature",
         * so we check for read-only by hand. */
        if (stat (permanent, &st) == 0 && !(st.st_mode & S_IWUSR))
        {
            msg_Err (p_this, "configuration file is read-only");
            goto error;
        }
    }

    /* Configuration lock must be taken before vlcrc serializer below. */
    vlc_rwlock_rdlock (&config_lock);

    /* The temporary configuration file is per-PID. Therefore this function
     * should be serialized against itself within a given process. */
    static vlc_mutex_t lock = VLC_STATIC_MUTEX;
    vlc_mutex_lock (&lock);

    int fd = vlc_open (temporary, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
    if (fd == -1)
    {
        vlc_rwlock_unlock (&config_lock);
        vlc_mutex_unlock (&lock);
        goto error;
    }
    FILE *file = fdopen (fd, "wt");
    if (file == NULL)
    {
        msg_Err (p_this, "cannot create configuration file: %s",
                 vlc_strerror_c(errno));
        vlc_rwlock_unlock (&config_lock);
        vlc_close (fd);
        vlc_mutex_unlock (&lock);
        goto error;
    }

    fprintf( file,
        "\xEF\xBB\xBF###\n"
        "###  "PACKAGE_NAME" "PACKAGE_VERSION"\n"
        "###\n"
        "\n"
        "###\n"
        "### lines beginning with a '#' character are comments\n"
        "###\n"
        "\n" );

    /* Ensure consistent number formatting... */
    locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
    locale_t baseloc = uselocale (loc);

    /* We would take the config lock here. But this would cause a lock
     * inversion with the serializer above and config_AutoSaveConfigFile().
    vlc_rwlock_rdlock (&config_lock);*/

    /* Look for the selected module, if NULL then save everything */
    size_t count;
    module_t **list = module_list_get (&count);
    for (size_t i = 0; i < count; i++)
    {
        module_t *p_parser = list[i];
        module_config_t *p_item, *p_end;

        if( !p_parser->i_config_items )
            continue;

        fprintf( file, "[%s]", module_get_object (p_parser) );
        if( p_parser->psz_longname )
            fprintf( file, " # %s\n\n", p_parser->psz_longname );
        else
            fprintf( file, "\n\n" );

        for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize;
             p_item < p_end;
             p_item++ )
        {
            if (!CONFIG_ITEM(p_item->i_type)   /* ignore hint */
             || p_item->b_removed              /* ignore deprecated option */
             || p_item->b_unsaveable)          /* ignore volatile option */
                continue;

            if (IsConfigIntegerType (p_item->i_type))
            {
                int64_t val = p_item->value.i;
                config_Write (file, p_item->psz_text,
                             (CONFIG_CLASS(p_item->i_type) == CONFIG_ITEM_BOOL)
                                  ? N_("boolean") : N_("integer"),
                              val == p_item->orig.i,
                              p_item->psz_name, "%"PRId64, val);
            }
            else
            if (IsConfigFloatType (p_item->i_type))
            {
                float val = p_item->value.f;
                config_Write (file, p_item->psz_text, N_("float"),
                              val == p_item->orig.f,
                              p_item->psz_name, "%f", val);
            }
            else
            {
                const char *psz_value = p_item->value.psz;
                bool modified;

                assert (IsConfigStringType (p_item->i_type));

                modified = !!strcmp (psz_value ? psz_value : "",
                                     p_item->orig.psz ? p_item->orig.psz : "");
                config_Write (file, p_item->psz_text, N_("string"),
                              !modified, p_item->psz_name, "%s",
                              psz_value ? psz_value : "");
            }
        }
    }
    vlc_rwlock_unlock (&config_lock);

    module_list_free (list);
    if (loc != (locale_t)0)
    {
        uselocale (baseloc);
        freelocale (loc);
    }

    /*
     * Flush to disk and replace atomically
     */
    fflush (file); /* Flush from run-time */
    if (ferror (file))
    {
        vlc_unlink (temporary);
        vlc_mutex_unlock (&lock);
        msg_Err (p_this, "cannot write configuration file");
        fclose (file);
        goto error;
    }
#if defined(__APPLE__) || defined(__ANDROID__)
    fsync (fd); /* Flush from OS */
#else
    fdatasync (fd); /* Flush from OS */
#endif
#if defined (_WIN32) || defined (__OS2__)
    /* Windows cannot (re)move open files nor overwrite existing ones */
    fclose (file);
    vlc_unlink (permanent);
#endif
    /* Atomically replace the file... */
    if (vlc_rename (temporary, permanent))
        vlc_unlink (temporary);
    /* (...then synchronize the directory, err, TODO...) */
    /* ...and finally close the file */
    vlc_mutex_unlock (&lock);
#if !defined (_WIN32) && !defined (__OS2__)
    fclose (file);
#endif

    free (temporary);
    free (permanent);
    return 0;

error:
    free (temporary);
    free (permanent);
    return -1;
}
Beispiel #22
0
/************************************************************************
 * CryptSetup: Initialize encryption
 ************************************************************************/
static int CryptSetup( sout_access_out_t *p_access, char *key_file )
{
    sout_access_out_sys_t *p_sys = p_access->p_sys;
    uint8_t key[16];
    char *keyfile = NULL;

    if( !p_sys->key_uri ) /*No key uri, assume no encryption wanted*/
    {
        msg_Dbg( p_access, "No key uri, no encryption");
        return VLC_SUCCESS;
    }

    if( key_file )
        keyfile = strdup( key_file );
    else
        keyfile = var_InheritString( p_access, SOUT_CFG_PREFIX "key-file" );

    if( unlikely(keyfile == NULL) )
    {
        msg_Err( p_access, "No key-file, no encryption" );
        return VLC_EGENERIC;
    }

    vlc_gcrypt_init();

    /*Setup encryption cipher*/
    gcry_error_t err = gcry_cipher_open( &p_sys->aes_ctx, GCRY_CIPHER_AES,
                                         GCRY_CIPHER_MODE_CBC, 0 );
    if( err )
    {
        msg_Err( p_access, "Openin AES Cipher failed: %s", gpg_strerror(err));
        free( keyfile );
        return VLC_EGENERIC;
    }

    int keyfd = vlc_open( keyfile, O_RDONLY | O_NONBLOCK );
    if( unlikely( keyfd == -1 ) )
    {
        msg_Err( p_access, "Unable to open keyfile %s: %s", keyfile,
                 vlc_strerror_c(errno) );
        free( keyfile );
        gcry_cipher_close( p_sys->aes_ctx );
        return VLC_EGENERIC;
    }
    free( keyfile );

    ssize_t keylen = read( keyfd, key, 16 );

    vlc_close( keyfd );
    if( keylen < 16 )
    {
        msg_Err( p_access, "No key at least 16 octects (you provided %zd), no encryption", keylen );
        gcry_cipher_close( p_sys->aes_ctx );
        return VLC_EGENERIC;
    }

    err = gcry_cipher_setkey( p_sys->aes_ctx, key, 16 );
    if(err)
    {
        msg_Err(p_access, "Setting AES key failed: %s", gpg_strerror(err));
        gcry_cipher_close( p_sys->aes_ctx );
        return VLC_EGENERIC;
    }

    if( p_sys->b_generate_iv )
        vlc_rand_bytes( p_sys->aes_ivs, sizeof(uint8_t)*16);

    return VLC_SUCCESS;
}
Beispiel #23
0
static void native_drm_destroy_cb(VANativeDisplay native)
{
    vlc_close((intptr_t) native);
}
Beispiel #24
0
static int Retrieve( addons_finder_t *p_finder, addon_entry_t *p_entry )
{
    vlc_mutex_lock( &p_entry->lock );
    if ( !p_entry->psz_archive_uri )
    {
        vlc_mutex_unlock( &p_entry->lock );
        return VLC_EGENERIC;
    }
    char *psz_archive_uri = strdup( p_entry->psz_archive_uri );
    vlc_mutex_unlock( &p_entry->lock );
    if ( !psz_archive_uri )
        return VLC_ENOMEM;

    /* get archive and parse manifest */
    stream_t *p_stream;

    if ( psz_archive_uri[0] == '/' )
    {
        /* Relative path */
        char *psz_uri;
        if ( ! asprintf( &psz_uri, ADDONS_REPO_SCHEMEHOST"%s", psz_archive_uri ) )
        {
            free( psz_archive_uri );
            return VLC_ENOMEM;
        }
        p_stream = vlc_stream_NewURL_ND( p_finder, psz_uri );
        free( psz_uri );
    }
    else
    {
        p_stream = vlc_stream_NewURL_ND( p_finder, psz_archive_uri );
    }

    msg_Dbg( p_finder, "downloading archive %s", psz_archive_uri );
    free ( psz_archive_uri );
    if ( !p_stream ) return VLC_EGENERIC;

    /* In case of pf_ reuse */
    if ( p_finder->p_sys->psz_tempfile )
    {
        vlc_unlink( p_finder->p_sys->psz_tempfile );
        FREENULL( p_finder->p_sys->psz_tempfile );
    }

    p_finder->p_sys->psz_tempfile = tempnam( NULL, "vlp" );
    if ( !p_finder->p_sys->psz_tempfile )
    {
        msg_Err( p_finder, "Can't create temp storage file" );
        vlc_stream_Delete( p_stream );
        return VLC_EGENERIC;
    }

    int fd = vlc_open( p_finder->p_sys->psz_tempfile,
                       O_WRONLY | O_CREAT | O_EXCL, 0600 );
    if( fd == -1 )
    {
        msg_Err( p_finder, "Failed to open addon temp storage file" );
        FREENULL(p_finder->p_sys->psz_tempfile);
        vlc_stream_Delete( p_stream );
        return VLC_EGENERIC;
    }

    char buffer[1<<10];
    ssize_t i_read = 0;
    int i_ret = VLC_SUCCESS;

    while ( ( i_read = vlc_stream_Read( p_stream, &buffer, 1<<10 ) ) > 0 )
    {
        if ( write( fd, buffer, i_read ) != i_read )
        {
            msg_Err( p_finder, "Failed to write to Addon file" );
            i_ret = VLC_EGENERIC;
            break;
        }
    }

    vlc_close( fd );
    vlc_stream_Delete( p_stream );

    if (i_ret)
        return i_ret;

    msg_Dbg( p_finder, "Reading manifest from %s", p_finder->p_sys->psz_tempfile );

    char *psz_tempfileuri = vlc_path2uri( p_finder->p_sys->psz_tempfile, NULL );
    if ( !psz_tempfileuri )
        return VLC_ENOMEM;

    char *psz_manifest_uri;
    if ( asprintf( &psz_manifest_uri, "%s#!/manifest.xml", psz_tempfileuri ) < 1 )
    {
        free( psz_tempfileuri );
        return VLC_ENOMEM;
    }

    p_stream = vlc_stream_NewMRL( p_finder, psz_manifest_uri );
    free( psz_manifest_uri );
    if ( !p_stream )
    {
        free( psz_tempfileuri );
        return VLC_EGENERIC;
    }

    vlc_mutex_lock( &p_entry->lock );
    i_ret = ( ParseManifest( p_finder, p_entry, psz_tempfileuri, p_stream ) > 0 )
                    ? VLC_SUCCESS : VLC_EGENERIC;
    vlc_mutex_unlock( &p_entry->lock );
    free( psz_tempfileuri );
    vlc_stream_Delete( p_stream );

    return i_ret;
}
Beispiel #25
0
/**
 * Opens the DVB tuner
 */
dvb_device_t *dvb_open (vlc_object_t *obj)
{
    dvb_device_t *d = malloc (sizeof (*d));
    if (unlikely(d == NULL))
        return NULL;

    d->obj = obj;

    uint8_t adapter = var_InheritInteger (obj, "dvb-adapter");
    d->device = var_InheritInteger (obj, "dvb-device");

    d->dir = dvb_open_adapter (adapter);
    if (d->dir == -1)
    {
        msg_Err (obj, "cannot access adapter %"PRIu8": %s", adapter,
                 vlc_strerror_c(errno));
        free (d);
        return NULL;
    }
    d->frontend = -1;
    d->cam = NULL;
    d->budget = var_InheritBool (obj, "dvb-budget-mode");

#ifndef USE_DMX
    if (d->budget)
#endif
    {
       d->demux = dvb_open_node (d, "demux", O_RDONLY);
       if (d->demux == -1)
       {
           msg_Err (obj, "cannot access demultiplexer: %s",
                    vlc_strerror_c(errno));
           vlc_close (d->dir);
           free (d);
           return NULL;
       }

       if (ioctl (d->demux, DMX_SET_BUFFER_SIZE, 1 << 20) < 0)
           msg_Warn (obj, "cannot expand demultiplexing buffer: %s",
                     vlc_strerror_c(errno));

       /* We need to filter at least one PID. The tap for TS demultiplexing
        * cannot be configured otherwise. So add the PAT. */
        struct dmx_pes_filter_params param;

        param.pid = d->budget ? 0x2000 : 0x000;
        param.input = DMX_IN_FRONTEND;
        param.output = DMX_OUT_TSDEMUX_TAP;
        param.pes_type = DMX_PES_OTHER;
        param.flags = DMX_IMMEDIATE_START;
        if (ioctl (d->demux, DMX_SET_PES_FILTER, &param) < 0)
        {
            msg_Err (obj, "cannot setup TS demultiplexer: %s",
                     vlc_strerror_c(errno));
            goto error;
        }
#ifndef USE_DMX
    }
    else
    {
        for (size_t i = 0; i < MAX_PIDS; i++)
            d->pids[i].pid = d->pids[i].fd = -1;
        d->demux = dvb_open_node (d, "dvr", O_RDONLY);
        if (d->demux == -1)
        {
            msg_Err (obj, "cannot access DVR: %s", vlc_strerror_c(errno));
            vlc_close (d->dir);
            free (d);
            return NULL;
        }
#endif
    }

    int ca = dvb_open_node (d, "ca", O_RDWR);
    if (ca != -1)
    {
        d->cam = en50221_Init (obj, ca);
        if (d->cam == NULL)
            vlc_close (ca);
    }
    else
        msg_Dbg (obj, "conditional access module not available: %s",
                 vlc_strerror_c(errno));
    return d;

error:
    dvb_close (d);
    return NULL;
}
Beispiel #26
0
Datei: dbus.c Projekt: etix/vlc
static int Open( vlc_object_t *p_this )
{
    intf_thread_t   *p_intf = (intf_thread_t*)p_this;

    /* initialisation of the connection */
    if( !dbus_threads_init_default() )
        return VLC_EGENERIC;

    intf_sys_t *p_sys  = calloc( 1, sizeof( intf_sys_t ) );
    if( unlikely(!p_sys) )
        return VLC_ENOMEM;

    playlist_t      *p_playlist;
    DBusConnection  *p_conn;
    p_sys->i_player_caps   = PLAYER_CAPS_NONE;
    p_sys->i_playing_state = PLAYBACK_STATE_INVALID;

    if( vlc_pipe( p_sys->p_pipe_fds ) )
    {
        free( p_sys );
        msg_Err( p_intf, "Could not create pipe" );
        return VLC_EGENERIC;
    }

    DBusError error;
    dbus_error_init( &error );

    /* connect privately to the session bus
     * the connection will not be shared with other vlc modules which use dbus,
     * thus avoiding a whole class of concurrency issues */
    p_conn = dbus_bus_get_private( DBUS_BUS_SESSION, &error );
    if( !p_conn )
    {
        msg_Err( p_this, "Failed to connect to the D-Bus session daemon: %s",
                error.message );
        dbus_error_free( &error );
        vlc_close( p_sys->p_pipe_fds[1] );
        vlc_close( p_sys->p_pipe_fds[0] );
        free( p_sys );
        return VLC_EGENERIC;
    }

    dbus_connection_set_exit_on_disconnect( p_conn, FALSE );

    /* Register the entry point object path */
    dbus_connection_register_object_path( p_conn, DBUS_MPRIS_OBJECT_PATH,
            &dbus_mpris_vtable, p_this );

    /* Try to register org.mpris.MediaPlayer2.vlc */
    dbus_bus_request_name( p_conn, DBUS_MPRIS_BUS_NAME, 0, &error );
    if( dbus_error_is_set( &error ) )
    {
        msg_Dbg( p_this, "Failed to get service name %s: %s",
                 DBUS_MPRIS_BUS_NAME, error.message );
        dbus_error_free( &error );

        /* Register an instance-specific well known name of the form
         * org.mpris.MediaPlayer2.vlc.instanceXXXX where XXXX is the
         * current Process ID */
        char unique_service[sizeof( DBUS_MPRIS_BUS_NAME ) +
                            sizeof( DBUS_INSTANCE_ID_PREFIX ) + 10];

        snprintf( unique_service, sizeof (unique_service),
                  DBUS_MPRIS_BUS_NAME"."DBUS_INSTANCE_ID_PREFIX"%"PRIu32,
                  (uint32_t)getpid() );

        dbus_bus_request_name( p_conn, unique_service, 0, &error );
        if( dbus_error_is_set( &error ) )
        {
            msg_Err( p_this, "Failed to get service name %s: %s",
                     DBUS_MPRIS_BUS_NAME, error.message );
            dbus_error_free( &error );
        }
        else
            msg_Dbg( p_intf, "listening on dbus as: %s", unique_service );
    }
    else
        msg_Dbg( p_intf, "listening on dbus as: %s", DBUS_MPRIS_BUS_NAME );

    dbus_connection_flush( p_conn );

    p_intf->p_sys = p_sys;
    p_sys->p_conn = p_conn;
    p_sys->p_events = vlc_array_new();
    p_sys->p_timeouts = vlc_array_new();
    p_sys->p_watches = vlc_array_new();
    vlc_mutex_init( &p_sys->lock );

    p_playlist = pl_Get( p_intf );
    p_sys->p_playlist = p_playlist;

    var_AddCallback( p_playlist, "input-current", AllCallback, p_intf );
    var_AddCallback( p_playlist, "volume", AllCallback, p_intf );
    var_AddCallback( p_playlist, "mute", AllCallback, p_intf );
    var_AddCallback( p_playlist, "playlist-item-append", AllCallback, p_intf );
    var_AddCallback( p_playlist, "playlist-item-deleted", AllCallback, p_intf );
    var_AddCallback( p_playlist, "random", AllCallback, p_intf );
    var_AddCallback( p_playlist, "repeat", AllCallback, p_intf );
    var_AddCallback( p_playlist, "loop", AllCallback, p_intf );
    var_AddCallback( p_playlist, "fullscreen", AllCallback, p_intf );

    if( !dbus_connection_set_timeout_functions( p_conn,
                                                add_timeout,
                                                remove_timeout,
                                                toggle_timeout,
                                                p_intf, NULL ) )
        goto error;

    if( !dbus_connection_set_watch_functions( p_conn,
                                              add_watch,
                                              remove_watch,
                                              watch_toggled,
                                              p_intf, NULL ) )
        goto error;

    if( vlc_clone( &p_sys->thread, Run, p_intf, VLC_THREAD_PRIORITY_LOW ) )
        goto error;

    return VLC_SUCCESS;

error:
    /* The dbus connection is private,
     * so we are responsible for closing it
     * XXX: Does this make sense when OOM ? */
    dbus_connection_close( p_sys->p_conn );
    dbus_connection_unref( p_conn );

    vlc_array_destroy( p_sys->p_events );
    vlc_array_destroy( p_sys->p_timeouts );
    vlc_array_destroy( p_sys->p_watches );

    vlc_mutex_destroy( &p_sys->lock );

    vlc_close( p_sys->p_pipe_fds[1] );
    vlc_close( p_sys->p_pipe_fds[0] );
    free( p_sys );
    return VLC_ENOMEM;
}
Beispiel #27
0
/*****************************************************************************
 * Render: displays previously rendered output
 *****************************************************************************
 * This function send the currently rendered image to adjust modified image,
 * waits until it is displayed and switch the two rendering buffers, preparing
 * next frame.
 *****************************************************************************/
static subpicture_t *Filter( filter_t *p_filter, vlc_tick_t date )
{
    filter_sys_t *p_sys = p_filter->p_sys;

    /* We might need to open these at any time. */
    vlc_mutex_lock( &p_sys->lock );
    if( p_sys->i_inputfd == -1 )
    {
        p_sys->i_inputfd = vlc_open( p_sys->psz_inputfile, O_RDONLY | O_NONBLOCK );
        if( p_sys->i_inputfd == -1 )
        {
            msg_Warn( p_filter, "Failed to grab input file: %s (%s)",
                      p_sys->psz_inputfile, vlc_strerror_c(errno) );
        }
        else
        {
            msg_Info( p_filter, "Grabbed input file: %s",
                      p_sys->psz_inputfile );
        }
    }

    if( p_sys->i_outputfd == -1 )
    {
        p_sys->i_outputfd = vlc_open( p_sys->psz_outputfile,
                                  O_WRONLY | O_NONBLOCK );
        if( p_sys->i_outputfd == -1 )
        {
            if( errno != ENXIO )
            {
                msg_Warn( p_filter, "Failed to grab output file: %s (%s)",
                          p_sys->psz_outputfile, vlc_strerror_c(errno) );
            }
        }
        else
        {
            msg_Info( p_filter, "Grabbed output file: %s",
                      p_sys->psz_outputfile );
        }
    }
    vlc_mutex_unlock( &p_sys->lock );

    /* Read any waiting commands */
    if( p_sys->i_inputfd != -1 )
    {
        char p_buffer[1024];
        ssize_t i_len = read( p_sys->i_inputfd, p_buffer, 1024 );
        if( i_len == -1 )
        {
            /* We hit an error */
            if( errno != EAGAIN )
            {
                msg_Warn( p_filter, "Error on input file: %s",
                          vlc_strerror_c(errno) );
                vlc_close( p_sys->i_inputfd );
                p_sys->i_inputfd = -1;
            }
        }
        else if( i_len == 0 )
        {
            /* We hit the end-of-file */
        }
        else
        {
            BufferAdd( &p_sys->input, p_buffer, i_len );
        }
    }

    /* Parse any complete commands */
    char *p_end, *p_cmd;
    while( ( p_end = memchr( p_sys->input.p_begin, '\n',
                             p_sys->input.i_length ) ) )
    {
        commanddesc_t *p_cur = NULL;
        bool b_found = false;
        size_t i_index = 0;

        *p_end = '\0';
        p_cmd = BufferGetToken( &p_sys->input );

        msg_Info( p_filter, "Search command: %s", p_cmd );
        for( i_index = 0; i_index < p_sys->i_commands; i_index++ )
        {
            p_cur = p_sys->pp_commands[i_index];
            if( !strncmp( p_cur->psz_command, p_cmd, strlen(p_cur->psz_command) ) )
            {
                p_cmd[strlen(p_cur->psz_command)] = '\0';
                b_found = true;
                break;
            }
        }

        if( !b_found )
        {
            /* No matching command */
            msg_Err( p_filter, "Got invalid command: %s", p_cmd );
            BufferPrintf( &p_sys->output, "FAILURE: %d Invalid Command\n", VLC_EGENERIC );
        }
        else
        {
            msg_Info( p_filter, "Got valid command: %s", p_cmd );

            command_t *p_cmddesc = malloc( sizeof( command_t ) );
            if( !p_cmddesc )
                return NULL;

            p_cmd = p_cmd + strlen(p_cur->psz_command) +1;
            p_cmddesc->p_command = p_cur;
            p_cmddesc->p_command->pf_parser( p_cmd, p_end,
                                             &p_cmddesc->params );

            if( p_cmddesc->p_command->b_atomic && p_sys->b_atomic )
                QueueEnqueue( &p_sys->atomic, p_cmddesc );
            else
                QueueEnqueue( &p_sys->pending, p_cmddesc );
        }

        BufferDel( &p_sys->input, p_end - p_sys->input.p_begin + 1 );
    }

    /* Process any pending commands */
    command_t *p_command = NULL;
    while( (p_command = QueueDequeue( &p_sys->pending )) )
    {
        p_command->i_status =
            p_command->p_command->pf_execute( p_filter, &p_command->params,
                                              &p_command->results );
        QueueEnqueue( &p_sys->processed, p_command );
    }

    /* Output any processed commands */
    while( (p_command = QueueDequeue( &p_sys->processed )) )
    {
        if( p_command->i_status == VLC_SUCCESS )
        {
            const char *psz_success = "SUCCESS:";
            const char *psz_nl = "\n";
            BufferAdd( &p_sys->output, psz_success, 8 );
            p_command->p_command->pf_unparse( &p_command->results,
                                              &p_sys->output );
            BufferAdd( &p_sys->output, psz_nl, 1 );
        }
        else
        {
            BufferPrintf( &p_sys->output, "FAILURE: %d\n",
                          p_command->i_status );
        }
    }

    /* Try emptying the output buffer */
    if( p_sys->i_outputfd != -1 )
    {
        ssize_t i_len = vlc_write( p_sys->i_outputfd, p_sys->output.p_begin,
                                   p_sys->output.i_length );
        if( i_len == -1 )
        {
            /* We hit an error */
            if( errno != EAGAIN )
            {
                msg_Warn( p_filter, "Error on output file: %s",
                          vlc_strerror_c(errno) );
                vlc_close( p_sys->i_outputfd );
                p_sys->i_outputfd = -1;
            }
        }
        else
        {
            BufferDel( &p_sys->output, i_len );
        }
    }

    if( !p_sys->b_updated )
        return NULL;

    subpicture_t *p_spu = NULL;
    overlay_t *p_overlay = NULL;

    p_spu = filter_NewSubpicture( p_filter );
    if( !p_spu )
        return NULL;

    p_spu->b_absolute = true;
    p_spu->i_start = date;
    p_spu->i_stop = 0;
    p_spu->b_ephemer = true;

    subpicture_region_t **pp_region = &p_spu->p_region;
    while( (p_overlay = ListWalk( &p_sys->overlays )) )
    {
        subpicture_region_t *p_region;

        *pp_region = p_region = subpicture_region_New( &p_overlay->format );
        if( !p_region )
            break;

        msg_Dbg( p_filter, "Displaying overlay: %4.4s, %d, %d, %d",
                 (char*)&p_overlay->format.i_chroma, p_overlay->i_x, p_overlay->i_y,
                 p_overlay->i_alpha );

        if( p_overlay->format.i_chroma == VLC_CODEC_TEXT )
        {
            p_region->p_text = text_segment_New( p_overlay->data.p_text );
            p_region->p_text->style = text_style_Duplicate( p_overlay->p_fontstyle );
        }
        else
        {
            /* FIXME the copy is probably not needed anymore */
            picture_Copy( p_region->p_picture, p_overlay->data.p_pic );
        }
        p_region->i_x = p_overlay->i_x;
        p_region->i_y = p_overlay->i_y;
        p_region->i_align = SUBPICTURE_ALIGN_LEFT | SUBPICTURE_ALIGN_TOP;
        p_region->i_alpha = p_overlay->i_alpha;
        pp_region = &p_region->p_next;
    }

    p_sys->b_updated = false;
    return p_spu;
}