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

Quelle  ts_si.c   Sprache: C

 

/*****************************************************************************
 * ts_psi_eit.c : TS demuxer SI handling
 *****************************************************************************
 * Copyright (C) 2014-2016 - VideoLAN Authors
 *
 * 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 General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *****************************************************************************/

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

#include <vlc_common.h>
#include <vlc_demux.h>
#include <vlc_meta.h>
#include <vlc_epg.h>
#include <vlc_charset.h>   /* FromCharset, for EIT */
#include <vlc_input.h>

#ifndef _DVBPSI_DVBPSI_H_
 #include <dvbpsi/dvbpsi.h>
#endif
#include <dvbpsi/demux.h>
#include <dvbpsi/descriptor.h>
#include <dvbpsi/sdt.h>
#include <dvbpsi/eit.h> /* EIT support */
#include <dvbpsi/tot.h> /* TDT support */
#include <dvbpsi/dr.h>
#include <dvbpsi/psi.h>
#include "../../mux/mpeg/dvbpsi_compat.h" /* dvbpsi_messages */

#include "ts_si.h"
#include "ts_arib.h"
#include "ts_decoders.h"

#include "ts_pid.h"
#include "ts_streams_private.h"
#include "ts.h"
#include "../dvb-text.h"

#ifdef HAVE_ARIBB24
 #include <aribb24/decoder.h>
#endif

#include <time.h>
#include <assert.h>
#include <limits.h>

struct ts_si_context_t
{
    dvbpsi_t *p_handle;
    int       i_version;
};

#ifndef SI_DEBUG_EIT
 #define SI_DEBUG_TIMESHIFT(t)
#else
 static time_t i_eit_debug_offset = 0;
 #define SI_DEBUG_TIMESHIFT(t) \
    do {\
        if( i_eit_debug_offset == 0 )\
            i_eit_debug_offset = time(NULL) - t;\
        t = t + i_eit_debug_offset;\
    } while(0);
#endif


static void SINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id,
                                uint16_t i_extension, void *p_pid_cbdata );

void ts_si_Packet_Push( ts_pid_t *p_pid, const uint8_t *p_pktbuffer )
{
    if( likely(p_pid->type == TYPE_SI) &&
        dvbpsi_decoder_present( p_pid->u.p_si->p_ctx->p_handle ) )
        dvbpsi_packet_push( p_pid->u.p_si->p_ctx->p_handle, (uint8_t *) p_pktbuffer );
}

static char *EITConvertToUTF8( demux_t *p_demux,
                               const unsigned char *psz_instring,
                               size_t i_length,
                               bool b_broken )
{
    demux_sys_t *p_sys = p_demux->p_sys;
#ifdef HAVE_ARIBB24
    if( p_sys->standard == TS_STANDARD_ARIB )
    {
        if ( !p_sys->arib.p_instance )
            p_sys->arib.p_instance = arib_instance_new( p_demux );
        if ( !p_sys->arib.p_instance )
            return NULL;
        arib_decoder_t *p_decoder = arib_get_decoder( p_sys->arib.p_instance );
        if ( !p_decoder )
            return NULL;

        char *psz_outstring = NULL;
        size_t i_out;

        i_out = i_length * 4;
        psz_outstring = (char*) calloc( i_out + 1, sizeof(char) );
        if( !psz_outstring )
            return NULL;

        arib_initialize_decoder( p_decoder );
        i_out = arib_decode_buffer( p_decoder, psz_instring, i_length,
                                    psz_outstring, i_out );
        arib_finalize_decoder( p_decoder );

        return psz_outstring;
    }
#else
    VLC_UNUSED(p_sys);
#endif
    /* Deal with no longer broken providers (no switch byte
      but sending ISO_8859-1 instead of ISO_6937) without
      removing them from the broken providers table
      (keep the entry for correctly handling recorded TS).
    */

    b_broken = b_broken && i_length && *psz_instring > 0x20;

    if( b_broken )
        return FromCharset( "ISO_8859-1", psz_instring, i_length );
    return vlc_from_EIT( psz_instring, i_length );
}

