110 lines
4.7 KiB
Go
110 lines
4.7 KiB
Go
// 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"
|
||
)
|
||
|
||
// 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 uint32
|
||
// is an integer that declares the creation time of the presentation (in seconds
|
||
// since midnight, Jan. 1, 1904, in UTC time)
|
||
CreationTimeV1 uint64
|
||
// is an integer that declares the most recent time the presentation was
|
||
// modified (in seconds since midnight, Jan. 1, 1904, in UTC time)
|
||
ModificationTimeV0 uint32
|
||
// is an integer that declares the most recent time the presentation was
|
||
// modified (in seconds since midnight, Jan. 1, 1904, in UTC time)
|
||
ModificationTimeV1 uint64
|
||
// 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 int32
|
||
// is a fixed point 8.8 number that indicates the preferred playback volume. 1.0 (0x0100) is
|
||
// full volume.
|
||
Volume int16
|
||
// 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 = binary.BigEndian.Uint64(content[4:12])
|
||
box.ModificationTimeV1 = 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 = binary.BigEndian.Uint32(content[4:8])
|
||
box.ModificationTimeV0 = 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 = int32(binary.BigEndian.Uint32(content[position : position+4]))
|
||
box.Volume = int16(binary.BigEndian.Uint16(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
|
||
}
|