• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Eyevinn / hi264 / 25463011825

06 May 2026 09:47PM UTC coverage: 87.597% (-0.7%) from 88.264%
25463011825

push

github

tobbee
docs: rewrite README intro around the three primary use cases

Lead with what the toolkit is for instead of how it's built. Three
numbered use cases up front (fMP4 fragment extension that survives
foreign SPS/PPS, scratch-built test content with tunable bitrate, IDR
thumbnail extraction), a 'Why pure Go' section calling out the single
mp4ff dependency and no-cgo / no-FFmpeg posture, then the existing
scope-and-constraints note.

7882 of 8998 relevant lines covered (87.6%)

1.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.31
/pkg/encode/api.go
1
package encode
2

3
import (
4
        "bytes"
5
        "fmt"
6

7
        "github.com/Eyevinn/mp4ff/avc"
8

9
        "github.com/Eyevinn/hi264/pkg/yuv"
10
)
11

12
// EncodeParams holds H.264 encoding parameters.
13
type EncodeParams struct {
14
        Width          int            // frame width in pixels (must be even)
15
        Height         int            // frame height in pixels (must be even)
16
        QP             int            // quantization parameter (0-51, default 26)
17
        CABAC          bool           // true=Main profile CABAC, false=Baseline CAVLC
18
        DisableDeblock int            // 0=enable, 1=disable
19
        MaxRefFrames   int            // max_num_ref_frames (0=IDR-only, 1+=P-frames)
20
        ColorSpace     yuv.ColorSpace // YCbCr matrix standard (default BT601)
21
        Range          yuv.Range      // sample value range (default LimitedRange)
22
        FPS            int            // frame rate (used for level selection, 0 = ignore MBPS)
23
        Kbps           int            // bitrate in kbit/s (used for level selection, 0 = ignore bitrate)
24
}
25

26
func (p *EncodeParams) validate() error {
1✔
27
        if p.Width <= 0 || p.Width%2 != 0 {
1✔
28
                return fmt.Errorf("width must be positive and even, got %d", p.Width)
×
29
        }
×
30
        if p.Height <= 0 || p.Height%2 != 0 {
1✔
31
                return fmt.Errorf("height must be positive and even, got %d", p.Height)
×
32
        }
×
33
        if p.QP < 0 || p.QP > 51 {
1✔
34
                return fmt.Errorf("QP must be 0-51, got %d", p.QP)
×
35
        }
×
36
        return nil
1✔
37
}
38

39
func (p *EncodeParams) qp() int {
1✔
40
        if p.QP == 0 {
1✔
41
                return 26
×
42
        }
×
43
        return p.QP
1✔
44
}
45

46
// GenerateSPS returns SPS NALU bytes in Annex-B format.
47
func GenerateSPS(p EncodeParams) ([]byte, error) {
1✔
48
        if err := p.validate(); err != nil {
1✔
49
                return nil, err
×
50
        }
×
51
        level := ChooseLevel(p.Width, p.Height, p.FPS, p.Kbps, p.CABAC)
1✔
52
        var rbsp []byte
1✔
53
        if p.CABAC {
2✔
54
                rbsp = EncodeSPSMain(p.Width, p.Height, p.MaxRefFrames, level, p.ColorSpace, p.Range)
1✔
55
        } else {
2✔
56
                rbsp = EncodeSPS(p.Width, p.Height, p.MaxRefFrames, level, p.ColorSpace, p.Range)
1✔
57
        }
1✔
58
        var buf bytes.Buffer
1✔
59
        if err := WriteNALU(&buf, 7, 3, rbsp); err != nil {
1✔
60
                return nil, fmt.Errorf("write SPS: %w", err)
×
61
        }
×
62
        return buf.Bytes(), nil
1✔
63
}
64

65
// GeneratePPS returns PPS NALU bytes in Annex-B format.
66
func GeneratePPS(p EncodeParams) ([]byte, error) {
1✔
67
        if err := p.validate(); err != nil {
1✔
68
                return nil, err
×
69
        }
×
70
        var rbsp []byte
1✔
71
        if p.CABAC {
2✔
72
                rbsp = EncodePPSCABAC(p.DisableDeblock)
1✔
73
        } else {
2✔
74
                rbsp = EncodePPS(p.DisableDeblock)
1✔
75
        }
1✔
76
        var buf bytes.Buffer
1✔
77
        if err := WriteNALU(&buf, 8, 3, rbsp); err != nil {
1✔
78
                return nil, fmt.Errorf("write PPS: %w", err)
×
79
        }
×
80
        return buf.Bytes(), nil
1✔
81
}
82

