Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  hx.c   Sprache: C

 

/*****************************************************************************
 * hx.c : raw video / audio IP cam demuxer
 *****************************************************************************
 * Copyright (C) 2022 - VideoLabs, VLC authors and VideoLAN
 *
 * 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 <vlc_common.h>
#include <vlc_arrays.h>
#include <vlc_plugin.h>
#include <vlc_demux.h>

/* All Marker formats:
 * [tag.4][size.4][tag dependant.8] */

static const char HXVS[4] = { 'H', 'X', 'V', 'S' }; /* H264 file tag */
static const char HXVT[4] = { 'H', 'X', 'V', 'T' }; /* HEVC */
static const char HXVF[4] = { 'H', 'X', 'V', 'F' }; /* Video samples */
static const char HXAF[4] = { 'H', 'X', 'A', 'F' }; /* Audio samples */
static const char HXFI[4] = { 'H', 'X', 'F', 'I' }; /* RAP Index */

#define HX_HEADER_SIZE 16
#define HX_INDEX_SIZE 200000

struct hxfi_index
{
    uint32_t offset;
    uint32_t time;
};

typedef struct
{
    es_out_id_t *p_es_video;
    es_out_id_t *p_es_audio;
    vlc_tick_t video_pts;
    vlc_tick_t audio_pts;
    vlc_tick_t pcr;
    uint32_t video_pts_offset;
    uint32_t audio_pts_offset;
    uint32_t duration;
    DECL_ARRAY(struct hxfi_index) index;
} hx_sys_t;

static int LoadIndex(demux_t *p_demux)
{
    hx_sys_t *p_sys  = p_demux->p_sys;

    /* From what I understand:
     * Header HXFI[size.4][duration.4][?.4]
     * Size is always 200K, predictable file offset
     * All indexes entries are 4/4 bytes
     * zero filled empty entries
     */


    uint64_t size;
    if(vlc_stream_GetSize(p_demux->s, &size) != VLC_SUCCESS ||
       size < HX_INDEX_SIZE + HX_HEADER_SIZE)
        return VLC_EGENERIC;

    if(vlc_stream_Seek(p_demux->s, size - HX_INDEX_SIZE - HX_HEADER_SIZE) != VLC_SUCCESS)
        return VLC_EGENERIC;

    uint8_t temp[HX_HEADER_SIZE];
    if(vlc_stream_Read(p_demux->s, temp, HX_HEADER_SIZE) != HX_HEADER_SIZE ||
       memcmp(temp, HXFI, 4))
    {
        msg_Warn(p_demux, "Could not find index at expected location");
        return VLC_EGENERIC;
    }

    p_sys->duration = GetDWLE(temp + 8);
    msg_Dbg(p_demux, "Reading Index Length @%" PRIu32 "ms", p_sys->duration);

    uint32_t prevtime = UINT32_MAX;
    for(;;)
    {
        if(vlc_stream_Read(p_demux->s, temp, 8) != 8)
            break;
        struct hxfi_index entry;
        entry.offset = GetDWLE(temp);
        entry.time = GetDWLE(temp + 4);
        if(entry.offset == 0)
            break;
        if(entry.time != prevtime)
        {
            prevtime = entry.time;
            ARRAY_APPEND(p_sys->index, entry);
        }
    }
    msg_Dbg(p_demux, "Using %d entries from HXFI index", p_sys->index.i_size);
    return VLC_SUCCESS;
}

static struct hxfi_index LookupIndex(hx_sys_t *p_sys, uint32_t time)
{
    struct hxfi_index entry = { 0, 0 };
    if(p_sys->index.i_size)
    {
        unsigned l = 0, h = p_sys->index.i_size - 1;
        while(l <= h)
        {
            unsigned m = (l + h) >> 1;
            if(p_sys->index.p_elems[m].time > time)
            {
                if(m == 0)
                    break;
                h = m -1;
            }
            else
            {
                /* store lowest as temp result */
                entry = p_sys->index.p_elems[m];
                if(entry.time == time)
                    break;
                l = m + 1;
            }
        };
    }
    return entry;
}

