Exemplo n.º 1
0
    def check_media(self, file_path, flag_path):
        """
        check media and add them to list view if duration > 0

        Args:
            file_path (str): media file path to be checked
            flag_path (bool): True include full path of media else only basename

        Returns:
             bool: True if file is media else False
             str: error message or empty string
        """

        r = utilities.accurate_media_analysis(self.ffmpeg_bin, file_path)
        if "error" in r:
            return False, r["error"]
        else:
            if r["duration"] > 0:
                if not flag_path:
                    file_path = str(Path(file_path).name)
                self.mediaDurations[file_path] = float(r["duration"])
                self.mediaFPS[file_path] = float(r["fps"])
                self.mediaHasVideo[file_path] = r["has_video"]
                self.mediaHasAudio[file_path] = r["has_audio"]
                self.add_media_to_listview(file_path)
                return True, ""
            else:
                return False, "duration not available"
Exemplo n.º 2
0
 def test_media_ok(self):
     r = utilities.accurate_media_analysis("ffmpeg", "files/geese1.mp4")
     assert r == {
         'frames_number': 1548,
         'duration_ms': Decimal('61920.00'),
         'duration': Decimal('61.92'),
         'fps': Decimal('25'),
         'has_video': True,
         'has_audio': True,
         'bitrate': 901,
         'resolution': '640x480'
     }
