commit c29a1e336e2176394997df419f8e06635db3eefe from: Oliver Lowe date: Mon Jan 27 07:18:27 2025 UTC Unpublish draft jxs package Not ready... if ever? commit - c5209d277a60973090abb0eaa9363428b111400f commit + c29a1e336e2176394997df419f8e06635db3eefe blob - e24725ee852538f5f5dd766c44b2dbe860f03d9c (mode 644) blob + /dev/null --- jxs/draft.txt +++ /dev/null @@ -1,64 +0,0 @@ -package main - -import ( - "rtp" - "jxs" -) - -func transmit(session *rtp.Session, payload chan *jxs.Payload) { - for p := range payload { - packets, err := jxs.Packets(p) - if err != nil { - log.Printf("payload to RTP packets: %v", err) - continue - } - for _, packet := range packets { - if err := session.Transmit(p); err != nil { - log.Printf("transmit: %v", err) - } - } - } -} - -func main() { - session, err := rtp.Dial("udp", "[::1]:5004") - if err != nil { - log.Fatal(err) - } - - ch := make(chan *jxs.Payload) - go transmit(session, ch) - - for i := 0; ; i++ { - frame, err := jxs.DecodeFrame(os.Stdin) - if errors.Is(err, io.EOF) { - close(ch) - break - } else if err != nil { - log.Fatal(err) - } - mtu := 1492 // typical network - pus, err := jxs.Packetize(&frame, mtu) - if err != nil { - log.Fatal(err) - } - for j, pu := range pus { - payload := &jxs.Payload{ - Header: &jxs.Header{ - Sequential: true, - PacketMode: true, - FrameCount: uint8(i), - SEPCount: 0, // TODO(otl) - PacketCount: j, // TODO(otl) - }, - PacketizationUnit: &jxs.PacketizationUnit{ - frame.VideoBox, - frame.ColorBox, - }, - }, - ch <- payload - } - } -} - - blob - 6d43e03986813e0eca0e95d9dc0653f003cfe8ef (mode 644) blob + /dev/null --- jxs/jxs.go +++ /dev/null @@ -1,27 +0,0 @@ -package jxs - -const ( - codestreamStart uint16 = 0xff10 - codestreamEnd uint16 = 0xff11 -) - -type codestream struct { - start uint16 - capabilities capabilities -} - -type capabilities uint8 - -const ( - starTetrixTransform capabilities = 1<<1 + iota - quadraticTransform - extendedTransform - waveletDecomposition - losslessDecode - rawMode -) - -type header struct { - marker uint16 - length uint16 -} blob - 87401eaeee3091c2f7e569fa61a53941cbb3055c (mode 644) blob + /dev/null --- jxs/payload.go +++ /dev/null @@ -1,122 +0,0 @@ -// Package jxs ... for transporting JPEG XS streams in RTP payloads -// as specified in RFC 9134. -package jxs - -import "encoding/binary" - -type ScanMode uint8 - -const ( - ScanModeProgressive ScanMode = 0 - _ - ScanModeInterlacedFirst ScanMode = 0b00010000 - ScanModeInterlacedSecond = 0b00011000 -) - -/* -type Payload struct { - Header *Header - PacketizationUnit *PacketizationUnit -} - -type PacketizationUnit struct { - VideoBox - ColorBox - // ... -} -*/ - -type Header struct { - // Sequential indicates whether packets are sent sequentially - // or possibly out of order. may be sent out of order. - Sequential bool - - // PacketMode indicates the packetization mode. If true, - // codestream packetization is used. If false, slice - // packetization is used and Sequential must be false. - PacketMode bool - - // Last indicates whether the packet is the last packet of a - // packetization unit. - Last bool - - // InterlacedInfo specifies how the frame is scanned. - InterlacedInfo ScanMode - - // FrameCount holds a 5-bit integer (modulo 32) identifying - // the frame to which the packet belongs. - FrameCount uint8 - - // SEPCounter (Slice and Extended Packet counter) - // holds an 11-bit integer which is interpreted differently - // depending on the value of PacketMode. - // - // If the packetization mode is codestream, then SEPCounter is - // incremented by 1 whenever PacketCounter overruns. - // - // If packetization mode is slice, then SEPCounter identifies - // the slice (modulo 2047) to which the packet contributes. - SEPCount uint16 - - // PacketCounter is an 11-bit integer identifying the packet number - // within the current packetization unit. - PacketCount uint16 -} - -func unmarshalHeader(a [4]byte, hdr Header) error { - hdr.Sequential = a[0]&0b10000000 > 0 - hdr.PacketMode = a[0]&0b01000000 > 0 - hdr.Last = a[0]&0b00100000 > 0 - hdr.InterlacedInfo = ScanMode(a[0] & 0b00011000) - - hdr.FrameCount = (a[0] & 0b00000111) << 2 - hdr.FrameCount |= ((a[1] & 0b11000000) >> 6) - - var sepc [2]byte - sepc[0] = a[1] & 0b00111000 >> 3 - sepc[1] = a[1] & 0b00000111 << 5 - sepc[1] |= a[2] & 0b11111000 >> 3 - hdr.SEPCount = binary.BigEndian.Uint16(sepc[:]) - - hdr.PacketCount = binary.BigEndian.Uint16([]byte{a[2] & 0b00000111, a[3]}) - return nil -} - -func marshalHeader(hdr Header) [4]byte { - var a [4]byte - if hdr.Sequential { - a[0] |= (1 << 7) - } - if hdr.PacketMode { - a[0] |= (1 << 6) - } - if hdr.Last { - a[0] |= (1 << 5) - } - a[0] |= byte(hdr.InterlacedInfo) - - // Need to pack the 5 bits in FrameCount across both a[0] and a[1]. - // Have 3 bits remaining in a[0]. - a[0] |= (hdr.FrameCount & 0b00011100) >> 2 - // Pack remaining 2 bits from FrameCount into left-most bits of a[1]. - a[1] = (hdr.FrameCount & 0b00000011) << 6 - - // 6 bits remaining in a[1]. - // We have 11 bits in SEPCount to pack. - b := make([]byte, 2) - binary.BigEndian.PutUint16(b, hdr.SEPCount) - a[1] |= (b[0] & 0b00000111) << 3 - // 3 bits remaining in a[1], so get next 3 bits from b. - a[1] |= (b[1] & 0b11100000) >> 5 - - // 5 bits remaining in b. - a[2] = (b[1] & 0b00011111) << 3 - - b[0] = 0 - b[1] = 0 - binary.BigEndian.PutUint16(b, hdr.PacketCount) - // 3 bits spare in a[2]. - a[2] |= (b[0] & 0b00000111) - a[3] = b[1] - return a -} blob - /dev/null blob + e24725ee852538f5f5dd766c44b2dbe860f03d9c (mode 644) --- /dev/null +++ internal/jxs/draft.txt @@ -0,0 +1,64 @@ +package main + +import ( + "rtp" + "jxs" +) + +func transmit(session *rtp.Session, payload chan *jxs.Payload) { + for p := range payload { + packets, err := jxs.Packets(p) + if err != nil { + log.Printf("payload to RTP packets: %v", err) + continue + } + for _, packet := range packets { + if err := session.Transmit(p); err != nil { + log.Printf("transmit: %v", err) + } + } + } +} + +func main() { + session, err := rtp.Dial("udp", "[::1]:5004") + if err != nil { + log.Fatal(err) + } + + ch := make(chan *jxs.Payload) + go transmit(session, ch) + + for i := 0; ; i++ { + frame, err := jxs.DecodeFrame(os.Stdin) + if errors.Is(err, io.EOF) { + close(ch) + break + } else if err != nil { + log.Fatal(err) + } + mtu := 1492 // typical network + pus, err := jxs.Packetize(&frame, mtu) + if err != nil { + log.Fatal(err) + } + for j, pu := range pus { + payload := &jxs.Payload{ + Header: &jxs.Header{ + Sequential: true, + PacketMode: true, + FrameCount: uint8(i), + SEPCount: 0, // TODO(otl) + PacketCount: j, // TODO(otl) + }, + PacketizationUnit: &jxs.PacketizationUnit{ + frame.VideoBox, + frame.ColorBox, + }, + }, + ch <- payload + } + } +} + + blob - /dev/null blob + 6d43e03986813e0eca0e95d9dc0653f003cfe8ef (mode 644) --- /dev/null +++ internal/jxs/jxs.go @@ -0,0 +1,27 @@ +package jxs + +const ( + codestreamStart uint16 = 0xff10 + codestreamEnd uint16 = 0xff11 +) + +type codestream struct { + start uint16 + capabilities capabilities +} + +type capabilities uint8 + +const ( + starTetrixTransform capabilities = 1<<1 + iota + quadraticTransform + extendedTransform + waveletDecomposition + losslessDecode + rawMode +) + +type header struct { + marker uint16 + length uint16 +} blob - /dev/null blob + 87401eaeee3091c2f7e569fa61a53941cbb3055c (mode 644) --- /dev/null +++ internal/jxs/payload.go @@ -0,0 +1,122 @@ +// Package jxs ... for transporting JPEG XS streams in RTP payloads +// as specified in RFC 9134. +package jxs + +import "encoding/binary" + +type ScanMode uint8 + +const ( + ScanModeProgressive ScanMode = 0 + _ + ScanModeInterlacedFirst ScanMode = 0b00010000 + ScanModeInterlacedSecond = 0b00011000 +) + +/* +type Payload struct { + Header *Header + PacketizationUnit *PacketizationUnit +} + +type PacketizationUnit struct { + VideoBox + ColorBox + // ... +} +*/ + +type Header struct { + // Sequential indicates whether packets are sent sequentially + // or possibly out of order. may be sent out of order. + Sequential bool + + // PacketMode indicates the packetization mode. If true, + // codestream packetization is used. If false, slice + // packetization is used and Sequential must be false. + PacketMode bool + + // Last indicates whether the packet is the last packet of a + // packetization unit. + Last bool + + // InterlacedInfo specifies how the frame is scanned. + InterlacedInfo ScanMode + + // FrameCount holds a 5-bit integer (modulo 32) identifying + // the frame to which the packet belongs. + FrameCount uint8 + + // SEPCounter (Slice and Extended Packet counter) + // holds an 11-bit integer which is interpreted differently + // depending on the value of PacketMode. + // + // If the packetization mode is codestream, then SEPCounter is + // incremented by 1 whenever PacketCounter overruns. + // + // If packetization mode is slice, then SEPCounter identifies + // the slice (modulo 2047) to which the packet contributes. + SEPCount uint16 + + // PacketCounter is an 11-bit integer identifying the packet number + // within the current packetization unit. + PacketCount uint16 +} + +func unmarshalHeader(a [4]byte, hdr Header) error { + hdr.Sequential = a[0]&0b10000000 > 0 + hdr.PacketMode = a[0]&0b01000000 > 0 + hdr.Last = a[0]&0b00100000 > 0 + hdr.InterlacedInfo = ScanMode(a[0] & 0b00011000) + + hdr.FrameCount = (a[0] & 0b00000111) << 2 + hdr.FrameCount |= ((a[1] & 0b11000000) >> 6) + + var sepc [2]byte + sepc[0] = a[1] & 0b00111000 >> 3 + sepc[1] = a[1] & 0b00000111 << 5 + sepc[1] |= a[2] & 0b11111000 >> 3 + hdr.SEPCount = binary.BigEndian.Uint16(sepc[:]) + + hdr.PacketCount = binary.BigEndian.Uint16([]byte{a[2] & 0b00000111, a[3]}) + return nil +} + +func marshalHeader(hdr Header) [4]byte { + var a [4]byte + if hdr.Sequential { + a[0] |= (1 << 7) + } + if hdr.PacketMode { + a[0] |= (1 << 6) + } + if hdr.Last { + a[0] |= (1 << 5) + } + a[0] |= byte(hdr.InterlacedInfo) + + // Need to pack the 5 bits in FrameCount across both a[0] and a[1]. + // Have 3 bits remaining in a[0]. + a[0] |= (hdr.FrameCount & 0b00011100) >> 2 + // Pack remaining 2 bits from FrameCount into left-most bits of a[1]. + a[1] = (hdr.FrameCount & 0b00000011) << 6 + + // 6 bits remaining in a[1]. + // We have 11 bits in SEPCount to pack. + b := make([]byte, 2) + binary.BigEndian.PutUint16(b, hdr.SEPCount) + a[1] |= (b[0] & 0b00000111) << 3 + // 3 bits remaining in a[1], so get next 3 bits from b. + a[1] |= (b[1] & 0b11100000) >> 5 + + // 5 bits remaining in b. + a[2] = (b[1] & 0b00011111) << 3 + + b[0] = 0 + b[1] = 0 + binary.BigEndian.PutUint16(b, hdr.PacketCount) + // 3 bits spare in a[2]. + a[2] |= (b[0] & 0b00000111) + a[3] = b[1] + return a +}