Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  image.c   Sprache: C

 

/*****************************************************************************
 * image.c: Image demuxer
 *****************************************************************************
 * Copyright (C) 2010 Laurent Aimar
 *
 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ 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.
 *****************************************************************************/


/*****************************************************************************
 * Preamble
 *****************************************************************************/


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

#include <assert.h>

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_demux.h>
#include <vlc_image.h>
#include <vlc_ancillary.h>
#include "mxpeg_helper.h"

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/

static int  Open (vlc_object_t *);
static void Close(vlc_object_t *);

#define ID_TEXT N_("ES ID")
#define ID_LONGTEXT N_( \
    "Set the ID of the elementary stream")

#define GROUP_TEXT N_("Group")
#define GROUP_LONGTEXT N_(\
    "Set the group of the elementary stream")

#define DECODE_TEXT N_("Decode")
#define DECODE_LONGTEXT N_( \
    "Decode at the demuxer stage")

#define CHROMA_TEXT N_("Forced chroma")
#define CHROMA_LONGTEXT N_( \
    "If non empty and image-decode is true, the image will be " \
    "converted to the specified chroma.")

#define DURATION_TEXT N_("Duration in seconds")
#define DURATION_LONGTEXT N_( \
    "Duration in seconds before simulating an end of file. " \
    "A negative value means an unlimited play time.")

#define FPS_TEXT N_("Frame rate")
#define FPS_LONGTEXT N_( \
    "Frame rate of the elementary stream produced.")

#define RT_TEXT N_("Real-time")
#define RT_LONGTEXT N_( \
    "Use real-time mode suitable for being used as a master input and " \
    "real-time input slaves.")

vlc_module_begin()
    set_description(N_("Image demuxer"))
    set_shortname(N_("Image"))
    set_subcategory(SUBCAT_INPUT_DEMUX)
    add_integer("image-id", -1, ID_TEXT, ID_LONGTEXT)
        change_safe()
    add_integer("image-group", 0, GROUP_TEXT, GROUP_LONGTEXT)
        change_safe()
    add_bool("image-decode", true, DECODE_TEXT, DECODE_LONGTEXT)
        change_safe()
    add_string("image-chroma", NULL, CHROMA_TEXT, CHROMA_LONGTEXT)
        change_safe()
    add_float("image-duration", 10, DURATION_TEXT, DURATION_LONGTEXT)
        change_safe()
    add_string("image-fps", "10/1", FPS_TEXT, FPS_LONGTEXT)
        change_safe()
    add_bool("image-realtime", false, RT_TEXT, RT_LONGTEXT)
        change_safe()
    set_capability("demux", 10)
    set_callbacks(Open, Close)
vlc_module_end()

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/

typedef struct
{
    block_t     *data;
    es_out_id_t *es;
    vlc_tick_t  duration;
    bool        is_realtime;
    vlc_tick_t  pts_offset;
    vlc_tick_t  pts_next;
    date_t        pts;
} demux_sys_t;

static block_t *Load(demux_t *demux)
{
    const unsigned max_size = 4096 * 4096 * 8;
    uint64_t size;

    if (vlc_stream_GetSize(demux->s, &size) == VLC_SUCCESS) {
        if (size > max_size) {
            msg_Err(demux, "image too large (%"PRIu64" > %u), rejected",
                    size, max_size);
            return NULL;
        }
    } else
        size = max_size;

    block_t *block = block_Alloc(size);
    if (block == NULL)
        return NULL;

    ssize_t val = vlc_stream_Read(demux->s, block->p_buffer, size);
    if (val < 0) {
        block_Release(block);
        return NULL;
    }

    block->i_buffer = val;
    return block;
}