Exemplo n.º 3
0
def open_project_json(projectFileName: str) -> tuple:
    """
    open BORIS project file in json format or GZ compressed json format

    Args:
        projectFileName (str): path of project

    Returns:
        str: project path
        bool: True if project changed
        dict: BORIS project
        str: message
    """

    logging.debug(f"open project: {projectFileName}")

    projectChanged = False
    msg = ""

    if not os.path.isfile(projectFileName):
        return projectFileName, projectChanged, {
            "error": f"File {projectFileName} not found"
        }, msg

    try:
        if projectFileName.endswith(".boris.gz"):
            file_in = gzip.open(projectFileName, mode="rt", encoding="utf-8")
        else:
            file_in = open(projectFileName, "r")
        file_content = file_in.read()
    except PermissionError:
        return projectFileName, projectChanged, {
            f"error": f"File {projectFileName}: Permission denied"
        }, msg
    except Exception:
        return projectFileName, projectChanged, {
            f"error": f"Error on file {projectFileName}: {sys.exc_info()[1]}"
        }, msg

    try:
        pj = json.loads(file_content)
    except json.decoder.JSONDecodeError:
        return projectFileName, projectChanged, {
            "error": "This project file seems corrupted"
        }, msg
    except Exception:
        return projectFileName, projectChanged, {
            f"error": f"Error on file {projectFileName}: {sys.exc_info()[1]}"
        }, msg

    # transform time to decimal
    pj = utilities.convert_time_to_decimal(pj)

    # add coding_map key to old project files
    if "coding_map" not in pj:
        pj["coding_map"] = {}
        projectChanged = True

    # add subject description
    if "project_format_version" in pj:
        for idx in [x for x in pj[SUBJECTS]]:
            if "description" not in pj[SUBJECTS][idx]:
                pj[SUBJECTS][idx]["description"] = ""
                projectChanged = True

    # check if project file version is newer than current BORIS project file version
    if "project_format_version" in pj and dec(
            pj["project_format_version"]) > dec(project_format_version):
        return (
            projectFileName,
            projectChanged,
            {
                "error":
                ("This project file was created with a more recent version of BORIS.<br>"
                 f"You must update BORIS to <b>v. >= {pj['project_format_version']}</b> to open this project"
                 )
            },
            msg,
        )

    # check if old version  v. 0 *.obs
    if "project_format_version" not in pj:

        # convert VIDEO, AUDIO -> MEDIA
        pj["project_format_version"] = project_format_version
        projectChanged = True

        for obs in [x for x in pj[OBSERVATIONS]]:

            # remove 'replace audio' key
            if "replace audio" in pj[OBSERVATIONS][obs]:
                del pj[OBSERVATIONS][obs]["replace audio"]

            if pj[OBSERVATIONS][obs][TYPE] in ["VIDEO", "AUDIO"]:
                pj[OBSERVATIONS][obs][TYPE] = MEDIA

            # convert old media list in new one
            if len(pj[OBSERVATIONS][obs][FILE]):
                d1 = {PLAYER1: [pj[OBSERVATIONS][obs][FILE][0]]}

            if len(pj[OBSERVATIONS][obs][FILE]) == 2:
                d1[PLAYER2] = [pj[OBSERVATIONS][obs][FILE][1]]

            pj[OBSERVATIONS][obs][FILE] = d1

        # convert VIDEO, AUDIO -> MEDIA
        for idx in [x for x in pj[SUBJECTS]]:
            key, name = pj[SUBJECTS][idx]
            pj[SUBJECTS][idx] = {"key": key, "name": name, "description": ""}

        msg = (
            f"The project file was converted to the new format (v. {project_format_version}) in use with your version of BORIS.<br>"
            "Choose a new file name for saving it.")
        projectFileName = ""

    # update modifiers to JSON format

    # check if project format version < 4 (modifiers were str)
    project_lowerthan4 = False
    if "project_format_version" in pj and utilities.versiontuple(
            pj["project_format_version"]) < utilities.versiontuple("4.0"):
        for idx in pj[ETHOGRAM]:
            if pj[ETHOGRAM][idx]["modifiers"]:
                if isinstance(pj[ETHOGRAM][idx]["modifiers"], str):
                    project_lowerthan4 = True
                    modif_set_list = pj[ETHOGRAM][idx]["modifiers"].split("|")
                    modif_set_dict = {}
                    for modif_set in modif_set_list:
                        modif_set_dict[str(len(modif_set_dict))] = {
                            "name": "",
                            "type": SINGLE_SELECTION,
                            "values": modif_set.split(",")
                        }
                    pj[ETHOGRAM][idx]["modifiers"] = dict(modif_set_dict)
            else:
                pj[ETHOGRAM][idx]["modifiers"] = {}

        if not project_lowerthan4:
            msg = "The project version was updated from {} to {}".format(
                pj["project_format_version"], project_format_version)
            pj["project_format_version"] = project_format_version
            projectChanged = True

    # add category key if not found
    for idx in pj[ETHOGRAM]:
        if "category" not in pj[ETHOGRAM][idx]:
            pj[ETHOGRAM][idx]["category"] = ""

    # if one file is present in player #1 -> set "media_info" key with value of media_file_info
    for obs in pj[OBSERVATIONS]:
        if pj[OBSERVATIONS][obs][TYPE] in [
                MEDIA
        ] and MEDIA_INFO not in pj[OBSERVATIONS][obs]:
            pj[OBSERVATIONS][obs][MEDIA_INFO] = {
                LENGTH: {},
                "fps": {},
                "hasVideo": {},
                "hasAudio": {}
            }
            for player in [PLAYER1, PLAYER2]:
                # fix bug Anne Maijer 2017-07-17
                if pj[OBSERVATIONS][obs][FILE] == []:
                    pj[OBSERVATIONS][obs][FILE] = {"1": [], "2": []}

                for media_file_path in pj[OBSERVATIONS][obs]["file"][player]:
                    # FIX: ffmpeg path
                    ret, msg = utilities.check_ffmpeg_path()
                    if not ret:
                        return projectFileName, projectChanged, {
                            "error": "FFmpeg path not found"
                        }, ""
                    else:
                        ffmpeg_bin = msg

                    r = utilities.accurate_media_analysis(
                        ffmpeg_bin, media_file_path)

                    if "duration" in r and r["duration"]:
                        pj[OBSERVATIONS][obs][MEDIA_INFO][LENGTH][
                            media_file_path] = float(r["duration"])
                        pj[OBSERVATIONS][obs][MEDIA_INFO][FPS][
                            media_file_path] = float(r["fps"])
                        pj[OBSERVATIONS][obs][MEDIA_INFO]["hasVideo"][
                            media_file_path] = r["has_video"]
                        pj[OBSERVATIONS][obs][MEDIA_INFO]["hasAudio"][
                            media_file_path] = r["has_audio"]
                        project_updated, projectChanged = True, True
                    else:  # file path not found
                        if ("media_file_info" in pj[OBSERVATIONS][obs] and len(
                                pj[OBSERVATIONS][obs]["media_file_info"]) == 1
                                and len(
                                    pj[OBSERVATIONS][obs][FILE][PLAYER1]) == 1
                                and len(pj[OBSERVATIONS][obs][FILE][PLAYER2])
                                == 0):
                            media_md5_key = list(pj[OBSERVATIONS][obs]
                                                 ["media_file_info"].keys())[0]
                            # duration
                            pj[OBSERVATIONS][obs][MEDIA_INFO] = {
                                LENGTH: {
                                    media_file_path:
                                    pj[OBSERVATIONS][obs]["media_file_info"]
                                    [media_md5_key]["video_length"] / 1000
                                }
                            }
                            projectChanged = True

                            # FPS
                            if "nframe" in pj[OBSERVATIONS][obs][
                                    "media_file_info"][media_md5_key]:
                                pj[OBSERVATIONS][obs][MEDIA_INFO][FPS] = {
                                    media_file_path:
                                    pj[OBSERVATIONS][obs]["media_file_info"]
                                    [media_md5_key]["nframe"] /
                                    (pj[OBSERVATIONS][obs]["media_file_info"]
                                     [media_md5_key]["video_length"] / 1000)
                                }
                            else:
                                pj[OBSERVATIONS][obs][MEDIA_INFO][FPS] = {
                                    media_file_path: 0
                                }

    # update project to v.7 for time offset second player
    project_lowerthan7 = False
    for obs in pj[OBSERVATIONS]:
        if "time offset second player" in pj[OBSERVATIONS][obs]:
            if MEDIA_INFO not in pj[OBSERVATIONS][obs]:
                pj[OBSERVATIONS][obs][MEDIA_INFO] = {}
            if "offset" not in pj[OBSERVATIONS][obs][MEDIA_INFO]:
                pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"] = {}
            for player in pj[OBSERVATIONS][obs][FILE]:
                pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"][player] = 0.0
            if pj[OBSERVATIONS][obs]["time offset second player"]:
                pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"]["2"] = float(
                    pj[OBSERVATIONS][obs]["time offset second player"])

            del pj[OBSERVATIONS][obs]["time offset second player"]
            project_lowerthan7 = True

            msg = (
                f"The project file was converted to the new format (v. {project_format_version}) in use with your version of BORIS.<br>"
                f"Please note that this new version will NOT be compatible with previous BORIS versions "
                f"(&lt; v. {project_format_version}).<br>")

            projectChanged = True

    if project_lowerthan7:

        msg = (
            f"The project was updated to the current project version ({project_format_version})."
        )

        try:
            old_project_file_name = projectFileName.replace(
                ".boris", f".v{pj['project_format_version']}.boris")
            copyfile(projectFileName, old_project_file_name)
            msg += f"\n\nThe old file project was saved as {old_project_file_name}"
        except Exception:
            pass

        pj["project_format_version"] = project_format_version

    return projectFileName, projectChanged, pj, msg
Exemplo n.º 4
0
 def test_media_does_not_exist(self):
     r = utilities.accurate_media_analysis("ffmpeg", "files/xxx")
     assert "error" in r
Exemplo n.º 5
0
 def test_no_media(self):
     r = utilities.accurate_media_analysis("ffmpeg", "files/test.boris")
     assert "error" in r