Skip to content

Commit 5ca580f

Browse files
committed
Added parameters
1 parent 3f773c3 commit 5ca580f

File tree

6 files changed

+247
-7
lines changed

6 files changed

+247
-7
lines changed

interfaces.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ type Manager interface {
7272

7373
// Return video parameters for encoding
7474
// Width, Height, PixelFormat, Framerate
75-
VideoParameters(int, int, string, float32) (VideoParameters, error)
75+
VideoParameters(int, int, string, float64) (VideoParameters, error)
7676

7777
// Return version information for the media manager as a set of
7878
// metadata
@@ -184,7 +184,7 @@ type AudioParameters interface {
184184
SampleFormat() string
185185

186186
// Return the sample rate (Hz)
187-
SampleRate() int
187+
Samplerate() int
188188

189189
// TODO:
190190
// Planar, number of planes, bits and bytes per sample
@@ -202,7 +202,7 @@ type VideoParameters interface {
202202
PixelFormat() string
203203

204204
// Return the frame rate (fps)
205-
FrameRate() int
205+
Framerate() float64
206206

207207
// TODO:
208208
// Planar, number of planes, names of the planes, bits and bytes per pixel

manager.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,14 +215,14 @@ func (manager *manager) PixelFormats() []Metadata {
215215

216216
// Return audio parameters for encoding
217217
// ChannelLayout, SampleFormat, Samplerate
218-
func (manager *manager) AudioParameters(string, string, int) (AudioParameters, error) {
219-
return nil, ErrNotImplemented
218+
func (manager *manager) AudioParameters(channels string, samplefmt string, samplerate int) (AudioParameters, error) {
219+
return newAudioParametersEx(channels, samplefmt, samplerate)
220220
}
221221

222222
// Return video parameters for encoding
223223
// Width, Height, PixelFormat, Framerate
224-
func (manager *manager) VideoParameters(int, int, string, float32) (VideoParameters, error) {
225-
return nil, ErrNotImplemented
224+
func (manager *manager) VideoParameters(width int, height int, pixelfmt string, framerate float64) (VideoParameters, error) {
225+
return newVideoParametersEx(width, height, pixelfmt, framerate)
226226
}
227227

228228
// Open a media file or device for reading, from a path or url.

parameters.go

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package media
2+
3+
import (
4+
"encoding/json"
5+
"math"
6+
7+
ff "github.com/mutablelogic/go-media/sys/ffmpeg61"
8+
9+
// Namespace imports
10+
. "github.com/djthorpe/go-errors"
11+
)
12+
13+
////////////////////////////////////////////////////////////////////////////////
14+
// TYPES
15+
16+
type par struct {
17+
t MediaType
18+
audiopar
19+
videopar
20+
}
21+
22+
type audiopar struct {
23+
Ch ff.AVChannelLayout
24+
SampleFormat ff.AVSampleFormat
25+
Samplerate int
26+
}
27+
28+
type videopar struct {
29+
PixelFormat ff.AVPixelFormat
30+
Width int
31+
Height int
32+
Framerate ff.AVRational
33+
}
34+
35+
var _ Parameters = (*par)(nil)
36+
37+
////////////////////////////////////////////////////////////////////////////////
38+
// LIFECYCLE
39+
40+
// Create new parameters for audio sampling from number of channels, sample format and sample rate in Hz
41+
func newAudioParameters(numchannels int, samplefmt string, samplerate int) (*par, error) {
42+
// Get channel layout from number of channels
43+
var ch ff.AVChannelLayout
44+
ff.AVUtil_channel_layout_default(&ch, numchannels)
45+
if name, err := ff.AVUtil_channel_layout_describe(&ch); err != nil {
46+
return nil, err
47+
} else {
48+
return newAudioParametersEx(name, samplefmt, samplerate)
49+
}
50+
}
51+
52+
// Create new parameters for audio sampling from a channel layout name, sample format and sample rate in Hz
53+
func newAudioParametersEx(channels string, samplefmt string, samplerate int) (*par, error) {
54+
par := new(par)
55+
par.t = AUDIO
56+
57+
// Set the parameters
58+
if err := ff.AVUtil_channel_layout_from_string(&par.audiopar.Ch, channels); err != nil {
59+
return nil, err
60+
}
61+
if fmt := ff.AVUtil_get_sample_fmt(samplefmt); fmt == ff.AV_SAMPLE_FMT_NONE {
62+
return nil, ErrBadParameter.Withf("sample format %q", samplefmt)
63+
} else {
64+
par.audiopar.SampleFormat = fmt
65+
}
66+
if samplerate <= 0 {
67+
return nil, ErrBadParameter.Withf("samplerate %v", samplerate)
68+
} else {
69+
par.audiopar.Samplerate = samplerate
70+
}
71+
72+
// Return success
73+
return par, nil
74+
}
75+
76+
// Create new parameters for video from a width, height, pixel format and framerate in fps
77+
func newVideoParametersEx(width int, height int, pixelfmt string, framerate float64) (*par, error) {
78+
par := new(par)
79+
par.t = VIDEO
80+
81+
// Set the parameters
82+
if width <= 0 {
83+
// Negative widths might mean "flip" but not tested yet
84+
return nil, ErrBadParameter.Withf("width %v", width)
85+
} else {
86+
par.videopar.Width = width
87+
}
88+
if height <= 0 {
89+
// Negative heights might mean "flip" but not tested yet
90+
return nil, ErrBadParameter.Withf("height %v", height)
91+
} else {
92+
par.videopar.Height = height
93+
}
94+
if fmt := ff.AVUtil_get_pix_fmt(pixelfmt); fmt == ff.AV_PIX_FMT_NONE {
95+
return nil, ErrBadParameter.Withf("pixel format %q", pixelfmt)
96+
} else {
97+
par.videopar.PixelFormat = fmt
98+
}
99+
if framerate <= 0 {
100+
return nil, ErrBadParameter.Withf("framerate %v", framerate)
101+
} else {
102+
par.videopar.Framerate = ff.AVUtil_rational_d2q(1/framerate, 0)
103+
}
104+
105+
// Return success
106+
return par, nil
107+
}
108+
109+
// Create new parameters for video from a frame size, pixel format and framerate in fps
110+
func newVideoParameters(frame string, pixelfmt string, framerate float64) (*par, error) {
111+
// Parse the frame size
112+
w, h, err := ff.AVUtil_parse_video_size(frame)
113+
if err != nil {
114+
return nil, err
115+
}
116+
return newVideoParametersEx(w, h, pixelfmt, framerate)
117+
}
118+
119+
////////////////////////////////////////////////////////////////////////////////
120+
// STRINGIFY
121+
122+
func (par *par) MarshalJSON() ([]byte, error) {
123+
if par.t == AUDIO {
124+
return json.Marshal(par.audiopar)
125+
} else {
126+
return json.Marshal(par.videopar)
127+
}
128+
}
129+
130+
func (par *par) String() string {
131+
data, _ := json.MarshalIndent(par, "", " ")
132+
return string(data)
133+
}
134+
135+
////////////////////////////////////////////////////////////////////////////////
136+
// PUBLIC METHODS
137+
138+
// Return type
139+
func (par *par) Type() MediaType {
140+
return par.t
141+
}
142+
143+
// Return the channel layout
144+
func (par *par) ChannelLayout() string {
145+
if name, err := ff.AVUtil_channel_layout_describe(&par.audiopar.Ch); err != nil {
146+
return ""
147+
} else {
148+
return name
149+
}
150+
}
151+
152+
// Return the sample format
153+
func (par *par) SampleFormat() string {
154+
return ff.AVUtil_get_sample_fmt_name(par.audiopar.SampleFormat)
155+
}
156+
157+
// Return the sample rate (Hz)
158+
func (par *par) Samplerate() int {
159+
return par.audiopar.Samplerate
160+
}
161+
162+
// Return the sample format
163+
164+
// Return the width of the video frame
165+
func (par *par) Width() int {
166+
return par.videopar.Width
167+
}
168+
169+
// Return the height of the video frame
170+
func (par *par) Height() int {
171+
return par.videopar.Height
172+
}
173+
174+
// Return the pixel format
175+
func (par *par) PixelFormat() string {
176+
return ff.AVUtil_get_pix_fmt_name(par.videopar.PixelFormat)
177+
}
178+
179+
// Return the frame rate (fps)
180+
func (par *par) Framerate() float64 {
181+
if v := par.videopar.Framerate.Float(1); v == 0 {
182+
return math.Inf(1)
183+
} else {
184+
return 1 / v
185+
}
186+
}

parameters_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package media
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func Test_parameters_001(t *testing.T) {
10+
assert := assert.New(t)
11+
12+
for ch := 1; ch < 8; ch++ {
13+
params, err := newAudioParameters(ch, "flt", 44100)
14+
if !assert.NoError(err) {
15+
t.FailNow()
16+
}
17+
assert.NotNil(params)
18+
t.Log(params)
19+
}
20+
21+
}
22+
23+
func Test_parameters_002(t *testing.T) {
24+
assert := assert.New(t)
25+
26+
for ch := 1; ch < 8; ch++ {
27+
params, err := newVideoParameters("100x100", "rgba", 25)
28+
if !assert.NoError(err) {
29+
t.FailNow()
30+
}
31+
assert.NotNil(params)
32+
t.Log(params)
33+
}
34+
35+
}

sys/ffmpeg61/avutil_pixfmt.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package ffmpeg
33
import (
44
"encoding/json"
55
"fmt"
6+
"unsafe"
67
)
78

89
////////////////////////////////////////////////////////////////////////////////
@@ -284,6 +285,14 @@ func AVUtil_get_pix_fmt_name(pixfmt AVPixelFormat) string {
284285
return C.GoString(C.av_get_pix_fmt_name((C.enum_AVPixelFormat)(pixfmt)))
285286
}
286287

288+
// Return the pixel format corresponding to name.
289+
// If no pixel format has been found, returns AV_PIX_FMT_NONE
290+
func AVUtil_get_pix_fmt(name string) AVPixelFormat {
291+
cName := C.CString(name)
292+
defer C.free(unsafe.Pointer(cName))
293+
return AVPixelFormat(C.av_get_pix_fmt(cName))
294+
}
295+
287296
func AVUtil_get_pix_fmt_desc(pixfmt AVPixelFormat) *AVPixFmtDescriptor {
288297
return (*AVPixFmtDescriptor)(C.av_pix_fmt_desc_get(C.enum_AVPixelFormat(pixfmt)))
289298
}

sys/ffmpeg61/avutil_rational.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,13 @@ func (r AVRational) IsZero() bool {
5656
func (r AVRational) Float(multiplier int64) float64 {
5757
return float64(int64(r.num)*multiplier) / float64(r.den)
5858
}
59+
60+
////////////////////////////////////////////////////////////////////////////////
61+
// BINDINGS
62+
63+
func AVUtil_rational_d2q(d float64, max int) AVRational {
64+
if max == 0 {
65+
max = C.INT_MAX
66+
}
67+
return AVRational(C.av_d2q(C.double(d), C.int(max)))
68+
}

0 commit comments

Comments
 (0)