File size: 3,466 Bytes
8e5456b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/usr/bin/env python3
"""Extract only the front-view (center) Multi-VSL clips from Data.zip.

The zip holds 87,817 mp4 across center/left/right plus ~176k stale .lock/.metadata
files from an interrupted HuggingFace upload. This pulls out just the clips named in
`Multi-VSL_WACV_2025/data/front_{train,val,test}.csv` (28,412 clips, ~23 GB) into a
flat directory, and records the per-clip resolution and fps -- both vary across
clips because the dataset ships per-clip YOLO crops, and the packing step needs
them to normalize.
"""
import argparse
import csv
import json
import os
import subprocess
import zipfile

from tqdm import tqdm

REPO = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')


def probe(path):
    out = subprocess.run(
        ['ffprobe', '-v', 'error', '-select_streams', 'v:0', '-show_entries',
         'stream=width,height,r_frame_rate,nb_frames', '-of', 'json', path],
        capture_output=True, text=True).stdout
    try:
        st = json.loads(out)['streams'][0]
        num, den = st['r_frame_rate'].split('/')
        return {'width': int(st['width']), 'height': int(st['height']),
                'fps': float(num) / float(den),
                'nb_frames': int(st.get('nb_frames') or 0)}
    except Exception:
        return None


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument('--zip', default=os.path.join(REPO, 'WACV-Data-SLR', 'Data.zip'))
    ap.add_argument('--labels-dir', default=os.path.join(REPO, 'Multi-VSL_WACV_2025', 'data'))
    ap.add_argument('--out-dir', default=os.path.join(REPO, 'Multi-VSL_front'))
    ap.add_argument('--probe', action='store_true', help='ffprobe each clip (slower)')
    args = ap.parse_args()

    vid_dir = os.path.join(args.out_dir, 'videos')
    os.makedirs(vid_dir, exist_ok=True)

    wanted = {}
    for split in ('train', 'val', 'test'):
        with open(os.path.join(args.labels_dir, f'front_{split}.csv'), encoding='utf-8') as f:
            for r in csv.DictReader(f):
                wanted[r['name']] = {'split': split, 'label': int(r['label']),
                                     'word': r['word']}
    print(f'front-view clips wanted: {len(wanted)}')

    z = zipfile.ZipFile(args.zip)
    inzip = {os.path.basename(n): n for n in z.namelist() if n.lower().endswith('.mp4')}
    print(f'mp4 in zip: {len(inzip)}')

    meta, missing, skipped = [], 0, 0
    for name, info in tqdm(sorted(wanted.items()), desc='extract'):
        src = inzip.get(name)
        if src is None:
            missing += 1
            continue
        dst = os.path.join(vid_dir, name)
        if not os.path.exists(dst) or os.path.getsize(dst) == 0:
            with z.open(src) as fi, open(dst, 'wb') as fo:
                while True:
                    b = fi.read(1 << 20)
                    if not b:
                        break
                    fo.write(b)
        else:
            skipped += 1
        rec = {'name': name, **info, 'size': os.path.getsize(dst)}
        if args.probe:
            p = probe(dst)
            if p:
                rec.update(p)
        meta.append(rec)

    with open(os.path.join(args.out_dir, 'clips.json'), 'w', encoding='utf-8') as f:
        json.dump(meta, f, ensure_ascii=False)
    print(f'extracted {len(meta)} clips ({skipped} already present), {missing} missing')
    print(f'-> {vid_dir}')
    tot = sum(m['size'] for m in meta)
    print(f'total {tot/1e9:.1f} GB')


if __name__ == '__main__':
    main()