From d2f0e417db0c5fe930eb483f3aa1bdec6033cd39 Mon Sep 17 00:00:00 2001 From: Chris Lawrence Date: Wed, 17 Sep 2014 20:44:30 -0400 Subject: [PATCH 1/5] Check H.264 level; if too high (greater than 4.1), transcode since higher levels aren't supported by TiVo hardware. --- plugins/video/transcode.py | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/plugins/video/transcode.py b/plugins/video/transcode.py index 94e1aea4..72460bf1 100644 --- a/plugins/video/transcode.py +++ b/plugins/video/transcode.py @@ -570,6 +570,11 @@ def tivo_compatible_video(vInfo, tsn, mime=''): message = (False, '%s kbps not supported' % vInfo['kbps']) break + # According to https://code.google.com/p/streambaby/wiki/video_compatibility, level 4.1 is the maximum supported on Series 4. + if codec == 'h264' and int(vInfo['vH264Level']) > 41: + message = (False, 'h264 level %s too high' % vInfo['vH264Level']) + break + if config.isHDtivo(tsn): # HD Tivo detected, skipping remaining tests. break @@ -741,6 +746,44 @@ def tivo_compatible(inFile, tsn='', mime=''): message[1], inFile)) return message +def detect_h264_level(fname, vstream=0): + ffprobe_path = config.get_bin('ffprobe') + if not ffprobe_path: + return 0 + + cmd = [ffprobe_path, '-of', 'flat', '-show_streams', '-i', fname] + # Windows and other OS buffer 4096 and ffprobe can output more than that. + out_tmp = tempfile.TemporaryFile() + ffprobe = subprocess.Popen(cmd, stdout=out_tmp, stderr=subprocess.PIPE, + stdin=subprocess.PIPE) + + # wait configured # of seconds: if ffprobe is not back give up + limit = config.getFFmpegWait() + if limit: + for i in xrange(limit * 20): + time.sleep(.05) + if not ffprobe.poll() == None: + break + + if ffprobe.poll() == None: + kill(ffprobe) + vInfo['Supported'] = False + if cache: + info_cache[inFile] = (mtime, vInfo) + return vInfo + else: + ffprobe.wait() + + out_tmp.seek(0) + output = out_tmp.read() + out_tmp.close() + debug('ffprobe output=%s' % repr(output)) + + match = re.search(r'streams\.stream\.\d+\.level=(\d+)', output) + if match: + return int(match.group(1)) + return 0 + def video_info(inFile, cache=True): vInfo = dict() fname = unicode(inFile, 'utf-8') @@ -884,6 +927,11 @@ def video_info(inFile, cache=True): else: vInfo['millisecs'] = 0 + # get h264 level + vInfo['vH264Level'] = 0 # Assume it's OK unless proven otherwise + if vInfo['vCodec'] == 'h264': + vInfo['vH264Level'] = detect_h264_level(fname) + # get bitrate of source for tivo compatibility test. rezre = re.compile(r'.*bitrate: (.+) (?:kb/s).*') x = rezre.search(output) From f6ba663bfd86fff7a7ec08388ab9101ed2f79fe1 Mon Sep 17 00:00:00 2001 From: Chris Lawrence Date: Wed, 17 Sep 2014 20:54:00 -0400 Subject: [PATCH 2/5] Fix logic in fallback code. --- plugins/video/transcode.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/video/transcode.py b/plugins/video/transcode.py index 72460bf1..1ddd8776 100644 --- a/plugins/video/transcode.py +++ b/plugins/video/transcode.py @@ -767,10 +767,7 @@ def detect_h264_level(fname, vstream=0): if ffprobe.poll() == None: kill(ffprobe) - vInfo['Supported'] = False - if cache: - info_cache[inFile] = (mtime, vInfo) - return vInfo + return 0 else: ffprobe.wait() From 55de79bd5fba45c83dfed635f44e5fb2cc723cc5 Mon Sep 17 00:00:00 2001 From: Chris Lawrence Date: Sun, 15 Mar 2015 01:04:36 -0400 Subject: [PATCH 3/5] Test was in wrong place, fix location. --- plugins/video/transcode.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/video/transcode.py b/plugins/video/transcode.py index 1ddd8776..4929451a 100644 --- a/plugins/video/transcode.py +++ b/plugins/video/transcode.py @@ -541,6 +541,9 @@ def tivo_compatible_video(vInfo, tsn, mime=''): if codec != 'h264': message = (False, 'vCodec %s not compatible' % codec) + # According to https://code.google.com/p/streambaby/wiki/video_compatibility, level 4.1 is the maximum supported on Series 4. + if int(vInfo['vH264Level']) > 41: + message = (False, 'h264 level %s too high' % vInfo['vH264Level']) break if mime == 'video/bif': @@ -570,11 +573,6 @@ def tivo_compatible_video(vInfo, tsn, mime=''): message = (False, '%s kbps not supported' % vInfo['kbps']) break - # According to https://code.google.com/p/streambaby/wiki/video_compatibility, level 4.1 is the maximum supported on Series 4. - if codec == 'h264' and int(vInfo['vH264Level']) > 41: - message = (False, 'h264 level %s too high' % vInfo['vH264Level']) - break - if config.isHDtivo(tsn): # HD Tivo detected, skipping remaining tests. break From c04b2d9a3c18e82c08f384126d18a2b084ef5be1 Mon Sep 17 00:00:00 2001 From: Chris Lawrence Date: Mon, 17 Oct 2016 06:35:59 -0400 Subject: [PATCH 4/5] Improve estimate of disk usage for videos that don't need converting. --- plugins/video/video.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/plugins/video/video.py b/plugins/video/video.py index 692ab68f..6a548c0b 100644 --- a/plugins/video/video.py +++ b/plugins/video/video.py @@ -324,7 +324,18 @@ def __total_items(self, full_path): def __est_size(self, full_path, tsn='', mime=''): # Size is estimated by taking audio and video bit rate adding 2% - if transcode.tivo_compatible(full_path, tsn, mime)[0]: + vInfo = transcode.video_info(full_path) + if not mime: + compat = False + for mimet in ['video/mp4', 'video/bip', 'video/mpeg', + 'video/x-tivo-mpeg-ts']: + compat = transcode.tivo_compatible_video(vInfo, tsn, mimet)[0] + if compat: + break + else: + compat = transcode.tivo_compatible_video(vInfo, tsn, mime)[0] + + if compat: return os.path.getsize(unicode(full_path, 'utf-8')) else: # Must be re-encoded From 94dc150f0aaae591f847b1c9f6e67a81282a66e5 Mon Sep 17 00:00:00 2001 From: Chris Lawrence Date: Tue, 18 Oct 2016 03:20:44 -0400 Subject: [PATCH 5/5] Do a better job of detecting when video transcoding may be used; add a padding factor in case audio is transcoded. --- plugins/video/video.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/video/video.py b/plugins/video/video.py index 6a548c0b..d8e0255f 100644 --- a/plugins/video/video.py +++ b/plugins/video/video.py @@ -327,8 +327,11 @@ def __est_size(self, full_path, tsn='', mime=''): vInfo = transcode.video_info(full_path) if not mime: compat = False - for mimet in ['video/mp4', 'video/bip', 'video/mpeg', - 'video/x-tivo-mpeg-ts']: + mimetypes = ['video/x-tivo-mpeg'] + if self.use_ts(tsn, full_path): + mimetypes = ['video/x-tivo-mpeg', 'video/x-tivo-mpeg-ts'] + + for mimet in mimetypes: compat = transcode.tivo_compatible_video(vInfo, tsn, mimet)[0] if compat: break @@ -336,7 +339,7 @@ def __est_size(self, full_path, tsn='', mime=''): compat = transcode.tivo_compatible_video(vInfo, tsn, mime)[0] if compat: - return os.path.getsize(unicode(full_path, 'utf-8')) + return int(os.path.getsize(unicode(full_path, 'utf-8'))*1.1) else: # Must be re-encoded audioBPS = config.getMaxAudioBR(tsn) * 1000