static block_t *Decode(demux_t *demux,
                       es_format_t *fmt, vlc_fourcc_t chroma, block_t *data)
{
    image_handler_t *handler = image_HandlerCreate(demux);
    if (!handler) {
        block_Release(data);
        return NULL;
    }

    video_format_t decoded;
    video_format_Init(&decoded, chroma);

    picture_t *image = image_Read(handler, data, fmt, &decoded);
    image_HandlerDelete(handler);

    if (!image)
        return NULL;

    es_format_Clean(fmt);
    es_format_InitFromVideo(fmt, &decoded);
    video_format_Clean(&decoded);

    size_t size = 0;
    for (int i = 0; i < image->i_planes; i++)
        size += image->p[i].i_pitch * image->p[i].i_lines;

    data = block_Alloc(size);
    if (!data) {
        picture_Release(image);
        return NULL;
    }

    size_t offset = 0;
    for (int i = 0; i < image->i_planes; i++) {
        const plane_t *src = &image->p[i];
        for (int y = 0; y < src->i_visible_lines; y++) {
            memcpy(&data->p_buffer[offset],
                   &src->p_pixels[y * src->i_pitch],
                   src->i_visible_pitch);
            offset += src->i_visible_pitch;
        }
    }

    // Preserve important metadata
    struct vlc_ancillary *ancillary;
    ancillary = picture_GetAncillary(image, VLC_ANCILLARY_ID_ICC);
    if (ancillary)
        vlc_frame_AttachAncillary(data, ancillary);

    picture_Release(image);
    return data;
}

static int Demux(demux_t *demux)
{
    demux_sys_t *sys = demux->p_sys;

    if (!sys->data)
        return VLC_DEMUXER_EOF;

    vlc_tick_t deadline;
    const vlc_tick_t pts_first = sys->pts_offset + date_Get(&sys->pts);
    if (sys->pts_next != VLC_TICK_INVALID) {
        deadline = sys->pts_next;
    } else if (sys->is_realtime) {
        deadline = vlc_tick_now();
        const vlc_tick_t max_wait = VLC_TICK_FROM_MS(20);
        if (deadline + max_wait < pts_first) {
            es_out_SetPCR(demux->out, deadline);
            /* That's ugly, but not yet easily fixable */
            vlc_tick_wait(deadline + max_wait);
            return VLC_DEMUXER_SUCCESS;
        }
    } else {
        deadline = 1 + pts_first;
    }

    for (;;) {
        const vlc_tick_t pts = sys->pts_offset + date_Get(&sys->pts);
        if (sys->duration >= 0 && pts >= VLC_TICK_0 + sys->pts_offset + sys->duration)
            return VLC_DEMUXER_EOF;

        if (pts >= deadline)
            return VLC_DEMUXER_SUCCESS;

        block_t *data = block_Duplicate(sys->data);
        if (!data)
            return VLC_DEMUXER_EGENERIC;

        data->i_dts =
        data->i_pts = VLC_TICK_0 + pts;
        es_out_SetPCR(demux->out, data->i_pts);
        if(sys->es)
            es_out_Send(demux->out, sys->es, data);
        else
            block_Release(data);

        date_Increment(&sys->pts, 1);
    }
}

static int Control(demux_t *demux, int query, va_list args)
{
    demux_sys_t *sys = demux->p_sys;

    switch (query) {
    case DEMUX_CAN_SEEK:
        *va_arg(args, bool *) = sys->duration >= 0 && !sys->is_realtime;
        return VLC_SUCCESS;
    case DEMUX_GET_POSITION: {
        double *position = va_arg(args, double *);
        if (sys->duration > 0)
            *position = date_Get(&sys->pts) / (double)sys->duration;
        else
            *position = 0;
        return VLC_SUCCESS;
    }
    case DEMUX_SET_POSITION: {
        if (sys->duration < 0 || sys->is_realtime)
            return VLC_EGENERIC;
        double position = va_arg(args, double);
        date_Set(&sys->pts, position * sys->duration);
        return VLC_SUCCESS;
    }
    case DEMUX_GET_TIME: {
        *va_arg(args, vlc_tick_t *) = sys->pts_offset + date_Get(&sys->pts);
        return VLC_SUCCESS;
    }
    case DEMUX_SET_TIME: {
        if (sys->duration < 0 || sys->is_realtime)
            return VLC_EGENERIC;
        vlc_tick_t time = va_arg(args, vlc_tick_t);
        date_Set(&sys->pts, VLC_CLIP(time - sys->pts_offset, VLC_TICK_0, sys->duration));
        return VLC_SUCCESS;
    }
    case DEMUX_SET_NEXT_DEMUX_TIME: {
        vlc_tick_t pts_next = VLC_TICK_0 + va_arg(args, vlc_tick_t);
        if (sys->pts_next == VLC_TICK_INVALID)
            sys->pts_offset = pts_next - VLC_TICK_0;
        sys->pts_next = pts_next;
        return VLC_SUCCESS;
    }
    case DEMUX_GET_LENGTH: {
        *va_arg(args, vlc_tick_t *) = __MAX(sys->duration, 0);
        return VLC_SUCCESS;
    }
    case DEMUX_GET_FPS: {
        double *fps = va_arg(args, double *);
        *fps = (double)sys->pts.i_divider_num / sys->pts.i_divider_den;
        return VLC_SUCCESS;
    }
    case DEMUX_GET_META:
    case DEMUX_HAS_UNSUPPORTED_META:
    case DEMUX_GET_ATTACHMENTS:
        return VLC_EGENERIC;

    case DEMUX_CAN_PAUSE:
    case DEMUX_SET_PAUSE_STATE:
    case DEMUX_CAN_CONTROL_PACE:
    case DEMUX_GET_PTS_DELAY:
        return demux_vaControlHelper( demux->s, 0, -1, 0, 1, query, args );

    default:
        return VLC_EGENERIC;

    }
}

