-
Notifications
You must be signed in to change notification settings - Fork 84
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New add-sidx example and supporting function.
fix: GetTrex return values feat: File.UpdateSidx to update or add a top-level sidx box feat: Can remove unused enc boxes feat: New decoder option to segment on moof start feat: New moov.IsEncrypted() method fix: make add-sidx work with unused senc and piff boxes fix: GetTrex now returns proper OK values
- Loading branch information
Showing
14 changed files
with
480 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
// add-sidx adds a top-level sidx box describing the segments of a fragmented files. | ||
// | ||
// Segments are identified by styp boxes if they exist, otherwise by | ||
// the start of moof or emsg boxes. | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"io" | ||
"log" | ||
"os" | ||
"strings" | ||
|
||
"github.com/Eyevinn/mp4ff/mp4" | ||
) | ||
|
||
var usg = `Usage of add-sidx: | ||
add-sidx adds a top-level sidx box to a fragmented file provided it does not exist. | ||
If styp boxes are present, they signal new segments. It is possible to interpret | ||
every moof box as the start of a new segment, by specifying the "-startSegOnMoof" option. | ||
One can further remove unused encryption boxes with the "-removeEnc" option. | ||
` | ||
|
||
var usage = func() { | ||
parts := strings.Split(os.Args[0], "/") | ||
name := parts[len(parts)-1] | ||
fmt.Fprintln(os.Stderr, usg) | ||
fmt.Fprintf(os.Stderr, "%s [options] <inFile> <outFile>\n", name) | ||
flag.PrintDefaults() | ||
} | ||
|
||
func main() { | ||
removeEncBoxes := flag.Bool("removeEnc", false, "Remove unused encryption boxes") | ||
usePTO := flag.Bool("nzEPT", false, "Use non-zero earliestPresentationTime") | ||
segOnMoof := flag.Bool("startSegOnMoof", false, "Start a new segment on every moof") | ||
version := flag.Bool("version", false, "Get mp4ff version") | ||
|
||
flag.Parse() | ||
|
||
if *version { | ||
fmt.Printf("add-sidx %s\n", mp4.GetVersion()) | ||
os.Exit(0) | ||
} | ||
flag.Parse() | ||
|
||
if *version { | ||
fmt.Printf("add-sidx %s\n", mp4.GetVersion()) | ||
os.Exit(0) | ||
} | ||
|
||
args := flag.Args() | ||
if len(args) != 2 { | ||
fmt.Fprintf(os.Stderr, "must specify infile and outfile\n") | ||
usage() | ||
os.Exit(1) | ||
} | ||
|
||
inFilePath := flag.Arg(0) | ||
outFilePath := flag.Arg(1) | ||
|
||
ifd, err := os.Open(inFilePath) | ||
if err != nil { | ||
fmt.Fprintln(os.Stderr, err) | ||
usage() | ||
os.Exit(1) | ||
} | ||
defer ifd.Close() | ||
ofd, err := os.Create(outFilePath) | ||
if err != nil { | ||
fmt.Fprintln(os.Stderr, err) | ||
usage() | ||
os.Exit(1) | ||
} | ||
defer ofd.Close() | ||
err = run(ifd, ofd, *usePTO, *removeEncBoxes, *segOnMoof) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func run(in io.Reader, out io.Writer, nonZeroEPT, removeEncBoxes, segOnMoof bool) error { | ||
var flags mp4.DecFileFlags | ||
if segOnMoof { | ||
flags |= mp4.DecStartOnMoof | ||
} | ||
mp4Root, err := mp4.DecodeFile(in, mp4.WithDecodeFlags(flags)) | ||
if err != nil { | ||
return err | ||
} | ||
fmt.Printf("found %d segments\n", len(mp4Root.Segments)) | ||
for i, seg := range mp4Root.Segments { | ||
for j, frag := range seg.Fragments { | ||
fmt.Printf("segment: %d, fragment: %d, sequenceNr: %d\n", i, j, frag.Moof.Mfhd.SequenceNumber) | ||
} | ||
} | ||
|
||
if removeEncBoxes { | ||
removeEncryptionBoxes(mp4Root) | ||
} | ||
|
||
addIfNotExists := true | ||
err = mp4Root.UpdateSidx(addIfNotExists, nonZeroEPT) | ||
if err != nil { | ||
return fmt.Errorf("addSidx failed: %w", err) | ||
} | ||
|
||
err = mp4Root.Encode(out) | ||
if err != nil { | ||
return fmt.Errorf("failed to encode output file: %w", err) | ||
} | ||
return nil | ||
} | ||
|
||
func removeEncryptionBoxes(inFile *mp4.File) { | ||
for _, seg := range inFile.Segments { | ||
for _, frag := range seg.Fragments { | ||
bytesRemoved := uint64(0) | ||
for _, traf := range frag.Moof.Trafs { | ||
bytesRemoved += traf.RemoveEncryptionBoxes() | ||
} | ||
for _, traf := range frag.Moof.Trafs { | ||
for _, trun := range traf.Truns { | ||
trun.DataOffset -= int32(bytesRemoved) | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"os" | ||
"testing" | ||
|
||
"github.com/Eyevinn/mp4ff/mp4" | ||
) | ||
|
||
func TestAddSidx(t *testing.T) { | ||
inPath := "testdata/clear_with_enc_boxes.mp4" | ||
testCases := []struct { | ||
desc string | ||
inPath string | ||
removeEnc bool | ||
segOnMoof bool | ||
wantedNrSegs uint32 | ||
wantedSize uint32 | ||
}{ | ||
{ | ||
desc: "sidx, enc boxes, 1 segment", | ||
inPath: inPath, | ||
removeEnc: false, | ||
segOnMoof: false, | ||
wantedNrSegs: 1, | ||
}, | ||
{ | ||
desc: "sidx, enc boxes, many segments", | ||
inPath: inPath, | ||
removeEnc: false, | ||
segOnMoof: true, | ||
wantedNrSegs: 2, | ||
}, | ||
{ | ||
desc: "sidx, no enc boxes, many segments", | ||
inPath: inPath, | ||
removeEnc: true, | ||
segOnMoof: true, | ||
wantedNrSegs: 2, | ||
}, | ||
{ | ||
desc: "normal file with styp", | ||
inPath: "../resegmenter/testdata/testV300.mp4", | ||
removeEnc: false, | ||
segOnMoof: false, | ||
wantedNrSegs: 4, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.desc, func(t *testing.T) { | ||
in, err := os.Open(tc.inPath) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
out := bytes.Buffer{} | ||
err = run(in, &out, false, tc.removeEnc, tc.segOnMoof) | ||
if err != nil { | ||
return | ||
} | ||
decOut, err := mp4.DecodeFile(&out) | ||
if err != nil { | ||
t.Error() | ||
} | ||
if decOut.Sidx == nil { | ||
t.Error("no sidx box") | ||
} | ||
gotNrEntries := len(decOut.Sidx.SidxRefs) | ||
if gotNrEntries != int(tc.wantedNrSegs) { | ||
t.Errorf("got %d sidx entries instead of %d", gotNrEntries, tc.wantedNrSegs) | ||
} | ||
if tc.removeEnc { | ||
for _, seg := range decOut.Segments { | ||
for _, frag := range seg.Fragments { | ||
if frag.Moof.Traf.Senc != nil { | ||
t.Error("senc is still present in fragment") | ||
} | ||
} | ||
} | ||
} | ||
}) | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.