83
// GenerateIDR encodes a flat-color IDR frame from a Grid/ColorMap.
84
// Returns the IDR slice NALU in Annex-B format (no SPS/PPS).
85
func GenerateIDR(p EncodeParams, grid *yuv.Grid, colors yuv.ColorMap, idrPicID uint32) ([]byte, error) {
1✔
86
        if err := p.validate(); err != nil {
1✔
87
                return nil, err
×
88
        }
×
89
        enc := &FrameEncoder{
1✔
90
                Grid:            grid,
1✔
91
                Colors:          colors,
1✔
92
                QP:              p.qp(),
1✔
93
                DisableDeblock:  p.DisableDeblock,
1✔
94
                CABAC:           p.CABAC,
1✔
95
                MaxNumRefFrames: p.MaxRefFrames,
1✔
96
                Width:           p.Width,
1✔
97
                Height:          p.Height,
1✔
98
                ColorSpace:      p.ColorSpace,
1✔
99
                Range:           p.Range,
1✔
100
        }
1✔
101
        return enc.EncodeSlice(idrPicID)
1✔
102
}
103

104
// GenerateIDRWithSPSPPS encodes a single IDR slice that references an
105
// existing SPS and PPS (typically extracted from the bitstream you're
106
// extending). The returned NALU has no fresh SPS/PPS — it is meant to be
107
// muxed into a stream that already declares them. Use this when splicing
108
// a fresh IDR onto an arbitrary upstream encoder's output.
109
//
110
// Constraints inherited from the FrameEncoder I_16x16 DC path: the source
111
// PPS must use entropy_coding_mode_flag matching p.CABAC; chroma_qp_offset
112
// is ignored (only matters for non-zero chroma residuals — fine for flat
113
// colors). Returns the IDR slice NALU in Annex-B format.
114
func GenerateIDRWithSPSPPS(p EncodeParams, sps *avc.SPS, pps *avc.PPS,
115
        plane *yuv.PlaneGrid, idrPicID uint32) ([]byte, error) {
1✔
116
        if err := p.validate(); err != nil {
1✔
117
                return nil, err
×
118
        }
×
119
        if sps.PicOrderCntType != 0 && sps.PicOrderCntType != 2 {
1✔
120
                return nil, fmt.Errorf("GenerateIDRWithSPSPPS: pic_order_cnt_type=%d not supported (only 0 and 2)",
×
121
                        sps.PicOrderCntType)
×
122
        }
×
123
        enc := &FrameEncoder{
1✔
124
                Plane:          plane,
1✔
125
                QP:             p.qp(),
1✔
126
                DisableDeblock: p.DisableDeblock,
1✔
127
                CABAC:          pps.EntropyCodingModeFlag,
1✔
128
                Width:          p.Width,
1✔
129
                Height:         p.Height,
1✔
130
                ColorSpace:     p.ColorSpace,
1✔
131
                Range:          p.Range,
1✔
132
                SPS:            sps,
1✔
133
                PPS:            pps,
1✔
134
        }
1✔
135
        return enc.EncodeSlice(idrPicID)
1✔
136
}
137

138
// GenerateIDRFromPlane encodes an IDR frame from a PlaneGrid.
139
// Returns the IDR slice NALU in Annex-B format (no SPS/PPS).
140
func GenerateIDRFromPlane(p EncodeParams, plane *yuv.PlaneGrid, idrPicID uint32) ([]byte, error) {
1✔
141
        if err := p.validate(); err != nil {
1✔
142
                return nil, err
×
143
        }
×
144
        enc := &FrameEncoder{
1✔
145
                Plane:           plane,
1✔
146
                QP:              p.qp(),
1✔
147
                DisableDeblock:  p.DisableDeblock,
1✔
148
                CABAC:           p.CABAC,
1✔
149
                MaxNumRefFrames: p.MaxRefFrames,
1✔
150
                Width:           p.Width,
1✔
151
                Height:          p.Height,
1✔
152
                ColorSpace:      p.ColorSpace,
1✔
153
                Range:           p.Range,
1✔
154
        }
1✔
155
        return enc.EncodeSlice(idrPicID)
1✔
156
}
157

158
// GeneratePSkip returns a P_Skip slice NALU in Annex-B format.
159
func GeneratePSkip(p EncodeParams, frameNum uint32) ([]byte, error) {
1✔
160
        if err := p.validate(); err != nil {
1✔
161
                return nil, err
×
162
        }
×
163
        sps := &avc.SPS{
1✔
164
                Width:            uint(p.Width),
1✔
165
                Height:           uint(p.Height),
1✔
166
                PicOrderCntType:  0,
1✔
167
                FrameMbsOnlyFlag: true,
1✔
168
        }
1✔
169
        pps := &avc.PPS{
1✔
170
                DeblockingFilterControlPresentFlag: true,
1✔
171
                EntropyCodingModeFlag:              p.CABAC,
1✔
172
                PicInitQpMinus26:                   p.qp() - 26,
1✔
173
        }
1✔
174
        // GeneratePSkip is meant for self-generated streams that start fresh
1✔
175
        // from an IDR (POC reset), so picOrderCntLsb = 2*frame_num is correct.
1✔
176
        return EncodePSkipSlice(sps, pps, frameNum, frameNum*2, p.DisableDeblock)
1✔
177
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc