def test_get_log_loss(self): undertest_obj = Undertest(n_mfcc=20) subs, audio_file_path, voice_probabilities, frame_rate = undertest_obj.predict_single_pass( self.__video_file_path, self.__srt_file_path, self.__weights_dir) log_loss = undertest_obj.get_log_loss(voice_probabilities, subs) self.assertGreater(log_loss, 0) self.assertEqual(24.0, frame_rate)
def kernprof_target(): examples_dir = os.path.dirname(os.path.abspath(__file__)) output_dir = os.path.join(examples_dir, "tmp") os.makedirs(output_dir, exist_ok=True) video_file_path = os.path.join(examples_dir, "..", "video.mp4") srt_file_path = os.path.join(examples_dir, "..", "subtitle.srt") predictor = Predictor() predictor.predict_dual_pass(video_file_path, srt_file_path)
def test_predict_dual_pass_on_audio(self): undertest_obj = Undertest(n_mfcc=20) new_subs, subs, voice_probabilities, frame_rate = undertest_obj.predict_dual_pass( self.__audio_file_path, self.__srt_file_path, self.__weights_dir) self.assertGreater(len(new_subs), 0) self.assertEqual(len(new_subs), len(subs)) self.assertGreater(len(voice_probabilities), 0) self.assertIsNone(frame_rate)
def test_throw_exception_on_segment_alignment_failure_when_flag_on(self, mock_time_to_sec): try: undertest_obj = Undertest(n_mfcc=20) undertest_obj.predict_dual_pass(self.__video_file_path, self.__srt_file_path, self.__weights_dir, exit_segfail=True) except Exception as e: self.assertTrue(mock_time_to_sec.called) self.assertTrue(isinstance(e, TerminalException)) self.assertTrue("At least one of the segments failed on alignment. Exiting..." in str(e)) else: self.fail("Should have thrown exception")
def test_not_throw_exception_on_segment_alignment_failure(self, mock_time_to_sec): undertest_obj = Undertest(n_mfcc=20) new_subs, subs, voice_probabilities, frame_rate = undertest_obj.predict_dual_pass( self.__video_file_path, self.__srt_file_path, self.__weights_dir ) self.assertGreater(len(new_subs), 0) self.assertEqual(len(new_subs), len(subs)) self.assertGreater(len(voice_probabilities), 0) self.assertTrue(mock_time_to_sec.called) self.assertEqual(24.0, frame_rate)
def test_get_log_loss_on_speech_shorter_than_subtitle(self): undertest_obj = Undertest(n_mfcc=20) shorter_audio_file_path, _ = MediaHelper.extract_audio_from_start_to_end(self.__audio_file_path, "00:00:00,000", "00:00:32,797") self.__audio_file_paths.append(shorter_audio_file_path) subs, audio_file_path, voice_probabilities, frame_rate = undertest_obj.predict_single_pass( shorter_audio_file_path, self.__srt_file_path, self.__weights_dir ) log_loss = undertest_obj.get_log_loss(voice_probabilities, subs) self.assertGreater(log_loss, 0) self.assertIsNone(frame_rate)
def test_throw_terminal_exception_on_timeout(self): backup = Undertest._Predictor__SEGMENT_PREDICTION_TIMEOUT Undertest._Predictor__SEGMENT_PREDICTION_TIMEOUT = 0.05 try: undertest_obj = Undertest(n_mfcc=20) undertest_obj.predict_dual_pass(self.__video_file_path, self.__srt_file_path, self.__weights_dir) except Exception as e: self.assertTrue(isinstance(e, TerminalException)) else: self.fail("Should have thrown exception") finally: Undertest._Predictor__SEGMENT_PREDICTION_TIMEOUT = backup
def test_throw_exception_on_predict_interrupted(self, mock_result): try: undertest_obj = Undertest(n_mfcc=20) undertest_obj.predict_dual_pass(self.__video_file_path, self.__srt_file_path, self.__weights_dir) except Exception as e: self.assertTrue(mock_result.called) self.assertTrue(isinstance(e, TerminalException)) self.assertTrue("interrupted" in str(e)) else: self.fail("Should have thrown exception")
def test_predict_dual_pass_without_stretching_logs(self): quiet = Logger.QUIET Logger.QUIET = True undertest_obj = Undertest(n_mfcc=20) new_subs, subs, voice_probabilities, frame_rate = undertest_obj.predict_dual_pass( self.__audio_file_path, self.__srt_file_path, self.__weights_dir ) self.assertGreater(len(new_subs), 0) self.assertEqual(len(new_subs), len(subs)) self.assertGreater(len(voice_probabilities), 0) self.assertIsNone(frame_rate) Logger.QUIET = quiet
def generate_profiles(file_dir="."): examples_dir = os.path.dirname(os.path.abspath(__file__)) output_dir = os.path.join(examples_dir, "tmp") os.makedirs(output_dir, exist_ok=True) video_file_path = os.path.join(examples_dir, "..", "tests/subaligner/resource/test.mp4") srt_file_path = os.path.join(examples_dir, "..", "tests/subaligner/resource/test.srt") predictor = Predictor() cProfile.runctx( "predictor.predict_dual_pass(video_file_path, srt_file_path)", None, locals(), os.path.join(file_dir, "predictor.prof")) hyperparameters = Hyperparameters() hyperparameters.epochs = 10 trainer = Trainer(FeatureEmbedder()) cProfile.runctx( ("trainer.train([video_file_path, video_file_path, video_file_path]," "[srt_file_path, srt_file_path, srt_file_path]," "output_dir," "output_dir," "output_dir," "output_dir," "output_dir," "hyperparameters)"), None, locals(), os.path.join(file_dir, "trainer.prof"))
def test_predict_dual_pass_with_stretching(self): undertest_obj = Undertest(n_mfcc=20) new_subs, subs, voice_probabilities, frame_rate = undertest_obj.predict_dual_pass( self.__video_file_path, self.__srt_file_path, self.__weights_dir, stretch=True ) stretched = False for index, sub in enumerate(new_subs): if (sub.duration != subs[index].duration): stretched = True break self.assertGreater(len(new_subs), 0) self.assertEqual(len(new_subs), len(subs)) self.assertTrue(stretched) self.assertGreater(len(voice_probabilities), 0) self.assertEqual(24.0, frame_rate)
def main(): if sys.version_info.major != 3: print("Cannot find Python 3") sys.exit(20) try: import subaligner except ModuleNotFoundError: print("Subaligner is not installed") sys.exit(20) parser = argparse.ArgumentParser( description="Subaligner command line interface") required_args = parser.add_argument_group("required arguments") required_args.add_argument( "-m", "--mode", type=str, default="", choices=["single", "dual"], help="Alignment mode: either single or dual", required=True, ) required_args.add_argument( "-v", "--video_path", type=str, default="", help="Path to the video file", required=True, ) required_args.add_argument( "-s", "--subtitle_path", type=str, default="", help="Path to the subtitle file", required=True, ) parser.add_argument( "-l", "--max_logloss", type=float, default=float("inf"), help="Max global log loss for alignment", ) parser.add_argument( "-so", "--stretch_off", action="store_true", help="Switch off stretch on non-English speech and subtitles)", ) parser.add_argument( "-fos", "--exit_segfail", action="store_true", help="Exit on any segment alignment failures", ) parser.add_argument( "-tod", "--training_output_directory", type=str, default=os.path.abspath(os.path.dirname(subaligner.__file__)), help="Path to the output directory containing training results", ) parser.add_argument( "-o", "--output", type=str, default="", help="Path to the output subtitle file", ) parser.add_argument("-d", "--debug", action="store_true", help="Print out debugging information") parser.add_argument("-q", "--quiet", action="store_true", help="Switch off logging information") FLAGS, unparsed = parser.parse_known_args() if FLAGS.mode == "": print("--mode was not passed in") sys.exit(21) if FLAGS.video_path == "": print("--video_path was not passed in") sys.exit(21) if FLAGS.subtitle_path == "": print("--subtitle_path was not passed in") sys.exit(21) exit_segfail = FLAGS.exit_segfail stretch = not FLAGS.stretch_off from subaligner.logger import Logger Logger.VERBOSE = FLAGS.debug Logger.QUIET = FLAGS.quiet from subaligner.predictor import Predictor from subaligner.subtitle import Subtitle from subaligner.exception import UnsupportedFormatException from subaligner.exception import TerminalException try: predictor = Predictor() if FLAGS.mode == "single": aligned_subs, audio_file_path, voice_probabilities, frame_rate = predictor.predict_single_pass( video_file_path=FLAGS.video_path, subtitle_file_path=FLAGS.subtitle_path, weights_dir=os.path.join(FLAGS.training_output_directory, "models/training/weights")) else: aligned_subs, subs, voice_probabilities, frame_rate = predictor.predict_dual_pass( video_file_path=FLAGS.video_path, subtitle_file_path=FLAGS.subtitle_path, weights_dir=os.path.join(FLAGS.training_output_directory, "models/training/weights"), stretch=stretch, exit_segfail=exit_segfail, ) aligned_subtitle_path = "_aligned.".join( FLAGS.subtitle_path.rsplit( ".", 1)) if FLAGS.output == "" else FLAGS.output Subtitle.export_subtitle(FLAGS.subtitle_path, aligned_subs, aligned_subtitle_path, frame_rate) print("Aligned subtitle saved to: {}".format(aligned_subtitle_path)) log_loss = predictor.get_log_loss(voice_probabilities, aligned_subs) if log_loss is None or log_loss > FLAGS.max_logloss: print("Alignment failed with a too high loss value: {}".format( log_loss)) exit(22) except UnsupportedFormatException as e: print("{}\n{}".format( str(e), "".join(traceback.format_stack()) if FLAGS.debug else "")) sys.exit(23) except TerminalException as e: print("{}\n{}".format( str(e), "".join(traceback.format_stack()) if FLAGS.debug else "")) sys.exit(24) except Exception as e: print("{}\n{}".format( str(e), "".join(traceback.format_stack()) if FLAGS.debug else "")) sys.exit(1) else: exit(0)
import os from subaligner.predictor import Predictor from subaligner.subtitle import Subtitle if __name__ == "__main__": examples_dir = os.path.dirname(os.path.abspath(__file__)) output_dir = os.path.join(examples_dir, "tmp") os.makedirs(output_dir, exist_ok=True) video_file_path = os.path.join(examples_dir, "..", "tests/subaligner/resource/test.mp4") srt_file_path = os.path.join(examples_dir, "..", "tests/subaligner/resource/test.srt") predictor = Predictor() subs, audio_file_path, voice_probabilities, frame_rate = predictor.predict_single_pass( video_file_path, srt_file_path) aligned_subtitle_path = os.path.join(output_dir, "test_aligned_1.srt") Subtitle.export_subtitle(srt_file_path, subs, aligned_subtitle_path) print("Aligned subtitle saved to: {}".format(aligned_subtitle_path)) log_loss = predictor.get_log_loss(voice_probabilities, subs) print("Alignment finished with overall loss: {}".format(log_loss)) subs_list, subs, voice_probabilities, frame_rate = predictor.predict_dual_pass( video_file_path, srt_file_path, stretch=False) aligned_subtitle_path = os.path.join(output_dir, "test_aligned_2.srt") Subtitle.export_subtitle(srt_file_path, subs_list, aligned_subtitle_path) print("Aligned subtitle saved to: {}".format(aligned_subtitle_path)) log_loss = predictor.get_log_loss(voice_probabilities, subs) print("Alignment finished with overall loss: {}".format(log_loss))
def main(): if sys.version_info.major != 3: print("Cannot find Python 3") sys.exit(20) try: import subaligner except ModuleNotFoundError: print("Subaligner is not installed") sys.exit(20) from subaligner._version import __version__ parser = argparse.ArgumentParser( description="Run single-stage alignment (v%s)" % __version__, formatter_class=argparse.RawTextHelpFormatter) required_args = parser.add_argument_group("required arguments") required_args.add_argument( "-v", "--video_path", type=str, default="", help="File path or URL to the video file", required=True, ) from subaligner.subtitle import Subtitle required_args.add_argument( "-s", "--subtitle_path", type=str, default="", help= "File path or URL to the subtitle file (Extensions of supported subtitles: {}) or selector for the embedded subtitle (e.g., embedded:page_num=888 or embedded:stream_index=0)" .format(", ".join(Subtitle.subtitle_extensions())), required=True, ) parser.add_argument( "-l", "--max_logloss", type=float, default=float("inf"), help="Max global log loss for alignment", ) parser.add_argument( "-tod", "--training_output_directory", type=str, default=os.path.abspath(os.path.dirname(subaligner.__file__)), help="Path to the output directory containing training results", ) parser.add_argument( "-o", "--output", type=str, default="", help="Path to the output subtitle file", ) parser.add_argument("-d", "--debug", action="store_true", help="Print out debugging information") parser.add_argument("-q", "--quiet", action="store_true", help="Switch off logging information") parser.add_argument("-ver", "--version", action="version", version=__version__) FLAGS, unparsed = parser.parse_known_args() if FLAGS.video_path == "": print("--video_path was not passed in") sys.exit(21) if FLAGS.subtitle_path == "": print("--subtitle_path was not passed in") sys.exit(21) if FLAGS.subtitle_path.lower().startswith("http") and FLAGS.output == "": print( "--output was not passed in for alignment on a remote subtitle file" ) sys.exit(21) if FLAGS.subtitle_path.lower().startswith( "teletext:") and FLAGS.output == "": print("--output was not passed in for alignment on embedded subtitles") sys.exit(21) local_video_path = FLAGS.video_path local_subtitle_path = FLAGS.subtitle_path from subaligner.logger import Logger Logger.VERBOSE = FLAGS.debug Logger.QUIET = FLAGS.quiet from subaligner.predictor import Predictor from subaligner.exception import UnsupportedFormatException from subaligner.exception import TerminalException from subaligner.utils import Utils try: if FLAGS.video_path.lower().startswith("http"): _, local_video_path = tempfile.mkstemp() _, video_file_extension = os.path.splitext( FLAGS.video_path.lower()) local_video_path = "{}{}".format(local_video_path, video_file_extension) Utils.download_file(FLAGS.video_path, local_video_path) if FLAGS.subtitle_path.lower().startswith("http"): _, local_subtitle_path = tempfile.mkstemp() _, subtitle_file_extension = os.path.splitext( FLAGS.subtitle_path.lower()) local_subtitle_path = "{}{}".format(local_subtitle_path, subtitle_file_extension) Utils.download_file(FLAGS.subtitle_path, local_subtitle_path) if FLAGS.subtitle_path.lower().startswith("embedded:"): _, local_subtitle_path = tempfile.mkstemp() _, subtitle_file_extension = os.path.splitext(FLAGS.output) local_subtitle_path = "{}{}".format(local_subtitle_path, subtitle_file_extension) params = FLAGS.subtitle_path.lower().split(":")[1].split(",") if params and "=" in params[0]: params = { param.split("=")[0]: param.split("=")[1] for param in params } if "page_num" in params: Utils.extract_teletext_as_subtitle(local_video_path, int(params["page_num"]), local_subtitle_path) elif "stream_index" in params: Utils.extract_matroska_subtitle( local_video_path, int(params["stream_index"]), local_subtitle_path) else: print("Embedded subtitle selector cannot be empty") sys.exit(21) predictor = Predictor() subs, audio_file_path, voice_probabilities, frame_rate = predictor.predict_single_pass( video_file_path=local_video_path, subtitle_file_path=local_subtitle_path, weights_dir=os.path.join(FLAGS.training_output_directory, "models/training/weights")) aligned_subtitle_path = "_aligned.".join( FLAGS.subtitle_path.rsplit(".", 1)).replace( ".stl", ".srt") if FLAGS.output == "" else FLAGS.output Subtitle.export_subtitle(local_subtitle_path, subs, aligned_subtitle_path, frame_rate) log_loss = predictor.get_log_loss(voice_probabilities, subs) if log_loss is None or log_loss > FLAGS.max_logloss: print("Alignment failed with a too high loss value: {}".format( log_loss)) _remove_tmp_files(FLAGS, local_video_path, local_subtitle_path) sys.exit(22) print("Aligned subtitle saved to: {}".format(aligned_subtitle_path)) except UnsupportedFormatException as e: print("{}\n{}".format( str(e), "".join(traceback.format_stack()) if FLAGS.debug else "")) _remove_tmp_files(FLAGS, local_video_path, local_subtitle_path) sys.exit(23) except TerminalException as e: print("{}\n{}".format( str(e), "".join(traceback.format_stack()) if FLAGS.debug else "")) _remove_tmp_files(FLAGS, local_video_path, local_subtitle_path) sys.exit(24) except Exception as e: print("{}\n{}".format( str(e), "".join(traceback.format_stack()) if FLAGS.debug else "")) _remove_tmp_files(FLAGS, local_video_path, local_subtitle_path) sys.exit(1) else: _remove_tmp_files(FLAGS, local_video_path, local_subtitle_path) sys.exit(0)