Esempio n. 1
0
static int Control(access_t *access, int query, va_list args)
{
    stream_t *s = access->p_sys->s;
    if (!s)
        return VLC_EGENERIC;

    switch (query) {
    case ACCESS_CAN_SEEK: {
        bool *b = va_arg(args, bool *);
        return stream_Control(s, STREAM_CAN_SEEK, b);
    }
    case ACCESS_CAN_FASTSEEK: {
        bool *b = va_arg(args, bool *);
        return stream_Control(s, STREAM_CAN_FASTSEEK, b);
    }
    /* FIXME the following request should ask the underlying access object */
    case ACCESS_CAN_PAUSE:
    case ACCESS_CAN_CONTROL_PACE: {
        bool *b = va_arg(args, bool *);
        *b = true;
        return VLC_SUCCESS;
    }
    case ACCESS_GET_PTS_DELAY: {
        int64_t *delay = va_arg(args, int64_t *);
        *delay = DEFAULT_PTS_DELAY;
        return VLC_SUCCESS;
    }
    case ACCESS_SET_PAUSE_STATE:
        return VLC_SUCCESS;

    default:
        return VLC_EGENERIC;
    }
}
Esempio n. 2
0
int main(void)
{
    ssize_t val;
    char buf[16];
    bool b;

    test_init();

    vlc = libvlc_new(0, NULL);
    assert(vlc != NULL);
    parent = VLC_OBJECT(vlc->p_libvlc_int);

    s = vlc_stream_fifo_New(parent);
    assert(s != NULL);
    val = stream_Control(s, STREAM_CAN_SEEK, &b);
    assert(val == VLC_SUCCESS && !b);
    val = stream_GetSize(s, &(uint64_t){ 0 });
    assert(val < 0);
    val = stream_Control(s, STREAM_GET_PTS_DELAY, &(int64_t){ 0 });
    assert(val == VLC_SUCCESS);
    stream_Delete(s);
    vlc_stream_fifo_Close(s);

    s = vlc_stream_fifo_New(parent);
    assert(s != NULL);
    val = vlc_stream_fifo_Write(s, "123", 3);
    vlc_stream_fifo_Close(s);
    val = stream_Read(s, buf, sizeof (buf));
    assert(val == 3);
    assert(memcmp(buf, "123", 3) == 0);
    val = stream_Read(s, buf, sizeof (buf));
    assert(val == 0);
    stream_Delete(s);

    s = vlc_stream_fifo_New(parent);
    assert(s != NULL);
    val = vlc_stream_fifo_Write(s, "Hello ", 6);
    assert(val == 6);
    val = vlc_stream_fifo_Write(s, "world!\n", 7);
    assert(val == 7);
    val = vlc_stream_fifo_Write(s, "blahblah", 8);
    assert(val == 8);

    val = stream_Read(s, buf, 13);
    assert(val == 13);
    assert(memcmp(buf, "Hello world!\n", 13) == 0);
    stream_Delete(s);

    val = vlc_stream_fifo_Write(s, "cough cough", 11);
    assert(val == -1 && errno == EPIPE);
    vlc_stream_fifo_Close(s);

    libvlc_release(vlc);

    return 0;
}
Esempio n. 3
0
/*****************************************************************************
 * ParseTags: check if ID3/APE tags at common locations.
 ****************************************************************************/