static bool IsBmp(stream_t *s)
{
    const uint8_t *header;
    if (vlc_stream_Peek(s, &header, 18) < 18)
        return false;
    if (memcmp(header, "BM", 2) &&
        memcmp(header, "BA", 2) &&
        memcmp(header, "CI", 2) &&
        memcmp(header, "CP", 2) &&
        memcmp(header, "IC", 2) &&
        memcmp(header, "PT", 2))
        return false;
    uint32_t file_size   = GetDWLE(&header[2]);
    uint32_t data_offset = GetDWLE(&header[10]);
    uint32_t header_size = GetDWLE(&header[14]);
    if (file_size != 14 && file_size != 14 + header_size &&
        file_size <= data_offset)
        return false;
    if (data_offset < header_size + 14)
        return false;
    static const uint8_t header_sizes[] = { 12, 40, 56, 64, 108, 124 };
    return memchr(header_sizes, header_size, ARRAY_SIZE(header_sizes)) != NULL;
}

static bool IsPcx(stream_t *s)
{
    const uint8_t *header;
    if (vlc_stream_Peek(s, &header, 66) < 66)
        return false;
    if (header[0] != 0x0A ||                        /* marker */
        (header[1] != 0x00 && header[1] != 0x02 &&
         header[1] != 0x03 && header[1] != 0x05) || /* version */
        (header[2] != 0 && header[2] != 1) ||       /* encoding */
        (header[3] != 1 && header[3] != 2 &&
         header[3] != 4 && header[3] != 8) ||       /* bits per pixel per plane */
        header[64] != 0 ||                          /* reserved */
        header[65] == 0 || header[65] > 4)          /* plane count */
        return false;
    if (GetWLE(&header[4]) > GetWLE(&header[8]) ||  /* xmin vs xmax */
        GetWLE(&header[6]) > GetWLE(&header[10]))   /* ymin vs ymax */
        return false;
    return true;
}

static bool IsLbm(stream_t *s)
{
    const uint8_t *header;
    if (vlc_stream_Peek(s, &header, 12) < 12)
        return false;
    if (memcmp(&header[0], "FORM", 4) ||
        GetDWBE(&header[4]) <= 4 ||
        (memcmp(&header[8], "ILBM", 4) && memcmp(&header[8], "PBM ", 4)))
        return false;
    return true;
}
static bool IsPnmBlank(uint8_t v)
{
    return v == ' ' || v == '\t' || v == '\r' || v == '\n';
}
static bool IsPnm(stream_t *s)
{
    const uint8_t *header;
    int size = vlc_stream_Peek(s, &header, 256);
    if (size < 3)
        return false;
    if (header[0] != 'P' ||
        header[1] < '1' || header[1] > '6' ||
        !IsPnmBlank(header[2]))
        return false;

    int number_count = 0;
    for (int i = 3, parsing_number = 0; i < size && number_count < 2; i++) {
        if (IsPnmBlank(header[i])) {
            if (parsing_number) {
                parsing_number = 0;
                number_count++;
            }
        } else {
            if (header[i] < '0' || header[i] > '9')
                break;
            parsing_number = 1;
        }
    }
    if (number_count < 2)
        return false;
    return true;
}

