Mercurial > mplayer.hg
diff libmpdemux/demux_mkv.cpp @ 10060:f4d6cf8c6c93
Fixed seeking in audio-only files. Added support for subtitle track selection via "-slang".
author | mosu |
---|---|
date | Sun, 04 May 2003 11:03:02 +0000 |
parents | 1dfe4dab4a42 |
children | 4c4c2761643c |
line wrap: on
line diff
--- a/libmpdemux/demux_mkv.cpp Sat May 03 17:03:13 2003 +0000 +++ b/libmpdemux/demux_mkv.cpp Sun May 04 11:03:02 2003 +0000 @@ -53,6 +53,9 @@ using namespace LIBMATROSKA_NAMESPACE; using namespace std; +// for e.g. "-slang ger" +extern char *dvdsub_lang; + // default values for Matroska elements #define MKVD_TIMECODESCALE 1000000 // 1000000 = 1ms @@ -127,8 +130,9 @@ char *codec_id; int ms_compat; + char *language; - char type; // 'v' = video, 'a' = audio, 't' = text subs + char type; // 'v' = video, 'a' = audio, 's' = subs char v_fourcc[5]; uint32_t v_width, v_height; @@ -176,6 +180,7 @@ int num_cluster_pos; int skip_to_keyframe; + int64_t skip_to_timecode; } mkv_demuxer_t; static uint16_t get_uint16(const void *buf) { @@ -282,6 +287,7 @@ t->default_track = 1; t->a_sfreq = 8000.0; t->a_channels = 1; + t->language = strdup("eng"); } return t; @@ -299,6 +305,20 @@ return NULL; } +static mkv_track_t *find_track_by_language(mkv_demuxer_t *d, char *language, + mkv_track_t *c, char type = 's') { + int i; + + for (i = 0; i < d->num_tracks; i++) + if ((d->tracks[i] != NULL) && (d->tracks[i] != c) && + (d->tracks[i]->language != NULL) && + !strcmp(d->tracks[i]->language, language) && + (d->tracks[i]->type == type)) + return d->tracks[i]; + + return NULL; +} + static int check_track_information(mkv_demuxer_t *d) { int i, track_num; unsigned char *c; @@ -533,6 +553,8 @@ if (d->tracks[i] != NULL) { if (d->tracks[i]->private_data != NULL) free(d->tracks[i]->private_data); + if (d->tracks[i]->language != NULL) + free(d->tracks[i]->language); free(d->tracks[i]); } @@ -1158,6 +1180,17 @@ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Default flag: %u\n", track->default_track); + } else if (EbmlId(*l3) == + KaxTrackLanguage::ClassInfos.GlobalId) { + KaxTrackLanguage &language = + *static_cast<KaxTrackLanguage *>(l3); + language.ReadData(es->I_O()); + mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Language: %s\n", + string(language).c_str()); + if (track->language != NULL) + free(track->language); + track->language = strdup(string(language).c_str()); + } else if ((!(EbmlId(*l3) == KaxTrackFlagLacing::ClassInfos.GlobalId)) && (!(EbmlId(*l3) == @@ -1487,27 +1520,28 @@ // DO NOT automatically select a subtitle track and behave like DVD // playback: only show subtitles if the user explicitely wants them. - if (demuxer->sub->id >= 0) { + if (dvdsub_lang != NULL) + track = find_track_by_language(mkv_d, dvdsub_lang, NULL); + else if (demuxer->sub->id >= 0) track = find_track_by_num(mkv_d, demuxer->sub->id, NULL); - if (track) { - if (strcmp(track->codec_id, MKV_S_TEXTASCII) && - strcmp(track->codec_id, MKV_S_TEXTUTF8)) - mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Subtitle type '%s' is not " - "supported. Track will not be displayed.\n", track->codec_id); - else { - mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will display subtitle track %u\n", - track->tnum); - mkv_d->subs_track = track; - if (!mkv_d->subs.text[0]) { - for (i = 0; i < SUB_MAX_TEXT; i++) - mkv_d->subs.text[i] = (char *)malloc(256); + if (track) { + if (strcmp(track->codec_id, MKV_S_TEXTASCII) && + strcmp(track->codec_id, MKV_S_TEXTUTF8)) + mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Subtitle type '%s' is not " + "supported. Track will not be displayed.\n", track->codec_id); + else { + mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will display subtitle track %u\n", + track->tnum); + mkv_d->subs_track = track; + if (!mkv_d->subs.text[0]) { + for (i = 0; i < SUB_MAX_TEXT; i++) + mkv_d->subs.text[i] = (char *)malloc(256); - if (!strcmp(track->codec_id, MKV_S_TEXTUTF8)) - sub_utf8 = 1; // Force UTF-8 conversion. - } else - mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] File does not contain a " - "subtitle track with the id %u.\n", demuxer->sub->id); - } + if (!strcmp(track->codec_id, MKV_S_TEXTUTF8)) + sub_utf8 = 1; // Force UTF-8 conversion. + } else + mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] File does not contain a " + "subtitle track with the id %u.\n", demuxer->sub->id); } } @@ -1530,7 +1564,7 @@ mkv_demuxer_t *mkv_d; int upper_lvl_el, exit_loop, found_data, i, delete_element, elements_found; // Elements for different levels - EbmlElement *l0 = NULL, *l1 = NULL, *l2 = NULL, *l3 = NULL, *l4 = NULL; + EbmlElement *l0 = NULL, *l1 = NULL, *l2 = NULL, *l3 = NULL; EbmlStream *es; KaxBlock *block; int64_t block_duration, block_ref1, block_ref2; @@ -1572,7 +1606,7 @@ if (upper_lvl_el != 0) break; - // Handle at at least one data packets in one call to + // Handle at least one data packets in one call to // demux_mkv_fill_buffer - but abort if we have found that. if (found_data >= 1) { mkv_d->saved_l2 = l2; @@ -1632,20 +1666,12 @@ } - if (upper_lvl_el > 0) { // we're coming from l4 - upper_lvl_el--; + l3->SkipData(static_cast<EbmlStream &>(*es), + l3->Generic().Context); + if (delete_element) delete l3; - l3 = l4; - if (upper_lvl_el > 0) - break; - } else { - l3->SkipData(static_cast<EbmlStream &>(*es), - l3->Generic().Context); - if (delete_element) - delete l3; - l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, - 0xFFFFFFFFL, true, 1); - } + l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, + 0xFFFFFFFFL, true, 1); } // while (l3 != NULL) if (block != NULL) { @@ -1671,7 +1697,8 @@ (((elements_found & 4) == 0) && // It's a key frame. (ds != NULL) && // Corresponding track found (ds == d->video))) { // track is our video track - if (ds != NULL) { + if ((ds != NULL) && ((block->GlobalTimecode() / 1000000) >= + (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()); @@ -1680,8 +1707,9 @@ dp->flags = 0; ds_add_packet(ds, dp); found_data++; - mkv_d->skip_to_keyframe = 0; } + 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); @@ -1732,7 +1760,7 @@ delete l1; l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); - if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) + if ((l1 != NULL) && (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId)) add_cluster_position(mkv_d, l1->GetElementPosition()); } } // while (l1 != NULL) @@ -1850,7 +1878,8 @@ target_filepos = (int64_t)(target_timecode * mkv_d->last_filepos / (mkv_d->last_pts * 1000.0)); mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No index entry found. Calculated " - "filepos %lld.\n", target_filepos); + "filepos %lld. Old timecode %lld.\n", target_filepos, + (int64_t)(mkv_d->last_pts * 1000.0)); // Let's find the nearest cluster so that libebml does not have to // do so much work. cluster_pos = 0; @@ -1867,33 +1896,34 @@ min_diff = abs(diff); } } - if (min_diff != 0x0FFFFFFFL) + if (min_diff != 0x0FFFFFFFL) { target_filepos = cluster_pos; + mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] New target_filepos because of " + "cluster: %lld.\n", target_filepos); + } if (target_filepos >= demuxer->movi_end) return; - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] New target_filepos because of cluster:" - " %lld.\n", target_filepos); mkv_d->in->setFilePointer(target_filepos); upper_lvl_el = 0; mkv_d->saved_l1 = mkv_d->es->FindNextElement(mkv_d->segment->Generic().Context, - upper_lvl_el, 0xFFFFFFFFL, false, 1); + upper_lvl_el, 0xFFFFFFFFL, true, 1); mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek result: target_timecode %lld, " "did not find an entry. Calculated target_filspos: %lld\n", target_timecode, target_filepos); - if ((mkv_d->saved_l1 != NULL) && - (EbmlId(*mkv_d->saved_l1) == KaxSegment::ClassInfos.GlobalId)) - mkv_d->saved_l1 = - mkv_d->es->FindNextElement(mkv_d->saved_l1->Generic().Context, - upper_lvl_el, 0xFFFFFFFFL, true, 1); mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek found %p (%s).\n", mkv_d->saved_l1, mkv_d->saved_l1 == NULL ? "null" : typeid(*mkv_d->saved_l1).name()); } - mkv_d->skip_to_keyframe = 1; + if (mkv_d->video != NULL) + mkv_d->skip_to_keyframe = 1; + if (rel_seek_secs > 0.0) + mkv_d->skip_to_timecode = target_timecode; demux_mkv_fill_buffer(demuxer); + mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] New timecode: %lld\n", + (int64_t)(mkv_d->last_pts * 1000.0)); mkv_d->subs.lines = 0; vo_sub = &mkv_d->subs;