def dar(self): if self.trackEntry.video: if (self.trackEntry.video.displayWidth and self.trackEntry.video.displayHeight): return QQ(self.trackEntry.video.displayWidth, self.trackEntry.video.displayHeight) return QQ(self.trackEntry.video.pixelWidth, self.trackEntry.video.pixelHeight)
def fgdata(self, index, obj): diff = self.editdata(index, obj) if diff is not None: if abs(diff) >= 2 / QQ(24000 / 1001): return self.white elif abs(diff) >= 1 / QQ(24000 / 1001): return self.red elif abs(diff) < 0.2 / QQ(24000 / 1001): return self.blue return self.fgcolor
def bgdata(self, index, obj): diff = self.editdata(index, obj) if diff is not None and abs(diff) >= 2 / QQ(24000 / 1001): return self.red return self.bgcolor
def __setattr__(self, attr, value): x265paramname = attr.rstrip("_").replace("_", "-") if value is None and x265paramname in x265params: self.x265params[x265paramname] = value elif ((isinstance(value, str) and x265paramname in x265strparams) or (isinstance(value, int) and not isinstance(value, bool) and x265paramname in x265intparams) or (isinstance(value, float) and x265paramname in x265floatparams) or (isinstance(value, bool) and x265paramname in x265boolparams) or (isinstance(value, QQ) and x265paramname in x265rationalparams)): self.x265params[x265paramname] = value elif x265paramname in x265rationalparams: self.x265params[x265paramname] = QQ(value) elif x265paramname in x265floatparams: self.x265params[x265paramname] = float(value) elif x265paramname in x265intparams: self.x265params[x265paramname] = int(value) elif x265paramname in x265boolparams: self.x265params[x265paramname] = bool(value) elif x265paramname in x265strparams: self.x265params[x265paramname] = str(value) return object.__setattr__(self, attr, value)
def _sendframe(self): if self._noMoreFrames: raise StopIteration try: frame = next(self._framesource) except StopIteration: self._success = True return self.stop() if isinstance(frame, av.AudioFrame): frame = aconvert(frame, self._encoder.format.name) frame.pts = None else: frame.pts = int(10**9*frame.pts*frame.time_base) frame.time_base = QQ(1, 10**9) if callable(self._notifyencode): self._notifyencode(frame) packets = self._encoder.encode(frame) self._packets.extend(packets) if frame is None: self.close() return len(packets)
def __init__(self, codec, framesource, notifyencode=None, logfile=None, **kwargs): if isinstance(codec, av.Codec): if not codec.is_encoder: raise TypeError("Codec object is not an encoder.") self._encoder = codec.create() else: self._encoder = av.CodecContext.create(codec, "w") for key, value in kwargs.items(): if value is not None: setattr(self._encoder, key, value) if "time_base" not in kwargs: self._encoder.time_base = QQ(1, 10**9) self._framesource = framesource self._packets = deque() self._logfile = logfile self._notifyencode = notifyencode self._isopen = False self._packetsEncoded = 0 self._streamSize = 0 self._noMoreFrames = False self._success = False self._pts = 0
def __init__(self, src_start, src_fps=QQ(24000, 1001), pulldown=None, pulldownoffset=0, yblend=False, uvblend=False, prev=None, next=None, framecount=None, parent=None): super().__init__(src_start=src_start, prev=prev, next=next, parent=parent) self.src_fps = src_fps self.yblend = bool(yblend) self.uvblend = bool(uvblend) self.pulldown = str(pulldown).upper() if pulldown is not None else None if self.pulldown is not None: self.pulldownoffset = int(pulldownoffset) % self.old_blksize else: self.pulldownoffset = 0 self._reverse_mapping = None self._reverse_mapping_head = None self._reverse_mapping_tail = None self._forward_matrix_blended = None self._reverse_matrix_blended = None self._reverse_matrix_blended_head = None self._reverse_matrix_blended_tail = None self._framecount = framecount
def __init__(self, rate=QQ(24000, 1001), prev=None, next=None, parent=None): super().__init__(prev=prev, next=next, parent=parent) self.rate = rate
def seteditdata(self, index, obj, value): K, zone = self.filter.zoneAt(obj) if value is None: zone.src_fps = QQ(24000, 1001) else: zone.src_fps = value
def setcheckstate(self, index, obj, data): if obj == 0: return if self.checkstate(index, obj): self.filter.removeZoneAt(obj) else: self.filter.insertZoneAt(obj, src_fps=QQ(24000, 1001))
def defaultDuration(self): if isinstance(self.trackEntry.defaultDuration, int): q, r = divmod(self.trackEntry.defaultDuration, 1000) if r % 111 in (0, 1): """Possible repeating digit. Will assume as such.""" return 1000 * q + r + QQ(r // 111, 9) return self.trackEntry.defaultDuration
def autoFrameRate(self, table): isdefault = (len(self.filter) == 1 and self.filter.start.src_fps == QQ(24000, 1001) and self.filter.start.pulldown is None) if isdefault or QMessageBox.question( table, "Auto Frame Rate", "Current zone settings will be lost! Do you wish to proceed?", QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes: self.filter.autoframerate() table.contentsModified.emit()
def setModelData(self, editor, model, index): value = editor.text() if regex.match(r"^\d+/\d+$", value): value = QQ(value) elif regex.match(r"^\d+$", value): value = int(value) else: value = float(value) model.setData(index, value, Qt.EditRole)
def defaultDuration(self): if self.encoder: if self.type == "audio": if self.codec in ("aac", "libfdk_aac"): return QQ(1024, self.rate)/self.time_base elif self.codec == "ac3": return QQ(1536, self.rate)/self.time_base elif self.codec == "dca": return QQ(512, self.rate)/self.time_base elif self.codec == "truehd": return QQ(40, self.rate)/self.time_base elif self.filters and self.filters.defaultDuration is not None: return (self.filters.defaultDuration * self.filters.time_base/self.time_base) source = self.source if source is not None and source.defaultDuration is not None: return source.defaultDuration*source.time_base/self.time_base
def handleRateChanged(self, value): if not regex.match(r"^(\d+(?:\.\d+)?|\.\d+|\d+/\d+)$", value): return if regex.match(r"^\d+/\d+$", value): value = QQ(value) elif regex.match(r"^\d+$", value): value = int(value) else: value = float(value) self.filtercopy.rate = value self.isModified()
def setSar(self, sar): if not regex.match(r"^(\d+(?:\.\d+)?|\.\d+|\d+/\d+)$", sar): return if regex.match(r"^\d+/\d+$", sar): sar = QQ(sar) elif regex.match(r"^\d+$", sar): sar = int(sar) else: sar = float(sar) self.filtercopy.sar = sar self.isModified()
def updateChildGeometry(self, size): if (self.inputPreviewWindow.framesource is not None and self.outputPreviewWindow.framesource is not None): inputDar = self.inputPreviewWindow.dar outputDar = self.outputPreviewWindow.dar if (isinstance(inputDar, (QQ, int)) and isinstance(outputDar, (QQ, int))): ratio = QQ(inputDar, outputDar) self.layout().setColumnStretch(0, ratio.numerator) self.layout().setColumnStretch(1, ratio.denominator) else: ratio = inputDar / outputDar self.layout().setColumnStretch(0, int(1000 * ratio)) self.layout().setColumnStretch(1, 1000)
def __init__(self, zones=[], time_base=QQ(1, 10**9), start_pts_time=0, prev=None, next=None, notify_input=None, notify_output=None): super().__init__(zones=zones, prev=prev, next=next, notify_input=notify_input, notify_output=notify_output) self.time_base = time_base self._start_pts_time = start_pts_time self._columns = None
def autoframerate(self): while len(self) > 1: self.removeZoneAt(self[1].src_start) dt = numpy.diff(self.prev.pts) n = 0 fr = None while n < len(dt) - 1: if abs(dt[n:n + 2] - numpy.array([50, 33])).max() <= 1: if fr != QQ(24000, 1001): fr = QQ(24000, 1001) if n == 0: self.start.src_fps = fr self.start.pulldown = None else: self.insertZoneAt(n, src_fps=fr) n += 2 while (n < len(dt) - 1 and abs(dt[n:n + 2] - numpy.array([50, 33])).max() <= 1): n += 2 elif abs(dt[n] - 33) <= 1: if fr != QQ(30000, 1001): fr = QQ(30000, 1001) if n == 0: self.start.src_fps = fr self.start.pulldown = None else: self.insertZoneAt(n, src_fps=fr) n += 1 while n < len(dt) - 1 and abs(dt[n] - 33).max() <= 1: n += 1 elif fr != QQ(24000, 1001): fr = QQ(24000, 1001) if n == 0: self.start.src_fps = fr self.start.pulldown = None else: self.insertZoneAt(n, src_fps=fr) n += 1 else: n += 1
def __init__(self, duration, title="Untitled", framecount=None, time_base=QQ(1 / 1000), keep=7200, font=QFont("DejaVu Serif", 8), parent=None): super(TrackStats, self).__init__(parent) self.setHidden(True) self.framecount = framecount self.duration = duration self.timestamps = [] self.sizes = [] self.byteswritten = 0 self.packetsreceived = 0 self.lastpts = 0 self.keep = keep self.time_base = time_base self.font = font self.titleLabel = QLabel(title, self) self.titleLabel.setFont(self.font) self.frameCountLabel = QLabel(self) self.sizeLabel = QLabel(self) self.bitrateLabel = QLabel(self) self.timestampLabel = QLabel(self) self.etaLabel = QLabel(self) self.etaLabel.setHidden(True) self.frameCountLabel.setFont(self.font) self.sizeLabel.setFont(self.font) self.bitrateLabel.setFont(self.font) self.timestampLabel.setFont(self.font) self.etaLabel.setFont(self.font) self.reset()
def _convert_dict(d, stripnones=True): for oldkey in list(d.keys()): newkey = oldkey.rstrip("_").replace("_", "-") if newkey not in x265params: raise ValueError(f"Not a valid x265 parameter: {newkey}") value = d.pop(oldkey) if value is None: if not stripnones: d[newkey] = None continue if ((isinstance(value, str) and newkey in x265strparams) or (isinstance(value, int) and not isinstance(value, bool) and newkey in x265intparams) or (isinstance(value, float) and newkey in x265floatparams) or (isinstance(value, bool) and newkey in x265boolparams) or (isinstance(value, QQ) and newkey in x265rationalparams)): d[newkey] = value elif newkey in x265rationalparams: d[newkey] = QQ(value) elif newkey in x265floatparams: d[newkey] = float(value) elif newkey in x265intparams: d[newkey] = int(value) elif newkey in x265boolparams: d[newkey] = bool(value) elif newkey in x265strparams: d[newkey] = str(value)
def _fromBytes(cls, data, parent=None): numdata, dendata = parseVints(data) return cls(QQ( fromVint(numdata) - 2**(7 * len(numdata) - 1), fromVint(dendata)), parent=parent)
def __setstate__(self, state): self.rate = state.get("rate", QQ(24000, 1001)) super().__setstate__(state)
def sar(self): if self.trackEntry.video: return self.dar / QQ(self.trackEntry.video.pixelWidth, self.trackEntry.video.pixelHeight)
def __setstate__(self, state): self.time_base = state.get("time_base", QQ(1, 10**9)) super().__setstate__(state)
def __init__(self, segments=[], time_base=QQ(1, 10**9), **kwargs): self.segments = list(map(tryweakref, segments)) self.time_base = time_base super().__init__(**kwargs)
def time_base(self): return QQ(1, 10**9)
def setZoneValues(table, zone, src_fps=QQ(24000, 1001), pulldown=None, pulldownoffset=0): zone.src_fps = src_fps zone.pulldown = pulldown zone.pulldownoffset = pulldownoffset table.contentsModified.emit()
def __init__( self, framesource, # Pyav encoder context options width, height, sample_aspect_ratio=1, rate=QQ(24000, 1001), pix_fmt="yuv420p", time_base=None, preset=None, tune=None, forced_idr=None, # Quality, rate control and rate distortion options bitrate=None, qp=None, crf=None, lossless=None, # python-transcode notifyencode=None, logfile=None, **x265params): self._rate = rate _convert_dict(x265params) kwargs = dict(width=width, height=height, sample_aspect_ratio=sample_aspect_ratio, rate=rate, pix_fmt=pix_fmt, time_base=time_base) options = {} if crf: options["crf"] = f"{crf:.2f}" print(f" crf={crf:.2f}", file=logfile) elif bitrate: kwargs["bit_rate"] = int(1000 * bitrate) print(f" bitrate={bitrate:,.2f}kbps", file=logfile) elif qp: x265params["qp"] = qp print(f" qp={qp}", file=logfile) elif lossless: x265params["lossless"] = True print(" lossless", file=logfile) if preset: options["preset"] = preset print(f" preset={preset}", file=logfile) if tune: options["tune"] = tune print(f" tune={tune}", file=logfile) self._rfd, self._wfd = os.pipe() self._rf = os.fdopen(self._rfd, "r") self._wf = os.fdopen(self._wfd, "w") flag = fcntl.fcntl(self._rfd, fcntl.F_GETFL) fcntl.fcntl(self._rfd, fcntl.F_SETFL, flag | os.O_NONBLOCK) if rate: x265params["fps"] = rate x265params = OrderedDict([("preset", None), ("tune", None), ("pass", None), ("stats", None)], **x265params) x265params["csv"] = f"/dev/fd/{self._wfd}" x265params["csv-log-level"] = 1 L = [] for key, value in x265params.items(): if value is True: L.append(f"{key}=1") print(f" {key}", file=logfile) elif value is False: L.append(f"{key}=0") print(f" no-{key}", file=logfile) elif isinstance(value, str): L.append(f"{key}={quote(value)}") if key != "csv": print(f" {key}={value}", file=logfile) elif isinstance(value, QQ): if key in x265colonrationalparams: L.append(f"{key}={value.numerator}\\:{value.denominator}") if key in x265slashrationalparams: L.append(f"{key}={value.numerator}/{value.denominator}") print(f" {key}={value.numerator}/{value.denominator}", file=logfile) elif value is not None: L.append(f"{key}={value}") if key != "csv-log-level": print(f" {key}={value}", file=logfile) if L: options["x265-params"] = ":".join(L) if options: kwargs["options"] = options self._statspattern = (r"(?P<encodeorder>\d+)," r"\s+(?P<pict_type>[IBP])-SLICE," r"\s*(?P<displayorder>\d+)," r"\s*(?P<qp>\d+(?:\.\d+)?)," r"\s*(?P<bits>\d+)," r"\s*(?P<scenecut>[01]),") self._statsbuffer = "" self._pktCount = {s: 0 for s in "IBP"} self._pktSizeSums = {s: 0 for s in "IBP"} self._pktQPSums = {s: 0 for s in "IBP"} self._pts = {} self._pass = x265params.get("pass") self._stats = x265params.get("stats") super().__init__("libx265", framesource, notifyencode=notifyencode, logfile=logfile, **kwargs)
def createContextMenu(self, table, index, obj): menu = ZoneCol.createContextMenu(self, table, index, obj) menu.addSeparator() J, zone = self.filter.zoneAt(obj) menu.addAction(QAction( "&AA (24000/1001)", table, triggered=partial(self.setZoneValues, table=table, zone=zone))) menu.addAction(QAction( "AA (&30000/1001)", table, triggered=partial( self.setZoneValues, table=table, zone=zone, src_fps=QQ(30000, 1001)))) menu.addAction(QAction( "A&B (24000/1001)", table, triggered=partial( self.setZoneValues, table=table, zone=zone, pulldown="AB"))) menu.addSeparator() menu.addAction(QAction( "AAABBCCCDD(&0) (30000/1001)", table, triggered=partial( self.setZoneValues, table=table, zone=zone, src_fps=QQ(30000, 1001), pulldown="AAABBCCCDD", pulldownoffset=(zone.src_start - obj) % 5))) menu.addAction(QAction( "AAABBCCCDD(&1) (30000/1001)", table, triggered=partial( self.setZoneValues, table=table, zone=zone, src_fps=QQ(30000, 1001), pulldown="AAABBCCCDD", pulldownoffset=(1 + zone.src_start - obj) % 5))) menu.addAction(QAction( "AAABBCCCDD(&2) (30000/1001)", table, triggered=partial( self.setZoneValues, table=table, zone=zone, src_fps=QQ(30000, 1001), pulldown="AAABBCCCDD", pulldownoffset=(2 + zone.src_start - obj) % 5))) menu.addAction(QAction( "AAABBCCCDD(&3) (30000/1001)", table, triggered=partial( self.setZoneValues, table=table, zone=zone, src_fps=QQ(30000, 1001), pulldown="AAABBCCCDD", pulldownoffset=(3 + zone.src_start - obj) % 5))) menu.addAction(QAction( "AAABBCCCDD(&4) (30000/1001)", table, triggered=partial( self.setZoneValues, table=table, zone=zone, src_fps=QQ(30000, 1001), pulldown="AAABBCCCDD", pulldownoffset=(4 + zone.src_start - obj) % 5))) menu.addSeparator() menu.addAction(QAction( "AAABBCC&DDD (30000/1001)", table, triggered=partial( self.setZoneValues, table=table, zone=zone, src_fps=QQ(30000, 1001), pulldown="AAABBCCDDD", pulldownoffset=0))) menu.addAction(QAction( "AAABBCCDD&E (30000/1001)", table, triggered=partial( self.setZoneValues, table=table, zone=zone, src_fps=QQ(30000, 1001), pulldown="AAABBCCDDE", pulldownoffset=0))) menu.addSeparator() menu.addAction(QAction( "Auto Frame Rate", table, triggered=partial(self.autoFrameRate, table=table))) return menu