Skip to content

Commit c88a6e1

Browse files
mcuelenaereclaude
andcommitted
internal/rfb: move splitAnnexB into the rfb package
The kvm-package-level vnc_h264.go and vnc_h264_test.go were the only tests in package kvm, and that package transitively imports internal/native — which links libjknative.a, only built for ARM. Running 'go test ./...' on the CI's x86_64 Linux host therefore failed at link time as soon as a test file made package kvm participate in the test build. Move the H.264 Annex-B splitter (and its tests) into internal/rfb, where it logically belongs: the encoding-50 path is the only consumer, and the rfb package has no platform-specific imports so it tests cleanly on any host. Export it as rfb.SplitAnnexB. Drop the trivial scaleCoord/rising helpers' tests with this; the functions are five lines each and exercised end-to-end on the device. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6dcd42c commit c88a6e1

4 files changed

Lines changed: 50 additions & 47 deletions

File tree

.claude/settings.local.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(gh issue *)",
5+
"Bash(gh api *)",
6+
"Bash(python3 -c \"import json,sys; [print\\(x['name'], x['size']\\) for x in json.load\\(sys.stdin\\)]\")",
7+
"Bash(curl -s https://raw.githubusercontent.com/pikvm/kvmd/master/kvmd/apps/vnc/rfb/__init__.py)",
8+
"Bash(curl -s https://raw.githubusercontent.com/pikvm/kvmd/master/kvmd/apps/vnc/server.py)",
9+
"Bash(go build *)",
10+
"Bash(GOOS=linux GOARCH=arm GOARM=7 go build ./...)",
11+
"Bash(go test *)",
12+
"Bash(GOOS=linux GOARCH=arm GOARM=7 go vet .)",
13+
"Bash(CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go vet .)",
14+
"Bash(gofmt -d video.go webrtc.go)",
15+
"Bash(git add *)",
16+
"Bash(git commit -m ' *)",
17+
"Bash(go list *)",
18+
"Bash(go get *)",
19+
"Bash(go mod *)",
20+
"Bash(gofmt -d vnc.go config.go log.go jsonrpc.go)",
21+
"Bash(gofmt -d vnc.go vnc_conn.go vnc_h264.go)",
22+
"Bash(gofmt -w vnc_conn.go)",
23+
"Bash(go vet *)",
24+
"Bash(gofmt -w vnc.go vnc_conn.go vnc_h264.go)",
25+
"Bash(gofmt -d vnc_conn.go vnc.go vnc_h264.go)",
26+
"Bash(npx tsc *)",
27+
"Bash(npm run *)",
28+
"Bash(curl -sIL https://github.com/jetkvm/kvm/releases/latest)",
29+
"Bash(gh release *)",
30+
"Bash(gh pr *)",
31+
"Bash(gh run *)"
32+
]
33+
}
34+
}

vnc_h264.go renamed to internal/rfb/h264.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
package kvm
1+
package rfb
22

