Skip to content

Commit

Permalink
Merge pull request #289 from Eyevinn/enc-cenc
Browse files Browse the repository at this point in the history
feat: common encryption support for AVC and audio.
  • Loading branch information
tobbee authored Oct 28, 2023
2 parents 89ae7d7 + 51438b5 commit 5e90b17
Show file tree
Hide file tree
Showing 22 changed files with 1,505 additions and 471 deletions.
22 changes: 18 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- SPS.ChromaArrayType method

### Added

- New CLI app: mp4ff-encrypt to encrypt segments
- New CLI app: mp4ff-decrypt to decrypt segments
- New encyption-related functions in mp4
- GetAVCProtectRanges to fine protection ranges for AVC video
- CryptSampleCenc for encrypting of decrypting with cenc scheme
- EncryptSampleCbcs - for encrypting with cbcs scheme
- DecryptSampleCbcs - for decrypting with cbcs scheme
- InitProtect to protect an init segment
- EncryptFragment to encrypt a fragment
- DecryptInit to extract and remove decryption info from an init segment
- DecryptFragment to decrypt a fragment
- ExtractInitProtect to generate data needed for encryption
- AccErrEBSPReader.NrBitsRead method
- PsshBoxesFromBase64 and PsshBoxesFromBytes functions

### Fixed

- SPS.ChromaArrayType method
- Makefile now builds all CLI applications with version

## [0.39.0] - 2023-10-13

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
all: test check coverage build

.PHONY: build
build: mp4ff-info mp4ff-nallister mp4ff-pslister mp4ff-wvttlister examples
build: mp4ff-crop mp4ff-decrypt mp4ff-encrypt mp4ff-info mp4ff-nallister mp4ff-pslister mp4ff-wvttlister examples

.PHONY: prepare
prepare:
go mod vendor

mp4ff-info mp4ff-nallister mp4ff-pslister mp4ff-wvttlister:
mp4ff-crop mp4ff-decrypt mp4ff-encrypt mp4ff-info mp4ff-nallister mp4ff-pslister mp4ff-wvttlister:
go build -ldflags "-X github.com/Eyevinn/mp4ff/mp4.commitVersion=$$(git describe --tags HEAD) -X github.com/Eyevinn/mp4ff/mp4.commitDate=$$(git log -1 --format=%ct)" -o out/$@ ./cmd/$@/main.go

.PHONY: examples
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Some useful command line tools are available in `cmd`.
3. `mp4ff-nallister` lists NALUs and picture types for video in progressive or fragmented file
4. `mp4ff-wvttlister` lists details of wvtt (WebVTT in ISOBMFF) samples
5. `mp4ff-crop` shortens a progressive mp4 file to a specified duration
6. `mp4ff-encrypt` encrypts a fragmented file using cenc or cbcs Common Encryption scheme
7. `mp4ff-decrypt` decrypts a fragmented file encrypted using cenc or cbcs Common Encryption scheme

You can install these tools by going to their respective directory and run `go install .` or directly from the repo with

Expand All @@ -40,8 +42,7 @@ The examples and their functions are:
This tool has been extended to support generation of segments with multiple tracks as well
as reading and writing `mdat` in lazy mode
4. `multitrack` parses a fragmented file with multiple tracks
5. `decrypt-cenc` decrypts a segmented mp4 file encrypted in `cenc` mode
6. `combine-segs` combines single-track init and media segments into multi-track segments
5. `combine-segs` combines single-track init and media segments into multi-track segments

## Library

Expand Down
14 changes: 14 additions & 0 deletions avc/annexb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package avc

import (
"bytes"
"math/rand"
"testing"

"github.com/go-test/deep"
Expand Down Expand Up @@ -231,3 +232,16 @@ func TestGetFirstAVCVideoNALUFromByteStream(t *testing.T) {
}
}
}

func BenchmarkByteStreamToNaluSample(b *testing.B) {
l := 1024 * 1024
data := make([]byte, l)
s := rand.NewSource(42)
r := rand.New(s)
for i := 0; i < l; i++ {
data[i] = byte(r.Intn(256))
}
for j := 0; j < b.N; j++ {
_ = ConvertByteStreamToNaluSample(data)
}
}
30 changes: 0 additions & 30 deletions cmd/mp4ff-crop/byteranges.go

This file was deleted.

145 changes: 145 additions & 0 deletions cmd/mp4ff-crop/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"io"
"log"
"os"
"sort"
"strings"

"github.com/Eyevinn/mp4ff/mp4"
Expand Down Expand Up @@ -387,3 +388,147 @@ func minUint32(a, b uint32) uint32 {
}
return b
}