static int Demux(demux_t *p_demux)
{
    hx_sys_t *p_sys  = p_demux->p_sys;

    uint8_t header[HX_HEADER_SIZE];
    if(vlc_stream_Read(p_demux->s, header, HX_HEADER_SIZE) != HX_HEADER_SIZE)
        return VLC_DEMUXER_EOF;

    es_out_id_t *es = NULL;
    vlc_tick_t *ppts;
    uint32_t *ppts_offset;

    if(!memcmp(header, HXVF, 4))
    {
        es = p_sys->p_es_video;
        ppts = &p_sys->video_pts;
        ppts_offset = &p_sys->video_pts_offset;
    }
    else if(!memcmp(header, HXAF, 4))
    {
        es = p_sys->p_es_audio;
        ppts = &p_sys->audio_pts;
        ppts_offset = &p_sys->audio_pts_offset;
    }
    else if(!memcmp(header, HXVS, 4) || !memcmp(header, HXVT, 4))
    {
        return VLC_DEMUXER_SUCCESS;
    }
    else
    {
        msg_Dbg(p_demux, "EOF on %4.4s", (const char *) header);
        return VLC_DEMUXER_EOF;
    }

    uint32_t sz = GetDWLE(header + 4);
    int i_ret = VLC_DEMUXER_SUCCESS;

    if(es)
    {
        /* [HXAF.4][size.4][pts.4][?.4] */
        /* [HXVF.4][size.4][pts.4][?.4] */
        *ppts = VLC_TICK_0;
        if(*ppts_offset != UINT32_MAX)
            *ppts += VLC_TICK_FROM_MS(GetDWLE(&header[8]) - *ppts_offset);
        else
            *ppts_offset = GetDWLE(&header[8]);

        block_t *p_block = vlc_stream_Block(p_demux->s, sz);
        if(p_block == NULL)
            return VLC_DEMUXER_EOF;

        if(p_block->i_buffer < sz)
            i_ret = VLC_DEMUXER_EOF;

        if(p_sys->p_es_audio == es)
        {
            /* HXAF sample format prefix [?.1/channels.1/rate.1/?.1] */
            const uint8_t audioprefix[4] = {0x00, 0x01, 0x50, 0x00};
            if(p_block->i_buffer >= 4 &&
               !memcmp(p_block->p_buffer, audioprefix, 4))
            {
                p_block->i_buffer -= 4;
                p_block->p_buffer += 4;
            }
            else
            {
                msg_Warn(p_demux,"Unsupported audio format, dropping");
                block_Release(p_block);
                p_block = NULL;
            }
        }

        if(p_sys->pcr == VLC_TICK_INVALID)
        {
            p_sys->pcr = *ppts;
            es_out_SetPCR(p_demux->out, p_sys->pcr);
        }

        if(p_block)
        {
            p_block->i_dts = p_block->i_pts = *ppts;
            es_out_Send(p_demux->out, es, p_block);
        }

        if( p_sys->audio_pts > p_sys->pcr )
        {
            p_sys->pcr = p_sys->audio_pts;
            es_out_SetPCR(p_demux->out, p_sys->pcr);
        }
    }
    else
    {
        if(vlc_stream_Read(p_demux->s, NULL, sz) != sz)
            i_ret = VLC_DEMUXER_EOF;
    }

    return i_ret;
}

static int SeekUsingIndex(demux_t *p_demux, uint32_t time, bool b_precise)
{
    hx_sys_t *p_sys  = p_demux->p_sys;
    struct hxfi_index idx = LookupIndex(p_sys, time);
    if(idx.offset == 0)
        return VLC_EGENERIC;
    int ret = vlc_stream_Seek(p_demux->s, idx.offset);
    if(ret == VLC_SUCCESS)
    {
        p_sys->pcr = VLC_TICK_0 + VLC_TICK_FROM_MS(idx.time);
        p_sys->audio_pts = VLC_TICK_INVALID;
        p_sys->video_pts = VLC_TICK_INVALID;
        if(b_precise)
            es_out_Control(p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
                           VLC_TICK_0 + VLC_TICK_FROM_MS(time));
    }
    return ret;
}

static int Control(demux_t *p_demux, int i_query, va_list args)
{
    hx_sys_t *p_sys  = p_demux->p_sys;
    switch(i_query)
    {
        case DEMUX_GET_TIME:
        {
            *va_arg(args, vlc_tick_t *) = p_sys->pcr;
            return VLC_SUCCESS;
        }
        case DEMUX_GET_LENGTH:
        {
            *va_arg(args, vlc_tick_t *) = VLC_TICK_FROM_MS(p_sys->duration);
            return VLC_SUCCESS;
        }
        case DEMUX_GET_POSITION:
        {
            if(!p_sys->duration)
                return VLC_EGENERIC;
            *va_arg(args, double *) = MS_FROM_VLC_TICK(p_sys->pcr) / p_sys->duration;
            return VLC_SUCCESS;
        }
        case DEMUX_SET_TIME:
        {
            vlc_tick_t time = va_arg(args, vlc_tick_t);
            bool b_precise = va_arg(args, int);
            return SeekUsingIndex(p_demux, MS_FROM_VLC_TICK(time), b_precise);
        }
        case DEMUX_SET_POSITION:
        {
            double pos = va_arg(args, double);
            bool b_precise = va_arg(args, int);
            if(p_sys->index.i_size == 0)
                return VLC_EGENERIC;
            return SeekUsingIndex(p_demux, pos * p_sys->duration, b_precise);
        }
        case DEMUX_CAN_SEEK:
        {
            if(p_sys->index.i_size == 0)
                return VLC_EGENERIC;
            /* fallthrough */
        }
        default:
            break;
    }

    return demux_vaControlHelper(p_demux->s, 0, -1, 0, 1, i_query, args);
}

static void Close(vlc_object_t *p_this)
{
    demux_t     *p_demux = (demux_t*)p_this;
    hx_sys_t *p_sys  = p_demux->p_sys;
    ARRAY_RESET(p_sys->index);
    free(p_sys);
}

static int Open(vlc_object_t * p_this)
{
    demux_t     *p_demux = (demux_t*)p_this;
    hx_sys_t *p_sys;
    const uint8_t *p_peek;

    if(vlc_stream_Peek(p_demux->s, &p_peek, 20) != 20 ||
       (memcmp(p_peek, HXVS, 4) && memcmp(p_peek, HXVT, 4)) ||
        memcmp(p_peek + 16, HXVF, 4))
        return VLC_EGENERIC;

    p_demux->p_sys = p_sys = malloc(sizeof(hx_sys_t));
    if(!p_sys)
        return VLC_ENOMEM;
    p_sys->audio_pts = VLC_TICK_INVALID;
    p_sys->video_pts = VLC_TICK_INVALID;
    p_sys->pcr = VLC_TICK_INVALID;
    p_sys->audio_pts_offset = UINT32_MAX;
    p_sys->video_pts_offset = UINT32_MAX;
    p_sys->p_es_audio = NULL;
    p_sys->p_es_video = NULL;
    p_sys->duration = 0;
    ARRAY_INIT(p_sys->index);

    bool b_seekable;
    if(vlc_stream_Control(p_demux->s, STREAM_CAN_SEEK, &b_seekable) != VLC_SUCCESS)
        b_seekable = false;

    vlc_fourcc_t vcodec = memcmp(p_peek, HXVT, 4) ? VLC_CODEC_H264 : VLC_CODEC_HEVC;
    unsigned width = GetDWLE(p_peek + 4);
    unsigned height = GetDWLE(p_peek + 8);

    if(b_seekable)
    {
        uint64_t origin = vlc_stream_Tell(p_demux->s);
        if(LoadIndex(p_demux) != VLC_SUCCESS)
            msg_Err(p_demux, "Failed to load index");
        if(vlc_stream_Seek(p_demux->s, origin) != VLC_SUCCESS)
        {
            msg_Err(p_demux, "Failed to seek after loading index, giving up");
            Close(p_this);
            return VLC_EGENERIC;
        }
    }

    /* Create ES from parameters or defaults */
    es_format_t fmt;

    es_format_Init(&fmt, VIDEO_ES, vcodec);
    fmt.video.i_visible_width = width;
    fmt.video.i_visible_height = height;
    fmt.b_packetized = false;
    p_sys->p_es_video = es_out_Add(p_demux->out, &fmt);
    es_format_Clean(&fmt);

    es_format_Init(&fmt, AUDIO_ES, VLC_CODEC_ALAW);
    fmt.audio.i_rate = 8000;
    fmt.audio.i_channels = 1;
    p_sys->p_es_audio = es_out_Add(p_demux->out, &fmt);
    es_format_Clean(&fmt);

    p_demux->pf_demux   = Demux;
    p_demux->pf_control = Control;

    return VLC_SUCCESS;
}

vlc_module_begin ()
    set_shortname("HX")
    set_description(N_("HX video demuxer"))
    set_capability("demux", 10)
    set_subcategory(SUBCAT_INPUT_DEMUX)
    set_callbacks(Open, Close)
    add_shortcut("hx")
vlc_module_end ()

Messung
CHZG
849810094

¤ 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104856
#Domains=417302