#define attach_SI_decoders(i_pid, name, member) do {\
    ts_pid_t *pid = GetPID(p_sys, i_pid);\
    if ( PIDSetup( p_demux, TYPE_SI, pid, NULL ) )\
    {\
        if( !ts_attach_SI_Tables_Decoders( pid ) )\
        {\
            msg_Err( p_demux, "Can't attach SI table decoders for pid %d", i_pid );\
            PIDRelease( p_demux, pid );\
        }\
        else\
        {\
            sdt->u.p_si->member = pid;\
            SetPIDFilter( p_demux->p_sys, pid, true );\
            msg_Dbg( p_demux, "  * pid=%d listening for "name, i_pid );\
        }\
    }\
    } while(0)\

static void SDTCallBack( void *opaque, dvbpsi_sdt_t *p_sdt )
{
    demux_t              *p_demux = opaque;
    demux_sys_t          *p_sys = p_demux->p_sys;
    ts_pid_t             *sdt = GetPID(p_sys, TS_SI_SDT_PID);
    ts_pat_t             *p_pat = ts_pid_Get(&p_sys->pids, 0)->u.p_pat;
    dvbpsi_sdt_service_t *p_srv;

    msg_Dbg( p_demux, "SDTCallBack called" );

    if( p_sys->es_creation != CREATE_ES ||
       !p_sdt->b_current_next ||
        p_sdt->i_version == sdt->u.p_si->p_ctx->i_version )
    {
        dvbpsi_sdt_delete( p_sdt );
        return;
    }

    /* First callback */
    if( sdt->u.p_si->p_ctx->i_version == -1 )
    {
        attach_SI_decoders( TS_SI_EIT_PID, "EIT", eitpid );
        attach_SI_decoders( TS_SI_TDT_PID, "TDT", tdtpid );
        if( p_sys->standard == TS_STANDARD_ARIB )
            attach_SI_decoders( TS_ARIB_CDT_PID, "CDT", cdtpid );
    }


    msg_Dbg( p_demux, "new SDT ts_id=%"PRIu16" version=%"PRIu8" current_next=%d "
             "network_id=%"PRIu16,
             p_sdt->i_extension,
             p_sdt->i_version, p_sdt->b_current_next,
             p_sdt->i_network_id );

    p_sys->b_broken_charset = false;

    for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
    {
        ts_pmt_t            *p_pmt = ts_pat_Get_pmt( p_pat, p_srv->i_service_id );
        vlc_meta_t          *p_meta;
        dvbpsi_descriptor_t *p_dr;

        const char *psz_type = NULL;
        const char *psz_status = NULL;

        msg_Dbg( p_demux, "  * service id=%"PRIu16" eit schedule=%d present=%d "
                 "running=%"PRIu8" free_ca=%d",
                 p_srv->i_service_id, p_srv->b_eit_schedule,
                 p_srv->b_eit_present, p_srv->i_running_status,
                 p_srv->b_free_ca );

        if( p_sys->vdr.i_service && p_srv->i_service_id != p_sys->vdr.i_service )
        {
            msg_Dbg( p_demux, "  * service id=%d skipped (not declared in vdr header)",
                     p_sys->vdr.i_service );
            continue;
        }

        p_meta = vlc_meta_New();
        for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
        {
            if( p_dr->i_tag == 0x48 )
            {
                static const char *ppsz_type[17] = {
                    "Reserved",
                    "Digital television service",
                    "Digital radio sound service",
                    "Teletext service",
                    "NVOD reference service",
                    "NVOD time-shifted service",
                    "Mosaic service",
                    "PAL coded signal",
                    "SECAM coded signal",
                    "D/D2-MAC",
                    "FM Radio",
                    "NTSC coded signal",
                    "Data broadcast service",
                    "Reserved for Common Interface Usage",
                    "RCS Map (see EN 301 790 [35])",
                    "RCS FLS (see EN 301 790 [35])",
                    "DVB MHP service"
                };
                dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
                char *str1 = NULL;
                char *str2 = NULL;

                /* Workarounds for broadcasters with broken EPG */

                if( p_sdt->i_network_id == 133 )
                    p_sys->b_broken_charset = true;  /* SKY DE & BetaDigital use ISO8859-1 */

                /* List of providers using ISO8859-1 */
                static const char ppsz_broken_providers[][8] = {
                    "CSAT",     /* CanalSat FR */
                    "GR1",      /* France televisions */
                    "MULTI4",   /* NT1 */
                    "MR5",      /* France 2/M6 HD */
                    ""
                };
                for( int i = 0; *ppsz_broken_providers[i]; i++ )
                {
                    const size_t i_length = strlen(ppsz_broken_providers[i]);
                    if( pD->i_service_provider_name_length == i_length &&
                        !strncmp( (char *)pD->i_service_provider_name, ppsz_broken_providers[i], i_length ) )
                        p_sys->b_broken_charset = true;
                }

                /* FIXME: Digital+ ES also uses ISO8859-1 */

                str1 = EITConvertToUTF8(p_demux,
                                        pD->i_service_provider_name,
                                        pD->i_service_provider_name_length,
                                        p_sys->b_broken_charset );
                str2 = EITConvertToUTF8(p_demux,
                                        pD->i_service_name,
                                        pD->i_service_name_length,
                                        p_sys->b_broken_charset );

                msg_Dbg( p_demux, "    - type=%"PRIu8" provider=%s name=%s",
                         pD->i_service_type, str1, str2 );

                if( !str2 || strcmp( "Service01", str2 ) ) /* Skip bogus libav/ffmpeg SDT */
                {
                    vlc_meta_SetTitle( p_meta, str2 );
                    vlc_meta_SetPublisher( p_meta, str1 );
                    if( pD->i_service_type >= 0x01 && pD->i_service_type <= 0x10 )
                        psz_type = ppsz_type[pD->i_service_type];
                }
                free( str1 );
                free( str2 );
            }
            else if( p_sys->standard == TS_STANDARD_ARIB &&
                     p_dr->i_tag == TS_ARIB_DR_LOGO_TRANSMISSION && p_pmt )
            {
                ts_arib_logo_dr_t *p_logodr = ts_arib_logo_dr_Decode( p_dr->p_data, p_dr->i_length );
                if( p_logodr )
                {
                    if( p_logodr->i_transmission_mode == 0 )
                    {
                        p_pmt->arib.i_logo_id = p_logodr->i_logo_id;
                        p_pmt->arib.i_download_id = p_logodr->i_download_data_id;
                    }
                    else if( p_logodr->i_transmission_mode == 1 )
                    {
                        p_pmt->arib.i_logo_id = p_logodr->i_logo_id;
                    }
                    else /* TODO simple logo identifier */
                    {

                    }

                    if( p_pmt->arib.i_logo_id > -1 )
                    {
                        char *psz_name;
                        if( asprintf( &psz_name, "attachment://onid[%"PRIx16"]_channel_logo_id[%"PRIx16"]q[%d]",
                                      p_sdt->i_network_id, p_logodr->i_logo_id,
                                      TS_ARIB_LOGO_TYPE_HD_LARGE ) > -1 )
                        {
                            vlc_meta_SetArtURL( p_meta, psz_name );
                            vlc_meta_SetExtra( p_meta, "ARTURL", psz_name );
                            free( psz_name );
                        }
                    }

                    ts_arib_logo_dr_Delete( p_logodr );
                }
            }
        }

        if( p_srv->i_running_status >= 0x01 && p_srv->i_running_status <= 0x04 )
        {
            static const char *ppsz_status[5] = {
                "Unknown",
                "Not running",
                "Starts in a few seconds",
                "Pausing",
                "Running"
            };
            psz_status = ppsz_status[p_srv->i_running_status];
        }

        if( psz_type )
            vlc_meta_SetExtra( p_meta, "Type", psz_type );
        if( psz_status )
            vlc_meta_SetExtra( p_meta, "Status", psz_status );

        es_out_Control( p_demux->out, ES_OUT_SET_GROUP_META,
                        p_srv->i_service_id, p_meta );
        vlc_meta_Delete( p_meta );
    }

    sdt->u.p_si->p_ctx->i_version = p_sdt->i_version;
    dvbpsi_sdt_delete( p_sdt );
}

