Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/src/misc/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 14 kB image not shown  

Quelle  frame.c   Sprache: C

 

/*****************************************************************************
 * frame.c: frames management functions
 *****************************************************************************
 * Copyright (C) 2003-2004 VLC authors and VideoLAN
 * Copyright (C) 2007-2009 Rémi Denis-Courmont
 *
 * Authors: Laurent Aimar <fenrir@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef _WIN32
# include <windows.h>
#endif

#include <vlc_common.h>
#include <vlc_atomic.h>
#include <vlc_frame.h>
#include <vlc_fs.h>

#include <vlc_ancillary.h>

#ifndef NDEBUG
static void vlc_frame_Check (vlc_frame_t *frame)
{
    while (frame != NULL)
    {
        unsigned char *start = frame->p_start;
        unsigned char *end = frame->p_start + frame->i_size;
        unsigned char *bufstart = frame->p_buffer;
        unsigned char *bufend = frame->p_buffer + frame->i_buffer;

        assert (start <= end);
        assert (bufstart <= bufend);
        assert (bufstart >= start);
        assert (bufend <= end);

        frame = frame->p_next;
    }
}
#else
# define vlc_frame_Check(b) ((void)(b))
#endif

void vlc_frame_CopyProperties(vlc_frame_t *restrict dst, const vlc_frame_t *src)
{
    vlc_ancillary_array_Merge(&dst->ancillaries,
                              &src->ancillaries);

    dst->i_flags   = src->i_flags;
    dst->i_nb_samples = src->i_nb_samples;
    dst->i_dts     = src->i_dts;
    dst->i_pts     = src->i_pts;
    dst->i_length  = src->i_length;
}

vlc_frame_t *vlc_frame_New(const struct vlc_frame_callbacks *cbs,
                           void *buf, size_t size)
{
    vlc_frame_t *f = malloc(sizeof (*f));
    if (unlikely(f == NULL))
        return NULL;

    return vlc_frame_Init(f, cbs, buf, size);
}

vlc_frame_t *vlc_frame_Init(vlc_frame_t *restrict f, const struct vlc_frame_callbacks *cbs,
                            void *buf, size_t size)
{
    /* Fill all fields to their default */
    f->p_next = NULL;
    f->p_buffer = buf;
    f->i_buffer = size;
    f->p_start = buf;
    f->i_size = size;
    f->i_flags = 0;
    f->i_nb_samples = 0;
    f->i_pts =
    f->i_dts = VLC_TICK_INVALID;
    f->i_length = 0;
    vlc_ancillary_array_Init(&f->ancillaries);
    f->cbs = cbs;
    return f;
}

/** Initial memory alignment of data frame.
 * @note This must be a multiple of sizeof(void*) and a power of two.
 * libavcodec AVX optimizations require at least 32-bytes. */

#define VLC_FRAME_ALIGN        32

/** Initial reserved header and footer size. */
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
# define VLC_FRAME_PADDING      0 /* Don't hide buffer overflows */
#else
# define VLC_FRAME_PADDING      32 /* Avoid <= 32 bytes reallocs */
#endif

vlc_frame_t *vlc_frame_Alloc (size_t size)
{
    if (unlikely(size >> 28))
    {
        errno = ENOBUFS;
        return NULL;
    }

    static_assert ((VLC_FRAME_PADDING % VLC_FRAME_ALIGN) == 0,
                   "VLC_FRAME_PADDING must be a multiple of VLC_FRAME_ALIGN");

    /* 2 * VLC_FRAME_PADDING: pre + post padding */
    size_t capacity = (2 * VLC_FRAME_PADDING) + size;
    unsigned char *buf;
#ifdef HAVE_ALIGNED_ALLOC
    capacity += (-size) % VLC_FRAME_ALIGN;
    buf = aligned_alloc(VLC_FRAME_ALIGN, capacity);
#else
    capacity += VLC_FRAME_ALIGN;
    buf = malloc(capacity);
#endif
    if (unlikely(buf == NULL))
        return NULL;

    vlc_frame_t *f = vlc_frame_heap_Alloc(buf, capacity);
    if (likely(f != NULL)) {
#ifndef HAVE_ALIGNED_ALLOC
        /* Alignment */
        buf += (-(uintptr_t)(void *)buf) % (uintptr_t)VLC_FRAME_ALIGN;
#endif
        /* Header reserve */
        buf += VLC_FRAME_PADDING;
        f->p_buffer = buf;
        f->i_buffer = size;
    }

    return f;
}

