///////////// // Open file void MatroskaWrapper::Open(wxString filename) { // Make sure it's closed first Close(); // Open char err[2048]; input = new MkvStdIO(filename); if (input->fp) { file = mkv_Open(input,err,sizeof(err)); // Failed parsing if (!file) { delete input; throw wxString(_T("MatroskaParser error: ") + wxString(err,wxConvUTF8)).c_str(); } Parse(); } // Failed opening else { delete input; throw _T("Unable to open Matroska file for parsing."); } }
bool MatroskaWrapper::HasSubtitles(agi::fs::path const& filename) { char err[2048]; try { MkvStdIO input(filename); agi::scoped_holder<MatroskaFile*, decltype(&mkv_Close)> file(mkv_Open(&input, err, sizeof(err)), mkv_Close); if (!file) return false; // Find tracks auto tracks = mkv_GetNumTracks(file); for (auto track : boost::irange(0u, tracks)) { auto trackInfo = mkv_GetTrackInfo(file, track); if (trackInfo->Type == 0x11 && !trackInfo->CompEnabled) { std::string CodecID(trackInfo->CodecID); if (CodecID == "S_TEXT/SSA" || CodecID == "S_TEXT/ASS" || CodecID == "S_TEXT/UTF8") return true; } } } catch (...) { // We don't care about why we couldn't read subtitles here } return false; }
MatroskaFile *openMatroskaFile(char *filePath, StdIoStream *ioStream) { char err_msg[256]; /* fill in I/O object */ ioStream->base.read = (int(*)(struct InputStream *, ulonglong, void *, int))StdIoRead; ioStream->base.scan = (longlong(*)(struct InputStream *, ulonglong, unsigned int))StdIoScan; ioStream->base.getcachesize = (unsigned int (*)(struct InputStream *))StdIoGetCacheSize; ioStream->base.geterror = (const char *(*)(struct InputStream *))StdIoGetLastError; ioStream->base.memalloc = (void *(*)(struct InputStream *, size_t))StdIoMalloc; ioStream->base.memrealloc = (void *(*)(struct InputStream *, void *, size_t))StdIoRealloc; ioStream->base.memfree = (void(*)(struct InputStream *, void *))StdIoFree; ioStream->base.progress = (int (*)(struct InputStream *, uint64_t, uint64_t))StdIoProgress; /* open source file */ ioStream->fp = fopen(filePath,"r"); if (ioStream->fp == NULL) { fprintf(stderr, "Can't open '%s': %s\n", filePath, strerror(errno)); return NULL; } setvbuf(ioStream->fp, NULL, _IOFBF, CACHESIZE); /* initialize matroska parser */ MatroskaFile *mf = mkv_Open(&ioStream->base, /* pointer to I/O object */ // 0, /* starting position in the file */ // 0, err_msg, sizeof(err_msg)); /* error message is returned here */ if (mf == NULL) { fclose(ioStream->fp); fprintf(stderr, "Can't parse Matroska file: %s\n", err_msg); return NULL; } return mf; }
void MatroskaWrapper::GetSubtitles(agi::fs::path const& filename, AssFile *target) { MkvStdIO input(filename); char err[2048]; agi::scoped_holder<MatroskaFile*, decltype(&mkv_Close)> file(mkv_Open(&input, err, sizeof(err)), mkv_Close); if (!file) throw MatroskaException(err); // Get info unsigned tracks = mkv_GetNumTracks(file); std::vector<unsigned> tracksFound; std::vector<std::string> tracksNames; // Find tracks for (auto track : boost::irange(0u, tracks)) { auto trackInfo = mkv_GetTrackInfo(file, track); if (trackInfo->Type != 0x11 || trackInfo->CompEnabled) continue; // Known subtitle format std::string CodecID(trackInfo->CodecID); if (CodecID == "S_TEXT/SSA" || CodecID == "S_TEXT/ASS" || CodecID == "S_TEXT/UTF8") { tracksFound.push_back(track); tracksNames.emplace_back(agi::format("%d (%s %s)", track, CodecID, trackInfo->Language)); if (trackInfo->Name) { tracksNames.back() += ": "; tracksNames.back() += trackInfo->Name; } } } // No tracks found if (tracksFound.empty()) throw MatroskaException("File has no recognised subtitle tracks."); unsigned trackToRead; // Only one track found if (tracksFound.size() == 1) trackToRead = tracksFound[0]; // Pick a track else { int choice = wxGetSingleChoiceIndex(_("Choose which track to read:"), _("Multiple subtitle tracks found"), to_wx(tracksNames)); if (choice == -1) throw agi::UserCancelException("canceled"); trackToRead = tracksFound[choice]; } // Picked track mkv_SetTrackMask(file, ~(1 << trackToRead)); auto trackInfo = mkv_GetTrackInfo(file, trackToRead); std::string CodecID(trackInfo->CodecID); bool srt = CodecID == "S_TEXT/UTF8"; bool ssa = CodecID == "S_TEXT/SSA"; AssParser parser(target, !ssa); // Read private data if it's ASS/SSA if (!srt) { // Read raw data std::string priv((const char *)trackInfo->CodecPrivate, trackInfo->CodecPrivateSize); // Load into file boost::char_separator<char> sep("\r\n"); for (auto const& cur : boost::tokenizer<boost::char_separator<char>>(priv, sep)) parser.AddLine(cur); } // Load default if it's SRT else { target->LoadDefault(false, OPT_GET("Subtitle Format/SRT/Default Style Catalog")->GetString()); parser.AddLine("[Events]"); } // Read timecode scale auto segInfo = mkv_GetFileInfo(file); int64_t timecodeScale = mkv_TruncFloat(trackInfo->TimecodeScale) * segInfo->TimecodeScale; // Progress bar auto totalTime = double(segInfo->Duration) / timecodeScale; DialogProgress progress(nullptr, _("Parsing Matroska"), _("Reading subtitles from Matroska file.")); progress.Run([&](agi::ProgressSink *ps) { read_subtitles(ps, file, &input, srt, totalTime, &parser); }); }