static uint8_t FindJpegMarker(size_t *position, const uint8_t *data, size_t size)
{
    for (size_t i = *position; i + 1 < size; i++) {
        if (data[i + 0] != 0xff || data[i + 1] == 0x00)
            return 0xff;
        if (data[i + 1] != 0xff) {
            *position = i + 2;
            return data[i + 1];
        }
    }
    return 0xff;
}
static bool IsJfif(stream_t *s)
{
    const uint8_t *header;
    ssize_t peek = vlc_stream_Peek(s, &header, 4096);
    if(peek < 256)
        return false;
    size_t size = (size_t) peek;
    size_t position = 0;

    if (FindJpegMarker(&position, header, size) != 0xd8) // SOI
        return false;

    while (1) {
        uint8_t marker = FindJpegMarker(&position, header, size);
        switch (marker) {
            case 0xe2: { // ICC Profile
                if (position + 14 > size)
                    return false;
                size_t icc_size = GetWBE(&header[position]);
                if (icc_size < 2)
                    return false;
                position += 2;
                if (memcmp(&header[position], "ICC_PROFILE\0", 12))
                    return false;
                position += icc_size - 2;
                break;
            }
            case 0xe0: { // APP0
                if (position + 7 > size)
                    return false;
                position += 2;  /* Skip size */
                return (memcmp(&header[position], "JFIF\0", 5) == 0);
            }
            default:
                return false;
        }
    }
}

static bool IsWebP(stream_t *s)
{
    const uint8_t *header;
    if (vlc_stream_Peek(s, &header, 20) < 20) /* WebP header size */
        return false;
    if (memcmp(&header[0], "RIFF", 4))
        return false;
    /* TODO: support other chunk types */
    if (memcmp(&header[8], "WEBPVP8 ", 8))
        return false;
    /* skip headers */
    return vlc_stream_Seek(s, 20) == 0;
}

static bool IsSpiff(stream_t *s)
{
    const uint8_t *header;
    if (vlc_stream_Peek(s, &header, 36) < 36) /* SPIFF header size */
        return false;
    if (header[0] != 0xff || header[1] != 0xd8 ||
        header[2] != 0xff || header[3] != 0xe8)
        return false;
    if (memcmp(&header[6], "SPIFF\0", 6))
        return false;
    return true;
}

#define EXIF_STRING "Exif" /* includes \0 */
#define EXIF_XMP_STRING "http://ns.adobe.com/xap/1.0/" /* includes \0 */
static bool IsExifXMP(stream_t *s)
{
    const uint8_t *header;
    ssize_t peek = vlc_stream_Peek(s, &header, 256);
    if (peek < 256)
        return false;
    size_t size = (size_t) peek;
    size_t position = 0;

    if (FindJpegMarker(&position, header, size) != 0xd8)
        return false;
    if (FindJpegMarker(&position, header, size) != 0xe1)
        return false;
    position += 2;  /* Skip size */
    if (position + sizeof(EXIF_STRING) <= size &&
        !memcmp(&header[position], EXIF_STRING, sizeof(EXIF_STRING)))
        return true;
    if (position + sizeof(EXIF_XMP_STRING) <= size &&
        !memcmp(&header[position], EXIF_XMP_STRING, sizeof(EXIF_XMP_STRING)))
        return true;
    return false;
}

static bool FindSVGmarker(int *position, const uint8_t *data, const int size, const char *marker)
{
    for( int i = *position; i < size; i++)
    {
        if (memcmp(&data[i], marker, strlen(marker)) == 0)
        {
            *position = i;
            return true;
        }
    }
    return false;
}

static bool IsSVG(stream_t *s)
{
    if (s->psz_url == NULL)
        return false;

    char *ext = strstr(s->psz_url, ".svg");
    if (!ext) return false;

    const uint8_t *header;
    ssize_t size = vlc_stream_Peek(s, &header, 4096);
    if (size == -1)
        return false;
    int position = 0;

    const char xml[] = "<?xml version=\"";
    if (!FindSVGmarker(&position, header, size, xml))
        return false;
    if (position != 0)
        return false;

    const char endxml[] = ">\0";
    if (!FindSVGmarker(&position, header, size, endxml))
        return false;
    if (position <= 15)
        return false;

    const char svg[] = "<svg";
    if (!FindSVGmarker(&position, header, size, svg))
        return false;
    if (position < 19)
        return false;

    /* SVG Scalable Vector Graphics image */

    /* NOTE: some SVG images have the mimetype set in a meta data section
     * and some do not */

    return true;
}

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 (vlc_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 (vlc_stream_Control(s, STREAM_CAN_SEEK, &can_seek) || !can_seek)
        return false;

    const int64_t position = vlc_stream_Tell(s);
    if (vlc_stream_Seek(s, size - 26))
        return false;

    const uint8_t *footer;
    if (vlc_stream_Peek(s, &footer, 26) < 26
     || memcmp(&footer[8], "TRUEVISION-XFILE.\x00", 18))
        return false;

    return vlc_stream_Seek(s, position) == 0;
}

