68 lines
2.3 KiB
Python
68 lines
2.3 KiB
Python
|
|
import sys,time,struct,os
|
||
|
|
BODY=bytes([6,14,43,52,2,5,1,1,13,1,2,1,1,3])
|
||
|
|
ITS=bytes([6,14,43,52,2,83,1,1,13,1,2,1,1,16,1,0])
|
||
|
|
def get_frames(p):
|
||
|
|
try:
|
||
|
|
sz=os.path.getsize(p)
|
||
|
|
if sz<50000:return 0
|
||
|
|
with open(p,"rb") as f:
|
||
|
|
f.seek(max(0,sz-3000000));d=f.read()
|
||
|
|
pos=len(d)
|
||
|
|
while True:
|
||
|
|
i=d.rfind(BODY,0,pos)
|
||
|
|
if i<0:break
|
||
|
|
pos=i;bs=i+16;b0=d[bs]
|
||
|
|
if b0==0x83:bl,bv=4,struct.unpack(">I",b"\x00"+d[bs+1:bs+4])[0]
|
||
|
|
elif b0==0x82:bl,bv=3,struct.unpack(">H",d[bs+1:bs+3])[0]
|
||
|
|
else:bl,bv=1,b0
|
||
|
|
if len(d)<bs+bl+48:break
|
||
|
|
ibc=struct.unpack(">Q",d[bs+bl+40:bs+bl+48])[0]
|
||
|
|
if not ibc:continue
|
||
|
|
itd=d[i+16+bl+bv:i+16+bl+bv+ibc]
|
||
|
|
ii=itd.find(ITS)
|
||
|
|
if ii<0:break
|
||
|
|
ib0=itd[ii+16]
|
||
|
|
if ib0==0x83:ivl,ivv=4,struct.unpack(">I",b"\x00"+itd[ii+17:ii+20])[0]
|
||
|
|
elif ib0==0x82:ivl,ivv=3,struct.unpack(">H",itd[ii+17:ii+19])[0]
|
||
|
|
else:ivl,ivv=1,ib0
|
||
|
|
sd=itd[ii+16+ivl:ii+16+ivl+ivv];p2=isp=dur=0
|
||
|
|
while p2<len(sd)-3:
|
||
|
|
t=struct.unpack(">H",sd[p2:p2+2])[0];l=struct.unpack(">H",sd[p2+2:p2+4])[0]
|
||
|
|
if p2+4+l>len(sd):break
|
||
|
|
v=sd[p2+4:p2+4+l]
|
||
|
|
if t==0x3F0C and l==8:isp=struct.unpack(">q",v)[0]
|
||
|
|
elif t==0x3F0D and l==8:dur=struct.unpack(">q",v)[0]
|
||
|
|
p2+=4+l
|
||
|
|
return max(0,isp+dur)
|
||
|
|
except:return 0
|
||
|
|
return 0
|
||
|
|
mxf=sys.argv[1]
|
||
|
|
while not os.path.exists(mxf) or os.path.getsize(mxf)<20000:time.sleep(0.3)
|
||
|
|
with open(mxf,"rb") as f:hdr=f.read(200000)
|
||
|
|
offs=[]
|
||
|
|
for pat in [b"\x02\x02\x00\x08\xff\xff\xff\xff\xff\xff\xff\xff",b"\x30\x02\x00\x08\xff\xff\xff\xff\xff\xff\xff\xff"]:
|
||
|
|
p=0
|
||
|
|
while True:
|
||
|
|
i=hdr.find(pat,p)
|
||
|
|
if i<0:break
|
||
|
|
offs.append(i+4);p=i+1
|
||
|
|
print("[dur-patch] %d Duration fields"%len(offs),flush=True)
|
||
|
|
def patch(val):
|
||
|
|
if not offs:return
|
||
|
|
try:
|
||
|
|
with open(mxf,"r+b") as f:
|
||
|
|
for o in offs:f.seek(o);f.write(struct.pack(">q",val))
|
||
|
|
except Exception as e:print("[dur-patch] err:",e,flush=True)
|
||
|
|
# Premiere rejects a growing OP1a/RDD9 whose header Duration is -1 on import
|
||
|
|
# (bmx thread 87ac5750: Premiere prefers 0). raw2bmx writes -1 at clip-open, so
|
||
|
|
# overwrite every -1 with 0 immediately, BEFORE any frames exist, then track the
|
||
|
|
# live frame count every 3s.
|
||
|
|
patch(0)
|
||
|
|
print("[dur-patch] Duration=0 (initial)",flush=True)
|
||
|
|
while True:
|
||
|
|
time.sleep(3)
|
||
|
|
fc=get_frames(mxf)
|
||
|
|
if fc>0:
|
||
|
|
patch(fc)
|
||
|
|
print("[dur-patch] Duration=%d"%fc,flush=True)
|