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

Quelle  asfpacket.c   Sprache: C

 

/*****************************************************************************
 * asfpacket.c :
 *****************************************************************************
 * Copyright © 2001-2004, 2011, 2014 VLC authors and VideoLAN
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
 * 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 "asfpacket.h"
#include <limits.h>

#ifndef NDEBUG
# define ASF_DEBUG 1
#endif

typedef struct asf_packet_t
{
    uint32_t property;
    uint32_t length;
    uint32_t padding_length;
    vlc_tick_t  send_time;
    bool multiple;
    int length_type;

    /* buffer handling for this ASF packet */
    uint32_t i_skip;
    const uint8_t *p_peek;
    uint32_t left;
} asf_packet_t;

static inline int GetValue2b(uint32_t *var, const uint8_t *p, unsigned int *skip, int left, int bits)
{
    switch(bits&0x03)
    {
    case 1:
        if (left < 1)
            return -1;
        *var = p[*skip]; *skip += 1;
        return 0;
    case 2:
        if (left < 2)
            return -1;
        *var = GetWLE(&p[*skip]); *skip += 2;
        return 0;
    case 3:
        if (left < 4)
            return -1;
        *var = GetDWLE(&p[*skip]); *skip += 4;
        return 0;
    case 0:
    default:
        return 0;
    }
}

static int DemuxSubPayload( asf_packet_sys_t *p_packetsys,
                            uint8_t i_stream_number, asf_track_info_t *p_tkinfo,
                            uint32_t i_sub_payload_data_length, vlc_tick_t i_pts, vlc_tick_t i_dts,
                            uint32_t i_media_object_number, uint32_t i_media_object_offset,
                            bool b_keyframe, bool b_ignore_pts )
{
    block_t **pp_frame = &p_tkinfo->p_frame;

    if( p_packetsys->b_deduplicate )
    {
        for(size_t i=0; i<p_tkinfo->i_pktcount; i++)
        {
            if(p_tkinfo->prev[i].media_number == i_media_object_number &&
               p_tkinfo->prev[i].media_offset == i_media_object_offset)
            {
                vlc_debug(p_packetsys->logger, "dropping duplicate num %"PRIu32" off %"PRIu32,
                          i_media_object_number , i_media_object_offset);
                return vlc_stream_Read( p_packetsys->s, NULL, i_sub_payload_data_length ) != i_sub_payload_data_length ? -1 : 0;
            }
        }

        unsigned dedupindex;
        if( p_tkinfo->i_pktcount < ASFPACKET_DEDUPLICATE )
            dedupindex = p_tkinfo->i_pkt = p_tkinfo->i_pktcount++;
        else
            dedupindex = (++p_tkinfo->i_pkt) % ASFPACKET_DEDUPLICATE;

        p_tkinfo->prev[dedupindex].media_number = i_media_object_number;
        p_tkinfo->prev[dedupindex].media_offset = i_media_object_offset;
    }

    /* FIXME I don't use i_media_object_number, sould I ? */
    if( *pp_frame && i_media_object_offset == 0 )
    {
        p_packetsys->pf_send( p_packetsys, i_stream_number, pp_frame );
    }

    block_t *p_frag = vlc_stream_Block( p_packetsys->s, i_sub_payload_data_length );
    if( p_frag == NULL ) {
        vlc_warning( p_packetsys->logger, "cannot read data" );
        return -1;
    }

    p_frag->i_pts = (b_ignore_pts) ? VLC_TICK_INVALID : VLC_TICK_0 + i_pts;
    p_frag->i_dts = VLC_TICK_0 + i_dts;
    if ( b_keyframe )
        p_frag->i_flags |= BLOCK_FLAG_TYPE_I;

    block_ChainAppend( pp_frame, p_frag );

    return 0;
}

