// 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" ) // ChunkOffsetBox chunk offset box struct // // 8.7.5 Chunk Offset Box // // Box Type: ‘stco’, ‘co64’ // Container: Sample Table Box (‘stbl’) // Mandatory: Yes // Quantity: Exactly one variant must be present // // The chunk offset table gives the index of each chunk into the containing file. There are two variants, // permitting the use of 32‐bit or 64‐bit offsets. The latter is useful when managing very large // presentations. At most one of these variants will occur in any single instance of a sample table. // // Offsets are file offsets, not the offset into any box within the file (e.g. Media Data Box). This permits // referring to media data in files without any box structure. It does also mean that care must be taken // when constructing a self‐contained ISO file with its metadata (Movie Box) at the front, as the size of the // Movie Box will affect the chunk offsets to the media data. type ChunkOffsetBox struct { *FullBox // is an integer that gives the number of entries in the following table EntryCount uint32 EntryList []ChunkOffsetEntry } type ChunkOffsetEntry struct { // is a 32 or 64 bit integer that gives the offset of the start of a chunk into its // containing media file. ChunkOffset uint32 } // BoxTypeChunkOffset Chunk Offset Box const BoxTypeChunkOffset = "stco" func init() { BoxDefinitions = append(BoxDefinitions, BoxDefinition{ Type: BoxTypeChunkOffset, ParentTypes: []string{BoxTypeSampleTable}, Parser: ParseChunkOffsetBox, }) } // ParseChunkOffsetBox creates a new chunk offset box struct based on bytes func ParseChunkOffsetBox(parser *Parser, filePosition uint64, headerSize uint32, content []byte) (any, error) { box := &ChunkOffsetBox{ FullBox: newFullBox(&Box{filePosition, headerSize}, content[0:4]), } // parse entry counter box.EntryCount = binary.BigEndian.Uint32(content[4:8]) // parse offset entries position := 8 for i := 0; i < int(box.EntryCount); i++ { newOffsetEntry := ChunkOffsetEntry{ ChunkOffset: binary.BigEndian.Uint32(content[position+(i*4) : position+4+(i*4)]), } box.EntryList = append(box.EntryList, newOffsetEntry) } // validate entries amount if len(box.EntryList) != int(box.EntryCount) { return box, fmt.Errorf("invalid amount of offset entries at %d; got %d but expected %d", filePosition, len(box.EntryList), box.EntryCount) } return box, nil }