Skip to content

Commit fe0b071

Browse files
committed
Changes for writer
1 parent 2c733b2 commit fe0b071

16 files changed

+1073
-31
lines changed

pkg/ffmpeg/frame.go

+30-24
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package media
1+
package ffmpeg
22

33
import (
44
"encoding/json"
@@ -17,8 +17,9 @@ import (
1717
////////////////////////////////////////////////////////////////////////////////
1818
// TYPES
1919

20-
type frame struct {
21-
ctx *ff.AVFrame
20+
type Frame struct {
21+
ctx *ff.AVFrame
22+
stream int
2223
}
2324

2425
var (
@@ -40,27 +41,32 @@ var (
4041
////////////////////////////////////////////////////////////////////////////////
4142
// LIFECYCLE
4243

43-
func NewFrame(ctx *ff.AVFrame) *frame {
44-
return &frame{ctx}
44+
func NewFrame(ctx *ff.AVFrame, stream int) *Frame {
45+
return &Frame{ctx, stream}
4546
}
4647

4748
////////////////////////////////////////////////////////////////////////////////
4849
// STRINGIFY
4950

50-
func (frame *frame) MarshalJSON() ([]byte, error) {
51+
func (frame *Frame) MarshalJSON() ([]byte, error) {
5152
return json.Marshal(frame.ctx)
5253
}
5354

54-
func (frame *frame) String() string {
55+
func (frame *Frame) String() string {
5556
data, _ := json.MarshalIndent(frame, "", " ")
5657
return string(data)
5758
}
5859

5960
////////////////////////////////////////////////////////////////////////////////
6061
// PARAMETERS
6162

63+
// Return the context
64+
func (frame *Frame) AVFrame() *ff.AVFrame {
65+
return frame.ctx
66+
}
67+
6268
// Return the media type (AUDIO, VIDEO)
63-
func (frame *frame) Type() media.MediaType {
69+
func (frame *Frame) Type() media.MediaType {
6470
if frame.ctx.NumSamples() > 0 {
6571
return media.AUDIO
6672
}
@@ -70,13 +76,13 @@ func (frame *frame) Type() media.MediaType {
7076
return media.NONE
7177
}
7278

73-
// Id is unused
74-
func (frame *frame) Id() int {
75-
return 0
79+
// Return the stream
80+
func (frame *Frame) Id() int {
81+
return frame.stream
7682
}
7783

7884
// Return the timestamp as a duration, or minus one if not set
79-
func (frame *frame) Time() time.Duration {
85+
func (frame *Frame) Time() time.Duration {
8086
pts := frame.ctx.Pts()
8187
if pts == ff.AV_NOPTS_VALUE {
8288
return -1
@@ -89,17 +95,17 @@ func (frame *frame) Time() time.Duration {
8995

9096
// Return the number of planes for a specific PixelFormat
9197
// or SampleFormat and ChannelLayout combination
92-
func (frame *frame) NumPlanes() int {
98+
func (frame *Frame) NumPlanes() int {
9399
return ff.AVUtil_frame_get_num_planes(frame.ctx)
94100
}
95101

96102
// Return the byte data for a plane
97-
func (frame *frame) Bytes(plane int) []byte {
103+
func (frame *Frame) Bytes(plane int) []byte {
98104
return frame.ctx.Bytes(plane)[:frame.ctx.Planesize(plane)]
99105
}
100106

101107
// Return the int16 data for a plane
102-
func (frame *frame) Int16(plane int) []int16 {
108+
func (frame *Frame) Int16(plane int) []int16 {
103109
sz := frame.ctx.Planesize(plane) >> 1
104110
return frame.ctx.Int16(plane)[:sz]
105111
}
@@ -108,15 +114,15 @@ func (frame *frame) Int16(plane int) []int16 {
108114
// AUDIO PARAMETERS
109115

110116
// Return number of samples
111-
func (frame *frame) NumSamples() int {
117+
func (frame *Frame) NumSamples() int {
112118
if frame.Type() != media.AUDIO {
113119
return 0
114120
}
115121
return frame.ctx.NumSamples()
116122
}
117123

118124
// Return channel layout
119-
func (frame *frame) ChannelLayout() string {
125+
func (frame *Frame) ChannelLayout() string {
120126
if frame.Type() != media.AUDIO {
121127
return ""
122128
}
@@ -129,15 +135,15 @@ func (frame *frame) ChannelLayout() string {
129135
}
130136

131137
// Return the sample format
132-
func (frame *frame) SampleFormat() string {
138+
func (frame *Frame) SampleFormat() string {
133139
if frame.Type() != media.AUDIO {
134140
return ""
135141
}
136142
return ff.AVUtil_get_sample_fmt_name(frame.ctx.SampleFormat())
137143
}
138144

139145
// Return the sample rate (Hz)
140-
func (frame *frame) Samplerate() int {
146+
func (frame *Frame) Samplerate() int {
141147
if frame.Type() != media.AUDIO {
142148
return 0
143149
}
@@ -149,7 +155,7 @@ func (frame *frame) Samplerate() int {
149155
// VIDEO PARAMETERS
150156

151157
// Convert a frame into an image
152-
func (frame *frame) Image() (image.Image, error) {
158+
func (frame *Frame) Image() (image.Image, error) {
153159
if t := frame.Type(); t != media.VIDEO {
154160
return nil, ErrBadParameter.With("unsupported frame type", t)
155161
}
@@ -205,7 +211,7 @@ func (frame *frame) Image() (image.Image, error) {
205211
}
206212

207213
// Return the number of bytes in a single row of the video frame
208-
func (frame *frame) Stride(plane int) int {
214+
func (frame *Frame) Stride(plane int) int {
209215
if frame.Type() == media.VIDEO {
210216
return frame.ctx.Linesize(plane)
211217
} else {
@@ -214,23 +220,23 @@ func (frame *frame) Stride(plane int) int {
214220
}
215221

216222
// Return the width of the video frame
217-
func (frame *frame) Width() int {
223+
func (frame *Frame) Width() int {
218224
if frame.Type() != media.VIDEO {
219225
return 0
220226
}
221227
return frame.ctx.Width()
222228
}
223229

224230
// Return the height of the video frame
225-
func (frame *frame) Height() int {
231+
func (frame *Frame) Height() int {
226232
if frame.Type() != media.VIDEO {
227233
return 0
228234
}
229235
return frame.ctx.Height()
230236
}
231237

232238
// Return the pixel format
233-
func (frame *frame) PixelFormat() string {
239+
func (frame *Frame) PixelFormat() string {
234240
if frame.Type() != media.VIDEO {
235241
return ""
236242
}

pkg/ffmpeg/opts.go

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package ffmpeg
2+
3+
import (
4+
// Namespace imports
5+
6+
. "github.com/djthorpe/go-errors"
7+
ffmpeg "github.com/mutablelogic/go-media/sys/ffmpeg61"
8+
)
9+
10+
////////////////////////////////////////////////////////////////////////////////
11+
// TYPES
12+
13+
type Opt func(*opts) error
14+
15+
type opts struct {
16+
// Resample/resize options
17+
force bool
18+
19+
// Format options
20+
oformat *ffmpeg.AVOutputFormat
21+
22+
// Audio options
23+
sample_fmt ffmpeg.AVSampleFormat
24+
ch ffmpeg.AVChannelLayout
25+
samplerate int
26+
27+
// Video options
28+
pix_fmt ffmpeg.AVPixelFormat
29+
width, height int
30+
}
31+
32+
////////////////////////////////////////////////////////////////////////////////
33+
// PUBLIC METHODS
34+
35+
// Output format from name or url
36+
func OptOutputFormat(name string) Opt {
37+
return func(o *opts) error {
38+
// By name
39+
if oformat := ffmpeg.AVFormat_guess_format(name, name, name); oformat != nil {
40+
o.oformat = oformat
41+
} else {
42+
return ErrBadParameter.Withf("invalid output format %q", name)
43+
}
44+
return nil
45+
}
46+
}
47+
48+
// Force resampling and resizing on decode, even if the input and output
49+
// parameters are the same
50+
func OptForce() Opt {
51+
return func(o *opts) error {
52+
o.force = true
53+
return nil
54+
}
55+
}
56+
57+
// Pixel format of the output frame
58+
func OptPixFormat(format string) Opt {
59+
return func(o *opts) error {
60+
fmt := ffmpeg.AVUtil_get_pix_fmt(format)
61+
if fmt == ffmpeg.AV_PIX_FMT_NONE {
62+
return ErrBadParameter.Withf("invalid pixel format %q", format)
63+
}
64+
o.pix_fmt = fmt
65+
return nil
66+
}
67+
}
68+
69+
// Width and height of the output frame
70+
func OptWidthHeight(w, h int) Opt {
71+
return func(o *opts) error {
72+
if w <= 0 || h <= 0 {
73+
return ErrBadParameter.Withf("invalid width %v or height %v", w, h)
74+
}
75+
o.width = w
76+
o.height = h
77+
return nil
78+
}
79+
}
80+
81+
// Frame size
82+
func OptFrameSize(size string) Opt {
83+
return func(o *opts) error {
84+
w, h, err := ffmpeg.AVUtil_parse_video_size(size)
85+
if err != nil {
86+
return ErrBadParameter.Withf("invalid frame size %q", size)
87+
}
88+
o.width = w
89+
o.height = h
90+
return nil
91+
}
92+
}
93+
94+
// Channel layout
95+
func OptChannelLayout(layout string) Opt {
96+
return func(o *opts) error {
97+
return ffmpeg.AVUtil_channel_layout_from_string(&o.ch, layout)
98+
}
99+
}
100+
101+
// Nuumber of channels
102+
func OptChannels(ch int) Opt {
103+
return func(o *opts) error {
104+
if ch <= 0 || ch > 64 {
105+
return ErrBadParameter.Withf("invalid number of channels %v", ch)
106+
}
107+
ffmpeg.AVUtil_channel_layout_default(&o.ch, ch)
108+
return nil
109+
}
110+
}
111+
112+
// Sample Rate
113+
func OptSampleRate(rate int) Opt {
114+
return func(o *opts) error {
115+
if rate <= 0 {
116+
return ErrBadParameter.Withf("invalid sample rate %v", rate)
117+
}
118+
o.samplerate = rate
119+
return nil
120+
}
121+
}
122+
123+
// Sample format
124+
func OptSampleFormat(format string) Opt {
125+
return func(o *opts) error {
126+
fmt := ffmpeg.AVUtil_get_sample_fmt(format)
127+
if fmt == ffmpeg.AV_SAMPLE_FMT_NONE {
128+
return ErrBadParameter.Withf("invalid sample format %q", format)
129+
}
130+
o.sample_fmt = fmt
131+
return nil
132+
}
133+
}

0 commit comments

Comments
 (0)