Example #1
0
        def _apply_compute_error(cls, instance, poll_interval=8):
            from vfs.gop import Gop
            from vfs.videoio import compute_mse

            current_interval, maximum_interval = poll_interval, 256

            while instance.running:
                leaf_gop_id, root_gop_id = instance.database.execute(
                    'WITH RECURSIVE'
                    '  parent(leaf_id, id, parent_id, mse) AS '
                    '    (SELECT id, id, parent_id, mse FROM gops '
                    '       WHERE id = (SELECT id FROM gops WHERE mse IS NULL LIMIT 1)'
                    '    UNION ALL '
                    '    SELECT parent.leaf_id, gops.id, gops.parent_id, gops.mse FROM parent '
                    '    INNER JOIN gops ON parent.parent_id = gops.id)'
                    'SELECT leaf_id, id FROM parent '
                    'WHERE parent_id IS NULL AND mse IS NOT NULL '
                    '').fetchone() or [None, None]

                if leaf_gop_id is not None and root_gop_id is not None:
                    mse = compute_mse(Gop.get(leaf_gop_id),
                                      Gop.get(root_gop_id))
                    instance.database.execute(
                        'UPDATE gops SET mse = ?, estimated_mse = ? WHERE id = ?',
                        (mse, mse, leaf_gop_id))
                    logging.info(
                        "ErrorWorker: Computed precise error for GOP %d",
                        leaf_gop_id)
                    current_interval = poll_interval
                else:
                    current_interval = min(current_interval * 2,
                                           maximum_interval)

                cls._sleep(instance, current_interval)
def evict_gop(database, gop_id, cut):
    from vfs.gop import Gop
    from vfs.physicalvideo import PhysicalVideo

    evict_gop = Gop.get(gop_id)
    gop_count = database.execute(
        "SELECT COUNT(*) FROM gops WHERE physical_id = ?",
        evict_gop.physical_id).fetchone()[0]

    if gop_count == 1:
        PhysicalVideo.delete(evict_gop.video())
        #logging.info('EvictWorker: Evicting GOP %d (covered by %d; last GOP, also deleting physical video)', gop_id, cover_gop_id)
        logging.info(
            'EvictWorker: Evicting GOP %d (last GOP, also deleting physical video)',
            gop_id)
    elif cut:
        new_physical_video = PhysicalVideo.add(evict_gop.video().logical(),
                                               evict_gop.video().height,
                                               evict_gop.video().width,
                                               evict_gop.video().codec)
        database.executebatch([
            'UPDATE gops SET physical_id = {} WHERE physical_id = {} AND start_time < {}'
            .format(new_physical_video.id, evict_gop.physical_id,
                    evict_gop.start_time),
            'DELETE FROM gops WHERE id = {}'.format(gop_id)
        ])
        Gop.delete(evict_gop)
        #logging.info('EvictWorker: Evicting GOP %d (covered by %d; middle GOP, cutting physical video)', gop_id, cover_gop_id)
        logging.info(
            'EvictWorker: Evicting GOP %d (middle GOP, cutting physical video)',
            gop_id)
    else:
        #logging.info('EvictWorker: Evicting GOP %d (covered by %d; endpoint GOP)', gop_id, cover_gop_id)
        logging.info('EvictWorker: Evicting GOP %d (endpoint GOP)', gop_id)
        Gop.delete(evict_gop)
Example #3
0
    def load(cls, logical_video, filename, resolution=None, codec=None, fps=None):
        from vfs.gop import Gop

        if resolution is None and codec is None:
            resolution, codec, fps = get_shape_and_codec(filename)
        elif codec is None:
            resolution = get_shape(filename)

        assert(resolution is not None)
        assert(codec is not None)
        assert(fps is not None)

        physical = cls.add(logical_video, *resolution, codec=codec)

        output_filename_template = os.path.join(
            VFS.instance().path,
            cls._gop_filename_template(logical_video, physical, '%04d'))
            #'{}-{}-%04d.{}'.format(logical_video.name, physical.id, extensions[physical.codec]))
        gop_filenames = split_video(filename, output_filename_template, resolution, codec, fps)

        Gop.addmany(physical, [(filename, start_time, end_time, os.path.getsize(filename), fps, 0, 0, None)
                               for (filename, start_time, end_time) in gop_filenames])

        logging.info('Ingested physical video %s-%d', logical_video.name, physical.id)

        return physical
