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

Quelle  demux.cpp   Sprache: C

 


/*****************************************************************************
 * mkv.cpp : matroska demuxer
 *****************************************************************************
 * Copyright (C) 2003-2004 VLC authors and VideoLAN
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Steve Lhomme <steve.lhomme@free.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.
 *****************************************************************************/


#include "demux.hpp"
#include "stream_io_callback.hpp"
#include "Ebml_parser.hpp"
#include "virtual_segment.hpp"

namespace mkv {

demux_sys_t::~demux_sys_t()
{
    size_t i;
    for ( i=0; i<streams.size(); i++ )
        delete streams[i];
    for ( i=0; i<opened_segments.size(); i++ )
        delete opened_segments[i];
    for ( i=0; i<used_vsegments.size(); i++ )
        delete used_vsegments[i];
    if( meta ) vlc_meta_Delete( meta );

    while( titles.size() )
    { vlc_input_title_Delete( titles.back() ); titles.pop_back();}
}


bool demux_sys_t::AnalyseAllSegmentsFound( demux_t *p_demux, matroska_stream_c *p_stream1 )
{
    int i_upper_lvl = 0;
    EbmlElement *p_l0;
    bool b_keep_stream = false;

    /* verify the EBML Header... it shouldn't be bigger than 1kB */
    p_l0 = p_stream1->estream.FindNextID(EBML_INFO(EbmlHead), 1024);
    if (p_l0 == nullptr || p_l0->IsDummy())
    {
        msg_Err( p_demux, "No EBML header found" );
        delete p_l0;
        return false;
    }

    /* verify we can read this Segment */
    try
    {
        EbmlElement *el = nullptr;
        p_l0->Read( p_stream1->estream, EBML_CLASS_CONTEXT(EbmlHead), i_upper_lvl, el, true);
        if (i_upper_lvl != 0)
        {
            assert(el != nullptr);
            delete el;
        }
    }
    catch(...)
    {
        msg_Err(p_demux, "EBML Header Read failed");
        delete p_l0;
        return false;
    }

    EDocType doc_type = GetChild<EDocType>(*static_cast<EbmlHead*>(p_l0));
    if (std::string(doc_type) != "matroska" && std::string(doc_type) != "webm" )
    {
        msg_Err( p_demux, "Not a Matroska file : DocType = %s ", std::string(doc_type).c_str());
        delete p_l0;
        return false;
    }

    EDocTypeReadVersion doc_read_version = GetChild<EDocTypeReadVersion>(*static_cast<EbmlHead*>(p_l0));
    if (uint64_t(doc_read_version) > 5)
    {
        msg_Err( p_demux, "matroska file needs version %" PRId64 " but only versions 1 to 4 supported", uint64_t(doc_read_version));
        delete p_l0;
        return false;
    }

    delete p_l0;


    // find all segments in this file
    p_l0 = p_stream1->estream.FindNextID(EBML_INFO(KaxSegment), UINT64_MAX);
    if (p_l0 == nullptr || p_l0->IsDummy())
    {
        msg_Err( p_demux, "No segment found" );
        delete p_l0;
        return false;
    }

    while (p_l0 != nullptr)
    {
        bool b_l0_handled = false;

        if ( MKV_IS_ID( p_l0, KaxSegment) )
        {
            matroska_segment_c *p_segment1 = new matroska_segment_c( *this, p_stream1->estream, (KaxSegment*)p_l0 );

            p_segment1->Preload();

            if ( !p_segment1->p_segment_uid ||
                 !SegmentIsOpened( *p_segment1->p_segment_uid ) )
            {
                opened_segments.push_back( p_segment1 );
                b_keep_stream = true;
                p_stream1->segments.push_back( p_segment1 );
            }
            else
            {
                p_segment1->segment = NULL;
                delete p_segment1;
            }

            b_l0_handled = true;
        }

        if ( !b_seekable )
            break;

        EbmlElement* p_l0_prev = p_l0;

        if (p_l0->IsFiniteSize() )
        {
            p_l0->SkipData(p_stream1->estream, Context_KaxMatroska);
            p_l0 = p_stream1->estream.FindNextID(EBML_INFO(KaxSegment), UINT64_MAX);
            if (p_l0 != nullptr && p_l0->IsDummy())
            {
                delete p_l0;
                p_l0 = nullptr;
            }
        }
        else
        {
            p_l0 = nullptr;
        }

        if( b_l0_handled == false )
            delete p_l0_prev;
    }

    if ( !b_keep_stream )
        return false;

    return true;
}

void demux_sys_t::PreloadFamily( const matroska_segment_c & of_segment )
{
    for (size_t i=0; i<opened_segments.size(); i++)
    {
        opened_segments[i]->PreloadFamily( of_segment );
    }
}

// preload all the linked segments for all preloaded segments
bool demux_sys_t::PreloadLinked()
{
    size_t i, j, ij = 0;
    virtual_segment_c *p_vseg;

    if ( unlikely(opened_segments.size() == 0) )
        return false;

    p_current_vsegment = new (std::nothrow) virtual_segment_c( *(opened_segments[0]), opened_segments );
    if ( !p_current_vsegment )
        return false;

    if ( unlikely(p_current_vsegment->CurrentEdition() == NULL) )
    {
        delete p_current_vsegment;
        return false;
    }

    /* Set current chapter */
    msg_Dbg( &demuxer, "NEW START CHAPTER uid=%" PRId64, p_current_vsegment->CurrentChapter() && p_current_vsegment->CurrentChapter()->p_chapter ?
                 p_current_vsegment->CurrentChapter()->p_chapter->i_uid : 0 );

    used_vsegments.push_back( p_current_vsegment );

    for ( i=1; i< opened_segments.size(); i++ )
    {
        /* add segments from the same family to used_segments */
        if ( opened_segments[0]->SameFamily( *(opened_segments[i]) ) )
        {
            virtual_segment_c *p_vsegment = new (std::nothrow) virtual_segment_c( *(opened_segments[i]), opened_segments );
            if ( likely(p_vsegment != NULL) )
                used_vsegments.push_back( p_vsegment );
        }
    }

    // publish all editions of all usable segment
    for ( i=0; i< used_vsegments.size(); i++ )
    {
        p_vseg = used_vsegments[i];
        if ( p_vseg->Editions() != NULL )
        {
            for ( j=0; j<p_vseg->Editions()->size(); j++ )
            {
                virtual_edition_c * p_ved = (*p_vseg->Editions())[j];
                input_title_t *p_title = vlc_input_title_New();
                int i_chapters;

                // TODO use a name for each edition, let the TITLE deal with a codec name
                if ( p_title->psz_name == NULL )
                {
                    const auto edition_name = p_ved->GetMainName();
                    if( edition_name.length() )
                        p_title->psz_name = strdup( edition_name.c_str() );
                    else
                    {
                        /* Check in tags if the edition has a name */

                        /* We use only the tags of the first segment as it contains the edition */
                        matroska_segment_c::tags_t const& tags = opened_segments[0]->tags;
                        uint64_t i_ed_uid = 0;
                        if( p_ved->p_edition )
                            i_ed_uid = (uint64_t) p_ved->p_edition->i_uid;

                        for( size_t k = 0; k < tags.size(); k++ )
                        {
                            if( tags[k].i_tag_type == EDITION_UID && tags[k].i_uid == i_ed_uid )
                                for( size_t l = 0; l < tags[k].simple_tags.size(); l++ )
                                {
                                    SimpleTag const& st = tags[k].simple_tags[l];
                                    if ( st.tag_name == "TITLE" )
                                    {
                                        msg_Dbg( &demuxer, "Using title \"%s\" from tag for edition %" PRIu64, st.value.c_str (), i_ed_uid );
                                        free(p_title->psz_name);
                                        p_title->psz_name = strdup( st.value.c_str () );
                                        break;
                                    }
                                }
                        }

                        if( !p_title->psz_name &&
                            asprintf(&(p_title->psz_name), "%s %d", "Segment", (int)ij) == -1 )
                            p_title->psz_name = NULL;
                    }
                }

                ij++;
                i_chapters = 0;
                p_ved->PublishChapters( *p_title, i_chapters, 0 );

                // Input duration into i_length
                p_title->i_length = p_ved->i_duration;

                titles.push_back( p_title );
            }
        }
        p_vseg->i_sys_title = p_vseg->i_current_edition;
    }

    // TODO decide which segment should be first used (VMG for DVD)

    return true;
}

bool demux_sys_t::FreeUnused()
{
    auto sIt = std::remove_if(begin(streams), end(streams), [](const matroska_stream_c* p_s) {
        return !p_s->isUsed();
    });
    for (auto it = sIt; it != end(streams); ++it)
        delete *it;
    streams.erase(sIt, end(streams));

    auto sgIt = std::remove_if(begin(opened_segments), end(opened_segments),
                [](const matroska_segment_c* p_sg) {
        return !p_sg->b_preloaded;
    });
    for (auto it = sgIt; it != end(opened_segments); ++it)
        delete *it;
    opened_segments.erase(sgIt, end(opened_segments));

    return !streams.empty() && !opened_segments.empty();
}

bool demux_sys_t::PreparePlayback( virtual_segment_c & new_vsegment )
{
    if ( !new_vsegment.CurrentSegment() )
        return false;

    if ( p_current_vsegment != &new_vsegment )
    {
        if ( p_current_vsegment->CurrentSegment() != NULL )
            p_current_vsegment->CurrentSegment()->ESDestroy();

        p_current_vsegment = &new_vsegment;
        p_current_vsegment->CurrentSegment()->ESCreate();
        i_current_title = p_current_vsegment->i_sys_title;
    }
    if( !p_current_vsegment->CurrentSegment()->b_cues )
        msg_Warn( &p_current_vsegment->CurrentSegment()->sys.demuxer, "no cues/empty cues found->seek won't be precise" );

    i_duration = p_current_vsegment->Duration();

    /* add information */
    p_current_vsegment->CurrentSegment()->InformationCreate( );
    p_current_vsegment->CurrentSegment()->ESCreate( );

    return true;
}

void demux_sys_t::JumpTo( virtual_segment_c & vsegment, virtual_chapter_c & vchapter )
{
    if ( !vchapter.p_chapter || !vchapter.p_chapter->Enter( true ) )
    {
        // jump to the location in the found segment
        vsegment.Seek( demuxer, vchapter.i_mk_virtual_start_time, &vchapter );
    }
}

bool demux_sys_t::SegmentIsOpened( const EbmlBinary & uid ) const
{
    for (size_t i=0; i<opened_segments.size(); i++)
    {
        if ( opened_segments[i]->p_segment_uid && *opened_segments[i]->p_segment_uid == uid )
            return true;
    }
    return false;
}

virtual_chapter_c *demux_sys_t::BrowseCodecPrivate( chapter_codec_id codec_id,
                                                    chapter_cmd_match match,
                                                    virtual_segment_c * &p_vsegment_found )
{
    virtual_chapter_c *p_result = NULL;
    for (size_t i=0; i<used_vsegments.size(); i++)
    {
        p_result = used_vsegments[i]->BrowseCodecPrivate( codec_id, match );
        if ( p_result != NULL )
        {
            p_vsegment_found = used_vsegments[i];
            break;
        }
    }
    return p_result;
}

virtual_chapter_c *demux_sys_t::FindVChapter( chapter_uid i_find_uid, virtual_segment_c * & p_vsegment_found )
{
    virtual_chapter_c *p_result = NULL;
    for (size_t i=0; i<used_vsegments.size(); i++)
    {
        p_result = used_vsegments[i]->FindChapter( i_find_uid );
        if ( p_result != NULL )
        {
            p_vsegment_found = used_vsegments[i];
            break;
        }
    }
    return p_result;
}

void demux_sys_t::SetHighlight( vlc_spu_highlight_t & spu_hl )
{
    ev.SetHighlight( spu_hl );
}

} // namespace

Messung
CHZG
849610093

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