Пример #1
0
def verify_file(orig_filename, filename):
    name, ext = os.path.splitext(orig_filename)
    ext = ext.lower()
    if ext in ('.jpg', '.jpeg'):
        im = Image.open(filename)
        w, h = im.size
        if w > 1920 or h > 1080:
            raise AssetError("image too big: %dx%d" % (w, h))
        if w < 128 or h < 128:
            raise AssetError("image too small: %dx%d" % (w, h))
        if im.mode != 'RGB':
            raise AssetError("invalid image mode: %s" % im.mode)
        return Asset.TYPE_IMAGE, make_thumb(im)
    elif ext in ('.mp4', ):
        vs = VideoStream(filename)
        if vs.codec_name != 'h264':
            raise AssetError("invalid codec %s" % (vs.codec_name, ))
        w, h = vs.frame_width, vs.frame_height
        duration = vs.duration
        log.info("video info: %dx%d (%fs)" % (w, h, duration))
        if w > 1920 or h > 1080:
            raise AssetError("video too big: %dx%d" % (w, h))
        if w < 128 or h < 128:
            raise AssetError("video too small: %dx%d" % (w, h))
        if duration < 1:
            raise AssetError("video too short: %fs" % (duration, ))
        if duration > 10.5:
            raise AssetError("video too long: %fs" % (duration, ))
        frame = vs.get_frame_no(3)
        im = frame.image()
        return Asset.TYPE_VIDEO, make_thumb(im)
    else:
        raise AssetError("invalid asset file extension")
Пример #2
0
def test_frames_getting():
    from ffvideo import VideoStream

    vs = VideoStream(v0)

    f1 = vs.current() # first frame
    f2 = vs.next()
    assert f2.timestamp > f1.timestamp

    f = vs[0] # first frame
    assert f.frameno == 0
    f = vs.get_frame_no(100)
#    f = vs[100]
#    assert f.frameno == 100

    f = vs.get_frame_no(100)
    f = vs.get_frame_at_sec(1)
    assert f.timestamp - 1 < 0.1
    f = vs.get_frame_at_pts(133000)

    assert f.width == vs.frame_width
    assert f.height == vs.frame_height
    assert f.mode == vs.frame_mode
Пример #3
0
def test_frames_getting():
    from ffvideo import VideoStream

    vs = VideoStream(v0)

    f1 = vs.current()  # first frame
    f2 = vs.next()
    assert f2.timestamp > f1.timestamp

    f = vs[0]  # first frame
    assert f.frameno == 0
    f = vs.get_frame_no(100)
    #    f = vs[100]
    #    assert f.frameno == 100

    f = vs.get_frame_no(100)
    f = vs.get_frame_at_sec(1)
    assert f.timestamp - 1 < 0.1
    f = vs.get_frame_at_pts(133000)

    assert f.width == vs.frame_width
    assert f.height == vs.frame_height
    assert f.mode == vs.frame_mode