static int ParseTags( vlc_object_t *p_this )
{
    demux_meta_t *p_demux_meta = (demux_meta_t *)p_this;
    demux_t      *p_demux = (demux_t *)p_demux_meta->p_demux;
    bool    b_seekable;
    int64_t       i_init;

    msg_Dbg( p_demux_meta, "checking for ID3v1/2 and APEv1/2 tags" );
    stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_seekable );
    if( !b_seekable )
        return VLC_EGENERIC;

    i_init = stream_Tell( p_demux->s );

    TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments );
    p_demux_meta->p_meta = NULL;

    /* */
    CheckFooter( p_demux_meta );

    /* */
    CheckHeader( p_demux_meta );

    /* Restore position
     *  Demuxer will not see tags at the start as src/input/demux.c skips it
     *  for them
     */
    stream_Seek( p_demux->s, i_init );
    if( !p_demux_meta->p_meta && p_demux_meta->i_attachments <= 0 )
        return VLC_EGENERIC;
    return VLC_SUCCESS;
}
Esempio n. 4
0
uint64 vlc_stream_io_callback::toRead( void )
{
    uint64_t i_size;

    if( s == NULL)
        return 0;

    stream_Control( s, STREAM_GET_SIZE, &i_size );

    if( i_size == 0 )
        return UINT64_MAX;

    return (uint64) i_size - stream_Tell( s );
}
Esempio n. 5
0
int AVI_ChunkReadRoot( stream_t *s, avi_chunk_t *p_root )
{
    avi_chunk_list_t *p_list = (avi_chunk_list_t*)p_root;
    avi_chunk_t      *p_chk;
    bool b_seekable;

    stream_Control( s, STREAM_CAN_FASTSEEK, &b_seekable );

    p_list->i_chunk_pos  = 0;
    p_list->i_chunk_size = stream_Size( s );
    p_list->i_chunk_fourcc = AVIFOURCC_LIST;
    p_list->p_father = NULL;
    p_list->p_next  = NULL;
    p_list->p_first = NULL;
    p_list->p_last  = NULL;

    p_list->i_type = VLC_FOURCC( 'r', 'o', 'o', 't' );

    for( ; ; )
    {
        p_chk = malloc( sizeof( avi_chunk_t ) );
        memset( p_chk, 0, sizeof( avi_chunk_t ) );
        if( !p_root->common.p_first )
        {
            p_root->common.p_first = p_chk;
        }
        else
        {
            p_root->common.p_last->common.p_next = p_chk;
        }
        p_root->common.p_last = p_chk;

        if( AVI_ChunkRead( s, p_chk, p_root ) ||
           ( stream_Tell( s ) >=
              (off_t)p_chk->common.p_father->common.i_chunk_pos +
               (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) )
        {
            break;
        }
        /* If we can't seek then stop when we 've found first RIFF-AVI */
        if( p_chk->common.i_chunk_fourcc == AVIFOURCC_RIFF &&
            p_chk->list.i_type == AVIFOURCC_AVI && !b_seekable )
        {
            break;
        }
    }

    AVI_ChunkDumpDebug_level( (vlc_object_t*)s, p_root, 0 );
    return VLC_SUCCESS;
}
Esempio n. 6
0
/* Allow to append indexes after starting playback */
int AVI_ChunkFetchIndexes( stream_t *s, avi_chunk_t *p_riff )
{
    avi_chunk_t *p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0 );
    if ( !p_movi )
        return VLC_EGENERIC;

    avi_chunk_t *p_chk;
    uint64_t i_indexpos = 8 + p_movi->common.i_chunk_pos + p_movi->common.i_chunk_size;
    bool b_seekable = false;
    int i_ret = VLC_SUCCESS;

    stream_Control( s, STREAM_CAN_SEEK, &b_seekable );
    if ( !b_seekable || stream_Seek( s, i_indexpos ) )
        return VLC_EGENERIC;

    for( ; ; )
    {
        p_chk = xmalloc( sizeof( avi_chunk_t ) );
        memset( p_chk, 0, sizeof( avi_chunk_t ) );
        if (unlikely( !p_riff->common.p_first ))
            p_riff->common.p_first = p_chk;
        else
            p_riff->common.p_last->common.p_next = p_chk;
        p_riff->common.p_last = p_chk;

        i_ret = AVI_ChunkRead( s, p_chk, p_riff );
        if( i_ret )
            break;

        if( p_chk->common.p_father->common.i_chunk_size > 0 &&
           ( stream_Tell( s ) >
              (off_t)p_chk->common.p_father->common.i_chunk_pos +
               (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) )
        {
            break;
        }

        /* If we can't seek then stop when we 've found any index */
        if( p_chk->common.i_chunk_fourcc == AVIFOURCC_indx ||
            p_chk->common.i_chunk_fourcc == AVIFOURCC_idx1 )
        {
            break;
        }

    }

    return i_ret;
}
Esempio n. 7
0
static int OpenCallback(struct archive *p_archive, void *p_object)
{
    VLC_UNUSED(p_archive);
    callback_data_t *p_data = (callback_data_t *) p_object;
    access_sys_t *p_sys = p_data->p_access->p_sys;

    p_sys->p_stream = stream_UrlNew( p_data->p_access, p_data->psz_uri );
    if(!p_sys->p_stream)
        return ARCHIVE_FATAL;

    /* Seek callback must only be set if calls are guaranteed to succeed */
    stream_Control(p_sys->p_stream, STREAM_CAN_SEEK, &p_sys->b_source_canseek);
    if(p_sys->b_source_canseek)
        archive_read_set_seek_callback(p_sys->p_archive, SeekCallback);

    return ARCHIVE_OK;
}
Esempio n. 8
0
static bool IsTarga(stream_t *s)
{
    /* The header is not enough to ensure proper detection, we need
     * to have a look at the footer. But doing so can be slow. So
     * try to avoid it when possible */
    const uint8_t *header;
    if (stream_Peek(s, &header, 18) < 18)   /* Targa fixed header */
        return false;
    if (header[1] > 1)                      /* Color Map Type */
        return false;
    if ((header[1] != 0 || header[3 + 4] != 0) &&
        header[3 + 4] != 8  &&
        header[3 + 4] != 15 && header[3 + 4] != 16 &&
        header[3 + 4] != 24 && header[3 + 4] != 32)
        return false;
    if ((header[2] > 3 && header[2] < 9) || header[2] > 11) /* Image Type */
        return false;
    if (GetWLE(&header[8 + 4]) <= 0 ||      /* Width */
        GetWLE(&header[8 + 6]) <= 0)        /* Height */
        return false;
    if (header[8 + 8] != 8  &&
        header[8 + 8] != 15 && header[8 + 8] != 16 &&
        header[8 + 8] != 24 && header[8 + 8] != 32)
        return false;
    if (header[8 + 9] & 0xc0)               /* Reserved bits */
        return false;

    const int64_t size = stream_Size(s);
    if (size <= 18 + 26)
        return false;
    bool can_seek;
    if (stream_Control(s, STREAM_CAN_SEEK, &can_seek) || !can_seek)
        return false;

    const int64_t position = stream_Tell(s);
    if (stream_Seek(s, size - 26))
        return false;

    const uint8_t *footer;
    bool is_targa = stream_Peek(s, &footer, 26) >= 26 &&
                    !memcmp(&footer[8], "TRUEVISION-XFILE.\x00", 18);
    stream_Seek(s, position);
    return is_targa;
}
Esempio n. 9
0
static picture_t *ImageReadUrl( image_handler_t *p_image, const char *psz_url,
                                video_format_t *p_fmt_in,
                                video_format_t *p_fmt_out )
{
    block_t *p_block;
    picture_t *p_pic;
    stream_t *p_stream = NULL;
    int i_size;

    p_stream = stream_UrlNew( p_image->p_parent, psz_url );

    if( !p_stream )
    {
        msg_Dbg( p_image->p_parent, "could not open %s for reading",
                 psz_url );
        return NULL;
    }

    i_size = stream_Size( p_stream );

    p_block = block_New( p_image->p_parent, i_size );

    stream_Read( p_stream, p_block->p_buffer, i_size );

    if( !p_fmt_in->i_chroma )
    {
        char *psz_mime = NULL;
        stream_Control( p_stream, STREAM_GET_CONTENT_TYPE, &psz_mime );
        if( psz_mime )
            p_fmt_in->i_chroma = image_Mime2Fourcc( psz_mime );
        free( psz_mime );
    }
    stream_Delete( p_stream );

    if( !p_fmt_in->i_chroma )
    {
        /* Try to guess format from file name */
        p_fmt_in->i_chroma = image_Ext2Fourcc( psz_url );
    }

    p_pic = ImageRead( p_image, p_block, p_fmt_in, p_fmt_out );

    return p_pic;
}
Esempio n. 10
0
static int Control (stream_t *stream, int query, va_list args)
{
    stream_sys_t *p_sys = stream->p_sys;

    switch (query)
    {
        case STREAM_CAN_SEEK:
        case STREAM_CAN_FASTSEEK:
            *(va_arg (args, bool *)) = false;
            break;
        case STREAM_CAN_PAUSE:
             *(va_arg (args, bool *)) = p_sys->can_pause;
            break;
        case STREAM_CAN_CONTROL_PACE:
            *(va_arg (args, bool *)) = p_sys->can_pace;
            break;
        case STREAM_GET_POSITION:
            *(va_arg (args, uint64_t *)) = p_sys->offset;
            break;
        case STREAM_GET_SIZE:
            *(va_arg (args, uint64_t *)) = 0;
            break;
        case STREAM_GET_PTS_DELAY:
            *va_arg (args, int64_t *) = p_sys->pts_delay;
            break;
        case STREAM_SET_PAUSE_STATE:
        {
            bool paused = va_arg (args, unsigned);

            vlc_mutex_lock (&p_sys->lock);
            stream_Control (stream->p_source, STREAM_SET_PAUSE_STATE, paused);
            p_sys->paused = paused;
            vlc_cond_signal (&p_sys->wait);
            vlc_mutex_unlock (&p_sys->lock);
            break;
        }
        default:
            return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}
Esempio n. 11
0
File: rar.c Progetto: Flameeyes/vlc
static int SkipFile(stream_t *s, int *count, rar_file_t ***file,
                    const rar_block_t *hdr, const char *volume_mrl)
{
    const uint8_t *peek;

    int min_size = 7+21;
    if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH)
        min_size += 8;
    if (hdr->size < (unsigned)min_size)
        return VLC_EGENERIC;

    if (stream_Peek(s, &peek, min_size) < min_size)
        return VLC_EGENERIC;

    /* */
    uint32_t file_size_low = GetDWLE(&peek[7+4]);
    uint8_t  method = peek[7+18];
    uint16_t name_size = GetWLE(&peek[7+19]);
    uint32_t file_size_high = 0;
    if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH)
        file_size_high = GetDWLE(&peek[7+25]);
    const uint64_t file_size = ((uint64_t)file_size_high << 32) | file_size_low;

    char *name = calloc(1, name_size + 1);
    if (!name)
        return VLC_EGENERIC;

    const int name_offset = (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH) ? (7+33) : (7+25);
    if (name_offset + name_size <= hdr->size) {
        const int max_size = name_offset + name_size;
        if (stream_Peek(s, &peek, max_size) < max_size) {
            free(name);
            return VLC_EGENERIC;
        }
        memcpy(name, &peek[name_offset], name_size);
    }

    rar_file_t *current = NULL;
    if (method != 0x30) {
        msg_Warn(s, "Ignoring compressed file %s (method=0x%2.2x)", name, method);
        goto exit;
    }

    /* */
    if( *count > 0 )
        current = (*file)[*count - 1];

    if (current &&
        (current->is_complete ||
          strcmp(current->name, name) ||
          (hdr->flags & RAR_BLOCK_FILE_HAS_PREVIOUS) == 0))
        current = NULL;

    if (!current) {
        if (hdr->flags & RAR_BLOCK_FILE_HAS_PREVIOUS)
            goto exit;
        current = malloc(sizeof(*current));
        if (!current)
            goto exit;
        TAB_APPEND(*count, *file, current);

        current->name = name;
        current->size = file_size;
        current->is_complete = false;
        current->real_size = 0;
        TAB_INIT(current->chunk_count, current->chunk);

        name = NULL;
    }

    /* Append chunks */
    rar_file_chunk_t *chunk = malloc(sizeof(*chunk));
    if (chunk) {
        chunk->mrl = strdup(volume_mrl);
        chunk->offset = stream_Tell(s) + hdr->size;
        chunk->size = hdr->add_size;
        chunk->cummulated_size = 0;
        if (current->chunk_count > 0) {
            rar_file_chunk_t *previous = current->chunk[current->chunk_count-1];

            chunk->cummulated_size += previous->cummulated_size +
                                      previous->size;
        }

        TAB_APPEND(current->chunk_count, current->chunk, chunk);

        current->real_size += hdr->add_size;
    }
    if ((hdr->flags & RAR_BLOCK_FILE_HAS_NEXT) == 0)
        current->is_complete = true;

exit:
    /* */
    free(name);

    /* We stop on the first non empty file if we cannot seek */
    if (current) {
        bool can_seek = false;
        stream_Control(s, STREAM_CAN_SEEK, &can_seek);
        if (!can_seek && current->size > 0)
            return VLC_EGENERIC;
    }

    if (SkipBlock(s, hdr))
        return VLC_EGENERIC;
    return VLC_SUCCESS;
}
Esempio n. 12
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;

    stream->pf_read = Read;
    stream->pf_peek = Peek;
    stream->pf_control = Control;

    vlc_cond_init (&p_sys->wait);
    vlc_mutex_init (&p_sys->lock);
    p_sys->paused = false;
    p_sys->pid = -1;
    p_sys->offset = 0;
    p_sys->peeked = NULL;
    stream_Control (stream->p_source, STREAM_CAN_PAUSE, &p_sys->can_pause);
    stream_Control (stream->p_source, STREAM_CAN_CONTROL_PACE,
                    &p_sys->can_pace);
    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, (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 */
            close (uncomp[1]);
            if (ret != VLC_SUCCESS)
                close (uncomp[0]);
        }
        close (comp[0]);
        if (ret != VLC_SUCCESS)
            close (comp[1]);
    }

    if (ret == VLC_SUCCESS)
        return VLC_SUCCESS;

    if (p_sys->pid != -1)
        while (waitpid (p_sys->pid, &(int){ 0 }, 0) == -1);
