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; }
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); }); }
AVStream *FFMpegManager::addVideoStream(AVFormatContext *oc, int codec_id, int width, int height, int fps) { AVCodecContext *c; AVStream *st; int w = width; int h = height; st = av_new_stream(oc, 0); if (!st) { dError() << "Could not alloc stream"; return 0; } #if LIBAVCODEC_BUILD <= 4743 c = &st->codec; #else c = st->codec; #endif c->codec_id = CodecID(codec_id); c->codec_type = CODEC_TYPE_VIDEO; /* put sample parameters */ c->bit_rate = 400000; /* resolution must be a multiple of two */ c->width = w; // 520 c->height = h; // 340 #if LIBAVCODEC_BUILD <= 4743 /* frames per second */ c->frame_rate = fps; c->frame_rate_base = 1; #else c->time_base.den = fps; c->time_base.num = 1; c->gop_size = 12; /* emit one intra frame every twelve frames at most */ c->pix_fmt = PIX_FMT_YUV420P; #endif c->gop_size = 12; /* emit one intra frame every twelve frames at most */ if (c->codec_id == CODEC_ID_MPEG2VIDEO) { /* just for testing, we also add B frames */ c->max_b_frames = 2; } if (c->codec_id == CODEC_ID_MPEG1VIDEO) { /* needed to avoid using macroblocks in which some coeffs overflow this doesnt happen with normal video, it just happens here as the motion of the chroma plane doesnt match the luma plane */ c->mb_decision=2; } // some formats want stream headers to be seperate if(!strcmp(oc->oformat->name, "mp4") || !strcmp(oc->oformat->name, "mov") || !strcmp(oc->oformat->name, "3gp")) { c->flags |= CODEC_FLAG_GLOBAL_HEADER; } return st; }