Пример #4
0
class Movie(QtCore.QObject):
    """This class represent the video data stream"""

    frameChanged = QtCore.pyqtSignal()
    endOfVideo = QtCore.pyqtSignal()
    
    def __init__(self, fileName=None):
        """Initialize the video stream and open the video file if a fileName is provided.
        
        :param filename: a string containing the name of the file to be opened.
        """
        self.rawBuffer=None
        self.source=None
        super(Movie, self).__init__()
        if(fileName is not None):
            self.setMovie(fileName)
        self.timer = None
        self.frame = None
        self.isPlaying = False
        self.frameRate = 0
        self.frameNumber = 0
    
    def reset(self):
        """Reset the movie object. Remove the source."""
        self.rawBuffer=None
        self.source=None
        self.timer = None
        self.frame = None
        self.isPlaying = False
        self.frameRate = 0
        self.frameNumber = 0
    def setMovie(self, fileName):
        """Open a video file.
        
        :param filename: a string containing the name of the file to be opened.
            
        :raise: TypeError: The fileName is not a string.
        """
        if(isinstance(fileName, basestring)):
            self.fileName =  u''.join(fileName).encode('utf-8')
            self.source = VideoStream(self.fileName)
        else: 
            raise TypeError('fileName must be a string')
        
        self.frameRate = self.source.framerate
        self.frameNumber = self.source.duration*1000/self.source.framerate
        self.timer = QtCore.QTimer()
        self.timer.setInterval(1000.0/self.frameRate)
        self.timer.setSingleShot(False)
        self.timer.timeout.connect(self.frameMustChange)
    
    def resetMovie(self):
        """Reset the video stream."""
        self.source = VideoStream(self.fileName)
        
    def play(self): 
        """Start to read the video stream."""
        self.isPlaying = True
        self.timer.start()
    
    def pause(self):
        """Pause the reading of the video stream."""
        self.isPlaying = False
        self.timer.stop()
        
    def frameMustChange(self):
        """Slot called when it is time to load the next frame.
        
        :raise: Exception: The file cannot be read because the codec is not supported or the video is compressed.
        """
        self.readNextFrame()
    
    def toggleState(self):
        """Toggle between playing and pausing the video."""
        if(self.isPlaying==True):
            self.pause()
        else:
            self.play()
            
    def jumpToFrame(self, position):
        """Modify the position in the video.
        
        :param position: a value between 0 and 1 corresponding to the position in the video. 0 is the beginning and 1 is the end.
        """
        if(position>1.0):
            position = 1.0
        elif(position<0.001):
            position = 0.001
        frame = self.source.get_frame_at_sec(position*self.source.duration).ndarray
        return frame
    
    def readNextFrame(self):
        """Load the next frame.
        :raise: Exception: The file cannot be read because the codec is not supported or the video is compressed.
        """
        try:
            self.rawBuffer = self.source.next().ndarray()
        except ffvideo.NoMoreData:
            self.isPlaying = False
            self.pause()
            self.rawBuffer = None
            self.endOfVideo.emit()
        self.frameChanged.emit()
        
    def readNCFrame(self, number):
        """Load the next frame.
        :raise: Exception: The file cannot be read because the codec is not supported or the video is compressed.
        """
        position = self.source.current().frameno
        try:
                self.rawBuffer = self.source.get_frame_no(position+number).ndarray()
        except ffvideo.NoMoreData:
            self.isPlaying = False
            self.pause()
            self.endOfVideo.emit()
        if(self.source.current().frameno>=self.source.duration*self.source.framerate):
            self.isPlaying = False
            self.pause()
            self.endOfVideo.emit()
        self.frameChanged.emit()

        
    def currentPositionRatio(self):
        """Returns the position in the video.
        
        :return: a value between 0 and 1 representing the position in the video. 0 is the beginning and 1 is the end.
        """
        if(self.source is not None and self.source.current() is not None):
            result = self.source.current().timestamp/self.source.duration
            if(result>1.0):
                return 1.0
            elif(result<0.0):
                return 0.0
            else:
                return result
        else:
            return 1.0
    
    def getFrameNumber(self):
        """Returns the number of frame in the video.
        
        :return: An integer representing the number of frame in the video.
        """
        return int(self.source.duration*self.source.framerate)
    
    def getFrameSize(self):
        return (self.source.frame_width, self.source.frame_height)
    
    def getEllapsedTime(self):
        """Returns the number ellapsed time in the video.
        
        :return: An integer representing the number of frame in the video.
        """
        return self.source.current().timestamp
