添加 Box 类及其子类 ItemLocationBox 的实现,包含初始化和解析逻辑
This commit is contained in:
@@ -1,78 +1,67 @@
|
||||
import struct
|
||||
|
||||
class Box:
|
||||
"""
|
||||
Represents a generic ISOBMFF box.
|
||||
"""
|
||||
def __init__(self, size: int, box_type: str, offset: int, raw_data: bytes):
|
||||
self.size = size
|
||||
self.type = box_type
|
||||
self.offset = offset
|
||||
self.raw_data = raw_data
|
||||
self.children = [] # Will be populated for container boxes
|
||||
|
||||
def __repr__(self) -> str:
|
||||
# e.g., <Box 'ftyp' size=36 offset=8>
|
||||
return f"<Box '{self.type}' size={self.size} offset={self.offset}>"
|
||||
|
||||
# In parser.py
|
||||
|
||||
from typing import List, BinaryIO
|
||||
from io import BytesIO
|
||||
|
||||
def parse_boxes(stream: BinaryIO) -> List[Box]:
|
||||
from base import Box # Import the base Box class
|
||||
from heic_types import ItemLocationBox
|
||||
|
||||
# The factory map remains here
|
||||
BOX_TYPE_MAP = {
|
||||
'iloc': ItemLocationBox,
|
||||
}
|
||||
|
||||
CONTAINER_BOXES = {'meta', 'moov', 'trak', 'iprp', 'ipco', 'dinf', 'fiinf', 'ipro'}
|
||||
FULL_BOXES = {'meta', 'hdlr', 'pitm', 'iinf', 'iloc'}
|
||||
|
||||
def parse_boxes(stream: BinaryIO, max_size: int) -> List[Box]:
|
||||
"""
|
||||
Parses all top-level boxes from a file stream, handling special size cases.
|
||||
Parses boxes from a file stream up to a maximum size.
|
||||
Now also handles recursive parsing.
|
||||
"""
|
||||
boxes = []
|
||||
start_pos_in_stream = stream.tell()
|
||||
|
||||
stream.seek(0, 2)
|
||||
file_size = stream.tell()
|
||||
stream.seek(0)
|
||||
|
||||
while stream.tell() < file_size:
|
||||
current_offset = stream.tell()
|
||||
while stream.tell() - start_pos_in_stream < max_size:
|
||||
current_offset_in_stream = stream.tell()
|
||||
|
||||
# Read the standard 8-byte header
|
||||
header = stream.read(8)
|
||||
if len(header) < 8:
|
||||
break
|
||||
if len(header) < 8: break
|
||||
|
||||
size = struct.unpack('>I', header[:4])[0]
|
||||
box_type = header[4:].decode('ascii')
|
||||
box_type = header[4:].decode('ascii', errors='ignore')
|
||||
|
||||
header_size = 8
|
||||
content_size = 0
|
||||
|
||||
# --- NEW: Handle special size cases ---
|
||||
if size == 1:
|
||||
# The actual size is a 64-bit integer following the type
|
||||
largesize_header = stream.read(8)
|
||||
if len(largesize_header) < 8:
|
||||
break
|
||||
if len(largesize_header) < 8: break
|
||||
size = struct.unpack('>Q', largesize_header)[0]
|
||||
header_size = 16
|
||||
content_size = size - header_size
|
||||
elif size == 0:
|
||||
# The box extends to the end of the file
|
||||
content_size = file_size - current_offset - header_size
|
||||
size = content_size + header_size
|
||||
else:
|
||||
# Standard size
|
||||
content_size = size - header_size
|
||||
# --- End of new code ---
|
||||
size = max_size - (current_offset_in_stream - start_pos_in_stream)
|
||||
|
||||
# Read the box's content (raw_data)
|
||||
# We need to rewind a bit if we read largesize header to get all content
|
||||
stream.seek(current_offset + header_size)
|
||||
raw_data = stream.read(content_size)
|
||||
if len(raw_data) < content_size:
|
||||
# Avoids errors on truncated files
|
||||
break
|
||||
|
||||
box = Box(size, box_type, current_offset, raw_data)
|
||||
boxes.append(box)
|
||||
if size < header_size: break
|
||||
|
||||
content_size = size - header_size
|
||||
|
||||
# Seek to the beginning of the next box
|
||||
stream.seek(current_offset + size)
|
||||
stream.seek(current_offset_in_stream + header_size)
|
||||
raw_data = stream.read(content_size)
|
||||
if len(raw_data) < content_size: break
|
||||
|
||||
# --- Factory Pattern ---
|
||||
box_class = BOX_TYPE_MAP.get(box_type, Box)
|
||||
box = box_class(size, box_type, current_offset_in_stream, raw_data)
|
||||
|
||||
# --- NEW: Recursive parsing logic moved here ---
|
||||
if box.type in CONTAINER_BOXES:
|
||||
child_stream = BytesIO(box.raw_data)
|
||||
parse_size = len(box.raw_data)
|
||||
if box.type in FULL_BOXES:
|
||||
child_stream.read(4) # Skip version/flags
|
||||
parse_size -= 4
|
||||
box.children = parse_boxes(child_stream, parse_size)
|
||||
# --- End of new logic ---
|
||||
|
||||
boxes.append(box)
|
||||
stream.seek(current_offset_in_stream + size)
|
||||
|
||||
return boxes
|
||||
Reference in New Issue
Block a user