static void EITDecodeMjd( int i_mjd, int *p_y, int *p_m, int *p_d )
{
    const int yp = (int)( ( (double)i_mjd - 15078.2)/365.25 );
    const int mp = (int)( ((double)i_mjd - 14956.1 - (int)(yp * 365.25)) / 30.6001 );
    const int c = ( mp == 14 || mp == 15 ) ? 1 : 0;

    *p_y = 1900 + yp + c*1;
    *p_m = mp - 1 - c*12;
    *p_d = i_mjd - 14956 - (int)(yp*365.25) - (int)(mp*30.6001);
}
#define CVT_FROM_BCD(v) ((((v) >> 4)&0xf)*10 + ((v)&0xf))
static int64_t EITConvertStartTime( uint64_t i_date )
{
    const int i_mjd = i_date >> 24;
    struct tm tm;

    tm.tm_hour = CVT_FROM_BCD(i_date >> 16);
    tm.tm_min  = CVT_FROM_BCD(i_date >>  8);
    tm.tm_sec  = CVT_FROM_BCD(i_date      );

    /* if all 40 bits are 1, the start is unknown */
    if( i_date == UINT64_C(0xffffffffff) )
        return -1;

    EITDecodeMjd( i_mjd, &tm.tm_year, &tm.tm_mon, &tm.tm_mday );
    tm.tm_year -= 1900;
    tm.tm_mon--;
    tm.tm_isdst = 0;

    return timegm( &tm );
}
static int EITConvertDuration( uint32_t i_duration )
{
    return CVT_FROM_BCD(i_duration >> 16) * 3600 +
           CVT_FROM_BCD(i_duration >> 8 ) * 60 +
           CVT_FROM_BCD(i_duration      );
}
#undef CVT_FROM_BCD

