Files
cvat-ai--cvat/utils/ffmpeg_compatibility/switch_task_to_static_cache.py
T
2026-07-13 13:32:23 +08:00

108 lines
3.7 KiB
Python

# This script is intended to be used with an old release of CVAT, so it uses the internal
# API as it existed in that release. Because of this, we cannot use Pylint, since it will attempt
# to match the API calls against the current API and report spurious problems.
# pylint: disable=all
from __future__ import annotations
import argparse
import os
import shutil
from unittest.mock import Mock, PropertyMock, patch
import django
from django.db import connection, transaction
from django.db.migrations.recorder import MigrationRecorder
from tqdm import tqdm
django.setup()
from cvat.apps.engine import models
from cvat.apps.engine.media_extractors import MEDIA_TYPES
from cvat.apps.engine.task import _create_static_chunks
EXPECTED_LAST_ENGINE_MIGRATION = "0095_fix_related_names"
def _ensure_last_engine_applied_migration_name():
recorder = MigrationRecorder(connection)
app_name = "engine"
applied_migrations_names = list(
recorder.Migration.objects.filter(app=app_name).values_list("name", flat=True)
)
assert applied_migrations_names, f"No migrations applied for app '{app_name}'"
highest_by_number = max(applied_migrations_names, key=lambda name: int(name.split("_")[0]))
assert highest_by_number == EXPECTED_LAST_ENGINE_MIGRATION, (
f"Last applied migration for app '{app_name}' is '{highest_by_number}', "
f"expected '{EXPECTED_LAST_ENGINE_MIGRATION}'. "
f"Manually verify that the script still works correctly "
f"and update EXPECTED_ENGINE_LAST_ENGINE_MIGRATION var in the script."
)
def _build_extractor(data: models.Data):
details = {
"source_path": [os.path.join(data.get_upload_dirname(), data.video.path)],
"step": data.get_frame_step(),
"start": data.start_frame,
"stop": data.stop_frame,
}
return MEDIA_TYPES["video"]["extractor"](**details)
def _cleanup_static_cache(data: models.Data):
for folder in (data.get_compressed_cache_dirname(), data.get_original_cache_dirname()):
if os.path.exists(folder):
shutil.rmtree(folder)
os.makedirs(folder)
def main():
parser = argparse.ArgumentParser(
description="Switch a video task to static cache storage and generate static chunks."
)
parser.add_argument("task_id", type=int, help="Task ID (integer)")
args = parser.parse_args()
task_id = args.task_id
_ensure_last_engine_applied_migration_name()
with transaction.atomic():
try:
task: models.Task = models.Task.objects.select_for_update().get(pk=task_id)
except models.Task.DoesNotExist as ex:
raise ValueError(f"Task #{task_id} not found.") from ex
assert (
task.mode == "interpolation"
), f"Task #{task_id} is not a video task (mode={task.mode})."
data: models.Data = task.data
extractor = _build_extractor(data)
data.storage_method = models.StorageMethodChoice.FILE_SYSTEM
_cleanup_static_cache(data)
with tqdm(total=1.0, bar_format="{l_bar}{bar}| {n:.2f}/{total:.2f}") as pbar:
class _PropertyMock(PropertyMock):
def __set__(self, instance, value):
pbar.n = value
pbar.refresh()
with patch("cvat.apps.engine.task.ImportRQMeta", return_value=Mock()) as mock:
type(mock.for_job.return_value).task_progress = _PropertyMock()
_create_static_chunks(
task, media_extractor=extractor, upload_dir=data.get_upload_dirname()
)
data.save(update_fields=["storage_method"])
print(f"Task #{task_id}: switched to static cache.")
if __name__ == "__main__":
main()