static void ParsePayloadExtensions( asf_packet_sys_t *p_packetsys,
                                    const asf_track_info_t *p_tkinfo,
                                    const uint8_t *p_data, size_t i_data,
                                    bool *b_keyframe )
{
    if ( !p_tkinfo || !p_tkinfo->p_esp || !p_tkinfo->p_esp->p_ext )
        return;

    uint16_t i_payload_extensions_size;
    asf_payload_extension_system_t *p_ext = NULL;

    /* Extensions always come in the declared order */
    for ( int i=0; i< p_tkinfo->p_esp->i_payload_extension_system_count; i++ )
    {
        p_ext = &p_tkinfo->p_esp->p_ext[i];
        if ( p_ext->i_data_size == 0xFFFF ) /* Variable length extension data */
        {
            if ( i_data < 2 ) return;
            i_payload_extensions_size = GetWLE( p_data );
            p_data += 2;
            i_data -= 2;
            i_payload_extensions_size = 0;
        }
        else
        {
            i_payload_extensions_size = p_ext->i_data_size;
        }

        if ( i_data < i_payload_extensions_size ) return;

        if ( guidcmp( &p_ext->i_extension_id, &mfasf_sampleextension_outputcleanpoint_guid ) )
        {
            if ( i_payload_extensions_size != 1 ) goto sizeerror;
            *b_keyframe |= *p_data;
        }
        else if ( guidcmp( &p_ext->i_extension_id, &asf_dvr_sampleextension_videoframe_guid ) )
        {
            if ( i_payload_extensions_size != 4U ) goto sizeerror;

            uint32_t i_val = GetDWLE( p_data );
            /* Valid keyframe must be a split frame start fragment */
            *b_keyframe = i_val & ASF_EXTENSION_VIDEOFRAME_NEWFRAME;
            if ( *b_keyframe )
            {
                /* And flagged as IFRAME */
                *b_keyframe |= ( ( i_val & ASF_EXTENSION_VIDEOFRAME_TYPE_MASK )
                                 == ASF_EXTENSION_VIDEOFRAME_IFRAME );
            }
        }
        else if ( guidcmp( &p_ext->i_extension_id, &mfasf_sampleextension_pixelaspectratio_guid ) &&
                  p_packetsys->pf_setaspectratio )
        {
            if ( i_payload_extensions_size != 2U ) goto sizeerror;

            p_packetsys->pf_setaspectratio( p_packetsys, p_tkinfo->p_sp->i_stream_number,
                                            p_data[0], p_data[1] );
        }
        else if ( guidcmp( &p_ext->i_extension_id, &asf_dvr_sampleextension_timing_rep_data_guid ) )
        {
            if ( i_payload_extensions_size != 48 ) goto sizeerror;
            /* const int64_t i_pts = GetQWLE(&p_data[8]); */
        }
#if 0
        else
        {
            msg_Dbg( p_demux, "Unknown extension " GUID_FMT, GUID_PRINT( p_ext->i_extension_id ) );
        }
#endif
        i_data -= i_payload_extensions_size;
        p_data += i_payload_extensions_size;
    }

    return;

sizeerror:
    vlc_warning( p_packetsys->logger, "Unknown extension " GUID_FMT " data size of %u",
              GUID_PRINT( p_ext->i_extension_id ), i_payload_extensions_size );
}