static void TDTCallBack( void *opaque, dvbpsi_tot_t *p_tdt )
{
    demux_t            *p_demux = opaque;
    demux_sys_t        *p_sys = p_demux->p_sys;


    p_sys->i_network_time = EITConvertStartTime( p_tdt->i_utc_time );
    p_sys->i_network_time_update = time(NULL);
    if( p_sys->standard == TS_STANDARD_ARIB )
    {
        /* All ARIB-B10 times are in JST time, where DVB is UTC. (spec being a fork)
           DVB TOT should include DTS offset in descriptor 0x58 (including DST),
           but as there's no DST in JAPAN (since Showa 27/1952)
           and considering that no-one seems to send TDT or desc 0x58,
           falling back on fixed offset is safe */

        p_sys->i_network_time += 9 * 3600;
    }

    /* Because libdvbpsi is broken and deduplicating timestamp tables,
     * we need to reset it to get next timestamp callback */

    ts_pid_t *pid = ts_pid_Get( &p_sys->pids, TS_SI_TDT_PID );
    dvbpsi_decoder_reset( pid->u.p_si->p_ctx->p_handle->p_decoder, true );
    dvbpsi_tot_delete(p_tdt);

    es_out_Control( p_demux->out, ES_OUT_SET_EPG_TIME, (int64_t) p_sys->i_network_time );
}