Пример #5
0
class videoExplorer(object):
    """
    Class for access of recorded video files

    Allows to filter video files in a root folder to be retrieved by date

    """
    def __init__(self,  verbose=False, rootPath="/run/media/peter/Elements/peter/data/"):
        """

        Args:
            verbose (bool):
                                switch verbosity on (prints some status messages)
            rootPath (string):
                                root directory to be scanned for video files
        """
        self.rootPath = rootPath
        self.start = 0
        self.end = 0
        self.fileList = []
        self.nightList = []
        self.dayList = []
        self.verbose = verbose
        self.vs = None
        self.frameMode = None
        self.frame = None

    def setTimeRange(self,  start,  end):
        """
        set range of video explorer (works similar to a slice())

        :note:`The range is inclusive for the lower and upper end of the range`

        Args:
            start (datetime object):
                                beginning of time range
            end(datetime object):
                                end of time range
        """
        self.start = start
        self.end = end

    def setRootPath(self,  root):
        """
        Set root path of object

        Test:
            asdad
        """
        self.rootPath = root

    def parseFiles(self):
        """
        parses files in the main path and returns list of all files fitting
        the start - end criteria

        make sure that before calling this function:

            - start and end datetimes were set
            - mainPath is set

        .. seealso::
            :func:`setTimeRange()`
            :func:`setRootPath()`
        """
        if self.start == 0 or self.end == 0:
            raise ValueError("start or end value not set properly")

        self.fileList = []

        for root,  dirs,  files in os.walk(self.rootPath):
            for fn in files:
                ################################################################ TODO: sort files by file name
                fileDT = self.fileName2DateTime(fn)

                if fileDT == -1:
                    ## file is no mp4 file of interest
                    continue
                ################################################################ TODO: add option to load files without filter

                if self.start <= fileDT and self.end >= fileDT:
                    ## if timestamp is within the given range, add to list
                    self.fileList.append([fileDT, root + r'/' + fn])

        self.filterDayVideos()
        self.filterNightVideos()


    def filterDayVideos(self):
        """
        generates list (self.nightList) of videos that were recorded during
        day (between 10am and 11pm)
        """
        self.dayList = []

        for vid in self.fileList:
            hour = vid[0].hour
            if hour >= 10 and hour < 23:
                self.dayList.append(vid)

    def filterNightVideos(self):
        """
        generates list (self.nightList) of videos that were recorded during
        night (between 11pm and 10am)
        """
        self.nightList = []

        for vid in self.fileList:
            hour = vid[0].hour
            if hour < 10 or hour >= 23:
                self.nightList.append(vid)

    def getPathsOfList(self,  list):
        """
        returns a list of pure filenames without the corresponding datetime
        """
        out = []
        for item in list:
            out.append(item[1])

        return out

    def getDatesOfList(self,  list):
        """
        returns a list of pure datetime without the corresponding paths
        """
        out = [item[0] for item in list]

        return out


    def fileName2DateTime(self,  fn, ending="mp4"):
        """
        converts filename of video file to python datetime object

        Args:
            fn (string):
                                filename

        Returns:
            out (datetime object):
                                conversion of filename
        """

        basename = os.path.basename(fn)
        parts = re.split("[.]",  basename)
        date = re.split("[-]", parts[0])
        time = re.split("[-]", parts[1])

        if fn[-len(ending):] != ending:
            return -1

        if len(date) != 3:
            raise ValueError("mp4 file without proper date part discovered")
            return -1

        if len(time) < 3:
            raise ValueError("mp4 file without proper time part discovered")
            return -1

        out = dt.datetime(int(date[0]), int(date[1]), int(date[2]),
                          int(time[0]), int(time[1]), int(time[2]))

        return out


    def findInteruptions(self, fileList):
        """
        separates the filelist into ranges of consequent films, i.e. each
        range represents a batch of videos that share the same background model

        :note:`it is assumed that each consequtive file is 1 min long`

        Args:
            fileList (list of [datetime, path])
                                each element of this list can be generated by
                                :func:`fileName2DateTime`

        Returns:
            ranges of datetime that can be passed directly into
            :func:`setTimeRange`
        """
        # set file chunk size to 1 minute
        chunkSize = dt.time(0, 1)

        fileList = sorted(fileList)

        rngs = []
        start = None
        stop = None

        if len(fileList) < 2:
            raise ValueError("There are less then 2 files in the list. That usually means that a wrong folder was selected.")

        for i in range(len(fileList) - 1):
            if start is None:
                start = fileList[i][0]
                if (not (fileList[i + 1][0] - fileList[i][0]) <= dt.timedelta(minutes=1))\
                    or fileList[i + 1][0].second != 0:
                    stop = fileList[i][0]

            elif (not (fileList[i + 1][0] - fileList[i][0]) == dt.timedelta(minutes=1))\
                    or fileList[i + 1][0].second != 0:
                stop = fileList[i][0]

            if stop is not None:
                rngs += [[start, stop, i]]
                start = None
                stop = None

        stop = fileList[i+1][0]
        rngs += [[start, stop, i]]

        return rngs

    def getRandomFrame(self, pathList,  info=False, frameMode='L'):
        """
        returns the first frame from a random video of the list

        Args:
            pathList (List of Strings):
                                paths to video files
            info (bool):
                                return frame and filename
            frameMode (String):
                                Switch of color mode:

                                - 'RGB': color representation
                                - 'L':   gray-scale representation
                                - 'F':   ???

        Returns:
            frame (ndarray):
                                decoded video frame
        """
        file = pathList[random.randint(0,  len(pathList) - 1)]
        frameNo = random.randint(0,  1600 - 1)

        if self.verbose:
            print "processing frame {0} of video {1}".format(frameNo,  file)

        self.vs = VideoStream(file, frame_mode=frameMode, exact_seek=True)
        self.frameMode = frameMode

        frame = self.vs.next().ndarray()

        if info:
            return [frame, file]
        else:
            return frame

    def getFrame(self, file, frameNo=0, info=False, frameMode='L'):
        """
        returns the given frame from a given video

        Args:
            file (String):
                                path to video file
            frameNo (int):
                                frame number to be returned
            info (bool):
                                return frame and filename
            frameMode (String):
                                Switch of color mode:

                                - 'RGB': color representation
                                - 'L':   gray-scale representation
                                - 'F':   ???


        Returns:
            frame (ndarray):
                                decoded video frame
        """

        if self.verbose:
            print "processing frame {0} of video {1}".format(frameNo,  file)

        if not self.vs \
        or self.frameMode != frameMode \
        or self.vs.filename != file:
            self.vs = VideoStream(file, frame_mode=frameMode, exact_seek=True)

            self.frameMode = frameMode
        
        frame = self.vs.get_frame_no(frameNo).ndarray()
        
        if info:
            return [frame, file]
        else:
            return frame
                
    def next(self):
        """
        returns next frame in opened video file
        Call getFrame() or getRandomFrame() first
        
        Args:
            info (bool):
                                return frame and filename
                                
        .. seealso::
            :func:`getFrame`
            :func:`getRandomFrame`
        """
        
        if self.vs is None:
            raise AttributeError("no video stream defined. (It might be that" +\
                                 " the last frame was captured before)")
        
        try:
            frame = self.vs.next().ndarray()
        except ffvideo.NoMoreData:
            self.vs = None
            frame = None
            raise StopIteration
            
        return frame
        
    
    def setVideoStream(self, file,  info=False, frameMode='L'):
        """
        returns the first frame from a random video of the list
        
        Args:
            pathList (List of Strings):
                                paths to video files
            info (bool):
                                return frame and filename
            frameMode (String):
                                Switch of color mode:
                                
                                - 'RGB': color representation
                                - 'L':   gray-scale representation
                                - 'F':   ???
            
        Returns:
            frame (ndarray):
                                decoded video frame
        """       
        frameNo = random.randint(0,  1600 - 1)
        
        if self.verbose:
            print "processing frame {0} of video {1}".format(frameNo,  file)

        if not self.frame is None:
            del self.frame

        if not self.vs is None:
            del self.vs


        self.vs = VideoStream(file, frame_mode=frameMode, exact_seek=True)
        self.frameMode = frameMode
        
    def __iter__(self):
        # rewind ffvideo thingy
        if self.vs is not None:
            self.vs.__iter__()
        
        return self
    
    @staticmethod
    def splitFolders(path):
        """
        splits path into its folders and returns them 
        in a list. 

        .. note::
            Last entry of the returned list will be the
            basename of the path if applicable

        Args:
            path (string):
                            path to split

        Returns:
            folders (list of strings):
                            list of folders in path
                            
        Source:
            http://stackoverflow.com/questions/3167154/how-to-split-a-dos-path-into-its-components-in-python
        """
        folders=[]
        while 1:
            path,folder=os.path.split(path)

            if folder!="":
                folders.append(folder)
            else:
                if path!="":
                    folders.append(path)

                break

        folders.reverse()

        return folders

    @staticmethod
    def retrieveVideoLength(filename, initialStepSize=10000):
        """
        Finds video length by accessing it bruteforce

        """
        idx = initialStepSize
        modi = initialStepSize
        vE = videoExplorer()

        reached_end = False

        while modi > 0:
            while True:
                try:
                    vE.getFrame(filename, frameNo=idx, frameMode='RGB')
                except ffvideo.FFVideoError:
                    if modi == 1:
                        idx -= modi

                    reached_end = True
                    break
                except StopIteration:
                    if modi == 1:
                        idx -= modi

                    reached_end = True
                    break

                if reached_end and modi > 1:
                    modi /= 2

                idx += modi

            modi /= 2
            idx -= modi



        return idx + 1 # + 1 to make it the same behaviour as len()


    @staticmethod
    def findFileInList(lst, filename):
        """
        returns the position of the file within the list of paths
        """
        return [a for a,b in enumerate(lst) if b[1].endswith(filename)]
        
    @staticmethod
    def findClosestDate(dateList, date):
		min(DTlist,key=lambda date : abs(dt-date))