static int DemuxPayload(asf_packet_sys_t *p_packetsys, asf_packet_t *pkt, int i_payload)
{
#ifndef ASF_DEBUG
    VLC_UNUSED( i_payload );
#endif
    if( ! pkt->left || pkt->i_skip >= pkt->left )
        return -1;

    bool b_packet_keyframe = pkt->p_peek[pkt->i_skip] >> 7;
    uint8_t i_stream_number = pkt->p_peek[pkt->i_skip++] & 0x7f;

    uint32_t i_media_object_number = 0;
    if (GetValue2b(&i_media_object_number, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 4) < 0)
        return -1;
    uint32_t i_media_object_offset = 0;
    if (GetValue2b(&i_media_object_offset, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 2) < 0)
        return -1;
    uint32_t i_replicated_data_length = 0;
    if (GetValue2b(&i_replicated_data_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property) < 0)
        return -1;

    vlc_tick_t i_pkt_time;
    vlc_tick_t i_pkt_time_delta = 0;
    uint32_t i_payload_data_length = 0;
    uint32_t i_temp_payload_length = 0;

    /* First packet, in case we do not have index to guess preroll start time */
    if ( *p_packetsys->pi_preroll_start == ASFPACKET_PREROLL_FROM_CURRENT )
        *p_packetsys->pi_preroll_start = pkt->send_time;

    asf_track_info_t *p_tkinfo = p_packetsys->pf_gettrackinfo( p_packetsys, i_stream_number );
    if ( !p_tkinfo )
        goto skip;

    bool b_ignore_pts = (p_tkinfo->i_cat == VIDEO_ES); /* ignore PTS delta with video when not set by mux */

    if( pkt->left - pkt->i_skip < i_replicated_data_length )
        return -1;

    /* Non compressed */
    if( i_replicated_data_length > 7 ) // should be at least 8 bytes
    {
        /* Followed by 2 optional DWORDS, offset in media and *media* presentation time */
        i_pkt_time = VLC_TICK_FROM_MS(GetDWLE( pkt->p_peek + pkt->i_skip + 4 ));

        /* Parsing extensions, See 7.3.1 */
        ParsePayloadExtensions( p_packetsys, p_tkinfo,
                                &pkt->p_peek[pkt->i_skip + 8],
                                i_replicated_data_length - 8,
                                &b_packet_keyframe );
        i_pkt_time -= *p_packetsys->pi_preroll;
        pkt->i_skip += i_replicated_data_length;
    }
    else if ( i_replicated_data_length == 0 )
    {
        /* optional DWORDS missing */
        i_pkt_time = pkt->send_time;
    }
    /* Compressed payload */
    else if( i_replicated_data_length == 1 )
    {
        /* i_media_object_offset is *media* presentation time */
        /* Next byte is *media* Presentation Time Delta */
        i_pkt_time_delta = VLC_TICK_FROM_MS(pkt->p_peek[pkt->i_skip]);
        b_ignore_pts = false;
        i_pkt_time = VLC_TICK_FROM_MS(i_media_object_offset);
        i_pkt_time -= *p_packetsys->pi_preroll;
        pkt->i_skip++;
        i_media_object_offset = 0;
    }
    else
    {
        /* >1 && <8 Invalid replicated length ! */
        vlc_warning( p_packetsys->logger, "Invalid replicated data length detected." );
        if( pkt->length - pkt->i_skip < pkt->padding_length )
            return -1;

        i_payload_data_length = pkt->length - pkt->padding_length - pkt->i_skip;
        goto skip;
    }

    if( ! pkt->left || pkt->i_skip >= pkt->left )
        return -1;

    bool b_preroll_done = ( pkt->send_time > (*p_packetsys->pi_preroll_start + *p_packetsys->pi_preroll) );

    if (i_pkt_time < 0) i_pkt_time = 0; // FIXME?

    if( pkt->multiple ) {
        if (GetValue2b(&i_temp_payload_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->length_type) < 0)
            return -1;
    }
    else
    {
        if( pkt->length - pkt->i_skip < pkt->padding_length )
            return -1;
        i_temp_payload_length = pkt->length - pkt->padding_length - pkt->i_skip;
    }

    i_payload_data_length = i_temp_payload_length;

#ifdef ASF_DEBUG
     vlc_debug( p_packetsys->logger,
              "payload(%d) stream_number:%"PRIu8" media_object_number:%d media_object_offset:%"PRIu32
                " replicated_data_length:%"PRIu32" payload_data_length %"PRIu32,
              i_payload + 1, i_stream_number, i_media_object_number,
              i_media_object_offset, i_replicated_data_length, i_payload_data_length );
     vlc_debug( p_packetsys->logger,
              "  pkttime=%"PRId64" st=%"PRId64,
              i_pkt_time, MS_FROM_VLC_TICK(pkt->send_time) );
#endif

     if( ! i_payload_data_length || i_payload_data_length > pkt->left )
     {
         vlc_debug( p_packetsys->logger, "  payload length problem %d %"PRIu32
                    " %"PRIu32, pkt->multiple, i_payload_data_length, pkt->left );
         return -1;
     }

    if ( p_packetsys->pf_doskip &&
         p_packetsys->pf_doskip( p_packetsys, i_stream_number, b_packet_keyframe ) )
        goto skip;

    if ( b_preroll_done )
    {
        vlc_tick_t i_track_time = i_pkt_time;

        if ( p_packetsys->pf_updatetime )
            p_packetsys->pf_updatetime( p_packetsys, i_stream_number, i_track_time );
    }

    if( p_packetsys->pf_updatesendtime )
        p_packetsys->pf_updatesendtime( p_packetsys, pkt->send_time );

    vlc_tick_t i_subpayload_delta = 0;
    while (i_payload_data_length && pkt->i_skip < pkt->left )
    {
        uint32_t i_sub_payload_data_length = i_payload_data_length;
        if( i_replicated_data_length == 1 )
        {
            i_sub_payload_data_length = pkt->p_peek[pkt->i_skip++];
            i_payload_data_length--;
            if( i_sub_payload_data_length > i_payload_data_length )
                goto skip;
        }

        if (pkt->i_skip && vlc_stream_Read( p_packetsys->s, NULL, pkt->i_skip ) != pkt->i_skip )
        {
            vlc_warning( p_packetsys->logger, "unexpected end of file" );
            return -1;
        }

        vlc_tick_t i_payload_pts;
        i_payload_pts = i_pkt_time + i_subpayload_delta;
        if ( p_tkinfo->p_sp )
            i_payload_pts -= VLC_TICK_FROM_MSFTIME(p_tkinfo->p_sp->i_time_offset);

        vlc_tick_t i_payload_dts = i_pkt_time;

        if ( p_tkinfo->p_sp )
            i_payload_dts -= VLC_TICK_FROM_MSFTIME(p_tkinfo->p_sp->i_time_offset);

        if ( i_sub_payload_data_length &&
             DemuxSubPayload( p_packetsys, i_stream_number, p_tkinfo,
                              i_sub_payload_data_length, i_payload_pts, i_payload_dts,
                              i_media_object_number, i_media_object_offset,
                              b_packet_keyframe, b_ignore_pts ) < 0)
            return -1;

        if ( pkt->left > pkt->i_skip + i_sub_payload_data_length )
            pkt->left -= pkt->i_skip + i_sub_payload_data_length;
        else
            pkt->left = 0;
        pkt->i_skip = 0;
        if( pkt->left > 0 )
        {
            ssize_t i_return = vlc_stream_Peek( p_packetsys->s, &pkt->p_peek, pkt->left );
            if ( i_return <= 0 || (size_t) i_return < pkt->left )
            {
                vlc_warning( p_packetsys->logger, "unexpected end of file" );
                return -1;
            }
        }

        if ( i_sub_payload_data_length <= i_payload_data_length )
            i_payload_data_length -= i_sub_payload_data_length;
        else
            i_payload_data_length = 0;

        i_subpayload_delta += i_pkt_time_delta;
    }

    return 0;

skip:
    pkt->i_skip += i_payload_data_length;
    return 0;
}