static void EITExtractDrDescItems( demux_t *p_demux, const dvbpsi_extended_event_dr_t *pE,
                                   vlc_epg_event_t *p_evt )
{
    demux_sys_t *p_sys = p_demux->p_sys;

    if( pE->i_entry_count )
    {
        char **ppsz_prev = NULL;
        /* Continued items from previous descriptor (ARIB) */
        if( p_evt->i_description_items > 0 )
            ppsz_prev = &p_evt->description_items[p_evt->i_description_items - 1].psz_value;

        for( int i = 0; i < pE->i_entry_count; i++ )
        {
            char *psz_key = NULL;
            /* Continued items have NULL key */
            const bool b_appending = ( pE->i_item_description_length[i] == 0 );
            if( !b_appending )
            {
                void *p_realloc = NULL;
                if( (size_t)p_evt->i_description_items < SIZE_MAX / sizeof(*p_evt->description_items) )
                {
                    p_realloc = realloc( p_evt->description_items,
                                        (p_evt->i_description_items + 1) *
                                         sizeof(*p_evt->description_items) );
                }
                if( !p_realloc )
                {
                    free( psz_key );
                    break;
                }
                p_evt->description_items = p_realloc;

                psz_key = EITConvertToUTF8( p_demux,
                                            pE->i_item_description[i],
                                            pE->i_item_description_length[i],
                                            p_sys->b_broken_charset );
                if( !psz_key )
                {
                    ppsz_prev = NULL;
                    continue;
                }
            }
            else if( ppsz_prev == NULL )
                continue;

            char *psz_itm = EITConvertToUTF8( p_demux,
                                              pE->i_item[i], pE->i_item_length[i],
                                              p_sys->b_broken_charset );
            if( !psz_itm )
            {
                free( psz_key );
                ppsz_prev = NULL;
                continue;
            }

            msg_Dbg( p_demux, "       - desc='%s' item='%s'",
                     psz_key ? psz_key : "(null)", psz_itm );
            if( b_appending )
            {
                /* Continued items */
                size_t i_total = strlen(*ppsz_prev) + strlen(psz_itm) + 1;
                char *psz_realloc = realloc( *ppsz_prev, i_total );
                if( psz_realloc )
                {
                    *ppsz_prev = psz_realloc;
                    strcat( *ppsz_prev, psz_itm );
                }
                free( psz_itm );
            }
            else
            {
                p_evt->description_items[p_evt->i_description_items].psz_key = psz_key;
                p_evt->description_items[p_evt->i_description_items].psz_value = psz_itm;
                ppsz_prev = &p_evt->description_items[p_evt->i_description_items].psz_value;
                p_evt->i_description_items++;
            }
        }
    }
}