Пример #6
0
class videoExplorer(object):
    """
    Class for access of recorded video files

    Allows to filter video files in a root folder to be retrieved by date

    """
    def __init__(self,
                 verbose=False,
                 rootPath="/run/media/peter/Elements/peter/data/"):
        """

        Args:
            verbose (bool):
                                switch verbosity on (prints some status messages)
            rootPath (string):
                                root directory to be scanned for video files
        """
        self.rootPath = rootPath
        self.start = 0
        self.end = 0
        self.fileList = []
        self.nightList = []
        self.dayList = []
        self.verbose = verbose
        self.vs = None
        self.frameMode = None
        self.frame = None

    def setTimeRange(self, start, end):
        """
        set range of video explorer (works similar to a slice())

        :note:`The range is inclusive for the lower and upper end of the range`

        Args:
            start (datetime object):
                                beginning of time range
            end(datetime object):
                                end of time range
        """
        self.start = start
        self.end = end

    def setRootPath(self, root):
        """
        Set root path of object

        Test:
            asdad
        """
        self.rootPath = root

    def parseFiles(self):
        """
        parses files in the main path and returns list of all files fitting
        the start - end criteria

        make sure that before calling this function:

            - start and end datetimes were set
            - mainPath is set

        .. seealso::
            :func:`setTimeRange()`
            :func:`setRootPath()`
        """
        if self.start == 0 or self.end == 0:
            raise ValueError("start or end value not set properly")

        self.fileList = []

        for root, dirs, files in os.walk(self.rootPath):
            for fn in files:
                ################################################################ TODO: sort files by file name
                fileDT = self.fileName2DateTime(fn)

                if fileDT == -1:
                    ## file is no mp4 file of interest
                    continue
                ################################################################ TODO: add option to load files without filter

                if self.start <= fileDT and self.end >= fileDT:
                    ## if timestamp is within the given range, add to list
                    self.fileList.append([fileDT, root + r'/' + fn])

        self.filterDayVideos()
        self.filterNightVideos()

    def filterDayVideos(self):
        """
        generates list (self.nightList) of videos that were recorded during
        day (between 10am and 11pm)
        """
        self.dayList = []

        for vid in self.fileList:
            hour = vid[0].hour
            if hour >= 10 and hour < 23:
                self.dayList.append(vid)

    def filterNightVideos(self):
        """
        generates list (self.nightList) of videos that were recorded during
        night (between 11pm and 10am)
        """
        self.nightList = []

        for vid in self.fileList:
            hour = vid[0].hour
            if hour < 10 or hour >= 23:
                self.nightList.append(vid)

    def getPathsOfList(self, list):
        """
        returns a list of pure filenames without the corresponding datetime
        """
        out = []
        for item in list:
            out.append(item[1])

        return out

    def getDatesOfList(self, list):
        """
        returns a list of pure datetime without the corresponding paths
        """
        out = [item[0] for item in list]

        return out

    def fileName2DateTime(self, fn, ending="mp4"):
        """
        converts filename of video file to python datetime object

        Args:
            fn (string):
                                filename

        Returns:
            out (datetime object):
                                conversion of filename
        """

        basename = os.path.basename(fn)
        parts = re.split("[.]", basename)
        date = re.split("[-]", parts[0])
        time = re.split("[-]", parts[1])

        if fn[-len(ending):] != ending:
            return -1

        if len(date) != 3:
            raise ValueError("mp4 file without proper date part discovered")
            return -1

        if len(time) < 3:
            raise ValueError("mp4 file without proper time part discovered")
            return -1

        out = dt.datetime(int(date[0]), int(date[1]), int(date[2]),
                          int(time[0]), int(time[1]), int(time[2]))

        return out

    def findInteruptions(self, fileList):
        """
        separates the filelist into ranges of consequent films, i.e. each
        range represents a batch of videos that share the same background model

        :note:`it is assumed that each consequtive file is 1 min long`

        Args:
            fileList (list of [datetime, path])
                                each element of this list can be generated by
                                :func:`fileName2DateTime`

        Returns:
            ranges of datetime that can be passed directly into
            :func:`setTimeRange`
        """
        # set file chunk size to 1 minute
        chunkSize = dt.time(0, 1)

        fileList = sorted(fileList)

        rngs = []
        start = None
        stop = None

        if len(fileList) < 2:
            raise ValueError(
                "There are less then 2 files in the list. That usually means that a wrong folder was selected."
            )

        for i in range(len(fileList) - 1):
            if start is None:
                start = fileList[i][0]
                if (not (fileList[i + 1][0] - fileList[i][0]) <= dt.timedelta(minutes=1))\
                    or fileList[i + 1][0].second != 0:
                    stop = fileList[i][0]

            elif (not (fileList[i + 1][0] - fileList[i][0]) == dt.timedelta(minutes=1))\
                    or fileList[i + 1][0].second != 0:
                stop = fileList[i][0]

            if stop is not None:
                rngs += [[start, stop, i]]
                start = None
                stop = None

        stop = fileList[i + 1][0]
        rngs += [[start, stop, i]]

        return rngs

    def getRandomFrame(self, pathList, info=False, frameMode='L'):
        """
        returns the first frame from a random video of the list

        Args:
            pathList (List of Strings):
                                paths to video files
            info (bool):
                                return frame and filename
            frameMode (String):
                                Switch of color mode:

                                - 'RGB': color representation
                                - 'L':   gray-scale representation
                                - 'F':   ???

        Returns:
            frame (ndarray):
                                decoded video frame
        """
        file = pathList[random.randint(0, len(pathList) - 1)]
        frameNo = random.randint(0, 1600 - 1)

        if self.verbose:
            print "processing frame {0} of video {1}".format(frameNo, file)

        self.vs = VideoStream(file, frame_mode=frameMode, exact_seek=True)
        self.frameMode = frameMode

        frame = self.vs.next().ndarray()

        if info:
            return [frame, file]
        else:
            return frame

    def getFrame(self, file, frameNo=0, info=False, frameMode='L'):
        """
        returns the given frame from a given video

        Args:
            file (String):
                                path to video file
            frameNo (int):
                                frame number to be returned
            info (bool):
                                return frame and filename
            frameMode (String):
                                Switch of color mode:

                                - 'RGB': color representation
                                - 'L':   gray-scale representation
                                - 'F':   ???


        Returns:
            frame (ndarray):
                                decoded video frame
        """

        if self.verbose:
            print "processing frame {0} of video {1}".format(frameNo, file)

        if not self.vs \
        or self.frameMode != frameMode \
        or self.vs.filename != file:
            self.vs = VideoStream(file, frame_mode=frameMode, exact_seek=True)

            self.frameMode = frameMode

        frame = self.vs.get_frame_no(frameNo).ndarray()

        if info:
            return [frame, file]
        else:
            return frame

    def next(self):
        """
        returns next frame in opened video file
        Call getFrame() or getRandomFrame() first
        
        Args:
            info (bool):
                                return frame and filename
                                
        .. seealso::
            :func:`getFrame`
            :func:`getRandomFrame`
        """

        if self.vs is None:
            raise AttributeError("no video stream defined. (It might be that" +\
                                 " the last frame was captured before)")

        try:
            frame = self.vs.next().ndarray()
        except ffvideo.NoMoreData:
            self.vs = None
            frame = None
            raise StopIteration

        return frame

    def setVideoStream(self, file, info=False, frameMode='L'):
        """
        returns the first frame from a random video of the list
        
        Args:
            pathList (List of Strings):
                                paths to video files
            info (bool):
                                return frame and filename
            frameMode (String):
                                Switch of color mode:
                                
                                - 'RGB': color representation
                                - 'L':   gray-scale representation
                                - 'F':   ???
            
        Returns:
            frame (ndarray):
                                decoded video frame
        """
        frameNo = random.randint(0, 1600 - 1)

        if self.verbose:
            print "processing frame {0} of video {1}".format(frameNo, file)

        if not self.frame is None:
            del self.frame

        if not self.vs is None:
            del self.vs

        self.vs = VideoStream(file, frame_mode=frameMode, exact_seek=True)
        self.frameMode = frameMode

    def __iter__(self):
        # rewind ffvideo thingy
        if self.vs is not None:
            self.vs.__iter__()

        return self

    @staticmethod
    def splitFolders(path):
        """
        splits path into its folders and returns them 
        in a list. 

        .. note::
            Last entry of the returned list will be the
            basename of the path if applicable

        Args:
            path (string):
                            path to split

        Returns:
            folders (list of strings):
                            list of folders in path
                            
        Source:
            http://stackoverflow.com/questions/3167154/how-to-split-a-dos-path-into-its-components-in-python
        """
        folders = []
        while 1:
            path, folder = os.path.split(path)

            if folder != "":
                folders.append(folder)
            else:
                if path != "":
                    folders.append(path)

                break

        folders.reverse()

        return folders

    @staticmethod
    def retrieveVideoLength(filename, initialStepSize=10000):
        """
        Finds video length by accessing it bruteforce

        """
        idx = initialStepSize
        modi = initialStepSize
        vE = videoExplorer()

        reached_end = False

        while modi > 0:
            while True:
                try:
                    vE.getFrame(filename, frameNo=idx, frameMode='RGB')
                except ffvideo.FFVideoError:
                    if modi == 1:
                        idx -= modi

                    reached_end = True
                    break
                except StopIteration:
                    if modi == 1:
                        idx -= modi

                    reached_end = True
                    break

                if reached_end and modi > 1:
                    modi /= 2

                idx += modi

            modi /= 2
            idx -= modi

        return idx + 1  # + 1 to make it the same behaviour as len()

    @staticmethod
    def findFileInList(lst, filename):
        """
        returns the position of the file within the list of paths
        """
        return [a for a, b in enumerate(lst) if b[1].endswith(filename)]

    @staticmethod
    def findClosestDate(dateList, date):
        min(DTlist, key=lambda date: abs(dt - date))
