Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/abema/go-mp4
Go library for reading and writing MP4 file
https://github.com/abema/go-mp4
fmp4 go golang mp4 mp4box
Last synced: 5 days ago
JSON representation
Go library for reading and writing MP4 file
- Host: GitHub
- URL: https://github.com/abema/go-mp4
- Owner: abema
- License: mit
- Created: 2020-01-09T14:09:33.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2024-09-06T14:31:18.000Z (2 months ago)
- Last Synced: 2024-09-06T17:15:07.047Z (2 months ago)
- Topics: fmp4, go, golang, mp4, mp4box
- Language: Go
- Homepage: https://dev.to/sunfishshogi/go-mp4-golang-library-and-cli-tool-for-mp4-52o1
- Size: 948 KB
- Stars: 450
- Watchers: 30
- Forks: 31
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- my-awesome - abema/go-mp4 - 09 star:0.5k fork:0.0k Go library for reading and writing MP4 file (Go)
README
go-mp4
------[![Go Reference](https://pkg.go.dev/badge/github.com/abema/go-mp4.svg)](https://pkg.go.dev/github.com/abema/go-mp4)
![Test](https://github.com/abema/go-mp4/actions/workflows/test.yml/badge.svg)
[![Coverage Status](https://coveralls.io/repos/github/abema/go-mp4/badge.svg)](https://coveralls.io/github/abema/go-mp4)
[![Go Report Card](https://goreportcard.com/badge/github.com/abema/go-mp4)](https://goreportcard.com/report/github.com/abema/go-mp4)go-mp4 is Go library which provides low-level I/O interfaces of MP4.
This library supports you to parse or build any MP4 boxes(atoms) directly.go-mp4 provides very flexible interfaces for reading boxes.
If you want to read only specific parts of MP4 file, this library extracts those boxes via io.ReadSeeker interface.On the other hand, this library is not suitable for complex data conversions.
## Integration with your Go application
### Reading
Using [ReadBoxStructure](https://pkg.go.dev/github.com/abema/go-mp4#ReadBoxStructure) or [ReadBoxStructureFromInternal](https://pkg.go.dev/github.com/abema/go-mp4#ReadBoxStructureFromInternal), you can scan box(atom) tree by depth-first order.
```go
// expand all boxes
_, err := mp4.ReadBoxStructure(file, func(h *mp4.ReadHandle) (interface{}, error) {
fmt.Println("depth", len(h.Path))// Box Type (e.g. "mdhd", "tfdt", "mdat")
fmt.Println("type", h.BoxInfo.Type.String())// Box Size
fmt.Println("size", h.BoxInfo.Size)if h.BoxInfo.IsSupportedType() {
// Payload
box, _, err := h.ReadPayload()
if err != nil {
return nil, err
}
str, err := mp4.Stringify(box, h.BoxInfo.Context)
if err != nil {
return nil, err
}
fmt.Println("payload", str)// Expands children
return h.Expand()
}
return nil, nil
})
```[ExtractBox](https://pkg.go.dev/github.com/abema/go-mp4#ExtractBox), [ExtractBoxes](https://pkg.go.dev/github.com/abema/go-mp4#ExtractBoxes), [ExtractBoxWithPayload](https://pkg.go.dev/github.com/abema/go-mp4#ExtractBoxWithPayload), [ExtractBoxesWithPayload](https://pkg.go.dev/github.com/abema/go-mp4#ExtractBoxesWithPayload), and [Probe](https://pkg.go.dev/github.com/abema/go-mp4#Probe) are wrapper functions of ReadBoxStructure.
```go
// extract specific boxes
boxes, err := mp4.ExtractBoxWithPayload(file, nil, mp4.BoxPath{mp4.BoxTypeMoov(), mp4.BoxTypeTrak(), mp4.BoxTypeTkhd()})
if err != nil {
:
}
for _, box := range boxes {
tkhd := box.Payload.(*mp4.Tkhd)
fmt.Println("track ID:", tkhd.TrackID)
}
``````go
// get basic informations
info, err := mp4.Probe(bufseekio.NewReadSeeker(file, 1024, 4))
if err != nil {
:
}
fmt.Println("track num:", len(info.Tracks))
```### Writing
Writer helps you to write box tree.
The following sample code edits emsg box and writes to another file.```go
r := bufseekio.NewReadSeeker(inputFile, 128*1024, 4)
w := mp4.NewWriter(outputFile)
_, err = mp4.ReadBoxStructure(r, func(h *mp4.ReadHandle) (interface{}, error) {
switch h.BoxInfo.Type {
case mp4.BoxTypeEmsg():
// write box size and box type
_, err := w.StartBox(&h.BoxInfo)
if err != nil {
return nil, err
}
// read payload
box, _, err := h.ReadPayload()
if err != nil {
return nil, err
}
// update MessageData
emsg := box.(*mp4.Emsg)
emsg.MessageData = []byte("hello world")
// write box playload
if _, err := mp4.Marshal(w, emsg, h.BoxInfo.Context); err != nil {
return nil, err
}
// rewrite box size
_, err = w.EndBox()
return nil, err
default:
// copy all
return nil, w.CopyBox(r, &h.BoxInfo)
}
})
```Please note that the above sample code doesn't work for some MP4 files.
If your MP4 files include specific box types (ex. stco, mfra), you should update those when offsets of mdat box changed.
Next sample code adds an metadata box and updates chunk offsets in stco boxes.[Sample Code: Insert Metadata and Update stco box](https://gist.github.com/sunfish-shogi/cccde016a38c66d32c07a0234368804e)
### User-defined Boxes
You can create additional box definition as follows:
```go
func BoxTypeXxxx() BoxType { return mp4.StrToBoxType("xxxx") }func init() {
mp4.AddBoxDef(&Xxxx{}, 0)
}type Xxxx struct {
FullBox `mp4:"0,extend"`
UI32 uint32 `mp4:"1,size=32"`
ByteArray []byte `mp4:"2,size=8,len=dynamic"`
}func (*Xxxx) GetType() BoxType {
return BoxTypeXxxx()
}
```### Buffering
go-mp4 has no buffering feature for I/O.
If you should reduce Read function calls, you can wrap the io.ReadSeeker by [bufseekio](https://github.com/sunfish-shogi/bufseekio).## Command Line Tool
Install mp4tool as follows:
```sh
go install github.com/abema/go-mp4/cmd/mp4tool@latestmp4tool -help
```For example, `mp4tool dump MP4_FILE_NAME` command prints MP4 box tree as follows:
```
[moof] Size=504
[mfhd] Size=16 Version=0 Flags=0x000000 SequenceNumber=1
[traf] Size=480
[tfhd] Size=28 Version=0 Flags=0x020038 TrackID=1 DefaultSampleDuration=9000 DefaultSampleSize=33550 DefaultSampleFlags=0x1010000
[tfdt] Size=20 Version=1 Flags=0x000000 BaseMediaDecodeTimeV1=0
[trun] Size=424 ... (use -a option to show all)
[mdat] Size=44569 Data=[...] (use -mdat option to expand)
```