Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/stream_out/transcode/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 8 kB image not shown  

Quelle  pcr_sync.c   Sprache: C

 

/*****************************************************************************
 * pcr_sync.c
 *****************************************************************************
 * Copyright (C) 2022 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 <assert.h>
#include <stdint.h>

#include <vlc_common.h>

#include <vlc_frame.h>
#include <vlc_list.h>
#include <vlc_tick.h>
#include <vlc_vector.h>

#include "pcr_sync.h"

struct es_dts_entry
{
    vlc_tick_t dts;
    bool passed;
    vlc_tick_t discontinuity;
};

typedef struct
{
    vlc_tick_t pcr;
    struct VLC_VECTOR(struct es_dts_entry) es_last_dts_entries;
    size_t entries_left;
    bool no_frame_before;

    struct vlc_list node;
} pcr_event_t;

static inline void pcr_event_Delete(pcr_event_t *ev)
{
    vlc_vector_destroy(&ev->es_last_dts_entries);
    free(ev);
}

struct es_data
{
    bool is_deleted;
    vlc_tick_t last_input_dts;
    vlc_tick_t last_output_dts;
    vlc_tick_t discontinuity;
    pcr_event_t *last_pcr_event;
};

static inline struct es_data es_data_Init(void)
{
    return (struct es_data){.is_deleted = false,
                            .last_input_dts = VLC_TICK_INVALID,
                            .last_output_dts = VLC_TICK_INVALID,
                            .discontinuity = VLC_TICK_INVALID};
}

struct es_data_vec VLC_VECTOR(struct es_data);

struct vlc_pcr_sync
{
    struct vlc_list pcr_events;
    struct es_data_vec es_data;
    vlc_mutex_t lock;
};

vlc_pcr_sync_t *vlc_pcr_sync_New(void)
{
    vlc_pcr_sync_t *ret = malloc(sizeof(*ret));
    if (unlikely(ret == NULL))
        return NULL;

    vlc_vector_init(&ret->es_data);
    vlc_list_init(&ret->pcr_events);
    vlc_mutex_init(&ret->lock);
    return ret;
}

void vlc_pcr_sync_Delete(vlc_pcr_sync_t *pcr_sync)
{
    vlc_vector_destroy(&pcr_sync->es_data);

    pcr_event_t *it;
    vlc_list_foreach(it, &pcr_sync->pcr_events, node) { pcr_event_Delete(it); }

    free(pcr_sync);
}

static bool pcr_sync_ShouldFastForwardPCR(vlc_pcr_sync_t *pcr_sync)
{
    struct es_data it;
    vlc_vector_foreach(it, &pcr_sync->es_data)
    {
        if (!it.is_deleted && it.last_output_dts != it.last_input_dts)
            return false;
    }
    return vlc_list_is_empty(&pcr_sync->pcr_events);
}

static bool pcr_sync_HadFrameInputSinceLastPCR(vlc_pcr_sync_t *pcr_sync)
{
    const pcr_event_t *pcr_event =
        vlc_list_last_entry_or_null(&pcr_sync->pcr_events, pcr_event_t, node);

    if (pcr_event == NULL)
        return true;

    for (unsigned int i = 0; i < pcr_sync->es_data.size; ++i)
    {
        const struct es_data *curr = &pcr_sync->es_data.data[i];
        if (curr->is_deleted || curr->last_input_dts == VLC_TICK_INVALID)
            continue;

        const bool is_oob = i >= pcr_event->es_last_dts_entries.size;
        if (!is_oob && curr->last_input_dts != pcr_event->es_last_dts_entries.data[i].dts)
            return true;
        else if (is_oob)
            return true;
    }
    return false;
}

static int pcr_sync_SignalPCRLocked(vlc_pcr_sync_t *pcr_sync, vlc_tick_t pcr)
{
    if (pcr_sync_ShouldFastForwardPCR(pcr_sync))
        return VLC_PCR_SYNC_FORWARD_PCR;

    pcr_event_t *event = malloc(sizeof(*event));
    if (unlikely(event == NULL))
        return VLC_ENOMEM;

    vlc_vector_init(&event->es_last_dts_entries);
    const bool alloc_succeeded =
        vlc_vector_reserve(&event->es_last_dts_entries, pcr_sync->es_data.size);
    if (unlikely(alloc_succeeded == false))
    {
        free(event);
        return VLC_ENOMEM;
    }

    size_t entries_left = 0;
    struct es_data data;
    vlc_vector_foreach(data, &pcr_sync->es_data)
    {
        if (!data.is_deleted)
        {
            vlc_vector_push(&event->es_last_dts_entries,
                            ((struct es_dts_entry){.dts = data.last_input_dts,
                                                   .discontinuity = data.discontinuity}));
            if (data.last_input_dts != VLC_TICK_INVALID)
                ++entries_left;
            data.discontinuity = VLC_TICK_INVALID;
        }
    }

    event->pcr = pcr;
    event->entries_left = entries_left;
    event->no_frame_before = !pcr_sync_HadFrameInputSinceLastPCR(pcr_sync);

    vlc_list_append(&event->node, &pcr_sync->pcr_events);

    return VLC_SUCCESS;
}

int vlc_pcr_sync_SignalPCR(vlc_pcr_sync_t *pcr_sync, vlc_tick_t pcr)
{
    vlc_mutex_lock(&pcr_sync->lock);
    const int result = pcr_sync_SignalPCRLocked(pcr_sync, pcr);
    vlc_mutex_unlock(&pcr_sync->lock);
    return result;
}

void vlc_pcr_sync_SignalFrame(vlc_pcr_sync_t *pcr_sync, unsigned int id, const vlc_frame_t *frame)
{
    vlc_mutex_lock(&pcr_sync->lock);
    assert(id < pcr_sync->es_data.size);

    struct es_data *data = &pcr_sync->es_data.data[id];
    assert(!data->is_deleted);
    if (frame->i_dts != VLC_TICK_INVALID)
        data->last_input_dts = frame->i_dts;
    if (frame->i_flags & VLC_FRAME_FLAG_DISCONTINUITY)
    {
        assert(frame->i_dts != VLC_TICK_INVALID);
        data->discontinuity = frame->i_dts;
    }

    vlc_mutex_unlock(&pcr_sync->lock);
}

int vlc_pcr_sync_NewESID(vlc_pcr_sync_t *pcr_sync, unsigned int *id)
{
    vlc_mutex_lock(&pcr_sync->lock);

    for (unsigned int i = 0; i < pcr_sync->es_data.size; ++i)
    {
        if (pcr_sync->es_data.data[i].is_deleted)
        {
            pcr_sync->es_data.data[i] = es_data_Init();
            vlc_mutex_unlock(&pcr_sync->lock);
            *id = i;
            return VLC_SUCCESS;
        }
    }

    const bool push_succeeded = vlc_vector_push(&pcr_sync->es_data, es_data_Init());
    const size_t ids_count = pcr_sync->es_data.size;

    vlc_mutex_unlock(&pcr_sync->lock);

    if (push_succeeded)
    {
        *id = ids_count - 1;
        return VLC_SUCCESS;
    }
    return VLC_ENOMEM;
}

void vlc_pcr_sync_DelESID(vlc_pcr_sync_t *pcr_sync, unsigned int id)
{
    vlc_mutex_lock(&pcr_sync->lock);

    assert(id < pcr_sync->es_data.size);
    pcr_sync->es_data.data[id].is_deleted = true;

    vlc_mutex_unlock(&pcr_sync->lock);
}

#define pcr_event_FirstEntry(head)                                                                 \
    vlc_list_first_entry_or_null(head, pcr_event_t, node)
#define pcr_event_NextEntry(head, entry)                                                           \
    vlc_list_next_entry_or_null(head, entry, pcr_event_t, node)

vlc_tick_t
vlc_pcr_sync_SignalFrameOutput(vlc_pcr_sync_t *pcr_sync, unsigned int id, const vlc_frame_t *frame)
{
    vlc_mutex_lock(&pcr_sync->lock);

    struct es_data *es = &pcr_sync->es_data.data[id];
    assert(!es->is_deleted);
    es->last_output_dts = frame->i_dts;

    pcr_event_t *pcr_event = (es->last_pcr_event == NULL)
                                 ? pcr_event_FirstEntry(&pcr_sync->pcr_events)
                                 : es->last_pcr_event;
    if (pcr_event == NULL)
        goto no_pcr;

    assert(id < pcr_event->es_last_dts_entries.size);

    const vlc_tick_t pcr = pcr_event->pcr;

    if (pcr_event->no_frame_before)
    {
        es->last_pcr_event = pcr_event_NextEntry(&pcr_sync->pcr_events, pcr_event);
        goto return_pcr;
    }

    assert(pcr_event->entries_left != 0);

    struct es_dts_entry *dts_entry = &pcr_event->es_last_dts_entries.data[id];

    if (dts_entry->discontinuity != VLC_TICK_INVALID && frame->i_dts > dts_entry->discontinuity)
        goto no_pcr;

    if (frame->i_dts < dts_entry->dts)
        goto no_pcr;

    if (dts_entry->passed)
        goto no_pcr;

    dts_entry->passed = true;
    es->last_pcr_event = pcr_event_NextEntry(&pcr_sync->pcr_events, pcr_event);
    if (--pcr_event->entries_left != 0)
        goto no_pcr;

return_pcr:
    vlc_list_remove(&pcr_event->node);
    pcr_event_Delete(pcr_event);

    vlc_mutex_unlock(&pcr_sync->lock);
    return pcr;

no_pcr:
    vlc_mutex_unlock(&pcr_sync->lock);
    return VLC_TICK_INVALID;
}

Messung
CHZG
849710093

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