Skip to content

Commit e9c241a

Browse files
committed
Changes
1 parent 8509004 commit e9c241a

File tree

10 files changed

+99
-31
lines changed

10 files changed

+99
-31
lines changed

pkg/ffmpeg/encoder.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func (e *Encoder) Par() *Par {
175175
}
176176
}
177177

178-
// Return the codec type
178+
// Return the next expected timestamp after a frame has been encoded
179179
func (e *Encoder) nextPts(frame *Frame) int64 {
180180
next_pts := int64(0)
181181
switch e.ctx.Codec().Type() {
@@ -213,6 +213,8 @@ func (e *Encoder) encode(frame *Frame, fn EncoderPacketFn) error {
213213

214214
// rescale output packet timestamp values from codec to stream timebase
215215
ff.AVCodec_packet_rescale_ts(e.packet, e.ctx.TimeBase(), e.stream.TimeBase())
216+
217+
// Set packet parameters
216218
e.packet.SetStreamIndex(e.stream.Index())
217219
e.packet.SetTimeBase(e.stream.TimeBase())
218220

pkg/ffmpeg/frame.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package ffmpeg
33
import (
44
"encoding/json"
55
"errors"
6+
"fmt"
67

78
// Packages
89
media "github.com/mutablelogic/go-media"
@@ -88,6 +89,11 @@ func (frame *Frame) AllocateBuffers() error {
8889
return ff.AVUtil_frame_get_buffer((*ff.AVFrame)(frame), false)
8990
}
9091

92+
// Return true if the frame has allocated buffers
93+
func (frame *Frame) IsAllocated() bool {
94+
return ff.AVUtil_frame_is_allocated((*ff.AVFrame)(frame))
95+
}
96+
9197
// Make the frame writable
9298
func (frame *Frame) MakeWritable() error {
9399
return ff.AVUtil_frame_make_writable((*ff.AVFrame)(frame))
@@ -99,6 +105,7 @@ func (frame *Frame) Copy() (*Frame, error) {
99105
if copy == nil {
100106
return nil, errors.New("failed to allocate frame")
101107
}
108+
102109
switch frame.Type() {
103110
case media.AUDIO:
104111
copy.SetSampleFormat(frame.SampleFormat())
@@ -114,18 +121,21 @@ func (frame *Frame) Copy() (*Frame, error) {
114121
ff.AVUtil_frame_free(copy)
115122
return nil, errors.New("invalid codec type")
116123
}
117-
if err := ff.AVUtil_frame_get_buffer(copy, false); err != nil {
118-
ff.AVUtil_frame_free(copy)
119-
return nil, err
120-
}
121-
if err := ff.AVUtil_frame_copy(copy, (*ff.AVFrame)(frame)); err != nil {
122-
ff.AVUtil_frame_free(copy)
123-
return nil, err
124+
if frame.IsAllocated() {
125+
if err := ff.AVUtil_frame_get_buffer(copy, false); err != nil {
126+
ff.AVUtil_frame_free(copy)
127+
return nil, fmt.Errorf("AVUtil_frame_get_buffer: %w", err)
128+
}
129+
if err := ff.AVUtil_frame_copy(copy, (*ff.AVFrame)(frame)); err != nil {
130+
ff.AVUtil_frame_free(copy)
131+
return nil, fmt.Errorf("AVUtil_frame_copy: %w", err)
132+
}
124133
}
125134
if err := ff.AVUtil_frame_copy_props(copy, (*ff.AVFrame)(frame)); err != nil {
126135
ff.AVUtil_frame_free(copy)
127-
return nil, err
136+
return nil, fmt.Errorf("AVUtil_frame_copy_props: %w", err)
128137
}
138+
129139
return (*Frame)(copy), nil
130140
}
131141

pkg/ffmpeg/frame_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,24 @@ func Test_frame_003(t *testing.T) {
4848
assert.Equal(720, frame.Height())
4949
t.Log(frame)
5050
}
51+
52+
func Test_frame_004(t *testing.T) {
53+
assert := assert.New(t)
54+
55+
frame, err := ffmpeg.NewFrame(ffmpeg.VideoPar("rgba", "1280x720", 25))
56+
if !assert.NoError(err) {
57+
t.FailNow()
58+
}
59+
defer frame.Close()
60+
61+
copy, err := frame.Copy()
62+
if !assert.NoError(err) {
63+
t.FailNow()
64+
}
65+
defer copy.Close()
66+
67+
assert.Equal(copy.Type(), frame.Type())
68+
assert.Equal(copy.PixelFormat(), frame.PixelFormat())
69+
assert.Equal(copy.Width(), frame.Width())
70+
assert.Equal(copy.Height(), frame.Height())
71+
}

pkg/ffmpeg/par.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ type Par struct {
2222
}
2323

2424
type jsonPar struct {
25-
Par ff.AVCodecParameters `json:"parameters"`
26-
Timebase ff.AVRational `json:"timebase"`
27-
Framerate float64 `json:"framerate,omitempty"`
25+
Par ff.AVCodecParameters `json:"parameters"`
26+
Timebase ff.AVRational `json:"timebase"`
2827
}
2928

3029
///////////////////////////////////////////////////////////////////////////////
@@ -79,7 +78,7 @@ func NewVideoPar(pixfmt string, size string, framerate float64) (*Par, error) {
7978
par.SetHeight(h)
8079
}
8180

82-
// Frame rate
81+
// Frame rate and timebase
8382
if framerate < 0 {
8483
return nil, ErrBadParameter.Withf("negative framerate %v", framerate)
8584
} else if framerate > 0 {
@@ -131,9 +130,8 @@ func VideoPar(pixfmt string, size string, framerate float64) *Par {
131130

132131
func (ctx *Par) MarshalJSON() ([]byte, error) {
133132
return json.Marshal(jsonPar{
134-
Par: ctx.AVCodecParameters,
135-
Timebase: ctx.timebase,
136-
Framerate: ctx.FrameRate(),
133+
Par: ctx.AVCodecParameters,
134+
Timebase: ctx.timebase,
137135
})
138136
}
139137

pkg/ffmpeg/reader.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@ import (
44
"context"
55
"encoding/json"
66
"errors"
7-
"fmt"
87
"io"
98
"slices"
109
"strings"
11-
"sync"
1210
"time"
1311

1412
// Packages
@@ -251,6 +249,7 @@ func (r *Reader) Decode(ctx context.Context, mapfn DecoderMapFunc, decodefn Deco
251249
// As per the decode method, the map function is called for each stream and should return the
252250
// parameters for the destination. If the map function returns nil for a stream, then
253251
// the stream is ignored.
252+
/*
254253
func (r *Reader) Transcode(ctx context.Context, w io.Writer, mapfn DecoderMapFunc, opt ...Opt) error {
255254
// Map streams to decoders
256255
decoders, err := r.mapStreams(mapfn)
@@ -309,7 +308,7 @@ func (r *Reader) Transcode(ctx context.Context, w io.Writer, mapfn DecoderMapFun
309308
// Return any errors
310309
return result
311310
}
312-
311+
*/
313312
////////////////////////////////////////////////////////////////////////////////
314313
// PRIVATE METHODS - DECODE
315314

pkg/ffmpeg/resampler.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,15 @@ func (r *resampler) Frame(src *Frame) (*Frame, error) {
112112
sample_fmt := r.dest.SampleFormat()
113113
sample_rate := r.dest.SampleRate()
114114
sample_ch := r.dest.ChannelLayout()
115+
sample_tb := r.dest.TimeBase()
116+
sample_pts := r.dest.Pts()
115117
r.dest.Unref()
116118
(*ff.AVFrame)(r.dest).SetSampleFormat(sample_fmt)
117119
(*ff.AVFrame)(r.dest).SetSampleRate(sample_rate)
118120
(*ff.AVFrame)(r.dest).SetChannelLayout(sample_ch)
119121
(*ff.AVFrame)(r.dest).SetNumSamples(num_samples)
122+
(*ff.AVFrame)(r.dest).SetTimeBase(sample_tb)
123+
(*ff.AVFrame)(r.dest).SetPts(sample_pts)
120124
if err := r.dest.AllocateBuffers(); err != nil {
121125
ff.SWResample_free(r.ctx)
122126
return nil, err
@@ -130,6 +134,11 @@ func (r *resampler) Frame(src *Frame) (*Frame, error) {
130134
return nil, nil
131135
}
132136

137+
// Set the pts
138+
if src != nil && src.Pts() != ff.AV_NOPTS_VALUE {
139+
r.dest.SetPts(ff.AVUtil_rational_rescale_q(src.Pts(), src.TimeBase(), r.dest.TimeBase()))
140+
}
141+
133142
// Return the destination frame or nil
134143
return r.dest, nil
135144
}

pkg/ffmpeg/resampler_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ func Test_resampler_001(t *testing.T) {
4949
if !assert.NoError(err) {
5050
t.FailNow()
5151
}
52-
t.Log(" =>", dest)
5352
if dest == nil {
5453
break
5554
}
55+
t.Log(" =>", dest)
5656
}
5757
}

pkg/generator/ebu.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func init() {
3636
draw2d.SetFontCache(fonts.NewFontCache())
3737
}
3838

39-
// Create a new video generator which generates the EBU Test Card
39+
// Create a new video generator which generates the EBU Colour Bars
4040
func NewEBU(par *ffmpeg.Par) (*ebu, error) {
4141
ebu := new(ebu)
4242

pkg/generator/yuv420p.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,11 @@ func (yuv420p *yuv420p) String() string {
7575

7676
// Return the first and subsequent frames of raw video data
7777
func (yuv420p *yuv420p) Frame() *ffmpeg.Frame {
78-
// Make a writable copy if the frame is not writable
79-
if err := yuv420p.frame.MakeWritable(); err != nil {
80-
return nil
81-
}
82-
8378
// Set the Pts
8479
if yuv420p.frame.Pts() == ffmpeg.PTS_UNDEFINED {
8580
yuv420p.frame.SetPts(0)
8681
} else {
82+
// Increment by one frame
8783
yuv420p.frame.IncPts(1)
8884
}
8985

sys/ffmpeg61/avutil_frame.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type jsonAVFrame struct {
4242
*jsonAVVideoFrame
4343
NumPlanes int `json:"num_planes,omitempty"`
4444
PlaneBytes []int `json:"plane_bytes,omitempty"`
45-
Pts AVTimestamp `json:"pts,omitempty"`
45+
Pts AVTimestamp `json:"pts"`
4646
TimeBase AVRational `json:"time_base,omitempty"`
4747
}
4848

@@ -123,6 +123,10 @@ func AVUtil_frame_get_buffer(frame *AVFrame, align bool) error {
123123
return nil
124124
}
125125

126+
func AVUtil_frame_is_allocated(frame *AVFrame) bool {
127+
return frame.data[0] != nil
128+
}
129+
126130
// Ensure that the frame data is writable, avoiding data copy if possible.
127131
// Do nothing if the frame is writable, allocate new buffers and copy the data if it is not.
128132
// Non-refcounted frames behave as non-writable, i.e. a copy is always made.
@@ -146,6 +150,7 @@ func AVUtil_frame_get_num_planes(frame *AVFrame) int {
146150
// Video
147151
return AVUtil_pix_fmt_count_planes(AVPixelFormat(frame.format))
148152
}
153+
149154
// Other
150155
return 0
151156
}
@@ -246,10 +251,6 @@ func (ctx *AVFrame) SetPts(pts int64) {
246251
ctx.pts = C.int64_t(pts)
247252
}
248253

249-
func (ctx *AVFrame) BestEffortTs() int64 {
250-
return int64(ctx.best_effort_timestamp)
251-
}
252-
253254
func (ctx *AVFrame) TimeBase() AVRational {
254255
return AVRational(ctx.time_base)
255256
}
@@ -283,6 +284,10 @@ func (ctx *AVFrame) Planesize(plane int) int {
283284
// Return all strides.
284285
func (ctx *AVFrame) linesizes() []int {
285286
var linesizes []int
287+
288+
if !AVUtil_frame_is_allocated(ctx) {
289+
return nil
290+
}
286291
for i := 0; i < AVUtil_frame_get_num_planes(ctx); i++ {
287292
linesizes = append(linesizes, ctx.Linesize(i))
288293
}
@@ -292,6 +297,10 @@ func (ctx *AVFrame) linesizes() []int {
292297
// Return all planes sizes
293298
func (ctx *AVFrame) planesizes() []int {
294299
var planesizes []int
300+
301+
if !AVUtil_frame_is_allocated(ctx) {
302+
return nil
303+
}
295304
for i := 0; i < AVUtil_frame_get_num_planes(ctx); i++ {
296305
planesizes = append(planesizes, ctx.Planesize(i))
297306
}
@@ -305,41 +314,65 @@ func (ctx *AVFrame) Bytes(plane int) []byte {
305314

306315
// Returns a plane as a uint8 array.
307316
func (ctx *AVFrame) Uint8(plane int) []uint8 {
317+
if !AVUtil_frame_is_allocated(ctx) {
318+
return nil
319+
}
308320
return cUint8Slice(unsafe.Pointer(ctx.data[plane]), C.int(ctx.Planesize(plane)))
309321
}
310322

311323
// Returns a plane as a int8 array.
312324
func (ctx *AVFrame) Int8(plane int) []int8 {
325+
if !AVUtil_frame_is_allocated(ctx) {
326+
return nil
327+
}
313328
return cInt8Slice(unsafe.Pointer(ctx.data[plane]), C.int(ctx.Planesize(plane)))
314329
}
315330

316331
// Returns a plane as a uint16 array.
317332
func (ctx *AVFrame) Uint16(plane int) []uint16 {
333+
if !AVUtil_frame_is_allocated(ctx) {
334+
return nil
335+
}
318336
return cUint16Slice(unsafe.Pointer(ctx.data[plane]), C.int(ctx.Planesize(plane)>>1))
319337
}
320338

321339
// Returns a plane as a int16 array.
322340
func (ctx *AVFrame) Int16(plane int) []int16 {
341+
if !AVUtil_frame_is_allocated(ctx) {
342+
return nil
343+
}
323344
return cInt16Slice(unsafe.Pointer(ctx.data[plane]), C.int(ctx.Planesize(plane)>>1))
324345
}
325346

326347
// Returns a plane as a uint32 array.
327348
func (ctx *AVFrame) Uint32(plane int) []uint32 {
349+
if !AVUtil_frame_is_allocated(ctx) {
350+
return nil
351+
}
328352
return cUint32Slice(unsafe.Pointer(ctx.data[plane]), C.int(ctx.Planesize(plane)>>2))
329353
}
330354

331355
// Returns a plane as a int32 array.
332356
func (ctx *AVFrame) Int32(plane int) []int32 {
357+
if !AVUtil_frame_is_allocated(ctx) {
358+
return nil
359+
}
333360
return cInt32Slice(unsafe.Pointer(ctx.data[plane]), C.int(ctx.Planesize(plane)>>2))
334361
}
335362

336363
// Returns a plane as a float32 array.
337364
func (ctx *AVFrame) Float32(plane int) []float32 {
365+
if !AVUtil_frame_is_allocated(ctx) {
366+
return nil
367+
}
338368
return cFloat32Slice(unsafe.Pointer(ctx.data[plane]), C.int(ctx.Planesize(plane)>>2))
339369
}
340370

341371
// Returns a plane as a float64 array.
342372
func (ctx *AVFrame) Float64(plane int) []float64 {
373+
if !AVUtil_frame_is_allocated(ctx) {
374+
return nil
375+
}
343376
return cFloat64Slice(unsafe.Pointer(ctx.data[plane]), C.int(ctx.Planesize(plane)>>3))
344377
}
345378

0 commit comments

Comments
 (0)