Spaces:
Sleeping
Sleeping
#! /usr/bin/env python | |
# -*- coding: utf-8 -*- | |
# Copyright 2016 Google Inc. All rights reserved. | |
# | |
# Licensed 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. | |
"""MPEG4 processing classes. | |
Functions for loading MP4/MOV files and manipulating boxes. | |
""" | |
from spatialmedia.mpeg import box | |
from spatialmedia.mpeg import constants | |
from spatialmedia.mpeg import container | |
def load(fh): | |
"""Load the mpeg4 file structure of a file. | |
Args: | |
fh: file handle, input file handle. | |
position: int, current file position. | |
size: int, maximum size. This is used to ensure correct box sizes. | |
return: | |
mpeg4, the loaded mpeg4 structure. | |
""" | |
fh.seek(0, 2) | |
size = fh.tell() | |
contents = container.load_multiple(fh, 0, size) | |
if not contents: | |
print("Error, failed to load .mp4 file.") | |
return None | |
elif len(contents) == 0: | |
print("Error, no boxes found.") | |
return None | |
loaded_mpeg4 = Mpeg4Container() | |
loaded_mpeg4.contents = contents | |
for element in loaded_mpeg4.contents: | |
if (element.name == constants.TAG_MOOV): | |
loaded_mpeg4.moov_box = element | |
if (element.name == constants.TAG_FREE): | |
loaded_mpeg4.free_box = element | |
if (element.name == constants.TAG_MDAT | |
and not loaded_mpeg4.first_mdat_box): | |
loaded_mpeg4.first_mdat_box = element | |
if (element.name == constants.TAG_FTYP): | |
loaded_mpeg4.ftyp_box = element | |
if not loaded_mpeg4.moov_box: | |
print("Error, file does not contain moov box.") | |
return None | |
if not loaded_mpeg4.first_mdat_box: | |
print("Error, file does not contain mdat box.") | |
return None | |
loaded_mpeg4.first_mdat_position = \ | |
loaded_mpeg4.first_mdat_box.position | |
loaded_mpeg4.first_mdat_position += \ | |
loaded_mpeg4.first_mdat_box.header_size | |
loaded_mpeg4.content_size = 0 | |
for element in loaded_mpeg4.contents: | |
loaded_mpeg4.content_size += element.size() | |
return loaded_mpeg4 | |
class Mpeg4Container(container.Container): | |
"""Specialized behaviour for the root mpeg4 container.""" | |
def __init__(self): | |
self.contents = list() | |
self.content_size = 0 | |
self.header_size = 0 | |
self.moov_box = None | |
self.free_box = None | |
self.first_mdat_box = None | |
self.ftyp_box = None | |
self.first_mdat_position = None | |
self.padding = 0 | |
def merge(self, element): | |
"""Mpeg4 containers do not support merging.""" | |
print("Cannot merge mpeg4 files") | |
exit(0) | |
def print_structure(self): | |
"""Print mpeg4 file structure recursively.""" | |
print("mpeg4 [{}]".format(self.content_size)) | |
size = len(self.contents) | |
for i in range(size): | |
next_indent = " βββ" | |
if i == (size - 1): | |
next_indent = " βββ" | |
self.contents[i].print_structure(next_indent) | |
def save(self, in_fh, out_fh): | |
"""Save mpeg4 filecontent to file. | |
Args: | |
in_fh: file handle, source file handle for uncached contents. | |
out_fh: file handle, destination file hand for saved file. | |
""" | |
self.resize() | |
new_position = 0 | |
for element in self.contents: | |
if element.name == constants.TAG_MDAT: | |
new_position += element.header_size | |
break | |
new_position += element.size() | |
delta = new_position - self.first_mdat_position | |
for element in self.contents: | |
element.save(in_fh, out_fh, delta) |