Changeset 5bc8ca51c941b558cfa42eccb71cb9f37e0f161f

Show
Ignore:
Timestamp:
09/02/05 11:09:41 (4 years ago)
Author:
Gildas Bazin <gbazin@videolan.org>
git-committer:
Gildas Bazin <gbazin@videolan.org> 1107943781 +0000
git-parent:

[5281148de4fb4ac815798a43aa67542a07315166]

git-author:
Gildas Bazin <gbazin@videolan.org> 1107943781 +0000
Message:

* modules/demux/mkv.cpp: Patch by Steve Lhomme (steve dot lhomme at free dot fr) to allow the Matroska demuxer to find all files in the same "family" in the same directory as the source file.
This will be useful to find segments corresponding to the different titles/domains (as in DVDs).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • configure.ac

    rbe52d3f r5bc8ca5  
    304304 
    305305dnl Check for usual libc functions 
    306 AC_CHECK_FUNCS(strdup strndup atof lseek
     306AC_CHECK_FUNCS(strdup strndup atof
    307307AC_CHECK_FUNCS(strcasecmp,,[AC_CHECK_FUNCS(stricmp)]) 
    308308AC_CHECK_FUNCS(strncasecmp,,[AC_CHECK_FUNCS(strnicmp)]) 
     
    17571757  AC_LANG_PUSH(C++) 
    17581758  AC_CHECK_HEADERS(ebml/EbmlVersion.h, [ 
    1759     AC_CHECK_HEADERS(matroska/KaxVersion.h, [ 
    1760       AC_CHECK_HEADERS(matroska/KaxAttachments.h) 
    1761       VLC_ADD_CXXFLAGS([mkv],[]) 
    1762       AC_CHECK_LIB(ebml_pic, main, [ 
    1763         # We have ebml_pic, that's good, we can build an mkv.so plugin ! 
    1764         VLC_ADD_PLUGINS([mkv]) 
    1765         VLC_ADD_LDFLAGS([mkv],[-lmatroska_pic -lebml_pic]) 
    1766       ], [ 
    1767         AC_CHECK_LIB(ebml, main, [ 
    1768           # We only have libebml, make mkv.a a builtin 
    1769           VLC_ADD_BUILTINS([mkv]) 
    1770           VLC_ADD_LDFLAGS([mkv],[-lmatroska -lebml]) 
     1759    AC_MSG_CHECKING(for libebml version >= 0.7.3) 
     1760    AC_EGREP_CPP(yes, 
     1761      [#include <ebml/EbmlVersion.h> 
     1762       #ifdef LIBEBML_VERSION 
     1763       #if LIBEBML_VERSION >= 0x000703 
     1764       yes 
     1765       #endif 
     1766       #endif], 
     1767      [AC_MSG_RESULT([yes]) 
     1768        AC_CHECK_HEADERS(matroska/KaxVersion.h, [ 
     1769          AC_MSG_CHECKING(for libmatroska version >= 0.7.5) 
     1770          AC_EGREP_CPP(yes, 
     1771            [#include <matroska/KaxVersion.h> 
     1772             #ifdef LIBMATROSKA_VERSION 
     1773             #if LIBMATROSKA_VERSION >= 0x000705 
     1774             yes 
     1775             #endif 
     1776             #endif], 
     1777            [AC_MSG_RESULT([yes]) 
     1778              AC_CHECK_HEADERS(matroska/KaxAttachments.h) 
     1779              VLC_ADD_CXXFLAGS([mkv],[]) 
     1780              AC_CHECK_LIB(ebml_pic, main, [ 
     1781                # We have ebml_pic, that's good, we can build an mkv.so plugin ! 
     1782                VLC_ADD_PLUGINS([mkv]) 
     1783                VLC_ADD_LDFLAGS([mkv],[-lmatroska_pic -lebml_pic]) 
     1784              ], [ 
     1785                AC_CHECK_LIB(ebml, main, [ 
     1786                  # We only have libebml, make mkv.a a builtin 
     1787                  VLC_ADD_BUILTINS([mkv]) 
     1788                  VLC_ADD_LDFLAGS([mkv],[-lmatroska -lebml]) 
     1789                ]) 
     1790              ]) 
     1791            ], 
     1792            [AC_MSG_RESULT([no]) 
     1793              AC_MSG_ERROR([Your libmatroska is too old: you may get a more recent one from http://dl.matroska.org/downloads/libmatroska/. Alternatively you can use --disable-mkv to disable the matroska plugin.]) 
     1794          ]) 
    17711795        ]) 
    1772       ]) 
     1796      ], 
     1797      [AC_MSG_RESULT([no]) 
     1798        AC_MSG_ERROR([Your libebml is too old: you may get a more recent one from http://dl.matroska.org/downloads/libebml/. Alternatively you can use --disable-mkv to disable the matroska plugin.]) 
    17731799    ]) 
    17741800  ]) 
  • modules/demux/mkv.cpp

    r94dfa75 r5bc8ca5  
    66 * 
    77 * Authors: Laurent Aimar <fenrir@via.ecp.fr> 
     8 *          Steve Lhomme <steve.lhomme@free.fr> 
    89 * 
    910 * This program is free software; you can redistribute it and/or modify 
     
    4243#include <cassert> 
    4344#include <typeinfo> 
     45#include <string> 
     46#include <vector> 
     47 
     48#ifdef HAVE_DIRENT_H 
     49#   include <dirent.h> 
     50#elif defined( UNDER_CE ) 
     51#   include <windows.h>                               /* GetFileAttributes() */ 
     52#else 
     53#   include "../../src/extras/dirent.h" 
     54#endif 
    4455 
    4556/* libebml and matroska */ 
     
    5061#include "ebml/EbmlVersion.h" 
    5162#include "ebml/EbmlVoid.h" 
    52  
    53 #include "matroska/FileKax.h" 
     63#include "ebml/StdIOCallback.h" 
     64 
    5465#include "matroska/KaxAttachments.h" 
    5566#include "matroska/KaxBlock.h" 
     
    8697#define MATROSKA_COMPRESSION_ZLIB 1 
    8798 
     99/** 
     100 * What's between a directory and a filename? 
     101 */ 
     102#if defined( WIN32 ) 
     103    #define DIRECTORY_SEPARATOR '\\' 
     104#else 
     105    #define DIRECTORY_SEPARATOR '/' 
     106#endif 
     107 
    88108using namespace LIBMATROSKA_NAMESPACE; 
    89109using namespace std; 
     
    299319} mkv_index_t; 
    300320 
    301 struct demux_sys_t 
    302 
     321class demux_sys_t 
     322
     323public: 
     324    demux_sys_t() 
     325        :in(NULL) 
     326        ,es(NULL) 
     327        ,ep(NULL) 
     328        ,i_timescale(0) 
     329        ,f_duration(0.0) 
     330        ,i_track(0) 
     331        ,track(NULL) 
     332        ,i_cues_position(0) 
     333        ,i_chapters_position(0) 
     334        ,i_tags_position(0) 
     335        ,segment(NULL) 
     336        ,cluster(NULL) 
     337        ,i_pts(0) 
     338        ,b_cues(false) 
     339        ,i_index(0) 
     340        ,i_index_max(0) 
     341        ,index(NULL) 
     342        ,psz_muxing_application(NULL) 
     343        ,psz_writing_application(NULL) 
     344        ,psz_segment_filename(NULL) 
     345        ,psz_title(NULL) 
     346        ,psz_date_utc(NULL) 
     347        ,meta(NULL) 
     348        ,title(NULL) 
     349    {} 
     350 
    303351    vlc_stream_io_callback  *in; 
    304352    EbmlStream              *es; 
     
    323371    KaxSegment              *segment; 
    324372    KaxCluster              *cluster; 
     373    KaxSegmentUID           segment_uid; 
    325374 
    326375    mtime_t                 i_pts; 
     
    341390 
    342391    input_title_t           *title; 
     392 
     393    std::vector<KaxSegmentFamily> families; 
     394    std::vector<KaxSegment*> family_members; 
    343395}; 
    344396 
     
    365417    demux_sys_t *p_sys; 
    366418    uint8_t     *p_peek; 
     419    std::string  s_path, s_filename; 
     420    int          i_upper_lvl; 
     421    size_t       i, j; 
    367422 
    368423    int          i_track; 
     
    390445    p_demux->pf_demux   = Demux; 
    391446    p_demux->pf_control = Control; 
    392     p_demux->p_sys      = p_sys = (demux_sys_t*)malloc(sizeof( demux_sys_t )); 
    393  
    394     memset( p_sys, 0, sizeof( demux_sys_t ) ); 
     447    p_demux->p_sys      = p_sys = new demux_sys_t; 
     448 
    395449    p_sys->in = new vlc_stream_io_callback( p_demux->s ); 
    396450    p_sys->es = new EbmlStream( *p_sys->in ); 
     
    422476        msg_Err( p_demux, "failed to create EbmlStream" ); 
    423477        delete p_sys->in; 
    424         free( p_sys )
     478        delete p_sys
    425479        return VLC_EGENERIC; 
    426480    } 
     
    496550        } 
    497551    } 
     552 
     553    /* get the files from the same dir from the same family (based on p_demux->psz_path) */ 
     554    /* _todo_ handle multi-segment files */ 
     555    if (p_demux->psz_path[0] != '\0' && (!strcmp(p_demux->psz_access, "") || !strcmp(p_demux->psz_access, ""))) 
     556    { 
     557        // assume it's a regular file 
     558        // get the directory path 
     559        s_path = p_demux->psz_path; 
     560        if (s_path.at(s_path.length() - 1) == DIRECTORY_SEPARATOR) 
     561        { 
     562            s_path = s_path.substr(0,s_path.length()-1); 
     563        } 
     564        else 
     565        { 
     566            if (s_path.find_last_of(DIRECTORY_SEPARATOR) > 0)  
     567            { 
     568                s_path = s_path.substr(0,s_path.find_last_of(DIRECTORY_SEPARATOR)); 
     569            } 
     570        } 
     571 
     572        struct dirent *p_file_item; 
     573        DIR *p_src_dir = opendir(s_path.c_str()); 
     574 
     575        if (p_src_dir != NULL) 
     576        { 
     577            while (p_file_item = readdir(p_src_dir)) 
     578            { 
     579                if (p_file_item->d_namlen > 4) 
     580                { 
     581                    s_filename = s_path + DIRECTORY_SEPARATOR + p_file_item->d_name; 
     582 
     583                    if (!s_filename.compare(p_demux->psz_path)) 
     584                        continue; 
     585 
     586                    if (!s_filename.compare(s_filename.length() - 3, 3, "mkv") ||  
     587                        !s_filename.compare(s_filename.length() - 3, 3, "mka")) 
     588                    { 
     589                        // test wether this file belongs to the our family 
     590                        bool b_keep_file_opened = false; 
     591                        StdIOCallback *p_file_io = new StdIOCallback(s_filename.c_str(), MODE_READ); 
     592                        EbmlStream *p_stream = new EbmlStream(*p_file_io); 
     593                        EbmlElement *p_l0, *p_l1, *p_l2; 
     594 
     595                        // verify the EBML Header 
     596                        p_l0 = p_stream->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL); 
     597                        if (p_l0 == NULL) 
     598                        { 
     599                            delete p_stream; 
     600                            delete p_file_io; 
     601                            continue; 
     602                        } 
     603 
     604                        p_l0->SkipData(*p_stream, EbmlHead_Context); 
     605                        delete p_l0; 
     606 
     607                        // find all segments in this file 
     608                        p_l0 = p_stream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL); 
     609                        if (p_l0 == NULL) 
     610                        { 
     611                            delete p_stream; 
     612                            delete p_file_io; 
     613                            continue; 
     614                        } 
     615 
     616                        i_upper_lvl = 0; 
     617 
     618                        while (p_l0 != 0) 
     619                        { 
     620                            if (EbmlId(*p_l0) == KaxSegment::ClassInfos.GlobalId) 
     621                            { 
     622                                EbmlParser  *ep; 
     623                                KaxSegmentUID *p_uid = NULL; 
     624 
     625                                ep = new EbmlParser(p_stream, p_l0); 
     626                                bool b_this_segment_matches = false; 
     627                                while (p_l1 = ep->Get()) 
     628                                { 
     629                                    if (MKV_IS_ID(p_l1, KaxInfo)) 
     630                                    { 
     631                                        // find the families of this segment 
     632                                        KaxInfo *p_info = static_cast<KaxInfo*>(p_l1); 
     633 
     634                                        p_info->Read(*p_stream, KaxInfo::ClassInfos.Context, i_upper_lvl, p_l2, true); 
     635                                        for( i = 0; i < p_info->ListSize() && !b_this_segment_matches; i++ ) 
     636                                        { 
     637                                            EbmlElement *l = (*p_info)[i]; 
     638 
     639                                            if( MKV_IS_ID( l, KaxSegmentUID ) ) 
     640                                            { 
     641                                                p_uid = static_cast<KaxSegmentUID*>(l); 
     642                                                if (p_sys->segment_uid == *p_uid) 
     643                                                    break; 
     644                                            } 
     645                                            else if( MKV_IS_ID( l, KaxSegmentFamily ) ) 
     646                                            { 
     647                                                KaxSegmentFamily *p_fam = static_cast<KaxSegmentFamily*>(l); 
     648                                                for (j=0; j<p_sys->families.size(); j++) 
     649                                                { 
     650                                                    if (p_sys->families.at(j) == *p_fam) 
     651                                                    { 
     652                                                        b_this_segment_matches = true; 
     653                                                        break; 
     654                                                    } 
     655                                                } 
     656                                            } 
     657                                        } 
     658                                        break; 
     659                                    } 
     660                                } 
     661 
     662                                if (b_this_segment_matches) 
     663                                { 
     664                                    b_keep_file_opened = true; 
     665                                } 
     666                            } 
     667 
     668                            p_l0->SkipData(*p_stream, EbmlHead_Context); 
     669                            delete p_l0; 
     670                            p_l0 = p_stream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL); 
     671                        } 
     672 
     673                        if (!b_keep_file_opened) 
     674                        { 
     675                            delete p_stream; 
     676                            delete p_file_io; 
     677                        } 
     678                    } 
     679                } 
     680            } 
     681            closedir( p_src_dir ); 
     682        } 
     683    } 
     684 
    498685 
    499686    if( p_sys->cluster == NULL ) 
     
    740927            tk.fmt.audio.i_blockalign = ( tk.fmt.audio.i_bitspersample + 7 ) / 8 * tk.fmt.audio.i_channels; 
    741928        } 
     929        else if( !strcmp( tk.psz_codec, "A_TTA1" ) ) 
     930        { 
     931            /* FIXME: support this codec */ 
     932            msg_Err( p_demux, "TTA not supported yet[%d, n=%d]", i_track, tk.i_number ); 
     933            tk.fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' ); 
     934        } 
     935        else if( !strcmp( tk.psz_codec, "A_WAVPACK4" ) ) 
     936        { 
     937            /* FIXME: support this codec */ 
     938            msg_Err( p_demux, "Wavpack not supported yet[%d, n=%d]", i_track, tk.i_number ); 
     939            tk.fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' ); 
     940        } 
    742941        else if( !strcmp( tk.psz_codec, "S_TEXT/UTF8" ) ) 
    743942        { 
     
    776975            } 
    777976        } 
     977        else if( !strcmp( tk.psz_codec, "B_VOBBTN" ) ) 
     978        { 
     979            /* FIXME: support this codec */ 
     980            msg_Err( p_demux, "Vob Buttons not supported yet[%d, n=%d]", i_track, tk.i_number ); 
     981            tk.fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' ); 
     982        } 
    778983        else 
    779984        { 
     
    7981003    delete p_sys->es; 
    7991004    delete p_sys->in; 
    800     free( p_sys )
     1005    delete p_sys
    8011006    return VLC_EGENERIC; 
    8021007} 
     
    8441049    delete p_sys->es; 
    8451050    delete p_sys->in; 
    846  
    847     free( p_sys ); 
     1051    delete p_sys; 
    8481052} 
    8491053 
     
    11011305    if( tk.p_es == NULL ) 
    11021306    { 
     1307        msg_Err( p_demux, "unknown track number=%d", block->TrackNum() ); 
    11031308        return; 
    11041309    } 
     
    23122517        if( MKV_IS_ID( l, KaxSegmentUID ) ) 
    23132518        { 
    2314             KaxSegmentUID &uid = *(KaxSegmentUID*)l
    2315  
    2316             msg_Dbg( p_demux, "|   |   + UID=%d", uint32(uid) ); 
     2519            p_sys->segment_uid = *(new KaxSegmentUID(*static_cast<KaxSegmentUID*>(l)))
     2520 
     2521            msg_Dbg( p_demux, "|   |   + UID=%d", *(uint32*)p_sys->segment_uid.GetBuffer() ); 
    23172522        } 
    23182523        else if( MKV_IS_ID( l, KaxTimecodeScale ) ) 
     
    23682573 
    23692574            msg_Dbg( p_demux, "|   |   + Title=%s", p_sys->psz_title ); 
     2575        } 
     2576        if( MKV_IS_ID( l, KaxSegmentFamily ) ) 
     2577        { 
     2578            KaxSegmentFamily *uid = static_cast<KaxSegmentFamily*>(l); 
     2579 
     2580            p_sys->families.push_back(*uid); 
     2581 
     2582            msg_Dbg( p_demux, "|   |   + family=%d", *(uint32*)uid->GetBuffer() ); 
    23702583        } 
    23712584#if defined( HAVE_GMTIME_R ) && !defined( SYS_DARWIN )