void vlc_frame_Release(vlc_frame_t *frame)
{
#ifndef NDEBUG
    frame->p_next = NULL;
    vlc_frame_Check (frame);
#endif
    vlc_ancillary_array_Clear(&frame->ancillaries);

    frame->cbs->free(frame);
}

static vlc_frame_t *vlc_frame_ReallocDup( vlc_frame_t *frame, ssize_t i_prebody, size_t requested )
{
    vlc_frame_t *p_rea = vlc_frame_Alloc( requested );
    if( p_rea == NULL )
        return NULL;

    if( frame->i_buffer > 0 )
        memcpy( p_rea->p_buffer + i_prebody, frame->p_buffer, frame->i_buffer );

    p_rea->p_next = frame->p_next;
    vlc_frame_CopyProperties( p_rea, frame );

    vlc_frame_Release( frame );
    return p_rea;
}

vlc_frame_t *vlc_frame_TryRealloc (vlc_frame_t *frame, ssize_t i_prebody, size_t i_body)
{
    vlc_frame_Check( frame );

    /* Corner case: empty frame requested */
    if( i_prebody <= 0 && i_body <= (size_t)(-i_prebody) )
        i_prebody = i_body = 0;

    assert( frame->p_start <= frame->p_buffer );
    assert( frame->p_start + frame->i_size
                                    >= frame->p_buffer + frame->i_buffer );

    /* First, shrink payload */

    /* Pull payload start */
    if( i_prebody < 0 )
    {
        if( frame->i_buffer >= (size_t)-i_prebody )
        {
            frame->p_buffer -= i_prebody;
            frame->i_buffer += i_prebody;
        }
        else /* Discard current payload entirely */
            frame->i_buffer = 0;
        i_body += i_prebody;
        i_prebody = 0;
    }

    /* Trim payload end */
    if( frame->i_buffer > i_body )
        frame->i_buffer = i_body;

    size_t requested = i_prebody + i_body;

    if( frame->i_buffer == 0 )
    {   /* Corner case: nothing to preserve */
        if( requested <= frame->i_size )
        {   /* Enough room: recycle buffer */
            size_t extra = frame->i_size - requested;

            frame->p_buffer = frame->p_start + (extra / 2);
            frame->i_buffer = requested;
            return frame;
        }

        /* Not enough room: allocate a new buffer */
        return vlc_frame_ReallocDup( frame, i_prebody, requested );
    }

    uint8_t *p_start = frame->p_start;
    uint8_t *p_end = p_start + frame->i_size;

    /* Second, reallocate the buffer if we lack space. */
    assert( i_prebody >= 0 );
    if( (size_t)(frame->p_buffer - p_start) < (size_t)i_prebody
     || (size_t)(p_end - frame->p_buffer) < i_body )
        return vlc_frame_ReallocDup( frame, i_prebody, requested );

    /* Third, expand payload */

    /* Push payload start */
    if( i_prebody > 0 )
    {
        frame->p_buffer -= i_prebody;
        frame->i_buffer += i_prebody;
        i_body += i_prebody;
        i_prebody = 0;
    }

    /* Expand payload to requested size */
    frame->i_buffer = i_body;

    return frame;
}

vlc_frame_t *vlc_frame_Realloc (vlc_frame_t *frame, ssize_t prebody, size_t body)
{
    vlc_frame_t *rea = vlc_frame_TryRealloc (frame, prebody, body);
    if (rea == NULL)
        vlc_frame_Release(frame);
    return rea;
}

static void vlc_frame_heap_Release (vlc_frame_t *frame)
{
    free (frame->p_start);
    free (frame);
}

static const struct vlc_frame_callbacks vlc_frame_heap_cbs =
{
    vlc_frame_heap_Release,
};

vlc_frame_t *vlc_frame_heap_Alloc (void *addr, size_t length)
{
    vlc_frame_t *frame = vlc_frame_New(&vlc_frame_heap_cbs, addr, length);
    if (unlikely(frame == NULL))
        free(addr);
    return frame;
}

#ifdef HAVE_MMAP
# include <sys/mman.h>

