def setFile(self,filePath): if self.player is not None: self.player.close() self.videoCuts=[] try: self.streamData = FFStreamProbe(filePath) self.currentPath = OSTools().getPathWithoutExtension(filePath); except: self.streamData = None self.currentPath = OSTools().getHomeDirectory() try: self.player = VideoPlayer(filePath,self.streamData) self._initSliderThread() self.player.validate() self.__initSliderTicks() self.gui.enableControls(True) #set ratio self.gui.getVideoWidget().setVideoRatio(self.streamData.getAspectRatio()) self.gui.updateWindowTitle(OSTools().getFileNameOnly(filePath)) self._asyncInitVideoViews() except: self.gui.updateWindowTitle(OSTools().getFileNameOnly(filePath)) self._gotoFrame(0) self._showCurrentFrameInfo(0) if not OSTools().fileExists(filePath): msg = "File not found" else: msg = "Invalid file format!" self.gui.showWarning(msg) self.gui.enableControls(False)
def testFrameProbe(): # m=FFStreamProbe("/home/matze/Videos/Handy-M4-Test/MOV_0296.MP4") # m=FFStreamProbe("/media/matze/Datastore/Videos/VCR/KiKA/11_13_19_25-pur+.m2t") # m=FFStreamProbe("/media/matze/Datastore/Videos/VCR/3sat_HD/11_24_07_00-nano.m2t") # m=FFStreamProbe("/media/matze/Datastore/Videos/6.Folge Craftattack.mp4") # m=FFStreamProbe("/home/matze/Videos/20051210-w50s.flv") # m=FFStreamProbe("/home/matze/Videos/recme/sample.3gp") # m=FFStreamProbe("/home/matze/Videos/handbrake.txt") # m=FFStreamProbe("/home/matze/Videos/CT.m2t") m = FFStreamProbe("/media/disk1/makemkv/title_t00.mkv") m.printCodecInfo() m.formatInfo._print() print ("getAspect2 ", m.getAspectRatio()) container = m.formatInfo print ("-------- container: -------------") print ("formats:", container.formatNames()) print ("bit-rate kb:", container.getBitRate()) print ("duration:", container.getDuration()) print ("size kb:", container.getSizeKB()) print ("is TS:", m.isTransportStream()) print ("-------- langMApping: -------------") langmap = m.getLanguageMapping() for key, index in langmap.items(): print("lang:%s @ %d" % (key, index)) print ("-------- all streams -------------") for s in m.streams: print ("##########################") print ("Index:", s.getStreamIndex()) print ("getCodec:", s.getCodec()) print ("getLanguage:", s.getLanguage()) print ("getCodecTimeBase: ", s.getCodecTimeBase()) print ("getTimeBase: ", s.getTimeBase()) print ("getAspect ", s.getAspectRatio()) print ("getFrameRate: ", s.getFrameRate()) print ("getDuration: ", s.duration()) print ("getWidth: ", s.getWidth()) print ("getHeight: ", s.getHeight()) print ("isAudio: ", s.isAudio()) print ("isVideo: ", s.isVideo())
class VideoControl(QObject): def __init__(self,mainFrame): #super(VideoControl, self).__init__() QObject.__init__(self) self.player = None self.gui = mainFrame self._frameSet=False self._initTimer() self.videoCuts=[] self.currentPath = OSTools().getHomeDirectory()#//TODO get a Video dir self.streamData = None self._vPlayer = None self.exactcut = False def _initTimer(self): self._timer = QTimer(self.gui) self._timer.timeout.connect(self._displayAutoFrame) def getTargetFile(self): if self.streamData is not None: return self.currentPath+"."+self.streamData.getTargetExtension() return self.currentPath #-- Menu handling --- def setFile(self,filePath): if self.player is not None: self.player.close() self.videoCuts=[] try: self.streamData = FFStreamProbe(filePath) self.currentPath = OSTools().getPathWithoutExtension(filePath); except: self.streamData = None self.currentPath = OSTools().getHomeDirectory() try: self.player = VideoPlayer(filePath,self.streamData) self._initSliderThread() self.player.validate() self.__initSliderTicks() self.gui.enableControls(True) #set ratio self.gui.getVideoWidget().setVideoRatio(self.streamData.getAspectRatio()) self.gui.updateWindowTitle(OSTools().getFileNameOnly(filePath)) self._asyncInitVideoViews() except: self.gui.updateWindowTitle(OSTools().getFileNameOnly(filePath)) self._gotoFrame(0) self._showCurrentFrameInfo(0) if not OSTools().fileExists(filePath): msg = "File not found" else: msg = "Invalid file format!" self.gui.showWarning(msg) self.gui.enableControls(False) def setExactCut(self,reencode): self.exactcut = Qt.Checked==reencode def addStartMarker(self): self._createVideoCutEntry(VideoCutEntry.MODE_START) self.gui._widgets.statusMessenger.say("Marker created") def addStopMarker(self): self._createVideoCutEntry(VideoCutEntry.MODE_STOP) def _createVideoCutEntry(self,mode,updateXML=True): self.sliderThread.wait() frame = self.player.getCurrentFrame() framePos = self.player.getCurrentFrameNumber() timePos = self.player.getCurrentFrameTime() cutEntry = VideoCutEntry(framePos,timePos,mode) self._addVideoCut(frame, cutEntry,updateXML) def _addVideoCut(self,frame,cutEntry,updateXML): rowIndex=len(self.videoCuts) for idx, videoEntry in enumerate(self.videoCuts): frameNbr = videoEntry.frameNumber testNbr = cutEntry.frameNumber if testNbr < frameNbr: rowIndex=idx break self.videoCuts.insert(rowIndex,cutEntry) self.gui.addCutMark(frame,cutEntry,rowIndex) if updateXML: XMLAccessor(self.currentPath).writeXML(self.videoCuts) def _asyncInitVideoViews(self): #QTimer.singleShot(10,self._gotoFrame) QTimer.singleShot(10,self._grabNextFrame) QTimer.singleShot(150, self.restoreVideoCuts) def restoreVideoCuts(self): self.sliderThread.wait() #sync with the worker cutList=XMLAccessor(self.currentPath).readXML() for cut in cutList: fbnr = cut.frameNumber self.player.setFrameAt(fbnr) mode = VideoCutEntry.MODE_STOP if cut.isStartMode(): mode = VideoCutEntry.MODE_START self._createVideoCutEntry(mode,False) self.player.setFrameAt(0) #remove/clear all cuts but leave the file untouched def clearVideoCutEntries(self): self.videoCuts=[] #clear all cuts and its persistence def purgeVideoCuts(self): self.clearVideoCutEntries() XMLAccessor(self.currentPath).clear() def removeVideoCutIndex(self,index): cut = self.videoCuts[index] self.videoCuts.remove(cut) XMLAccessor(self.currentPath).writeXML(self.videoCuts) def gotoCutIndex(self,index): cut = self.videoCuts[index] self._gotoFrame(cut.frameNumber) def saveVideo(self,path): spanns=[] block = None for cutEntry in self.videoCuts: if cutEntry.isStartMode(): if block: print "Start invalid:", cutEntry.getTimeString() else: block=[] block.append(cutEntry) print "Start ok:", cutEntry.getTimeString() else: if block: print "Stop:", cutEntry.getTimeString() block.append(cutEntry) spanns.append(block) block=None else: print "Stop ignored:", cutEntry.getTimeString() for cutmarks in spanns: print cutmarks[0].getTimeString(),"-",cutmarks[1].getTimeString() src = self.player._file #need that without extension! self.cutAsync(src,path,spanns) #-- Menu handling end --- def cutAsync(self,srcPath,targetPath,spanns): worker = LongRunningOperation(self.__makeCuts,srcPath, targetPath, spanns) self.connect(worker,worker.signalDone,self.gui.stopProgress) #start the worker thread. worker.startOperation() def __makeCuts(self,srcPath,targetPath,spanns): config = CuttingConfig(srcPath,targetPath) config.streamData = self.streamData config.reencode = self.exactcut config.messenger = self.gui._widgets.statusMessenger cutter = FFMPEGCutter(config) cutter.ensureAvailableSpace() slices = len(spanns) for index, cutmark in enumerate(spanns): t1=cutmark[0].timePos t2 = cutmark[1].timePos hasSucess = cutter.cutPart(t1, t2, index,slices) if not hasSucess: print"VC-Cut error" #TODO need a signal for error return cutter.join() ''' ''' def _initSliderThread(self): self.sliderThread = Worker(self.player.getFrameAt) self.connect(self.sliderThread,self.sliderThread.signal,self._showFrame) #we want 1 minute per single step def __initSliderTicks(self): videoInfo= self.streamData.getVideoStream() fps = videoInfo.getFrameRate() if self.player.framecount > 0: ratio = round(LayoutWindow.SLIDER_RESOLUTION*60*fps/self.player.framecount,1) self.gui.setSliderTicks(ratio) self.gui.setDialResolution(fps) self.gui.setGotoMaximum(self.player.framecount) self._frameSet=False #connected to slider-called whenever position is changed. def sliderMoved(self,pos): if self.player is None or not self.player.isValid(): self.gui.syncSliderPos(0) if not self._frameSet: frameNumber = round(self.player.framecount/LayoutWindow.SLIDER_RESOLUTION*pos,0) self.__dispatchShowFrame(frameNumber) self._frameSet=False #display Frame with syncing the slider pos. def _gotoFrame(self,frameNumber=0): self._frameSet=True if self.player.framecount < 1: return; if frameNumber == 0: sliderPos=0 else: sliderPos= int(frameNumber*LayoutWindow.SLIDER_RESOLUTION/self.player.framecount) self.gui.syncSliderPos(sliderPos) self.__dispatchShowFrame(frameNumber) def __dispatchShowFrame(self,frameNumber): if self._vPlayer is None: self.sliderThread.showFrame(frameNumber) #connected to the dial def dialChanged(self,pos): if self.player is None or pos == 0: self._timer.stop() return self._dialStep = pos #self._dialStep = 1 ts=(1/self.player.fps)*2500 #print "dial:",pos, " time:",ts self._timer.start(ts) #called by timer on dial change... def _displayAutoFrame(self): if self.player is None or not self.player.isValid(): return self.sliderThread.wait()#No concurrency with worker! self._frameSet = True frameNumber = max(0,self.player.getCurrentFrameNumber()+self._dialStep); sliderPos= int(frameNumber*LayoutWindow.SLIDER_RESOLUTION/self.player.framecount) self.gui.syncSliderPos(sliderPos) aFrame = self.player.getFrameAt(frameNumber) self._showFrame(aFrame) # self._gotoFrame(frameNumber) self._frameSet = False #called by worker ... def _showFrame(self,aFrame): self._videoUI().showFrame(aFrame) x = self.player.getCurrentFrameNumber() self._showCurrentFrameInfo(x) def _displayFrame(self,frameNumber): self._videoUI().showFrame(self.player.getFrameAt(frameNumber)) def _videoUI(self): return self.gui.getVideoWidget() def _showCurrentFrameInfo(self,frameNumber): timeinfo = self.player.getCurrentFrameTime() #basket = "%02d.%03i" %(timeinfo.seconds,timeinfo.microseconds/1000) out = "Frame: %s Time: %s max: %s" %(str(frameNumber), str(timeinfo),str(self.player.framecount)) #TODO: Pass 3 values for 3 widgets.... self.gui.showInfo(out) def toggleVideoPlay(self): if self.streamData is None: return False if self._vPlayer is None: return self.__playVideo() return self.__stopVideo() #TODO Warning, if it runs, Worker may NOT be used! def __playVideo(self): self._vPlayer = QTimer(self.gui) self._vPlayer.timeout.connect(self._grabNextFrame) #50 ms if 25 fps and 25 if 50fps fRate=(1/self.player.fps)*1250 self._vPlayer.start(fRate) return True def __stopVideo(self): self._vPlayer.stop() self._vPlayer = None self._frameSet = False return False def _grabNextFrame(self): self._frameSet = True frame= self.player.grabNextFrame() if frame is not None: self._videoUI().showFrame(frame) frameNumber = self.player.getCurrentFrameNumber() sliderPos= int(frameNumber*LayoutWindow.SLIDER_RESOLUTION/self.player.framecount) self._showCurrentFrameInfo(frameNumber) self.gui.syncSliderPos(sliderPos) else: self.gui.setVideoPlayerControls(False) self.player.framecount = self.player.getCurrentFrameNumber() self.__stopVideo()