Example #4
0
        def task(candidate_gop):
            from vfs.gop import Gop

            closest_gops = Descriptor.closest_match(epoch, candidate_gop) if candidate_gop else (None, None)
            overlap_gop = None

            with cls.lock:
                for gop_id, matches in closest_gops:
                    if VFS.instance().database.execute(
                        'SELECT examined FROM gops WHERE id = ? AND joint = 0', gop_id).fetchone()[0] <= epoch:
                        overlap_gop = Gop.get(gop_id)
                        VFS.instance().database.execute(
                            'UPDATE gops SET examined = ? WHERE id = ?', (epoch + 1, overlap_gop.id)).close()
                        break

            if not overlap_gop is None:
                #VFS.instance().database.execute(
                #    'UPDATE gops SET examined = ? WHERE id in (?, ?)', (epoch + 10, candidate_gop.id, overlap_gop.id)).close()
                #threading.Thread(target=cls.co_compress, args=(candidate_gop, overlap_gop, matches)).start()
                return cls.co_compress(candidate_gop, overlap_gop, matches)
                #return True, candidate_gop, pool.submit(cls.co_compress, candidate_gop, overlap_gop, matches)
                #return True, candidate_gop, future #bytes_saved
            elif not candidate_gop is None:
                logging.info("Deferring joint compression for gop %d-%d", candidate_gop.physical_id, candidate_gop.id)
                VFS.instance().database.execute(
                    'UPDATE gops SET examined = ? WHERE id = ?', (epoch + 1, candidate_gop.id)).close()
                return 0 #False, candidate_gop, None
            else:
                return 0 #False, None, None
Example #5
0
def solve_constraint(logical, resolution, roi, t, fps, codec):
    physical, fragments = _prepare(logical, resolution, t)

    logging.info(
        f'Solving for {len(physical)} physical videos with {len(fragments)} fragments'
    )

    if len(physical) == 1:
        # Only one physical video, so not really much to solve
        distinct_fragment_ids = (
            f['id'] for f in sorted(fragments, key=lambda f: f['start'])
            if f['end'] >= t[0] and f['start'] < t[1])
    elif len(physical) > 1:
        video_objects, goal_ints = build_from_video_info(
            physical, fragments, t)

        fragment_ids = find_best_intervals(video_objects, goal_ints, codec,
                                           resolution)
        distinct_fragment_ids = list(dict.fromkeys(fragment_ids))
    else:
        logging.error("No physical videos found for solver to examine")
        assert False

    gops = [Gop.get(id) for id in distinct_fragment_ids]
    return gops
Example #6
0
    def delete(cls, video):
        from vfs.gop import Gop

        logging.info('Deleting Physical Video %d', video.id)

        gops = video.gops()
        references = {filename: count for (filename, count) in
                      VFS.instance().database.execute(
                          'SELECT filename, COUNT(*) '
                                 'FROM gops '
                                 'WHERE filename IN (SELECT filename FROM gops WHERE physical_id = ?) '
                                 'GROUP BY filename', video.id).fetchall()}

        VFS.instance().database.execute('DELETE FROM gops WHERE physical_id = ?', video.id)
        VFS.instance().database.execute('DELETE FROM physical_videos WHERE id = ?', video.id)
        video.id = None

        for gop in gops:
            Gop.delete(gop, references=references.get(gop.filename, 0))