static void vlc_frame_mmap_Release (vlc_frame_t *frame)
{
    munmap (frame->p_start, frame->i_size);
    free (frame);
}

static const struct vlc_frame_callbacks vlc_frame_mmap_cbs =
{
    vlc_frame_mmap_Release,
};

vlc_frame_t *vlc_frame_mmap_Alloc (void *addr, size_t length)
{
    if (addr == MAP_FAILED)
        return NULL;

    long page_mask = sysconf(_SC_PAGESIZE) - 1;
    size_t left = ((uintptr_t)addr) & page_mask;
    size_t right = (-length) & page_mask;
    vlc_frame_t *frame = vlc_frame_New(&vlc_frame_mmap_cbs,
                                       ((char *)addr) - left,
                                       left + length + right);
    if (likely(frame != NULL)) {
        frame->p_buffer = addr;
        frame->i_buffer = length;
    } else
        munmap(addr, length);
    return frame;
}
#else
vlc_frame_t *vlc_frame_mmap_Alloc (void *addr, size_t length)
{
    (void)addr; (void)length; return NULL;
}
#endif
#if defined(_WIN32)
struct vlc_frame_mv
{
    vlc_frame_t b;
    HANDLE  hMap;
};

static void vlc_frame_mapview_Release (vlc_frame_t *frame)
{
    struct vlc_frame_mv *mvframe = container_of(frame, struct vlc_frame_mv, b);

    UnmapViewOfFile(frame->p_start);
    CloseHandle(mvframe->hMap);
    free(mvframe);
}

static const struct vlc_frame_callbacks vlc_frame_mapview_cbs =
{
    vlc_frame_mapview_Release,
};

static vlc_frame_t *vlc_frame_mapview_Alloc(HANDLE hMap, void *addr, size_t length)
{
    struct vlc_frame_mv *mvframe = malloc (sizeof (*mvframe));
    if (unlikely(mvframe == NULL))
    {
        UnmapViewOfFile(addr);
        CloseHandle(hMap);
        return NULL;
    }
    mvframe->hMap = hMap;

    vlc_frame_t *frame = &mvframe->b;
    vlc_frame_Init(frame, &vlc_frame_mapview_cbs, addr, length);
    return frame;
}
#endif

#ifdef HAVE_SYS_SHM_H
# include <sys/shm.h>

static void vlc_frame_shm_Release (vlc_frame_t *frame)
{
    shmdt(frame->p_start);
    free(frame);
}

static const struct vlc_frame_callbacks vlc_frame_shm_cbs =
{
    vlc_frame_shm_Release,
};

vlc_frame_t *vlc_frame_shm_Alloc (void *addr, size_t length)
{
    vlc_frame_t *frame = vlc_frame_New(&vlc_frame_shm_cbs, (uint8_t *)addr,
                                       length);
    if (unlikely(frame == NULL))
        shmdt(addr);
    return frame;
}
#else
vlc_frame_t *vlc_frame_shm_Alloc (void *addr, size_t length)
{
    (void) addr; (void) length;
    abort ();
}
#endif


#ifdef _WIN32
static void cleanup_hmap(void *opaque)
{
    HANDLE hMap = opaque;
    CloseHandle(hMap);
}
#endif