int DemuxASFPacket( asf_packet_sys_t *p_packetsys,
                    uint32_t i_data_packet_min, uint32_t i_data_packet_max,
                    uint64_t i_data_begin, uint64_t i_data_end )
{
    const uint64_t i_read_pos = vlc_stream_Tell( p_packetsys->s );
    if( i_read_pos < i_data_begin ||
        (i_data_end && ( i_data_packet_min > i_data_end ||
                         i_read_pos > i_data_end - i_data_packet_min ) ) )
        return 0;

    const uint8_t *p_peek;
    ssize_t i_return = vlc_stream_Peek( p_packetsys->s, &p_peek,i_data_packet_min );
    if( i_return <= 0 || (size_t) i_return < i_data_packet_min )
    {
        vlc_warning( p_packetsys->logger, "unexpected end of file" );
        return 0;
    }
    unsigned int i_skip = 0;

    /* *** parse error correction if present *** */
    if( p_peek[0]&0x80 )
    {
        unsigned int i_error_correction_data_length = p_peek[0] & 0x0f;
        unsigned int i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01;
        unsigned int i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03;
        i_skip += 1; // skip error correction flags

        if( i_error_correction_length_type != 0x00 ||
            i_opaque_data_present != 0 ||
            i_error_correction_data_length != 0x02 )
        {
            goto loop_error_recovery;
        }

        i_skip += i_error_correction_data_length;
    }
    else
        vlc_warning( p_packetsys->logger, "no error correction" );

    /* sanity check */
    if( i_skip + 2 >= i_data_packet_min )
        goto loop_error_recovery;

    asf_packet_t pkt;
    int i_packet_flags = p_peek[i_skip]; i_skip++;
    pkt.property = p_peek[i_skip]; i_skip++;
    pkt.multiple = !!(i_packet_flags&0x01);

    pkt.length = p_packetsys->b_can_hold_multiple_packets ? i_data_packet_max : i_data_packet_min;
    pkt.padding_length = 0;

    if (GetValue2b(&pkt.length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 5) < 0)
        goto loop_error_recovery;
    uint32_t i_packet_sequence;
    if (GetValue2b(&i_packet_sequence, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 1) < 0)
        goto loop_error_recovery;
    if (GetValue2b(&pkt.padding_length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 3) < 0)
        goto loop_error_recovery;

    if( pkt.padding_length > pkt.length )
    {
        vlc_warning( p_packetsys->logger, "Too large padding: %"PRIu32, pkt.padding_length );
        goto loop_error_recovery;
    }

    if( pkt.length < i_data_packet_min )
    {
        /* if packet length too short, there is extra padding */
        pkt.padding_length += i_data_packet_min - pkt.length;
        pkt.length = i_data_packet_min;
    }

    if( i_skip + 4 > i_data_packet_min )
        goto loop_error_recovery;

    pkt.send_time = VLC_TICK_FROM_MS(GetDWLE( p_peek + i_skip )); i_skip += 4;
    /* uint16_t i_packet_duration = GetWLE( p_peek + i_skip ); */ i_skip += 2;

    uint32_t i_read_length = pkt.length;
    if( i_data_end &&
        (pkt.length > i_data_end ||
         i_read_pos > i_data_end - pkt.length) )
    {
        if( !p_packetsys->b_can_hold_multiple_packets )
        {
            vlc_warning( p_packetsys->logger, "pkt size %"PRIu32" at %"PRIu64" does not fit data chunk size %"PRIu32,
                         pkt.length, i_read_pos, i_data_packet_max );
            return 0;
        }
        i_read_length = i_data_end - i_read_pos;
    }

    i_return = vlc_stream_Peek( p_packetsys->s, &p_peek, i_read_length );
    if( i_return <= 0 || pkt.length == 0 || (size_t)i_return < i_read_length )
    {
        vlc_warning( p_packetsys->logger, "unexpected end of file" );
        return 0;
    }

    int i_payload_count = 1;
    pkt.length_type = 0x02; //unused
    if( pkt.multiple )
    {
        if( i_skip + 1 >= i_data_packet_min )
            goto loop_error_recovery;
        i_payload_count = p_peek[i_skip] & 0x3f;
        pkt.length_type = ( p_peek[i_skip] >> 6 )&0x03;
        i_skip++;
    }

#ifdef ASF_DEBUG
    vlc_debug( p_packetsys->logger, "%d payloads", i_payload_count);
#endif

    pkt.i_skip = i_skip;
    pkt.p_peek = p_peek;
    pkt.left = i_read_length;

    for( int i_payload = 0; i_payload < i_payload_count &&
         (!p_packetsys->b_can_hold_multiple_packets || pkt.left > 0); i_payload++ )
        if (DemuxPayload(p_packetsys, &pkt, i_payload) < 0)
        {
            vlc_warning( p_packetsys->logger, "payload err %d / %d", i_payload + 1, i_payload_count );
            return 0;
        }

    if( pkt.left > 0 )
    {
        uint32_t toskip;
        if( pkt.left > pkt.padding_length &&
            !p_packetsys->b_can_hold_multiple_packets )
        {
            toskip = pkt.left;
#ifdef ASF_DEBUG
            vlc_warning( p_packetsys->logger, "Didn't read %"PRIu32" bytes in the packet at %"PRIu64,
                            pkt.left - pkt.padding_length, vlc_stream_Tell(p_packetsys->s) );
#endif
        }
        else if( pkt.left < pkt.padding_length )
        {
            toskip = p_packetsys->b_can_hold_multiple_packets ? pkt.left : 0;
#ifdef ASF_DEBUG
            vlc_warning( p_packetsys->logger, "Read %"PRIu32" too much bytes from the packet",
                               pkt.padding_length - pkt.left );
#endif
        }
        else
        {
            toskip = pkt.padding_length;
        }

        if( toskip  && vlc_stream_Read( p_packetsys->s, NULL, toskip ) != toskip )
        {
            vlc_error( p_packetsys->logger, "cannot skip data, EOF ?" );
            return 0;
        }
    }

    return 1;

loop_error_recovery:
    vlc_warning( p_packetsys->logger, "unsupported packet header" );
    if( i_data_packet_min != i_data_packet_max )
    {
        vlc_error( p_packetsys->logger, "unsupported packet header, fatal error" );
        return -1;
    }
    if( vlc_stream_Read( p_packetsys->s, NULL, i_data_packet_min ) != i_data_packet_min )
    {
        vlc_warning( p_packetsys->logger, "cannot skip data, EOF ?" );
        return 0;
    }

    return 1;
}

void ASFPacketTrackInit( asf_track_info_t *p_ti )
{
    p_ti->i_cat = UNKNOWN_ES;
    p_ti->p_esp = NULL;
    p_ti->p_sp = NULL;
    p_ti->p_frame = NULL;
    p_ti->i_pktcount = 0;
    p_ti->i_pkt = 0;
}

void ASFPacketTrackReset( asf_track_info_t *p_ti )
{
    if( p_ti->p_frame )
        block_ChainRelease( p_ti->p_frame );
    p_ti->p_frame = NULL;
    p_ti->i_pktcount = 0;
    p_ti->i_pkt = 0;
}

Messung
CHZG
859610093

¤ Dauer der Verarbeitung: 0.11 Sekunden  ¤

*© 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.