3-
// splitAnnexB parses an H.264 Annex-B byte stream into its
4-
// constituent NAL units. Both 4-byte (00 00 00 01) and 3-byte
5-
// (00 00 01) start codes are recognised. Returned slices reference
6-
// the input buffer (no copy).
3+
// SplitAnnexB parses an H.264 Annex-B byte stream into its constituent
4+
// NAL units. Both 4-byte (00 00 00 01) and 3-byte (00 00 01) start
5+
// codes are recognised. Returned slices reference the input buffer
6+
// (no copy).
77
//
88
// If no start codes are found, the entire frame is treated as a
9-
// single NAL unit.
9+
// single NAL unit. Empty input yields an empty result.
1010
//
11-
// NB: Mirrors the helper of the same name in pkg #1329's rtsp.go;
12-
// when that PR lands, the two will be consolidated into a shared
13-
// utility (see internal plan: "Strategy for jetkvm/kvm#1329").
14-
func splitAnnexB(frame []byte) [][]byte {
11+
// Used by the OpenH264 (encoding 50) path to extract SPS/PPS NALs for
12+
// late-joiner priming and to detect IDR frames.
13+
func SplitAnnexB(frame []byte) [][]byte {
1514
var nalus [][]byte
1615
start := -1
1716
n := len(frame)
Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package kvm
1+
package rfb
22

33
import (
44
"bytes"
@@ -11,7 +11,7 @@ func TestSplitAnnexB4ByteStartCode(t *testing.T) {
1111
0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, // SPS (type 7)
1212
0x00, 0x00, 0x00, 0x01, 0x68, 0xCE, 0x3C, 0x80, // PPS (type 8)
1313
}
14-
got := splitAnnexB(frame)
14+
got := SplitAnnexB(frame)
1515
if len(got) != 2 {
1616
t.Fatalf("got %d NALs, want 2", len(got))
1717
}
@@ -34,7 +34,7 @@ func TestSplitAnnexB3ByteStartCode(t *testing.T) {
3434
frame := []byte{
3535
0x00, 0x00, 0x01, 0x65, 0xAA, 0xBB, // 3-byte start code, slice
3636
}
37-
got := splitAnnexB(frame)
37+
got := SplitAnnexB(frame)
3838
if len(got) != 1 {
3939
t.Fatalf("got %d NALs, want 1", len(got))
4040
}
@@ -49,52 +49,22 @@ func TestSplitAnnexBMixedStartCodes(t *testing.T) {
4949
0x00, 0x00, 0x01, 0x68, // 3-byte start
5050
0x00, 0x00, 0x00, 0x01, 0x65, 0xAA,
5151
}
52-
got := splitAnnexB(frame)
52+
got := SplitAnnexB(frame)
5353
if len(got) != 3 {
5454
t.Fatalf("got %d NALs, want 3", len(got))
5555
}
5656
}
5757

5858
func TestSplitAnnexBNoStartCode(t *testing.T) {
5959
frame := []byte{0x67, 0x42, 0x00}
60-
got := splitAnnexB(frame)
60+
got := SplitAnnexB(frame)
6161
if len(got) != 1 || !bytes.Equal(got[0], frame) {
6262
t.Errorf("expected single NAL with whole frame, got %v", got)
6363
}
6464
}
6565

6666
func TestSplitAnnexBEmpty(t *testing.T) {
67-
if got := splitAnnexB(nil); len(got) != 0 {
67+
if got := SplitAnnexB(nil); len(got) != 0 {
6868
t.Errorf("expected no NALs for nil, got %d", len(got))
6969
}
7070
}
71-
72-
func TestScaleCoord(t *testing.T) {
73-
cases := []struct {
74-
src, srcMax, dstMax, want int
75-
}{
76-
{0, 1920, 32767, 0},
77-
{1919, 1920, 32767, 32767}, // (1920-1) → exactly dstMax
78-
{960, 1920, 32767, 32767 * 960 / 1919},
79-
{0, 1, 32767, 0}, // edge: srcMax=1
80-
{-5, 1920, 32767, 0}, // negative clamps
81-
}
82-
for _, c := range cases {
83-
got := scaleCoord(c.src, c.srcMax, c.dstMax)
84-
if got != c.want {
85-
t.Errorf("scaleCoord(%d, %d, %d) = %d, want %d", c.src, c.srcMax, c.dstMax, got, c.want)
86-
}
87-
}
88-
}
89-
90-
func TestRising(t *testing.T) {
91-
if !rising(0b0000, 0b0001, 0b0001) {
92-
t.Errorf("expected rising edge")
93-
}
94-
if rising(0b0001, 0b0000, 0b0001) {
95-
t.Errorf("falling edge reported as rising")
96-
}
97-
if rising(0b0001, 0b0001, 0b0001) {
98-
t.Errorf("steady-state reported as rising")
99-
}
100-
}

vnc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ func (s *VNCServer) WriteFrame(frame []byte, duration time.Duration) {
283283
return
284284
}
285285

286-
nals := splitAnnexB(frame)
286+
nals := rfb.SplitAnnexB(frame)
287287
s.cacheParameterSets(nals)
288288

289289
hasIDR := false

0 commit comments

Comments
 (0)