func cropStblChildren(traks []*mp4.TrakBox, trakOuts map[uint32]*trakOut) (err error) {
for _, trak := range traks {
trakID := trak.Tkhd.TrackID
stbl := trak.Mdia.Minf.Stbl
to := trakOuts[trakID]
for _, ch := range stbl.Children {
switch ch.Type() {
case "stts":
cropStts(ch.(*mp4.SttsBox), to.lastSampleNr)
case "stss":
cropStss(ch.(*mp4.StssBox), to.lastSampleNr)
case "ctts":
cropCtts(ch.(*mp4.CttsBox), to.lastSampleNr)
case "stsc":
err = cropStsc(ch.(*mp4.StscBox), to.lastSampleNr)
case "stsz":
cropStsz(ch.(*mp4.StszBox), to.lastSampleNr)
case "sdtp":
cropSdtp(ch.(*mp4.SdtpBox), to.lastSampleNr)
case "stco":
updateStco(ch.(*mp4.StcoBox), to.chunkOffsets)
case "co64":
updateCo64(ch.(*mp4.Co64Box), to.chunkOffsets)
}
}
}
return err
}

func cropStts(b *mp4.SttsBox, lastSampleNr uint32) {
var countedSamples uint32 = 0
lastEntry := -1
for i := 0; i < len(b.SampleCount); i++ {
if countedSamples < lastSampleNr {
lastEntry++
}
if countedSamples+b.SampleCount[i] >= lastSampleNr {
break
}
countedSamples += b.SampleCount[i]
}
remaining := lastSampleNr - countedSamples
if remaining > 0 {
b.SampleCount[lastEntry] = remaining
}

b.SampleCount = b.SampleCount[:lastEntry+1]
b.SampleTimeDelta = b.SampleTimeDelta[:lastEntry+1]
}

func cropStss(b *mp4.StssBox, lastSampleNr uint32) {
nrEntries := b.EntryCount()
nrEntriesToKeep := 0
for i := uint32(0); i < nrEntries; i++ {
if b.SampleNumber[i] > lastSampleNr {
break
}
nrEntriesToKeep++
}
b.SampleNumber = b.SampleNumber[:nrEntriesToKeep]
}

func cropCtts(b *mp4.CttsBox, lastSampleNr uint32) {
lastIdx := sort.Search(len(b.EndSampleNr), func(i int) bool { return b.EndSampleNr[i] >= lastSampleNr })
// Finally cut down the endSampleNr for this index
b.EndSampleNr[lastIdx] = lastSampleNr
b.EndSampleNr = b.EndSampleNr[:lastIdx+1]
b.SampleOffset = b.SampleOffset[:lastIdx]
}

func cropStsc(b *mp4.StscBox, lastSampleNr uint32) error {
entryIdx := b.FindEntryNrForSampleNr(lastSampleNr, 0)
lastEntry := b.Entries[entryIdx]
b.Entries = b.Entries[:entryIdx+1]
if len(b.SampleDescriptionID) > 0 {
b.Entries = b.Entries[:entryIdx+1]
}
samplesLeft := lastSampleNr - lastEntry.FirstSampleNr + 1
nrChunksInLast := samplesLeft / lastEntry.SamplesPerChunk
nrLeft := samplesLeft - nrChunksInLast*lastEntry.SamplesPerChunk
if nrLeft > 0 {
sdid := b.GetSampleDescriptionID(int(lastEntry.FirstChunk))
err := b.AddEntry(lastEntry.FirstChunk+nrChunksInLast, nrLeft, sdid)
if err != nil {
return fmt.Errorf("stsc AddEntry: %w", err)
}
}
return nil
}

func cropStsz(b *mp4.StszBox, lastSampleNr uint32) {
if b.SampleUniformSize == 0 {
b.SampleSize = b.SampleSize[:lastSampleNr]
}
b.SampleNumber = lastSampleNr
}

func cropSdtp(b *mp4.SdtpBox, lastSampleNr uint32) {
if len(b.Entries) > int(lastSampleNr) {
b.Entries = b.Entries[:lastSampleNr]
}
}

func updateStco(b *mp4.StcoBox, offsets []uint64) {
b.ChunkOffset = make([]uint32, len(offsets))
for i := range offsets {
b.ChunkOffset[i] = uint32(offsets[i])
}
}

func updateCo64(b *mp4.Co64Box, offsets []uint64) {
b.ChunkOffset = make([]uint64, len(offsets))
_ = copy(b.ChunkOffset, offsets)
}

type byteRange struct {
start uint64
end uint64 // Included
}

type byteRanges struct {
ranges []byteRange
}

func createByteRanges() *byteRanges {
return &byteRanges{}
}

func (b *byteRanges) addRange(start, end uint64) {
if len(b.ranges) == 0 || b.ranges[len(b.ranges)-1].end+1 != start {
b.ranges = append(b.ranges, byteRange{start, end})
return
}
b.ranges[len(b.ranges)-1].end = end
}

func (b *byteRanges) size() uint64 {
var totSize uint64 = 0
for _, br := range b.ranges {
totSize += br.end - br.start + 1
}
return uint64(totSize)
}
Loading

0 comments on commit 5e90b17

Please sign in to comment.