typedef struct {
    vlc_fourcc_t  codec;
    size_t        marker_size;
    const uint8_t marker[14];
    bool          (*detect)(stream_t *s);
} image_format_t;

#define VLC_CODEC_XCF VLC_FOURCC('X', 'C', 'F', ' ')
#define VLC_CODEC_LBM VLC_FOURCC('L', 'B', 'M', ' ')
static const image_format_t formats[] = {
    { .codec = VLC_CODEC_XCF,
      .marker_size = 9 + 4 + 1,
      .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
                  'f', 'i', 'l', 'e', '\0' }
    },
    { .codec = VLC_CODEC_XCF,
      .marker_size = 9 + 4 + 1,
      .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
                  'v', '0', '0', '1', '\0' }
    },
    { .codec = VLC_CODEC_XCF,
      .marker_size = 9 + 4 + 1,
      .marker = { 'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ',
                  'v', '0', '0', '2', '\0' }
    },
    { .codec = VLC_CODEC_PNG,
      .marker_size = 8,
      .marker = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }
    },
    { .codec = VLC_CODEC_GIF,
      .marker_size = 6,
      .marker = { 'G', 'I', 'F', '8', '7', 'a' }
    },
    { .codec = VLC_CODEC_GIF,
      .marker_size = 6,
      .marker = { 'G', 'I', 'F', '8', '9', 'a' }
    },
    /* XXX TIFF detection may be a bit weak */
    { .codec = VLC_CODEC_TIFF,
      .marker_size = 4,
      .marker = { 'I', 'I', 0x2a, 0x00 },
    },
    { .codec = VLC_CODEC_TIFF,
      .marker_size = 4,
      .marker = { 'M', 'M', 0x00, 0x2a },
    },
    { .codec = VLC_CODEC_BMP,
      .detect = IsBmp,
    },
    { .codec = VLC_CODEC_PCX,
      .detect = IsPcx,
    },
    { .codec = VLC_CODEC_LBM,
      .detect = IsLbm,
    },
    { .codec = VLC_CODEC_PNM,
      .detect = IsPnm,
    },
    { .codec = VLC_CODEC_MXPEG,
      .detect = IsMxpeg,
    },
    { .codec = VLC_CODEC_JPEG,
      .detect = IsJfif,
    },
    { .codec = VLC_CODEC_JPEG,
      .detect = IsSpiff,
    },
    { .codec = VLC_CODEC_JPEG,
      .detect = IsExifXMP,
    },
    { .codec = VLC_CODEC_WEBP,
      .detect = IsWebP,
    },
    { .codec = VLC_CODEC_FARBFELD,
      .marker_size = 8,
      .marker = { 'f', 'a', 'r', 'b', 'f', 'e', 'l', 'd' },
    },
    { .codec = VLC_CODEC_BPG,
      .marker_size = 4,
      .marker = { 'B', 'P', 'G', 0xFB },
    },
    { .codec = VLC_CODEC_SVG,
      .detect = IsSVG,
    },
    { .codec = VLC_CODEC_TARGA,
      .detect = IsTarga,
    },
};

static vlc_fourcc_t Detect(stream_t *s)
{
    const uint8_t *peek;
    size_t peek_size = 0;

    for (size_t i = 0; i < ARRAY_SIZE(formats); i++) {
        const image_format_t *img = &formats[i];

        if (img->detect != NULL) {
            if (img->detect(s))
                return img->codec;

            if (vlc_stream_Seek(s, 0))
               return 0;

            /* Seeking invalidates the current peek buffer */
            peek_size = 0;
            continue;
        }

        if (peek_size < img->marker_size) {
            ssize_t val = vlc_stream_Peek(s, &peek, img->marker_size);
            if (val < 0)
                continue;
            peek_size = val;
        }

        assert(img->marker_size > 0); /* ensure peek is a valid pointer */

        if (peek_size >= img->marker_size
         && memcmp(peek, img->marker, img->marker_size) == 0)
            return img->codec;
    }
    return 0;
}

