blob: 9fe04c6c235cfb2aa8ace0cc956d11669051b762 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Locate a top-level moov box while copying encoded video bytes."""
import struct
class MoovLocator:
def __init__(self):
self.position = 0
self.next_box = 0
self.header = bytearray()
self.header_size = 8
self.found = None
self.valid = True
def feed(self, data):
end = self.position + len(data)
while self.valid and self.next_box is not None and self.next_box < end:
start = max(0, self.next_box + len(self.header) - self.position)
needed = self.header_size - len(self.header)
self.header.extend(data[start:start + needed])
if len(self.header) < self.header_size:
break
size, kind = struct.unpack_from(">I4s", self.header)
if size == 1:
self.header_size = 16
if len(self.header) < 16:
continue
size = struct.unpack_from(">Q", self.header, 8)[0]
if size == 0 and self.header_size == 16:
self.valid = False
break
if size == 0:
# A zero-sized box extends to EOF, resolved by finish().
if kind == b"moov" and self.found is None:
self.found = (self.next_box, 0)
elif kind == b"moov":
self.valid = False
self.next_box = None
break
if size < self.header_size:
self.valid = False
break
if kind == b"moov":
if self.found is not None:
self.valid = False
break
self.found = (self.next_box, size)
self.next_box += size
self.header.clear()
self.header_size = 8
self.position = end
def finish(self):
if (not self.valid or self.found is None
or (self.next_box is not None
and (self.next_box != self.position or self.header))):
return (0, 0)
offset, size = self.found
return offset, size or self.position - offset