static void EITCallBack( void *opaque, dvbpsi_eit_t *p_eit )
{
    demux_t            *p_demux = opaque;
    demux_sys_t        *p_sys = p_demux->p_sys;
    const dvbpsi_eit_event_t *p_evt;
    uint64_t i_runevt = 0;
    uint64_t i_fallbackevt = 0;
    vlc_epg_t *p_epg;

    msg_Dbg( p_demux, "EITCallBack called" );
    if( !p_eit->b_current_next )
    {
        dvbpsi_eit_delete( p_eit );
        return;
    }

    msg_Dbg( p_demux, "new EIT service_id=%"PRIu16" version=%"PRIu8" current_next=%d "
             "ts_id=%"PRIu16" network_id=%"PRIu16" segment_last_section_number=%"PRIu8" "
             "last_table_id=%"PRIu8,
             p_eit->i_extension,
             p_eit->i_version, p_eit->b_current_next,
             p_eit->i_ts_id, p_eit->i_network_id,
             p_eit->i_segment_last_section_number, p_eit->i_last_table_id );

    /* Use table ID for segmenting our EPG tables updates. 1 table id has 256 sections which
     * represents 8 segments of 32 sections each. Thus a max of 24 hours per table ID
     * (Should be even better with tableid+segmentid compound if dvbpsi would export segment id)
     * see TS 101 211, 4.1.4.2.1 */

    p_epg = vlc_epg_New( p_eit->i_table_id, p_eit->i_extension );
    if( !p_epg )
    {
        dvbpsi_eit_delete( p_eit );
        return;
    }

    for( p_evt = p_eit->p_first_event; p_evt; p_evt = p_evt->p_next )
    {
        dvbpsi_descriptor_t *p_dr;
        int64_t i_start;
        int i_duration;

        i_start = EITConvertStartTime( p_evt->i_start_time );
        SI_DEBUG_TIMESHIFT(i_start);
        i_duration = EITConvertDuration( p_evt->i_duration );

        /* We have to fix ARIB-B10 as all timestamps are JST */
        if( p_sys->standard == TS_STANDARD_ARIB )
        {
            /* See comments on TDT callback */
            i_start += 9 * 3600;
        }

        msg_Dbg( p_demux, "  * event id=%"PRIu16" start_time:%"PRId64" duration=%d "
                          "running=%"PRIu8" free_ca=%d",
                 p_evt->i_event_id, i_start, i_duration,
                 p_evt->i_running_status, p_evt->b_free_ca );

        /* */
        if( i_start <= 0 )
            continue;

        vlc_epg_event_t *p_epgevt = vlc_epg_event_New( p_evt->i_event_id,
                                                       i_start, i_duration );
        if( !p_epgevt )
            continue;

        if( !vlc_epg_AddEvent( p_epg, p_epgevt ) )
        {
            vlc_epg_event_Delete( p_epgevt );
            continue;
        }

        for( p_dr = p_evt->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
        {
            switch(p_dr->i_tag)
            {
            case 0x4d:
            {
                dvbpsi_short_event_dr_t *pE = dvbpsi_DecodeShortEventDr( p_dr );

                /* Only take first description, as we don't handle language-info
                   for epg atm*/

                if( pE )
                {
                    char **ppsz = &p_epgevt->psz_name;
                    free( *ppsz );
                    *ppsz = EITConvertToUTF8( p_demux,
                                              pE->i_event_name, pE->i_event_name_length,
                                              p_sys->b_broken_charset );
                    ppsz = &p_epgevt->psz_short_description;
                    free( *ppsz );
                    *ppsz = EITConvertToUTF8( p_demux,
                                              pE->i_text, pE->i_text_length,
                                              p_sys->b_broken_charset );
                    msg_Dbg( p_demux, "    - short event lang=%3.3s '%s' : '%s'",
                             pE->i_iso_639_code, p_epgevt->psz_name, *ppsz );
                }
            }
                break;

            case 0x4e:
            {
                dvbpsi_extended_event_dr_t *pE = dvbpsi_DecodeExtendedEventDr( p_dr );
                if( pE )
                {
                    msg_Dbg( p_demux, "    - extended event lang=%3.3s [%"PRIu8"/%"PRIu8"]",
                             pE->i_iso_639_code,
                             pE->i_descriptor_number, pE->i_last_descriptor_number );

                    if( pE->i_text_length > 0 )
                    {
                        char *psz_text = EITConvertToUTF8( p_demux,
                                                           pE->i_text, pE->i_text_length,
                                                           p_sys->b_broken_charset );
                        if( psz_text )
                        {
                            msg_Dbg( p_demux, "       - text='%s'", psz_text );

                            if( p_epgevt->psz_description )
                            {
                                size_t i_total = strlen( p_epgevt->psz_description ) + strlen( psz_text ) + 1;
                                char *psz_realloc = realloc( p_epgevt->psz_description, i_total );
                                if( psz_realloc )
                                {
                                    p_epgevt->psz_description = psz_realloc;
                                    strcat( psz_realloc, psz_text );
                                }
                                free( psz_text );
                            }
                            else
                            {
                                p_epgevt->psz_description = psz_text;
                            }
                        }
                    }

                    EITExtractDrDescItems( p_demux, pE, p_epgevt );
                }
            }
                break;

            case 0x55:
            {
                dvbpsi_parental_rating_dr_t *pR = dvbpsi_DecodeParentalRatingDr( p_dr );
                if ( pR )
                {
                    int i_min_age = 0;
                    for ( int i = 0; i < pR->i_ratings_number; i++ )
                    {
                        const dvbpsi_parental_rating_t *p_rating = & pR->p_parental_rating[ i ];
                        if ( p_rating->i_rating > 0x00 && p_rating->i_rating <= 0x0F )
                        {
                            if ( p_rating->i_rating + 3 > i_min_age )
                                i_min_age = p_rating->i_rating + 3;
                            msg_Dbg( p_demux, "    - parental control set to %d years",
                                     i_min_age );
                        }
                    }
                    p_epgevt->i_rating = i_min_age;
                }
            }
                break;

            default:
                msg_Dbg( p_demux, "    - event unknown dr 0x%"PRIx8"(%"PRIu8")", p_dr->i_tag, p_dr->i_tag );
                break;
            }
        }

        switch ( p_evt->i_running_status )
        {
            case TS_SI_RUNSTATUS_RUNNING:
                if( i_runevt == 0 )
                    i_runevt = i_start;
                break;
            case TS_SI_RUNSTATUS_UNDEFINED:
            {
                if( i_fallbackevt == 0 &&
                    i_start <= p_sys->i_network_time &&
                    p_sys->i_network_time < i_start + i_duration )
                    i_fallbackevt = i_start;
                break;
            }
            default:
                break;
        }
    }

    /* Update "now playing" field */
    if( i_runevt || i_fallbackevt )
        vlc_epg_SetCurrent( p_epg, (i_runevt) ? i_runevt : i_fallbackevt );

    if( p_epg->i_event > 0 )
    {
        if( p_epg->b_present && p_epg->p_current )
        {
            ts_pat_t *p_pat = ts_pid_Get(&p_sys->pids, 0)->u.p_pat;
            ts_pmt_t *p_pmt = ts_pat_Get_pmt(p_pat, p_eit->i_extension);
            if(p_pmt)
            {
                p_pmt->eit.i_event_start = p_epg->p_current->i_start;
                p_pmt->eit.i_event_length = p_epg->p_current->i_duration;
            }
        }
        p_epg->b_present = (p_eit->i_table_id == 0x4e);
        es_out_Control( p_demux->out, ES_OUT_SET_GROUP_EPG, p_eit->i_extension, p_epg );
    }
    vlc_epg_Delete( p_epg );

    dvbpsi_eit_delete( p_eit );
}

static void ARIB_CDT_RawCallback( dvbpsi_t *p_handle, const dvbpsi_psi_section_t* p_section,
                                  void *p_cdtpid )
{
    VLC_UNUSED(p_cdtpid);
    demux_t *p_demux = (demux_t *) p_handle->p_sys;
    demux_sys_t *p_sys = p_demux->p_sys;
    const ts_pat_t *p_pat = GetPID(p_sys, 0)->u.p_pat;

    while( p_section )
    {
        const uint8_t *p_data = p_section->p_payload_start;
        size_t i_data = p_section->p_payload_end - p_section->p_payload_start;

        if( i_data < (6U + 7 + 1) || p_data[2] != TS_ARIB_CDT_DATA_TYPE_LOGO )
            continue;

        uint16_t i_onid = (p_data[0] << 8) | p_data[1];
        uint16_t i_dr_len = ((p_data[3] & 0x0F) << 4) | p_data[4];
        if( i_data < i_dr_len + (6U + 7 + 1) )
            continue;

        /* STD-B21 A.5.4 (Japanese spec only) */

        const uint8_t *p_dmb = &p_data[5 + i_dr_len];
        size_t i_dmb = i_data - 5 - i_dr_len;

        while( i_dmb > 7 )
        {
            uint8_t i_logo_type = p_dmb[0];
            uint16_t i_logo_id = ((p_dmb[1] & 0x01) << 8) | p_dmb[2];
            uint16_t i_size = (p_dmb[5] << 8) | p_dmb[6];

            if( 7U + i_size > i_dmb )
                break;

            for( int i=0; i<p_pat->programs.i_size; i++ )
            {
                ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt;
                if( p_pmt->arib.i_logo_id == i_logo_id && i_logo_type == TS_ARIB_LOGO_TYPE_HD_LARGE )
                {
                    char *psz_name;
                    if( asprintf( &psz_name, "onid[%"PRIx16"]_channel_logo_id[%"PRIx16"]q[%d]",
                                  i_onid, i_logo_id, i_logo_type ) > -1 )
                    {
                        uint8_t *p_png; size_t i_png;
                        if( !vlc_dictionary_has_key( &p_sys->attachments, psz_name ) &&
                            ts_arib_inject_png_palette( &p_dmb[7], i_size, &p_png, &i_png ) )
                        {
                            input_attachment_t *p_att = vlc_input_attachment_New(
                                                        psz_name, "image/png", NULL, p_png, i_png );
                            if( p_att )
                            {
                                vlc_dictionary_insert( &p_sys->attachments, psz_name, p_att );
                                p_sys->updates |= INPUT_UPDATE_META;
                            }
                            free( p_png );
                        }
                        free( psz_name );
                    }
                }
            }

            i_dmb -= 7 + i_size;
            p_dmb += 7 + i_size;
        }

        p_section = p_section->p_next;
    }
}

static void SINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id,
                                uint16_t i_extension, void *p_pid_cbdata )
{
    assert( h );
    ts_pid_t *p_pid = (ts_pid_t *) p_pid_cbdata;
    demux_t *p_demux = (demux_t *) h->p_sys;
#if 0
    msg_Dbg( p_demux, "SINewTableCallback: table 0x%"PRIx8"(%"PRIu16") ext=0x%"PRIx16"(%"PRIu16")",
             i_table_id, i_table_id, i_extension, i_extension );
#endif
    if( p_pid->i_pid == TS_SI_SDT_PID && i_table_id == 0x42 )
    {
        if( !dvbpsi_sdt_attach( h, i_table_id, i_extension, SDTCallBack, p_demux ) )
            msg_Err( p_demux, "SINewTableCallback: failed attaching SDTCallback" );
    }
    else if( p_pid->i_pid == TS_SI_EIT_PID &&
             ( i_table_id == 0x4e || /* Current/Following */
               (i_table_id >= 0x50 && i_table_id <= 0x5f) ) ) /* Schedule */
    {
        if( !dvbpsi_eit_attach( h, i_table_id, i_extension,
                                EITCallBack, p_demux ) )
            msg_Err( p_demux, "SINewTableCallback: failed attaching EITCallback" );
    }
    else if( p_pid->i_pid == TS_SI_TDT_PID &&
            (i_table_id == TS_SI_TDT_TABLE_ID || i_table_id == TS_SI_TOT_TABLE_ID) )
    {
        if( !dvbpsi_tot_attach( h, i_table_id, i_extension, TDTCallBack, p_demux ) )
            msg_Err( p_demux, "SINewTableCallback: failed attaching TDTCallback" );
    }
    else if( p_pid->i_pid == TS_ARIB_CDT_PID && i_table_id == TS_ARIB_CDT_TABLE_ID )
    {
        if( dvbpsi_demuxGetSubDec( (dvbpsi_demux_t *) h->p_decoder, i_table_id, i_extension ) == NULL &&
            !ts_dvbpsi_AttachRawSubDecoder( h, i_table_id, i_extension, ARIB_CDT_RawCallback, p_pid ) )
            msg_Err( p_demux, "SINewTableCallback: failed attaching ARIB_CDT_RawCallback" );
    }
}

