diff --git a/CHANGELOG.md b/CHANGELOG.md index abc439a..fb961c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Calculate frame-rate based on DTS/PTS and print out in JSON format - Enable NALU/SEI printing by option - Print SDT in JSON format +- Support for HEVC PicTiming SEI message +- SEI message data is now also printed as JSON + +## Changed + +- mp2ts-info and mp2ts-pslister now always print indented output +- mp2ts-nallister -sei option now turns on details. ## [0.1.0] - 2024-01-15 diff --git a/cmd/mp2ts-info/main.go b/cmd/mp2ts-info/main.go index 50a12c0..5f6ca12 100644 --- a/cmd/mp2ts-info/main.go +++ b/cmd/mp2ts-info/main.go @@ -10,7 +10,6 @@ import ( "strings" "github.com/Eyevinn/mp2ts-tools/internal" - "github.com/Eyevinn/mp2ts-tools/internal/avc" ) var usg = `Usage of %s: @@ -19,9 +18,8 @@ var usg = `Usage of %s: ` func parseOptions() internal.Options { - opts := internal.Options{ShowStreamInfo: true} + opts := internal.Options{ShowStreamInfo: true, Indent: true} flag.BoolVar(&opts.ShowService, "service", false, "show service information") - flag.BoolVar(&opts.Indent, "indent", true, "indent JSON output") flag.BoolVar(&opts.Version, "version", false, "print version") flag.Usage = func() { @@ -37,7 +35,7 @@ func parseOptions() internal.Options { } func parseInfo(ctx context.Context, w io.Writer, f io.Reader, o internal.Options) error { - return avc.ParseInfo(ctx, w, f, o) + return internal.ParseInfo(ctx, w, f, o) } func main() { diff --git a/cmd/mp2ts-nallister/main.go b/cmd/mp2ts-nallister/main.go index 03c8029..9c9ce9f 100644 --- a/cmd/mp2ts-nallister/main.go +++ b/cmd/mp2ts-nallister/main.go @@ -10,7 +10,6 @@ import ( "strings" "github.com/Eyevinn/mp2ts-tools/internal" - "github.com/Eyevinn/mp2ts-tools/internal/avc" ) var usg = `Usage of %s: @@ -19,9 +18,9 @@ var usg = `Usage of %s: ` func parseOptions() internal.Options { - opts := internal.Options{ShowStreamInfo: true, ShowService: false, ShowPS: false, ShowNALU: true, ShowSEI: false, ShowStatistics: true} + opts := internal.Options{ShowStreamInfo: true, ShowService: false, ShowPS: false, ShowNALU: true, ShowSEIDetails: false, ShowStatistics: true} flag.IntVar(&opts.MaxNrPictures, "max", 0, "max nr pictures to parse") - flag.BoolVar(&opts.ShowSEI, "sei", false, "print sei messages") + flag.BoolVar(&opts.ShowSEIDetails, "sei", false, "print detailed sei message information") flag.BoolVar(&opts.Indent, "indent", false, "indent JSON output") flag.BoolVar(&opts.Version, "version", false, "print version") @@ -38,7 +37,7 @@ func parseOptions() internal.Options { } func parseNALUInfo(ctx context.Context, w io.Writer, f io.Reader, o internal.Options) error { - return avc.ParseAll(ctx, w, f, o) + return internal.ParseAll(ctx, w, f, o) } func main() { diff --git a/cmd/mp2ts-pslister/main.go b/cmd/mp2ts-pslister/main.go index de98ef4..bdb34f8 100644 --- a/cmd/mp2ts-pslister/main.go +++ b/cmd/mp2ts-pslister/main.go @@ -10,7 +10,6 @@ import ( "strings" "github.com/Eyevinn/mp2ts-tools/internal" - "github.com/Eyevinn/mp2ts-tools/internal/avc" ) var usg = `Usage of %s: @@ -19,10 +18,9 @@ var usg = `Usage of %s: ` func parseOptions() internal.Options { - opts := internal.Options{ShowStreamInfo: true, ShowService: false, ShowPS: true, ShowNALU: false, ShowSEI: false, ShowStatistics: false} + opts := internal.Options{ShowStreamInfo: true, ShowService: false, ShowPS: true, Indent: true, ShowNALU: false, ShowSEIDetails: false, ShowStatistics: false} flag.IntVar(&opts.MaxNrPictures, "max", 0, "max nr pictures to parse") flag.BoolVar(&opts.VerbosePSInfo, "ps", false, "show verbose information") - flag.BoolVar(&opts.Indent, "indent", true, "indent JSON output") flag.BoolVar(&opts.Version, "version", false, "print version") flag.Usage = func() { @@ -38,7 +36,7 @@ func parseOptions() internal.Options { } func parsePSInfo(ctx context.Context, w io.Writer, f io.Reader, o internal.Options) error { - return avc.ParseAll(ctx, w, f, o) + return internal.ParseAll(ctx, w, f, o) } func main() { diff --git a/go.mod b/go.mod index ed7d1cf..0293921 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/Eyevinn/mp2ts-tools go 1.19 require ( - github.com/Eyevinn/mp4ff v0.41.0 + github.com/Eyevinn/mp4ff v0.41.1-0.20240123164056-bbd4656aecc0 github.com/asticode/go-astits v1.13.0 github.com/stretchr/testify v1.8.4 ) diff --git a/go.sum b/go.sum index 33964a2..3908072 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/Eyevinn/mp4ff v0.41.0 h1:EdXMeorCcuzMrnHShC7xX5dyNVYAkgp2lwK/ed64JKk= -github.com/Eyevinn/mp4ff v0.41.0/go.mod h1:w/6GSa5ghZ1VavzJK6McQ2/flx8mKtcrKDr11SsEweA= +github.com/Eyevinn/mp4ff v0.41.1-0.20240123164056-bbd4656aecc0 h1:TVO5vjF4CEAB6OKR0RWMQFvHXtZ+UdKCsp+awECiIVE= +github.com/Eyevinn/mp4ff v0.41.1-0.20240123164056-bbd4656aecc0/go.mod h1:w/6GSa5ghZ1VavzJK6McQ2/flx8mKtcrKDr11SsEweA= github.com/asticode/go-astikit v0.30.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0= github.com/asticode/go-astikit v0.42.0 h1:pnir/2KLUSr0527Tv908iAH6EGYYrYta132vvjXsH5w= github.com/asticode/go-astikit v0.42.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0= diff --git a/internal/avc/avc.go b/internal/avc.go similarity index 77% rename from internal/avc/avc.go rename to internal/avc.go index c9821cb..75cc757 100644 --- a/internal/avc/avc.go +++ b/internal/avc.go @@ -1,10 +1,8 @@ -package avc +package internal import ( "fmt" - "strings" - "github.com/Eyevinn/mp2ts-tools/internal" "github.com/Eyevinn/mp4ff/avc" "github.com/Eyevinn/mp4ff/sei" "github.com/asticode/go-astits" @@ -15,11 +13,18 @@ type AvcPS struct { ppss map[uint32]*avc.PPS spsnalu []byte ppsnalus [][]byte - Statistics internal.StreamStatistics + Statistics StreamStatistics } func (a *AvcPS) getSPS() *avc.SPS { - return a.spss[0] + if len(a.spss) == 0 { + return nil + } + for _, sps := range a.spss { + return sps + } + // Not reachable + return nil } func (a *AvcPS) setSPS(nalu []byte) error { @@ -50,14 +55,14 @@ func (a *AvcPS) setPPS(nalu []byte) error { return nil } -func ParseAVCPES(jp *internal.JsonPrinter, d *astits.DemuxerData, ps *AvcPS, o internal.Options) (*AvcPS, error) { +func ParseAVCPES(jp *JsonPrinter, d *astits.DemuxerData, ps *AvcPS, o Options) (*AvcPS, error) { pid := d.PID pes := d.PES fp := d.FirstPacket if pes.Header.OptionalHeader.PTS == nil { return nil, fmt.Errorf("no PTS in PES") } - nfd := internal.NaluFrameData{ + nfd := NaluFrameData{ PID: pid, } if ps == nil { @@ -89,7 +94,7 @@ func ParseAVCPES(jp *internal.JsonPrinter, d *astits.DemuxerData, ps *AvcPS, o i nalus := avc.ExtractNalusFromByteStream(data) firstPS := false for _, nalu := range nalus { - seiMsg := "" + var data any naluType := avc.GetNaluType(nalu[0]) switch naluType { case avc.NALU_SPS: @@ -108,25 +113,33 @@ func ParseAVCPES(jp *internal.JsonPrinter, d *astits.DemuxerData, ps *AvcPS, o i } } case avc.NALU_SEI: - if !o.ShowSEI { - continue - } - var sps *avc.SPS - if firstPS { - sps = ps.getSPS() - } + sps := ps.getSPS() msgs, err := avc.ParseSEINalu(nalu, sps) if err != nil { return nil, err } - seiTexts := make([]string, 0, len(msgs)) + parts := make([]SeiOut, 0, len(msgs)) for _, msg := range msgs { - if msg.Type() == sei.SEIPicTimingType { + t := sei.SEIType(msg.Type()) + if t == sei.SEIPicTimingType { pt := msg.(*sei.PicTimingAvcSEI) - seiTexts = append(seiTexts, fmt.Sprintf("Type 1: %s", pt.Clocks[0])) + if o.ShowSEIDetails && sps != nil { + parts = append(parts, SeiOut{ + Msg: t.String(), + Payload: pt, + }) + } else { + parts = append(parts, SeiOut{Msg: t.String()}) + } + } else { + if o.ShowSEIDetails { + parts = append(parts, SeiOut{Msg: t.String(), Payload: msg}) + } else { + parts = append(parts, SeiOut{Msg: t.String()}) + } } } - seiMsg = strings.Join(seiTexts, ", ") + data = parts case avc.NALU_IDR, avc.NALU_NON_IDR: if naluType == avc.NALU_IDR { ps.Statistics.IDRPTS = append(ps.Statistics.IDRPTS, pts.Base) @@ -136,10 +149,10 @@ func ParseAVCPES(jp *internal.JsonPrinter, d *astits.DemuxerData, ps *AvcPS, o i nfd.ImgType = fmt.Sprintf("[%s]", sliceType) } } - nfd.NALUS = append(nfd.NALUS, internal.NaluData{ + nfd.NALUS = append(nfd.NALUS, NaluData{ Type: naluType.String(), Len: len(nalu), - Data: seiMsg, + Data: data, }) } diff --git a/internal/hevc/hevc.go b/internal/hevc.go similarity index 73% rename from internal/hevc/hevc.go rename to internal/hevc.go index 7458ea8..ecfc1b6 100644 --- a/internal/hevc/hevc.go +++ b/internal/hevc.go @@ -1,10 +1,8 @@ -package hevc +package internal import ( - "bytes" "fmt" - "github.com/Eyevinn/mp2ts-tools/internal" "github.com/Eyevinn/mp4ff/avc" "github.com/Eyevinn/mp4ff/hevc" "github.com/Eyevinn/mp4ff/sei" @@ -17,7 +15,7 @@ type HevcPS struct { vpsnalu []byte spsnalu []byte ppsnalus [][]byte - Statistics internal.StreamStatistics + Statistics StreamStatistics } func (a *HevcPS) setSPS(nalu []byte) error { @@ -48,14 +46,14 @@ func (a *HevcPS) setPPS(nalu []byte) error { return nil } -func ParseHEVCPES(jp *internal.JsonPrinter, d *astits.DemuxerData, ps *HevcPS, o internal.Options) (*HevcPS, error) { +func ParseHEVCPES(jp *JsonPrinter, d *astits.DemuxerData, ps *HevcPS, o Options) (*HevcPS, error) { pid := d.PID pes := d.PES fp := d.FirstPacket if pes.Header.OptionalHeader.PTS == nil { return nil, fmt.Errorf("no PTS in PES") } - nfd := internal.NaluFrameData{ + nfd := NaluFrameData{ PID: pid, } if ps == nil { @@ -87,43 +85,12 @@ func ParseHEVCPES(jp *internal.JsonPrinter, d *astits.DemuxerData, ps *HevcPS, o firstPS := false for _, nalu := range avc.ExtractNalusFromByteStream(data) { naluType := hevc.GetNaluType(nalu[0]) - // Handle SEI messages separately - if naluType == hevc.NALU_SEI_PREFIX || naluType == hevc.NALU_SEI_SUFFIX { - if !o.ShowSEI { - continue - } - var hdrLen = 2 - seiBytes := nalu[hdrLen:] - buf := bytes.NewReader(seiBytes) - seiDatas, err := sei.ExtractSEIData(buf) - if err != nil { - return nil, err - } - - for _, seiData := range seiDatas { - var seiMsg sei.SEIMessage - seiMsg, err = sei.DecodeSEIMessage(&seiData, sei.HEVC) - if err != nil { - fmt.Printf("SEI: Got error %q\n", err) - continue - } - - nfd.NALUS = append(nfd.NALUS, internal.NaluData{ - Type: naluType.String(), - Len: len(nalu), - Data: seiMsg.String(), - }) - } - - continue - } - - // Handle other NALUs switch naluType { case hevc.NALU_VPS: ps.vpsnalu = nalu + firstPS = true case hevc.NALU_SPS: - if !firstPS { + if firstPS { err := ps.setSPS(nalu) if err != nil { return nil, fmt.Errorf("cannot set SPS") @@ -137,13 +104,41 @@ func ParseHEVCPES(jp *internal.JsonPrinter, d *astits.DemuxerData, ps *HevcPS, o return nil, fmt.Errorf("cannot set PPS") } } + case hevc.NALU_SEI_PREFIX, hevc.NALU_SEI_SUFFIX: + + var seiData any + if o.ShowSEIDetails && len(ps.spss) > 0 { + sps := ps.spss[0] + seiMessages, err := hevc.ParseSEINalu(nalu, sps) + if err != nil { + return nil, fmt.Errorf("cannot parse SEI NALU") + } + parts := make([]SeiOut, 0, len(seiMessages)) + for _, seiMsg := range seiMessages { + var payload any + switch seiMsg.Type() { + case sei.SEIPicTimingType: + payload = seiMsg.(*sei.PicTimingHevcSEI) + } + parts = append(parts, SeiOut{Msg: sei.SEIType(seiMsg.Type()).String(), Payload: payload}) + } + seiData = parts + } else { + seiData = nil // hex.EncodeToString(nalu) + } + nfd.NALUS = append(nfd.NALUS, NaluData{ + Type: naluType.String(), + Len: len(nalu), + Data: seiData, + }) + continue case hevc.NALU_IDR_W_RADL, hevc.NALU_IDR_N_LP: ps.Statistics.IDRPTS = append(ps.Statistics.IDRPTS, pts.Base) } - nfd.NALUS = append(nfd.NALUS, internal.NaluData{ + nfd.NALUS = append(nfd.NALUS, NaluData{ Type: naluType.String(), Len: len(nalu), - Data: "", + Data: nil, }) } diff --git a/internal/nalu.go b/internal/nalu.go index 8d6d7d9..4e865df 100644 --- a/internal/nalu.go +++ b/internal/nalu.go @@ -12,5 +12,10 @@ type NaluFrameData struct { type NaluData struct { Type string `json:"type"` Len int `json:"len"` - Data string `json:"data,omitempty"` + Data any `json:"data,omitempty"` +} + +type SeiOut struct { + Msg string `json:"msg"` + Payload any `json:"payload,omitempty"` } diff --git a/internal/avc/parser.go b/internal/parser.go similarity index 71% rename from internal/avc/parser.go rename to internal/parser.go index 7db3161..c8e20af 100644 --- a/internal/avc/parser.go +++ b/internal/parser.go @@ -1,4 +1,4 @@ -package avc +package internal import ( "bufio" @@ -6,22 +6,20 @@ import ( "fmt" "io" - "github.com/Eyevinn/mp2ts-tools/internal" - "github.com/Eyevinn/mp2ts-tools/internal/hevc" "github.com/asticode/go-astits" ) -func ParseAll(ctx context.Context, w io.Writer, f io.Reader, o internal.Options) error { - rd := bufio.NewReaderSize(f, 1000*internal.PacketSize) +func ParseAll(ctx context.Context, w io.Writer, f io.Reader, o Options) error { + rd := bufio.NewReaderSize(f, 1000*PacketSize) dmx := astits.NewDemuxer(ctx, rd) pmtPID := -1 nrPics := 0 sdtPrinted := false esKinds := make(map[uint16]string) avcPSs := make(map[uint16]*AvcPS) - hevcPSs := make(map[uint16]*hevc.HevcPS) - jp := &internal.JsonPrinter{W: w, Indent: o.Indent} - statistics := make(map[uint16]*internal.StreamStatistics) + hevcPSs := make(map[uint16]*HevcPS) + jp := &JsonPrinter{W: w, Indent: o.Indent} + statistics := make(map[uint16]*StreamStatistics) dataLoop: for { // Check if context was cancelled @@ -49,16 +47,16 @@ dataLoop: if pmtPID < 0 && d.PMT != nil { // Loop through elementary streams for _, es := range d.PMT.ElementaryStreams { - var streamInfo *internal.ElementaryStreamInfo + var streamInfo *ElementaryStreamInfo switch es.StreamType { case astits.StreamTypeH264Video: - streamInfo = &internal.ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "AVC", Type: "video"} + streamInfo = &ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "AVC", Type: "video"} esKinds[es.ElementaryPID] = "AVC" case astits.StreamTypeAACAudio: - streamInfo = &internal.ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "AAC", Type: "audio"} + streamInfo = &ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "AAC", Type: "audio"} esKinds[es.ElementaryPID] = "AAC" case astits.StreamTypeH265Video: - streamInfo = &internal.ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "HEVC", Type: "video"} + streamInfo = &ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "HEVC", Type: "video"} esKinds[es.ElementaryPID] = "HEVC" } @@ -93,7 +91,7 @@ dataLoop: statistics[d.PID] = &avcPS.Statistics case "HEVC": hevcPS := hevcPSs[d.PID] - hevcPS, err = hevc.ParseHEVCPES(jp, d, hevcPS, o) + hevcPS, err = ParseHEVCPES(jp, d, hevcPS, o) if err != nil { return err } @@ -123,11 +121,11 @@ dataLoop: return jp.Error() } -func ParseInfo(ctx context.Context, w io.Writer, f io.Reader, o internal.Options) error { - rd := bufio.NewReaderSize(f, 1000*internal.PacketSize) +func ParseInfo(ctx context.Context, w io.Writer, f io.Reader, o Options) error { + rd := bufio.NewReaderSize(f, 1000*PacketSize) dmx := astits.NewDemuxer(ctx, rd) pmtPID := -1 - jp := &internal.JsonPrinter{W: w, Indent: o.Indent} + jp := &JsonPrinter{W: w, Indent: o.Indent} dataLoop: for { // Check if context was cancelled @@ -149,14 +147,14 @@ dataLoop: if pmtPID < 0 && d.PMT != nil { // Loop through elementary streams for _, es := range d.PMT.ElementaryStreams { - var streamInfo *internal.ElementaryStreamInfo + var streamInfo *ElementaryStreamInfo switch es.StreamType { case astits.StreamTypeH264Video: - streamInfo = &internal.ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "AVC", Type: "video"} + streamInfo = &ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "AVC", Type: "video"} case astits.StreamTypeAACAudio: - streamInfo = &internal.ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "AAC", Type: "audio"} + streamInfo = &ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "AAC", Type: "audio"} case astits.StreamTypeH265Video: - streamInfo = &internal.ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "HEVC", Type: "video"} + streamInfo = &ElementaryStreamInfo{PID: es.ElementaryPID, Codec: "HEVC", Type: "video"} } if streamInfo != nil { diff --git a/internal/avc/parser_test.go b/internal/parser_test.go similarity index 76% rename from internal/avc/parser_test.go rename to internal/parser_test.go index ee520f0..089b952 100644 --- a/internal/avc/parser_test.go +++ b/internal/parser_test.go @@ -1,4 +1,4 @@ -package avc +package internal import ( "bytes" @@ -8,7 +8,6 @@ import ( "strings" "testing" - "github.com/Eyevinn/mp2ts-tools/internal" "github.com/stretchr/testify/require" ) @@ -17,12 +16,12 @@ var ( ) func TestParseFile(t *testing.T) { - fullOptionsWith2Pic := internal.CreateFullOptions(2) + fullOptionsWith2Pic := CreateFullOptions(2) fullOptionsWith2Pic.Indent = true - fullOptionsWith35Pic := internal.CreateFullOptions(35) - fullOptionsWith35PicWithoutNALUSEI := internal.CreateFullOptions(35) + fullOptionsWith35Pic := CreateFullOptions(35) + fullOptionsWith35PicWithoutNALUSEI := CreateFullOptions(35) fullOptionsWith35PicWithoutNALUSEI.ShowNALU = false - fullOptionsWith35PicWithoutNALUSEI.ShowSEI = false + fullOptionsWith35PicWithoutNALUSEI.ShowSEIDetails = false parseInfoFunc := ParseInfo parseAllFunc := ParseAll @@ -30,12 +29,12 @@ func TestParseFile(t *testing.T) { cases := []struct { name string file string - options internal.Options + options Options expected_output_file string - f internal.RunableFunc + f RunableFunc }{ - {"avc", "testdata/avc_with_time.ts", internal.Options{MaxNrPictures: 10, Indent: true, ShowStreamInfo: true, ShowPS: true, ShowStatistics: true}, "testdata/golden_avc.txt", parseAllFunc}, - {"avc_without_ps", "testdata/avc_with_time.ts", internal.Options{MaxNrPictures: 10, ShowStreamInfo: true}, "testdata/golden_avc_without_ps.txt", parseInfoFunc}, + {"avc", "testdata/avc_with_time.ts", Options{MaxNrPictures: 10, Indent: true, ShowStreamInfo: true, ShowPS: true, ShowStatistics: true}, "testdata/golden_avc.txt", parseAllFunc}, + {"avc_without_ps", "testdata/avc_with_time.ts", Options{MaxNrPictures: 10, ShowStreamInfo: true}, "testdata/golden_avc_without_ps.txt", parseInfoFunc}, {"bbb_1s", "testdata/bbb_1s.ts", fullOptionsWith35Pic, "testdata/golden_bbb_1s.txt", parseAllFunc}, {"bbb_1s_indented", "testdata/bbb_1s.ts", fullOptionsWith2Pic, "testdata/golden_bbb_1s_indented.txt", parseAllFunc}, {"bbb_1s_no_nalu_no_sei", "testdata/bbb_1s.ts", fullOptionsWith35PicWithoutNALUSEI, "testdata/golden_bbb_1s_no_nalu(no_sei).txt", parseAllFunc}, diff --git a/internal/avc/testdata/avc_with_time.ts b/internal/testdata/avc_with_time.ts similarity index 100% rename from internal/avc/testdata/avc_with_time.ts rename to internal/testdata/avc_with_time.ts diff --git a/internal/avc/testdata/bbb_1s.ts b/internal/testdata/bbb_1s.ts similarity index 100% rename from internal/avc/testdata/bbb_1s.ts rename to internal/testdata/bbb_1s.ts diff --git a/internal/avc/testdata/golden_avc.txt b/internal/testdata/golden_avc.txt similarity index 100% rename from internal/avc/testdata/golden_avc.txt rename to internal/testdata/golden_avc.txt diff --git a/internal/avc/testdata/golden_avc_without_ps.txt b/internal/testdata/golden_avc_without_ps.txt similarity index 100% rename from internal/avc/testdata/golden_avc_without_ps.txt rename to internal/testdata/golden_avc_without_ps.txt diff --git a/internal/avc/testdata/golden_bbb_1s.txt b/internal/testdata/golden_bbb_1s.txt similarity index 94% rename from internal/avc/testdata/golden_bbb_1s.txt rename to internal/testdata/golden_bbb_1s.txt index 4e6d23a..a39f329 100644 --- a/internal/avc/testdata/golden_bbb_1s.txt +++ b/internal/testdata/golden_bbb_1s.txt @@ -2,7 +2,7 @@ {"pid":257,"codec":"AAC","type":"audio"} {"pid":256,"parameterSet":"SPS","nr":0,"hex":"6764001facd9405005bb011000000300100000030300f1831960","length":26} {"pid":256,"parameterSet":"PPS","nr":0,"hex":"68ebecb22c","length":5} -{"pid":256,"rai":true,"pts":133500,"dts":126000,"imgType":"[I]","nalus":[{"type":"AUD_9","len":2},{"type":"SEI_6","len":701},{"type":"SPS_7","len":26},{"type":"PPS_8","len":5},{"type":"IDR_5","len":209}]} +{"pid":256,"rai":true,"pts":133500,"dts":126000,"imgType":"[I]","nalus":[{"type":"AUD_9","len":2},{"type":"SEI_6","len":701,"data":[{"msg":"SEIUserDataUnregisteredType (5)","payload":{"UUID":"3EXpvebZSLeWLNgg2SPu7w=="}}]},{"type":"SPS_7","len":26},{"type":"PPS_8","len":5},{"type":"IDR_5","len":209}]} {"pid":256,"rai":false,"pts":144750,"dts":129750,"imgType":"[P]","nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":34}]} {"pid":256,"rai":false,"pts":137250,"dts":133500,"imgType":"[B]","nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":32}]} {"pid":256,"rai":false,"pts":141000,"dts":137250,"imgType":"[B]","nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":32}]} diff --git a/internal/avc/testdata/golden_bbb_1s_indented.txt b/internal/testdata/golden_bbb_1s_indented.txt similarity index 83% rename from internal/avc/testdata/golden_bbb_1s_indented.txt rename to internal/testdata/golden_bbb_1s_indented.txt index afa907d..dab8417 100644 --- a/internal/avc/testdata/golden_bbb_1s_indented.txt +++ b/internal/testdata/golden_bbb_1s_indented.txt @@ -35,7 +35,15 @@ }, { "type": "SEI_6", - "len": 701 + "len": 701, + "data": [ + { + "msg": "SEIUserDataUnregisteredType (5)", + "payload": { + "UUID": "3EXpvebZSLeWLNgg2SPu7w==" + } + } + ] }, { "type": "SPS_7", diff --git a/internal/avc/testdata/golden_bbb_1s_no_nalu(no_sei).txt b/internal/testdata/golden_bbb_1s_no_nalu(no_sei).txt similarity index 100% rename from internal/avc/testdata/golden_bbb_1s_no_nalu(no_sei).txt rename to internal/testdata/golden_bbb_1s_no_nalu(no_sei).txt diff --git a/internal/avc/testdata/golden_obs_hevc_aac.txt b/internal/testdata/golden_obs_hevc_aac.txt similarity index 97% rename from internal/avc/testdata/golden_obs_hevc_aac.txt rename to internal/testdata/golden_obs_hevc_aac.txt index 53b597e..af76b22 100644 --- a/internal/avc/testdata/golden_obs_hevc_aac.txt +++ b/internal/testdata/golden_obs_hevc_aac.txt @@ -3,7 +3,7 @@ {"pid":256,"parameterSet":"VPS","nr":0,"hex":"40010c01ffff016000000300b00000030000030078170240","length":24} {"pid":256,"parameterSet":"SPS","nr":0,"hex":"420101016000000300b00000030000030078a005020171f2e205ee45914bff2e7f13fa9a8080808040","length":41} {"pid":256,"parameterSet":"PPS","nr":0,"hex":"4401c072f05324","length":7} -{"pid":256,"rai":true,"pts":1920,"dts":1920,"nalus":[{"type":"AUD_35","len":3},{"type":"VPS_32","len":24},{"type":"SPS_33","len":41},{"type":"PPS_34","len":7},{"type":"SEI_39","len":31,"data":"SEI type 5, size=26, uuid=\"47564adc5c4c433f94efc5113cd143a8\", payload=\"\\x03\\xee\\x00\\x00\\xee\\x02\\x00\\x0fB@\""},{"type":"RAP_IDR_20","len":12860}]} +{"pid":256,"rai":true,"pts":1920,"dts":1920,"nalus":[{"type":"AUD_35","len":3},{"type":"VPS_32","len":24},{"type":"SPS_33","len":41},{"type":"PPS_34","len":7},{"type":"SEI_39","len":31,"data":[{"msg":"SEIUserDataUnregisteredType (5)"}]},{"type":"RAP_IDR_20","len":12860}]} {"pid":256,"rai":false,"pts":4920,"dts":4920,"nalus":[{"type":"AUD_35","len":3},{"type":"NonRAP_Trail_1","len":409}]} {"pid":256,"rai":false,"pts":7920,"dts":7920,"nalus":[{"type":"AUD_35","len":3},{"type":"NonRAP_Trail_1","len":332}]} {"pid":256,"rai":false,"pts":10920,"dts":10920,"nalus":[{"type":"AUD_35","len":3},{"type":"NonRAP_Trail_1","len":427}]} diff --git a/internal/avc/testdata/golden_obs_hevc_aac_indented.txt b/internal/testdata/golden_obs_hevc_aac_indented.txt similarity index 90% rename from internal/avc/testdata/golden_obs_hevc_aac_indented.txt rename to internal/testdata/golden_obs_hevc_aac_indented.txt index 0824b0b..95d0093 100644 --- a/internal/avc/testdata/golden_obs_hevc_aac_indented.txt +++ b/internal/testdata/golden_obs_hevc_aac_indented.txt @@ -54,7 +54,11 @@ { "type": "SEI_39", "len": 31, - "data": "SEI type 5, size=26, uuid=\"47564adc5c4c433f94efc5113cd143a8\", payload=\"\\x03\\xee\\x00\\x00\\xee\\x02\\x00\\x0fB@\"" + "data": [ + { + "msg": "SEIUserDataUnregisteredType (5)" + } + ] }, { "type": "RAP_IDR_20", diff --git a/internal/avc/testdata/golden_obs_hevc_aac_no_nalu(no_sei).txt b/internal/testdata/golden_obs_hevc_aac_no_nalu(no_sei).txt similarity index 100% rename from internal/avc/testdata/golden_obs_hevc_aac_no_nalu(no_sei).txt rename to internal/testdata/golden_obs_hevc_aac_no_nalu(no_sei).txt diff --git a/internal/avc/testdata/obs_hevc_aac.ts b/internal/testdata/obs_hevc_aac.ts similarity index 100% rename from internal/avc/testdata/obs_hevc_aac.ts rename to internal/testdata/obs_hevc_aac.ts diff --git a/internal/utils.go b/internal/utils.go index 204c5ce..115882c 100644 --- a/internal/utils.go +++ b/internal/utils.go @@ -20,12 +20,12 @@ type Options struct { ShowPS bool VerbosePSInfo bool ShowNALU bool - ShowSEI bool + ShowSEIDetails bool ShowStatistics bool } func CreateFullOptions(max int) Options { - return Options{MaxNrPictures: max, ShowStreamInfo: true, ShowService: true, ShowPS: true, ShowNALU: true, ShowSEI: true, ShowStatistics: true} + return Options{MaxNrPictures: max, ShowStreamInfo: true, ShowService: true, ShowPS: true, ShowNALU: true, ShowSEIDetails: true, ShowStatistics: true} } type OptionParseFunc func() Options