def get_size_ffmpeg(self, ffmpeg_path, fname): cmd = [ffmpeg_path, '-i', fname] # Windows and other OS buffer 4096 and ffmpeg can output more # than that. err_tmp = tempfile.TemporaryFile() ffmpeg = subprocess.Popen(cmd, stderr=err_tmp, stdout=subprocess.PIPE, stdin=subprocess.PIPE) # wait configured # of seconds: if ffmpeg is not back give up limit = config.getFFmpegWait() if limit: for i in xrange(limit * 20): time.sleep(.05) if not ffmpeg.poll() == None: break if ffmpeg.poll() == None: kill(ffmpeg) return False, 'FFmpeg timed out' else: ffmpeg.wait() err_tmp.seek(0) output = err_tmp.read() err_tmp.close() x = ffmpeg_size.search(output) if x: width = int(x.group(1)) height = int(x.group(2)) else: return False, "Couldn't parse size" return True, (width, height)
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) return 0 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') mtime = os.stat(fname).st_mtime if cache: if inFile in info_cache and info_cache[inFile][0] == mtime: debug('CACHE HIT! %s' % inFile) return info_cache[inFile][1] vInfo['Supported'] = True ffmpeg_path = config.get_bin('ffmpeg') if not ffmpeg_path: if os.path.splitext(inFile)[1].lower() not in ['.mpg', '.mpeg', '.vob', '.tivo']: vInfo['Supported'] = False vInfo.update({'millisecs': 0, 'vWidth': 704, 'vHeight': 480, 'rawmeta': {}}) if cache: info_cache[inFile] = (mtime, vInfo) return vInfo if mswindows: fname = fname.encode('iso8859-1') cmd = [ffmpeg_path, '-i', fname] # Windows and other OS buffer 4096 and ffmpeg can output more than that. err_tmp = tempfile.TemporaryFile() ffmpeg = subprocess.Popen(cmd, stderr=err_tmp, stdout=subprocess.PIPE, stdin=subprocess.PIPE) # wait configured # of seconds: if ffmpeg is not back give up limit = config.getFFmpegWait() if limit: for i in xrange(limit * 20): time.sleep(.05) if not ffmpeg.poll() == None: break if ffmpeg.poll() == None: kill(ffmpeg) vInfo['Supported'] = False if cache: info_cache[inFile] = (mtime, vInfo) return vInfo else: ffmpeg.wait() err_tmp.seek(0) output = err_tmp.read() err_tmp.close() debug('ffmpeg output=%s' % output) attrs = {'container': r'Input #0, ([^,]+),', 'vCodec': r'Video: ([^, ]+)', # video codec 'aKbps': r'.*Audio: .+, (.+) (?:kb/s).*', # audio bitrate 'aCodec': r'.*Audio: ([^, ]+)', # audio codec 'aFreq': r'.*Audio: .+, (.+) (?:Hz).*', # audio frequency 'mapVideo': r'([0-9]+[.:]+[0-9]+).*: Video:.*'} # video mapping for attr in attrs: rezre = re.compile(attrs[attr]) x = rezre.search(output) if x: vInfo[attr] = x.group(1) else: if attr in ['container', 'vCodec']: vInfo[attr] = '' vInfo['Supported'] = False else: vInfo[attr] = None debug('failed at ' + attr) rezre = re.compile(r'.*Audio: .+, (?:(\d+)(?:(?:\.(\d).*)?(?: channels.*)?)|(stereo|mono)),.*') x = rezre.search(output) if x: if x.group(3): if x.group(3) == 'stereo': vInfo['aCh'] = 2 elif x.group(3) == 'mono': vInfo['aCh'] = 1 elif x.group(2): vInfo['aCh'] = int(x.group(1)) + int(x.group(2)) elif x.group(1): vInfo['aCh'] = int(x.group(1)) else: vInfo['aCh'] = None debug('failed at aCh') else: vInfo['aCh'] = None debug('failed at aCh') rezre = re.compile(r'.*Video: .+, (\d+)x(\d+)[, ].*') x = rezre.search(output) if x: vInfo['vWidth'] = int(x.group(1)) vInfo['vHeight'] = int(x.group(2)) else: vInfo['vWidth'] = '' vInfo['vHeight'] = '' vInfo['Supported'] = False debug('failed at vWidth/vHeight') rezre = re.compile(r'.*Video: .+, (.+) (?:fps|tb\(r\)|tbr).*') x = rezre.search(output) if x: vInfo['vFps'] = x.group(1) if '.' not in vInfo['vFps']: vInfo['vFps'] += '.00' # Allow override only if it is mpeg2 and frame rate was doubled # to 59.94 if vInfo['vCodec'] == 'mpeg2video' and vInfo['vFps'] != '29.97': # First look for the build 7215 version rezre = re.compile(r'.*film source: 29.97.*') x = rezre.search(output.lower()) if x: debug('film source: 29.97 setting vFps to 29.97') vInfo['vFps'] = '29.97' else: # for build 8047: rezre = re.compile(r'.*frame rate differs from container ' + r'frame rate: 29.97.*') debug('Bug in VideoReDo') x = rezre.search(output.lower()) if x: vInfo['vFps'] = '29.97' else: vInfo['vFps'] = '' vInfo['Supported'] = False debug('failed at vFps') durre = re.compile(r'.*Duration: ([0-9]+):([0-9]+):([0-9]+)\.([0-9]+),') d = durre.search(output) if d: vInfo['millisecs'] = ((int(d.group(1)) * 3600 + int(d.group(2)) * 60 + int(d.group(3))) * 1000 + int(d.group(4)) * (10 ** (3 - len(d.group(4))))) else: vInfo['millisecs'] = 0 # get bitrate of source for tivo compatibility test. rezre = re.compile(r'.*bitrate: (.+) (?:kb/s).*') x = rezre.search(output) if x: vInfo['kbps'] = x.group(1) else: # Fallback method of getting video bitrate # Sample line: Stream #0.0[0x1e0]: Video: mpeg2video, yuv420p, # 720x480 [PAR 32:27 DAR 16:9], 9800 kb/s, 59.94 tb(r) rezre = re.compile(r'.*Stream #0\.0\[.*\]: Video: mpeg2video, ' + r'\S+, \S+ \[.*\], (\d+) (?:kb/s).*') x = rezre.search(output) if x: vInfo['kbps'] = x.group(1) else: vInfo['kbps'] = None debug('failed at kbps') # get par. rezre = re.compile(r'.*Video: .+PAR ([0-9]+):([0-9]+) DAR [0-9:]+.*') x = rezre.search(output) if x and x.group(1) != "0" and x.group(2) != "0": vInfo['par1'] = x.group(1) + ':' + x.group(2) vInfo['par2'] = float(x.group(1)) / float(x.group(2)) else: vInfo['par1'], vInfo['par2'] = None, None # get dar. rezre = re.compile(r'.*Video: .+DAR ([0-9]+):([0-9]+).*') x = rezre.search(output) if x and x.group(1) != "0" and x.group(2) != "0": vInfo['dar1'] = x.group(1) + ':' + x.group(2) else: vInfo['dar1'] = None # get Audio Stream mapping. rezre = re.compile(r'([0-9]+[.:]+[0-9]+)(.*): Audio:(.*)') x = rezre.search(output) amap = [] if x: for x in rezre.finditer(output): amap.append((x.group(1), x.group(2) + x.group(3))) else: amap.append(('', '')) debug('failed at mapAudio') vInfo['mapAudio'] = amap vInfo['par'] = None # get Metadata dump (newer ffmpeg). lines = output.split('\n') rawmeta = {} flag = False for line in lines: if line.startswith(' Metadata:'): flag = True else: if flag: if line.startswith(' Duration:'): flag = False else: try: key, value = [x.strip() for x in line.split(':', 1)] try: value = value.decode('utf-8') except: if sys.platform == 'darwin': value = value.decode('macroman') else: value = value.decode('iso8859-1') rawmeta[key] = [value] except: pass vInfo['rawmeta'] = rawmeta data = metadata.from_text(inFile) for key in data: if key.startswith('Override_'): vInfo['Supported'] = True if key.startswith('Override_mapAudio'): audiomap = dict(vInfo['mapAudio']) newmap = shlex.split(data[key]) audiomap.update(zip(newmap[::2], newmap[1::2])) vInfo['mapAudio'] = sorted(audiomap.items(), key=lambda (k,v): (k,v)) elif key.startswith('Override_millisecs'): vInfo[key.replace('Override_', '')] = int(data[key]) else: vInfo[key.replace('Override_', '')] = data[key] if cache: info_cache[inFile] = (mtime, vInfo) debug("; ".join(["%s=%s" % (k, v) for k, v in vInfo.items()])) return vInfo
def get_image_ffmpeg(self, path, width, height, pshape, rot, attrs): ffmpeg_path = config.get_bin('ffmpeg') if not ffmpeg_path: return False, 'FFmpeg not found' fname = unicode(path, 'utf-8') if sys.platform == 'win32': fname = fname.encode('iso8859-1') if attrs and 'size' in attrs: result = attrs['size'] else: status, result = self.get_size_ffmpeg(ffmpeg_path, fname) if not status: return False, result if attrs: attrs['size'] = result if rot in (90, 270): oldh, oldw = result else: oldw, oldh = result width, height = self.new_size(oldw, oldh, width, height, pshape) if rot == 270: filters = 'transpose=1,' elif rot == 180: filters = 'hflip,vflip,' elif rot == 90: filters = 'transpose=2,' else: filters = '' filters += 'format=yuvj420p,' neww, newh = oldw, oldh while (neww / width >= 50) or (newh / height >= 50): neww /= 2 newh /= 2 filters += 'scale=%d:%d,' % (neww, newh) filters += 'scale=%d:%d' % (width, height) cmd = [ffmpeg_path, '-i', fname, '-vf', filters, '-f', 'mjpeg', '-'] jpeg_tmp = tempfile.TemporaryFile() ffmpeg = subprocess.Popen(cmd, stdout=jpeg_tmp, stdin=subprocess.PIPE) # wait configured # of seconds: if ffmpeg is not back give up limit = config.getFFmpegWait() if limit: for i in xrange(limit * 20): time.sleep(.05) if not ffmpeg.poll() == None: break if ffmpeg.poll() == None: kill(ffmpeg) return False, 'FFmpeg timed out' else: ffmpeg.wait() jpeg_tmp.seek(0) output = jpeg_tmp.read() jpeg_tmp.close() if 'JFIF' not in output[:10]: output = output[:2] + JFIF_TAG + output[2:] return True, output
def video_info(inFile, cache=True): vInfo = dict() fname = unicode(inFile, "utf-8") mtime = os.path.getmtime(fname) if cache: if inFile in info_cache and info_cache[inFile][0] == mtime: debug("CACHE HIT! %s" % inFile) return info_cache[inFile][1] vInfo["Supported"] = True ffmpeg_path = config.get_bin("ffmpeg") if not ffmpeg_path: if os.path.splitext(inFile)[1].lower() not in [".mpg", ".mpeg", ".vob", ".tivo", ".ts"]: vInfo["Supported"] = False vInfo.update({"millisecs": 0, "vWidth": 704, "vHeight": 480, "rawmeta": {}}) if cache: info_cache[inFile] = (mtime, vInfo) return vInfo if mswindows: fname = fname.encode("cp1252") cmd = [ffmpeg_path, "-i", fname] # Windows and other OS buffer 4096 and ffmpeg can output more than that. err_tmp = tempfile.TemporaryFile() ffmpeg = subprocess.Popen(cmd, stderr=err_tmp, stdout=subprocess.PIPE, stdin=subprocess.PIPE) # wait configured # of seconds: if ffmpeg is not back give up limit = config.getFFmpegWait() if limit: for i in xrange(limit * 20): time.sleep(0.05) if not ffmpeg.poll() == None: break if ffmpeg.poll() == None: kill(ffmpeg) vInfo["Supported"] = False if cache: info_cache[inFile] = (mtime, vInfo) return vInfo else: ffmpeg.wait() err_tmp.seek(0) output = err_tmp.read() err_tmp.close() debug("ffmpeg output=%s" % output) attrs = { "container": r"Input #0, ([^,]+),", "vCodec": r"Video: ([^, ]+)", # video codec "aKbps": r".*Audio: .+, (.+) (?:kb/s).*", # audio bitrate "aCodec": r".*Audio: ([^, ]+)", # audio codec "aFreq": r".*Audio: .+, (.+) (?:Hz).*", # audio frequency "mapVideo": r"([0-9]+[.:]+[0-9]+).*: Video:.*", } # video mapping for attr in attrs: rezre = re.compile(attrs[attr]) x = rezre.search(output) if x: vInfo[attr] = x.group(1) else: if attr in ["container", "vCodec"]: vInfo[attr] = "" vInfo["Supported"] = False else: vInfo[attr] = None debug("failed at " + attr) rezre = re.compile(r".*Audio: .+, (?:(\d+)(?:(?:\.(\d).*)?(?: channels.*)?)|(stereo|mono)),.*") x = rezre.search(output) if x: if x.group(3): if x.group(3) == "stereo": vInfo["aCh"] = 2 elif x.group(3) == "mono": vInfo["aCh"] = 1 elif x.group(2): vInfo["aCh"] = int(x.group(1)) + int(x.group(2)) elif x.group(1): vInfo["aCh"] = int(x.group(1)) else: vInfo["aCh"] = None debug("failed at aCh") else: vInfo["aCh"] = None debug("failed at aCh") rezre = re.compile(r".*Video: .+, (\d+)x(\d+)[, ].*") x = rezre.search(output) if x: vInfo["vWidth"] = int(x.group(1)) vInfo["vHeight"] = int(x.group(2)) else: vInfo["vWidth"] = "" vInfo["vHeight"] = "" vInfo["Supported"] = False debug("failed at vWidth/vHeight") rezre = re.compile(r".*Video: .+, (.+) (?:fps|tb\(r\)|tbr).*") x = rezre.search(output) if x: vInfo["vFps"] = x.group(1) if "." not in vInfo["vFps"]: vInfo["vFps"] += ".00" # Allow override only if it is mpeg2 and frame rate was doubled # to 59.94 if vInfo["vCodec"] == "mpeg2video" and vInfo["vFps"] != "29.97": # First look for the build 7215 version rezre = re.compile(r".*film source: 29.97.*") x = rezre.search(output.lower()) if x: debug("film source: 29.97 setting vFps to 29.97") vInfo["vFps"] = "29.97" else: # for build 8047: rezre = re.compile(r".*frame rate differs from container " + r"frame rate: 29.97.*") debug("Bug in VideoReDo") x = rezre.search(output.lower()) if x: vInfo["vFps"] = "29.97" else: vInfo["vFps"] = "" vInfo["Supported"] = False debug("failed at vFps") durre = re.compile(r".*Duration: ([0-9]+):([0-9]+):([0-9]+)\.([0-9]+),") d = durre.search(output) if d: vInfo["millisecs"] = (int(d.group(1)) * 3600 + int(d.group(2)) * 60 + int(d.group(3))) * 1000 + int( d.group(4) ) * (10 ** (3 - len(d.group(4)))) else: vInfo["millisecs"] = 0 # get bitrate of source for tivo compatibility test. rezre = re.compile(r".*bitrate: (.+) (?:kb/s).*") x = rezre.search(output) if x: vInfo["kbps"] = x.group(1) else: # Fallback method of getting video bitrate # Sample line: Stream #0.0[0x1e0]: Video: mpeg2video, yuv420p, # 720x480 [PAR 32:27 DAR 16:9], 9800 kb/s, 59.94 tb(r) rezre = re.compile(r".*Stream #0\.0\[.*\]: Video: mpeg2video, " + r"\S+, \S+ \[.*\], (\d+) (?:kb/s).*") x = rezre.search(output) if x: vInfo["kbps"] = x.group(1) else: vInfo["kbps"] = None debug("failed at kbps") # get par. rezre = re.compile(r".*Video: .+PAR ([0-9]+):([0-9]+) DAR [0-9:]+.*") x = rezre.search(output) if x and x.group(1) != "0" and x.group(2) != "0": vInfo["par1"] = x.group(1) + ":" + x.group(2) vInfo["par2"] = float(x.group(1)) / float(x.group(2)) else: vInfo["par1"], vInfo["par2"] = None, None # get dar. rezre = re.compile(r".*Video: .+DAR ([0-9]+):([0-9]+).*") x = rezre.search(output) if x and x.group(1) != "0" and x.group(2) != "0": vInfo["dar1"] = x.group(1) + ":" + x.group(2) else: vInfo["dar1"] = None # get Audio Stream mapping. rezre = re.compile(r"([0-9]+[.:]+[0-9]+)(.*): Audio:(.*)") x = rezre.search(output) amap = [] if x: for x in rezre.finditer(output): amap.append((x.group(1), x.group(2) + x.group(3))) else: amap.append(("", "")) debug("failed at mapAudio") vInfo["mapAudio"] = amap vInfo["par"] = None # get Metadata dump (newer ffmpeg). lines = output.split("\n") rawmeta = {} flag = False for line in lines: if line.startswith(" Metadata:"): flag = True else: if flag: if line.startswith(" Duration:"): flag = False else: try: key, value = [x.strip() for x in line.split(":", 1)] try: value = value.decode("utf-8") except: if sys.platform == "darwin": value = value.decode("macroman") else: value = value.decode("cp1252") rawmeta[key] = [value] except: pass vInfo["rawmeta"] = rawmeta data = metadata.from_text(inFile) for key in data: if key.startswith("Override_"): vInfo["Supported"] = True if key.startswith("Override_mapAudio"): audiomap = dict(vInfo["mapAudio"]) newmap = shlex.split(data[key]) audiomap.update(zip(newmap[::2], newmap[1::2])) vInfo["mapAudio"] = sorted(audiomap.items(), key=lambda (k, v): (k, v)) elif key.startswith("Override_millisecs"): vInfo[key.replace("Override_", "")] = int(data[key]) else: vInfo[key.replace("Override_", "")] = data[key] if cache: info_cache[inFile] = (mtime, vInfo) debug("; ".join(["%s=%s" % (k, v) for k, v in vInfo.items()])) return vInfo
def video_info(inFile, cache=True): vInfo = dict() fname = unicode(inFile, 'utf-8') mtime = os.path.getmtime(fname) if cache: if inFile in info_cache and info_cache[inFile][0] == mtime: debug('CACHE HIT! %s' % inFile) return info_cache[inFile][1] vInfo['Supported'] = True ffmpeg_path = config.get_bin('ffmpeg') if not ffmpeg_path: if os.path.splitext(inFile)[1].lower() not in [ '.mpg', '.mpeg', '.vob', '.tivo', '.ts' ]: vInfo['Supported'] = False vInfo.update({ 'millisecs': 0, 'vWidth': 704, 'vHeight': 480, 'rawmeta': {} }) if cache: info_cache[inFile] = (mtime, vInfo) return vInfo if mswindows: fname = fname.encode('cp1252') cmd = [ffmpeg_path, '-i', fname] # Windows and other OS buffer 4096 and ffmpeg can output more than that. err_tmp = tempfile.TemporaryFile() ffmpeg = subprocess.Popen(cmd, stderr=err_tmp, stdout=subprocess.PIPE, stdin=subprocess.PIPE) # wait configured # of seconds: if ffmpeg is not back give up limit = config.getFFmpegWait() if limit: for i in xrange(limit * 20): time.sleep(.05) if not ffmpeg.poll() == None: break if ffmpeg.poll() == None: kill(ffmpeg) vInfo['Supported'] = False if cache: info_cache[inFile] = (mtime, vInfo) return vInfo else: ffmpeg.wait() err_tmp.seek(0) output = err_tmp.read() err_tmp.close() debug('ffmpeg output=%s' % output) attrs = { 'container': r'Input #0, ([^,]+),', 'vCodec': r'Video: ([^, ]+)', # video codec 'aKbps': r'.*Audio: .+, (.+) (?:kb/s).*', # audio bitrate 'aCodec': r'.*Audio: ([^, ]+)', # audio codec 'aFreq': r'.*Audio: .+, (.+) (?:Hz).*', # audio frequency 'mapVideo': r'([0-9]+[.:]+[0-9]+).*: Video:.*' } # video mapping for attr in attrs: rezre = re.compile(attrs[attr]) x = rezre.search(output) if x: vInfo[attr] = x.group(1) else: if attr in ['container', 'vCodec']: vInfo[attr] = '' vInfo['Supported'] = False else: vInfo[attr] = None debug('failed at ' + attr) rezre = re.compile( r'.*Audio: .+, (?:(\d+)(?:(?:\.(\d).*)?(?: channels.*)?)|(stereo|mono)),.*' ) x = rezre.search(output) if x: if x.group(3): if x.group(3) == 'stereo': vInfo['aCh'] = 2 elif x.group(3) == 'mono': vInfo['aCh'] = 1 elif x.group(2): vInfo['aCh'] = int(x.group(1)) + int(x.group(2)) elif x.group(1): vInfo['aCh'] = int(x.group(1)) else: vInfo['aCh'] = None debug('failed at aCh') else: vInfo['aCh'] = None debug('failed at aCh') rezre = re.compile(r'.*Video: .+, (\d+)x(\d+)[, ].*') x = rezre.search(output) if x: vInfo['vWidth'] = int(x.group(1)) vInfo['vHeight'] = int(x.group(2)) else: vInfo['vWidth'] = '' vInfo['vHeight'] = '' vInfo['Supported'] = False debug('failed at vWidth/vHeight') rezre = re.compile(r'.*Video: .+, (.+) (?:fps|tb\(r\)|tbr).*') x = rezre.search(output) if x: vInfo['vFps'] = x.group(1) if '.' not in vInfo['vFps']: vInfo['vFps'] += '.00' # Allow override only if it is mpeg2 and frame rate was doubled # to 59.94 if vInfo['vCodec'] == 'mpeg2video' and vInfo['vFps'] != '29.97': # First look for the build 7215 version rezre = re.compile(r'.*film source: 29.97.*') x = rezre.search(output.lower()) if x: debug('film source: 29.97 setting vFps to 29.97') vInfo['vFps'] = '29.97' else: # for build 8047: rezre = re.compile(r'.*frame rate differs from container ' + r'frame rate: 29.97.*') debug('Bug in VideoReDo') x = rezre.search(output.lower()) if x: vInfo['vFps'] = '29.97' else: vInfo['vFps'] = '' vInfo['Supported'] = False debug('failed at vFps') durre = re.compile(r'.*Duration: ([0-9]+):([0-9]+):([0-9]+)\.([0-9]+),') d = durre.search(output) if d: vInfo['millisecs'] = ( (int(d.group(1)) * 3600 + int(d.group(2)) * 60 + int(d.group(3))) * 1000 + int(d.group(4)) * (10**(3 - len(d.group(4))))) else: vInfo['millisecs'] = 0 # get bitrate of source for tivo compatibility test. rezre = re.compile(r'.*bitrate: (.+) (?:kb/s).*') x = rezre.search(output) if x: vInfo['kbps'] = x.group(1) else: # Fallback method of getting video bitrate # Sample line: Stream #0.0[0x1e0]: Video: mpeg2video, yuv420p, # 720x480 [PAR 32:27 DAR 16:9], 9800 kb/s, 59.94 tb(r) rezre = re.compile(r'.*Stream #0\.0\[.*\]: Video: mpeg2video, ' + r'\S+, \S+ \[.*\], (\d+) (?:kb/s).*') x = rezre.search(output) if x: vInfo['kbps'] = x.group(1) else: vInfo['kbps'] = None debug('failed at kbps') # get par. rezre = re.compile(r'.*Video: .+PAR ([0-9]+):([0-9]+) DAR [0-9:]+.*') x = rezre.search(output) if x and x.group(1) != "0" and x.group(2) != "0": vInfo['par1'] = x.group(1) + ':' + x.group(2) vInfo['par2'] = float(x.group(1)) / float(x.group(2)) else: vInfo['par1'], vInfo['par2'] = None, None # get dar. rezre = re.compile(r'.*Video: .+DAR ([0-9]+):([0-9]+).*') x = rezre.search(output) if x and x.group(1) != "0" and x.group(2) != "0": vInfo['dar1'] = x.group(1) + ':' + x.group(2) else: vInfo['dar1'] = None # get Audio Stream mapping. rezre = re.compile(r'([0-9]+[.:]+[0-9]+)(.*): Audio:(.*)') x = rezre.search(output) amap = [] if x: for x in rezre.finditer(output): amap.append((x.group(1), x.group(2) + x.group(3))) else: amap.append(('', '')) debug('failed at mapAudio') vInfo['mapAudio'] = amap vInfo['par'] = None # get Metadata dump (newer ffmpeg). lines = output.split('\n') rawmeta = {} flag = False for line in lines: if line.startswith(' Metadata:'): flag = True else: if flag: if line.startswith(' Duration:'): flag = False else: try: key, value = [x.strip() for x in line.split(':', 1)] try: value = value.decode('utf-8') except: if sys.platform == 'darwin': value = value.decode('macroman') else: value = value.decode('cp1252') rawmeta[key] = [value] except: pass vInfo['rawmeta'] = rawmeta data = metadata.from_text(inFile) for key in data: if key.startswith('Override_'): vInfo['Supported'] = True if key.startswith('Override_mapAudio'): audiomap = dict(vInfo['mapAudio']) newmap = shlex.split(data[key]) audiomap.update(zip(newmap[::2], newmap[1::2])) vInfo['mapAudio'] = sorted(audiomap.items(), key=lambda (k, v): (k, v)) elif key.startswith('Override_millisecs'): vInfo[key.replace('Override_', '')] = int(data[key]) else: vInfo[key.replace('Override_', '')] = data[key] if cache: info_cache[inFile] = (mtime, vInfo) debug("; ".join(["%s=%s" % (k, v) for k, v in vInfo.items()])) return vInfo
def get_image_ffmpeg(self, path, width, height, pshape, rot, attrs): ffmpeg_path = config.get_bin('ffmpeg') if not ffmpeg_path: return False, 'FFmpeg not found' fname = unicode(path, 'utf-8') if sys.platform == 'win32': fname = fname.encode('cp1252') if attrs and 'size' in attrs: result = attrs['size'] else: status, result = self.get_size_ffmpeg(ffmpeg_path, fname) if not status: return False, result if attrs: attrs['size'] = result if rot in (90, 270): oldh, oldw = result else: oldw, oldh = result width, height = self.new_size(oldw, oldh, width, height, pshape) if rot == 270: filters = 'transpose=1,' elif rot == 180: filters = 'hflip,vflip,' elif rot == 90: filters = 'transpose=2,' else: filters = '' filters += 'format=yuvj420p,' neww, newh = oldw, oldh while (neww / width >= 50) or (newh / height >= 50): neww /= 2 newh /= 2 filters += 'scale=%d:%d,' % (neww, newh) filters += 'scale=%d:%d' % (width, height) cmd = [ffmpeg_path, '-i', fname, '-vf', filters, '-f', 'mjpeg', '-'] jpeg_tmp = tempfile.TemporaryFile() ffmpeg = subprocess.Popen(cmd, stdout=jpeg_tmp, stdin=subprocess.PIPE) # wait configured # of seconds: if ffmpeg is not back give up limit = config.getFFmpegWait() if limit: for i in xrange(limit * 20): time.sleep(.05) if not ffmpeg.poll() == None: break if ffmpeg.poll() == None: kill(ffmpeg) return False, 'FFmpeg timed out' else: ffmpeg.wait() jpeg_tmp.seek(0) output = jpeg_tmp.read() jpeg_tmp.close() if 'JFIF' not in output[:10]: output = output[:2] + JFIF_TAG + output[2:] return True, output