From e4694cd76ecddab157b06aafef83779556250b66 Mon Sep 17 00:00:00 2001 From: Martin Riedl Date: Fri, 18 Oct 2024 18:13:05 +0200 Subject: [PATCH] new media box and media header box --- Box.go | 4 +++ MediaBox.go | 41 +++++++++++++++++++++++ MediaHeaderBox.go | 85 +++++++++++++++++++++++++++++++++++++++++++++++ Parser.go | 4 +++ README.md | 4 +-- 5 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 MediaBox.go create mode 100644 MediaHeaderBox.go diff --git a/Box.go b/Box.go index 000bf43..c09918d 100644 --- a/Box.go +++ b/Box.go @@ -32,6 +32,10 @@ const ( BoxTypeTrackBox = "trak" // BoxTypeTrackHeaderBox Track Header Box BoxTypeTrackHeaderBox = "tkhd" + // BoxTypeMediaBox Media Box + BoxTypeMediaBox = "mdia" + // BoxTypeMediaHeaderBox Media Header Box + BoxTypeMediaHeaderBox = "mdhd" // BoxTypeMovieFragment Movie Fragment Box BoxTypeMovieFragment = "moof" // BoxTypeMovieFragmentHeader Movie Fragment Header Box diff --git a/MediaBox.go b/MediaBox.go new file mode 100644 index 0000000..41edd19 --- /dev/null +++ b/MediaBox.go @@ -0,0 +1,41 @@ +// 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 + +// MediaBox media box struct +// +// 8.4.1 Media Box +// +// Box Type: ‘mdia’ +// Container: Track Box (‘trak’) +// Mandatory: Yes +// Quantity: Exactly one +// +// The media declaration container contains all the objects that declare information about the media data +// within a track. +type MediaBox struct { + *Box + ChildBoxes []interface{} +} + +// ParseMediaBox creates a new media box struct based on bytes +func ParseMediaBox(filePosition uint64, headerSize uint32, content []byte) (*MediaBox, error) { + box := &MediaBox{Box: &Box{filePosition, headerSize}} + + // parse child boxes + var err error + box.ChildBoxes, err = box.parseChildBoxes(filePosition, content) + return box, err +} diff --git a/MediaHeaderBox.go b/MediaHeaderBox.go new file mode 100644 index 0000000..39646af --- /dev/null +++ b/MediaHeaderBox.go @@ -0,0 +1,85 @@ +// 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" +) + +// MediaHeaderBox media header box struct +// +// 8.4.2 Media Header Box +// +// Box Type: ‘mdhd’ +// Container: Media Box (‘mdia’) +// Mandatory: Yes +// Quantity: Exactly one +// +// The media header declares overall information that is media‐independent, and relevant to +// characteristics of the media in a track. +type MediaHeaderBox struct { + *FullBox + // is an integer that declares the creation time of the media in this track (in + // seconds since midnight, Jan. 1, 1904, in UTC time). + CreationTimeV0 time.Time + // is an integer that declares the creation time of the media in this track (in + // seconds since midnight, Jan. 1, 1904, in UTC time). + CreationTimeV1 time.Time + // is an integer that declares the most recent time the media in this track 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 media in this track was + // modified (in seconds since midnight, Jan. 1, 1904, in UTC time). + ModificationTimeV1 time.Time + // is an integer that specifies the time‐scale for this media; 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 the duration of this media (in the scale of the timescale). If the + // duration cannot be determined then duration is set to all 1s. + DurationV0 uint32 + // is an integer that declares the duration of this media (in the scale of the timescale). If the + // duration cannot be determined then duration is set to all 1s. + DurationV1 uint64 + + // TODO: parse language language +} + +// ParseMediaHeaderBox creates a new Track Header Box struct +func ParseMediaHeaderBox(filePosition uint64, headerSize uint32, content []byte) *MediaHeaderBox { + box := &MediaHeaderBox{ + FullBox: newFullBox(&Box{filePosition, headerSize}, content[0:4]), + } + + position := 4 + if box.Version == 1 { + box.CreationTimeV1 = since1904ToTime(int64(binary.BigEndian.Uint64(content[position : position+8]))) + box.ModificationTimeV1 = since1904ToTime(int64(binary.BigEndian.Uint64(content[position+8 : position+16]))) + box.Timescale = binary.BigEndian.Uint32(content[position+16 : position+20]) + box.DurationV1 = binary.BigEndian.Uint64(content[position+20 : position+28]) + position += 28 + } else { // version == 0 + box.CreationTimeV0 = since1904ToTime(int64(binary.BigEndian.Uint32(content[position : position+4]))) + box.ModificationTimeV0 = since1904ToTime(int64(binary.BigEndian.Uint32(content[position+4 : position+8]))) + box.Timescale = binary.BigEndian.Uint32(content[position+8 : position+12]) + box.DurationV0 = binary.BigEndian.Uint32(content[position+12 : position+16]) + position += 16 + } + + // TODO: parse language language + + return box +} diff --git a/Parser.go b/Parser.go index 237114e..49f4a36 100644 --- a/Parser.go +++ b/Parser.go @@ -116,6 +116,10 @@ func parseNextBox(reader io.Reader, filePosition uint64) (box interface{}, endPo box, err = ParseTrackBox(filePosition, boxHeaderSize, boxContentBytes) case BoxTypeTrackHeaderBox: box = ParseTrackHeaderBox(filePosition, boxHeaderSize, boxContentBytes) + case BoxTypeMediaBox: + box, err = ParseMediaBox(filePosition, boxHeaderSize, boxContentBytes) + case BoxTypeMediaHeaderBox: + box = ParseMediaHeaderBox(filePosition, boxHeaderSize, boxContentBytes) case BoxTypeMovieFragment: box, err = ParseMovieFragmentBox(filePosition, boxHeaderSize, boxContentBytes) case BoxTypeMovieFragmentHeader: diff --git a/README.md b/README.md index 8b3ecef..3078c61 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ Implementation progress | 8.3.2 Track Header Box | tkhd | 100% | | 8.3.3 Track Reference Box | tref | - | | 8.3.4 Track Group Box | trgr | - | -| 8.4.1 Media Box | mdia | - | -| 8.4.2 Media Header Box | mdhd | - | +| 8.4.1 Media Box | mdia | 100% | +| 8.4.2 Media Header Box | mdhd | 80% | | 8.4.3 Handler Reference Box | hdlr | - | | 8.4.4 Media Information Box | minf | - | | 8.4.5.2 Null Media Header Box | nmhd | - |