static int parse_farbfeld_header(vlc_object_t *object, es_format_t *fmt)
{
    demux_t *demux = (demux_t*)object;

    const uint8_t *p_peek;
    if (vlc_stream_Peek(demux->s, &p_peek, 16) < 16)
        return VLC_EGENERIC;

    uint32_t width = GetDWBE(p_peek + 8);
    uint32_t height = GetDWBE(p_peek + 12);

    if (width == 0 || height == 0)
        return VLC_EGENERIC;

    /* Farbfeld is essentially just a header followed by pixels. */
    fmt->video.i_width = width;
    fmt->video.i_height = height;
    fmt->video.i_chroma = fmt->i_codec = VLC_CODEC_RGBA64;

    (void) vlc_stream_Read(demux->s, NULL, 16);

    return VLC_SUCCESS;
}

static int Open(vlc_object_t *object)
{
    demux_t *demux = (demux_t*)object;

    /* Detect the image type */
    vlc_fourcc_t codec = Detect(demux->s);
    if (codec == 0)
        return VLC_EGENERIC;

    msg_Dbg(demux, "Detected image: %s",
            vlc_fourcc_GetDescription(VIDEO_ES, codec));

    if (codec == VLC_CODEC_MXPEG)
        return VLC_EGENERIC; //let avformat demux this file

    /* Load and if selected decode */
    es_format_t fmt;
    es_format_Init(&fmt, VIDEO_ES, codec);
    fmt.video.i_chroma = fmt.i_codec;

    if (codec == VLC_CODEC_FARBFELD)
    {
        if (parse_farbfeld_header(object, &fmt))
            return VLC_EGENERIC;
    }

    block_t *data = Load(demux);
    if (data && var_InheritBool(demux, "image-decode")) {
        char *string = var_InheritString(demux, "image-chroma");
        vlc_fourcc_t chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, string);
        free(string);

        data = Decode(demux, &fmt, chroma, data);
    }
    fmt.i_id    = var_InheritInteger(demux, "image-id");
    fmt.i_group = var_InheritInteger(demux, "image-group");
    if (var_InheritURational(demux,
                             &fmt.video.i_frame_rate,
                             &fmt.video.i_frame_rate_base,
                             "image-fps") ||
        fmt.video.i_frame_rate <= 0 || fmt.video.i_frame_rate_base <= 0) {
        msg_Err(demux, "Invalid frame rate, using 10/1 instead");
        fmt.video.i_frame_rate      = 10;
        fmt.video.i_frame_rate_base = 1;
    }

    /* If loadind failed, we still continue to avoid mis-detection
     * by other demuxers. */

    if (!data)
        msg_Err(demux, "Failed to load the image");

    /* */
    demux_sys_t *sys = malloc(sizeof(*sys));
    if (!sys) {
        if (data)
            block_Release(data);
        es_format_Clean(&fmt);
        return VLC_ENOMEM;
    }

    date_Init(&sys->pts, fmt.video.i_frame_rate, fmt.video.i_frame_rate_base);
    date_Set(&sys->pts, VLC_TICK_0);
    sys->es = es_out_Add(demux->out, &fmt);
    es_format_Clean(&fmt);
    if(unlikely(!sys->es))
    {
        if (data)
            block_Release(data);
        free(sys);
        return VLC_EGENERIC;
    }
    sys->data        = data;
    sys->duration    = vlc_tick_from_sec( var_InheritFloat(demux, "image-duration") );
    sys->is_realtime = var_InheritBool(demux, "image-realtime");
    sys->pts_offset  = sys->is_realtime ? vlc_tick_now() : 0;
    sys->pts_next    = VLC_TICK_INVALID;

    demux->pf_demux   = Demux;
    demux->pf_control = Control;
    demux->p_sys      = sys;
    return VLC_SUCCESS;
}

static void Close(vlc_object_t *object)
{
    demux_t     *demux = (demux_t*)object;
    demux_sys_t *sys   = demux->p_sys;

    if (sys->data)
        block_Release(sys->data);
    free(sys);
}

Messung
CHZG
839610093

¤ Dauer der Verarbeitung: 0.5 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104852
#Domains=417162