Esempio n. 13
0
/****************************************************************************
 *
 * Functions to read chunks
 *
 ****************************************************************************/
static int AVI_ChunkRead_list( stream_t *s, avi_chunk_t *p_container )
{
    avi_chunk_t *p_chk;
    const uint8_t *p_peek;
    bool b_seekable;

    if( p_container->common.i_chunk_size > 0 && p_container->common.i_chunk_size < 8 )
    {
        /* empty box */
        msg_Warn( (vlc_object_t*)s, "empty list chunk" );
        return VLC_EGENERIC;
    }
    if( stream_Peek( s, &p_peek, 12 ) < 12 )
    {
        msg_Warn( (vlc_object_t*)s, "cannot peek while reading list chunk" );
        return VLC_EGENERIC;
    }

    stream_Control( s, STREAM_CAN_FASTSEEK, &b_seekable );

    p_container->list.i_type = GetFOURCC( p_peek + 8 );

    /* XXX fixed for on2 hack */
    if( p_container->common.i_chunk_fourcc == AVIFOURCC_ON2 && p_container->list.i_type == AVIFOURCC_ON2f )
    {
        p_container->common.i_chunk_fourcc = AVIFOURCC_RIFF;
        p_container->list.i_type = AVIFOURCC_AVI;
    }

    if( p_container->common.i_chunk_fourcc == AVIFOURCC_LIST &&
        p_container->list.i_type == AVIFOURCC_movi )
    {
        msg_Dbg( (vlc_object_t*)s, "skipping movi chunk" );
        if( b_seekable )
        {
            return AVI_NextChunk( s, p_container );
        }
        return VLC_SUCCESS; /* point at begining of LIST-movi */
    }

    if( stream_Read( s, NULL, 12 ) != 12 )
    {
        msg_Warn( (vlc_object_t*)s, "cannot enter chunk" );
        return VLC_EGENERIC;
    }

#ifdef AVI_DEBUG
    msg_Dbg( (vlc_object_t*)s,
             "found LIST chunk: \'%4.4s\'",
             (char*)&p_container->list.i_type );
#endif
    msg_Dbg( (vlc_object_t*)s, "<list \'%4.4s\'>", (char*)&p_container->list.i_type );
    for( ; ; )
    {
        p_chk = malloc( sizeof( avi_chunk_t ) );
        memset( p_chk, 0, sizeof( avi_chunk_t ) );
        if( !p_container->common.p_first )
        {
            p_container->common.p_first = p_chk;
        }
        else
        {
            p_container->common.p_last->common.p_next = p_chk;
        }
        p_container->common.p_last = p_chk;

        if( AVI_ChunkRead( s, p_chk, p_container ) )
        {
            break;
        }
        if( p_chk->common.p_father->common.i_chunk_size > 0 &&
           ( stream_Tell( s ) >
              (off_t)p_chk->common.p_father->common.i_chunk_pos +
               (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) )
        {
            break;
        }

        /* If we can't seek then stop when we 've found LIST-movi */
        if( p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST &&
            p_chk->list.i_type == AVIFOURCC_movi &&
            ( !b_seekable || p_chk->common.i_chunk_size == 0 ) )
        {
            break;
        }

    }
    msg_Dbg( (vlc_object_t*)s, "</list \'%4.4s\'>", (char*)&p_container->list.i_type );

    return VLC_SUCCESS;
}
Esempio n. 14
0
static int ControlSetTime( demux_t *p_demux, int64_t i_time )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    int64_t i_delta_time;
    bool b_seekable;
    int i;

    /* */
    stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_seekable );
    if( !b_seekable )
        return VLC_EGENERIC;

    /* */
    assert( p_sys->i_seekpoint > 0 );   /* ReadMeta ensure at least (0,0) */
    for( i = p_sys->i_seekpoint-1; i >= 0; i-- )
    {
        if( p_sys->seekpoint[i]->i_time_offset <= i_time )
            break;
    }
    i_delta_time = i_time - p_sys->seekpoint[i]->i_time_offset;

    /* XXX We do exact seek if it's not too far away(45s) */
    if( i_delta_time < 45*INT64_C(1000000) )
    {
        if( stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos ) )
            return VLC_EGENERIC;

        p_sys->i_time_offset = p_sys->seekpoint[i]->i_time_offset - p_sys->i_pts;
        p_sys->i_pts_start = p_sys->i_pts+i_delta_time;
        es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, p_sys->i_pts_start + p_sys->i_time_offset );
    }
    else
    {
        int64_t i_delta_offset;
        int64_t i_next_time;
        int64_t i_next_offset;

        if( i+1 < p_sys->i_seekpoint )
        {
            i_next_time   = p_sys->seekpoint[i+1]->i_time_offset;
            i_next_offset = p_sys->seekpoint[i+1]->i_byte_offset;
        }
        else
        {
            i_next_time   = p_sys->i_length;
            i_next_offset = stream_Size(p_demux->s)-p_sys->i_data_pos;
        }

        i_delta_offset = 0;
        if( i_next_time-p_sys->seekpoint[i]->i_time_offset > 0 )
            i_delta_offset = (i_next_offset - p_sys->seekpoint[i]->i_byte_offset) * i_delta_time /
                             (i_next_time-p_sys->seekpoint[i]->i_time_offset);

        if( stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos + i_delta_offset ) )
            return VLC_EGENERIC;

        p_sys->i_pts_start = p_sys->i_pts;
        p_sys->i_time_offset = (p_sys->seekpoint[i]->i_time_offset+i_delta_time) - p_sys->i_pts;
    }
    return VLC_SUCCESS;
}
Esempio n. 15
0
static int AStreamSeekStream(stream_t *s, uint64_t i_pos)
{
    stream_sys_t *sys = s->p_sys;
    stream_track_t *p_current = &sys->tk[sys->i_tk];

    if (p_current->i_start >= p_current->i_end  && i_pos >= p_current->i_end)
        return 0; /* EOF */

#ifdef STREAM_DEBUG
    msg_Dbg(s, "AStreamSeekStream: to %"PRId64" pos=%"PRId64
             " tk=%d start=%"PRId64" offset=%d end=%"PRId64,
             i_pos, sys->i_pos, sys->i_tk, p_current->i_start,
             sys->i_offset, p_current->i_end);
#endif

    bool   b_aseek;
    stream_Control(s->p_source, STREAM_CAN_SEEK, &b_aseek);
    if (!b_aseek && i_pos < p_current->i_start)
    {
        msg_Warn(s, "AStreamSeekStream: can't seek");
        return VLC_EGENERIC;
    }

    bool   b_afastseek;
    stream_Control(s->p_source, STREAM_CAN_FASTSEEK, &b_afastseek);

    /* FIXME compute seek cost (instead of static 'stupid' value) */
    uint64_t i_skip_threshold;
    if (b_aseek)
        i_skip_threshold = b_afastseek ? 128 : 3 * sys->i_read_size;
    else
        i_skip_threshold = INT64_MAX;

    /* Date the current track */
    p_current->date = mdate();

    /* Search a new track slot */
    stream_track_t *tk = NULL;
    int i_tk_idx = -1;

    /* Prefer the current track */
    if (p_current->i_start <= i_pos && i_pos <= p_current->i_end + i_skip_threshold)
    {
        tk = p_current;
        i_tk_idx = sys->i_tk;
    }
    if (!tk)
    {
        /* Try to maximize already read data */
        for (int i = 0; i < STREAM_CACHE_TRACK; i++)
        {
            stream_track_t *t = &sys->tk[i];

            if (t->i_start > i_pos || i_pos > t->i_end)
                continue;

            if (!tk || tk->i_end < t->i_end)
            {
                tk = t;
                i_tk_idx = i;
            }
        }
    }
    if (!tk)
    {
        /* Use the oldest unused */
        for (int i = 0; i < STREAM_CACHE_TRACK; i++)
        {
            stream_track_t *t = &sys->tk[i];

            if (!tk || tk->date > t->date)
            {
                tk = t;
                i_tk_idx = i;
            }
        }
    }
    assert(i_tk_idx >= 0 && i_tk_idx < STREAM_CACHE_TRACK);

    if (tk != p_current)
        i_skip_threshold = 0;
    if (tk->i_start <= i_pos && i_pos <= tk->i_end + i_skip_threshold)
    {
#ifdef STREAM_DEBUG
        msg_Err(s, "AStreamSeekStream: reusing %d start=%"PRId64
                 " end=%"PRId64"(%s)",
                 i_tk_idx, tk->i_start, tk->i_end,
                 tk != p_current ? "seek" : i_pos > tk->i_end ? "skip" : "noseek");
#endif
        if (tk != p_current)
        {
            assert(b_aseek);

            /* Seek at the end of the buffer
             * TODO it is stupid to seek now, it would be better to delay it
             */
            if (stream_Seek(s->p_source, tk->i_end))
            {
                msg_Err(s, "AStreamSeekStream: hard seek failed");
                return VLC_EGENERIC;
            }
        }
        else if (i_pos > tk->i_end)
        {
            uint64_t i_skip = i_pos - tk->i_end;
            while (i_skip > 0)
            {
                const int i_read_max = __MIN(10 * STREAM_READ_ATONCE, i_skip);
                int i_read = 0;
                if ((i_read = AStreamReadNoSeekStream(s, NULL, i_read_max)) < 0)
                {
                    msg_Err(s, "AStreamSeekStream: skip failed");
                    return VLC_EGENERIC;
                } else if (i_read == 0)
                    return VLC_SUCCESS; /* EOF */
                i_skip -= i_read_max;
            }
        }
    }
    else
    {
#ifdef STREAM_DEBUG
        msg_Err(s, "AStreamSeekStream: hard seek");
#endif
        /* Nothing good, seek and choose oldest segment */
        if (stream_Seek(s->p_source, i_pos))
        {
            msg_Err(s, "AStreamSeekStream: hard seek failed");
            return VLC_EGENERIC;
        }

        tk->i_start = i_pos;
        tk->i_end   = i_pos;
    }
    sys->i_offset = i_pos - tk->i_start;
    sys->i_tk = i_tk_idx;
    sys->i_pos = i_pos;

    /* If there is not enough data left in the track, refill  */
    /* TODO How to get a correct value for
     *    - refilling threshold
     *    - how much to refill
     */
    if (tk->i_end < tk->i_start + sys->i_offset + sys->i_read_size)
    {
        if (sys->i_used < STREAM_READ_ATONCE / 2)
            sys->i_used = STREAM_READ_ATONCE / 2;

        if (AStreamRefillStream(s))
            return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}