2022-06-29 03:21:31 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
from datetime import timedelta
|
|
|
|
import logging
|
|
|
|
|
|
|
|
from .disposition import FFprobeSubtitleDisposition
|
|
|
|
from .exceptions import UnsupportedCodec
|
|
|
|
from .tags import FFprobeGenericSubtitleTags
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class FFprobeSubtitleStream:
|
|
|
|
"""Base class for FFprobe (FFmpeg) extractable subtitle streams."""
|
|
|
|
|
|
|
|
def __init__(self, stream: dict):
|
|
|
|
"""
|
|
|
|
:raises: LanguageNotFound, UnsupportedCodec
|
|
|
|
"""
|
|
|
|
self.index = int(stream["index"])
|
2022-10-06 20:38:56 +00:00
|
|
|
self.codec_name = stream.get("codec_name", "Unknown")
|
2022-06-29 03:21:31 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
self._codec = _codecs[self.codec_name]
|
|
|
|
except KeyError:
|
|
|
|
raise UnsupportedCodec(f"{self.codec_name} is not supported")
|
|
|
|
|
|
|
|
self.r_frame_rate = stream.get("r_frame_rate")
|
|
|
|
self.avg_frame_rate = stream.get("avg_frame_rate")
|
|
|
|
self.start_time = timedelta(seconds=float(stream.get("start_time", 0)))
|
|
|
|
self.start_pts = timedelta(milliseconds=int(stream.get("start_pts", 0)))
|
|
|
|
self.duration_ts = timedelta(milliseconds=int(stream.get("duration_ts", 0)))
|
|
|
|
self.duration = timedelta(seconds=float(stream.get("duration", 0)))
|
|
|
|
|
|
|
|
self.tags = FFprobeGenericSubtitleTags.detect_cls_from_data(
|
|
|
|
stream.get("tags", {})
|
|
|
|
)
|
|
|
|
self.disposition = FFprobeSubtitleDisposition(stream.get("disposition", {}))
|
|
|
|
|
|
|
|
if stream.get("tags") is not None:
|
|
|
|
self.disposition.update_from_tags(stream["tags"])
|
|
|
|
|
|
|
|
def convert_args(self, convert_format, outfile):
|
|
|
|
"""
|
|
|
|
convert_format: Union[str, None] = the codec format to convert. if None is set, defaults
|
|
|
|
to 'convert_default_format' codec's key
|
|
|
|
outfile: str = output file
|
|
|
|
|
|
|
|
raises UnsupportedCodec if convert_format doesn't exist or if the codec doesn't
|
|
|
|
support conversion
|
|
|
|
"""
|
|
|
|
convert_format = convert_format or self._codec["convert_default_format"]
|
|
|
|
|
|
|
|
if convert_format is None or not any(
|
|
|
|
convert_format == item["copy_format"] for item in _codecs.values()
|
|
|
|
):
|
|
|
|
raise UnsupportedCodec(f"Unknown convert format: {convert_format}")
|
|
|
|
|
|
|
|
if not self._codec["convert"]:
|
|
|
|
raise UnsupportedCodec(
|
|
|
|
f"{self.codec_name} codec doesn't support conversion"
|
|
|
|
)
|
|
|
|
|
|
|
|
return ["-map", f"0:{self.index}", "-f", convert_format, outfile]
|
|
|
|
|
|
|
|
def copy_args(self, outfile):
|
|
|
|
"raises UnsupportedCodec if the codec doesn't support copy"
|
|
|
|
if not self._codec["copy"] or not self._codec["copy_format"]:
|
|
|
|
raise UnsupportedCodec(f"{self.codec_name} doesn't support copy")
|
|
|
|
|
|
|
|
return [
|
|
|
|
"-map",
|
|
|
|
f"0:{self.index}",
|
|
|
|
"-c:s",
|
|
|
|
"copy",
|
|
|
|
"-f",
|
|
|
|
self._codec["copy_format"],
|
|
|
|
outfile,
|
|
|
|
]
|
|
|
|
|
|
|
|
@property
|
|
|
|
def language(self):
|
|
|
|
# Legacy
|
|
|
|
return self.tags.language
|
|
|
|
|
|
|
|
@property
|
|
|
|
def extension(self):
|
|
|
|
return self._codec["copy_format"] or self._codec["convert_default_format"] or ""
|
|
|
|
|
|
|
|
@property
|
|
|
|
def convert_default_format(self):
|
|
|
|
return self._codec["convert_default_format"]
|
|
|
|
|
|
|
|
@property
|
|
|
|
def type(self):
|
|
|
|
return self._codec["type"]
|
|
|
|
|
|
|
|
@property
|
|
|
|
def suffix(self):
|
|
|
|
return ".".join(
|
|
|
|
item
|
|
|
|
for item in (self.tags.suffix, self.disposition.suffix, self.extension)
|
|
|
|
if item
|
|
|
|
)
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
return f"<{self.codec_name.upper()}: {self.tags}@{self.disposition}>"
|
|
|
|
|
|
|
|
|
|
|
|
_codecs = {
|
|
|
|
"ass": {
|
|
|
|
"type": "text",
|
|
|
|
"copy": True,
|
|
|
|
"copy_format": "ass",
|
|
|
|
"convert": True,
|
|
|
|
"convert_default_format": "srt",
|
|
|
|
},
|
|
|
|
"subrip": {
|
|
|
|
"type": "text",
|
|
|
|
"copy": True,
|
|
|
|
"copy_format": "srt",
|
|
|
|
"convert": True,
|
|
|
|
"convert_default_format": "srt",
|
|
|
|
},
|
|
|
|
"webvtt": {
|
|
|
|
"type": "text",
|
|
|
|
"copy": True,
|
|
|
|
"copy_format": "webvtt",
|
|
|
|
"convert": True,
|
|
|
|
"convert_default_format": "srt",
|
|
|
|
},
|
|
|
|
"mov_text": {
|
|
|
|
"type": "text",
|
|
|
|
"copy": False,
|
|
|
|
"copy_format": None,
|
|
|
|
"convert": True,
|
|
|
|
"convert_default_format": "srt",
|
|
|
|
},
|
|
|
|
"hdmv_pgs_subtitle": {
|
|
|
|
"type": "bitmap",
|
|
|
|
"copy": True,
|
|
|
|
"copy_format": "sup",
|
|
|
|
"convert": False,
|
|
|
|
"convert_default_format": None,
|
|
|
|
},
|
|
|
|
"dvb_subtitle": {
|
|
|
|
"type": "bitmap",
|
|
|
|
"copy": True,
|
|
|
|
"copy_format": "sup",
|
|
|
|
"convert": False,
|
|
|
|
"convert_default_format": None,
|
|
|
|
},
|
|
|
|
"dvd_subtitle": {
|
|
|
|
"type": "bitmap",
|
|
|
|
"copy": True,
|
|
|
|
"copy_format": "sup",
|
|
|
|
"convert": False,
|
|
|
|
"convert_default_format": None,
|
|
|
|
},
|
|
|
|
}
|