Пример #7
0
class Movie(QtCore.QObject):
    """This class represent the video data stream"""

    frameChanged = QtCore.pyqtSignal()
    endOfVideo = QtCore.pyqtSignal()

    def __init__(self, fileName=None):
        """Initialize the video stream and open the video file if a fileName is provided.
        
        :param filename: a string containing the name of the file to be opened.
        """
        self.rawBuffer = None
        self.source = None
        super(Movie, self).__init__()
        if (fileName is not None):
            self.setMovie(fileName)
        self.timer = None
        self.frame = None
        self.isPlaying = False
        self.frameRate = 0
        self.frameNumber = 0

    def reset(self):
        """Reset the movie object. Remove the source."""
        self.rawBuffer = None
        self.source = None
        self.timer = None
        self.frame = None
        self.isPlaying = False
        self.frameRate = 0
        self.frameNumber = 0

    def setMovie(self, fileName):
        """Open a video file.
        
        :param filename: a string containing the name of the file to be opened.
            
        :raise: TypeError: The fileName is not a string.
        """
        if (isinstance(fileName, basestring)):
            self.fileName = u''.join(fileName).encode('utf-8')
            self.source = VideoStream(self.fileName)
        else:
            raise TypeError('fileName must be a string')

        self.frameRate = self.source.framerate
        self.frameNumber = self.source.duration * 1000 / self.source.framerate
        self.timer = QtCore.QTimer()
        self.timer.setInterval(1000.0 / self.frameRate)
        self.timer.setSingleShot(False)
        self.timer.timeout.connect(self.frameMustChange)

    def resetMovie(self):
        """Reset the video stream."""
        self.source = VideoStream(self.fileName)

    def play(self):
        """Start to read the video stream."""
        self.isPlaying = True
        self.timer.start()

    def pause(self):
        """Pause the reading of the video stream."""
        self.isPlaying = False
        self.timer.stop()

    def frameMustChange(self):
        """Slot called when it is time to load the next frame.
        
        :raise: Exception: The file cannot be read because the codec is not supported or the video is compressed.
        """
        self.readNextFrame()

    def toggleState(self):
        """Toggle between playing and pausing the video."""
        if (self.isPlaying == True):
            self.pause()
        else:
            self.play()

    def jumpToFrame(self, position):
        """Modify the position in the video.
        
        :param position: a value between 0 and 1 corresponding to the position in the video. 0 is the beginning and 1 is the end.
        """
        if (position > 1.0):
            position = 1.0
        elif (position < 0.001):
            position = 0.001
        frame = self.source.get_frame_at_sec(position *
                                             self.source.duration).ndarray
        return frame

    def readNextFrame(self):
        """Load the next frame.
        :raise: Exception: The file cannot be read because the codec is not supported or the video is compressed.
        """
        try:
            self.rawBuffer = self.source.next().ndarray()
        except ffvideo.NoMoreData:
            self.isPlaying = False
            self.pause()
            self.rawBuffer = None
            self.endOfVideo.emit()
        self.frameChanged.emit()

    def readNCFrame(self, number):
        """Load the next frame.
        :raise: Exception: The file cannot be read because the codec is not supported or the video is compressed.
        """
        position = self.source.current().frameno
        try:
            self.rawBuffer = self.source.get_frame_no(position +
                                                      number).ndarray()
        except ffvideo.NoMoreData:
            self.isPlaying = False
            self.pause()
            self.endOfVideo.emit()
        if (self.source.current().frameno >=
                self.source.duration * self.source.framerate):
            self.isPlaying = False
            self.pause()
            self.endOfVideo.emit()
        self.frameChanged.emit()

    def currentPositionRatio(self):
        """Returns the position in the video.
        
        :return: a value between 0 and 1 representing the position in the video. 0 is the beginning and 1 is the end.
        """
        if (self.source is not None and self.source.current() is not None):
            result = self.source.current().timestamp / self.source.duration
            if (result > 1.0):
                return 1.0
            elif (result < 0.0):
                return 0.0
            else:
                return result
        else:
            return 1.0

    def getFrameNumber(self):
        """Returns the number of frame in the video.
        
        :return: An integer representing the number of frame in the video.
        """
        return int(self.source.duration * self.source.framerate)

    def getFrameSize(self):
        return (self.source.frame_width, self.source.frame_height)

    def getEllapsedTime(self):
        """Returns the number ellapsed time in the video.
        
        :return: An integer representing the number of frame in the video.
        """
        return self.source.current().timestamp
