void Project::LoadVideo(agi::fs::path path) { if (path.empty()) return; if (!DoLoadVideo(path)) return; if (OPT_GET("Video/Open Audio")->GetBool() && audio_file != video_file && video_provider->HasAudio()) DoLoadAudio(video_file, true); double dar = video_provider->GetDAR(); if (dar > 0) context->videoController->SetAspectRatio(dar); else context->videoController->SetAspectRatio(AspectRatio::Default); context->videoController->JumpToFrame(0); }
void VideoContext::LoadKeyframes(agi::fs::path const& filename) { if (filename == keyframes_filename || filename.empty()) return; try { keyframes = agi::keyframe::Load(filename); keyframes_filename = filename; KeyframesOpen(keyframes); config::mru->Add("Keyframes", filename); } catch (agi::keyframe::Error const& err) { wxMessageBox(to_wx(err.GetMessage()), "Error opening keyframes file", wxOK | wxICON_ERROR | wxCENTER, context->parent); config::mru->Remove("Keyframes", filename); } catch (agi::fs::FileSystemError const& err) { wxMessageBox(to_wx(err.GetMessage()), "Error opening keyframes file", wxOK | wxICON_ERROR | wxCENTER, context->parent); config::mru->Remove("Keyframes", filename); } }
void AudioController::OpenAudio(agi::fs::path const& url) { if (url.empty()) throw agi::InternalError("AudioController::OpenAudio() was passed an empty string. This must not happen.", 0); std::unique_ptr<AudioProvider> new_provider; try { new_provider = AudioProviderFactory::GetProvider(url); config::path->SetToken("?audio", url); } catch (agi::UserCancelException const&) { throw; } catch (...) { config::mru->Remove("Audio", url); throw; } CloseAudio(); provider = std::move(new_provider); try { player = AudioPlayerFactory::GetAudioPlayer(provider.get()); } catch (...) { provider.reset(); throw; } audio_url = url; config::mru->Add("Audio", url); try { AnnounceAudioOpen(provider.get()); } catch (...) { CloseAudio(); throw; } }
void VideoContext::LoadTimecodes(agi::fs::path const& filename) { if (filename == timecodes_filename || filename.empty()) return; try { ovr_fps = agi::vfr::Framerate(filename); timecodes_filename = filename; config::mru->Add("Timecodes", filename); OnSubtitlesCommit(0, std::set<const AssEntry*>()); TimecodesOpen(ovr_fps); } catch (agi::fs::FileSystemError const& err) { wxMessageBox(to_wx(err.GetMessage()), "Error opening timecodes file", wxOK | wxICON_ERROR | wxCENTER, context->parent); config::mru->Remove("Timecodes", filename); } catch (const agi::vfr::Error& e) { wxLogError("Timecode file parse error: %s", to_wx(e.GetMessage())); config::mru->Remove("Timecodes", filename); } }
void AudioController::SaveClip(agi::fs::path const& filename, TimeRange const& range) const { int64_t start_sample = SamplesFromMilliseconds(range.begin()); int64_t end_sample = SamplesFromMilliseconds(range.end()); if (filename.empty() || start_sample > provider->GetNumSamples() || range.length() == 0) return; agi::io::Save outfile(filename, true); std::ofstream& out(outfile.Get()); size_t bytes_per_sample = provider->GetBytesPerSample() * provider->GetChannels(); size_t bufsize = (end_sample - start_sample) * bytes_per_sample; int intval; short shortval; out << "RIFF"; out.write((char*)&(intval=bufsize+36),4); out<< "WAVEfmt "; out.write((char*)&(intval=16),4); out.write((char*)&(shortval=1),2); out.write((char*)&(shortval=provider->GetChannels()),2); out.write((char*)&(intval=provider->GetSampleRate()),4); out.write((char*)&(intval=provider->GetSampleRate()*provider->GetChannels()*provider->GetBytesPerSample()),4); out.write((char*)&(intval=provider->GetChannels()*provider->GetBytesPerSample()),2); out.write((char*)&(shortval=provider->GetBytesPerSample()<<3),2); out << "data"; out.write((char*)&bufsize,4); //samples per read size_t spr = 65536 / bytes_per_sample; std::vector<char> buf(bufsize); for(int64_t i = start_sample; i < end_sample; i += spr) { size_t len = std::min<size_t>(spr, end_sample - i); provider->GetAudio(&buf[0], i, len); out.write(&buf[0], len * bytes_per_sample); } }
void VideoContext::SetVideo(const agi::fs::path &filename) { Reset(); if (filename.empty()) { VideoOpen(); return; } bool commit_subs = false; try { provider.reset(new ThreadedFrameSource(filename, context->ass->GetScriptInfo("YCbCr Matrix"), this)); video_provider = provider->GetVideoProvider(); video_filename = filename; // Check that the script resolution matches the video resolution int sx = context->ass->GetScriptInfoAsInt("PlayResX"); int sy = context->ass->GetScriptInfoAsInt("PlayResY"); int vx = GetWidth(); int vy = GetHeight(); // If the script resolution hasn't been set at all just force it to the // video resolution if (sx == 0 && sy == 0) { context->ass->SetScriptInfo("PlayResX", std::to_string(vx)); context->ass->SetScriptInfo("PlayResY", std::to_string(vy)); commit_subs = true; } // If it has been set to something other than a multiple of the video // resolution, ask the user if they want it to be fixed else if (sx % vx != 0 || sy % vy != 0) { switch (OPT_GET("Video/Check Script Res")->GetInt()) { case 1: // Ask to change on mismatch if (wxYES != wxMessageBox( wxString::Format(_("The resolution of the loaded video and the resolution specified for the subtitles don't match.\n\nVideo resolution:\t%d x %d\nScript resolution:\t%d x %d\n\nChange subtitles resolution to match video?"), vx, vy, sx, sy), _("Resolution mismatch"), wxYES_NO | wxCENTER, context->parent)) break; // Fallthrough to case 2 case 2: // Always change script res context->ass->SetScriptInfo("PlayResX", std::to_string(vx)); context->ass->SetScriptInfo("PlayResY", std::to_string(vy)); commit_subs = true; break; default: // Never change break; } } keyframes = video_provider->GetKeyFrames(); // Set frame rate video_fps = video_provider->GetFPS(); if (ovr_fps.IsLoaded()) { int ovr = wxMessageBox(_("You already have timecodes loaded. Would you like to replace them with timecodes from the video file?"), _("Replace timecodes?"), wxYES_NO | wxICON_QUESTION); if (ovr == wxYES) { ovr_fps = agi::vfr::Framerate(); timecodes_filename.clear(); } } // Set aspect ratio double dar = video_provider->GetDAR(); if (dar > 0) SetAspectRatio(dar); // Set filename config::mru->Add("Video", filename); config::path->SetToken("?video", filename); // Show warning std::string warning = video_provider->GetWarning(); if (!warning.empty()) wxMessageBox(to_wx(warning), "Warning", wxICON_WARNING | wxOK); has_subtitles = false; if (agi::fs::HasExtension(filename, "mkv")) has_subtitles = MatroskaWrapper::HasSubtitles(filename); provider->LoadSubtitles(context->ass); VideoOpen(); KeyframesOpen(keyframes); TimecodesOpen(FPS()); } catch (agi::UserCancelException const&) { } catch (agi::fs::FileSystemError const& err) { config::mru->Remove("Video", filename); wxMessageBox(to_wx(err.GetMessage()), "Error setting video", wxOK | wxICON_ERROR | wxCENTER); } catch (VideoProviderError const& err) { wxMessageBox(to_wx(err.GetMessage()), "Error setting video", wxOK | wxICON_ERROR | wxCENTER); } if (commit_subs) context->ass->Commit(_("change script resolution"), AssFile::COMMIT_SCRIPTINFO); else JumpToFrame(0); }