feat: new data reference box

This commit is contained in:
Martin Riedl 2024-11-20 17:53:24 +01:00
parent 65eb9ae5c1
commit 00105f5142
Signed by: martinr92
GPG key ID: FB68DA65516A804C
6 changed files with 153 additions and 5 deletions

6
Box.go
View file

@ -42,6 +42,12 @@ const (
BoxTypeMediaInformation = "minf"
// BoxTypeDataInformation Data Information Box
BoxTypeDataInformation = "dinf"
// BoxTypeDataReferenceBox Data Reference Box
BoxTypeDataReferenceBox = "dref"
// BoxTypeDataEntryUrlBox Data Entry URL Box
BoxTypeDataEntryUrlBox = "url "
// BoxTypeDataEntryUrnBox Data Entry URN Box
BoxTypeDataEntryUrnBox = "urn "
// BoxTypeMovieFragment Movie Fragment Box
BoxTypeMovieFragment = "moof"
// BoxTypeMovieFragmentHeader Movie Fragment Header Box

136
DataReferenceBox.go Normal file
View file

@ -0,0 +1,136 @@
// 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"
"fmt"
)
// DataReferenceBox data reference box struct
//
// 8.7.2 Data Reference Box
//
// Box Types: dref
// Container: Data Information Box (dinf)
// Mandatory: Yes
// Quantity: Exactly one
//
// The data reference object contains a table of data references (normally URLs) that declare the
// location(s) of the media data used within the presentation. The data reference index in the sample
// description ties entries in this table to the samples in the track. A track may be split over several
// sources in this way.
//
// If the flag is set indicating that the data is in the same file as this box, then no string (not even an empty
// one) shall be supplied in the entry field.
//
// The entry_count in the DataReferenceBox shall be 1 or greater; each DataEntryBox within the
// DataReferenceBox shall be either a DataEntryUrnBox or a DataEntryUrlBox.
//
// When a file that has data entries with the flag set indicating that the media data is in the same file, is
// split into segments for transport, the value of this flag does not change, as the file is (logically)
// reassembled after the transport operation.
type DataReferenceBox struct {
*FullBox
// EntryCount is an integer that counts the actual entries
EntryCount uint32
ChildBoxes []interface{}
}
// ParseDataReferenceBox creates a new data reference box struct based on bytes
func ParseDataReferenceBox(filePosition uint64, headerSize uint32, content []byte) (*DataReferenceBox, error) {
box := &DataReferenceBox{
FullBox: newFullBox(&Box{filePosition, headerSize}, content[0:4]),
}
// parse entry counter
box.EntryCount = binary.BigEndian.Uint32(content[4:8])
// parse child boxes
var err error
box.ChildBoxes, err = box.parseChildBoxes(filePosition, content[8:])
if err != nil {
return box, err
}
// validate entries amount
if len(box.ChildBoxes) != int(box.EntryCount) {
return box, fmt.Errorf("invalid amount of boxes at %d", filePosition)
}
return box, err
}
// DataEntryUrlBox data entry URL box struct
//
// Box Types: url
// Container: Data Information Box (dref)
// Mandatory: Yes (at least one of url or urn shall be present)
// Quantity: One or more
type DataEntryUrlBox struct {
*FullBox
// Location is a URL, and is required in a URL entry and optional in a URN entry, where it gives a location to find
// the resource with the given name. If the
// selfcontained flag is set, the URL form is used and no string is present; the box terminates with
// the entryflags field. The URL type should be of a service that delivers a file (e.g. URLs of type file,
// http, ftp etc.), and which services ideally also permit random access. Relative URLs are
// permissible and are relative to the file containing the Movie Box that contains this data
// reference.
Location string
}
// ParseDataEntryUrlBox creates a data entry URL box struct based on bytes
func ParseDataEntryUrlBox(filePosition uint64, headerSize uint32, content []byte) *DataEntryUrlBox {
box := &DataEntryUrlBox{
FullBox: newFullBox(&Box{filePosition, headerSize}, content[0:4]),
}
box.Location, _ = ParseStringNullTerminated(content[4:])
return box
}
// DataEntryUrnBox data entry URN box struct
//
// Box Types: urn
// Container: Data Information Box (dref)
// Mandatory: Yes (at least one of url or urn shall be present)
// Quantity: One or more
type DataEntryUrnBox struct {
*FullBox
// Name is a URN, and is required in a URN entry.
Name string
// Location is a URL, and is required in a URL entry and optional in a URN entry, where it gives a location to find
// the resource with the given name. If the
// selfcontained flag is set, the URL form is used and no string is present; the box terminates with
// the entryflags field. The URL type should be of a service that delivers a file (e.g. URLs of type file,
// http, ftp etc.), and which services ideally also permit random access. Relative URLs are
// permissible and are relative to the file containing the Movie Box that contains this data
// reference.
Location string
}
// ParseDataEntryUrnBox creates a data entry URN box struct based on bytes
func ParseDataEntryUrnBox(filePosition uint64, headerSize uint32, content []byte) *DataEntryUrnBox {
box := &DataEntryUrnBox{
FullBox: newFullBox(&Box{filePosition, headerSize}, content[0:4]),
}
name, endIndex := ParseStringNullTerminated(content[4:])
box.Name = name
box.Location, _ = ParseStringNullTerminated(content[4+endIndex:])
return box
}

View file

@ -65,7 +65,7 @@ func ParseHandlerReferenceBox(filePosition uint64, headerSize uint32, content []
position += 3 * 4
// parse name
box.Name = ParseStringNullTerminated(content[position:])
box.Name, _ = ParseStringNullTerminated(content[position:])
return box
}

View file

@ -126,6 +126,12 @@ func parseNextBox(reader io.Reader, filePosition uint64) (box interface{}, endPo
box, err = ParseMediaInformationBox(filePosition, boxHeaderSize, boxContentBytes)
case BoxTypeDataInformation:
box, err = ParseDataInformationBox(filePosition, boxHeaderSize, boxContentBytes)
case BoxTypeDataReferenceBox:
box, err = ParseDataReferenceBox(filePosition, boxHeaderSize, boxContentBytes)
case BoxTypeDataEntryUrlBox:
box = ParseDataEntryUrlBox(filePosition, boxHeaderSize, boxContentBytes)
case BoxTypeDataEntryUrnBox:
box = ParseDataEntryUrnBox(filePosition, boxHeaderSize, boxContentBytes)
case BoxTypeMovieFragment:
box, err = ParseMovieFragmentBox(filePosition, boxHeaderSize, boxContentBytes)
case BoxTypeMovieFragmentHeader:

View file

@ -45,7 +45,7 @@ Implementation progress
| 8.6.5 Edit Box | edts | - |
| 8.6.6 Edit List Box | elst | - |
| 8.7.1 Data Information Box | dinf | 100% |
| 8.7.2 Data Reference Box | dref, url, urn | - |
| 8.7.2 Data Reference Box | dref, url, urn | 100% |
| 8.7.3 Sample Size Boxes | stsz, stz2 | - |
| 8.7.4 Sample To Chunk Box | stsc | - |
| 8.7.5 Chunk Offset Box | stco, co64 | - |

View file

@ -18,11 +18,11 @@ import (
"bytes"
)
func ParseStringNullTerminated(b []byte) string {
func ParseStringNullTerminated(b []byte) (string, int) {
endIndex := bytes.IndexByte(b, '\x00')
if endIndex == -1 {
return ""
return "", -1
}
return string(b[:endIndex])
return string(b[:endIndex]), endIndex
}