# HG changeset patch # User mosu # Date 1057955060 0 # Node ID c2fc1c3106996343c7319a35e6fabe2fb5aee733 # Parent 4c9ca4819bedd71afae19f96ca4d2bc939b1b1f7 Necessary changes for the upcoming libebml/libmatroska 0.5.0. Implemented support for RealAudio and RealVideo inside Matroska. diff -r 4c9ca4819bed -r c2fc1c310699 configure --- a/configure Fri Jul 11 07:54:52 2003 +0000 +++ b/configure Fri Jul 11 20:24:20 2003 +0000 @@ -4169,35 +4169,40 @@ echores "$_theora" -echocheck "Matroska support" +echocheck "Matroska support (0.5.0 or later)" if test "$_matroska" != no ; then _matroska=no + _TMPC=$TMPC + TMPC=${TMPC}pp cat > $TMPC << EOF -#include +#include +#include + +#if LIBEBML_VERSION < 000500 +#error libebml is too old +#endif + +#if LIBMATROSKA_VERSION < 000500 +#error libmatroska is too old +#endif + int main(void) { return 0; } EOF - cc_check -lmatroska -lebml && _matroska=yes + cc_check -lmatroska -lebml -lstdc++ && _matroska=yes if test "$_matroska" = no ; then _saved_inc_extra=$_inc_extra - _inc_extra="$_inc_extra -I/usr/include/ebml -I/usr/include/matroska" - cc_check -lmatroska -lebml && _matroska=yes + _inc_extra="$_inc_extra -I/usr/local/include" + cc_check -lmatroska -lebml -lstdc++ && _matroska=yes if test "$_matroska" = no ; then - _inc_extra="$_saved_inc_extra -I/usr/local/include/ebml -I/usr/local/include/matroska" - cc_check -lmatroska -lebml && _matroska=yes - if test "$_matroska" = no ; then - _inc_extra=$_saved_inc_extra - fi + _inc_extra=$_saved_inc_extra fi fi + TMPC=$_TMPC fi if test "$_matroska" = yes ; then _def_matroska='#define HAVE_MATROSKA 1' _inputmodules="matroska $_inputmodules" _ld_matroska="-lmatroska -lebml -lstdc++" - case $cc_version in - 2.*) _def_matroska_gcc2="#define LIBEBML_GCC2" ;; - *) _def_matroska_gcc2="/*#define LIBEBML_GCC2*/" ;; - esac else _def_matroska='#undef HAVE_MATROSKA' _noinputmodules="matroska $_noinputmodules" @@ -5870,7 +5875,6 @@ /* enable Matroska support */ $_def_matroska -$_def_matroska_gcc2 /* enable FAAD (AAC) support */ $_def_faad diff -r 4c9ca4819bed -r c2fc1c310699 libmpdemux/demux_mkv.cpp --- a/libmpdemux/demux_mkv.cpp Fri Jul 11 07:54:52 2003 +0000 +++ b/libmpdemux/demux_mkv.cpp Fri Jul 11 20:24:20 2003 +0000 @@ -22,32 +22,32 @@ #include #include #include +#include -#include "EbmlHead.h" -#include "EbmlSubHead.h" -#include "EbmlStream.h" -#include "EbmlContexts.h" -#include "EbmlVersion.h" -#include "FileKax.h" +#include +#include +#include +#include +#include +#include -#include "KaxAttachements.h" -#include "KaxBlock.h" -#include "KaxBlockData.h" -#include "KaxChapters.h" -#include "KaxCluster.h" -#include "KaxClusterData.h" -#include "KaxContexts.h" -#include "KaxCues.h" -#include "KaxCuesData.h" -#include "KaxInfo.h" -#include "KaxInfoData.h" -#include "KaxSeekHead.h" -#include "KaxSegment.h" -#include "KaxTracks.h" -#include "KaxTrackAudio.h" -#include "KaxTrackVideo.h" - -#include "StdIOCallback.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "matroska.h" @@ -58,6 +58,10 @@ #define LIBEBML_VERSION 000000 #endif // LIBEBML_VERSION +#if LIBEBML_VERSION < 000500 +#error libebml version too old - need at least 0.5.0 +#endif + // for e.g. "-slang ger" extern char *dvdsub_lang; extern char *audio_lang; @@ -153,10 +157,16 @@ void *private_data; unsigned int private_size; + // For Vorbis audio unsigned char *headers[3]; uint32_t header_sizes[3]; int ok; + + // Stuff for RealMedia packet assembly + bool realmedia; + demux_packet_t *rm_dp; + int rm_seqnum; } mkv_track_t; typedef struct mkv_demuxer { @@ -189,6 +199,79 @@ int64_t skip_to_timecode; } mkv_demuxer_t; +typedef struct { + uint32_t chunks; // number of chunks + uint32_t timestamp; // timestamp from packet header + uint32_t len; // length of actual data + uint32_t chunktab; // offset to chunk offset array +} dp_hdr_t; + +#pragma pack(push,2) + +typedef struct { + uint32_t size; + uint32_t fourcc1; + uint32_t fourcc2; + uint16_t width; + uint16_t height; + uint16_t bpp; + uint32_t unknown1; + uint32_t fps; + uint32_t type1; + uint32_t type2; +} real_video_props_t; + +typedef struct { + uint32_t fourcc1; // '.', 'r', 'a', 0xfd + uint16_t version1; // 4 or 5 + uint16_t unknown1; // 00 000 + uint32_t fourcc2; // .ra4 or .ra5 + uint32_t unknown2; // ??? + uint16_t version2; // 4 or 5 + uint32_t header_size; // == 0x4e + uint16_t flavor; // codec flavor id + uint32_t coded_frame_size; // coded frame size + uint32_t unknown3; // big number + uint32_t unknown4; // bigger number + uint32_t unknown5; // yet another number + uint16_t sub_packet_h; + uint16_t frame_size; + uint16_t sub_packet_size; + uint16_t unknown6; // 00 00 + uint16_t sample_rate; + uint16_t unknown8; // 0 + uint16_t sample_size; + uint16_t channels; +} real_audio_v4_props_t; + +typedef struct { + uint32_t fourcc1; // '.', 'r', 'a', 0xfd + uint16_t version1; // 4 or 5 + uint16_t unknown1; // 00 000 + uint32_t fourcc2; // .ra4 or .ra5 + uint32_t unknown2; // ??? + uint16_t version2; // 4 or 5 + uint32_t header_size; // == 0x4e + uint16_t flavor; // codec flavor id + uint32_t coded_frame_size; // coded frame size + uint32_t unknown3; // big number + uint32_t unknown4; // bigger number + uint32_t unknown5; // yet another number + uint16_t sub_packet_h; + uint16_t frame_size; + uint16_t sub_packet_size; + uint16_t unknown6; // 00 00 + uint8_t unknown7[6]; // 0, srate, 0 + uint16_t sample_rate; + uint16_t unknown8; // 0 + uint16_t sample_size; + uint16_t channels; + uint32_t genr; // "genr" + uint32_t fourcc3; // fourcc +} real_audio_v5_props_t; + +#pragma pack(pop) + static uint16_t get_uint16(const void *buf) { uint16_t ret; unsigned char *tmp; @@ -215,6 +298,63 @@ return ret; } +static uint16_t get_uint16_be(const void *buf) { + uint16_t ret; + unsigned char *tmp; + + tmp = (unsigned char *) buf; + + ret = tmp[0] & 0xff; + ret = (ret << 8) + (tmp[1] & 0xff); + + return ret; +} + +static uint32_t get_uint32_be(const void *buf) { + uint32_t ret; + unsigned char *tmp; + + tmp = (unsigned char *) buf; + + ret = tmp[0] & 0xff; + ret = (ret << 8) + (tmp[1] & 0xff); + ret = (ret << 8) + (tmp[2] & 0xff); + ret = (ret << 8) + (tmp[3] & 0xff); + + return ret; +} + +unsigned char read_char(unsigned char *p, int &pos, int size) { + if ((pos + 1) > size) + throw exception(); + pos++; + return p[pos - 1]; +} + +unsigned short read_word(unsigned char *p, int &pos, int size) { + unsigned short v; + + if ((pos + 2) > size) + throw exception(); + v = p[pos]; + v = (v << 8) | (p[pos + 1] & 0xff); + pos += 2; + return v; +} + +unsigned int read_dword(unsigned char *p, int &pos, int size) { + unsigned int v; + + if ((pos + 4) > size) + throw exception(); + v = p[pos]; + v = (v << 8) | (p[pos + 1] & 0xff); + v = (v << 8) | (p[pos + 2] & 0xff); + v = (v << 8) | (p[pos + 3] & 0xff); + pos += 4; + return v; +} + static void handle_subtitles(demuxer_t *d, KaxBlock *block, int64_t duration) { mkv_demuxer_t *mkv_d = (mkv_demuxer_t *)d->priv; int len, line, state; @@ -375,18 +515,7 @@ } memcpy(t->v_fourcc, &bih->biCompression, 4); - - if (t->v_frate == 0.0) { - mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] ERROR: (MS compatibility " - "mode, track %u) " - "No VideoFrameRate element was found.\n", t->tnum); - continue; - } } - } else { - mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Native CodecIDs for video " - "tracks are not supported yet (track %u).\n", t->tnum); - continue; } if (t->v_width == 0) { @@ -521,9 +650,21 @@ t->header_sizes[0] - t->header_sizes[1]; t->a_formattag = 0xFFFE; + } else if (t->private_size >= sizeof(real_audio_v4_props_t)) { + if (!strcmp(t->codec_id, MKV_A_REAL28)) + t->a_formattag = mmioFOURCC('2', '8', '_', '8'); + else if (!strcmp(t->codec_id, MKV_A_REALATRC)) + t->a_formattag = mmioFOURCC('a', 't', 'r', 'c'); + else if (!strcmp(t->codec_id, MKV_A_REALCOOK)) + t->a_formattag = mmioFOURCC('c', 'o', 'o', 'k'); + else if (!strcmp(t->codec_id, MKV_A_REALDNET)) + t->a_formattag = mmioFOURCC('d', 'n', 'e', 't'); + else if (!strcmp(t->codec_id, MKV_A_REALSIPR)) + t->a_formattag = mmioFOURCC('s', 'i', 'p', 'r'); } else { mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Unknown/unsupported audio " - "codec ID '%s' for track %u.\n", t->codec_id, t->tnum); + "codec ID '%s' for track %u or missing/faulty private " + "codec data.\n", t->codec_id, t->tnum); continue; } } @@ -645,6 +786,9 @@ mkv_d->num_cluster_pos = 0; } +#define fits_parent(l, p) (l->GetElementPosition() < \ + (p->GetElementPosition() + p->ElementSize())) + static int parse_cues(mkv_demuxer_t *mkv_d) { EbmlElement *l1 = NULL, *l2 = NULL, *l3 = NULL, *l4 = NULL, *l5 = NULL; EbmlStream *es; @@ -676,7 +820,9 @@ l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l2 != NULL) { - if (upper_lvl_el != 0) + if (upper_lvl_el > 0) + break; + if ((upper_lvl_el < 0) && !fits_parent(l2, l1)) break; if (EbmlId(*l2) == KaxCuePoint::ClassInfos.GlobalId) { @@ -687,7 +833,9 @@ l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l3 != NULL) { - if (upper_lvl_el != 0) + if (upper_lvl_el > 0) + break; + if ((upper_lvl_el < 0) && !fits_parent(l3, l2)) break; if (EbmlId(*l3) == KaxCueTime::ClassInfos.GlobalId) { @@ -706,7 +854,9 @@ l4 = es->FindNextElement(l3->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l4 != NULL) { - if (upper_lvl_el != 0) + if (upper_lvl_el > 0) + break; + if ((upper_lvl_el < 0) && !fits_parent(l4, l3)) break; if (EbmlId(*l4) == KaxCueTrack::ClassInfos.GlobalId) { @@ -755,7 +905,9 @@ l5 = es->FindNextElement(l4->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l5 != NULL) { - if (upper_lvl_el != 0) + if (upper_lvl_el > 0) + break; + if ((upper_lvl_el < 0) && !fits_parent(l5, l4)) break; if (EbmlId(*l5) == KaxCueRefTime::ClassInfos.GlobalId) { @@ -789,21 +941,21 @@ mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] | + found cue ref " "codec state: %llu\n", uint64(cue_rcs)); - } else { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] | + unknown " - "element, level 5: %s\n", typeid(*l5).name()); + } else + upper_lvl_el = 0; + + if (upper_lvl_el == 0) { + l5->SkipData(static_cast(*es), + l5->Generic().Context); + delete l5; + l5 = es->FindNextElement(l4->Generic().Context, + upper_lvl_el, 0xFFFFFFFFL, true); } - l5->SkipData(static_cast(*es), - l5->Generic().Context); - delete l5; - l5 = es->FindNextElement(l4->Generic().Context, - upper_lvl_el, 0xFFFFFFFFL, true, 1); } // while (l5 != NULL) } else - mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] | + unknown element, " - "level 4: %s\n", typeid(*l4).name()); + upper_lvl_el = 0; if (upper_lvl_el > 0) { // we're coming from l5 upper_lvl_el--; @@ -812,13 +964,17 @@ if (upper_lvl_el > 0) break; - } else { + } else if (upper_lvl_el == 0) { l4->SkipData(static_cast(*es), l4->Generic().Context); delete l4; l4 = es->FindNextElement(l3->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); + } else { + delete l4; + l4 = l5; } + } // while (l4 != NULL) } else @@ -832,13 +988,17 @@ if (upper_lvl_el > 0) break; - } else { + } else if (upper_lvl_el == 0) { l3->SkipData(static_cast(*es), l3->Generic().Context); delete l3; l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); + } else { + delete l3; + l3 = l4; } + } // while (l3 != NULL) // Three elements must have been found in order for this to be a @@ -854,8 +1014,7 @@ (elements_found & 8) ? 0 : 1); } else - mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] | + unknown element, level 2: " - "%s\n", typeid(*l2).name()); + upper_lvl_el = 0; if (upper_lvl_el > 0) { // we're coming from l3 upper_lvl_el--; @@ -864,13 +1023,17 @@ if (upper_lvl_el > 0) break; - } else { + } else if (upper_lvl_el == 0) { l2->SkipData(static_cast(*es), l2->Generic().Context); delete l2; l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); + } else { + delete l2; + l2 = l3; } + } // while (l2 != NULL) // Debug: dump the index @@ -890,6 +1053,10 @@ return 1; } + + +extern "C" void print_wave_header(WAVEFORMATEX *h); + extern "C" int demux_mkv_open(demuxer_t *demuxer) { unsigned char signature[4]; stream_t *s; @@ -977,7 +1144,9 @@ l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l1 != NULL) { - if ((upper_lvl_el != 0) || exit_loop) + if ((upper_lvl_el > 0) || exit_loop) + break; + if ((upper_lvl_el < 0) && !fits_parent(l1, l0)) break; if (EbmlId(*l1) == KaxInfo::ClassInfos.GlobalId) { @@ -987,7 +1156,9 @@ l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l2 != NULL) { - if ((upper_lvl_el != 0) || exit_loop) + if ((upper_lvl_el > 0) || exit_loop) + break; + if ((upper_lvl_el < 0) && !fits_parent(l2, l1)) break; if (EbmlId(*l2) == KaxTimecodeScale::ClassInfos.GlobalId) { @@ -1005,14 +1176,15 @@ mkv_d->duration); } else - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + unknown element@2: %s\n", - typeid(*l2).name()); + upper_lvl_el = 0; - l2->SkipData(static_cast(*es), - l2->Generic().Context); - delete l2; - l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, - 0xFFFFFFFFL, true, 1); + if (upper_lvl_el == 0) { + l2->SkipData(static_cast(*es), + l2->Generic().Context); + delete l2; + l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, + 0xFFFFFFFFL, true, 1); + } } } else if (EbmlId(*l1) == KaxTracks::ClassInfos.GlobalId) { @@ -1023,7 +1195,9 @@ l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l2 != NULL) { - if ((upper_lvl_el != 0) || exit_loop) + if ((upper_lvl_el > 0) || exit_loop) + break; + if ((upper_lvl_el < 0) && !fits_parent(l2, l1)) break; if (EbmlId(*l2) == KaxTrackEntry::ClassInfos.GlobalId) { @@ -1037,7 +1211,9 @@ l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l3 != NULL) { - if (upper_lvl_el != 0) + if (upper_lvl_el > 0) + break; + if ((upper_lvl_el < 0) && !fits_parent(l3, l2)) break; // Now evaluate the data belonging to this track @@ -1058,17 +1234,20 @@ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Track UID: %u\n", uint32(tuid)); -#if LIBEBML_VERSION >= 000404 } else if (EbmlId(*l3) == KaxTrackDefaultDuration::ClassInfos.GlobalId) { KaxTrackDefaultDuration &def_duration = *static_cast(l3); def_duration.ReadData(es->I_O()); - track->v_frate = 1000000000.0 / (float)uint64(def_duration); - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Default duration: " - "%.3fms ( = %.3f fps)\n", (float)uint64(def_duration) / - 1000000.0, track->v_frate); -#endif // LIBEBML_VERSION + if (uint64(def_duration) == 0) + mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Default duration: 0"); + else { + track->v_frate = 1000000000.0 / (float)uint64(def_duration); + mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Default duration: " + "%.3fms ( = %.3f fps)\n", + (float)uint64(def_duration) / 1000000.0, + track->v_frate); + } } else if (EbmlId(*l3) == KaxTrackType::ClassInfos.GlobalId) { KaxTrackType &ttype = *static_cast(l3); @@ -1099,7 +1278,9 @@ l4 = es->FindNextElement(l3->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l4 != NULL) { - if (upper_lvl_el != 0) + if (upper_lvl_el > 0) + break; + if ((upper_lvl_el < 0) && !fits_parent(l4, l3)) break; if (EbmlId(*l4) == @@ -1130,14 +1311,16 @@ track->a_bps); } else - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + unknown " - "element@4: %s\n", typeid(*l4).name()); + upper_lvl_el = 0; - l4->SkipData(static_cast(*es), - l4->Generic().Context); - delete l4; - l4 = es->FindNextElement(l3->Generic().Context, upper_lvl_el, - 0xFFFFFFFFL, true, 1); + if (upper_lvl_el == 0) { + l4->SkipData(static_cast(*es), + l4->Generic().Context); + delete l4; + l4 = es->FindNextElement(l3->Generic().Context, + upper_lvl_el, 0xFFFFFFFFL, true); + } + } // while (l4 != NULL) } else if (EbmlId(*l3) == KaxTrackVideo::ClassInfos.GlobalId) { @@ -1145,7 +1328,9 @@ l4 = es->FindNextElement(l3->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l4 != NULL) { - if (upper_lvl_el != 0) + if (upper_lvl_el > 0) + break; + if ((upper_lvl_el < 0) && !fits_parent(l4, l3)) break; if (EbmlId(*l4) == KaxVideoPixelWidth::ClassInfos.GlobalId) { @@ -1194,28 +1379,24 @@ float(framerate)); } else - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + unknown " - "element@4: %s\n", typeid(*l4).name()); + upper_lvl_el = 0; - l4->SkipData(static_cast(*es), - l4->Generic().Context); - delete l4; - l4 = es->FindNextElement(l3->Generic().Context, upper_lvl_el, - 0xFFFFFFFFL, true, 1); + if (upper_lvl_el == 0) { + l4->SkipData(static_cast(*es), + l4->Generic().Context); + delete l4; + l4 = es->FindNextElement(l3->Generic().Context, + upper_lvl_el, 0xFFFFFFFFL, true); + } + } // while (l4 != NULL) } else if (EbmlId(*l3) == KaxCodecID::ClassInfos.GlobalId) { KaxCodecID &codec_id = *static_cast(l3); codec_id.ReadData(es->I_O()); -#if LIBEBML_VERSION >= 000404 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Codec ID: %s\n", string(codec_id).c_str()); track->codec_id = strdup(string(codec_id).c_str()); -#else - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Codec ID: %s\n", - &binary(codec_id)); - track->codec_id = strdup((char *)&binary(codec_id)); -#endif // LIBEBML_VERSION } else if (EbmlId(*l3) == KaxCodecPrivate::ClassInfos.GlobalId) { KaxCodecPrivate &c_priv = *static_cast(l3); @@ -1251,14 +1432,8 @@ free(track->language); track->language = strdup(string(language).c_str()); - } else if ((!(EbmlId(*l3) == - KaxTrackFlagLacing::ClassInfos.GlobalId)) && - (!(EbmlId(*l3) == - KaxTrackMinCache::ClassInfos.GlobalId)) && - (!(EbmlId(*l3) == - KaxTrackMaxCache::ClassInfos.GlobalId))) - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + unknown element@3: " - "%s\n", typeid(*l3).name()); + } else + upper_lvl_el = 0; if (upper_lvl_el > 0) { // we're coming from l4 upper_lvl_el--; @@ -1266,13 +1441,17 @@ l3 = l4; if (upper_lvl_el > 0) break; - } else { + } else if (upper_lvl_el == 0) { l3->SkipData(static_cast(*es), l3->Generic().Context); delete l3; l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); + } else { + delete l3; + l3 = l4; } + } // while (l3 != NULL) } else @@ -1284,13 +1463,17 @@ l2 = l3; if (upper_lvl_el > 0) break; - } else { + } else if (upper_lvl_el == 0) { l2->SkipData(static_cast(*es), l2->Generic().Context); delete l2; l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); + } else { + delete l2; + l2 = l3; } + } // while (l2 != NULL) } else if (EbmlId(*l1) == KaxSeekHead::ClassInfos.GlobalId) { @@ -1299,7 +1482,9 @@ l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l2 != NULL) { - if (upper_lvl_el != 0) + if (upper_lvl_el > 0) + break; + if ((upper_lvl_el < 0) && !fits_parent(l2, l1)) break; if (EbmlId(*l2) == KaxSeek::ClassInfos.GlobalId) { @@ -1311,7 +1496,9 @@ l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l3 != NULL) { - if (upper_lvl_el != 0) + if (upper_lvl_el > 0) + break; + if ((upper_lvl_el < 0) && !fits_parent(l3, l2)) break; if (EbmlId(*l3) == KaxSeekID::ClassInfos.GlobalId) { @@ -1354,14 +1541,16 @@ seek_pos = uint64(kax_seek_pos); } else - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + unknown element, " - "level 3: %s\n", typeid(*l3).name()); + upper_lvl_el = 0; - l3->SkipData(static_cast(*es), - l3->Generic().Context); - delete l3; - l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, - 0xFFFFFFFFL, true, 1); + if (upper_lvl_el == 0) { + l3->SkipData(static_cast(*es), + l3->Generic().Context); + delete l3; + l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, + 0xFFFFFFFFL, true, 1); + } + } // while (l3 != NULL) if (!mkv_d->cues_found && (seek_pos > 0) && @@ -1369,8 +1558,7 @@ cues_pos = mkv_d->segment->GetGlobalPosition(seek_pos); } else - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + unknown element, level 2: " - "%s\n", typeid(*l2).name()); + upper_lvl_el = 0; if (upper_lvl_el > 0) { // we're coming from l3 upper_lvl_el--; @@ -1379,13 +1567,17 @@ if (upper_lvl_el > 0) break; - } else { + } else if (upper_lvl_el == 0) { l2->SkipData(static_cast(*es), l2->Generic().Context); delete l2; l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); + } else { + delete l2; + l2 = l3; } + } // while (l2 != NULL) } else if ((EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) && @@ -1405,8 +1597,7 @@ exit_loop = 1; } else - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ unknown element@1: %s\n", - typeid(*l1).name()); + upper_lvl_el = 0; if (exit_loop) // we've found the first cluster, so get out break; @@ -1417,12 +1608,16 @@ l1 = l2; if (upper_lvl_el > 0) break; - } else { + } else if (upper_lvl_el == 0) { l1->SkipData(static_cast(*es), l1->Generic().Context); delete l1; l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, - 0xFFFFFFFFL, true, 1); + 0xFFFFFFFFL, true); + } else { + delete l1; + l1 = l2; } + } // while (l1 != NULL) if (!exit_loop) { @@ -1443,8 +1638,6 @@ mkv_d->first_tc = 0; stream_seek(s, l1->GetElementPosition()); - mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] First tc: %lld\n", mkv_d->first_tc); - // If we have found an entry for the cues in the meta seek data but no // cues at the front of the file then read them now. This way the // timecode scale will have been initialized correctly. @@ -1489,35 +1682,88 @@ track = find_track_by_num(mkv_d, demuxer->video->id, NULL); if (track) { + BITMAPINFOHEADER *bih; + + bih = (BITMAPINFOHEADER *)calloc(1, track->private_size); + if (bih == NULL) { + free_mkv_demuxer(mkv_d); + return 0; + } + if (track->ms_compat) { // MS compatibility mode - BITMAPINFOHEADER *src, *dst; - mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will play video track %u\n", - track->tnum); - sh_v = new_sh_video(demuxer, track->tnum); - sh_v->bih = (BITMAPINFOHEADER *)calloc(1, track->private_size); - if (sh_v->bih == NULL) { - free_mkv_demuxer(mkv_d); - return 0; - } - - dst = sh_v->bih; + BITMAPINFOHEADER *src; src = (BITMAPINFOHEADER *)track->private_data; - dst->biSize = get_uint32(&src->biSize); - dst->biWidth = get_uint32(&src->biWidth); - dst->biHeight = get_uint32(&src->biHeight); - dst->biPlanes = get_uint16(&src->biPlanes); - dst->biBitCount = get_uint16(&src->biBitCount); - dst->biCompression = get_uint32(&src->biCompression); - dst->biSizeImage = get_uint32(&src->biSizeImage); - dst->biXPelsPerMeter = get_uint32(&src->biXPelsPerMeter); - dst->biYPelsPerMeter = get_uint32(&src->biYPelsPerMeter); - dst->biClrUsed = get_uint32(&src->biClrUsed); - dst->biClrImportant = get_uint32(&src->biClrImportant); - memcpy((char *)dst + sizeof(BITMAPINFOHEADER), + bih->biSize = get_uint32(&src->biSize); + bih->biWidth = get_uint32(&src->biWidth); + bih->biHeight = get_uint32(&src->biHeight); + bih->biPlanes = get_uint16(&src->biPlanes); + bih->biBitCount = get_uint16(&src->biBitCount); + bih->biCompression = get_uint32(&src->biCompression); + bih->biSizeImage = get_uint32(&src->biSizeImage); + bih->biXPelsPerMeter = get_uint32(&src->biXPelsPerMeter); + bih->biYPelsPerMeter = get_uint32(&src->biYPelsPerMeter); + bih->biClrUsed = get_uint32(&src->biClrUsed); + bih->biClrImportant = get_uint32(&src->biClrImportant); + memcpy((char *)bih + sizeof(BITMAPINFOHEADER), (char *)src + sizeof(BITMAPINFOHEADER), track->private_size - sizeof(BITMAPINFOHEADER)); + } else { + bih->biSize = sizeof(BITMAPINFOHEADER); + bih->biWidth = track->v_width; + bih->biHeight = track->v_height; + bih->biBitCount = 24; + bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount / 8; + + if ((track->private_size >= sizeof(real_video_props_t)) && + (!strcmp(track->codec_id, MKV_V_REALV10) || + !strcmp(track->codec_id, MKV_V_REALV20) || + !strcmp(track->codec_id, MKV_V_REALV30) || + !strcmp(track->codec_id, MKV_V_REALV40))) { + unsigned char *dst, *src; + real_video_props_t *rvp; + uint32_t type2; + + rvp = (real_video_props_t *)track->private_data; + src = (unsigned char *)(rvp + 1); + + bih = (BITMAPINFOHEADER *)realloc(bih, sizeof(BITMAPINFOHEADER) + 12); + bih->biSize += 12; + type2 = get_uint32_be(&rvp->type2); + if ((type2 == 0x10003000) || (type2 == 0x100030001)) + bih->biCompression = mmioFOURCC('R', 'V', '1', '3'); + else + bih->biCompression = mmioFOURCC('R', 'V', track->codec_id[9], '0'); + dst = (unsigned char *)(bih + 1); + ((unsigned int *)dst)[0] = get_uint32_be(&rvp->type1); + ((unsigned int *)dst)[1] = type2; + + if ((bih->biCompression <= 0x30335652) && + (type2 >= 0x20200002)) { + // read secondary WxH for the cmsg24[] (see vd_realvid.c) + ((unsigned short *)(bih + 1))[4] = 4 * (unsigned short)src[0]; + ((unsigned short *)(bih + 1))[5] = 4 * (unsigned short)src[1]; + } else + memset(&dst[8], 0, 4); + track->realmedia = true; + + } else { + mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Unknown/unsupported CodecID " + "(%s) or missing/bad CodecPrivate data (track %u).\n", + track->codec_id, track->tnum); + demuxer->video->id = -2; + } + } + + if (demuxer->video->id != -2) { + mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will play video track %u\n", + track->tnum); + + sh_v = new_sh_video(demuxer, track->tnum); + sh_v->bih = bih; sh_v->format = sh_v->bih->biCompression; + if (track->v_frate == 0.0) + track->v_frate = 25.0; sh_v->fps = track->v_frate; sh_v->frametime = 1 / track->v_frate; sh_v->disp_w = track->v_width; @@ -1530,11 +1776,9 @@ sh_v->ds = demuxer->video; mkv_d->video = track; - } else { - mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Native CodecIDs not supported at " - "the moment (track %u).\n", track->tnum); - demuxer->video->id = -2; - } + } else + free(bih); + } else { mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] No video track found/wanted.\n"); demuxer->video->id = -2; @@ -1594,23 +1838,28 @@ } sh_a->format = track->a_formattag; sh_a->wf->wFormatTag = track->a_formattag; - sh_a->channels = sh_a->wf->nChannels = track->a_channels; - sh_a->samplerate = sh_a->wf->nSamplesPerSec = (uint32_t)track->a_sfreq; + sh_a->channels = track->a_channels; + sh_a->wf->nChannels = track->a_channels; + sh_a->samplerate = (uint32_t)track->a_sfreq; + sh_a->wf->nSamplesPerSec = (uint32_t)track->a_sfreq; + sh_a->samplesize = track->a_bps / 8; if (!strcmp(track->codec_id, MKV_A_MP3)) { sh_a->wf->nAvgBytesPerSec = 16000; sh_a->wf->nBlockAlign = 1152; sh_a->wf->wBitsPerSample = 0; sh_a->samplesize = 0; + } else if (!strcmp(track->codec_id, MKV_A_AC3)) { sh_a->wf->nAvgBytesPerSec = 16000; sh_a->wf->nBlockAlign = 1536; sh_a->wf->wBitsPerSample = 0; sh_a->samplesize = 0; + } else if (!strcmp(track->codec_id, MKV_A_PCM)) { sh_a->wf->nAvgBytesPerSec = sh_a->channels * sh_a->samplerate * 2; sh_a->wf->nBlockAlign = sh_a->wf->nAvgBytesPerSec; sh_a->wf->wBitsPerSample = track->a_bps; - sh_a->samplesize = track->a_bps / 8; + } else if (track->a_formattag == mmioFOURCC('M', 'P', '4', 'A')) { int profile, srate_idx; @@ -1659,6 +1908,7 @@ sh_a->codecdata_len = 2; sh_a->codecdata[0] = ((profile + 1) << 3) | ((srate_idx & 0xe) >> 1); sh_a->codecdata[1] = ((srate_idx & 0x1) << 7) | (track->a_channels << 3); + } else if (!strcmp(track->codec_id, MKV_A_VORBIS)) { for (i = 0; i < 3; i++) { dp = new_demux_packet(track->header_sizes[i]); @@ -1667,7 +1917,47 @@ dp->flags = 0; ds_add_packet(demuxer->audio, dp); } + + } else if ((track->private_size >= sizeof(real_audio_v4_props_t)) && + !strncmp(track->codec_id, MKV_A_REALATRC, 7)) { + // Common initialization for all RealAudio codecs + real_audio_v4_props_t *ra4p; + real_audio_v5_props_t *ra5p; + unsigned char *src; + int codecdata_length, version; + + ra4p = (real_audio_v4_props_t *)track->private_data; + ra5p = (real_audio_v5_props_t *)track->private_data; + + sh_a->wf->wBitsPerSample = sh_a->samplesize * 8; + sh_a->wf->nAvgBytesPerSec = 0; // FIXME !? + sh_a->wf->nBlockAlign = get_uint16_be(&ra4p->frame_size); + + version = get_uint16_be(&ra4p->version1); + + if (version == 4) { + src = (unsigned char *)(ra4p + 1); + src += src[0] + 1; + src += src[0] + 1; + } else + src = (unsigned char *)(ra5p + 1); + + src += 3; + if (version == 5) + src++; + codecdata_length = get_uint32_be(src); + src += 4; + sh_a->wf->cbSize = 10 + codecdata_length; + sh_a->wf = (WAVEFORMATEX *)realloc(sh_a->wf, sizeof(WAVEFORMATEX) + + sh_a->wf->cbSize); + ((short *)(sh_a->wf + 1))[0] = get_uint16_be(&ra4p->sub_packet_size); + ((short *)(sh_a->wf + 1))[1] = get_uint16_be(&ra4p->sub_packet_h); + ((short *)(sh_a->wf + 1))[2] = get_uint16_be(&ra4p->flavor); + ((short *)(sh_a->wf + 1))[3] = get_uint32_be(&ra4p->coded_frame_size); + ((short *)(sh_a->wf + 1))[4] = codecdata_length; + memcpy(((char *)(sh_a->wf + 1)) + 10, src, codecdata_length); } + } else { mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] No audio track found/wanted.\n"); demuxer->audio->id = -2; @@ -1714,6 +2004,39 @@ return 1; } +static void handle_realvideo(demuxer_t *demuxer, DataBuffer &data, + bool keyframe, int &found_data) { + unsigned char *p, *buffer; + dp_hdr_t *hdr; + int chunks, isize; + mkv_demuxer_t *mkv_d; + demux_stream_t *ds; + demux_packet_t *dp; + + mkv_d = (mkv_demuxer_t *)demuxer->priv; + ds = demuxer->video; + p = (unsigned char *)data.Buffer(); + chunks = p[0]; + isize = data.Size() - 1 - (chunks + 1) * 8; + dp = new_demux_packet(sizeof(dp_hdr_t) + isize + 8 * (chunks + 1)); + memcpy(&dp->buffer[sizeof(dp_hdr_t)], &p[1 + (chunks + 1) * 8], isize); + memcpy(&dp->buffer[sizeof(dp_hdr_t) + isize], &p[1], (chunks + 1) * 8); + hdr = (dp_hdr_t *)dp->buffer; + hdr->len = isize; + hdr->chunks = chunks; + hdr->timestamp = (int)(mkv_d->last_pts * 1000); + hdr->chunktab = sizeof(dp_hdr_t) + isize; + + dp->len = sizeof(dp_hdr_t) + isize + 8 * (chunks + 1); + dp->pts = hdr->timestamp; + dp->pos = demuxer->filepos; + dp->flags = keyframe ? 0x10 : 0; + + ds_add_packet(ds, dp); + + found_data++; +} + extern "C" int demux_mkv_fill_buffer(demuxer_t *d) { demux_packet_t *dp; demux_stream_t *ds; @@ -1742,7 +2065,9 @@ // The idea is not to handle a complete KaxCluster with each call to // demux_mkv_fill_buffer because those might be rather big. while (l1 != NULL) { - if ((upper_lvl_el != 0) || exit_loop) + if ((upper_lvl_el > 0) || exit_loop) + break; + if ((upper_lvl_el < 0) && !fits_parent(l1, l0)) break; if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) { @@ -1759,7 +2084,9 @@ l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); while (l2 != NULL) { - if (upper_lvl_el != 0) + if (upper_lvl_el > 0) + break; + if ((upper_lvl_el < 0) && !fits_parent(l2, l1)) break; // Handle at least one data packets in one call to @@ -1795,6 +2122,8 @@ delete_element = 1; if (upper_lvl_el > 0) break; + if ((upper_lvl_el < 0) && !fits_parent(l3, l2)) + break; if (EbmlId(*l3) == KaxBlock::ClassInfos.GlobalId) { block = static_cast(l3); @@ -1816,7 +2145,7 @@ KaxReferenceBlock &ref = *static_cast(l3); ref.ReadData(es->I_O()); - if (block_ref1 == 0) { + if ((elements_found & 4) == 0) { block_ref1 = int64(ref); elements_found |= 4; } else { @@ -1824,14 +2153,18 @@ elements_found |= 8; } + } else + upper_lvl_el = 0; + + if (upper_lvl_el == 0) { + l3->SkipData(static_cast(*es), + l3->Generic().Context); + if (delete_element) + delete l3; + l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, + 0xFFFFFFFFL, true, 1); } - l3->SkipData(static_cast(*es), - l3->Generic().Context); - if (delete_element) - delete l3; - l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, - 0xFFFFFFFFL, true, 1); } // while (l3 != NULL) if (block != NULL) { @@ -1850,41 +2183,50 @@ (mkv_d->video->tnum == block->TrackNum())) ds = d->video; else if ((mkv_d->audio != NULL) && - (mkv_d->audio->tnum == block->TrackNum())) - ds = d->audio; + (mkv_d->audio->tnum == block->TrackNum())) + ds = d->audio; if (!mkv_d->skip_to_keyframe || // Not skipping is ok. (((elements_found & 4) == 0) && // It's a key frame. (ds != NULL) && // Corresponding track found (ds == d->video))) { // track is our video track + mkv_d->last_pts = (float)(block->GlobalTimecode() / 1000000.0 - + mkv_d->first_tc) / 1000.0; + d->filepos = mkv_d->in->getFilePointer(); + mkv_d->last_filepos = d->filepos; + if ((ds != NULL) && ((block->GlobalTimecode() / 1000000 - mkv_d->first_tc) >= (uint64_t)mkv_d->skip_to_timecode)) { for (i = 0; i < (int)block->NumberFrames(); i++) { DataBuffer &data = block->GetBuffer(i); - dp = new_demux_packet(data.Size()); - memcpy(dp->buffer, data.Buffer(), data.Size()); - dp->pts = mkv_d->last_pts; - dp->flags = (elements_found & 4) == 0 ? 1 : 0; // keyframe - ds_add_packet(ds, dp); - found_data++; + if ((mkv_d->video != NULL) && + mkv_d->video->realmedia && + (mkv_d->video->tnum == block->TrackNum())) + handle_realvideo(d, data, (elements_found & 4) == 0, + found_data); + else { + dp = new_demux_packet(data.Size()); + memcpy(dp->buffer, data.Buffer(), data.Size()); + dp->pts = mkv_d->last_pts; + // keyframe? + dp->flags = (elements_found & 4) == 0 ? 1 : 0; + ds_add_packet(ds, dp); + found_data++; + } } mkv_d->skip_to_keyframe = 0; mkv_d->skip_to_timecode = 0; } else if ((mkv_d->subs_track != NULL) && (mkv_d->subs_track->tnum == block->TrackNum())) handle_subtitles(d, block, block_duration); - - d->filepos = mkv_d->in->getFilePointer(); - mkv_d->last_pts = (float)(block->GlobalTimecode() / 1000000.0 - - mkv_d->first_tc) / 1000.0; - mkv_d->last_filepos = d->filepos; } delete block; } // block != NULL - } + } else + upper_lvl_el = 0; if (upper_lvl_el > 0) { // we're coming from l3 upper_lvl_el--; @@ -1892,20 +2234,22 @@ l2 = l3; if (upper_lvl_el > 0) break; - } else { + } else if (upper_lvl_el == 0) { l2->SkipData(static_cast(*es), l2->Generic().Context); delete l2; l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); + } else { + delete l2; + l2 = l3; } + } // while (l2 != NULL) } else if (EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) return 0; else - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Unknown element@1: %s (stream " - "position %llu)\n", typeid(*l1).name(), - l1->GetElementPosition()); + upper_lvl_el = 0; if (exit_loop) break; @@ -1916,14 +2260,18 @@ l1 = l2; if (upper_lvl_el > 0) break; - } else { + } else if (upper_lvl_el == 0) { l1->SkipData(static_cast(*es), l1->Generic().Context); delete l1; l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); if ((l1 != NULL) && (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId)) add_cluster_position(mkv_d, l1->GetElementPosition()); + } else { + delete l1; + l1 = l2; } + } // while (l1 != NULL) } catch (exception ex) { mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] exception caught\n"); diff -r 4c9ca4819bed -r c2fc1c310699 libmpdemux/matroska.h --- a/libmpdemux/matroska.h Fri Jul 11 07:54:52 2003 +0000 +++ b/libmpdemux/matroska.h Fri Jul 11 20:24:20 2003 +0000 @@ -21,8 +21,17 @@ #define MKV_A_PCM "A_PCM/INT/LIT" #define MKV_A_VORBIS "A_VORBIS" #define MKV_A_ACM "A_MS/ACM" +#define MKV_A_REAL28 "A_REAL/28_8" +#define MKV_A_REALATRC "A_REAL/ATRC" +#define MKV_A_REALCOOK "A_REAL/COOK" +#define MKV_A_REALDNET "A_REAL/DNET" +#define MKV_A_REALSIPR "A_REAL/SIPR" #define MKV_V_MSCOMP "V_MS/VFW/FOURCC" +#define MKV_V_REALV10 "V_REAL/RV10" +#define MKV_V_REALV20 "V_REAL/RV20" +#define MKV_V_REALV30 "V_REAL/RV30" +#define MKV_V_REALV40 "V_REAL/RV40" #define MKV_S_TEXTASCII "S_TEXT/ASCII" #define MKV_S_TEXTUTF8 "S_TEXT/UTF8"