bool ts_attach_SI_Tables_Decoders( ts_pid_t *p_pid )
{
    if( p_pid->type != TYPE_SI )
        return false;

    if( dvbpsi_decoder_present( p_pid->u.p_si->p_ctx->p_handle ) )
        return true;

    return dvbpsi_AttachDemux( p_pid->u.p_si->p_ctx->p_handle, SINewTableCallBack, p_pid );
}

void ts_si_context_Delete( ts_si_context_t *p_ctx )
{
    if( dvbpsi_decoder_present( p_ctx->p_handle ) )
        dvbpsi_DetachDemux( p_ctx->p_handle );
    dvbpsi_delete( p_ctx->p_handle );
    free( p_ctx );
}

ts_si_context_t * ts_si_context_New( demux_t *p_demux )
{
    ts_si_context_t *p_ctx = malloc(sizeof(*p_ctx));
    if(likely(p_ctx))
    {
        p_ctx->p_handle = dvbpsi_new( &dvbpsi_messages, DVBPSI_MSG_DEBUG );
        if( !p_ctx->p_handle )
        {
            free( p_ctx );
            return NULL;
        }
        p_ctx->p_handle->p_sys = (void *) p_demux;
        p_ctx->i_version = -1;
    }
    return p_ctx;
}

Messung
CHZG
84969792

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