Use PGS (Presentation Graphic Stream) subtitle timings as a sync reference. PGS subtitles are bitmap-based (e.g. Blu-ray / HDMV) and cannot be converted to text by ffmpeg, so they can't be fed through the normal subtitle pipeline. However, when muxed into an MKV the container still stor
| 1101 | |
| 1102 | |
| 1103 | class PGSSpeechTransformer(TransformerMixin, ComputeSpeechFrameBoundariesMixin): |
| 1104 | """Use PGS (Presentation Graphic Stream) subtitle timings as a sync reference. |
| 1105 | |
| 1106 | PGS subtitles are bitmap-based (e.g. Blu-ray / HDMV) and cannot be converted |
| 1107 | to text by ffmpeg, so they can't be fed through the normal subtitle pipeline. |
| 1108 | However, when muxed into an MKV the container still stores a presentation |
| 1109 | timestamp (``pts_time``) and ``duration_time`` for every subtitle packet, so |
| 1110 | we can recover *when* each caption is on screen without decoding the bitmaps |
| 1111 | or parsing the raw SUP/PCS binary at all. |
| 1112 | |
| 1113 | This transformer reads those per-packet timings via ``ffprobe`` (see |
| 1114 | :func:`_get_pgs_timings_via_ffprobe`), filtering out the tiny "clear" packets |
| 1115 | that carry no image, and builds the same kind of sparse binary speech signal |
| 1116 | that :class:`SubtitleSpeechTransformer` produces for text subtitles: 1.0 while |
| 1117 | a caption is displayed, 0.0 otherwise. That signal can then be aligned against |
| 1118 | the input subtitle file by the normal ffsubsync pipeline. |
| 1119 | |
| 1120 | The reference stream may be given explicitly via ``ref_stream`` (with or |
| 1121 | without a leading ``0:``), or left as ``None`` to auto-detect the first |
| 1122 | ``hdmv_pgs_subtitle`` track in the file. |
| 1123 | """ |
| 1124 | |
| 1125 | # PGS is already in the MKV timebase so its duration cannot be compared |
| 1126 | # against the SRT to infer a framerate ratio. Returning None here prevents |
| 1127 | # the duration-based framerate inference in try_sync from running. |
| 1128 | @property |
| 1129 | def num_frames(self) -> None: |
| 1130 | return None |
| 1131 | |
| 1132 | def __init__( |
| 1133 | self, |
| 1134 | sample_rate: int, |
| 1135 | start_seconds: int = 0, |
| 1136 | ffmpeg_path: Optional[str] = None, |
| 1137 | ref_stream: Optional[str] = None, |
| 1138 | gui_mode: bool = False, |
| 1139 | ) -> None: |
| 1140 | super(PGSSpeechTransformer, self).__init__() |
| 1141 | self.sample_rate: int = sample_rate |
| 1142 | self.start_seconds: int = start_seconds |
| 1143 | self.ffmpeg_path: Optional[str] = ffmpeg_path |
| 1144 | self.ref_stream: Optional[str] = ref_stream |
| 1145 | self.gui_mode: bool = gui_mode |
| 1146 | self.pgs_speech_results_: Optional[np.ndarray] = None |
| 1147 | |
| 1148 | def fit(self, fname: str, *_) -> "PGSSpeechTransformer": |
| 1149 | if self.ref_stream is None: |
| 1150 | stream = find_pgs_stream(fname, self.ffmpeg_path, self.gui_mode) |
| 1151 | if stream is None: |
| 1152 | raise ValueError( |
| 1153 | "No hdmv_pgs_subtitle stream found in {}. " |
| 1154 | "Specify one explicitly with --pgs-ref-stream.".format(fname) |
| 1155 | ) |
| 1156 | else: |
| 1157 | stream = self.ref_stream |
| 1158 | if not stream.startswith("0:"): |
| 1159 | stream = "0:" + stream |
| 1160 |
no outgoing calls
no test coverage detected