import os import glob import re from common import constants def get_latest_n_segments(camera_root_dir: str, n: int) -> list: """ 获取最新的n个TS分片 逻辑: 1. 获取index_code文件夹下所有时间戳文件夹 2. 按时间戳名称降序排序(最新的在前) 3. 从最新的时间戳文件夹开始获取分片 4. 如果分片数不足n,继续从上一个时间戳文件夹获取 5. 返回最新的n个分片路径list(按时间顺序,最旧的在前) """ if not os.path.exists(camera_root_dir): return [] # 获取所有时间戳文件夹并排序(字符串排序即时间排序) timestamp_folders = [] for folder_name in os.listdir(camera_root_dir): folder_path = os.path.join(camera_root_dir, folder_name) if os.path.isdir(folder_path): timestamp_folders.append(folder_name) if not timestamp_folders: return [] # 降序排序,最新的在前 timestamp_folders.sort(reverse=True) # 收集分片 all_segments = [] for ts_folder in timestamp_folders: ts_folder_path = os.path.join(camera_root_dir, ts_folder) pattern = os.path.join(ts_folder_path, "segment_*.ts") segment_files = glob.glob(pattern) # 按分片序号排序 segment_files.sort(key=lambda x: int(os.path.basename(x).split('_')[-1].split('.')[0])) all_segments.extend(segment_files) # 已经收集够了 if len(all_segments) >= n: break # 返回最新的n个(取最后n个,因为最新的在后面) if len(all_segments) >= n: return all_segments[-n:] else: return all_segments def get_latest_n_segments_by_camera_id(camera_id: str, n: int) -> list: """ 根据摄像头ID获取最新的n个TS分片 Args: camera_id: 摄像头ID n: 获取的分片数量 Returns: 最新的n个分片路径list """ camera_root_dir = os.path.join(constants.HLS_ROOT_PATH, camera_id) return get_latest_n_segments(camera_root_dir, n) def parse_segment_info(segment_path: str) -> tuple: """ 从TS分片路径解析出 camera_id, timestamp, sequence Args: segment_path: TS分片路径,格式如: hls_root_path/camera_id/timestamp/segment_xxxxx.ts Returns: (camera_id, timestamp, sequence) 或 (None, None, None) 解析失败时 """ try: # 获取文件名和目录结构 # 路径格式: .../camera_id/timestamp/segment_00001.ts abs_path = os.path.abspath(segment_path) parts = abs_path.split(os.sep) # 从后往前找 # parts[-1] = segment_00001.ts # parts[-2] = timestamp # parts[-3] = camera_id if len(parts) < 3: return None, None, None # 解析序号 filename = parts[-1] match = re.search(r'segment_(\d+)\.ts$', filename) if not match: return None, None, None sequence = match.group(1) # 时间戳 timestamp = parts[-2] # camera_id camera_id = parts[-3] return camera_id, timestamp, sequence except Exception: return None, None, None def get_segments_before_current(current_segment_path: str, n: int) -> list: """ 获取当前分片之前的n个分片(包括当前分片) Args: current_segment_path: 当前TS分片路径 n: 需要获取的分片数量 Returns: 分片路径列表(按时间顺序,旧的在前),如果不够n个则返回现有的 """ if not current_segment_path or not os.path.exists(current_segment_path): return [] # 解析当前分片信息 camera_id, timestamp, current_seq = parse_segment_info(current_segment_path) if not camera_id: return [] # 构建摄像头根目录和时间戳目录 camera_root_dir = os.path.join(constants.HLS_ROOT_PATH, camera_id) timestamp_dir = os.path.join(camera_root_dir, timestamp) if not os.path.exists(timestamp_dir): return [] # 获取当前时间戳文件夹下的所有分片 pattern = os.path.join(timestamp_dir, "segment_*.ts") segment_files = glob.glob(pattern) # 按分片序号排序 segment_files.sort(key=lambda x: int(os.path.basename(x).split('_')[-1].split('.')[0])) # 找到当前分片的位置 try: current_index = segment_files.index(current_segment_path) except ValueError: # 当前分片不在列表中 return [] # 计算起始位置 start_index = max(0, current_index - n + 1) # 返回从起始位置到当前位置的所有分片 result = segment_files[start_index:current_index + 1] # 如果不够n个,需要从之前的时间戳文件夹获取 if len(result) < n: # 获取所有时间戳文件夹 timestamp_folders = [] for folder_name in os.listdir(camera_root_dir): folder_path = os.path.join(camera_root_dir, folder_name) if os.path.isdir(folder_path): timestamp_folders.append(folder_name) # 排序,找到当前时间戳之前的时间戳 timestamp_folders.sort() try: current_ts_index = timestamp_folders.index(timestamp) except ValueError: current_ts_index = len(timestamp_folders) # 从之前的时间戳文件夹获取分片 needed_count = n - len(result) for i in range(current_ts_index - 1, -1, -1): prev_ts_dir = os.path.join(camera_root_dir, timestamp_folders[i]) prev_pattern = os.path.join(prev_ts_dir, "segment_*.ts") prev_segments = glob.glob(prev_pattern) prev_segments.sort(key=lambda x: int(os.path.basename(x).split('_')[-1].split('.')[0])) # 取最后 needed_count 个 take_count = min(needed_count, len(prev_segments)) if take_count > 0: result = prev_segments[-take_count:] + result needed_count -= take_count if needed_count <= 0: break return result