Потоковая загрузка видео с серверов телеграм. Telethon
Задача: скачать только 5мб из видео не зависимо от размера. При этом файл должен быть не битый, т.е спокойно открываться. На один запрос не должно тратиться более 1мб озу.
Проблема в том, что при загрузке через client.iter_download я не могу найти атом moov, который отвечает за расположение кадров, без него видео не загружается корректно. Атомы ftyp и mdat присутствуют. Так же присутствуют атомы stsz, stco, trak. В итоге видео получается битое и не воспроизводится.
Мой код:
if event.video:
logger.debug("Start processing video...")
flag = -1
frames_count = [0, 0] # all frames, loaded
ftyp, mdat, stsz, stco, trak = bytearray(), bytearray(), bytearray(), bytearray(), bytearray()
gen_pos = 0
async for chunk in client.iter_download(media, chunk_size=CHUNK_SIZE):
pos = 0
while pos < len(chunk) - 8:
part = bytearray(chunk[pos: pos+8])
size, atom = struct.unpack('>I4s', part)
if size == 1:
part.extend(chunk[pos+8: pos+16])
size = struct.unpack('>Q', chunk[pos+8: pos+16])[0]
if atom == b"ftyp":
flag = 0
ftyp.extend(part)
logger.debug(f"ftyp atom size: {size}")
elif atom == b"mdat":
flag = 1
mdat.extend(part)
logger.debug(f"mdat atom size: {size}")
elif atom == b"stsz":
flag = 2
stsz.extend(part)
logger.debug(f"stsz atom size: {size}")
elif atom == b"stco":
flag = 3
stco.extend(part)
logger.debug(f"stco atom size: {size}")
elif atom == b"trak":
flag = 4
trak.extend(part)
logger.debug(f"trak atom size: {size}")
else:
if flag == 0:
if len(ftyp) < 128:
ftyp.extend(part)
elif flag == 1:
is_frame = False
if b'\x00\x00\x00\x01' in part or b'\x00\x00\x01':
frames_count[0] += 1
is_frame = True
if len(mdat) < MDAT_SIZE:
mdat.extend(part)
if is_frame:
frames_count[1] += 1
elif 1 < flag < 5:
if len(stsz) + len(stco) + len(trak) < MOOV_SIZE:
if flag == 2:
stsz.extend(part)
elif flag == 3:
stco.extend(part)
elif flag == 4:
trak.extend(part)
pos += len(part)
gen_pos += len(part)
data = ftyp + mdat + stsz + stco + trak
logger.debug(data)
with open(f"temp/{event.id}.h264", "wb") as file:
for offset, size in zip(stco, stsz):
frame = data[offset : offset + size]
file.write(b'\x00\x00\x00\x01')
file.write(frame)
logger.debug(f"Frames count | loaded: {frames_count[1]}; all: {frames_count[0]}")