Пример #8
0
class VideoFrameGrabber(object):
    """Extracts frames at a fixed time step and saves them to a folder.

    Parameters
    ----------

    input_video_path : str
        Path to input video file.
    output_path : str
        Path to directory which will contain output frames as jpegs and html page.\
        Should be descriptive.
    frame_step : int
        Number of frames between samples.
    resize_factor : int
        Factor to resize frames by when saving.
    """
    def __init__(self, input_video_path, output_path, frame_step, resize_factor=2):
        self.input_video_path = input_video_path
        self.output_path = output_path
        self.frame_step = frame_step
        self.resize_factor = resize_factor

        self.vs = VideoStream(input_video_path)
        # self.duration = self.vs.duration
        self.total_frames = int(self.vs.duration * self.vs.framerate)

    def set_frame_step(self, frame_step):
        self.frame_step = frame_step

    def set_output_path(self, output_path):
        self.output_path = output_path

    def _make_output_directory(self):

        if not os.path.exists(self.output_path):
            os.makedirs(self.output_path)

        frames_directory = os.path.join(self.output_path, 'static')
        if not os.path.exists(frames_directory):
            os.makedirs(frames_directory)

    def run(self, start_frame=0, end_frame=None):

        # Check input video exists.
        if not os.path.exists(self.input_video_path):
            raise Exception('Video does not exist!!')

        # Set up output directory.
        self._make_output_directory()

        # Save out frames to output directory.
        if not end_frame:
            end_frame = self.total_frames

        frames_to_get = numpy.arange(start_frame, end_frame, self.frame_step)
        frame_path_list = []

        prog = progress(len(frames_to_get))
        for i, frame in enumerate(frames_to_get):
            prog.update(i)
            video_frame = self.vs.get_frame_no(frame).image()
            width, height = video_frame.size
            new_size = (int(width/self.resize_factor), int(height/self.resize_factor))
            video_frame = video_frame.resize(new_size)
            filename = os.path.join(self.output_path, 'static', 'frame-%06d.jpeg' % frame)
            relative_path = os.path.join('static', 'frame-%06d.jpeg' % frame)
            video_frame.save(filename)
            frame_path_list.append(relative_path)

        frame_to_get_str_list = [str(frame) for frame in frames_to_get]
        prog.end()

        # Make webpage.
        make_page(self.output_path, 'index', frame_path_list, frame_to_get_str_list)