Even more linting: no more variable with camel case.
This commit is contained in:
295
removeads.py
295
removeads.py
@@ -53,7 +53,14 @@ from iso639.exceptions import InvalidLanguageValue
|
|||||||
# Then finally, change the Private Codec Data in the final MKV.
|
# Then finally, change the Private Codec Data in the final MKV.
|
||||||
|
|
||||||
|
|
||||||
def checkRequiredTools():
|
def checkRequiredTools() -> tuple[bool,list[str]]:
|
||||||
|
"""Check if required external tools are installed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[bool, list[str]] : does all optional tools are installed and the paths of all tools.
|
||||||
|
"""
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
all_optional_tools = True
|
all_optional_tools = True
|
||||||
paths = {}
|
paths = {}
|
||||||
@@ -76,7 +83,15 @@ def checkRequiredTools():
|
|||||||
|
|
||||||
return all_optional_tools, paths
|
return all_optional_tools, paths
|
||||||
|
|
||||||
def getTesseractSupportedLang(tesseract):
|
def getTesseractSupportedLang(tesseract:str) -> dict[str,str]|None:
|
||||||
|
"""Returns the set of natural languages supported by Tesseract OCR tool.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tesseract: str: path to tesseract binary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, str] : a mapping ....
|
||||||
|
"""
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
res = {}
|
res = {}
|
||||||
|
|
||||||
@@ -102,7 +117,7 @@ def getTesseractSupportedLang(tesseract):
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def getFrameRate(ffprobe, inputFile):
|
def getFrameRate(ffprobe:str, inputFile) -> float|None:
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
infd = inputFile.fileno()
|
infd = inputFile.fileno()
|
||||||
@@ -167,7 +182,7 @@ def getFrameRate(ffprobe, inputFile):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getSubTitlesTracks(ffprobe, mkvPath):
|
def getSubTitlesTracks(ffprobe:str, mkvPath: str) -> dict[str,str]|None:
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
tracks={}
|
tracks={}
|
||||||
|
|
||||||
@@ -199,7 +214,7 @@ def getSubTitlesTracks(ffprobe, mkvPath):
|
|||||||
|
|
||||||
return tracks
|
return tracks
|
||||||
|
|
||||||
def extractSRT(mkvextract, fileName, subtitles, langs):
|
def extractSRT(mkvextract:str, fileName:str, subtitles:str, langs:list[str]) -> list|None:
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
params = [mkvextract, fileName, 'tracks']
|
params = [mkvextract, fileName, 'tracks']
|
||||||
@@ -279,7 +294,7 @@ def doOCR(vobsubocr, idxs, duration, temporaries, dumpMemFD=False):
|
|||||||
write(srtfd, line.encode(encoding='UTF-8'))
|
write(srtfd, line.encode(encoding='UTF-8'))
|
||||||
|
|
||||||
m = re.match(timestamps, line)
|
m = re.match(timestamps, line)
|
||||||
if m!=None:
|
if m is not None:
|
||||||
hours = int(m.group('hours'))
|
hours = int(m.group('hours'))
|
||||||
minutes = int(m.group('hours'))
|
minutes = int(m.group('hours'))
|
||||||
seconds = int(m.group('seconds'))
|
seconds = int(m.group('seconds'))
|
||||||
@@ -499,11 +514,11 @@ def parseRBSPTrailingBits(buf, bit_position):
|
|||||||
|
|
||||||
bit_position, one = readBit(buf, bit_position)
|
bit_position, one = readBit(buf, bit_position)
|
||||||
if one==0:
|
if one==0:
|
||||||
raise Exception(f'Stop bit should be equal to one. Read: {one:d}')
|
raise ValueError(f'Stop bit should be equal to one. Read: {one:d}')
|
||||||
while bit_position%8 != 0:
|
while bit_position%8 != 0:
|
||||||
bit_position, zero = readBit(buf, bit_position)
|
bit_position, zero = readBit(buf, bit_position)
|
||||||
if zero==1:
|
if zero==1:
|
||||||
raise Exception('Trailing bit should be equal to zero')
|
raise ValueError('Trailing bit should be equal to zero')
|
||||||
|
|
||||||
return bit_position
|
return bit_position
|
||||||
|
|
||||||
@@ -534,7 +549,7 @@ def moreRBSPData(buf, bit_position):
|
|||||||
break
|
break
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
raise Exception('Impossible to find trailing stop bit !')
|
raise ValueError('Impossible to find trailing stop bit !')
|
||||||
|
|
||||||
# No more data
|
# No more data
|
||||||
if bit_position == pos:
|
if bit_position == pos:
|
||||||
@@ -888,20 +903,10 @@ class SPS:
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
x264opts = []
|
x264opts = []
|
||||||
|
|
||||||
if self.profile_idc in [ 0x42, 0x4D, 0x64, 0x6E, 0x7A, 0xF4, 0x2C]:
|
try:
|
||||||
if self.profile_idc == 0x42:
|
profile = {0x42:'baseline', 0x4D:'main', 0x64:'high', 0x6E:'high10', 0x7A:'high422',
|
||||||
profile = 'baseline'
|
0xF4:'high444'}[self.profile_idc]
|
||||||
elif self.profile_idc == 0x4D:
|
except KeyError:
|
||||||
profile = 'main'
|
|
||||||
elif self.profile_idc == 0x64 :
|
|
||||||
profile = 'high'
|
|
||||||
elif self.profile_idc == 0x6E:
|
|
||||||
profile = 'high10'
|
|
||||||
elif self.profile_idc == 0x7A:
|
|
||||||
profile = 'high422'
|
|
||||||
elif self.profile_idc == 0xF4:
|
|
||||||
profile = 'high444'
|
|
||||||
else:
|
|
||||||
logger.error('Unknow profile: %x', self.profile_idc)
|
logger.error('Unknow profile: %x', self.profile_idc)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@@ -942,13 +947,13 @@ class SPS:
|
|||||||
# NAL Unit SPS
|
# NAL Unit SPS
|
||||||
bit_position, zero = readBit(buf, bit_position)
|
bit_position, zero = readBit(buf, bit_position)
|
||||||
if zero != 0:
|
if zero != 0:
|
||||||
raise Exception(f'Reserved bit is not equal to 0: {zero:d}')
|
raise ValueError(f'Reserved bit is not equal to 0: {zero:d}')
|
||||||
bit_position, nal_ref_idc = readBits(buf, bit_position,2)
|
bit_position, nal_ref_idc = readBits(buf, bit_position,2)
|
||||||
if nal_ref_idc != 3:
|
if nal_ref_idc != 3:
|
||||||
raise Exception(f'NAL ref idc is not equal to 3: {nal_ref_idc:d}')
|
raise ValueError(f'NAL ref idc is not equal to 3: {nal_ref_idc:d}')
|
||||||
bit_position, nal_unit_type = readBits(buf, bit_position,5)
|
bit_position, nal_unit_type = readBits(buf, bit_position,5)
|
||||||
if nal_unit_type != 7:
|
if nal_unit_type != 7:
|
||||||
raise Exception(f'NAL unit type is not a SPS: {nal_unit_type:d}')
|
raise ValueError(f'NAL unit type is not a SPS: {nal_unit_type:d}')
|
||||||
|
|
||||||
bit_position, self.profile_idc = readByte(buf, bit_position)
|
bit_position, self.profile_idc = readByte(buf, bit_position)
|
||||||
bit_position, self.constraint_set0_flag = readBit(buf,bit_position)
|
bit_position, self.constraint_set0_flag = readBit(buf,bit_position)
|
||||||
@@ -959,7 +964,7 @@ class SPS:
|
|||||||
bit_position, self.constraint_set5_flag = readBit(buf,bit_position)
|
bit_position, self.constraint_set5_flag = readBit(buf,bit_position)
|
||||||
bit_position, v = readBits(buf, bit_position, 2)
|
bit_position, v = readBits(buf, bit_position, 2)
|
||||||
if v!=0:
|
if v!=0:
|
||||||
raise Exception(f'Reserved bits different from 0b00: {v:x}')
|
raise ValueError(f'Reserved bits different from 0b00: {v:x}')
|
||||||
bit_position, self.level_idc = readByte(buf, bit_position)
|
bit_position, self.level_idc = readByte(buf, bit_position)
|
||||||
bit_position, self.seq_parameter_set_id = readUnsignedExpGolomb(buf, bit_position)
|
bit_position, self.seq_parameter_set_id = readUnsignedExpGolomb(buf, bit_position)
|
||||||
if self.profile_idc in [44, 83, 86, 100, 110, 118, 122, 128, 134, 135, 138, 139, 244]:
|
if self.profile_idc in [44, 83, 86, 100, 110, 118, 122, 128, 134, 135, 138, 139, 244]:
|
||||||
@@ -1153,13 +1158,13 @@ class PPS:
|
|||||||
# NAL Unit PPS
|
# NAL Unit PPS
|
||||||
bit_position, zero = readBit(buf, bit_position)
|
bit_position, zero = readBit(buf, bit_position)
|
||||||
if zero != 0:
|
if zero != 0:
|
||||||
raise Exception(f'Reserved bit is not equal to 0: {zero:d}')
|
raise ValueError(f'Reserved bit is not equal to 0: {zero:d}')
|
||||||
bit_position, nal_ref_idc = readBits(buf, bit_position,2)
|
bit_position, nal_ref_idc = readBits(buf, bit_position,2)
|
||||||
if nal_ref_idc != 3:
|
if nal_ref_idc != 3:
|
||||||
raise Exception(f'NAL ref idc is not equal to 3: {nal_ref_idc:d}')
|
raise ValueError(f'NAL ref idc is not equal to 3: {nal_ref_idc:d}')
|
||||||
bit_position, nal_unit_type = readBits(buf, bit_position,5)
|
bit_position, nal_unit_type = readBits(buf, bit_position,5)
|
||||||
if nal_unit_type != 8:
|
if nal_unit_type != 8:
|
||||||
raise Exception(f'NAL unit type is not a PPS: {nal_unit_type:d}')
|
raise ValueError(f'NAL unit type is not a PPS: {nal_unit_type:d}')
|
||||||
|
|
||||||
bit_position, self.pic_parameter_set_id = readUnsignedExpGolomb(buf, bit_position)
|
bit_position, self.pic_parameter_set_id = readUnsignedExpGolomb(buf, bit_position)
|
||||||
bit_position, self.seq_parameter_set_id = readUnsignedExpGolomb(buf, bit_position)
|
bit_position, self.seq_parameter_set_id = readUnsignedExpGolomb(buf, bit_position)
|
||||||
@@ -1348,17 +1353,17 @@ class AVCDecoderConfiguration:
|
|||||||
bit_position, self.AVCLevelIndication = readByte(buf, bit_position)
|
bit_position, self.AVCLevelIndication = readByte(buf, bit_position)
|
||||||
bit_position, v = readBits(buf, bit_position, 6)
|
bit_position, v = readBits(buf, bit_position, 6)
|
||||||
if v != 0b111111:
|
if v != 0b111111:
|
||||||
raise Exception(f'Reserved bits are not equal to 0b111111: {v:x}')
|
raise ValueError(f'Reserved bits are not equal to 0b111111: {v:x}')
|
||||||
bit_position, self.lengthSizeMinusOne = readBits(buf, bit_position, 2)
|
bit_position, self.lengthSizeMinusOne = readBits(buf, bit_position, 2)
|
||||||
bit_position, v = readBits(buf, bit_position, 3)
|
bit_position, v = readBits(buf, bit_position, 3)
|
||||||
if v != 0b111:
|
if v != 0b111:
|
||||||
raise Exception(f'Reserved bits are not equal to 0b111: {v:x}')
|
raise ValueError(f'Reserved bits are not equal to 0b111: {v:x}')
|
||||||
bit_position, self.numOfSequenceParameterSets= readBits(buf, bit_position, 5)
|
bit_position, self.numOfSequenceParameterSets= readBits(buf, bit_position, 5)
|
||||||
logger.debug('Number of SPS: %d', self.numOfSequenceParameterSets)
|
logger.debug('Number of SPS: %d', self.numOfSequenceParameterSets)
|
||||||
for _ in range(0,self.numOfSequenceParameterSets):
|
for _ in range(0,self.numOfSequenceParameterSets):
|
||||||
bit_position, length = readWord(buf, bit_position)
|
bit_position, length = readWord(buf, bit_position)
|
||||||
if bit_position % 8 != 0:
|
if bit_position % 8 != 0:
|
||||||
raise Exception(f'SPS is not located at a byte boundary: {bit_position:d}')
|
raise ValueError(f'SPS is not located at a byte boundary: {bit_position:d}')
|
||||||
|
|
||||||
sps = SPS()
|
sps = SPS()
|
||||||
sodb = RBSP2SODB(buf[floor(bit_position/8):])
|
sodb = RBSP2SODB(buf[floor(bit_position/8):])
|
||||||
@@ -1381,7 +1386,7 @@ class AVCDecoderConfiguration:
|
|||||||
for _ in range(0,self.numOfPictureParameterSets):
|
for _ in range(0,self.numOfPictureParameterSets):
|
||||||
bit_position, length = readWord(buf, bit_position)
|
bit_position, length = readWord(buf, bit_position)
|
||||||
if bit_position % 8 != 0:
|
if bit_position % 8 != 0:
|
||||||
raise Exception('PPS is not located at a byte boundary: {bit_position:d}')
|
raise ValueError('PPS is not located at a byte boundary: {bit_position:d}')
|
||||||
|
|
||||||
pps = PPS()
|
pps = PPS()
|
||||||
sodb = RBSP2SODB(buf[floor(bit_position/8):])
|
sodb = RBSP2SODB(buf[floor(bit_position/8):])
|
||||||
@@ -1402,15 +1407,15 @@ class AVCDecoderConfiguration:
|
|||||||
if self.AVCProfileIndication in [100, 110, 122, 144]:
|
if self.AVCProfileIndication in [100, 110, 122, 144]:
|
||||||
bit_position, reserved = readBits(buf, bit_position, 6)
|
bit_position, reserved = readBits(buf, bit_position, 6)
|
||||||
if reserved != 0b111111:
|
if reserved != 0b111111:
|
||||||
raise Exception(f'Reserved bits are different from 111111: {reserved:x}')
|
raise ValueError(f'Reserved bits are different from 111111: {reserved:x}')
|
||||||
bit_position, self.chroma_format = readBits(buf, bit_position, 2)
|
bit_position, self.chroma_format = readBits(buf, bit_position, 2)
|
||||||
bit_position, reserved = readBits(buf, bit_position, 5)
|
bit_position, reserved = readBits(buf, bit_position, 5)
|
||||||
if reserved != 0b11111:
|
if reserved != 0b11111:
|
||||||
raise Exception(f'Reserved bits are different from 11111: {reserved:x}')
|
raise ValueError(f'Reserved bits are different from 11111: {reserved:x}')
|
||||||
bit_position, self.bit_depth_luma_minus8 = readBits(buf, bit_position, 3)
|
bit_position, self.bit_depth_luma_minus8 = readBits(buf, bit_position, 3)
|
||||||
bit_position, reserved = readBits(buf, bit_position, 5)
|
bit_position, reserved = readBits(buf, bit_position, 5)
|
||||||
if reserved != 0b11111:
|
if reserved != 0b11111:
|
||||||
raise Exception(f'Reserved bits are different from 11111: {reserved:x}')
|
raise ValueError(f'Reserved bits are different from 11111: {reserved:x}')
|
||||||
bit_position, self.bit_depth_chroma_minus8 = readBits(buf, bit_position, 3)
|
bit_position, self.bit_depth_chroma_minus8 = readBits(buf, bit_position, 3)
|
||||||
bit_position, self.numOfSequenceParameterSetExt = readByte(buf, bit_position)
|
bit_position, self.numOfSequenceParameterSetExt = readByte(buf, bit_position)
|
||||||
for _ in range(0, self.numOfSequenceParameterSetExt):
|
for _ in range(0, self.numOfSequenceParameterSetExt):
|
||||||
@@ -1482,28 +1487,28 @@ class AVCDecoderConfiguration:
|
|||||||
def merge(self, config):
|
def merge(self, config):
|
||||||
# Check config compatibility
|
# Check config compatibility
|
||||||
if self.configurationVersion != config.configurationVersion:
|
if self.configurationVersion != config.configurationVersion:
|
||||||
raise Exception('Configuration versions are different: %d vs %s' %\
|
raise ValueError('Configuration versions are different: %d vs %s' %\
|
||||||
(self.configurationVersion, config.configurationVersion))
|
(self.configurationVersion, config.configurationVersion))
|
||||||
if self.AVCProfileIndication != config.AVCProfileIndication:
|
if self.AVCProfileIndication != config.AVCProfileIndication:
|
||||||
raise Exception('AVC profiles are different: %d vs %s' %\
|
raise ValueError('AVC profiles are different: %d vs %s' %\
|
||||||
(self.AVCProfileIndication, config.AVCProfileIndication))
|
(self.AVCProfileIndication, config.AVCProfileIndication))
|
||||||
if self.profile_compatibility != config.profile_compatibility:
|
if self.profile_compatibility != config.profile_compatibility:
|
||||||
raise Exception('Profile compatilities are different: %d vs %s' %\
|
raise ValueError('Profile compatilities are different: %d vs %s' %\
|
||||||
(self.profile_compatibility, config.profile_compatibility))
|
(self.profile_compatibility, config.profile_compatibility))
|
||||||
if self.AVCLevelIndication != config.AVCLevelIndication:
|
if self.AVCLevelIndication != config.AVCLevelIndication:
|
||||||
raise Exception('Level indications are different: %d vs %s' %\
|
raise ValueError('Level indications are different: %d vs %s' %\
|
||||||
(self.AVCLevelIndication, config.AVCLevelIndication))
|
(self.AVCLevelIndication, config.AVCLevelIndication))
|
||||||
if self.lengthSizeMinusOne != config.lengthSizeMinusOne:
|
if self.lengthSizeMinusOne != config.lengthSizeMinusOne:
|
||||||
raise Exception('Length units are different: %d vs %s' %\
|
raise ValueError('Length units are different: %d vs %s' %\
|
||||||
(self.lengthSizeMinusOne, config.lengthSizeMinusOne))
|
(self.lengthSizeMinusOne, config.lengthSizeMinusOne))
|
||||||
if self.chroma_format != config.chroma_format:
|
if self.chroma_format != config.chroma_format:
|
||||||
raise Exception('Colour format are different: %d vs %s' %\
|
raise ValueError('Colour format are different: %d vs %s' %\
|
||||||
(self.chroma_format, config.chroma_format))
|
(self.chroma_format, config.chroma_format))
|
||||||
if self.bit_depth_luma_minus8 != config.bit_depth_luma_minus8:
|
if self.bit_depth_luma_minus8 != config.bit_depth_luma_minus8:
|
||||||
raise Exception('Depth of luminance are different: %d vs %s' %\
|
raise ValueError('Depth of luminance are different: %d vs %s' %\
|
||||||
(self.bit_depth_luma_minus8, config.bit_depth_luma_minus8))
|
(self.bit_depth_luma_minus8, config.bit_depth_luma_minus8))
|
||||||
if self.bit_depth_chroma_minus8 != config.bit_depth_chroma_minus8:
|
if self.bit_depth_chroma_minus8 != config.bit_depth_chroma_minus8:
|
||||||
raise Exception('Depth of chromaticity are different: %d vs %s' %\
|
raise ValueError('Depth of chromaticity are different: %d vs %s' %\
|
||||||
(self.bit_depth_chroma_minus8, config.bit_depth_luma_minus8))
|
(self.bit_depth_chroma_minus8, config.bit_depth_luma_minus8))
|
||||||
|
|
||||||
for spsid in config.sps:
|
for spsid in config.sps:
|
||||||
@@ -1511,7 +1516,7 @@ class AVCDecoderConfiguration:
|
|||||||
if spsid in self.sps:
|
if spsid in self.sps:
|
||||||
localsps = self.sps[spsid]
|
localsps = self.sps[spsid]
|
||||||
if sps!=localsps:
|
if sps!=localsps:
|
||||||
raise Exception(f'Profile are not compatible. They contain two different SPS\
|
raise ValueError(f'Profile are not compatible. They contain two different SPS\
|
||||||
with the same identifier ({spsid:d}): {localsps}\n{sps}\n')
|
with the same identifier ({spsid:d}): {localsps}\n{sps}\n')
|
||||||
self.sps[spsid] = sps
|
self.sps[spsid] = sps
|
||||||
|
|
||||||
@@ -1522,7 +1527,7 @@ class AVCDecoderConfiguration:
|
|||||||
if ppsid in self.pps:
|
if ppsid in self.pps:
|
||||||
localpps = self.pps[ppsid]
|
localpps = self.pps[ppsid]
|
||||||
if pps!=localpps:
|
if pps!=localpps:
|
||||||
raise Exception(f'Profile are not compatible. They contain two different PPS\
|
raise ValueError(f'Profile are not compatible. They contain two different PPS\
|
||||||
with the same identifier ({ppsid:d}): {localpps}\n{pps}\n')
|
with the same identifier ({ppsid:d}): {localpps}\n{pps}\n')
|
||||||
self.pps[ppsid] = pps
|
self.pps[ppsid] = pps
|
||||||
|
|
||||||
@@ -1532,12 +1537,12 @@ class AVCDecoderConfiguration:
|
|||||||
|
|
||||||
def parseCodecPrivate(codecPrivateData):
|
def parseCodecPrivate(codecPrivateData):
|
||||||
if codecPrivateData[0] != 0x63:
|
if codecPrivateData[0] != 0x63:
|
||||||
raise Exception(f'Matroska header is wrong: {codecPrivateData[0]:x}')
|
raise ValueError(f'Matroska header is wrong: {codecPrivateData[0]:x}')
|
||||||
if codecPrivateData[1] != 0xA2:
|
if codecPrivateData[1] != 0xA2:
|
||||||
raise Exception(f'Matroska header is wrong: {codecPrivateData[1]:x}')
|
raise ValueError(f'Matroska header is wrong: {codecPrivateData[1]:x}')
|
||||||
length = codecPrivateData[2]
|
length = codecPrivateData[2]
|
||||||
if length == 0:
|
if length == 0:
|
||||||
raise Exception('Matroska length cannot start with zero byte.')
|
raise ValueError('Matroska length cannot start with zero byte.')
|
||||||
for nb_zeroes in range(0,8):
|
for nb_zeroes in range(0,8):
|
||||||
b = readBit(codecPrivateData[2:], nb_zeroes)
|
b = readBit(codecPrivateData[2:], nb_zeroes)
|
||||||
if b != 0:
|
if b != 0:
|
||||||
@@ -1563,14 +1568,14 @@ def getAvcConfigFromH264(inputFile):
|
|||||||
bit_position = 0
|
bit_position = 0
|
||||||
bit_position, start_code = readLong(sodb, bit_position)
|
bit_position, start_code = readLong(sodb, bit_position)
|
||||||
if start_code != 1:
|
if start_code != 1:
|
||||||
raise Exception(f'Starting code not detected: {start_code:x}')
|
raise ValueError(f'Starting code not detected: {start_code:x}')
|
||||||
sps = SPS()
|
sps = SPS()
|
||||||
bit_length = sps.fromBytes(sodb[4:])
|
bit_length = sps.fromBytes(sodb[4:])
|
||||||
bit_position+=bit_length
|
bit_position+=bit_length
|
||||||
|
|
||||||
bit_position, start_code = readLong(sodb, bit_position)
|
bit_position, start_code = readLong(sodb, bit_position)
|
||||||
if start_code != 1:
|
if start_code != 1:
|
||||||
raise Exception('Starting code not detected: {start_code:x}')
|
raise ValueError(f'Starting code not detected: {start_code:x}')
|
||||||
pps = PPS()
|
pps = PPS()
|
||||||
bit_length = pps.fromBytes(sodb[floor(bit_position/8):], sps.chroma_format_idc)
|
bit_length = pps.fromBytes(sodb[floor(bit_position/8):], sps.chroma_format_idc)
|
||||||
logger.debug(pps)
|
logger.debug(pps)
|
||||||
@@ -1625,7 +1630,7 @@ def parseMKVTree(mkvinfo, inputFile):
|
|||||||
else:
|
else:
|
||||||
position = int(m.group('position'))
|
position = int(m.group('position'))
|
||||||
size = int(m.group('size'))
|
size = int(m.group('size'))
|
||||||
root = m.group('root')!=None
|
root = m.group('root') is not None
|
||||||
if root:
|
if root:
|
||||||
depth = 0
|
depth = 0
|
||||||
else:
|
else:
|
||||||
@@ -2490,18 +2495,17 @@ def dumpPPM(pictures, prefix, temporaries):
|
|||||||
|
|
||||||
header_len=2+1+ceil(log(width, 10))+1+ceil(log(height, 10))+1+3+1
|
header_len=2+1+ceil(log(width, 10))+1+ceil(log(height, 10))+1+3+1
|
||||||
try:
|
try:
|
||||||
out = open(filename, 'w', encoding='utf8')
|
with open(filename, 'w', encoding='utf8') as out:
|
||||||
outfd = out.fileno()
|
temporaries.append(out)
|
||||||
|
outfd = out.fileno()
|
||||||
|
length=header_len+3*width*height
|
||||||
|
nb_bytes = 0
|
||||||
|
while nb_bytes < length:
|
||||||
|
nb_bytes+=write(outfd, pictures[pos+nb_bytes:pos+length])
|
||||||
|
pos+=length
|
||||||
|
picture+=1
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.error('Impossible to create file: %s', filename)
|
logger.error('Impossible to create file: %s', filename)
|
||||||
temporaries.append(out)
|
|
||||||
|
|
||||||
length=header_len+3*width*height
|
|
||||||
nb_bytes = 0
|
|
||||||
while nb_bytes < length:
|
|
||||||
nb_bytes+=write(outfd, pictures[pos+nb_bytes:pos+length])
|
|
||||||
pos+=length
|
|
||||||
picture+=1
|
|
||||||
|
|
||||||
|
|
||||||
def extractAllStreams(ffmpeg, ffprobe, inputFile, begin, end, streams, filesPrefix, nbFrames,
|
def extractAllStreams(ffmpeg, ffprobe, inputFile, begin, end, streams, filesPrefix, nbFrames,
|
||||||
@@ -2629,17 +2633,16 @@ def extractAllStreams(ffmpeg, ffprobe, inputFile, begin, end, streams, filesPref
|
|||||||
|
|
||||||
if dumpMemFD:
|
if dumpMemFD:
|
||||||
try:
|
try:
|
||||||
output = open(tmpname,'w', encoding='utf8')
|
with open(tmpname,'w', encoding='utf8') as output:
|
||||||
|
temporaries.append(output)
|
||||||
|
outfd = output.fileno()
|
||||||
|
pos = 0
|
||||||
|
while pos < len(sound_bytes):
|
||||||
|
pos+=write(outfd, sound_bytes[pos:])
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.error('Impossible to create file: %s', tmpname)
|
logger.error('Impossible to create file: %s', tmpname)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
outfd = output.fileno()
|
|
||||||
pos = 0
|
|
||||||
while pos < len(sound_bytes):
|
|
||||||
pos+=write(outfd, sound_bytes[pos:])
|
|
||||||
temporaries.append(output)
|
|
||||||
|
|
||||||
# We rewind to zero the memory file descriptor
|
# We rewind to zero the memory file descriptor
|
||||||
lseek(memfd, 0, SEEK_SET)
|
lseek(memfd, 0, SEEK_SET)
|
||||||
set_inheritable(memfd, True)
|
set_inheritable(memfd, True)
|
||||||
@@ -3351,65 +3354,65 @@ def main():
|
|||||||
|
|
||||||
# Creating MKV file that corresponds to current part between I-frames
|
# Creating MKV file that corresponds to current part between I-frames
|
||||||
# Internal video with all streams (video, audio and subtitles)
|
# Internal video with all streams (video, audio and subtitles)
|
||||||
internalMKVName = f'part-{partnum:d}-internal.mkv'
|
internal_mkv_name = f'part-{partnum:d}-internal.mkv'
|
||||||
# Internal video stream as a raw H264 stream
|
# Internal video stream as a raw H264 stream
|
||||||
internalH264Name = f'part-{partnum:d}-internal.h264'
|
internal_h264_name = f'part-{partnum:d}-internal.h264'
|
||||||
# Internal video timestamps
|
# Internal video timestamps
|
||||||
internalH264TSName = f'part-{partnum:d}-internal-ts.txt'
|
internal_h264_ts_name = f'part-{partnum:d}-internal-ts.txt'
|
||||||
# Internal video with only audio and subtitles streams
|
# Internal video with only audio and subtitles streams
|
||||||
internalNoVideoMKVName = f'part-{partnum:d}-internal-novideo.mkv'
|
internal_novideo_mkv_name = f'part-{partnum:d}-internal-novideo.mkv'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
internalMKV = open(internalMKVName, 'w+', encoding='utf8')
|
internal_mkv = open(internal_mkv_name, 'w+', encoding='utf8')
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.error('Impossible to create file: %s', internalMKVName)
|
logger.error('Impossible to create file: %s', internal_mkv_name)
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
internalNoVideoMKV = open(internalNoVideoMKVName, 'w+', encoding='utf8')
|
internal_novideo_mkv = open(internal_novideo_mkv_name, 'w+', encoding='utf8')
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.error('Impossible to create file: %s', internalNoVideoMKVName)
|
logger.error('Impossible to create file: %s', internal_novideo_mkv_name)
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
internalH264 = open(internalH264Name, 'w+', encoding='utf8')
|
internal_h264 = open(internal_h264_name, 'w+', encoding='utf8')
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.error('Impossible to create file: %s', internalH264Name)
|
logger.error('Impossible to create file: %s', internal_h264_name)
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
internalH264TS = open(internalH264TSName, 'w+', encoding='utf8')
|
internal_h264_ts = open(internal_h264_ts_name, 'w+', encoding='utf8')
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.error('Impossible to create file: %s', internalH264TSName)
|
logger.error('Impossible to create file: %s', internal_h264_ts_name)
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
# logger.info('Merge header, middle and trailer subpart into: %s' % internalMKVName)
|
# logger.info('Merge header, middle and trailer subpart into: %s' % internal_mkv_name)
|
||||||
# Extract internal part of MKV
|
# Extract internal part of MKV
|
||||||
extractMKVPart(mkvmerge=paths['mkvmerge'], inputFile=mkv, outputFile=internalMKV,
|
extractMKVPart(mkvmerge=paths['mkvmerge'], inputFile=mkv, outputFile=internal_mkv,
|
||||||
begin=head_iframe_ts, end=tail_iframe_ts)
|
begin=head_iframe_ts, end=tail_iframe_ts)
|
||||||
|
|
||||||
# Extract video stream of internal part as a raw H264 and its timestamps.
|
# Extract video stream of internal part as a raw H264 and its timestamps.
|
||||||
logger.info('Extract video track as raw H264 file.')
|
logger.info('Extract video track as raw H264 file.')
|
||||||
extractTrackFromMKV(mkvextract=paths['mkvextract'], inputFile=internalMKV, index=0,
|
extractTrackFromMKV(mkvextract=paths['mkvextract'], inputFile=internal_mkv, index=0,
|
||||||
outputFile=internalH264, timestamps=internalH264TS)
|
outputFile=internal_h264, timestamps=internal_h264_ts)
|
||||||
|
|
||||||
# Remove video track from internal part of MKV
|
# Remove video track from internal part of MKV
|
||||||
logger.info('Remove video track from %s', internalMKVName)
|
logger.info('Remove video track from %s', internal_mkv_name)
|
||||||
removeVideoTracksFromMKV(mkvmerge=paths['mkvmerge'], inputFile=internalMKV,
|
removeVideoTracksFromMKV(mkvmerge=paths['mkvmerge'], inputFile=internal_mkv,
|
||||||
outputFile=internalNoVideoMKV)
|
outputFile=internal_novideo_mkv)
|
||||||
|
|
||||||
temporaries.append(internalMKV)
|
temporaries.append(internal_mkv)
|
||||||
temporaries.append(internalH264)
|
temporaries.append(internal_h264)
|
||||||
temporaries.append(internalH264TS)
|
temporaries.append(internal_h264_ts)
|
||||||
temporaries.append(internalNoVideoMKV)
|
temporaries.append(internal_novideo_mkv)
|
||||||
|
|
||||||
h264parts.append(internalH264)
|
h264parts.append(internal_h264)
|
||||||
h264_ts.append(internalH264TS)
|
h264_ts.append(internal_h264_ts)
|
||||||
subparts.append(internalNoVideoMKV)
|
subparts.append(internal_novideo_mkv)
|
||||||
|
|
||||||
if (not args.coarse) and (nb_tail_frames > args.threshold):
|
if (not args.coarse) and (nb_tail_frames > args.threshold):
|
||||||
# We extract all frames between the I-frame (including it) upto the end.
|
# We extract all frames between the I-frame (including it) upto the end.
|
||||||
h264Tail, h264TailTS, mkvTail = extractAllStreams(ffmpeg=paths['ffmpeg'],
|
h264_tail, h264_tail_ts, mkv_tail = extractAllStreams(ffmpeg=paths['ffmpeg'],
|
||||||
ffprobe=paths['ffprobe'],
|
ffprobe=paths['ffprobe'],
|
||||||
inputFile=mkv, begin=tail_iframe_ts,
|
inputFile=mkv, begin=tail_iframe_ts,
|
||||||
end=ts2, nbFrames=nb_tail_frames,
|
end=ts2, nbFrames=nb_tail_frames,
|
||||||
@@ -3420,14 +3423,14 @@ def main():
|
|||||||
temporaries=temporaries,
|
temporaries=temporaries,
|
||||||
dumpMemFD=args.dump)
|
dumpMemFD=args.dump)
|
||||||
|
|
||||||
if mkvTail is not None:
|
if mkv_tail is not None:
|
||||||
subparts.append(mkvTail)
|
subparts.append(mkv_tail)
|
||||||
if h264Tail is not None:
|
if h264_tail is not None:
|
||||||
avcconfig = getAvcConfigFromH264(h264Tail)
|
avcconfig = getAvcConfigFromH264(h264_tail)
|
||||||
other_avc_configs.append(avcconfig)
|
other_avc_configs.append(avcconfig)
|
||||||
h264parts.append(h264Tail)
|
h264parts.append(h264_tail)
|
||||||
if h264TailTS is not None:
|
if h264_tail_ts is not None:
|
||||||
h264_ts.append(h264TailTS)
|
h264_ts.append(h264_tail_ts)
|
||||||
|
|
||||||
logger.info('Merging MKV: %s', subparts)
|
logger.info('Merging MKV: %s', subparts)
|
||||||
part = mergeMKVs(mkvmerge=paths['mkvmerge'], inputs=subparts,
|
part = mergeMKVs(mkvmerge=paths['mkvmerge'], inputs=subparts,
|
||||||
@@ -3441,77 +3444,77 @@ def main():
|
|||||||
checks.append(pos)
|
checks.append(pos)
|
||||||
|
|
||||||
# When using coarse option there is a single AVC configuration.
|
# When using coarse option there is a single AVC configuration.
|
||||||
for avcConfig in other_avc_configs:
|
for avc_config in other_avc_configs:
|
||||||
main_avc_config.merge(avcConfig)
|
main_avc_config.merge(avc_config)
|
||||||
logger.debug('Merged AVC configuration: %s', main_avc_config)
|
logger.debug('Merged AVC configuration: %s', main_avc_config)
|
||||||
|
|
||||||
nbMKVParts = len(mkvparts)
|
nb_mkv_parts = len(mkvparts)
|
||||||
if nbMKVParts > 0:
|
if nb_mkv_parts > 0:
|
||||||
try:
|
try:
|
||||||
fullH264 = open(f'{basename}-full.h264', 'w+', encoding='utf8')
|
full_h264 = open(f'{basename}-full.h264', 'w+', encoding='utf8')
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.error('Impossible to create file full H264 stream.')
|
logger.error('Impossible to create file full H264 stream.')
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
logger.info('Merging all H264 tracks')
|
logger.info('Merging all H264 tracks')
|
||||||
concatenateH264Parts(h264parts=h264parts, output=fullH264)
|
concatenateH264Parts(h264parts=h264parts, output=full_h264)
|
||||||
temporaries.append(fullH264)
|
temporaries.append(full_h264)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fullH264TS = open(f'{basename}-ts.txt', 'w+', encoding='utf8')
|
full_h264_ts = open(f'{basename}-ts.txt', 'w+', encoding='utf8')
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.error('Impossible to create file containing all video timestamps.')
|
logger.error('Impossible to create file containing all video timestamps.')
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
logger.info('Merging H264 timestamps')
|
logger.info('Merging H264 timestamps')
|
||||||
concatenateH264TSParts(h264TSParts=h264_ts, output=fullH264TS)
|
concatenateH264TSParts(h264TSParts=h264_ts, output=full_h264_ts)
|
||||||
temporaries.append(fullH264TS)
|
temporaries.append(full_h264_ts)
|
||||||
|
|
||||||
finalNoVideoName = f'{basename}-novideo.mkv'
|
final_novideo_name = f'{basename}-novideo.mkv'
|
||||||
finalWithVideoName = f'{basename}-video.mkv'
|
final_with_video_name = f'{basename}-video.mkv'
|
||||||
|
|
||||||
if nbMKVParts > 1:
|
if nb_mkv_parts > 1:
|
||||||
logger.info('Merging all audio and subtitles parts: %s', mkvparts)
|
logger.info('Merging all audio and subtitles parts: %s', mkvparts)
|
||||||
mergeMKVs(mkvmerge=paths['mkvmerge'], inputs=mkvparts, outputName=finalNoVideoName,
|
mergeMKVs(mkvmerge=paths['mkvmerge'], inputs=mkvparts, outputName=final_novideo_name,
|
||||||
concatenate=True)
|
concatenate=True)
|
||||||
elif nbMKVParts == 1:
|
elif nb_mkv_parts == 1:
|
||||||
copyfile('part-1.mkv', finalNoVideoName)
|
copyfile('part-1.mkv', final_novideo_name)
|
||||||
else:
|
else:
|
||||||
logger.info("Nothing else to do.")
|
logger.info("Nothing else to do.")
|
||||||
copyfile(mkvfilename, finalWithVideoName)
|
copyfile(mkvfilename, final_with_video_name)
|
||||||
|
|
||||||
if nbMKVParts >=1 :
|
if nb_mkv_parts >=1 :
|
||||||
try:
|
try:
|
||||||
finalNoVideo = open(finalNoVideoName, 'r', encoding='utf8')
|
final_novideo = open(final_novideo_name, 'r', encoding='utf8')
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.error('Impossible to open file: %s.', finalNoVideoName)
|
logger.error('Impossible to open file: %s.', final_novideo_name)
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
temporaries.append(finalNoVideo)
|
temporaries.append(final_novideo)
|
||||||
|
|
||||||
fullH264TS.seek(0)
|
full_h264_ts.seek(0)
|
||||||
|
|
||||||
logger.info('Merging final video track and all other tracks together')
|
logger.info('Merging final video track and all other tracks together')
|
||||||
finalWithVideo = mergeMKVs(mkvmerge=paths['mkvmerge'], inputs=[fullH264, finalNoVideo],
|
final_with_video = mergeMKVs(mkvmerge=paths['mkvmerge'], inputs=[full_h264, final_novideo],
|
||||||
outputName=finalWithVideoName, concatenate=False,
|
outputName=final_with_video_name, concatenate=False,
|
||||||
timestamps={0: fullH264TS})
|
timestamps={0: full_h264_ts})
|
||||||
finalCodecPrivateData = dumpCodecPrivateData(main_avc_config)
|
final_codec_private_data = dumpCodecPrivateData(main_avc_config)
|
||||||
logger.debug('Final codec private data: %s', hexdump.dump(finalCodecPrivateData, sep=':'))
|
logger.debug('Final codec private data: %s', hexdump.dump(final_codec_private_data, sep=':'))
|
||||||
logger.info('Changing codec private data with the new one.')
|
logger.info('Changing codec private data with the new one.')
|
||||||
changeCodecPrivateData(paths['mkvinfo'], finalWithVideo, finalCodecPrivateData)
|
changeCodecPrivateData(paths['mkvinfo'], final_with_video, final_codec_private_data)
|
||||||
|
|
||||||
if args.srt:
|
if args.srt:
|
||||||
if not all_optional_tools:
|
if not all_optional_tools:
|
||||||
logger.warning("Missing tools for extracting subtitles.")
|
logger.warning("Missing tools for extracting subtitles.")
|
||||||
move(finalWithVideoName, args.outputFile)
|
move(final_with_video_name, args.outputFile)
|
||||||
else:
|
else:
|
||||||
# Final cut is not any more the final step.
|
# Final cut is not any more the final step.
|
||||||
temporaries.append(finalWithVideo)
|
temporaries.append(final_with_video)
|
||||||
duration = getMovieDuration(paths['ffprobe'], finalWithVideo)
|
duration = getMovieDuration(paths['ffprobe'], final_with_video)
|
||||||
supportedLangs = getTesseractSupportedLang(paths['tesseract'])
|
supported_langs = getTesseractSupportedLang(paths['tesseract'])
|
||||||
logger.info('Supported lang: %s', supportedLangs)
|
logger.info('Supported lang: %s', supported_langs)
|
||||||
logger.info('Find subtitles tracks and language.')
|
logger.info('Find subtitles tracks and language.')
|
||||||
subtitles = findSubtitlesTracks(paths['ffprobe'], finalWithVideo)
|
subtitles = findSubtitlesTracks(paths['ffprobe'], final_with_video)
|
||||||
logger.info(subtitles)
|
logger.info(subtitles)
|
||||||
sts = {}
|
sts = {}
|
||||||
for subtitle in subtitles:
|
for subtitle in subtitles:
|
||||||
@@ -3532,10 +3535,10 @@ def main():
|
|||||||
|
|
||||||
logger.info(sts)
|
logger.info(sts)
|
||||||
if len(sts) > 0:
|
if len(sts) > 0:
|
||||||
listOfSubtitles = extractSRT(paths['mkvextract'], finalWithVideoName, sts,
|
list_of_subtitles = extractSRT(paths['mkvextract'], final_with_video_name, sts,
|
||||||
supportedLangs)
|
supported_langs)
|
||||||
logger.info(listOfSubtitles)
|
logger.info(list_of_subtitles)
|
||||||
for idx_name, sub_name, _, _ in listOfSubtitles:
|
for idx_name, sub_name, _, _ in list_of_subtitles:
|
||||||
try:
|
try:
|
||||||
idx = open(idx_name,'r', encoding='utf8')
|
idx = open(idx_name,'r', encoding='utf8')
|
||||||
except IOError:
|
except IOError:
|
||||||
@@ -3550,15 +3553,15 @@ def main():
|
|||||||
temporaries.append(idx)
|
temporaries.append(idx)
|
||||||
temporaries.append(sub)
|
temporaries.append(sub)
|
||||||
|
|
||||||
ocr = doOCR(paths['vobsubocr'], listOfSubtitles, duration, temporaries, args.dump)
|
ocr = doOCR(paths['vobsubocr'], list_of_subtitles, duration, temporaries, args.dump)
|
||||||
logger.info(ocr)
|
logger.info(ocr)
|
||||||
|
|
||||||
# Remux SRT subtitles
|
# Remux SRT subtitles
|
||||||
remuxSRTSubtitles(paths['mkvmerge'], finalWithVideo, args.outputFile, ocr)
|
remuxSRTSubtitles(paths['mkvmerge'], final_with_video, args.outputFile, ocr)
|
||||||
else:
|
else:
|
||||||
copyfile(finalWithVideoName, args.outputFile)
|
copyfile(final_with_video_name, args.outputFile)
|
||||||
else:
|
else:
|
||||||
move(finalWithVideoName, args.outputFile)
|
move(final_with_video_name, args.outputFile)
|
||||||
|
|
||||||
if not args.keep:
|
if not args.keep:
|
||||||
logger.info("Cleaning temporary files")
|
logger.info("Cleaning temporary files")
|
||||||
|
|||||||
Reference in New Issue
Block a user