Example #7
0
    def gops(self):
        from vfs.gop import Gop

        if self._gops is None:
            self._gops = list(map(lambda args: Gop(*args),
                       VFS.instance().database.execute(
                           'SELECT id, physical_id, filename, start_time, end_time, cluster_id, joint, examined, '
                           '       histogram, descriptors, keypoints, size, zstandard, fps, mse, estimated_mse, parent_id, original_size '
                           'FROM gops WHERE physical_id = ? ORDER BY id', self.id).fetchall()))
        return self._gops
def get_random_gop(engine, name, r, t, index, avoid_ids=None):
    gops = engine.database.execute(
        "SELECT gops.id FROM gops, physical_videos, logical_videos WHERE logical_videos.id == physical_videos.logical_id AND gops.physical_id = physical_videos.id AND height = ? AND width = ? AND name = ? ORDER BY gops.id LIMIT ?",
        (r[0], r[1], name, index + 1)).fetchall()
    #gops = engine.database.execute("SELECT gops.id FROM gops, physical_videos, logical_videos WHERE logical_videos.id == physical_videos.logical_id AND gops.physical_id = physical_videos.id AND height = ? AND width = ? AND end_time - start_time != ? AND name = ?", (r[0], r[1], t, name)).fetchall()
    gop = Gop.get(gops[-1])  #random.choice(gops))

    if not os.path.exists(gop.filename):
        return get_random_gop(engine, name, r, t, index, avoid_ids)
    elif gop.id in (avoid_ids or []):
        return get_random_gop(engine, name, r, t, index, avoid_ids)
    else:
        return gop
Example #9
0
def cache_reconstructions(logical, resolution, codec, times, fps,
                          cache_sequences):
    for sequence in (sequence for sequence in cache_sequences if sequence):
        physical = PhysicalVideo.add(logical, *resolution, codec)
        new_gop_data = []

        transitive_estimated_mses = VFS.instance().database.execute(
            'WITH RECURSIVE'
            '  error(id, estimated_mse) AS '
            '    (SELECT id, estimated_mse FROM gops child WHERE id IN ({}) '.
            format(','.join(str(gop.id)
                            for gop, _, _ in sequence)) + '    UNION ALL '
            '    SELECT id, estimated_mse FROM gops parent WHERE parent.id = id)'
            'SELECT id, SUM(estimated_mse) FROM error GROUP BY id').fetchall()

        for (_, current_estimated_mse), (index, (gop, filename,
                                                 new_mse)) in zip(
                                                     transitive_estimated_mses,
                                                     enumerate(sequence)):
            new_filename = path.join(
                VFS.instance().path,
                PhysicalVideo._gop_filename_template(logical, physical, index))

            new_gop_data.append(
                (new_filename, max(gop.start_time, times[0]),
                 min(gop.end_time, times[1]), os.path.getsize(filename), fps,
                 None, 2 * (current_estimated_mse + (new_mse or 0)), gop.id))

            #TODO remove guard
            #duplicates = VFS.instance().database.execute("SELECT * FROM gops, physical_videos WHERE start_time = ? AND end_time = ? and height = ? and width = ? and codec = ? and gops.physical_id = physical_videos.id",
            #                                (new_gop_data[-1][0], new_gop_data[-1][1], resolution[0], resolution[1], codec)).fetchall()
            #if len(duplicates) > 0:
            #    print("Duplicate detected???")

            os.rename(filename, new_filename)

        Gop.addmany(physical, new_gop_data)
        logging.info('Cached physical video %s-%d', logical.name, physical.id)
        return new_gop_data
Example #10
0
def solve_exact(logical, resolution, roi, t, fps, codec):
    #if roi is not None:
    #    return None

    gop_id = VFS.instance().database.execute(
        """
        SELECT gops.id FROM gops, physical_videos
        WHERE height = ? AND width = ? AND 
              start_time <= ? AND end_time >= ? AND 
              codec = ? AND
              gops.physical_id = physical_videos.id AND 
              logical_id = ?""", (resolution[0], resolution[1], t[0], t[1],
                                  codec, logical.id)).fetchone()

    return [Gop.get(gop_id[0])] if gop_id else None
