Compare commits
	
		
			2 Commits
		
	
	
		
			efceec0e48
			...
			926ee16433
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 926ee16433 | ||
|  | 489435a87f | 
							
								
								
									
										239
									
								
								removeads.py
									
									
									
									
									
								
							
							
						
						
									
										239
									
								
								removeads.py
									
									
									
									
									
								
							| @@ -1,9 +1,10 @@ | |||||||
| #!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||||
|  | '''A module to remove parts of video (.e.g advertisements) with single frame precision.''' | ||||||
|  |  | ||||||
| import argparse | import argparse | ||||||
| import re | import re | ||||||
| from sys import exit | from sys import exit | ||||||
| from datetime import datetime,timedelta,time | from datetime import datetime,timedelta | ||||||
| import coloredlogs, logging | import coloredlogs, logging | ||||||
| from functools import cmp_to_key | from functools import cmp_to_key | ||||||
| from subprocess import Popen, PIPE | from subprocess import Popen, PIPE | ||||||
| @@ -35,7 +36,7 @@ from dataclasses import dataclass, field | |||||||
| # Concatenate all raw H264 in a giant one (like cat), and the same for timestamps of video frames (to keep | # Concatenate all raw H264 in a giant one (like cat), and the same for timestamps of video frames (to keep | ||||||
| # sound and video synchronized). | # sound and video synchronized). | ||||||
| # Then use mkvmerge to remux the H264 track and the rest of tracks. | # Then use mkvmerge to remux the H264 track and the rest of tracks. | ||||||
| # MKVmerge concatenate is able to concatenate different SPS/PPS data into a bigger Private Codec Data. | # MKVmerge "concatenate" subcommand is able to concatenate different SPS/PPS data into a bigger Private Codec Data. | ||||||
| # However, this is proved to be not reliable. Sometimes it results in a AVC context containing a single SPS/PPS. | # However, this is proved to be not reliable. Sometimes it results in a AVC context containing a single SPS/PPS. | ||||||
| # So we have to rely on a manual parsing of the H264 AVC context of original movie | # So we have to rely on a manual parsing of the H264 AVC context of original movie | ||||||
| # and the ones produced for headers and trailers, and then merging them into a bigger AVC context. | # and the ones produced for headers and trailers, and then merging them into a bigger AVC context. | ||||||
| @@ -50,15 +51,15 @@ def checkRequiredTools(): | |||||||
|     optional = ['mkvextract', 'vobsubocr','tesseract'] |     optional = ['mkvextract', 'vobsubocr','tesseract'] | ||||||
|     for tool in required: |     for tool in required: | ||||||
|         path = which(tool) |         path = which(tool) | ||||||
|         if  path == None: |         if  path is None: | ||||||
|             logger.error('Required tool: %s is missing.' % tool) |             logger.error('Required tool: %s is missing.',tool) | ||||||
|             exit(-1) |             exit(-1) | ||||||
|         else: |         else: | ||||||
|             paths[tool] = path |             paths[tool] = path | ||||||
|     for tool in optional: |     for tool in optional: | ||||||
|         path = which(tool) |         path = which(tool) | ||||||
|         if path == None: |         if path is None: | ||||||
|             logger.info('Optional tool: %s is missing.' % tool) |             logger.info('Optional tool: %s is missing.',tool) | ||||||
|             allOptionalTools = False |             allOptionalTools = False | ||||||
|         else: |         else: | ||||||
|             paths[tool] = path |             paths[tool] = path | ||||||
| @@ -74,7 +75,7 @@ def getTesseractSupportedLang(tesseract): | |||||||
|             line = line.decode('utf8') |             line = line.decode('utf8') | ||||||
|             p = re.compile('(?P<lang>[a-z]{3})\n') |             p = re.compile('(?P<lang>[a-z]{3})\n') | ||||||
|             m = re.match(p,line) |             m = re.match(p,line) | ||||||
|             if m != None: |             if m is not None: | ||||||
|                 try: |                 try: | ||||||
|                     lang = m.group('lang') |                     lang = m.group('lang') | ||||||
|                     key = Lang(lang) |                     key = Lang(lang) | ||||||
| @@ -85,7 +86,7 @@ def getTesseractSupportedLang(tesseract): | |||||||
|     tesseract.wait() |     tesseract.wait() | ||||||
|  |  | ||||||
|     if tesseract.returncode != 0: |     if tesseract.returncode != 0: | ||||||
|         logger.error("Tesseract returns an error code: %d" % tesseract.returncode) |         logger.error("Tesseract returns an error code: %d",tesseract.returncode) | ||||||
|         return None |         return None | ||||||
|  |  | ||||||
|     return res |     return res | ||||||
| @@ -105,7 +106,8 @@ def getFrameRate(ffprobe, inputFile): | |||||||
|     maxTs = None |     maxTs = None | ||||||
|     interlaced = False |     interlaced = False | ||||||
|      |      | ||||||
|     params = [ffprobe, '-loglevel', 'quiet', '-select_streams', 'v', '-show_frames', '-read_intervals', '00%+30', '-of', 'json', '/proc/self/fd/%d' % infd] |     params = [ffprobe, '-loglevel', 'quiet', '-select_streams', 'v', '-show_frames', | ||||||
|  |             '-read_intervals', '00%+30', '-of', 'json', '/proc/self/fd/%d' % infd] | ||||||
|     env = {**os.environ, 'LANG': 'C'} |     env = {**os.environ, 'LANG': 'C'} | ||||||
|     with Popen(params, stdout=PIPE, close_fds=False, env=env) as ffprobe: |     with Popen(params, stdout=PIPE, close_fds=False, env=env) as ffprobe: | ||||||
|         out, _ = ffprobe.communicate() |         out, _ = ffprobe.communicate() | ||||||
| @@ -117,9 +119,9 @@ def getFrameRate(ffprobe, inputFile): | |||||||
|                         interlaced = True |                         interlaced = True | ||||||
|                 if 'pts_time' in frame: |                 if 'pts_time' in frame: | ||||||
|                     ts = float(frame['pts_time']) |                     ts = float(frame['pts_time']) | ||||||
|                     if minTs == None: |                     if minTs is None: | ||||||
|                         minTs = ts |                         minTs = ts | ||||||
|                     if maxTs == None: |                     if maxTs is None: | ||||||
|                         maxTs = ts |                         maxTs = ts | ||||||
|                     if ts < minTs: |                     if ts < minTs: | ||||||
|                         minTs = ts |                         minTs = ts | ||||||
| @@ -135,7 +137,7 @@ def getFrameRate(ffprobe, inputFile): | |||||||
|     ffprobe.wait() |     ffprobe.wait() | ||||||
|      |      | ||||||
|     if ffprobe.returncode != 0: |     if ffprobe.returncode != 0: | ||||||
|         logger.error("ffprobe returns an error code: %d" % ffprobe.returncode) |         logger.error("ffprobe returns an error code: %d", ffprobe.returncode) | ||||||
|         return None |         return None | ||||||
|      |      | ||||||
|     frameRate1 = nbFrames1/(maxTs-minTs) |     frameRate1 = nbFrames1/(maxTs-minTs) | ||||||
| @@ -143,12 +145,12 @@ def getFrameRate(ffprobe, inputFile): | |||||||
|  |  | ||||||
|     if abs(frameRate1 - frameRate2) > 0.2: |     if abs(frameRate1 - frameRate2) > 0.2: | ||||||
|         if not interlaced: |         if not interlaced: | ||||||
|             logger.error('Video is not interlaced and the disperancy between frame rates is too big: %f / %f' % (frameRate1, frameRate2)) |             logger.error('Video is not interlaced and the disperancy between frame rates is too big: %f / %f', frameRate1, frameRate2) | ||||||
|             return None |             return None | ||||||
|         if abs(frameRate1*2 - frameRate2) < 0.2: |         if abs(frameRate1*2 - frameRate2) < 0.2: | ||||||
|             return frameRate2/2 |             return frameRate2/2 | ||||||
|         else: |         else: | ||||||
|             logger.error('Video is interlaced and the disperancy between frame rates is too big: %f / %f' % (frameRate1, frameRate2)) |             logger.error('Video is interlaced and the disperancy between frame rates is too big: %f / %f', frameRate1, frameRate2) | ||||||
|             return None |             return None | ||||||
|     else: |     else: | ||||||
|         return frameRate2 |         return frameRate2 | ||||||
| @@ -160,7 +162,8 @@ def getSubTitlesTracks(ffprobe, mkvPath): | |||||||
|     tracks={} |     tracks={} | ||||||
|  |  | ||||||
|     nbSubTitles = 0 |     nbSubTitles = 0 | ||||||
|     with Popen([ffprobe, '-loglevel', 'quiet', '-select_streams', 's', '-show_entries', 'stream=index,codec_name:stream_tags=language', '-of', 'json', mkvPath], stdout=PIPE) as ffprobe: |     with Popen([ffprobe, '-loglevel', 'quiet', '-select_streams', 's', '-show_entries', | ||||||
|  |                 'stream=index,codec_name:stream_tags=language', '-of', 'json', mkvPath], stdout=PIPE) as ffprobe: | ||||||
|         out, _ = ffprobe.communicate() |         out, _ = ffprobe.communicate() | ||||||
|         out = json.load(BytesIO(out)) |         out = json.load(BytesIO(out)) | ||||||
|         if 'streams' in out: |         if 'streams' in out: | ||||||
| @@ -170,10 +173,10 @@ def getSubTitlesTracks(ffprobe, mkvPath): | |||||||
|                 lang = stream['tags']['language'] |                 lang = stream['tags']['language'] | ||||||
|                 if codec == 'dvd_subtitle': |                 if codec == 'dvd_subtitle': | ||||||
|                     if lang not in tracks: |                     if lang not in tracks: | ||||||
|                         tracks[lang] = [track] |                         tracks[lang] = [index] | ||||||
|                     else: |                     else: | ||||||
|                         l = tracks[lang] |                         l = tracks[lang] | ||||||
|                         l.append(track) |                         l.append(index) | ||||||
|                         tracks[lang] = l   |                         tracks[lang] = l   | ||||||
|         else: |         else: | ||||||
|             return None |             return None | ||||||
| @@ -181,7 +184,7 @@ def getSubTitlesTracks(ffprobe, mkvPath): | |||||||
|     ffprobe.wait() |     ffprobe.wait() | ||||||
|      |      | ||||||
|     if ffprobe.returncode != 0: |     if ffprobe.returncode != 0: | ||||||
|         logger.error("ffprobe returns an error code: %d" % ffprobe.returncode) |         logger.error("ffprobe returns an error code: %d", ffprobe.returncode) | ||||||
|         return None |         return None | ||||||
|      |      | ||||||
|     return tracks |     return tracks | ||||||
| @@ -199,7 +202,7 @@ def extractSRT(mkvextract, fileName, subtitles, langs): | |||||||
|         if iso in langs: |         if iso in langs: | ||||||
|             ocrlang = langs[iso] |             ocrlang = langs[iso] | ||||||
|         else: |         else: | ||||||
|             logger.warning("Language not supported by Tesseract: %s" % iso.name) |             logger.warning("Language not supported by Tesseract: %s", iso.name) | ||||||
|             ocrlang ='osd' |             ocrlang ='osd' | ||||||
|              |              | ||||||
|         if len(subtitles[lang]) == 1: |         if len(subtitles[lang]) == 1: | ||||||
| @@ -221,7 +224,7 @@ def extractSRT(mkvextract, fileName, subtitles, langs): | |||||||
|             if line.startswith('Progress :'): |             if line.startswith('Progress :'): | ||||||
|                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') |                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') | ||||||
|                 m = p.match(line) |                 m = p.match(line) | ||||||
|                 if m == None: |                 if m is None: | ||||||
|                     logger.error('Impossible to parse progress') |                     logger.error('Impossible to parse progress') | ||||||
|                 pb.update(int(m['progress'])-pb.n) |                 pb.update(int(m['progress'])-pb.n) | ||||||
|         pb.update(100-pb.n) |         pb.update(100-pb.n) | ||||||
| @@ -238,7 +241,7 @@ def extractSRT(mkvextract, fileName, subtitles, langs): | |||||||
|         logger.warning('Mkvextract returns warning') |         logger.warning('Mkvextract returns warning') | ||||||
|         return res |         return res | ||||||
|     else: |     else: | ||||||
|         logger.error('Mkvextract returns an error code: %d' % extract.returncode) |         logger.error('Mkvextract returns an error code: %d', extract.returncode) | ||||||
|         return None |         return None | ||||||
|          |          | ||||||
| def doOCR(vobsubocr, idxs, duration, temporaries, dumpMemFD=False): | def doOCR(vobsubocr, idxs, duration, temporaries, dumpMemFD=False): | ||||||
| @@ -256,7 +259,7 @@ def doOCR(vobsubocr, idxs, duration, temporaries, dumpMemFD=False): | |||||||
|             pb = tqdm(TextIOWrapper(ocr.stdout, encoding="utf-8"), total=int(duration/timedelta(seconds=1)), unit='s', desc='OCR') |             pb = tqdm(TextIOWrapper(ocr.stdout, encoding="utf-8"), total=int(duration/timedelta(seconds=1)), unit='s', desc='OCR') | ||||||
|             for line in pb: |             for line in pb: | ||||||
|                 m = re.match(ldots,line) |                 m = re.match(ldots,line) | ||||||
|                 if m != None: |                 if m is not None: | ||||||
|                     write(srtfd, '...'.encode(encoding='UTF-8')) |                     write(srtfd, '...'.encode(encoding='UTF-8')) | ||||||
|                 else: |                 else: | ||||||
|                     write(srtfd, line.encode(encoding='UTF-8')) |                     write(srtfd, line.encode(encoding='UTF-8')) | ||||||
| @@ -273,13 +276,13 @@ def doOCR(vobsubocr, idxs, duration, temporaries, dumpMemFD=False): | |||||||
|         status = ocr.wait() |         status = ocr.wait() | ||||||
|      |      | ||||||
|         if status != 0: |         if status != 0: | ||||||
|             logger.error('OCR failed with status code: %d' % status) |             logger.error('OCR failed with status code: %d', status) | ||||||
|  |  | ||||||
|         if dumpMemFD: |         if dumpMemFD: | ||||||
|             try: |             try: | ||||||
|                 dumpSrt = open(srtname,'w') |                 dumpSrt = open(srtname,'w') | ||||||
|             except IOError: |             except IOError: | ||||||
|                 logger.error('Impossible to create file: %s' % srtname) |                 logger.error('Impossible to create file: %s', srtname) | ||||||
|                 return None |                 return None | ||||||
|  |  | ||||||
|             lseek(srtfd, 0, SEEK_SET) |             lseek(srtfd, 0, SEEK_SET) | ||||||
| @@ -339,10 +342,10 @@ def getCodecPrivateDataFromMKV(mkvinfo, inputFile): | |||||||
|         p = re.compile(regExp) |         p = re.compile(regExp) | ||||||
|         for line in out.splitlines(): |         for line in out.splitlines(): | ||||||
|             m = p.match(line) |             m = p.match(line) | ||||||
|             if m != None: |             if m is not None: | ||||||
|                 size = int(m.group('size')) |                 size = int(m.group('size')) | ||||||
|                 position = int(m.group('position')) |                 position = int(m.group('position')) | ||||||
|                 logger.debug("Found codec private data at position: %s, size: %d" % (position, size)) |                 logger.debug("Found codec private data at position: %s, size: %d", position, size) | ||||||
|                 found = True |                 found = True | ||||||
|                 mkvinfo.wait() |                 mkvinfo.wait() | ||||||
|                 break |                 break | ||||||
| @@ -569,7 +572,7 @@ def parseScalingList(buf, bitPosition, size): | |||||||
| # The ISO/IEC H.264-201602 seems to take into account the case where the end of the deltas list is full of zeroes. | # The ISO/IEC H.264-201602 seems to take into account the case where the end of the deltas list is full of zeroes. | ||||||
| def writeScalingList(buf, bitPosition, size, matrix, optimized=False): | def writeScalingList(buf, bitPosition, size, matrix, optimized=False): | ||||||
|     logger = logging.getLogger(__name__) |     logger = logging.getLogger(__name__) | ||||||
|     logger.debug('Dumping matrix: %s of size: %d, size parameter: %d.' % (matrix, len(matrix), size)) |     logger.debug('Dumping matrix: %s of size: %d, size parameter: %d.', matrix, len(matrix), size) | ||||||
|      |      | ||||||
|     prev = 8 |     prev = 8 | ||||||
|     deltas = [] |     deltas = [] | ||||||
| @@ -846,9 +849,13 @@ class SPS: | |||||||
|         self.scaling_list={} |         self.scaling_list={} | ||||||
|         self.offset_for_ref_frame={} |         self.offset_for_ref_frame={} | ||||||
|      |      | ||||||
|     # Compute options to pass to ffmpeg so as to reproduce the same SPS. |  | ||||||
|     # TODO: ... |     # TODO: ... | ||||||
|  |     # Compute options to pass to ffmpeg so as to reproduce the same SPS. | ||||||
|  |     # Very complex since some codec configuration are not provided by ffmpeg and/or libx264. | ||||||
|  |     # This is only an attempt. | ||||||
|  |     | ||||||
|     def ffmpegOptions(self, videoID=0): |     def ffmpegOptions(self, videoID=0): | ||||||
|  |         logger = logging.getLogger(__name__) | ||||||
|         x264opts = [] |         x264opts = [] | ||||||
|          |          | ||||||
|         if self.profile_idc in [ 0x42, 0x4D, 0x64, 0x6E, 0x7A, 0xF4, 0x2C]: |         if self.profile_idc in [ 0x42, 0x4D, 0x64, 0x6E, 0x7A, 0xF4, 0x2C]: | ||||||
| @@ -865,14 +872,14 @@ class SPS: | |||||||
|             elif self.profile_idc == 0xF4: |             elif self.profile_idc == 0xF4: | ||||||
|                 profile = 'high444' |                 profile = 'high444' | ||||||
|         else: |         else: | ||||||
|             logger.error('Unknow profile: %x' % self.profile) |             logger.error('Unknow profile: %x', self.profile_idc) | ||||||
|             return [] |             return [] | ||||||
|  |  | ||||||
|         level = '%d.%d' % (floor(self.level/10), self.level % 10) |         level = '%d.%d' % (floor(self.level_idc/10), self.level_idc % 10) | ||||||
|         x264opts.extend(['sps-id=%d' % self.seq_parameter_set_id] ) |         x264opts.extend(['sps-id=%d' % self.seq_parameter_set_id] ) | ||||||
|          |          | ||||||
|         if self.bit_depth_chroma_minus8 not in [0,1,2,4,6,8]: |         if self.bit_depth_chroma_minus8 not in [0,1,2,4,6,8]: | ||||||
|             logger.error('Bit depth of chrominance is not supported: %d' % (self.bit_depth_chroma_minus8+8)) |             logger.error('Bit depth of chrominance is not supported: %d', self.bit_depth_chroma_minus8+8) | ||||||
|             return [] |             return [] | ||||||
|          |          | ||||||
|         if self.chroma_format_idc in range(0,4): |         if self.chroma_format_idc in range(0,4): | ||||||
| @@ -889,7 +896,7 @@ class SPS: | |||||||
|                 # YUV:4:4:4 |                 # YUV:4:4:4 | ||||||
|                 pass |                 pass | ||||||
|         else: |         else: | ||||||
|             logger.error('Unknow chrominance format: %x' % self.profile) |             logger.error('Unknow chrominance format: %x', self.chroma_format_idc) | ||||||
|             return [] |             return [] | ||||||
|          |          | ||||||
|         res = ['-profile:v:%d' % videoID, self.profile_idc, '-level:v:%d' % videoID, level] |         res = ['-profile:v:%d' % videoID, self.profile_idc, '-level:v:%d' % videoID, level] | ||||||
| @@ -978,7 +985,7 @@ class SPS: | |||||||
|         if self.vui_parameters_present_flag: |         if self.vui_parameters_present_flag: | ||||||
|             self.vui = VUI() |             self.vui = VUI() | ||||||
|             bitPosition = self.vui.fromBytes(buf,bitPosition) |             bitPosition = self.vui.fromBytes(buf,bitPosition) | ||||||
|             logger.debug('VUI present: %s' % self.vui) |             logger.debug('VUI present: %s', self.vui) | ||||||
|          |          | ||||||
|          |          | ||||||
|         logger.debug('Parse end of SPS. Bit position: %d. Remaining bytes: %s.' % (bitPosition, hexdump.dump(buf[floor(bitPosition/8):], sep=':'))) |         logger.debug('Parse end of SPS. Bit position: %d. Remaining bytes: %s.' % (bitPosition, hexdump.dump(buf[floor(bitPosition/8):], sep=':'))) | ||||||
| @@ -1035,7 +1042,7 @@ class SPS: | |||||||
|             bitPosition = writeUnsignedExpGolomb(buf, bitPosition, self.num_ref_frames_in_pic_order_cnt_cycle) |             bitPosition = writeUnsignedExpGolomb(buf, bitPosition, self.num_ref_frames_in_pic_order_cnt_cycle) | ||||||
|             for i in range(0, self.num_ref_frames_in_pic_order_cnt_cycle): |             for i in range(0, self.num_ref_frames_in_pic_order_cnt_cycle): | ||||||
|                 v = self.offset_for_ref_frame[i] |                 v = self.offset_for_ref_frame[i] | ||||||
|                 bitPosition, v = writeUnsignedExpGolomb(buf, bitPosition) |                 bitPosition = writeUnsignedExpGolomb(buf, bitPosition, v) | ||||||
|         bitPosition = writeUnsignedExpGolomb(buf, bitPosition, self.max_num_ref_frames) |         bitPosition = writeUnsignedExpGolomb(buf, bitPosition, self.max_num_ref_frames) | ||||||
|         bitPosition = writeBoolean(buf, bitPosition, self.gaps_in_frame_num_value_allowed_flag) |         bitPosition = writeBoolean(buf, bitPosition, self.gaps_in_frame_num_value_allowed_flag) | ||||||
|         bitPosition = writeUnsignedExpGolomb(buf, bitPosition, self.pic_width_in_mbs_minus1) |         bitPosition = writeUnsignedExpGolomb(buf, bitPosition, self.pic_width_in_mbs_minus1) | ||||||
| @@ -1052,9 +1059,9 @@ class SPS: | |||||||
|             bitPosition = writeUnsignedExpGolomb(buf, bitPosition, self.frame_crop_bottom_offset) |             bitPosition = writeUnsignedExpGolomb(buf, bitPosition, self.frame_crop_bottom_offset) | ||||||
|         bitPosition = writeBoolean(buf, bitPosition, self.vui_parameters_present_flag) |         bitPosition = writeBoolean(buf, bitPosition, self.vui_parameters_present_flag) | ||||||
|         if self.vui_parameters_present_flag: |         if self.vui_parameters_present_flag: | ||||||
|             logger.debug('SPS has VUI. Writing VUI at position: %d' % bitPosition) |             logger.debug('SPS has VUI. Writing VUI at position: %d', bitPosition) | ||||||
|             bitPosition = self.vui.toBytes(buf, bitPosition) |             bitPosition = self.vui.toBytes(buf, bitPosition) | ||||||
|             logger.debug('VUI written. New bit position: %d' % bitPosition) |             logger.debug('VUI written. New bit position: %d', bitPosition) | ||||||
|              |              | ||||||
|         bitPosition = writeRBSPTrailingBits(buf, bitPosition) |         bitPosition = writeRBSPTrailingBits(buf, bitPosition) | ||||||
|          |          | ||||||
| @@ -1129,7 +1136,7 @@ class PPS: | |||||||
|             elif self.slice_group_map_type == 2: |             elif self.slice_group_map_type == 2: | ||||||
|                 for i in range(0, self.num_slice_groups_minus1): |                 for i in range(0, self.num_slice_groups_minus1): | ||||||
|                     bitPosition, v = readUnsignedExpGolomb(buf, bitPosition) |                     bitPosition, v = readUnsignedExpGolomb(buf, bitPosition) | ||||||
|                     self.top_left.append[i] = v |                     self.top_left[i] = v | ||||||
|                     bitPosition, v = readUnsignedExpGolomb(buf, bitPosition) |                     bitPosition, v = readUnsignedExpGolomb(buf, bitPosition) | ||||||
|                     self.bottom_right[i] = v |                     self.bottom_right[i] = v | ||||||
|             elif self.slice_group_map_type in [3,4,5]: |             elif self.slice_group_map_type in [3,4,5]: | ||||||
| @@ -1204,7 +1211,7 @@ class PPS: | |||||||
|                     bitPosition = writeUnsignedExpGolomb(buf, bitPosition, v) |                     bitPosition = writeUnsignedExpGolomb(buf, bitPosition, v) | ||||||
|             elif self.slice_group_map_type == 2: |             elif self.slice_group_map_type == 2: | ||||||
|                 for i in range(0, self.num_slice_groups_minus1): |                 for i in range(0, self.num_slice_groups_minus1): | ||||||
|                     v = self.top_left.append[i]  |                     v = self.top_left[i]  | ||||||
|                     bitPosition = writeUnsignedExpGolomb(buf, bitPosition, v) |                     bitPosition = writeUnsignedExpGolomb(buf, bitPosition, v) | ||||||
|                     v =  self.bottom_right[i] |                     v =  self.bottom_right[i] | ||||||
|                     bitPosition = writeUnsignedExpGolomb(buf, bitPosition, v) |                     bitPosition = writeUnsignedExpGolomb(buf, bitPosition, v) | ||||||
| @@ -1545,7 +1552,7 @@ def parseMKVTree(mkvinfo, inputFile): | |||||||
|         prevDepth = -1 |         prevDepth = -1 | ||||||
|         for line in out.splitlines(): |         for line in out.splitlines(): | ||||||
|             m = p.match(line) |             m = p.match(line) | ||||||
|             if m == None: |             if m is None: | ||||||
|                 logger.error("Impossible to match line: %s" % line) |                 logger.error("Impossible to match line: %s" % line) | ||||||
|             else: |             else: | ||||||
|                 position = int(m.group('position')) |                 position = int(m.group('position')) | ||||||
| @@ -1668,7 +1675,7 @@ def changeEBMLElementSize(inputFile, position, addendum): | |||||||
|             mask = mask>>1 |             mask = mask>>1 | ||||||
|      |      | ||||||
|     if not found: |     if not found: | ||||||
|         logger.error('Size of element type cannot be determined: %b' % elementType) |         logger.error('Size of element type cannot be determined: %d', elementType) | ||||||
|         exit(-1) |         exit(-1) | ||||||
|      |      | ||||||
|     # We seek to size  |     # We seek to size  | ||||||
| @@ -1689,10 +1696,10 @@ def changeEBMLElementSize(inputFile, position, addendum): | |||||||
|             mask = mask>>1 |             mask = mask>>1 | ||||||
|  |  | ||||||
|     if not found: |     if not found: | ||||||
|         logger.error('Size of data size cannot be determined: %b' % sizeHead) |         logger.error('Size of data size cannot be determined: %d', sizeHead) | ||||||
|         exit(-1) |         exit(-1) | ||||||
|     else: |     else: | ||||||
|         logger.info('Size of data size: %d.' % sizeOfDataSize) |         logger.info('Size of data size: %d.', sizeOfDataSize) | ||||||
|      |      | ||||||
|     lseek(infd, position, SEEK_SET) |     lseek(infd, position, SEEK_SET) | ||||||
|     oldSizeBuf = read(infd, sizeOfDataSize) |     oldSizeBuf = read(infd, sizeOfDataSize) | ||||||
| @@ -1842,7 +1849,7 @@ def getMovieDuration(ffprobe, inputFile): | |||||||
|  |  | ||||||
|     return None |     return None | ||||||
|  |  | ||||||
| # ffprobe -loglevel quiet -select_streams v:0 -show_entries stream=width,height -of json ./talons.ts | # ffprobe -loglevel quiet -select_streams v:0 -show_entries stream=width,height -of json ./example.ts | ||||||
| def getVideoDimensions(ffprobe, inputFile): | def getVideoDimensions(ffprobe, inputFile): | ||||||
|     logger = logging.getLogger(__name__) |     logger = logging.getLogger(__name__) | ||||||
|          |          | ||||||
| @@ -1902,7 +1909,7 @@ def parseTimestamp(ts): | |||||||
|     tsRegExp = r'^(?P<hour>[0-9]{1,2}):(?P<minute>[0-9]{1,2}):(?P<second>[0-9]{1,2})(\.(?P<us>[0-9]{1,6}))?$' |     tsRegExp = r'^(?P<hour>[0-9]{1,2}):(?P<minute>[0-9]{1,2}):(?P<second>[0-9]{1,2})(\.(?P<us>[0-9]{1,6}))?$' | ||||||
|     p = re.compile(tsRegExp) |     p = re.compile(tsRegExp) | ||||||
|     m = p.match(ts) |     m = p.match(ts) | ||||||
|     if m == None: |     if m is None: | ||||||
|         logger.warning("Impossible to parse timestamp: %s" % ts) |         logger.warning("Impossible to parse timestamp: %s" % ts) | ||||||
|         return None |         return None | ||||||
|    |    | ||||||
| @@ -1911,13 +1918,13 @@ def parseTimestamp(ts): | |||||||
|     minute = 0 |     minute = 0 | ||||||
|     second = 0 |     second = 0 | ||||||
|     us = 0 |     us = 0 | ||||||
|     if values['hour'] != None: |     if values['hour'] is not None: | ||||||
|         hour = int(values['hour']) |         hour = int(values['hour']) | ||||||
|     if values['minute'] != None: |     if values['minute'] is not None: | ||||||
|         minute = int(values['minute']) |         minute = int(values['minute']) | ||||||
|     if values['second'] != None: |     if values['second'] is not None: | ||||||
|         second = int(values['second']) |         second = int(values['second']) | ||||||
|     if values['us'] != None: |     if values['us'] is not None: | ||||||
|         us = int(values['us']) |         us = int(values['us']) | ||||||
|    |    | ||||||
|     if hour < 0 or hour > 23: |     if hour < 0 or hour > 23: | ||||||
| @@ -1943,7 +1950,7 @@ def parseTimeInterval(interval): | |||||||
|     intervalRegExp = r'^(?P<hour1>[0-9]{1,2}):(?P<minute1>[0-9]{1,2}):(?P<second1>[0-9]{1,2})(\.(?P<ms1>[0-9]{1,3}))?-(?P<hour2>[0-9]{1,2}):(?P<minute2>[0-9]{1,2}):(?P<second2>[0-9]{1,2})(\.(?P<ms2>[0-9]{1,3}))?$' |     intervalRegExp = r'^(?P<hour1>[0-9]{1,2}):(?P<minute1>[0-9]{1,2}):(?P<second1>[0-9]{1,2})(\.(?P<ms1>[0-9]{1,3}))?-(?P<hour2>[0-9]{1,2}):(?P<minute2>[0-9]{1,2}):(?P<second2>[0-9]{1,2})(\.(?P<ms2>[0-9]{1,3}))?$' | ||||||
|     p = re.compile(intervalRegExp) |     p = re.compile(intervalRegExp) | ||||||
|     m = p.match(interval) |     m = p.match(interval) | ||||||
|     if m == None: |     if m is None: | ||||||
|         logger.error("Impossible to parse time interval") |         logger.error("Impossible to parse time interval") | ||||||
|         return None |         return None | ||||||
|    |    | ||||||
| @@ -1956,21 +1963,21 @@ def parseTimeInterval(interval): | |||||||
|     minute2 = 0 |     minute2 = 0 | ||||||
|     second2 = 0 |     second2 = 0 | ||||||
|     ms2 = 0 |     ms2 = 0 | ||||||
|     if values['hour1'] != None: |     if values['hour1'] is not None: | ||||||
|         hour1 = int(values['hour1']) |         hour1 = int(values['hour1']) | ||||||
|     if values['minute1'] != None: |     if values['minute1'] is not None: | ||||||
|         minute1 = int(values['minute1']) |         minute1 = int(values['minute1']) | ||||||
|     if values['second1'] != None: |     if values['second1'] is not None: | ||||||
|         second1 = int(values['second1']) |         second1 = int(values['second1']) | ||||||
|     if values['ms1'] != None: |     if values['ms1'] is not None: | ||||||
|         ms1 = int(values['ms1']) |         ms1 = int(values['ms1']) | ||||||
|     if values['hour2'] != None: |     if values['hour2'] is not None: | ||||||
|         hour2 = int(values['hour2']) |         hour2 = int(values['hour2']) | ||||||
|     if values['minute2'] != None: |     if values['minute2'] is not None: | ||||||
|         minute2 = int(values['minute2']) |         minute2 = int(values['minute2']) | ||||||
|     if values['second2'] != None: |     if values['second2'] is not None: | ||||||
|         second2 = int(values['second2']) |         second2 = int(values['second2']) | ||||||
|     if values['ms2'] != None: |     if values['ms2'] is not None: | ||||||
|         ms2 = int(values['ms2']) |         ms2 = int(values['ms2']) | ||||||
|    |    | ||||||
|     if hour1 < 0 or hour1 > 23: |     if hour1 < 0 or hour1 > 23: | ||||||
| @@ -2053,32 +2060,36 @@ def ffmpegConvert(ffmpeg, ffprobe, inputFile, inputFormat, outputFile, outputFor | |||||||
|             if line.startswith('out_time='): |             if line.startswith('out_time='): | ||||||
|                 ts = line.split('=')[1].strip() |                 ts = line.split('=')[1].strip() | ||||||
|                 ts = parseTimestamp(ts) |                 ts = parseTimestamp(ts) | ||||||
|                 if ts != None: |                 if ts is not None: | ||||||
|                     pb.n = int(ts/timedelta(seconds=1)) |                     pb.n = int(ts/timedelta(seconds=1)) | ||||||
|                     pb.update() |                     pb.update() | ||||||
|         status = ffmpeg.wait() |         status = ffmpeg.wait() | ||||||
|         if status != 0: |         if status != 0: | ||||||
|             logger.error('Conversion failed with status code: %d' % status) |             logger.error('Conversion failed with status code: %d', status) | ||||||
|  |  | ||||||
| def getTSFrame(frame): | def getTSFrame(frame): | ||||||
|  |     logger = logging.getLogger(__name__) | ||||||
|  |      | ||||||
|     if 'pts_time' in frame: |     if 'pts_time' in frame: | ||||||
|         pts_time = float(frame['pts_time']) |         pts_time = float(frame['pts_time']) | ||||||
|     elif 'pkt_pts_time' in frame: |     elif 'pkt_pts_time' in frame: | ||||||
|         pts_time = float(frame['pkt_pts_time']) |         pts_time = float(frame['pkt_pts_time']) | ||||||
|     else: |     else: | ||||||
|         logger.error('Impossible to find timestamp of frame %s' % frame) |         logger.error('Impossible to find timestamp of frame %s', frame) | ||||||
|         return None |         return None | ||||||
|  |  | ||||||
|     ts = timedelta(seconds=pts_time) |     ts = timedelta(seconds=pts_time) | ||||||
|     return ts |     return ts | ||||||
|  |  | ||||||
| def getPacketDuration(packet): | def getPacketDuration(packet): | ||||||
|  |     logger = logging.getLogger(__name__) | ||||||
|  |      | ||||||
|     if 'duration' in packet: |     if 'duration' in packet: | ||||||
|         duration = int(packet['duration']) |         duration = int(packet['duration']) | ||||||
|     elif 'pkt_duration' in packet: |     elif 'pkt_duration' in packet: | ||||||
|         duration = int(packet['pkt_duration']) |         duration = int(packet['pkt_duration']) | ||||||
|     else: |     else: | ||||||
|         logger.error('Impossible to find duration of packet %s' % packet) |         logger.error('Impossible to find duration of packet %s', packet) | ||||||
|         return None |         return None | ||||||
|      |      | ||||||
|     return duration |     return duration | ||||||
| @@ -2107,7 +2118,7 @@ def getFramesInStream(ffprobe, inputFile, begin, end, streamKind, subStreamId=0) | |||||||
|             frames = frames['frames'] |             frames = frames['frames'] | ||||||
|             for frame in frames: |             for frame in frames: | ||||||
|                 ts = getTSFrame(frame) |                 ts = getTSFrame(frame) | ||||||
|                 if ts == None: |                 if ts is None: | ||||||
|                     return None |                     return None | ||||||
|                 if begin <= ts and ts <= end: |                 if begin <= ts and ts <= end: | ||||||
|                     tmp[ts]=frame |                     tmp[ts]=frame | ||||||
| @@ -2134,12 +2145,12 @@ def getNearestIDRFrame(ffprobe, inputFile, timestamp, before=True, delta=timedel | |||||||
|     infd = inputFile.fileno() |     infd = inputFile.fileno() | ||||||
|     set_inheritable(infd, True) |     set_inheritable(infd, True) | ||||||
|      |      | ||||||
|     logger.debug('Looking for IDR frame in [%s, %s]' % (tbegin, tend)) |     logger.debug('Looking for IDR frame in [%s, %s]', tbegin, tend) | ||||||
|      |      | ||||||
|     idrs = [] |     idrs = [] | ||||||
|      |      | ||||||
|     # Retains only IDR frame |     # Retains only IDR frame | ||||||
|     with Popen([ffprobe, '-loglevel', 'quiet', '-read_intervals', ('%s%%%s' %(begin, end)), '-skip_frame', 'nokey', '-show_entries', 'frame', '-select_streams', 'v:0', '-of', 'json', '/proc/self/fd/%d' % infd], stdout=PIPE, close_fds=False) as ffprobe: |     with Popen([ffprobe, '-loglevel', 'quiet', '-read_intervals', ('%s%%%s' %(tbegin, tend)), '-skip_frame', 'nokey', '-show_entries', 'frame', '-select_streams', 'v:0', '-of', 'json', '/proc/self/fd/%d' % infd], stdout=PIPE, close_fds=False) as ffprobe: | ||||||
|         out, _ = ffprobe.communicate() |         out, _ = ffprobe.communicate() | ||||||
|         frames = json.load(BytesIO(out)) |         frames = json.load(BytesIO(out)) | ||||||
|         status = ffprobe.wait() |         status = ffprobe.wait() | ||||||
| @@ -2151,12 +2162,12 @@ def getNearestIDRFrame(ffprobe, inputFile, timestamp, before=True, delta=timedel | |||||||
|             frames = frames['frames'] |             frames = frames['frames'] | ||||||
|             for frame in frames: |             for frame in frames: | ||||||
|                 ts = getTSFrame(frame) |                 ts = getTSFrame(frame) | ||||||
|                 if ts == None: |                 if ts is None: | ||||||
|                     return None |                     return None | ||||||
|                 if begin <= ts and ts <= end: |                 if tbegin <= ts and ts <= tend: | ||||||
|                     idrs.append(frame) |                     idrs.append(frame) | ||||||
|         else: |         else: | ||||||
|            logger.error('Impossible to retrieve IDR frames inside file around [%s,%s]' % (begin, end)) |            logger.error('Impossible to retrieve IDR frames inside file around [%s,%s]', tbegin, tend) | ||||||
|            return None |            return None | ||||||
|      |      | ||||||
|      |      | ||||||
| @@ -2186,7 +2197,7 @@ def getNearestIFrame(ffprobe, inputFile, timestamp, before=True, deltaMax=timede | |||||||
|         logger.debug('Looking for an iframe in [%s, %s]' % (tbegin, tend)) |         logger.debug('Looking for an iframe in [%s, %s]' % (tbegin, tend)) | ||||||
|      |      | ||||||
|         frames = getFramesInStream(ffprobe, inputFile=inputFile, begin=tbegin, end=tend, streamKind='v') |         frames = getFramesInStream(ffprobe, inputFile=inputFile, begin=tbegin, end=tend, streamKind='v') | ||||||
|         if frames == None: |         if frames is None: | ||||||
|             logger.debug('Found no frame in [%s, %s]' % (tbegin, tend)) |             logger.debug('Found no frame in [%s, %s]' % (tbegin, tend)) | ||||||
|             delta+=timedelta(seconds=1) |             delta+=timedelta(seconds=1) | ||||||
|             continue |             continue | ||||||
| @@ -2199,7 +2210,7 @@ def getNearestIFrame(ffprobe, inputFile, timestamp, before=True, deltaMax=timede | |||||||
|         found = False |         found = False | ||||||
|         for frame in iframes: |         for frame in iframes: | ||||||
|             ts = getTSFrame(frame) |             ts = getTSFrame(frame) | ||||||
|             if ts == None: |             if ts is None: | ||||||
|                 logger.warning('I-frame with no timestamp: %s' % frame) |                 logger.warning('I-frame with no timestamp: %s' % frame) | ||||||
|                 continue |                 continue | ||||||
|        |        | ||||||
| @@ -2218,12 +2229,12 @@ def getNearestIFrame(ffprobe, inputFile, timestamp, before=True, deltaMax=timede | |||||||
|             delta+=timedelta(seconds=1) |             delta+=timedelta(seconds=1) | ||||||
|             continue |             continue | ||||||
|      |      | ||||||
|     if iframe != None: |     if iframe is not None: | ||||||
|         its = getTSFrame(iframe) |         its = getTSFrame(iframe) | ||||||
|         nbFrames = 0 |         nbFrames = 0 | ||||||
|         for frame in frames: |         for frame in frames: | ||||||
|             ts = getTSFrame(frame) |             ts = getTSFrame(frame) | ||||||
|             if ts == None: |             if ts is None: | ||||||
|                 logger.warning('Frame without timestamp: %s' % frame) |                 logger.warning('Frame without timestamp: %s' % frame) | ||||||
|                 continue |                 continue | ||||||
|  |  | ||||||
| @@ -2263,7 +2274,7 @@ def extractMKVPart(mkvmerge, inputFile, outputFile, begin, end): | |||||||
|             if line.startswith('Progress :'): |             if line.startswith('Progress :'): | ||||||
|                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') |                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') | ||||||
|                 m = p.match(line) |                 m = p.match(line) | ||||||
|                 if m == None: |                 if m is None: | ||||||
|                     logger.error('Impossible to parse progress') |                     logger.error('Impossible to parse progress') | ||||||
|                 pb.update(int(m['progress'])-pb.n) |                 pb.update(int(m['progress'])-pb.n) | ||||||
|             elif line.startswith('Warning'): |             elif line.startswith('Warning'): | ||||||
| @@ -2367,7 +2378,7 @@ def dumpPPM(pictures, prefix, temporaries): | |||||||
|         if magic == 'P6\n': |         if magic == 'P6\n': | ||||||
|             pattern = re.compile('^(?P<width>[0-9]+) (?P<height>[0-9]+)\n$')  |             pattern = re.compile('^(?P<width>[0-9]+) (?P<height>[0-9]+)\n$')  | ||||||
|             m = pattern.match(dimensions) |             m = pattern.match(dimensions) | ||||||
|             if m != None: |             if m is not None: | ||||||
|                 width = int(m['width']) |                 width = int(m['width']) | ||||||
|                 height = int(m['height']) |                 height = int(m['height']) | ||||||
|             else: |             else: | ||||||
| @@ -2424,7 +2435,8 @@ def extractAllStreams(ffmpeg, ffprobe, inputFile, begin, end, streams, filesPref | |||||||
|                 level = int(stream['level']) |                 level = int(stream['level']) | ||||||
|                 level = '%d.%d' % (floor(level/10), level%10)  |                 level = '%d.%d' % (floor(level/10), level%10)  | ||||||
|                 chromaLocation = stream['chroma_location'] |                 chromaLocation = stream['chroma_location'] | ||||||
|                 fieldOrder = stream['field_order'] |                 fieldOrder = stream | ||||||
|  |                 interlacedOptions = [] | ||||||
|                 if fieldOrder == 'progressive': |                 if fieldOrder == 'progressive': | ||||||
|                     interlacedOptions = ['-field_order', '0'] |                     interlacedOptions = ['-field_order', '0'] | ||||||
|                 elif fieldOrder == 'tt': |                 elif fieldOrder == 'tt': | ||||||
| @@ -2441,7 +2453,7 @@ def extractAllStreams(ffmpeg, ffprobe, inputFile, begin, end, streams, filesPref | |||||||
|                 # https://superuser.com/questions/907933/correct-aspect-ratio-without-re-encoding-video-file |                 # https://superuser.com/questions/907933/correct-aspect-ratio-without-re-encoding-video-file | ||||||
|                 codec = stream['codec_name'] |                 codec = stream['codec_name'] | ||||||
|                 imagesBytes, memfd = extractPictures(ffmpeg, inputFile=inputFile, begin=begin, nbFrames=nbFrames, width=width, height=height) |                 imagesBytes, memfd = extractPictures(ffmpeg, inputFile=inputFile, begin=begin, nbFrames=nbFrames, width=width, height=height) | ||||||
|                 if imagesBytes == None: |                 if imagesBytes is None: | ||||||
|                     exit(-1) |                     exit(-1) | ||||||
|                  |                  | ||||||
|                 memfds.append(memfd) |                 memfds.append(memfd) | ||||||
| @@ -2475,7 +2487,7 @@ def extractAllStreams(ffmpeg, ffprobe, inputFile, begin, end, streams, filesPref | |||||||
|                 logger.debug("Found %d packets to be extracted from audio track." % nbPackets) |                 logger.debug("Found %d packets to be extracted from audio track." % nbPackets) | ||||||
|                 if(nbPackets > 0): |                 if(nbPackets > 0): | ||||||
|                     packetDuration = getPacketDuration(packets[0]) |                     packetDuration = getPacketDuration(packets[0]) | ||||||
|                     if packetDuration == None: |                     if packetDuration is None: | ||||||
|                         return None |                         return None | ||||||
|                 else: |                 else: | ||||||
|                     packetDuration = 0 |                     packetDuration = 0 | ||||||
| @@ -2486,7 +2498,7 @@ def extractAllStreams(ffmpeg, ffprobe, inputFile, begin, end, streams, filesPref | |||||||
|                  |                  | ||||||
|                 soundBytes, memfd = extractSound(ffmpeg=ffmpeg, inputFile=inputFile, begin=begin, nbPackets=nbPackets, packetDuration=packetDuration, outputFileName=tmpname, sampleRate=sampleRate, nbChannels=nbChannels) |                 soundBytes, memfd = extractSound(ffmpeg=ffmpeg, inputFile=inputFile, begin=begin, nbPackets=nbPackets, packetDuration=packetDuration, outputFileName=tmpname, sampleRate=sampleRate, nbChannels=nbChannels) | ||||||
|                  |                  | ||||||
|                 if soundBytes == None: |                 if soundBytes is None: | ||||||
|                     exit(-1) |                     exit(-1) | ||||||
|                      |                      | ||||||
|                 memfds.append(memfd) |                 memfds.append(memfd) | ||||||
| @@ -2633,7 +2645,7 @@ def mergeMKVs(mkvmerge, inputs, outputName, concatenate=True, timestamps=None): | |||||||
|             fds.append(fd) |             fds.append(fd) | ||||||
|             set_inheritable(fd, True) |             set_inheritable(fd, True) | ||||||
|             # If we pass a timestamps file associated with the considered track, use it.  |             # If we pass a timestamps file associated with the considered track, use it.  | ||||||
|             if timestamps != None and partNum in timestamps: |             if timestamps is not None and partNum in timestamps: | ||||||
|                 tsfd = timestamps[partNum].fileno() |                 tsfd = timestamps[partNum].fileno() | ||||||
|                 lseek(tsfd, 0, SEEK_SET) |                 lseek(tsfd, 0, SEEK_SET) | ||||||
|                 fds.append(tsfd) |                 fds.append(tsfd) | ||||||
| @@ -2661,7 +2673,7 @@ def mergeMKVs(mkvmerge, inputs, outputName, concatenate=True, timestamps=None): | |||||||
|             if line.startswith('Progress :'): |             if line.startswith('Progress :'): | ||||||
|                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') |                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') | ||||||
|                 m = p.match(line) |                 m = p.match(line) | ||||||
|                 if m == None: |                 if m is None: | ||||||
|                     logger.error('Impossible to parse progress') |                     logger.error('Impossible to parse progress') | ||||||
|                 pb.n = int(m['progress']) |                 pb.n = int(m['progress']) | ||||||
|                 pb.update() |                 pb.update() | ||||||
| @@ -2728,7 +2740,7 @@ def extractTrackFromMKV(mkvextract, inputFile, index, outputFile, timestamps): | |||||||
|             if line.startswith('Progress :'): |             if line.startswith('Progress :'): | ||||||
|                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') |                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') | ||||||
|                 m = p.match(line) |                 m = p.match(line) | ||||||
|                 if m == None: |                 if m is None: | ||||||
|                     logger.error('Impossible to parse progress') |                     logger.error('Impossible to parse progress') | ||||||
|                 pb.update(int(m['progress'])-pb.n) |                 pb.update(int(m['progress'])-pb.n) | ||||||
|         pb.update(100-pb.n) |         pb.update(100-pb.n) | ||||||
| @@ -2763,7 +2775,7 @@ def removeVideoTracksFromMKV(mkvmerge, inputFile, outputFile): | |||||||
|             if line.startswith('Progress :'): |             if line.startswith('Progress :'): | ||||||
|                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') |                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') | ||||||
|                 m = p.match(line) |                 m = p.match(line) | ||||||
|                 if m == None: |                 if m is None: | ||||||
|                     logger.error('Impossible to parse progress') |                     logger.error('Impossible to parse progress') | ||||||
|                 pb.update(int(m['progress'])-pb.n) |                 pb.update(int(m['progress'])-pb.n) | ||||||
|         pb.update(100-pb.n) |         pb.update(100-pb.n) | ||||||
| @@ -2810,7 +2822,7 @@ def remuxSRTSubtitles(mkvmerge, inputFile, outputFileName, subtitles): | |||||||
|             if line.startswith('Progress :'): |             if line.startswith('Progress :'): | ||||||
|                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') |                 p = re.compile('^Progress : (?P<progress>[0-9]{1,3})%$') | ||||||
|                 m = p.match(line) |                 m = p.match(line) | ||||||
|                 if m == None: |                 if m is None: | ||||||
|                     logger.error('Impossible to parse progress') |                     logger.error('Impossible to parse progress') | ||||||
|                 pb.n = int(m['progress']) |                 pb.n = int(m['progress']) | ||||||
|                 pb.update() |                 pb.update() | ||||||
| @@ -2844,7 +2856,7 @@ def concatenateH264Parts(h264parts, output): | |||||||
|         lseek(fd, 0, SEEK_SET) |         lseek(fd, 0, SEEK_SET) | ||||||
|         while True: |         while True: | ||||||
|             buf = read(fd, 1000000) |             buf = read(fd, 1000000) | ||||||
|             if buf == None or len(buf) == 0: |             if buf is None or len(buf) == 0: | ||||||
|                 break |                 break | ||||||
|             pos = 0 |             pos = 0 | ||||||
|             while pos < len(buf): |             while pos < len(buf): | ||||||
| @@ -2882,6 +2894,7 @@ def concatenateH264TSParts(h264TSParts, output): | |||||||
|             first = False |             first = False | ||||||
|  |  | ||||||
| def doCoarseProcessing(ffmpeg, ffprobe, mkvmerge, inputFile, begin, end, nbFrames, frameRate, filesPrefix, streams, width, height, temporaries, dumpMemFD): | def doCoarseProcessing(ffmpeg, ffprobe, mkvmerge, inputFile, begin, end, nbFrames, frameRate, filesPrefix, streams, width, height, temporaries, dumpMemFD): | ||||||
|  |     logger = logging.getLogger(__name__) | ||||||
|      |      | ||||||
|     # Internal video with all streams (video, audio and subtitles) |     # Internal video with all streams (video, audio and subtitles) | ||||||
|     internalMKVName = '%s.mkv' % filesPrefix |     internalMKVName = '%s.mkv' % filesPrefix | ||||||
| @@ -2889,7 +2902,7 @@ def doCoarseProcessing(ffmpeg, ffprobe, mkvmerge, inputFile, begin, end, nbFrame | |||||||
|     try: |     try: | ||||||
|         internalMKV = open(internalMKVName, 'w+') |         internalMKV = open(internalMKVName, 'w+') | ||||||
|     except IOError: |     except IOError: | ||||||
|         logger.error('Impossible to create file: %s' % internalMKVName) |         logger.error('Impossible to create file: %s', internalMKVName) | ||||||
|         exit(-1) |         exit(-1) | ||||||
|      |      | ||||||
|     # Extract internal part of MKV |     # Extract internal part of MKV | ||||||
| @@ -2923,18 +2936,18 @@ def main(): | |||||||
|      |      | ||||||
|     logger.debug('Arguments: %s' % args) |     logger.debug('Arguments: %s' % args) | ||||||
|  |  | ||||||
|     if args.coarse and args.threshold != None: |     if args.coarse and args.threshold is not None: | ||||||
|         logger.error('--coarse and threshold arguments are exclusive.') |         logger.error('--coarse and threshold arguments are exclusive.') | ||||||
|         exit(-1) |         exit(-1) | ||||||
|  |  | ||||||
|     if (not args.coarse) and args.threshold == None: |     if (not args.coarse) and args.threshold is None: | ||||||
|         args.threshold = 0 |         args.threshold = 0 | ||||||
|      |      | ||||||
|     allOptionalTools, paths = checkRequiredTools() |     allOptionalTools, paths = checkRequiredTools() | ||||||
|  |  | ||||||
|     # Flatten args.parts |     # Flatten args.parts | ||||||
|     intervals = [] |     intervals = [] | ||||||
|     if args.parts != None: |     if args.parts is not None: | ||||||
|         for part in args.parts: |         for part in args.parts: | ||||||
|             for subpart in part: |             for subpart in part: | ||||||
|                 intervals.append(subpart) |                 intervals.append(subpart) | ||||||
| @@ -2943,7 +2956,7 @@ def main(): | |||||||
|     # Parse each interval |     # Parse each interval | ||||||
|     for interval in intervals: |     for interval in intervals: | ||||||
|         ts1, ts2 = parseTimeInterval(interval) |         ts1, ts2 = parseTimeInterval(interval) | ||||||
|         if ts1 == None or ts2 == None: |         if ts1 is None or ts2 is None: | ||||||
|             logger.error("Illegal time interval: %s" % interval) |             logger.error("Illegal time interval: %s" % interval) | ||||||
|             exit(-1) |             exit(-1) | ||||||
|         parts.append((ts1,ts2)) |         parts.append((ts1,ts2)) | ||||||
| @@ -2975,15 +2988,15 @@ def main(): | |||||||
|      |      | ||||||
|     formatOfFile = getFormat(paths['ffprobe'], inputFile) |     formatOfFile = getFormat(paths['ffprobe'], inputFile) | ||||||
|     |     | ||||||
|     if formatOfFile == None: |     if formatOfFile is None: | ||||||
|         exit(-1) |         exit(-1) | ||||||
|     |     | ||||||
|     duration = timedelta(seconds=float(formatOfFile['duration'])) |     duration = timedelta(seconds=float(formatOfFile['duration'])) | ||||||
|     logger.info("Durée de l'enregistrement: %s" % duration) |     logger.info("Durée de l'enregistrement: %s" % duration) | ||||||
|      |      | ||||||
|     if args.framerate == None: |     if args.framerate is None: | ||||||
|         frameRate = getFrameRate(paths['ffprobe'], inputFile) |         frameRate = getFrameRate(paths['ffprobe'], inputFile) | ||||||
|         if frameRate == None: |         if frameRate is None: | ||||||
|             logger.error('Impossible to estimate frame rate !') |             logger.error('Impossible to estimate frame rate !') | ||||||
|             exit(-1) |             exit(-1) | ||||||
|     else: |     else: | ||||||
| @@ -3053,7 +3066,7 @@ def main(): | |||||||
|             else: |             else: | ||||||
|                 mainVideo = None |                 mainVideo = None | ||||||
|      |      | ||||||
|     if mainVideo == None: |     if mainVideo is None: | ||||||
|         logger.error('Impossible to find main video stream.') |         logger.error('Impossible to find main video stream.') | ||||||
|         exit(-1) |         exit(-1) | ||||||
|      |      | ||||||
| @@ -3106,26 +3119,26 @@ def main(): | |||||||
|          |          | ||||||
|         # Get the nearest I-frame whose timestamp is greater or equal to the beginning. |         # Get the nearest I-frame whose timestamp is greater or equal to the beginning. | ||||||
|         headFrames = getNearestIFrame(paths['ffprobe'], mkv, ts1, before=False) |         headFrames = getNearestIFrame(paths['ffprobe'], mkv, ts1, before=False) | ||||||
|         if headFrames == None: |         if headFrames is None: | ||||||
|             exit(-1) |             exit(-1) | ||||||
|          |          | ||||||
|         # Get the nearest I-frame whose timestamp ... |         # Get the nearest I-frame whose timestamp ... | ||||||
|         # TODO: wrong here ... |         # TODO: wrong here ... | ||||||
|         tailFrames = getNearestIFrame(paths['ffprobe'], mkv, ts2, before=True) |         tailFrames = getNearestIFrame(paths['ffprobe'], mkv, ts2, before=True) | ||||||
|         if tailFrames == None: |         if tailFrames is None: | ||||||
|             exit(-1) |             exit(-1) | ||||||
|          |          | ||||||
|         nbHeadFrames, headIFrame = headFrames |         nbHeadFrames, headIFrame = headFrames | ||||||
|         nbTailFrames, tailIFrame = tailFrames |         nbTailFrames, tailIFrame = tailFrames | ||||||
|          |          | ||||||
|         logger.info("Found %d frames between beginning of current part and first I-frame" % nbHeadFrames) |         logger.info("Found %d frames between beginning of current part and first I-frame", nbHeadFrames) | ||||||
|         logger.info("Found %d frames between last I-frame and end of current part" % nbTailFrames) |         logger.info("Found %d frames between last I-frame and end of current part", nbTailFrames) | ||||||
|          |          | ||||||
|         headIFrameTS = getTSFrame(headIFrame) |         headIFrameTS = getTSFrame(headIFrame) | ||||||
|         if headIFrameTS == None: |         if headIFrameTS is None: | ||||||
|             exit(-1) |             exit(-1) | ||||||
|         tailIFrameTS = getTSFrame(tailIFrame) |         tailIFrameTS = getTSFrame(tailIFrame) | ||||||
|         if tailIFrameTS == None: |         if tailIFrameTS is None: | ||||||
|             exit(-1) |             exit(-1) | ||||||
|  |  | ||||||
|         checks.append(pos+headIFrameTS-ts1) |         checks.append(pos+headIFrameTS-ts1) | ||||||
| @@ -3145,13 +3158,13 @@ def main(): | |||||||
|             h264Head, h264HeadTS, mkvHead = extractAllStreams(ffmpeg=paths['ffmpeg'], ffprobe=paths['ffprobe'], inputFile=mkv, begin=ts1, end=headIFrameTS, nbFrames=nbHeadFrames-1, frameRate=frameRate, filesPrefix='part-%d-head' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries, dumpMemFD=args.dump) |             h264Head, h264HeadTS, mkvHead = extractAllStreams(ffmpeg=paths['ffmpeg'], ffprobe=paths['ffprobe'], inputFile=mkv, begin=ts1, end=headIFrameTS, nbFrames=nbHeadFrames-1, frameRate=frameRate, filesPrefix='part-%d-head' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries, dumpMemFD=args.dump) | ||||||
|          |          | ||||||
|             # If we are not at an exact boundary: |             # If we are not at an exact boundary: | ||||||
|             if mkvHead != None: |             if mkvHead is not None: | ||||||
|                 subparts.append(mkvHead) |                 subparts.append(mkvHead) | ||||||
|             if h264Head != None: |             if h264Head is not None: | ||||||
|                 avcconfig = getAvcConfigFromH264(h264Head) |                 avcconfig = getAvcConfigFromH264(h264Head) | ||||||
|                 otherAvcConfigs.append(avcconfig) |                 otherAvcConfigs.append(avcconfig) | ||||||
|                 h264parts.append(h264Head) |                 h264parts.append(h264Head) | ||||||
|             if h264HeadTS != None: |             if h264HeadTS is not None: | ||||||
|                 h264TS.append(h264HeadTS) |                 h264TS.append(h264HeadTS) | ||||||
|              |              | ||||||
|          |          | ||||||
| @@ -3168,25 +3181,25 @@ def main(): | |||||||
|         try: |         try: | ||||||
|             internalMKV = open(internalMKVName, 'w+') |             internalMKV = open(internalMKVName, 'w+') | ||||||
|         except IOError: |         except IOError: | ||||||
|             logger.error('Impossible to create file: %s' % internalMKVName) |             logger.error('Impossible to create file: %s', internalMKVName) | ||||||
|             exit(-1) |             exit(-1) | ||||||
|          |          | ||||||
|         try: |         try: | ||||||
|             internalNoVideoMKV = open(internalNoVideoMKVName, 'w+') |             internalNoVideoMKV = open(internalNoVideoMKVName, 'w+') | ||||||
|         except IOError: |         except IOError: | ||||||
|             logger.error('Impossible to create file: %s' % internalNoVideoMKVName) |             logger.error('Impossible to create file: %s', internalNoVideoMKVName) | ||||||
|             exit(-1) |             exit(-1) | ||||||
|          |          | ||||||
|         try: |         try: | ||||||
|             internalH264 = open(internalH264Name, 'w+') |             internalH264 = open(internalH264Name, 'w+') | ||||||
|         except IOError: |         except IOError: | ||||||
|             logger.error('Impossible to create file: %s' % internalH264Name) |             logger.error('Impossible to create file: %s', internalH264Name) | ||||||
|             exit(-1) |             exit(-1) | ||||||
|              |              | ||||||
|         try: |         try: | ||||||
|             internalH264TS = open(internalH264TSName, 'w+') |             internalH264TS = open(internalH264TSName, 'w+') | ||||||
|         except IOError: |         except IOError: | ||||||
|             logger.error('Impossible to create file: %s' % internalH264TSName) |             logger.error('Impossible to create file: %s', internalH264TSName) | ||||||
|             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' % internalMKVName) | ||||||
| @@ -3199,7 +3212,7 @@ def main(): | |||||||
|         extractTrackFromMKV(mkvextract=paths['mkvextract'], inputFile=internalMKV, index=0, outputFile=internalH264, timestamps=internalH264TS) |         extractTrackFromMKV(mkvextract=paths['mkvextract'], inputFile=internalMKV, index=0, outputFile=internalH264, timestamps=internalH264TS) | ||||||
|          |          | ||||||
|         # 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', internalMKVName) | ||||||
|         removeVideoTracksFromMKV(mkvmerge=paths['mkvmerge'], inputFile=internalMKV, outputFile=internalNoVideoMKV) |         removeVideoTracksFromMKV(mkvmerge=paths['mkvmerge'], inputFile=internalMKV, outputFile=internalNoVideoMKV) | ||||||
|          |          | ||||||
|         temporaries.append(internalMKV) |         temporaries.append(internalMKV) | ||||||
| @@ -3215,16 +3228,16 @@ def main(): | |||||||
|             # 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'], ffprobe=paths['ffprobe'], inputFile=mkv, begin=tailIFrameTS, end=ts2, nbFrames=nbTailFrames, frameRate=frameRate, filesPrefix='part-%d-tail' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries, dumpMemFD=args.dump) |             h264Tail, h264TailTS, mkvTail = extractAllStreams(ffmpeg=paths['ffmpeg'], ffprobe=paths['ffprobe'], inputFile=mkv, begin=tailIFrameTS, end=ts2, nbFrames=nbTailFrames, frameRate=frameRate, filesPrefix='part-%d-tail' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries, dumpMemFD=args.dump) | ||||||
|              |              | ||||||
|             if mkvTail != None: |             if mkvTail is not None: | ||||||
|                 subparts.append(mkvTail) |                 subparts.append(mkvTail) | ||||||
|             if h264Tail != None: |             if h264Tail is not None: | ||||||
|                 avcconfig = getAvcConfigFromH264(h264Tail) |                 avcconfig = getAvcConfigFromH264(h264Tail) | ||||||
|                 otherAvcConfigs.append(avcconfig) |                 otherAvcConfigs.append(avcconfig) | ||||||
|                 h264parts.append(h264Tail) |                 h264parts.append(h264Tail) | ||||||
|             if h264TailTS != None: |             if h264TailTS is not None: | ||||||
|                 h264TS.append(h264TailTS) |                 h264TS.append(h264TailTS) | ||||||
|          |          | ||||||
|         logger.info('Merging MKV: %s' % subparts) |         logger.info('Merging MKV: %s', subparts) | ||||||
|         part = mergeMKVs(mkvmerge=paths['mkvmerge'], inputs=subparts, outputName="part-%d.mkv" % partnum, concatenate=True) |         part = mergeMKVs(mkvmerge=paths['mkvmerge'], inputs=subparts, outputName="part-%d.mkv" % partnum, concatenate=True) | ||||||
|         mkvparts.append(part) |         mkvparts.append(part) | ||||||
|         temporaries.append(part) |         temporaries.append(part) | ||||||
| @@ -3237,7 +3250,7 @@ def main(): | |||||||
|     # When using coarse option there is a single AVC configuration. |     # When using coarse option there is a single AVC configuration. | ||||||
|     for avcConfig in otherAvcConfigs:         |     for avcConfig in otherAvcConfigs:         | ||||||
|         mainAvcConfig.merge(avcConfig) |         mainAvcConfig.merge(avcConfig) | ||||||
|         logger.debug('Merged AVC configuration: %s' % mainAvcConfig) |         logger.debug('Merged AVC configuration: %s', mainAvcConfig) | ||||||
|      |      | ||||||
|     nbMKVParts = len(mkvparts) |     nbMKVParts = len(mkvparts) | ||||||
|     if nbMKVParts > 0: |     if nbMKVParts > 0: | ||||||
| @@ -3328,12 +3341,12 @@ def main(): | |||||||
|                     try: |                     try: | ||||||
|                         idx = open(idxName,'r') |                         idx = open(idxName,'r') | ||||||
|                     except IOError: |                     except IOError: | ||||||
|                         logger.error("Impossible to open %s." % idxName) |                         logger.error("Impossible to open %s.", idxName) | ||||||
|                         exit(-1) |                         exit(-1) | ||||||
|                     try: |                     try: | ||||||
|                         sub = open(subName,'r') |                         sub = open(subName,'r') | ||||||
|                     except IOError: |                     except IOError: | ||||||
|                         logger.error("Impossible to open %s." % subName) |                         logger.error("Impossible to open %s.", subName) | ||||||
|                         exit(-1) |                         exit(-1) | ||||||
|                      |                      | ||||||
|                     temporaries.append(idx) |                     temporaries.append(idx) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user