// Copyright 2024 Martin Riedl // // 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. package gomp4 import ( "encoding/binary" "time" ) // MovieHeaderBox Movie Header Box struct // // 8.2.2 Movie Header Box // Box Type: ‘mvhd’ // Container: Movie Box (‘moov’) // Mandatory: Yes // Quantity: Exactly one // // This box defines overall information which is media‐independent, and relevant to the entire // presentation considered as a whole. type MovieHeaderBox struct { *FullBox // is an integer that declares the creation time of the presentation (in seconds // since midnight, Jan. 1, 1904, in UTC time) CreationTimeV0 time.Time // is an integer that declares the creation time of the presentation (in seconds // since midnight, Jan. 1, 1904, in UTC time) CreationTimeV1 time.Time // is an integer that declares the most recent time the presentation was // modified (in seconds since midnight, Jan. 1, 1904, in UTC time) ModificationTimeV0 time.Time // is an integer that declares the most recent time the presentation was // modified (in seconds since midnight, Jan. 1, 1904, in UTC time) ModificationTimeV1 time.Time // is an integer that specifies the time‐scale for the entire presentation; this is the // number of time units that pass in one second. For example, a time coordinate system that // measures time in sixtieths of a second has a time scale of 60. Timescale uint32 // is an integer that declares length of the presentation (in the indicated timescale). This // property is derived from the presentation’s tracks: the value of this field corresponds to the // duration of the longest track in the presentation. If the duration cannot be determined then // duration is set to all 1s. DurationV0 uint32 // is an integer that declares length of the presentation (in the indicated timescale). This // property is derived from the presentation’s tracks: the value of this field corresponds to the // duration of the longest track in the presentation. If the duration cannot be determined then // duration is set to all 1s. DurationV1 uint64 // is a fixed point 16.16 number that indicates the preferred rate to play the presentation; 1.0 // (0x00010000) is normal forward playback Rate Fixed1616 // is a fixed point 8.8 number that indicates the preferred playback volume. 1.0 (0x0100) is // full volume. Volume Fixed88 // provides a transformation matrix for the video; (u,v,w) are restricted here to (0,0,1), hex // values (0,0,0x40000000). Matrix []int32 // is a non‐zero integer that indicates a value to use for the track ID of the next track // to be added to this presentation. Zero is not a valid track ID value. The value of // next_track_ID shall be larger than the largest track‐ID in use. If this value is equal to all 1s // (32‐bit maxint), and a new media track is to be added, then a search must be made in the file for // an unused track identifier. NextTrackID uint32 } // ParseMovieHeaderBox creates a new Movie Header Box struct func ParseMovieHeaderBox(filePosition uint64, headerSize uint32, content []byte) *MovieHeaderBox { box := &MovieHeaderBox{ FullBox: newFullBox(&Box{filePosition, headerSize}, content[0:4]), } position := 4 if box.Version == 1 { box.CreationTimeV1 = since1904ToTime(int64(binary.BigEndian.Uint64(content[4:12]))) box.ModificationTimeV1 = since1904ToTime(int64(binary.BigEndian.Uint64(content[12:20]))) box.Timescale = binary.BigEndian.Uint32(content[20:24]) box.DurationV1 = binary.BigEndian.Uint64(content[24:32]) position += 28 } else { // version == 0 box.CreationTimeV0 = since1904ToTime(int64(binary.BigEndian.Uint32(content[4:8]))) box.ModificationTimeV0 = since1904ToTime(int64(binary.BigEndian.Uint32(content[8:12]))) box.Timescale = binary.BigEndian.Uint32(content[12:16]) box.DurationV0 = binary.BigEndian.Uint32(content[16:20]) position += 16 } box.Rate = NewFixed1616ByBytes(content[position : position+4]) box.Volume = NewFixed88ByBytes(content[position+4 : position+6]) position += 4 + 2 + 2 + 8 // 4 bytes for rate, 2 bytes for volume, 2 bytes reserved and 8 bytes reserved for i := 0; i < 9; i++ { box.Matrix = append(box.Matrix, int32(binary.BigEndian.Uint32(content[position:position+4]))) position += 4 } // skip 6*32 bit "pre-defined" position += 6 * 4 box.NextTrackID = binary.BigEndian.Uint32(content[position : position+4]) return box }