Example #11
0
    def get_candidate(cls, epoch):
        from vfs.gop import Gop

        smallest_cluster = (VFS.instance().database.execute(
            'SELECT cluster_id, COUNT(*) FROM gops candidate '
              'WHERE examined <= ? AND joint = 0 AND '
              '      cluster_id > 0 '
              # What did this do?
              #'      physical_id < (SELECT MAX(physical_id) FROM gops WHERE examined <= ? AND joint = 0 AND cluster_id = candidate.cluster_id) '
              'GROUP BY cluster_id '
              'ORDER BY COUNT(*) ASC '
              'LIMIT 1', (epoch)).fetchone() or [None])[0] #(epoch, epoch)

        if smallest_cluster is not None:
            return Gop.get(*VFS.instance().database.execute(
                'SELECT MIN(id) FROM gops '
                'WHERE cluster_id = ? AND examined <= ? AND joint = 0',
                (smallest_cluster, epoch)).fetchone())
        else:
            return None
Example #12
0
def execute():
    candidate_gop = JointCompression.get_candidate(epoch)

    if candidate_gop is None:
        return 0

    #VFS.instance().database.execute(
    #    'UPDATE gops SET examined = ? WHERE id = ?', (epoch + 1, candidate_gop.id)).close()

    closest_gops = Descriptor.closest_match(
        epoch, candidate_gop) if candidate_gop else (None, None)

    for gop_id, matches in closest_gops:
        overlap_gop = Gop.get(gop_id)

        if not overlap_gop is None:
            return JointCompression.co_compress(candidate_gop, overlap_gop,
                                                matches)
        else:
            logging.info("No GOP found")
            return None
    def closest_match(cls,
                      epoch,
                      gop,
                      matches_required=DEFAULT_MATCHES_REQUIRED,
                      radius=400):  #400):
        from vfs.gop import Gop

        with log_runtime("Joint compression candidate selection"):
            cluster_gops = VFS.instance().database.execute(
                "SELECT id, filename, descriptors FROM gops WHERE cluster_id = ? AND physical_id != ? AND descriptors IS NOT NULL AND joint = 0 AND examined <= ? AND NOT EXISTS (SELECT id FROM gop_joint_aborted WHERE gop1 = ? AND gop2 = id)",
                (gop.cluster_id, gop.physical_id, epoch, gop.id)).fetchall()
            candidate_gops = []
            for gop2_id, gop2_filename, gop2_descriptors in cluster_gops:
                success, matches = cls.adhoc_match(gop.descriptors,
                                                   gop2_descriptors)
                if success and len(matches) > matches_required:
                    candidate_gops.append(
                        (gop.filename.split('-')[-1] == gop2_filename.split(
                            '-')[-1], len(matches), gop2_id, matches))
                    if candidate_gops[-1][1] > 400 or candidate_gops[-1][
                            0]:  # Break on "good enough" match to try out
                        break
            candidate_gop = sorted(candidate_gops,
                                   reverse=True)[0] if candidate_gops else None
            return [(candidate_gop[2], candidate_gop[3])]

        matcher = cls._get_matcher(epoch, gop)
        physical_map = cls._get_physical_map(gop.cluster_id).get(
            gop.physical_id, None)
        index_map = cls._get_index_map(gop.cluster_id)
        all_matches = matcher.radiusMatch(queryDescriptors=gop.descriptors,
                                          maxDistance=radius)
        good_matches = defaultdict(lambda: [])
        first_matches = {}
        complete = set()

        # For each frame/descriptor pair, find matches that pass the Lowe threshold test
        #all_matches = all_matches[:5000]
        filtered_matches = (
            m for d in all_matches for m in d
            if index_map[m.imgIdx] > gop.id and m.imgIdx not in physical_map
            and not (m.imgIdx, m.queryIdx) in complete)
        #for descriptor_matches in all_matches:
        #    for match in descriptor_matches:
        with log_runtime("Lowes test"):
            for match in filtered_matches:
                #if match.imgIdx not in physical_map and \
                #    index_map[match.imgIdx] > gop.id and \
                #if not (match.imgIdx, match.queryIdx) in complete:
                # First match
                if (match.imgIdx, match.queryIdx) not in first_matches:
                    first_matches[match.imgIdx, match.queryIdx] = match
                # Second match
                else:
                    if first_matches[
                            match.imgIdx, match.
                            queryIdx].distance < cls.LOWE_THRESHOLD * match.distance:
                        good_matches[match.imgIdx].append(
                            first_matches[match.imgIdx, match.queryIdx])
                    del first_matches[match.imgIdx, match.queryIdx]
                    complete.add((match.imgIdx, match.queryIdx))

        # Some matches may not have a second match to apply Lowe's threshold on.
        # Check to see if we should have seen it and count it if so.
        for first_match in first_matches.values():
            if first_match.distance / cls.LOWE_THRESHOLD < radius:
                good_matches[first_match.imgIdx].append(first_match)

        ignore_ids = set(VFS.instance().database.execute(
            'SELECT gop2 FROM gop_joint_aborted WHERE gop1 = ?',
            gop.id).fetchall())
        best_indexes = [
            index for index, matches in good_matches.items()
            if len(matches) >= matches_required
            and index_map[index] not in ignore_ids
        ]
        #best_ids = [index_map[index] for index in best_indexes if index_map[index] not in ignore_ids]
        #best_id = VFS.instance().database.execute(
        #    'SELECT MIN(id) FROM gops WHERE joint=0 AND id in ({})'.format(','.join(map(str, best_ids)))).fetchone()[0]
        #best_index = max((index for index, matches in good_matches.items() if len(matches) >= matches_required),
        #                 default=None)
        #best = sorted([(index_map[index], good_matches[index]) for index in best_indexes], key=lambda pair: len(pair[1]), reverse=True)
        gops = Gop.get_all(index_map[index] for index in best_indexes)
        best = [(gop, good_matches[index])
                for gop, index in zip(gops, best_indexes)]
        best = sorted(best,
                      key=lambda pair: (pair[0].filename.split('-')[-1] == gop.
                                        filename.split('-')[-1], len(pair[1])),
                      reverse=True)
        best = best[:len(best) // 20 + 1]  # Keep top 5%
        best = [(mgop.id, matches) for mgop, matches in best]
        #best = sorted([(mgop.id, cv2.compareHist(gop.histogram, mgop.histogram, cv2.HISTCMP_CHISQR), gop.filename, mgop.filename, matches) for (mgop, matches) in best], key=lambda pair: (len(pair[2]), cv2.compareHist(gop.histogram, pair[0].histogram, cv2.HISTCMP_CHISQR), -pair[0].id), reverse=True)
        #best = sorted([(id, cv2.compareHist(gop.histogram, Gop.get(id).histogram, cv2.HISTCMP_CHISQR), gop.filename, Gop.get(id).filename, matches) for (id, matches) in best], key=lambda pair: (len(pair[2]), cv2.compareHist(gop.histogram, Gop.get(pair[0]).histogram, cv2.HISTCMP_CHISQR), -pair[0]), reverse=True)

        return best

        if best_id is not None:
            return Gop.get(best_id), good_matches[best_indexes[best_ids.index(
                best_id)]]  #best_index]
        #if best_index is not None:
        #    return Gop.get(index_map[best_index]), good_matches[best_index]
        #return Gop.get(VFS.instance().database.execute(
        #    '''SELECT id FROM gops
        #              WHERE cluster_id = ? AND joint = 0
        #              LIMIT 1
        #              OFFSET ?''', (gop.cluster_id, best_index)).fetchone()[0]), good_matches[best_index]
        else:
            return None, None