vlc_frame_t *vlc_frame_File(int fd, bool write)
{
    size_t length;
    struct stat st;

    /* First, get the file size */
    if (fstat (fd, &st))
        return NULL;

    /* st_size is meaningful for regular files, shared memory and typed memory.
     * It's also meaning for symlinks, but that's not possible with fstat().
     * In other cases, it's undefined, and we should really not go further. */

#ifndef S_TYPEISSHM
# define S_TYPEISSHM( buf ) (0)
#endif
    if (S_ISDIR (st.st_mode))
    {
        errno = EISDIR;
        return NULL;
    }
    if (!S_ISREG (st.st_mode) && !S_TYPEISSHM (&st))
    {
        errno = ESPIPE;
        return NULL;
    }

    /* Prevent an integer overflow in mmap() and malloc() */
    if ((uintmax_t)st.st_size >= SIZE_MAX)
    {
        errno = ENOMEM;
        return NULL;
    }
    length = (size_t)st.st_size;

#ifdef HAVE_MMAP
    if (length > 0)
    {
        int prot = PROT_READ | (write ? PROT_WRITE : 0);
        int flags = write ? MAP_PRIVATE : MAP_SHARED;
        void *addr = mmap(NULL, length, prot, flags, fd, 0);

        if (addr != MAP_FAILED)
            return vlc_frame_mmap_Alloc (addr, length);
    }
#elif defined(_WIN32)
    HANDLE handle = INVALID_HANDLE_VALUE;
    if (length > 0)
    {
        handle = (HANDLE)(intptr_t)_get_osfhandle (fd);
        if (handle == INVALID_HANDLE_VALUE)
        {
            errno = EBADF;
            return NULL;
        }

        void *addr = NULL;
        HANDLE hMap;
        DWORD prot = write ? PAGE_READWRITE : PAGE_READONLY;
        DWORD access = FILE_MAP_READ | (write ? FILE_MAP_WRITE : 0);
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
        hMap = CreateFileMappingFromApp(handle, NULL, prot, length, NULL);
        if (hMap != INVALID_HANDLE_VALUE)
            addr = MapViewOfFileFromApp(hMap, access, 0, length);
#else
        DWORD hLength = (DWORD)(length >> 32);
        DWORD lLength = (DWORD)(length & 0xFFFFFFFF);
        hMap = CreateFileMapping(handle, NULL, prot, hLength, lLength, NULL);
        if (hMap != INVALID_HANDLE_VALUE)
            addr = MapViewOfFile(hMap, access, 0, 0, length);
#endif
        vlc_cleanup_push(cleanup_hmap, hMap);
        vlc_testcancel();
        vlc_cleanup_pop();

        if (addr != NULL)
            return vlc_frame_mapview_Alloc(hMap, addr, length);

        CloseHandle(hMap);
    }
#else
    (void) write;
#endif

    /* If mmap() is not implemented by the OS _or_ the filesystem... */
    vlc_frame_t *frame = vlc_frame_Alloc (length);
    if (frame == NULL)
        return NULL;
    vlc_frame_cleanup_push (frame);

#if defined(_WIN32)
    LARGE_INTEGER srcPointer = { 0 };
    if (unlikely(!SetFilePointerEx(handle, srcPointer, &srcPointer, FILE_CURRENT)))
    {
        vlc_frame_Release (frame);
        frame = NULL;
        errno = EIO;
        goto done;
    }
    LARGE_INTEGER startPointer = { 0 };
    if (unlikely(!SetFilePointerEx(handle, startPointer, NULL, FILE_BEGIN)))
    {
        vlc_frame_Release (frame);
        frame = NULL;
        errno = EIO;
        goto done;
    }
    for (size_t i = 0; i < length;)
    {
        DWORD hOffset = (DWORD)(i >> 32);
        DWORD lOffset = (DWORD)(i & 0xFFFFFFFF);
        OVERLAPPED olap = {.Offset = hOffset, .OffsetHigh = lOffset};
        DWORD lLength = (length - i) > ULONG_MAX ? ULONG_MAX : (DWORD)(length - i);
        DWORD len;
        if (!ReadFile(handle, frame->p_buffer + i, lLength, &len, &olap))
        {
            vlc_frame_Release (frame);
            frame = NULL;
            errno = EIO;
            break;
        }
        vlc_testcancel();
        i += len;
    }
    if (frame != NULL && unlikely(!SetFilePointerEx(handle, srcPointer, NULL, FILE_BEGIN)))
    {
        vlc_frame_Release (frame);
        frame = NULL;
        errno = EIO;
    }
done:
#else // !_WIN32
    for (size_t i = 0; i < length;)
    {
        ssize_t len = pread (fd, frame->p_buffer + i, length - i, i);
        if (len == -1)
        {
            vlc_frame_Release (frame);
            frame = NULL;
            break;
        }
        i += len;
    }
#endif // !_WIN32
    vlc_cleanup_pop ();
    return frame;
}

vlc_frame_t *vlc_frame_FilePath(const char *path, bool write)
{
    /* NOTE: Writeable shared mappings are not supported here. So there are no
     * needs to open the file for writing (even if the mapping is writable). */

    int fd = vlc_open (path, O_RDONLY);
    if (fd == -1)
        return NULL;

    vlc_frame_t *frame = vlc_frame_File(fd, write);
    vlc_close (fd);
    return frame;
}

Messung
CHZG
849510093

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.