4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 | Handcrafted Go bindings for libVLC and high-level media player interface
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | The package can be useful for adding multimedia capabilities to applications
44 | through the provided player interfaces. It relies on Go modules in order to
45 | mirror each supported major version of [libVLC](https://www.videolan.org/vlc/libvlc.html).
46 |
47 | Documentation for v3, which implements bindings for libVLC 3.X, can be found on [pkg.go.dev](https://pkg.go.dev/github.com/adrg/libvlc-go/v3).
48 | Documentation for v2, which implements bindings for libVLC 2.X, can be found on [pkg.go.dev](https://pkg.go.dev/github.com/adrg/libvlc-go/v2).
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | Example applications:
66 |
67 | * [GUI media player](https://github.com/adrg/libvlc-go-examples/tree/master/v3/gtk3_player)
68 | * [GUI screen recorder](https://github.com/adrg/libvlc-go-examples/tree/master/v3/gtk3_screen_recorder)
69 | * [GUI equalizer](https://github.com/adrg/libvlc-go-examples/tree/master/v3/gtk3_equalizer)
70 | * [GUI media discovery](https://github.com/adrg/libvlc-go-examples/tree/master/v3/gtk3_media_discovery)
71 |
72 | ## Prerequisites
73 |
74 | The libVLC development files are required. Instructions for installing the
75 | VLC SDK on multiple operating systems can be found on the wiki pages of this project.
76 |
77 | - [Install on Linux](https://github.com/adrg/libvlc-go/wiki/Install-on-Linux)
78 | - [Install on Windows](https://github.com/adrg/libvlc-go/wiki/Install-on-Windows)
79 | - [Install on macOS](https://github.com/adrg/libvlc-go/wiki/Install-on-macOS)
80 |
81 | ## Installation
82 |
83 | In order to support multiple versions of libVLC, the package contains a Go
84 | module for each major version of the API. Choose an installation option
85 | depending on the version of libVLC you want to use.
86 |
87 | **libVLC v3.X**
88 |
89 | ```bash
90 | go get github.com/adrg/libvlc-go/v3
91 | ```
92 |
93 | **libVLC v2.X**
94 |
95 | ```bash
96 | go get github.com/adrg/libvlc-go/v2
97 |
98 | # Build for libVLC < v2.2.0
99 | go build -tags legacy
100 | ```
101 |
102 | All versions above also work for projects which are not using Go modules.
103 | However, consider switching to modules.
104 |
105 | ## Examples
106 |
107 | * [GTK 3 media player](https://github.com/adrg/libvlc-go-examples/tree/master/v3/gtk3_player) (using [gotk3](https://github.com/gotk3/gotk3))
108 | * [GTK 3 screen recorder](https://github.com/adrg/libvlc-go-examples/tree/master/v3/gtk3_screen_recorder) (using [gotk3](https://github.com/gotk3/gotk3))
109 | * [GTK 3 media discovery](https://github.com/adrg/libvlc-go-examples/tree/master/v3/gtk3_media_discovery) (using [gotk3](https://github.com/gotk3/gotk3))
110 | * [GTK 3 equalizer](https://github.com/adrg/libvlc-go-examples/tree/master/v3/gtk3_equalizer) (using [gotk3](https://github.com/gotk3/gotk3))
111 | * [GTK 2 media player](https://github.com/adrg/libvlc-go-examples/tree/master/v3/gtk2_player) (using [go-gtk](https://github.com/mattn/go-gtk))
112 | * [GTK 2 screen recorder](https://github.com/adrg/libvlc-go-examples/tree/master/v3/gtk2_screen_recorder) (using [go-gtk](https://github.com/mattn/go-gtk))
113 | * [Basic player usage](https://github.com/adrg/libvlc-go-examples/blob/master/v3/player/player.go)
114 | * [Basic list player usage](https://github.com/adrg/libvlc-go-examples/tree/master/v3/list_player/list_player.go)
115 | * [Handling events](https://github.com/adrg/libvlc-go-examples/tree/master/v3/event_handling/event_handling.go)
116 | * [Retrieve media tracks](https://github.com/adrg/libvlc-go-examples/blob/master/v3/media_tracks/media_tracks.go)
117 | * [Retrieve media information](https://github.com/adrg/libvlc-go-examples/blob/master/v3/media_information/media_information.go)
118 | * [Display screen as player media](https://github.com/adrg/libvlc-go-examples/blob/master/v3/display_screen_media/display_screen_media.go)
119 | * [Stream media to Chromecast](https://github.com/adrg/libvlc-go-examples/blob/master/v3/chromecast_streaming/chromecast_streaming.go)
120 | * [Player equalizer usage](https://github.com/adrg/libvlc-go-examples/blob/master/v3/equalizer/equalizer.go)
121 |
122 | Examples for all supported API versions can be found at https://github.com/adrg/libvlc-go-examples.
123 |
124 | ## Usage
125 |
126 | ```go
127 | package main
128 |
129 | import (
130 | "log"
131 |
132 | vlc "github.com/adrg/libvlc-go/v3"
133 | )
134 |
135 | func main() {
136 | // Initialize libVLC. Additional command line arguments can be passed in
137 | // to libVLC by specifying them in the Init function.
138 | if err := vlc.Init("--no-video", "--quiet"); err != nil {
139 | log.Fatal(err)
140 | }
141 | defer vlc.Release()
142 |
143 | // Create a new player.
144 | player, err := vlc.NewPlayer()
145 | if err != nil {
146 | log.Fatal(err)
147 | }
148 | defer func() {
149 | player.Stop()
150 | player.Release()
151 | }()
152 |
153 | // Add a media file from path or from URL.
154 | // Set player media from path:
155 | // media, err := player.LoadMediaFromPath("localpath/test.mp4")
156 | // Set player media from URL:
157 | media, err := player.LoadMediaFromURL("http://stream-uk1.radioparadise.com/mp3-32")
158 | if err != nil {
159 | log.Fatal(err)
160 | }
161 | defer media.Release()
162 |
163 | // Retrieve player event manager.
164 | manager, err := player.EventManager()
165 | if err != nil {
166 | log.Fatal(err)
167 | }
168 |
169 | // Register the media end reached event with the event manager.
170 | quit := make(chan struct{})
171 | eventCallback := func(event vlc.Event, userData interface{}) {
172 | close(quit)
173 | }
174 |
175 | eventID, err := manager.Attach(vlc.MediaPlayerEndReached, eventCallback, nil)
176 | if err != nil {
177 | log.Fatal(err)
178 | }
179 | defer manager.Detach(eventID)
180 |
181 | // Start playing the media.
182 | err = player.Play()
183 | if err != nil {
184 | log.Fatal(err)
185 | }
186 |
187 | <-quit
188 | }
189 | ```
190 |
191 | ## In action
192 |
193 | A list of projects using libvlc-go, in alphabetical order. If you want to
194 | showcase your project in this section, please create a pull request with it.
195 |
196 | - [Alio](https://github.com/fenimore/alio) - Command-line music player with Emacs style key bindings.
197 | - [Tripbot](https://github.com/adanalife/tripbot) - An ongoing 24/7 slow-TV art project.
198 |
199 | ## Stargazers over time
200 |
201 | [](https://starchart.cc/adrg/libvlc-go)
202 |
203 | ## Contributing
204 |
205 | Contributions in the form of pull requests, issues or just general feedback,
206 | are always welcome.
207 | See [CONTRIBUTING.MD](CONTRIBUTING.md).
208 |
209 | **Contributors**:
210 | [adrg](https://github.com/adrg),
211 | [fenimore](https://github.com/fenimore),
212 | [tarrsalah](https://github.com/tarrsalah),
213 | [danielpellon](https://github.com/danielpellon),
214 | [patknight](https://github.com/patknight),
215 | [sndnvaps](https://github.com/sndnvaps),
216 | [karlpip](https://github.com/karlpip).
217 |
218 | ## Discord server
219 |
220 | libvlc-go is part of the libVLC Discord Community [server](https://discord.gg/3h3K3JF). Feel free to come say hello!
221 |
222 | ## References
223 |
224 | For more information see the
225 | [libVLC](https://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc.html) documentation.
226 |
227 | ## License
228 |
229 | Copyright (c) 2018 Adrian-George Bostan.
230 |
231 | This project is licensed under the [MIT license](https://opensource.org/licenses/MIT).
232 | See [LICENSE](LICENSE) for more details.
233 |
--------------------------------------------------------------------------------
/v2/av.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | // #include
6 | import "C"
7 | import (
8 | "unsafe"
9 | )
10 |
11 | // StereoMode defines stereo modes which can be used by an audio output.
12 | type StereoMode int
13 |
14 | // Stereo modes.
15 | const (
16 | StereoModeError StereoMode = iota - 1
17 | StereoModeNotSet
18 | StereoModeNormal
19 | StereoModeReverse
20 | StereoModeLeft
21 | StereoModeRight
22 | StereoModeDolbySurround
23 | )
24 |
25 | // Position defines locations of entities relative to a container.
26 | type Position int
27 |
28 | // Positions.
29 | const (
30 | PositionDisable Position = iota - 1
31 | PositionCenter
32 | PositionLeft
33 | PositionRight
34 | PositionTop
35 | PositionTopLeft
36 | PositionTopRight
37 | PositionBottom
38 | PositionBottomLeft
39 | PositionBottomRight
40 | )
41 |
42 | // DeinterlaceMode defines deinterlacing modes which can be used when
43 | // rendering videos.
44 | //
45 | // For more information see https://wiki.videolan.org/Deinterlacing.
46 | type DeinterlaceMode string
47 |
48 | // Deinterlace modes.
49 | const (
50 | DeinterlaceModeDisable DeinterlaceMode = ""
51 | DeinterlaceModeDiscard DeinterlaceMode = "discard"
52 | DeinterlaceModeBlend DeinterlaceMode = "blend"
53 | DeinterlaceModeMean DeinterlaceMode = "mean"
54 | DeinterlaceModeBob DeinterlaceMode = "bob"
55 | DeinterlaceModeLinear DeinterlaceMode = "linear"
56 | DeinterlaceModeX DeinterlaceMode = "x"
57 | DeinterlaceModeYadif DeinterlaceMode = "yadif"
58 | DeinterlaceModeYadif2x DeinterlaceMode = "yadif2x"
59 | DeinterlaceModePhosphor DeinterlaceMode = "phosphor"
60 | DeinterlaceModeIVTC DeinterlaceMode = "ivtc"
61 | )
62 |
63 | // AudioOutput contains information regarding an audio output.
64 | type AudioOutput struct {
65 | Name string
66 | Description string
67 | }
68 |
69 | // AudioOutputList returns the list of available audio outputs.
70 | // In order to change the audio output of a media player instance,
71 | // use the Player.SetAudioOutput method.
72 | func AudioOutputList() ([]*AudioOutput, error) {
73 | if err := inst.assertInit(); err != nil {
74 | return nil, err
75 | }
76 |
77 | cOutputs := C.libvlc_audio_output_list_get(inst.handle)
78 | if cOutputs == nil {
79 | return nil, errOrDefault(getError(), ErrAudioOutputListMissing)
80 | }
81 |
82 | var outputs []*AudioOutput
83 | for n := cOutputs; n != nil; n = n.p_next {
84 | outputs = append(outputs, &AudioOutput{
85 | Name: C.GoString(n.psz_name),
86 | Description: C.GoString(n.psz_description),
87 | })
88 | }
89 |
90 | C.libvlc_audio_output_list_release(cOutputs)
91 | return outputs, nil
92 | }
93 |
94 | // AudioOutputDevice contains information regarding an audio output device.
95 | type AudioOutputDevice struct {
96 | Name string
97 | Description string
98 | }
99 |
100 | // ListAudioOutputDevices returns the list of available devices for the
101 | // specified audio output. Use the AudioOutputList method in order to obtain
102 | // the list of available audio outputs. In order to change the audio output
103 | // device of a media player instance, use Player.SetAudioOutputDevice.
104 | //
105 | // NOTE: Not all audio outputs support this. An empty list of devices does
106 | // not imply that the specified audio output does not work.
107 | // Some audio output devices in the list might not work in some circumstances.
108 | // By default, it is recommended to not specify any explicit audio device.
109 | func ListAudioOutputDevices(output string) ([]*AudioOutputDevice, error) {
110 | if err := inst.assertInit(); err != nil {
111 | return nil, err
112 | }
113 |
114 | cOutput := C.CString(output)
115 | defer C.free(unsafe.Pointer(cOutput))
116 | return parseAudioOutputDeviceList(C.libvlc_audio_output_device_list_get(inst.handle, cOutput))
117 | }
118 |
119 | func parseAudioOutputDeviceList(cDevices *C.libvlc_audio_output_device_t) ([]*AudioOutputDevice, error) {
120 | if cDevices == nil {
121 | return nil, errOrDefault(getError(), ErrAudioOutputDeviceListMissing)
122 | }
123 |
124 | var devices []*AudioOutputDevice
125 | for n := cDevices; n != nil; n = n.p_next {
126 | devices = append(devices, &AudioOutputDevice{
127 | Name: C.GoString(n.psz_device),
128 | Description: C.GoString(n.psz_description),
129 | })
130 | }
131 |
132 | C.libvlc_audio_output_device_list_release(cDevices)
133 | return devices, nil
134 | }
135 |
136 | // ModuleDescription contains information about a libVLC module.
137 | type ModuleDescription struct {
138 | Name string
139 | ShortName string
140 | LongName string
141 | Help string
142 | }
143 |
144 | // ListAudioFilters returns the list of available audio filters.
145 | func ListAudioFilters() ([]*ModuleDescription, error) {
146 | if err := inst.assertInit(); err != nil {
147 | return nil, err
148 | }
149 |
150 | return parseFilterList(C.libvlc_audio_filter_list_get(inst.handle))
151 | }
152 |
153 | // ListVideoFilters returns the list of available video filters.
154 | func ListVideoFilters() ([]*ModuleDescription, error) {
155 | if err := inst.assertInit(); err != nil {
156 | return nil, err
157 | }
158 |
159 | return parseFilterList(C.libvlc_video_filter_list_get(inst.handle))
160 | }
161 |
162 | func parseFilterList(cFilters *C.libvlc_module_description_t) ([]*ModuleDescription, error) {
163 | if cFilters == nil {
164 | return nil, errOrDefault(getError(), ErrFilterListMissing)
165 | }
166 |
167 | var filters []*ModuleDescription
168 | for n := cFilters; n != nil; n = n.p_next {
169 | filters = append(filters, &ModuleDescription{
170 | Name: C.GoString(n.psz_name),
171 | ShortName: C.GoString(n.psz_shortname),
172 | LongName: C.GoString(n.psz_longname),
173 | Help: C.GoString(n.psz_help),
174 | })
175 | }
176 |
177 | C.libvlc_module_description_list_release(cFilters)
178 | return filters, nil
179 | }
180 |
--------------------------------------------------------------------------------
/v2/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package vlc provides Golang bindings for libVLC version 2.X.
3 |
4 | # Usage
5 |
6 | Initialization
7 |
8 | // Initialize libVLC. Additional command line arguments can be passed in
9 | // to libVLC by specifying them in the Init function.
10 | if err := vlc.Init("--no-video", "--quiet"); err != nil {
11 | log.Fatal(err)
12 | }
13 | defer vlc.Release()
14 |
15 | Player example
16 |
17 | // Create a new player.
18 | player, err := vlc.NewPlayer()
19 | if err != nil {
20 | log.Fatal(err)
21 | }
22 | defer func() {
23 | player.Stop()
24 | player.Release()
25 | }()
26 |
27 | // Add a media file from path or from URL.
28 | // Set player media from path:
29 | // media, err := player.LoadMediaFromPath("localpath/test.mp4")
30 | // Set player media from URL:
31 | media, err := player.LoadMediaFromURL("http://stream-uk1.radioparadise.com/mp3-32")
32 | if err != nil {
33 | log.Fatal(err)
34 | }
35 | defer media.Release()
36 |
37 | // Retrieve player event manager.
38 | manager, err := player.EventManager()
39 | if err != nil {
40 | log.Fatal(err)
41 | }
42 |
43 | // Register the media end reached event with the event manager.
44 | quit := make(chan struct{})
45 | eventCallback := func(event vlc.Event, userData interface{}) {
46 | close(quit)
47 | }
48 |
49 | eventID, err := manager.Attach(vlc.MediaPlayerEndReached, eventCallback, nil)
50 | if err != nil {
51 | log.Fatal(err)
52 | }
53 | defer manager.Detach(eventID)
54 |
55 | // Start playing the media.
56 | if err = player.Play(); err != nil {
57 | log.Fatal(err)
58 | }
59 |
60 | <-quit
61 |
62 | List player example
63 |
64 | // Create a new list player.
65 | player, err := vlc.NewListPlayer()
66 | if err != nil {
67 | log.Fatal(err)
68 | }
69 | defer func() {
70 | player.Stop()
71 | player.Release()
72 | }()
73 |
74 | // Create a new media list.
75 | list, err := vlc.NewMediaList()
76 | if err != nil {
77 | log.Fatal(err)
78 | }
79 | defer list.Release()
80 |
81 | err = list.AddMediaFromPath("localpath/test1.mp3")
82 | if err != nil {
83 | log.Fatal(err)
84 | }
85 |
86 | err = list.AddMediaFromURL("http://stream-uk1.radioparadise.com/mp3-32")
87 | if err != nil {
88 | log.Fatal(err)
89 | }
90 |
91 | // Set player media list.
92 | if err = player.SetMediaList(list); err != nil {
93 | log.Fatal(err)
94 | }
95 |
96 | // Media files can be added to the list after the list has been added
97 | // to the player. The player will play these files as well.
98 | err = list.AddMediaFromPath("localpath/test2.mp3")
99 | if err != nil {
100 | log.Fatal(err)
101 | }
102 |
103 | // Retrieve player event manager.
104 | manager, err := player.EventManager()
105 | if err != nil {
106 | log.Fatal(err)
107 | }
108 |
109 | // Register the media end reached event with the event manager.
110 | quit := make(chan struct{})
111 | eventCallback := func(event vlc.Event, userData interface{}) {
112 | close(quit)
113 | }
114 |
115 | eventID, err := manager.Attach(vlc.MediaListPlayerPlayed, eventCallback, nil)
116 | if err != nil {
117 | log.Fatal(err)
118 | }
119 | defer manager.Detach(eventID)
120 |
121 | // Start playing the media list.
122 | if err = player.Play(); err != nil {
123 | log.Fatal(err)
124 | }
125 |
126 | <-quit
127 |
128 | Handling multiple events example
129 |
130 | // Create a new player.
131 | player, err := vlc.NewPlayer()
132 | if err != nil {
133 | log.Fatal(err)
134 | }
135 | defer func() {
136 | player.Stop()
137 | player.Release()
138 | }()
139 |
140 | // Add a media file from path or from URL.
141 | // Set player media from path:
142 | // media, err := player.LoadMediaFromPath("test.mp3")
143 | // Set player media from URL:
144 | media, err := player.LoadMediaFromURL("http://stream-uk1.radioparadise.com/mp3-32")
145 | if err != nil {
146 | log.Fatal(err)
147 | }
148 | defer media.Release()
149 |
150 | // Retrieve player event manager.
151 | manager, err := player.EventManager()
152 | if err != nil {
153 | log.Fatal(err)
154 | }
155 |
156 | // Create event handler.
157 | quit := make(chan struct{})
158 | eventCallback := func(event vlc.Event, userData interface{}) {
159 | switch event {
160 | case vlc.MediaPlayerEndReached:
161 | log.Println("Player end reached")
162 | close(quit)
163 | case vlc.MediaPlayerTimeChanged:
164 | media, err := player.Media()
165 | if err != nil {
166 | log.Println(err)
167 | break
168 | }
169 |
170 | stats, err := media.Stats()
171 | if err != nil {
172 | log.Println(err)
173 | break
174 | }
175 |
176 | log.Printf("%+v\n", stats)
177 | }
178 | }
179 |
180 | // Register events with the event manager.
181 | events := []vlc.Event{
182 | vlc.MediaPlayerTimeChanged,
183 | vlc.MediaPlayerEndReached,
184 | }
185 |
186 | var eventIDs []vlc.EventID
187 | for _, event := range events {
188 | eventID, err := manager.Attach(event, eventCallback, nil)
189 | if err != nil {
190 | log.Fatal(err)
191 | }
192 |
193 | eventIDs = append(eventIDs, eventID)
194 | }
195 |
196 | // De-register attached events.
197 | defer func() {
198 | for _, eventID := range eventIDs {
199 | manager.Detach(eventID)
200 | }
201 | }()
202 |
203 | // Start playing the media.
204 | if err = player.Play(); err != nil {
205 | log.Fatal(err)
206 | }
207 |
208 | <-quit
209 | */
210 | package vlc
211 |
--------------------------------------------------------------------------------
/v2/equalizer.go:
--------------------------------------------------------------------------------
1 | //go:build !legacy
2 | // +build !legacy
3 |
4 | package vlc
5 |
6 | // #cgo LDFLAGS: -lvlc
7 | // #include
8 | import "C"
9 |
10 | // EqualizerPresetCount returns the number of available equalizer presets.
11 | func EqualizerPresetCount() uint {
12 | return uint(C.libvlc_audio_equalizer_get_preset_count())
13 | }
14 |
15 | // EqualizerPresetName returns the name of the equalizer preset with the
16 | // specified index. The index must be a number greater than or equal to 0
17 | // and less than EqualizerPresetCount(). The function returns an empty string
18 | // for invalid indices.
19 | func EqualizerPresetName(index uint) string {
20 | return C.GoString(C.libvlc_audio_equalizer_get_preset_name(C.uint(index)))
21 | }
22 |
23 | // EqualizerPresetNames returns the names of all available equalizer presets,
24 | // sorted by their indices in ascending order.
25 | func EqualizerPresetNames() []string {
26 | // Get preset count.
27 | count := EqualizerPresetCount()
28 |
29 | // Get preset names.
30 | names := make([]string, 0, count)
31 | for i := uint(0); i < count; i++ {
32 | names = append(names, EqualizerPresetName(i))
33 | }
34 |
35 | return names
36 | }
37 |
38 | // EqualizerBandCount returns the number of distinct equalizer frequency bands.
39 | func EqualizerBandCount() uint {
40 | return uint(C.libvlc_audio_equalizer_get_band_count())
41 | }
42 |
43 | // EqualizerBandFrequency returns the frequency of the equalizer band with the
44 | // specified index. The index must be a number greater than or equal to 0 and
45 | // less than EqualizerBandCount(). The function returns -1 for invalid indices.
46 | func EqualizerBandFrequency(index uint) float64 {
47 | return float64(C.libvlc_audio_equalizer_get_band_frequency(C.uint(index)))
48 | }
49 |
50 | // EqualizerBandFrequencies returns the frequencies of all available equalizer
51 | // bands, sorted by their indices in ascending order.
52 | func EqualizerBandFrequencies() []float64 {
53 | // Get band count.
54 | count := EqualizerBandCount()
55 |
56 | // Get band frequencies.
57 | frequencies := make([]float64, 0, count)
58 | for i := uint(0); i < count; i++ {
59 | frequencies = append(frequencies, EqualizerBandFrequency(i))
60 | }
61 |
62 | return frequencies
63 | }
64 |
65 | // Equalizer represents an audio equalizer. Use Player.SetEqualizer to assign
66 | // the equalizer to a player instance.
67 | type Equalizer struct {
68 | equalizer *C.libvlc_equalizer_t
69 | }
70 |
71 | // NewEqualizer returns a new equalizer with all frequency values set to zero.
72 | func NewEqualizer() (*Equalizer, error) {
73 | equalizer := C.libvlc_audio_equalizer_new()
74 | if equalizer == nil {
75 | return nil, errOrDefault(getError(), ErrEqualizerCreate)
76 | }
77 |
78 | return &Equalizer{equalizer: equalizer}, nil
79 | }
80 |
81 | // NewEqualizerFromPreset returns a new equalizer with the frequency values
82 | // copied from the preset with the specified index. The index must be a number
83 | // greater than or equal to 0 and less than EqualizerPresetCount().
84 | func NewEqualizerFromPreset(index uint) (*Equalizer, error) {
85 | equalizer := C.libvlc_audio_equalizer_new_from_preset(C.uint(index))
86 | if equalizer == nil {
87 | return nil, errOrDefault(getError(), ErrEqualizerCreate)
88 | }
89 |
90 | return &Equalizer{equalizer: equalizer}, nil
91 | }
92 |
93 | // Release destroys the equalizer instance.
94 | func (e *Equalizer) Release() error {
95 | if err := e.assertInit(); err != nil {
96 | return nil
97 | }
98 |
99 | C.libvlc_audio_equalizer_release(e.equalizer)
100 | e.equalizer = nil
101 |
102 | return nil
103 | }
104 |
105 | // PreampValue returns the pre-amplification value of the equalizer in Hz.
106 | func (e *Equalizer) PreampValue() (float64, error) {
107 | if err := e.assertInit(); err != nil {
108 | return 0, err
109 | }
110 |
111 | value := C.libvlc_audio_equalizer_get_preamp(e.equalizer)
112 | return float64(value), nil
113 | }
114 |
115 | // SetPreampValue sets the pre-amplification value of the equalizer.
116 | // The specified amplification value is clamped to the [-20.0, 20.0] Hz range.
117 | func (e *Equalizer) SetPreampValue(value float64) error {
118 | if err := e.assertInit(); err != nil {
119 | return err
120 | }
121 |
122 | if C.libvlc_audio_equalizer_set_preamp(e.equalizer, C.float(value)) != 0 {
123 | return errOrDefault(getError(), ErrEqualizerAmpValueSet)
124 | }
125 |
126 | return nil
127 | }
128 |
129 | // AmpValueAtIndex returns the amplification value for the equalizer frequency
130 | // band with the specified index, in Hz. The index must be a number greater
131 | // than or equal to 0 and less than EqualizerBandCount().
132 | func (e *Equalizer) AmpValueAtIndex(index uint) (float64, error) {
133 | if err := e.assertInit(); err != nil {
134 | return 0, err
135 | }
136 |
137 | value := C.libvlc_audio_equalizer_get_amp_at_index(e.equalizer, C.uint(index))
138 | return float64(value), nil
139 | }
140 |
141 | // SetAmpValueAtIndex sets the amplification value for the equalizer frequency
142 | // band with the specified index, in Hz. The index must be a number greater
143 | // than or equal to 0 and less than EqualizerBandCount().
144 | func (e *Equalizer) SetAmpValueAtIndex(value float64, index uint) error {
145 | if err := e.assertInit(); err != nil {
146 | return err
147 | }
148 |
149 | if C.libvlc_audio_equalizer_set_amp_at_index(e.equalizer, C.float(value), C.uint(index)) != 0 {
150 | return errOrDefault(getError(), ErrEqualizerAmpValueSet)
151 | }
152 |
153 | return nil
154 | }
155 |
156 | func (e *Equalizer) assertInit() error {
157 | if e == nil || e.equalizer == nil {
158 | return ErrEqualizerNotInitialized
159 | }
160 |
161 | return nil
162 | }
163 |
--------------------------------------------------------------------------------
/v2/errors.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | import "errors"
4 |
5 | // Generic errors.
6 | var (
7 | ErrInvalid = errors.New("the provided value is not valid")
8 | )
9 |
10 | // Module errors.
11 | var (
12 | ErrModuleInitialize = errors.New("could not initialize module")
13 | ErrModuleNotInitialized = errors.New("module not initialized")
14 | ErrUserInterfaceStart = errors.New("could not start user interface")
15 | )
16 |
17 | // Player errors.
18 | var (
19 | ErrPlayerCreate = errors.New("could not create player")
20 | ErrPlayerNotInitialized = errors.New("player is not initialized")
21 | ErrPlayerPlay = errors.New("cannot play the requested media")
22 | ErrPlayerSetVolume = errors.New("could not set player volume")
23 | ErrPlayerSetEqualizer = errors.New("could not set player equalizer")
24 | )
25 |
26 | // List player errors.
27 | var (
28 | ErrListPlayerCreate = errors.New("could not create list player")
29 | ErrListPlayerNotInitialized = errors.New("list player is not initialized")
30 | )
31 |
32 | // Media errors.
33 | var (
34 | ErrMediaCreate = errors.New("could not create media")
35 | ErrMediaNotFound = errors.New("could not find media")
36 | ErrMediaNotInitialized = errors.New("media is not initialized")
37 | ErrMediaListCreate = errors.New("could not create media list")
38 | ErrMediaListNotFound = errors.New("could not find media list")
39 | ErrMediaListNotInitialized = errors.New("media list is not initialized")
40 | ErrMediaListReadOnly = errors.New("media list is read-only")
41 | ErrMediaListActionFailed = errors.New("could not perform media list action")
42 | ErrMissingMediaStats = errors.New("could not get media statistics")
43 | ErrInvalidMediaStats = errors.New("invalid media statistics")
44 | ErrMissingMediaLocation = errors.New("could not get media location")
45 | ErrMissingMediaDimensions = errors.New("could not get media dimensions")
46 | ErrMediaMetaSave = errors.New("could not save media metadata")
47 | ErrMediaNotParsed = errors.New("media is not parsed")
48 | )
49 |
50 | // Media track errors.
51 | var (
52 | ErrMediaTrackNotInitialized = errors.New("media track is not initialized")
53 | ErrMediaTrackNotFound = errors.New("could not find media track")
54 | ErrInvalidMediaTrack = errors.New("invalid media track")
55 | )
56 |
57 | // Event manager errors.
58 | var (
59 | ErrMissingEventManager = errors.New("could not get event manager instance")
60 | ErrInvalidEventCallback = errors.New("invalid event callback")
61 | )
62 |
63 | // Audio/Video errors.
64 | var (
65 | ErrAudioOutputListMissing = errors.New("could not get audio output list")
66 | ErrAudioOutputSet = errors.New("could not set audio output")
67 | ErrAudioOutputDeviceListMissing = errors.New("could not get audio output device list")
68 | ErrFilterListMissing = errors.New("could not get filter list")
69 | ErrStereoModeSet = errors.New("could not set stereo mode")
70 | ErrVideoSnapshot = errors.New("could not take video snapshot")
71 | ErrCursorPositionMissing = errors.New("could not get cursor position")
72 | )
73 |
74 | // Equalizer errors.
75 | var (
76 | ErrEqualizerCreate = errors.New("could not create equalizer")
77 | ErrEqualizerNotInitialized = errors.New("equalizer is not initialized")
78 | ErrEqualizerAmpValueSet = errors.New("could not set equalizer amplification value")
79 | ErrEventAttach = errors.New("could not attach event")
80 | )
81 |
--------------------------------------------------------------------------------
/v2/event_manager.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | /*
4 | #cgo LDFLAGS: -lvlc
5 | #include
6 |
7 | typedef const libvlc_event_t constev;
8 | extern void eventDispatch(constev*, void*);
9 |
10 | static inline int eventAttach(libvlc_event_manager_t* em, libvlc_event_type_t et, unsigned long userData) {
11 | return libvlc_event_attach(em, et, eventDispatch, (void*)userData);
12 | }
13 | static inline int eventDetach(libvlc_event_manager_t* em, libvlc_event_type_t et, unsigned long userData) {
14 | libvlc_event_detach(em, et, eventDispatch, (void*)userData);
15 | }
16 | */
17 | import "C"
18 |
19 | import (
20 | "unsafe"
21 | )
22 |
23 | // EventManager wraps a libvlc event manager.
24 | type EventManager struct {
25 | manager *C.libvlc_event_manager_t
26 | }
27 |
28 | // newEventManager returns a new event manager instance.
29 | func newEventManager(manager *C.libvlc_event_manager_t) *EventManager {
30 | return &EventManager{
31 | manager: manager,
32 | }
33 | }
34 |
35 | // Attach registers a callback for an event notification.
36 | func (em *EventManager) Attach(event Event, callback EventCallback, userData interface{}) (EventID, error) {
37 | return em.attach(event, callback, nil, userData)
38 | }
39 |
40 | // attach registers callbacks for an event notification.
41 | func (em *EventManager) attach(event Event, externalCallback EventCallback,
42 | internalCallback internalEventCallback, userData interface{}) (EventID, error) {
43 | if err := inst.assertInit(); err != nil {
44 | return 0, err
45 | }
46 | if externalCallback == nil && internalCallback == nil {
47 | return 0, ErrInvalidEventCallback
48 | }
49 |
50 | id := inst.events.add(event, externalCallback, internalCallback, userData)
51 | if C.eventAttach(em.manager, C.libvlc_event_type_t(event), C.ulong(id)) != 0 {
52 | return 0, errOrDefault(getError(), ErrEventAttach)
53 | }
54 |
55 | return id, nil
56 | }
57 |
58 | // Detach unregisters the specified event notification.
59 | func (em *EventManager) Detach(eventIDs ...EventID) {
60 | if err := inst.assertInit(); err != nil {
61 | return
62 | }
63 |
64 | for _, eventID := range eventIDs {
65 | ctx, ok := inst.events.get(eventID)
66 | if !ok {
67 | continue
68 | }
69 |
70 | inst.events.remove(eventID)
71 | C.eventDetach(em.manager, C.libvlc_event_type_t(ctx.event), C.ulong(eventID))
72 | }
73 | }
74 |
75 | //export eventDispatch
76 | func eventDispatch(event *C.constev, userData unsafe.Pointer) {
77 | if err := inst.assertInit(); err != nil {
78 | return
79 | }
80 |
81 | ctx, ok := inst.events.get(EventID(uintptr(userData)))
82 | if !ok {
83 | return
84 | }
85 |
86 | // Execute external callback.
87 | if ctx.externalCallback != nil {
88 | ctx.externalCallback(ctx.event, ctx.userData)
89 | }
90 |
91 | // Execute internal callback.
92 | if ctx.internalCallback != nil {
93 | ctx.internalCallback(event, ctx.userData)
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/v2/event_registry.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | import "C"
6 | import "sync"
7 |
8 | // EventID uniquely identifies a registered event.
9 | type EventID uint64
10 |
11 | // EventCallback represents an event notification callback function.
12 | type EventCallback func(Event, interface{})
13 |
14 | type internalEventCallback func(*C.libvlc_event_t, interface{})
15 |
16 | type eventContext struct {
17 | event Event
18 | externalCallback EventCallback
19 | internalCallback internalEventCallback
20 | userData interface{}
21 | }
22 |
23 | type eventRegistry struct {
24 | sync.RWMutex
25 |
26 | contexts map[EventID]*eventContext
27 | sequence EventID
28 | }
29 |
30 | func newEventRegistry() *eventRegistry {
31 | return &eventRegistry{
32 | contexts: map[EventID]*eventContext{},
33 | }
34 | }
35 |
36 | func (er *eventRegistry) get(id EventID) (*eventContext, bool) {
37 | if id == 0 {
38 | return nil, false
39 | }
40 |
41 | er.RLock()
42 | ctx, ok := er.contexts[id]
43 | er.RUnlock()
44 |
45 | return ctx, ok
46 | }
47 |
48 | func (er *eventRegistry) add(event Event, externalCallback EventCallback,
49 | internalCallback internalEventCallback, userData interface{}) EventID {
50 | er.Lock()
51 |
52 | er.sequence++
53 | id := er.sequence
54 |
55 | er.contexts[id] = &eventContext{
56 | event: event,
57 | externalCallback: externalCallback,
58 | internalCallback: internalCallback,
59 | userData: userData,
60 | }
61 |
62 | er.Unlock()
63 | return id
64 | }
65 |
66 | func (er *eventRegistry) remove(id EventID) {
67 | if id == 0 {
68 | return
69 | }
70 |
71 | er.Lock()
72 | delete(er.contexts, id)
73 | er.Unlock()
74 | }
75 |
--------------------------------------------------------------------------------
/v2/events.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // Event represents an event that can occur inside libvlc.
4 | type Event int
5 |
6 | // Media events.
7 | const (
8 | // MediaMetaChanged is triggered when the metadata of a media item changes.
9 | MediaMetaChanged Event = iota
10 |
11 | // MediaSubItemAdded is triggered when a Subitem is added to a media item.
12 | MediaSubItemAdded
13 |
14 | // MediaDurationChanged is triggered when the duration
15 | // of a media item changes.
16 | MediaDurationChanged
17 |
18 | // MediaParsedChanged is triggered when the parsing state
19 | // of a media item changes.
20 | MediaParsedChanged
21 |
22 | // MediaFreed is triggered when a media item is freed.
23 | MediaFreed
24 |
25 | // MediaStateChanged is triggered when the state of the media item changes.
26 | MediaStateChanged
27 |
28 | // MediaSubItemTreeAdded is triggered when a Subitem tree is
29 | // added to a media item.
30 | MediaSubItemTreeAdded
31 |
32 | // MediaThumbnailGenerated is triggered when a thumbnail
33 | // generation is completed.
34 | MediaThumbnailGenerated
35 | )
36 |
37 | // Player events.
38 | const (
39 | MediaPlayerMediaChanged Event = 0x100 + iota
40 | MediaPlayerNothingSpecial
41 | MediaPlayerOpening
42 | MediaPlayerBuffering
43 | MediaPlayerPlaying
44 | MediaPlayerPaused
45 | MediaPlayerStopped
46 | MediaPlayerForward
47 | MediaPlayerBackward
48 | MediaPlayerEndReached
49 | MediaPlayerEncounteredError
50 | MediaPlayerTimeChanged
51 | MediaPlayerPositionChanged
52 | MediaPlayerSeekableChanged
53 | MediaPlayerPausableChanged
54 | MediaPlayerTitleChanged
55 | MediaPlayerSnapshotTaken
56 | MediaPlayerLengthChanged
57 | MediaPlayerVout
58 | MediaPlayerScrambledChanged
59 | MediaPlayerESAdded
60 | MediaPlayerESDeleted
61 | MediaPlayerESSelected
62 | MediaPlayerCorked
63 | MediaPlayerUncorked
64 | MediaPlayerMuted
65 | MediaPlayerUnmuted
66 | MediaPlayerAudioVolume
67 | MediaPlayerAudioDevice
68 | MediaPlayerChapterChanged
69 | )
70 |
71 | // Media list events.
72 | const (
73 | // MediaListItemAdded is triggered when a media item is added to a media list.
74 | MediaListItemAdded Event = 0x200 + iota
75 |
76 | // MediaListWillAddItem is triggered when a media item is about to get
77 | // added to a media list.
78 | MediaListWillAddItem
79 |
80 | // MediaListItemDeleted is triggered when a media item is deleted
81 | // from a media list.
82 | MediaListItemDeleted
83 |
84 | // MediaListWillDeleteItem is triggered when a media item is about to get
85 | // deleted from a media list.
86 | MediaListWillDeleteItem
87 |
88 | // MediaListEndReached is triggered when a media list has reached the end.
89 | MediaListEndReached
90 | )
91 |
92 | // Deprecated events.
93 | const (
94 | MediaListViewItemAdded = 0x300 + iota
95 | MediaListViewWillAddItem
96 | MediaListViewItemDeleted
97 | MediaListViewWillDeleteItem
98 | )
99 |
100 | const (
101 | // MediaListPlayerPlayed is triggered when playback of the media list
102 | // of the list player has ended.
103 | MediaListPlayerPlayed = 0x400 + iota
104 |
105 | // MediaListPlayerNextItemSet is triggered when the current item
106 | // of a media list player has changed to a different item.
107 | MediaListPlayerNextItemSet
108 |
109 | // MediaListPlayerStopped is triggered when playback
110 | // of a media list player is stopped programmatically.
111 | MediaListPlayerStopped
112 | )
113 |
114 | // Deprecated events.
115 | const (
116 | MediaDiscovererStarted Event = 0x500 + iota
117 | MediaDiscovererEnded
118 | )
119 |
120 | // Renderer events.
121 | const (
122 | // RendererDiscovererItemAdded is triggered when a new renderer item is
123 | // found by a renderer discoverer. The renderer item is valid until deleted.
124 | RendererDiscovererItemAdded Event = 0x502 + iota
125 |
126 | // RendererDiscovererItemDeleted is triggered when a previously discovered
127 | // renderer item was deleted by a renderer discoverer. The renderer item
128 | // is no longer valid.
129 | RendererDiscovererItemDeleted
130 | )
131 |
132 | // VideoLAN Manager events.
133 | const (
134 | VlmMediaAdded Event = 0x600 + iota
135 | VlmMediaRemoved
136 | VlmMediaChanged
137 | VlmMediaInstanceStarted
138 | VlmMediaInstanceStopped
139 | VlmMediaInstanceStatusInit
140 | VlmMediaInstanceStatusOpening
141 | VlmMediaInstanceStatusPlaying
142 | VlmMediaInstanceStatusPause
143 | VlmMediaInstanceStatusEnd
144 | VlmMediaInstanceStatusError
145 | )
146 |
--------------------------------------------------------------------------------
/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/adrg/libvlc-go/v2
2 |
3 | go 1.13
4 |
--------------------------------------------------------------------------------
/v2/list_player.go:
--------------------------------------------------------------------------------
1 | //go:build !legacy
2 | // +build !legacy
3 |
4 | package vlc
5 |
6 | // #cgo LDFLAGS: -lvlc
7 | // #include
8 | // #include
9 | import "C"
10 |
11 | // PlaybackMode defines playback modes for a media list.
12 | type PlaybackMode uint
13 |
14 | // Playback modes.
15 | const (
16 | Default PlaybackMode = iota
17 | Loop
18 | Repeat
19 | )
20 |
21 | // Validate checks if the playback mode valid.
22 | func (pm PlaybackMode) Validate() error {
23 | if pm > Repeat {
24 | return ErrInvalid
25 | }
26 |
27 | return nil
28 | }
29 |
30 | // ListPlayer is an enhanced media player used to play media lists.
31 | type ListPlayer struct {
32 | player *C.libvlc_media_list_player_t
33 | list *MediaList
34 | }
35 |
36 | // NewListPlayer creates a new list player instance.
37 | func NewListPlayer() (*ListPlayer, error) {
38 | if err := inst.assertInit(); err != nil {
39 | return nil, err
40 | }
41 |
42 | player := C.libvlc_media_list_player_new(inst.handle)
43 | if player == nil {
44 | return nil, errOrDefault(getError(), ErrListPlayerCreate)
45 | }
46 |
47 | return &ListPlayer{player: player}, nil
48 | }
49 |
50 | // Release destroys the list player instance.
51 | func (lp *ListPlayer) Release() error {
52 | if err := lp.assertInit(); err != nil {
53 | return nil
54 | }
55 |
56 | C.libvlc_media_list_player_release(lp.player)
57 | lp.player = nil
58 |
59 | return nil
60 | }
61 |
62 | // Player returns the underlying Player instance of the list player.
63 | func (lp *ListPlayer) Player() (*Player, error) {
64 | if err := lp.assertInit(); err != nil {
65 | return nil, err
66 | }
67 |
68 | player := C.libvlc_media_list_player_get_media_player(lp.player)
69 | if player == nil {
70 | return nil, errOrDefault(getError(), ErrPlayerNotInitialized)
71 | }
72 |
73 | // This call will not release the player. Instead, it will decrement the
74 | // reference count increased by libvlc_media_list_player_get_media_player.
75 | C.libvlc_media_player_release(player)
76 |
77 | return &Player{player: player}, nil
78 | }
79 |
80 | // SetPlayer sets the underlying Player instance of the list player.
81 | func (lp *ListPlayer) SetPlayer(player *Player) error {
82 | if err := lp.assertInit(); err != nil {
83 | return err
84 | }
85 | if err := player.assertInit(); err != nil {
86 | return err
87 | }
88 |
89 | C.libvlc_media_list_player_set_media_player(lp.player, player.player)
90 | return nil
91 | }
92 |
93 | // Play plays the current media list.
94 | func (lp *ListPlayer) Play() error {
95 | if err := lp.assertInit(); err != nil {
96 | return err
97 | }
98 | if lp.IsPlaying() {
99 | return nil
100 | }
101 |
102 | C.libvlc_media_list_player_play(lp.player)
103 | return getError()
104 | }
105 |
106 | // PlayNext plays the next media in the current media list.
107 | func (lp *ListPlayer) PlayNext() error {
108 | if err := lp.assertInit(); err != nil {
109 | return err
110 | }
111 |
112 | if C.libvlc_media_list_player_next(lp.player) < 0 {
113 | return errOrDefault(getError(), ErrPlayerPlay)
114 | }
115 |
116 | return nil
117 | }
118 |
119 | // PlayPrevious plays the previous media in the current media list.
120 | func (lp *ListPlayer) PlayPrevious() error {
121 | if err := lp.assertInit(); err != nil {
122 | return err
123 | }
124 |
125 | if C.libvlc_media_list_player_previous(lp.player) < 0 {
126 | return errOrDefault(getError(), ErrPlayerPlay)
127 | }
128 |
129 | return nil
130 | }
131 |
132 | // PlayAtIndex plays the media at the specified index from the
133 | // current media list.
134 | func (lp *ListPlayer) PlayAtIndex(index uint) error {
135 | if err := lp.assertInit(); err != nil {
136 | return err
137 | }
138 |
139 | idx := C.int(index)
140 | if C.libvlc_media_list_player_play_item_at_index(lp.player, idx) < 0 {
141 | return errOrDefault(getError(), ErrPlayerPlay)
142 | }
143 |
144 | return nil
145 | }
146 |
147 | // PlayItem plays the specified media item. The item must be part of the
148 | // current media list of the player.
149 | func (lp *ListPlayer) PlayItem(m *Media) error {
150 | if err := lp.assertInit(); err != nil {
151 | return err
152 | }
153 | if err := m.assertInit(); err != nil {
154 | return err
155 | }
156 |
157 | if C.libvlc_media_list_player_play_item(lp.player, m.media) < 0 {
158 | return errOrDefault(getError(), ErrMediaNotFound)
159 | }
160 |
161 | return nil
162 | }
163 |
164 | // IsPlaying returns a boolean value specifying if the player is currently
165 | // playing.
166 | func (lp *ListPlayer) IsPlaying() bool {
167 | if err := lp.assertInit(); err != nil {
168 | return false
169 | }
170 |
171 | return C.libvlc_media_list_player_is_playing(lp.player) != 0
172 | }
173 |
174 | // Stop cancels the currently playing media list, if there is one.
175 | func (lp *ListPlayer) Stop() error {
176 | if err := lp.assertInit(); err != nil {
177 | return err
178 | }
179 |
180 | C.libvlc_media_list_player_stop(lp.player)
181 | return getError()
182 | }
183 |
184 | // TogglePause pauses/resumes the player.
185 | // Calling this method has no effect if there is no media.
186 | func (lp *ListPlayer) TogglePause() error {
187 | if err := lp.assertInit(); err != nil {
188 | return err
189 | }
190 |
191 | C.libvlc_media_list_player_pause(lp.player)
192 | return getError()
193 | }
194 |
195 | // SetPlaybackMode sets the player playback mode for the media list.
196 | // By default, it plays the media list once and then stops.
197 | func (lp *ListPlayer) SetPlaybackMode(mode PlaybackMode) error {
198 | if err := lp.assertInit(); err != nil {
199 | return err
200 | }
201 | if err := mode.Validate(); err != nil {
202 | return err
203 | }
204 |
205 | C.libvlc_media_list_player_set_playback_mode(
206 | lp.player,
207 | C.libvlc_playback_mode_t(mode),
208 | )
209 | return nil
210 | }
211 |
212 | // MediaState returns the state of the current media.
213 | func (lp *ListPlayer) MediaState() (MediaState, error) {
214 | if err := lp.assertInit(); err != nil {
215 | return MediaNothingSpecial, err
216 | }
217 |
218 | return MediaState(C.libvlc_media_list_player_get_state(lp.player)), nil
219 | }
220 |
221 | // MediaList returns the current media list of the player, if one exists.
222 | func (lp *ListPlayer) MediaList() *MediaList {
223 | return lp.list
224 | }
225 |
226 | // SetMediaList sets the media list to be played.
227 | func (lp *ListPlayer) SetMediaList(ml *MediaList) error {
228 | if err := lp.assertInit(); err != nil {
229 | return err
230 | }
231 | if err := ml.assertInit(); err != nil {
232 | return err
233 | }
234 |
235 | lp.list = ml
236 | C.libvlc_media_list_player_set_media_list(lp.player, ml.list)
237 |
238 | return nil
239 | }
240 |
241 | // EventManager returns the event manager responsible for the list player.
242 | func (lp *ListPlayer) EventManager() (*EventManager, error) {
243 | if err := lp.assertInit(); err != nil {
244 | return nil, err
245 | }
246 |
247 | manager := C.libvlc_media_list_player_event_manager(lp.player)
248 | if manager == nil {
249 | return nil, ErrMissingEventManager
250 | }
251 |
252 | return newEventManager(manager), nil
253 | }
254 |
255 | func (lp *ListPlayer) assertInit() error {
256 | if lp == nil || lp.player == nil {
257 | return ErrListPlayerNotInitialized
258 | }
259 |
260 | return nil
261 | }
262 |
--------------------------------------------------------------------------------
/v2/logo.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | /*
4 | #cgo LDFLAGS: -lvlc
5 | #include
6 | #include
7 | */
8 | import "C"
9 | import (
10 | "fmt"
11 | "image"
12 | "image/png"
13 | "os"
14 | "strings"
15 | "time"
16 | "unsafe"
17 | )
18 |
19 | // LogoFile represents a logo file which can be used as a media player's logo.
20 | // The logo of a player can also be composed of a series of alternating files.
21 | type LogoFile struct {
22 | path string
23 | displayDuration time.Duration
24 | opacity int
25 | }
26 |
27 | // NewLogoFileFromPath returns a new logo file with the specified path.
28 | // The file is displyed for the provided duration. If the specified display
29 | // duration is negative, the global display duration set on the logo the file
30 | // is applied to is used.
31 | // The provided opacity must be a value between 0 (transparent) and 255 (opaque).
32 | // If the specified opacity is negative, the global opacity set on the logo
33 | // the file is applied to is used.
34 | func NewLogoFileFromPath(path string, displayDuration time.Duration, opacity int) (*LogoFile, error) {
35 | if path == "" {
36 | return nil, ErrInvalid
37 | }
38 |
39 | return &LogoFile{
40 | path: path,
41 | displayDuration: displayDuration,
42 | opacity: opacity,
43 | }, nil
44 | }
45 |
46 | // NewLogoFileFromImage returns a new logo file with the specified image.
47 | // The file is displyed for the provided duration. If the specified display
48 | // duration is negative, the global display duration set on the logo the file
49 | // is applied to is used.
50 | // The provided opacity must be a value between 0 (transparent) and 255 (opaque).
51 | // If the specified opacity is negative, the global opacity set on the logo
52 | // the file is applied to is used.
53 | func NewLogoFileFromImage(img image.Image, displayDuration time.Duration, opacity int) (*LogoFile, error) {
54 | if img == nil {
55 | return nil, ErrInvalid
56 | }
57 |
58 | // Create temporary file.
59 | f, err := os.CreateTemp("", "logo_*.png")
60 | if err != nil {
61 | return nil, err
62 | }
63 |
64 | // Encode logo image to temporary file.
65 | if err := png.Encode(f, img); err != nil {
66 | return nil, err
67 | }
68 |
69 | // Close temporary file.
70 | path := f.Name()
71 | if err := f.Close(); err != nil {
72 | return nil, err
73 | }
74 |
75 | return NewLogoFileFromPath(path, displayDuration, opacity)
76 | }
77 |
78 | // Logo represents a logo that can be displayed over a media instance.
79 | //
80 | // For more information see https://wiki.videolan.org/Documentation:Modules/logo.
81 | type Logo struct {
82 | player *Player
83 | }
84 |
85 | func newLogo(player *Player) *Logo {
86 | return &Logo{
87 | player: player,
88 | }
89 | }
90 |
91 | // Enable enables or disables the logo. By default, the logo is disabled.
92 | func (l *Logo) Enable(enable bool) error {
93 | return l.setInt(C.libvlc_logo_enable, boolToInt(enable))
94 | }
95 |
96 | // SetFiles sets the sequence of files to be displayed for the logo.
97 | func (l *Logo) SetFiles(files ...*LogoFile) error {
98 | fileFmts := make([]string, 0, len(files))
99 | for _, file := range files {
100 | if file == nil {
101 | continue
102 | }
103 | fileFmt := file.path
104 | if file.displayDuration >= 0 {
105 | fileFmt = fmt.Sprintf("%s,%d", fileFmt, file.displayDuration.Milliseconds())
106 | }
107 | if file.opacity >= 0 {
108 | fileFmt = fmt.Sprintf("%s,%d", fileFmt, file.opacity)
109 | }
110 |
111 | fileFmts = append(fileFmts, fileFmt)
112 | }
113 |
114 | if len(fileFmts) == 0 {
115 | return nil
116 | }
117 |
118 | return l.setString(C.libvlc_logo_file, strings.Join(fileFmts, ";"))
119 | }
120 |
121 | // Position returns the position of the logo, relative to its container.
122 | // Default: vlc.PositionTopLeft.
123 | func (l *Logo) Position() (Position, error) {
124 | iVal, err := l.getInt(C.libvlc_logo_position)
125 | if err != nil {
126 | return PositionDisable, err
127 | }
128 |
129 | switch {
130 | case iVal >= 8:
131 | iVal -= 2
132 | case iVal >= 4:
133 | iVal--
134 | }
135 |
136 | if iVal < 0 {
137 | return PositionTopLeft, nil
138 | }
139 | return Position(iVal), nil
140 | }
141 |
142 | // SetPosition sets the position of the logo, relative to its container.
143 | func (l *Logo) SetPosition(position Position) error {
144 | switch {
145 | case position >= PositionBottom:
146 | position += 2
147 | case position >= PositionTop:
148 | position++
149 | }
150 |
151 | return l.setInt(C.libvlc_logo_position, int(position))
152 | }
153 |
154 | // X returns the X coordinate of the logo. The returned value is
155 | // relative to the position of the logo inside its container, i.e. the
156 | // position set using Logo.SetPosition method.
157 | // Default: 0.
158 | func (l *Logo) X() (int, error) {
159 | return l.getInt(C.libvlc_logo_x)
160 | }
161 |
162 | // SetX sets the X coordinate of the logo. The value is specified
163 | // relative to the position of the logo inside its container, i.e. the
164 | // position set using the `Logo.SetPosition` method.
165 | //
166 | // NOTE: the method has no effect if the position of the logo is set to
167 | // `vlc.PositionCenter`, `vlc.PositionTop` or `vlc.PositionBottom`.
168 | func (l *Logo) SetX(x int) error {
169 | return l.setInt(C.libvlc_logo_x, x)
170 | }
171 |
172 | // Y returns the Y coordinate of the logo. The returned value is
173 | // relative to the position of the logo inside its container, i.e. the
174 | // position set using the `Logo.SetPosition` method.
175 | // Default: 0.
176 | func (l *Logo) Y() (int, error) {
177 | return l.getInt(C.libvlc_logo_y)
178 | }
179 |
180 | // SetY sets the Y coordinate of the logo. The value is specified
181 | // relative to the position of the logo inside its container.
182 | //
183 | // NOTE: the method has no effect if the position of the logo is set to
184 | // `vlc.PositionCenter`, `vlc.PositionLeft` or `vlc.PositionRight`.
185 | func (l *Logo) SetY(y int) error {
186 | return l.setInt(C.libvlc_logo_y, y)
187 | }
188 |
189 | // Opacity returns the global opacity of the logo.
190 | // The returned opacity is a value between 0 (transparent) and 255 (opaque).
191 | // The global opacity can be overridden by each provided logo file.
192 | // Default: 255.
193 | func (l *Logo) Opacity() (int, error) {
194 | return l.getInt(C.libvlc_logo_opacity)
195 | }
196 |
197 | // SetOpacity sets the global opacity of the logo. If an opacity override is
198 | // not specified when setting the logo files, the global opacity is used. The
199 | // opacity is specified as an integer between 0 (transparent) and 255 (opaque).
200 | // The global opacity can be overridden by each provided logo file.
201 | func (l *Logo) SetOpacity(opacity int) error {
202 | return l.setInt(C.libvlc_logo_opacity, opacity)
203 | }
204 |
205 | // DisplayDuration returns the global duration for which a logo file
206 | // is set to be displayed before displaying the next one (if one is available).
207 | // The global display duration can be overridden by each provided logo file.
208 | // Default: 1s.
209 | func (l *Logo) DisplayDuration() (time.Duration, error) {
210 | iVal, err := l.getInt(C.libvlc_logo_delay)
211 | return time.Duration(iVal) * time.Millisecond, err
212 | }
213 |
214 | // SetDisplayDuration sets the duration for which to display a logo file
215 | // before displaying the next one (if one is available).
216 | // The global display duration can be overridden by each provided logo file.
217 | func (l *Logo) SetDisplayDuration(displayDuration time.Duration) error {
218 | return l.setInt(C.libvlc_logo_delay, int(displayDuration.Milliseconds()))
219 | }
220 |
221 | // RepeatCount returns the number of times the logo sequence is set
222 | // to be repeated.
223 | func (l *Logo) RepeatCount() (int, error) {
224 | return l.getInt(C.libvlc_logo_repeat)
225 | }
226 |
227 | // SetRepeatCount sets the number of times the logo sequence should repeat.
228 | // Pass in `-1` to repeat the logo sequence indefinitely, `0` to disable logo
229 | // sequence looping or a positive number to repeat the logo sequence a specific
230 | // number of times.
231 | // Default: -1 (the logo sequence is repeated indefinitely).
232 | func (l *Logo) SetRepeatCount(count int) error {
233 | if count > 0 {
234 | count++
235 | }
236 |
237 | return l.setInt(C.libvlc_logo_repeat, count)
238 | }
239 |
240 | func (l *Logo) getInt(option C.uint) (int, error) {
241 | if err := l.player.assertInit(); err != nil {
242 | return 0, err
243 | }
244 |
245 | return int(C.libvlc_video_get_logo_int(l.player.player, option)), nil
246 | }
247 |
248 | func (l *Logo) setInt(option C.uint, val int) error {
249 | if err := l.player.assertInit(); err != nil {
250 | return err
251 | }
252 |
253 | C.libvlc_video_set_logo_int(l.player.player, option, C.int(val))
254 | return nil
255 | }
256 |
257 | func (l *Logo) setString(option C.uint, val string) error {
258 | if err := l.player.assertInit(); err != nil {
259 | return err
260 | }
261 |
262 | cVal := C.CString(val)
263 | defer C.free(unsafe.Pointer(cVal))
264 |
265 | C.libvlc_video_set_logo_string(l.player.player, option, cVal)
266 | return nil
267 | }
268 |
--------------------------------------------------------------------------------
/v2/marquee.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | /*
4 | #cgo LDFLAGS: -lvlc
5 | #include
6 | #include
7 | */
8 | import "C"
9 | import (
10 | "image/color"
11 | "time"
12 | "unsafe"
13 | )
14 |
15 | // Marquee represents a marquee text than can be displayed over a media
16 | // instance, along with its visual properties.
17 | //
18 | // For more information see https://wiki.videolan.org/Documentation:Modules/marq.
19 | type Marquee struct {
20 | player *Player
21 | }
22 |
23 | func newMarquee(player *Player) *Marquee {
24 | return &Marquee{
25 | player: player,
26 | }
27 | }
28 |
29 | // Enable enables or disables the marquee. By default, the marquee is disabled.
30 | func (m *Marquee) Enable(enable bool) error {
31 | return m.setInt(C.libvlc_marquee_Enable, boolToInt(enable))
32 | }
33 |
34 | // Text returns the marquee text.
35 | // Default: "".
36 | func (m *Marquee) Text() (string, error) {
37 | return m.getString(C.libvlc_marquee_Text)
38 | }
39 |
40 | // SetText sets the marquee text.
41 | // The specified text can contain time format string sequences which are
42 | // converted to the requested time values at runtime. Most of the time
43 | // conversion specifiers supported by the `strftime` C function can be used.
44 | //
45 | // Common time format string sequences:
46 | // %Y = year, %m = month, %d = day, %H = hour, %M = minute, %S = second.
47 | // For more information see https://en.cppreference.com/w/c/chrono/strftime.
48 | func (m *Marquee) SetText(text string) error {
49 | return m.setString(C.libvlc_marquee_Text, text)
50 | }
51 |
52 | // Color returns the marquee text color.
53 | // Opacity information is included in the returned color.
54 | // Default: white.
55 | func (m *Marquee) Color() (color.Color, error) {
56 | // Get color.
57 | rgb, err := m.getInt(C.libvlc_marquee_Color)
58 | if err != nil {
59 | return nil, err
60 | }
61 |
62 | // Get alpha.
63 | alpha, err := m.getInt(C.libvlc_marquee_Opacity)
64 | if err != nil {
65 | return nil, err
66 | }
67 |
68 | return color.RGBA{
69 | R: uint8((rgb >> 16) & 0x0ff),
70 | G: uint8((rgb >> 8) & 0x0ff),
71 | B: uint8((rgb) & 0x0ff),
72 | A: uint8(alpha & 0x0ff),
73 | }, err
74 | }
75 |
76 | // SetColor sets the color of the marquee text. The opacity of the text
77 | // is also set, based on the alpha value of the color.
78 | func (m *Marquee) SetColor(color color.Color) error {
79 | r, g, b, a := color.RGBA()
80 |
81 | // Set color.
82 | rgb := int((((r >> 8) & 0x0ff) << 16) |
83 | (((g >> 8) & 0x0ff) << 8) |
84 | ((b >> 8) & 0x0ff))
85 | if err := m.setInt(C.libvlc_marquee_Color, rgb); err != nil {
86 | return err
87 | }
88 |
89 | // Set alpha.
90 | alpha := int((a >> 8) & 0x0ff)
91 | if err := m.setInt(C.libvlc_marquee_Opacity, alpha); err != nil {
92 | return err
93 | }
94 |
95 | return nil
96 | }
97 |
98 | // Opacity returns the opacity of the marquee text.
99 | // The returned opacity is a value between 0 (transparent) and 255 (opaque).
100 | // Default: 255.
101 | func (m *Marquee) Opacity() (int, error) {
102 | return m.getInt(C.libvlc_marquee_Opacity)
103 | }
104 |
105 | // SetOpacity sets the opacity of the marquee text. The opacity is specified
106 | // as an integer between 0 (transparent) and 255 (opaque).
107 | func (m *Marquee) SetOpacity(opacity int) error {
108 | return m.setInt(C.libvlc_marquee_Opacity, opacity)
109 | }
110 |
111 | // Position returns the position of the marquee, relative to its container.
112 | // Default: vlc.PositionTopLeft.
113 | func (m *Marquee) Position() (Position, error) {
114 | iVal, err := m.getInt(C.libvlc_marquee_Position)
115 | if err != nil {
116 | return PositionDisable, err
117 | }
118 |
119 | switch {
120 | case iVal >= 8:
121 | iVal -= 2
122 | case iVal >= 4:
123 | iVal--
124 | }
125 |
126 | if iVal < 0 {
127 | return PositionTopLeft, nil
128 | }
129 | return Position(iVal), nil
130 | }
131 |
132 | // SetPosition sets the position of the marquee, relative to its container.
133 | func (m *Marquee) SetPosition(position Position) error {
134 | switch {
135 | case position >= PositionBottom:
136 | position += 2
137 | case position >= PositionTop:
138 | position++
139 | }
140 |
141 | return m.setInt(C.libvlc_marquee_Position, int(position))
142 | }
143 |
144 | // X returns the X coordinate of the marquee text. The returned value is
145 | // relative to the position of the marquee inside its container, i.e. the
146 | // position set using the `Marquee.SetPosition` method.
147 | // Default: 0.
148 | func (m *Marquee) X() (int, error) {
149 | return m.getInt(C.libvlc_marquee_X)
150 | }
151 |
152 | // SetX sets the X coordinate of the marquee text. The value is specified
153 | // relative to the position of the marquee inside its container.
154 | //
155 | // NOTE: the method has no effect if the position of the marquee is set to
156 | // `vlc.PositionCenter`, `vlc.PositionTop` or `vlc.PositionBottom`.
157 | func (m *Marquee) SetX(x int) error {
158 | return m.setInt(C.libvlc_marquee_X, x)
159 | }
160 |
161 | // Y returns the Y coordinate of the marquee text. The returned value is
162 | // relative to the position of the marquee inside its container, i.e. the
163 | // position set using the `Marquee.SetPosition` method.
164 | // Default: 0.
165 | func (m *Marquee) Y() (int, error) {
166 | return m.getInt(C.libvlc_marquee_Y)
167 | }
168 |
169 | // SetY sets the Y coordinate of the marquee text. The value is specified
170 | // relative to the position of the marquee inside its container.
171 | //
172 | // NOTE: the method has no effect if the position of the marquee is set to
173 | // `vlc.PositionCenter`, `vlc.PositionLeft` or `vlc.PositionRight`.
174 | func (m *Marquee) SetY(y int) error {
175 | return m.setInt(C.libvlc_marquee_Y, y)
176 | }
177 |
178 | // Size returns the font size used to render the marquee text.
179 | // Default: 0 (default font size is used).
180 | func (m *Marquee) Size() (int, error) {
181 | return m.getInt(C.libvlc_marquee_Size)
182 | }
183 |
184 | // SetSize sets the font size used to render the marquee text.
185 | func (m *Marquee) SetSize(size int) error {
186 | return m.setInt(C.libvlc_marquee_Size, size)
187 | }
188 |
189 | // RefreshInterval returns the interval between marquee text updates.
190 | // The marquee text refreshes mainly when using time format string sequences.
191 | // Default: 1s.
192 | func (m *Marquee) RefreshInterval() (time.Duration, error) {
193 | iVal, err := m.getInt(C.libvlc_marquee_Refresh)
194 | return time.Duration(iVal) * time.Millisecond, err
195 | }
196 |
197 | // SetRefreshInterval sets the interval between marquee text updates.
198 | // The marquee text refreshes mainly when using time format string sequences.
199 | func (m *Marquee) SetRefreshInterval(refreshInterval time.Duration) error {
200 | return m.setInt(C.libvlc_marquee_Refresh, int(refreshInterval.Milliseconds()))
201 | }
202 |
203 | // DisplayDuration returns the duration for which the marquee text
204 | // is set to be displayed.
205 | // Default: 0 (the marquee is displayed indefinitely).
206 | func (m *Marquee) DisplayDuration() (time.Duration, error) {
207 | iVal, err := m.getInt(C.libvlc_marquee_Timeout)
208 | return time.Duration(iVal) * time.Millisecond, err
209 | }
210 |
211 | // SetDisplayDuration sets the duration for which to display the marquee text.
212 | func (m *Marquee) SetDisplayDuration(displayDuration time.Duration) error {
213 | return m.setInt(C.libvlc_marquee_Timeout, int(displayDuration.Milliseconds()))
214 | }
215 |
216 | func (m *Marquee) getInt(option C.uint) (int, error) {
217 | if err := m.player.assertInit(); err != nil {
218 | return 0, err
219 | }
220 |
221 | return int(C.libvlc_video_get_marquee_int(m.player.player, option)), nil
222 | }
223 |
224 | func (m *Marquee) setInt(option C.uint, val int) error {
225 | if err := m.player.assertInit(); err != nil {
226 | return err
227 | }
228 |
229 | C.libvlc_video_set_marquee_int(m.player.player, option, C.int(val))
230 | return nil
231 | }
232 |
233 | func (m *Marquee) getString(option C.uint) (string, error) {
234 | if err := m.player.assertInit(); err != nil {
235 | return "", err
236 | }
237 |
238 | cVal := C.libvlc_video_get_marquee_string(m.player.player, option)
239 | if cVal == nil {
240 | return "", errOrDefault(getError(), ErrInvalid)
241 | }
242 | defer C.free(unsafe.Pointer(cVal))
243 |
244 | return C.GoString(cVal), nil
245 | }
246 |
247 | func (m *Marquee) setString(option C.uint, val string) error {
248 | if err := m.player.assertInit(); err != nil {
249 | return err
250 | }
251 |
252 | cVal := C.CString(val)
253 | defer C.free(unsafe.Pointer(cVal))
254 |
255 | C.libvlc_video_set_marquee_string(m.player.player, option, cVal)
256 | return nil
257 | }
258 |
--------------------------------------------------------------------------------
/v2/media.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | // #include
6 | import "C"
7 | import (
8 | "fmt"
9 | "os"
10 | "time"
11 | "unsafe"
12 | )
13 |
14 | // MediaState represents the state of a media file.
15 | type MediaState uint
16 |
17 | // Media states.
18 | const (
19 | MediaNothingSpecial MediaState = iota
20 | MediaOpening
21 | MediaBuffering
22 | MediaPlaying
23 | MediaPaused
24 | MediaStopped
25 | MediaEnded
26 | MediaError
27 | )
28 |
29 | // MediaMetaKey uniquely identifies a type of media metadata.
30 | type MediaMetaKey uint
31 |
32 | // Media metadata types.
33 | const (
34 | MediaTitle MediaMetaKey = iota
35 | MediaArtist
36 | MediaGenre
37 | MediaCopyright
38 | MediaAlbum
39 | MediaTrackNumber
40 | MediaDescription
41 | MediaRating
42 | MediaDate
43 | MediaSetting
44 | MediaURL
45 | MediaLanguage
46 | MediaNowPlaying
47 | MediaPublisher
48 | MediaEncodedBy
49 | MediaArtworkURL
50 | MediaTrackID
51 | MediaTrackTotal
52 | MediaDirector
53 | MediaSeason
54 | MediaEpisode
55 | MediaShowName
56 | MediaActors
57 | MediaAlbumArtist
58 | MediaDiscNumber
59 | MediaDiscTotal
60 | )
61 |
62 | // Validate checks if the media metadata key is valid.
63 | func (mt MediaMetaKey) Validate() error {
64 | if mt > MediaDiscTotal {
65 | return ErrInvalid
66 | }
67 |
68 | return nil
69 | }
70 |
71 | // MediaStats contains playback statistics for a media file.
72 | type MediaStats struct {
73 | // Input statistics.
74 | ReadBytes int // Input bytes read.
75 | InputBitRate float64 // Input bit rate.
76 |
77 | // Demux statistics.
78 | DemuxReadBytes int // Demux bytes read (demuxed data size).
79 | DemuxBitRate float64 // Demux bit rate (content bit rate).
80 | DemuxCorrupted int // Demux corruptions (discarded).
81 | DemuxDiscontinuity int // Demux discontinuities (dropped).
82 |
83 | // Video output statistics.
84 | DecodedVideo int // Number of decoded video blocks.
85 | DisplayedPictures int // Number of displayed frames.
86 | LostPictures int // Number of lost frames.
87 |
88 | // Audio output statistics.
89 | DecodedAudio int // Number of decoded audio blocks.
90 | PlayedAudioBuffers int // Number of played audio buffers.
91 | LostAudioBuffers int // Number of lost audio buffers.
92 | }
93 |
94 | func newMediaStats(st *C.libvlc_media_stats_t) (*MediaStats, error) {
95 | if st == nil {
96 | return nil, ErrInvalidMediaStats
97 | }
98 |
99 | return &MediaStats{
100 | // Input statistics.
101 | ReadBytes: int(st.i_read_bytes),
102 | InputBitRate: float64(st.f_input_bitrate),
103 |
104 | // Demux statistics.
105 | DemuxReadBytes: int(st.i_demux_read_bytes),
106 | DemuxBitRate: float64(st.f_demux_bitrate),
107 | DemuxCorrupted: int(st.i_demux_corrupted),
108 | DemuxDiscontinuity: int(st.i_demux_discontinuity),
109 |
110 | // Video output statistics.
111 | DecodedVideo: int(st.i_decoded_video),
112 | DisplayedPictures: int(st.i_displayed_pictures),
113 | LostPictures: int(st.i_lost_pictures),
114 |
115 | // Audio output statistics.
116 | DecodedAudio: int(st.i_decoded_audio),
117 | PlayedAudioBuffers: int(st.i_played_abuffers),
118 | LostAudioBuffers: int(st.i_lost_abuffers),
119 | }, nil
120 | }
121 |
122 | // MediaScreenOptions provides configuration options for creating media
123 | // instances from the current computer screen.
124 | type MediaScreenOptions struct {
125 | // Screen capture area.
126 | X int // Left edge coordinate of the subscreen. Default: 0.
127 | Y int // Top edge coordinate of the subscreen. Default: 0.
128 | Width int // Width of the subscreen. Default: 0 (full screen width).
129 | Height int // Height of the subscreen. Default: 0 (full screen height).
130 |
131 | // Screen capture frame rate. Default: 0.
132 | FPS float64
133 |
134 | // Follow the mouse when capturing a subscreen. Default: false.
135 | FollowMouse bool
136 |
137 | // Mouse cursor image to use. If specified, the cursor will be overlayed
138 | // on the captured video. Default: "".
139 | // NOTE: Windows only.
140 | CursorImage string
141 |
142 | // Optimize the capture by fragmenting the screen in chunks of predefined
143 | // height (16 might be a good value). Default: 0 (disabled).
144 | // NOTE: Windows only.
145 | FragmentSize int
146 | }
147 |
148 | type mediaData struct {
149 | userData interface{}
150 | }
151 |
152 | // Media is an abstract representation of a playable media file.
153 | type Media struct {
154 | media *C.libvlc_media_t
155 | }
156 |
157 | // NewMediaFromPath creates a new media instance based on the media
158 | // located at the specified path.
159 | func NewMediaFromPath(path string) (*Media, error) {
160 | return newMedia(path, true)
161 | }
162 |
163 | // NewMediaFromURL creates a new media instance based on the media
164 | // located at the specified URL.
165 | func NewMediaFromURL(url string) (*Media, error) {
166 | return newMedia(url, false)
167 | }
168 |
169 | // NewMediaFromScreen creates a media instance from the current computer
170 | // screen, using the specified options.
171 | //
172 | // NOTE: This functionality requires the VLC screen module to be installed.
173 | // See installation instructions at https://github.com/adrg/libvlc-go/wiki.
174 | // See https://wiki.videolan.org/Documentation:Modules/screen.
175 | func NewMediaFromScreen(opts *MediaScreenOptions) (*Media, error) {
176 | media, err := newMedia("screen://", false)
177 | if err != nil {
178 | return nil, err
179 | }
180 | if opts == nil {
181 | return media, nil
182 | }
183 |
184 | var mediaOpts []string
185 | if opts.X > 0 {
186 | mediaOpts = append(mediaOpts, fmt.Sprintf(":screen-left=%d", opts.X))
187 | }
188 | if opts.Y > 0 {
189 | mediaOpts = append(mediaOpts, fmt.Sprintf(":screen-top=%d", opts.Y))
190 | }
191 | if opts.Width > 0 {
192 | mediaOpts = append(mediaOpts, fmt.Sprintf(":screen-width=%d", opts.Width))
193 | }
194 | if opts.Height > 0 {
195 | mediaOpts = append(mediaOpts, fmt.Sprintf(":screen-height=%d", opts.Height))
196 | }
197 | if opts.FPS != 0 {
198 | mediaOpts = append(mediaOpts, fmt.Sprintf(":screen-fps=%f", opts.FPS))
199 | }
200 | if opts.FollowMouse {
201 | mediaOpts = append(mediaOpts, ":screen-follow-mouse")
202 | }
203 | if opts.FragmentSize > 0 {
204 | mediaOpts = append(mediaOpts, fmt.Sprintf(":screen-fragment-size=%d", opts.FragmentSize))
205 | }
206 | if opts.CursorImage != "" {
207 | mediaOpts = append(mediaOpts, fmt.Sprintf(":screen-mouse-image=%s", opts.CursorImage))
208 | }
209 |
210 | if len(mediaOpts) > 0 {
211 | return media, media.AddOptions(mediaOpts...)
212 | }
213 |
214 | return media, nil
215 | }
216 |
217 | // Release destroys the media instance.
218 | func (m *Media) Release() error {
219 | if err := m.assertInit(); err != nil {
220 | return nil
221 | }
222 |
223 | m.release()
224 | return nil
225 | }
226 |
227 | // Duplicate duplicates the current media instance.
228 | //
229 | // NOTE: Call the Release method on the returned media in order to
230 | // free the allocated resources.
231 | func (m *Media) Duplicate() (*Media, error) {
232 | if err := m.assertInit(); err != nil {
233 | return nil, err
234 | }
235 |
236 | // Duplicate media.
237 | cMedia := C.libvlc_media_duplicate(m.media)
238 | if cMedia == nil {
239 | return nil, errOrDefault(getError(), ErrMediaCreate)
240 | }
241 |
242 | // Duplicate user data.
243 | dup := &Media{media: cMedia}
244 | if _, data := m.getUserData(); data != nil {
245 | dupData := *data
246 | dup.setUserData(&dupData)
247 | }
248 |
249 | return dup, nil
250 | }
251 |
252 | // AddOptions adds the specified options to the media. The specified options
253 | // determine how a media player reads the media, allowing advanced reading or
254 | // streaming on a per-media basis.
255 | func (m *Media) AddOptions(options ...string) error {
256 | if err := m.assertInit(); err != nil {
257 | return err
258 | }
259 |
260 | for _, option := range options {
261 | if err := m.addOption(option); err != nil {
262 | return err
263 | }
264 | }
265 |
266 | return nil
267 | }
268 |
269 | // State returns the current state of the media instance.
270 | func (m *Media) State() (MediaState, error) {
271 | if err := m.assertInit(); err != nil {
272 | return 0, err
273 | }
274 |
275 | return MediaState(C.libvlc_media_get_state(m.media)), nil
276 | }
277 |
278 | // Stats returns playback statistics for the media.
279 | func (m *Media) Stats() (*MediaStats, error) {
280 | if err := m.assertInit(); err != nil {
281 | return nil, err
282 | }
283 |
284 | var stats C.libvlc_media_stats_t
285 | if int(C.libvlc_media_get_stats(m.media, &stats)) != 1 {
286 | return nil, errOrDefault(getError(), ErrMissingMediaStats)
287 | }
288 |
289 | return newMediaStats(&stats)
290 | }
291 |
292 | // Location returns the media location, which can be either a local path or
293 | // a URL, depending on how the media was loaded.
294 | func (m *Media) Location() (string, error) {
295 | if err := m.assertInit(); err != nil {
296 | return "", err
297 | }
298 |
299 | mrl := C.libvlc_media_get_mrl(m.media)
300 | if mrl == nil {
301 | return "", ErrMissingMediaLocation
302 | }
303 | defer C.free(unsafe.Pointer(mrl))
304 |
305 | return urlToPath(C.GoString(mrl))
306 | }
307 |
308 | // Duration returns the media duration in milliseconds.
309 | //
310 | // NOTE: The duration can only be obtained for parsed media instances.
311 | // Either play the media once or call one of the parsing methods first.
312 | func (m *Media) Duration() (time.Duration, error) {
313 | if err := m.assertInit(); err != nil {
314 | return 0, err
315 | }
316 |
317 | duration := C.libvlc_media_get_duration(m.media)
318 | if duration < 0 {
319 | return 0, errOrDefault(getError(), ErrMediaNotParsed)
320 | }
321 |
322 | return time.Duration(duration) * time.Millisecond, nil
323 | }
324 |
325 | // Meta reads the value of the specified media metadata key.
326 | func (m *Media) Meta(key MediaMetaKey) (string, error) {
327 | if err := m.assertInit(); err != nil {
328 | return "", err
329 | }
330 | if err := key.Validate(); err != nil {
331 | return "", err
332 | }
333 |
334 | val := C.libvlc_media_get_meta(m.media, C.libvlc_meta_t(key))
335 | if val == nil {
336 | return "", nil
337 | }
338 | defer C.free(unsafe.Pointer(val))
339 |
340 | return C.GoString(val), nil
341 | }
342 |
343 | // SetMeta sets the specified media metadata key to the provided value.
344 | // In order to save the metadata on the media file, call SaveMeta.
345 | func (m *Media) SetMeta(key MediaMetaKey, val string) error {
346 | if err := m.assertInit(); err != nil {
347 | return err
348 | }
349 | if err := key.Validate(); err != nil {
350 | return err
351 | }
352 |
353 | cVal := C.CString(val)
354 | C.libvlc_media_set_meta(m.media, C.libvlc_meta_t(key), cVal)
355 | C.free(unsafe.Pointer(cVal))
356 | return nil
357 | }
358 |
359 | // SaveMeta saves the previously set media metadata.
360 | func (m *Media) SaveMeta() error {
361 | if err := m.assertInit(); err != nil {
362 | return err
363 | }
364 |
365 | if int(C.libvlc_media_save_meta(m.media)) != 1 {
366 | return errOrDefault(getError(), ErrMediaMetaSave)
367 | }
368 |
369 | return nil
370 | }
371 |
372 | // Parse fetches local art, metadata and track information synchronously.
373 | func (m *Media) Parse() error {
374 | if err := m.assertInit(); err != nil {
375 | return err
376 | }
377 |
378 | C.libvlc_media_parse(m.media)
379 | return getError()
380 | }
381 |
382 | // ParseAsync fetches local art, metadata and track information asynchronously.
383 | // Listen to the MediaParsedChanged event on the media event manager the track
384 | // when the parsing has finished. However, if the media was already parsed,
385 | // the event is not sent.
386 | func (m *Media) ParseAsync() error {
387 | if err := m.assertInit(); err != nil {
388 | return err
389 | }
390 |
391 | C.libvlc_media_parse_async(m.media)
392 | return getError()
393 | }
394 |
395 | // IsParsed returns true if the media was parsed.
396 | func (m *Media) IsParsed() (bool, error) {
397 | if err := m.assertInit(); err != nil {
398 | return false, err
399 | }
400 |
401 | return C.libvlc_media_is_parsed(m.media) != 0, nil
402 | }
403 |
404 | // SubItems returns a media list containing the sub-items of the current
405 | // media instance. If the media does not have any sub-items, an empty media
406 | // list is returned.
407 | //
408 | // NOTE: Call the Release method on the returned media list in order to
409 | // free the allocated resources.
410 | func (m *Media) SubItems() (*MediaList, error) {
411 | if err := m.assertInit(); err != nil {
412 | return nil, err
413 | }
414 |
415 | var subitems *C.libvlc_media_list_t
416 | if subitems = C.libvlc_media_subitems(m.media); subitems == nil {
417 | return nil, errOrDefault(getError(), ErrMediaListNotFound)
418 | }
419 |
420 | return &MediaList{list: subitems}, nil
421 | }
422 |
423 | // Tracks returns the tracks (audio, video, subtitle) of the current media.
424 | //
425 | // NOTE: The tracks can only be obtained for parsed media instances.
426 | // Either play the media once or call one of the parsing methods first.
427 | func (m *Media) Tracks() ([]*MediaTrack, error) {
428 | if err := m.assertInit(); err != nil {
429 | return nil, err
430 | }
431 |
432 | // Get media tracks.
433 | var cTracks **C.libvlc_media_track_t
434 |
435 | count := int(C.libvlc_media_tracks_get(m.media, &cTracks))
436 | if count <= 0 || cTracks == nil {
437 | return nil, nil
438 | }
439 | defer C.libvlc_media_tracks_release(cTracks, C.uint(count))
440 |
441 | // Parse media tracks.
442 | tracks := make([]*MediaTrack, 0, count)
443 | for i := 0; i < count; i++ {
444 | // Get current track pointer.
445 | cTrack := unsafe.Pointer(uintptr(unsafe.Pointer(cTracks)) +
446 | uintptr(i)*unsafe.Sizeof(*cTracks))
447 | if cTrack == nil {
448 | return nil, ErrMediaTrackNotInitialized
449 | }
450 |
451 | // Parse media track.
452 | track, err := parseMediaTrack(*(**C.libvlc_media_track_t)(cTrack))
453 | if err != nil {
454 | return nil, err
455 | }
456 |
457 | tracks = append(tracks, track)
458 | }
459 |
460 | return tracks, nil
461 | }
462 |
463 | // UserData returns the user data associated with the media instance.
464 | //
465 | // NOTE: The method returns `nil` if no user data is found.
466 | func (m *Media) UserData() (interface{}, error) {
467 | if err := m.assertInit(); err != nil {
468 | return nil, err
469 | }
470 |
471 | // Retrieve user data.
472 | _, md := m.getUserData()
473 | if md == nil {
474 | return nil, nil
475 | }
476 |
477 | return md.userData, nil
478 | }
479 |
480 | // SetUserData associates the passed in user data with the media instance.
481 | // The data can be retrieved by using the UserData method.
482 | func (m *Media) SetUserData(userData interface{}) error {
483 | if err := m.assertInit(); err != nil {
484 | return err
485 | }
486 |
487 | // Set or update user data.
488 | if _, md := m.getUserData(); md != nil {
489 | md.userData = userData
490 | } else {
491 | m.setUserData(&mediaData{userData: userData})
492 | }
493 |
494 | return nil
495 | }
496 |
497 | // EventManager returns the event manager responsible for the media.
498 | func (m *Media) EventManager() (*EventManager, error) {
499 | if err := m.assertInit(); err != nil {
500 | return nil, err
501 | }
502 |
503 | manager := C.libvlc_media_event_manager(m.media)
504 | if manager == nil {
505 | return nil, ErrMissingEventManager
506 | }
507 |
508 | return newEventManager(manager), nil
509 | }
510 |
511 | func (m *Media) addOption(option string) error {
512 | if option == "" {
513 | return nil
514 | }
515 |
516 | cOption := C.CString(option)
517 | defer C.free(unsafe.Pointer(cOption))
518 |
519 | C.libvlc_media_add_option(m.media, cOption)
520 | return getError()
521 | }
522 |
523 | func (m *Media) getUserData() (objectID, *mediaData) {
524 | if err := inst.assertInit(); err != nil {
525 | return nil, nil
526 | }
527 | id := C.libvlc_media_get_user_data(m.media)
528 |
529 | obj, ok := inst.objects.get(id)
530 | if !ok {
531 | return nil, nil
532 | }
533 |
534 | data, ok := obj.(*mediaData)
535 | if !ok {
536 | return nil, nil
537 | }
538 |
539 | return id, data
540 | }
541 |
542 | func (m *Media) setUserData(data *mediaData) objectID {
543 | id := inst.objects.add(data)
544 | C.libvlc_media_set_user_data(m.media, id)
545 | return id
546 | }
547 |
548 | func (m *Media) deleteUserData() {
549 | id, data := m.getUserData()
550 | if data == nil {
551 | return
552 | }
553 |
554 | inst.objects.decRefs(id)
555 | }
556 |
557 | func (m *Media) release() {
558 | // Delete user data.
559 | m.deleteUserData()
560 |
561 | // Delete media.
562 | C.libvlc_media_release(m.media)
563 | m.media = nil
564 | }
565 |
566 | func (m *Media) assertInit() error {
567 | if m == nil || m.media == nil {
568 | return ErrMediaNotInitialized
569 | }
570 |
571 | return nil
572 | }
573 |
574 | func newMedia(path string, local bool) (*Media, error) {
575 | if err := inst.assertInit(); err != nil {
576 | return nil, err
577 | }
578 |
579 | cPath := C.CString(path)
580 | defer C.free(unsafe.Pointer(cPath))
581 |
582 | var media *C.libvlc_media_t
583 | if local {
584 | if _, err := os.Stat(path); err != nil {
585 | return nil, err
586 | }
587 |
588 | media = C.libvlc_media_new_path(inst.handle, cPath)
589 | } else {
590 | media = C.libvlc_media_new_location(inst.handle, cPath)
591 | }
592 |
593 | if media == nil {
594 | return nil, errOrDefault(getError(), ErrMediaCreate)
595 | }
596 |
597 | return &Media{media: media}, nil
598 | }
599 |
--------------------------------------------------------------------------------
/v2/media_list.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | import "C"
6 |
7 | // MediaList represents a collection of media files.
8 | type MediaList struct {
9 | list *C.libvlc_media_list_t
10 | }
11 |
12 | // NewMediaList creates an empty media list.
13 | func NewMediaList() (*MediaList, error) {
14 | if err := inst.assertInit(); err != nil {
15 | return nil, err
16 | }
17 |
18 | var list *C.libvlc_media_list_t
19 | if list = C.libvlc_media_list_new(inst.handle); list == nil {
20 | return nil, errOrDefault(getError(), ErrMediaListCreate)
21 | }
22 |
23 | return &MediaList{list: list}, nil
24 | }
25 |
26 | // Release destroys the media list instance.
27 | func (ml *MediaList) Release() error {
28 | if err := ml.assertInit(); err != nil {
29 | return nil
30 | }
31 |
32 | C.libvlc_media_list_release(ml.list)
33 | ml.list = nil
34 |
35 | return nil
36 | }
37 |
38 | // AddMedia adds the provided Media instance at the end of the media list.
39 | func (ml *MediaList) AddMedia(m *Media) error {
40 | if err := m.assertInit(); err != nil {
41 | return err
42 | }
43 |
44 | // Check if media list is read-only.
45 | isReadOnly, err := ml.IsReadOnly()
46 | if err != nil {
47 | return err
48 | }
49 | if isReadOnly {
50 | return ErrMediaListReadOnly
51 | }
52 |
53 | // Lock media list.
54 | if err := ml.Lock(); err != nil {
55 | return err
56 | }
57 | defer ml.unlock()
58 |
59 | // Add the media to the list.
60 | if C.libvlc_media_list_add_media(ml.list, m.media) < 0 {
61 | return errOrDefault(getError(), ErrMediaListActionFailed)
62 | }
63 |
64 | return nil
65 | }
66 |
67 | // AddMediaFromPath loads the media file at the specified path and adds it at
68 | // the end of the media list.
69 | func (ml *MediaList) AddMediaFromPath(path string) error {
70 | media, err := NewMediaFromPath(path)
71 | if err != nil {
72 | return err
73 | }
74 |
75 | // Add the media to the list.
76 | if err := ml.AddMedia(media); err != nil {
77 | media.release()
78 | return err
79 | }
80 |
81 | return nil
82 | }
83 |
84 | // AddMediaFromURL loads the media file at the specified URL and adds it at
85 | // the end of the the media list.
86 | func (ml *MediaList) AddMediaFromURL(url string) error {
87 | media, err := NewMediaFromURL(url)
88 | if err != nil {
89 | return err
90 | }
91 |
92 | if err := ml.AddMedia(media); err != nil {
93 | media.release()
94 | return err
95 | }
96 |
97 | return nil
98 | }
99 |
100 | // InsertMedia inserts the provided Media instance in the list,
101 | // at the specified index.
102 | func (ml *MediaList) InsertMedia(m *Media, index uint) error {
103 | if err := m.assertInit(); err != nil {
104 | return err
105 | }
106 |
107 | // Check if media list is read-only.
108 | isReadOnly, err := ml.IsReadOnly()
109 | if err != nil {
110 | return err
111 | }
112 | if isReadOnly {
113 | return ErrMediaListReadOnly
114 | }
115 |
116 | // Lock media list.
117 | if err := ml.Lock(); err != nil {
118 | return err
119 | }
120 | defer ml.unlock()
121 |
122 | // Insert the media in the list.
123 | if C.libvlc_media_list_insert_media(ml.list, m.media, C.int(index)) < 0 {
124 | return errOrDefault(getError(), ErrMediaListActionFailed)
125 | }
126 |
127 | return nil
128 | }
129 |
130 | // InsertMediaFromPath loads the media file at the provided path and inserts
131 | // it in the list, at the specified index.
132 | func (ml *MediaList) InsertMediaFromPath(path string, index uint) error {
133 | media, err := NewMediaFromPath(path)
134 | if err != nil {
135 | return err
136 | }
137 |
138 | // Insert the media in the list.
139 | if err := ml.InsertMedia(media, index); err != nil {
140 | media.release()
141 | return err
142 | }
143 |
144 | return nil
145 | }
146 |
147 | // InsertMediaFromURL loads the media file at the provided URL and inserts
148 | // it in the list, at the specified index.
149 | func (ml *MediaList) InsertMediaFromURL(url string, index uint) error {
150 | media, err := NewMediaFromURL(url)
151 | if err != nil {
152 | return err
153 | }
154 |
155 | // Insert the media in the list.
156 | if err := ml.InsertMedia(media, index); err != nil {
157 | media.release()
158 | return err
159 | }
160 |
161 | return nil
162 | }
163 |
164 | // RemoveMediaAtIndex removes the media item at the specified index
165 | // from the list.
166 | func (ml *MediaList) RemoveMediaAtIndex(index uint) error {
167 | // Check if media list is read-only.
168 | isReadOnly, err := ml.IsReadOnly()
169 | if err != nil {
170 | return err
171 | }
172 | if isReadOnly {
173 | return ErrMediaListReadOnly
174 | }
175 |
176 | // Lock media list.
177 | if err := ml.Lock(); err != nil {
178 | return err
179 | }
180 | defer ml.unlock()
181 |
182 | // Remove the media from the list.
183 | if C.libvlc_media_list_remove_index(ml.list, C.int(index)) < 0 {
184 | return errOrDefault(getError(), ErrMediaListActionFailed)
185 | }
186 |
187 | return nil
188 | }
189 |
190 | // MediaAtIndex returns the media item at the specified index from the list.
191 | func (ml *MediaList) MediaAtIndex(index uint) (*Media, error) {
192 | // Lock media list.
193 | if err := ml.Lock(); err != nil {
194 | return nil, err
195 | }
196 | defer ml.unlock()
197 |
198 | // Retrieve the media at the specified index.
199 | media := C.libvlc_media_list_item_at_index(ml.list, C.int(index))
200 | if media == nil {
201 | return nil, errOrDefault(getError(), ErrMediaListActionFailed)
202 | }
203 |
204 | // This call will not release the media. Instead, it will decrement
205 | // the reference count increased by libvlc_media_list_item_at_index.
206 | C.libvlc_media_release(media)
207 |
208 | return &Media{media}, nil
209 | }
210 |
211 | // IndexOfMedia returns the index of the specified media item in the list.
212 | //
213 | // NOTE: The same instance of a media item can be present multiple times
214 | // in the list. The method returns the first matched index.
215 | func (ml *MediaList) IndexOfMedia(m *Media) (int, error) {
216 | if err := m.assertInit(); err != nil {
217 | return 0, err
218 | }
219 |
220 | if err := ml.Lock(); err != nil {
221 | return 0, err
222 | }
223 | defer ml.unlock()
224 |
225 | // Retrieve the index of the media.
226 | idx := int(C.libvlc_media_list_index_of_item(ml.list, m.media))
227 | if idx < 0 {
228 | return 0, errOrDefault(getError(), ErrMediaNotFound)
229 | }
230 |
231 | return idx, nil
232 | }
233 |
234 | // Count returns the number of media items in the list.
235 | func (ml *MediaList) Count() (int, error) {
236 | // Lock media list.
237 | if err := ml.Lock(); err != nil {
238 | return 0, err
239 | }
240 | defer ml.unlock()
241 |
242 | // Retrieve media count.
243 | return int(C.libvlc_media_list_count(ml.list)), nil
244 | }
245 |
246 | // IsReadOnly specifies if the media list can be modified.
247 | func (ml *MediaList) IsReadOnly() (bool, error) {
248 | if err := ml.assertInit(); err != nil {
249 | return false, err
250 | }
251 |
252 | return (C.libvlc_media_list_is_readonly(ml.list) != C.int(0)), nil
253 | }
254 |
255 | // AssociatedMedia returns the media instance associated with the list,
256 | // if one exists. A media instance is automatically associated with the
257 | // list of its sub-items.
258 | //
259 | // NOTE: Do not call Release on the returned media instance.
260 | func (ml *MediaList) AssociatedMedia() (*Media, error) {
261 | if err := ml.assertInit(); err != nil {
262 | return nil, err
263 | }
264 |
265 | media := C.libvlc_media_list_media(ml.list)
266 | if media == nil {
267 | return nil, errOrDefault(getError(), ErrMediaNotFound)
268 | }
269 |
270 | // This call will not release the media. Instead, it will decrement
271 | // the reference count increased by libvlc_media_list_media.
272 | C.libvlc_media_release(media)
273 |
274 | return &Media{media: media}, nil
275 | }
276 |
277 | // AssociateMedia associates the specified media with the media list instance.
278 | //
279 | // NOTE: If another media instance is already associated with the list,
280 | // it will be released.
281 | func (ml *MediaList) AssociateMedia(m *Media) error {
282 | if err := ml.assertInit(); err != nil {
283 | return err
284 | }
285 | if err := m.assertInit(); err != nil {
286 | return err
287 | }
288 |
289 | C.libvlc_media_list_set_media(ml.list, m.media)
290 | return nil
291 | }
292 |
293 | // Lock makes the caller the current owner of the media list.
294 | func (ml *MediaList) Lock() error {
295 | if err := ml.assertInit(); err != nil {
296 | return err
297 | }
298 |
299 | C.libvlc_media_list_lock(ml.list)
300 | return nil
301 | }
302 |
303 | // Unlock releases ownership of the media list.
304 | func (ml *MediaList) Unlock() error {
305 | if err := ml.assertInit(); err != nil {
306 | return err
307 | }
308 |
309 | ml.unlock()
310 | return nil
311 | }
312 |
313 | // EventManager returns the event manager responsible for the media list.
314 | func (ml *MediaList) EventManager() (*EventManager, error) {
315 | if err := ml.assertInit(); err != nil {
316 | return nil, err
317 | }
318 |
319 | manager := C.libvlc_media_list_event_manager(ml.list)
320 | if manager == nil {
321 | return nil, ErrMissingEventManager
322 | }
323 |
324 | return newEventManager(manager), nil
325 | }
326 |
327 | func (ml *MediaList) assertInit() error {
328 | if ml == nil || ml.list == nil {
329 | return ErrMediaListNotInitialized
330 | }
331 |
332 | return nil
333 | }
334 |
335 | func (ml *MediaList) unlock() {
336 | C.libvlc_media_list_unlock(ml.list)
337 | }
338 |
--------------------------------------------------------------------------------
/v2/media_track.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | import "C"
6 | import (
7 | "unsafe"
8 | )
9 |
10 | // MediaTrackType represents the type of a media track.
11 | type MediaTrackType int
12 |
13 | // Media track types.
14 | const (
15 | MediaTrackUnknown MediaTrackType = iota - 1
16 | MediaTrackAudio
17 | MediaTrackVideo
18 | MediaTrackText
19 | )
20 |
21 | // MediaTrackDescriptor contains information about a media track.
22 | type MediaTrackDescriptor struct {
23 | ID int // Media track identifier.
24 | Description string // Description of the media track.
25 | }
26 |
27 | // MediaAudioTrack contains information specific to audio media tracks.
28 | type MediaAudioTrack struct {
29 | Channels uint // number of audio channels.
30 | Rate uint // audio sample rate.
31 | }
32 |
33 | // MediaVideoTrack contains information specific to video media tracks.
34 | type MediaVideoTrack struct {
35 | Width uint // video width.
36 | Height uint // video height.
37 |
38 | // Aspect ratio information.
39 | AspectRatioNum uint // aspect ratio numerator.
40 | AspectRatioDen uint // aspect ratio denominator.
41 |
42 | // Frame rate information.
43 | FrameRateNum uint // frame rate numerator.
44 | FrameRateDen uint // frame rate denominator.
45 | }
46 |
47 | // MediaSubtitleTrack contains information specific to subtitle media tracks.
48 | type MediaSubtitleTrack struct {
49 | Encoding string // character encoding of the subtitle.
50 | }
51 |
52 | // MediaTrack contains information regarding a media track.
53 | type MediaTrack struct {
54 | ID int // Media track identifier.
55 | Type MediaTrackType // Media track type.
56 | BitRate uint // Media track bit rate.
57 |
58 | // libVLC representation of the four-character code of the codec used by
59 | // the media track.
60 | Codec uint
61 |
62 | // The original four-character code of the codec used by the media track,
63 | // extracted from the container.
64 | OriginalCodec uint
65 |
66 | // Codec profile (real audio flavor, MPEG audio layer, H264 profile, etc.).
67 | // NOTE: Profile values are codec specific.
68 | Profile int
69 |
70 | // Stream restriction level (resolution, bitrate, codec features, etc.).
71 | // NOTE: Level values are codec specific.
72 | Level int
73 |
74 | Language string // Media track language name.
75 | Description string // Description of the media track.
76 |
77 | // Type specific information.
78 | Audio *MediaAudioTrack
79 | Video *MediaVideoTrack
80 | Subtitle *MediaSubtitleTrack
81 | }
82 |
83 | func (mt *MediaTrack) assertInit() error {
84 | if mt == nil {
85 | return ErrMediaTrackNotInitialized
86 | }
87 |
88 | return nil
89 | }
90 |
91 | func parseMediaTrack(cTrack *C.libvlc_media_track_t) (*MediaTrack, error) {
92 | if cTrack == nil {
93 | return nil, ErrMediaTrackNotInitialized
94 | }
95 |
96 | mt := &MediaTrack{
97 | ID: int(cTrack.i_id),
98 | Type: MediaTrackType(cTrack.i_type),
99 | BitRate: uint(cTrack.i_bitrate),
100 | Codec: uint(cTrack.i_codec),
101 | OriginalCodec: uint(cTrack.i_original_fourcc),
102 | Profile: int(cTrack.i_profile),
103 | Level: int(cTrack.i_level),
104 | Language: C.GoString(cTrack.psz_language),
105 | Description: C.GoString(cTrack.psz_description),
106 | }
107 |
108 | switch mt.Type {
109 | case MediaTrackAudio:
110 | audio := *(**C.libvlc_audio_track_t)(unsafe.Pointer(&cTrack.anon0[0]))
111 | if audio == nil {
112 | break
113 | }
114 |
115 | mt.Audio = &MediaAudioTrack{
116 | Channels: uint(audio.i_channels),
117 | Rate: uint(audio.i_rate),
118 | }
119 | case MediaTrackVideo:
120 | video := *(**C.libvlc_video_track_t)(unsafe.Pointer(&cTrack.anon0[0]))
121 | if video == nil {
122 | break
123 | }
124 |
125 | mt.Video = &MediaVideoTrack{
126 | Width: uint(video.i_width),
127 | Height: uint(video.i_height),
128 | AspectRatioNum: uint(video.i_sar_num),
129 | AspectRatioDen: uint(video.i_sar_den),
130 | FrameRateNum: uint(video.i_frame_rate_num),
131 | FrameRateDen: uint(video.i_frame_rate_den),
132 | }
133 | case MediaTrackText:
134 | subtitle := *(**C.libvlc_subtitle_track_t)(unsafe.Pointer(&cTrack.anon0[0]))
135 | if subtitle == nil {
136 | break
137 | }
138 |
139 | mt.Subtitle = &MediaSubtitleTrack{
140 | Encoding: C.GoString(subtitle.psz_encoding),
141 | }
142 | }
143 |
144 | return mt, nil
145 | }
146 |
147 | func parseMediaTrackDescriptorList(cDescriptors *C.libvlc_track_description_t) ([]*MediaTrackDescriptor, error) {
148 | if cDescriptors == nil {
149 | return nil, nil
150 | }
151 |
152 | var descriptors []*MediaTrackDescriptor
153 | for n := cDescriptors; n != nil; n = n.p_next {
154 | descriptors = append(descriptors, &MediaTrackDescriptor{
155 | ID: int(n.i_id),
156 | Description: C.GoString(n.psz_name),
157 | })
158 | }
159 |
160 | C.libvlc_track_description_list_release(cDescriptors)
161 | return descriptors, nil
162 | }
163 |
--------------------------------------------------------------------------------
/v2/object_registry.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #include
4 | import "C"
5 | import (
6 | "sync"
7 | "unsafe"
8 | )
9 |
10 | type objectID = unsafe.Pointer
11 |
12 | type objectContext struct {
13 | refs uint
14 | data interface{}
15 | }
16 |
17 | type objectRegistry struct {
18 | sync.RWMutex
19 |
20 | contexts map[objectID]*objectContext
21 | }
22 |
23 | func newObjectRegistry() *objectRegistry {
24 | return &objectRegistry{
25 | contexts: map[objectID]*objectContext{},
26 | }
27 | }
28 |
29 | func (or *objectRegistry) get(id objectID) (interface{}, bool) {
30 | if id == nil {
31 | return nil, false
32 | }
33 |
34 | or.RLock()
35 | ctx, ok := or.contexts[id]
36 | or.RUnlock()
37 |
38 | if !ok {
39 | return nil, false
40 | }
41 | return ctx.data, ok
42 | }
43 |
44 | func (or *objectRegistry) add(data interface{}) objectID {
45 | or.Lock()
46 |
47 | var id objectID = C.malloc(C.size_t(1))
48 | or.contexts[id] = &objectContext{
49 | refs: 1,
50 | data: data,
51 | }
52 |
53 | or.Unlock()
54 | return id
55 | }
56 |
57 | func (or *objectRegistry) incRefs(id objectID) {
58 | if id == nil {
59 | return
60 | }
61 |
62 | or.Lock()
63 |
64 | ctx, ok := or.contexts[id]
65 | if ok {
66 | ctx.refs++
67 | }
68 |
69 | or.Unlock()
70 | }
71 |
72 | func (or *objectRegistry) decRefs(id objectID) {
73 | if id == nil {
74 | return
75 | }
76 |
77 | or.Lock()
78 |
79 | ctx, ok := or.contexts[id]
80 | if ok {
81 | ctx.refs--
82 | if ctx.refs == 0 {
83 | delete(or.contexts, id)
84 | C.free(id)
85 | }
86 | }
87 |
88 | or.Unlock()
89 | }
90 |
--------------------------------------------------------------------------------
/v2/utils.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | // #include
6 | import "C"
7 | import (
8 | "errors"
9 | "net/url"
10 | "path/filepath"
11 | "runtime"
12 | "strings"
13 | )
14 |
15 | func getError() error {
16 | msg := C.libvlc_errmsg()
17 | if msg == nil {
18 | return nil
19 | }
20 |
21 | err := errors.New(C.GoString(msg))
22 | C.libvlc_clearerr()
23 | return err
24 | }
25 |
26 | func errOrDefault(err, defaultErr error) error {
27 | if err != nil {
28 | return err
29 | }
30 |
31 | return defaultErr
32 | }
33 |
34 | func boolToInt(value bool) int {
35 | if value {
36 | return 1
37 | }
38 |
39 | return 0
40 | }
41 |
42 | func urlToPath(mrl string) (string, error) {
43 | url, err := url.Parse(mrl)
44 | if err != nil {
45 | return "", err
46 | }
47 | if url.Scheme != "file" {
48 | return mrl, nil
49 | }
50 | path := filepath.Clean(url.Path)
51 |
52 | if runtime.GOOS == "windows" {
53 | sep := string(filepath.Separator)
54 | if url.Host != "" {
55 | path = strings.Repeat(sep, 2) + filepath.Join(url.Host, path)
56 | } else {
57 | path = strings.TrimLeft(path, sep)
58 | }
59 | }
60 |
61 | return path, nil
62 | }
63 |
--------------------------------------------------------------------------------
/v2/version.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | // #include
6 | import "C"
7 | import "fmt"
8 |
9 | // VersionInfo contains details regarding the version of the libVLC module.
10 | type VersionInfo struct {
11 | Major uint
12 | Minor uint
13 | Patch uint
14 | Extra uint
15 | }
16 |
17 | // String returns a string representation of the version.
18 | func (v VersionInfo) String() string {
19 | return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
20 | }
21 |
22 | // Runtime returns the runtime version of libVLC, usually including
23 | // the codename of the build.
24 | //
25 | // NOTE: Due to binary backward compatibility, the runtime version may be
26 | // more recent than the build version.
27 | func (v VersionInfo) Runtime() string {
28 | return C.GoString(C.libvlc_get_version())
29 | }
30 |
31 | // Changeset returns the changeset identifier for the current libVLC build.
32 | func (v VersionInfo) Changeset() string {
33 | return C.GoString(C.libvlc_get_changeset())
34 | }
35 |
36 | // Compiler returns information regarding the compiler used to build libVLC.
37 | func (v VersionInfo) Compiler() string {
38 | return C.GoString(C.libvlc_get_compiler())
39 | }
40 |
41 | var moduleVersion = VersionInfo{
42 | Major: C.LIBVLC_VERSION_MAJOR,
43 | Minor: C.LIBVLC_VERSION_MINOR,
44 | Patch: C.LIBVLC_VERSION_REVISION,
45 | Extra: C.LIBVLC_VERSION_EXTRA,
46 | }
47 |
--------------------------------------------------------------------------------
/v2/vlc.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #cgo CFLAGS: -w
5 | // #include
6 | // #include
7 | import "C"
8 | import (
9 | "unsafe"
10 | )
11 |
12 | type instance struct {
13 | handle *C.libvlc_instance_t
14 | events *eventRegistry
15 | objects *objectRegistry
16 | }
17 |
18 | func (i *instance) assertInit() error {
19 | if i == nil || i.handle == nil {
20 | return ErrModuleNotInitialized
21 | }
22 |
23 | return nil
24 | }
25 |
26 | var inst *instance
27 |
28 | // Init creates an instance of the libVLC module.
29 | // Must be called only once and the module instance must be released using
30 | // the Release function.
31 | func Init(args ...string) error {
32 | if inst != nil {
33 | return nil
34 | }
35 |
36 | argc := len(args)
37 | argv := make([]*C.char, argc)
38 |
39 | for i, arg := range args {
40 | argv[i] = C.CString(arg)
41 | }
42 | defer func() {
43 | for i := range argv {
44 | C.free(unsafe.Pointer(argv[i]))
45 | }
46 | }()
47 |
48 | handle := C.libvlc_new(C.int(argc), *(***C.char)(unsafe.Pointer(&argv)))
49 | if handle == nil {
50 | return errOrDefault(getError(), ErrModuleInitialize)
51 | }
52 |
53 | inst = &instance{
54 | handle: handle,
55 | events: newEventRegistry(),
56 | objects: newObjectRegistry(),
57 | }
58 |
59 | return nil
60 | }
61 |
62 | // Release destroys the instance created by the Init function.
63 | func Release() error {
64 | if inst == nil {
65 | return nil
66 | }
67 |
68 | C.libvlc_release(inst.handle)
69 | inst = nil
70 |
71 | return nil
72 | }
73 |
74 | // Version returns details regarding the version of the libVLC module.
75 | func Version() VersionInfo {
76 | return moduleVersion
77 | }
78 |
79 | // SetAppName sets the human-readable application name and the HTTP user agent.
80 | // The specified user agent is used when a protocol requires it.
81 | func SetAppName(name, userAgent string) error {
82 | if err := inst.assertInit(); err != nil {
83 | return err
84 | }
85 |
86 | cName, cUserAgent := C.CString(name), C.CString(userAgent)
87 | C.libvlc_set_user_agent(inst.handle, cName, cUserAgent)
88 |
89 | C.free(unsafe.Pointer(cName))
90 | C.free(unsafe.Pointer(cUserAgent))
91 | return nil
92 | }
93 |
94 | // SetAppID sets metadata for identifying the application.
95 | func SetAppID(id, version, icon string) error {
96 | if err := inst.assertInit(); err != nil {
97 | return err
98 | }
99 |
100 | cID, cVersion, cIcon := C.CString(id), C.CString(version), C.CString(icon)
101 | C.libvlc_set_app_id(inst.handle, cID, cVersion, cIcon)
102 |
103 | C.free(unsafe.Pointer(cID))
104 | C.free(unsafe.Pointer(cVersion))
105 | C.free(unsafe.Pointer(cIcon))
106 | return nil
107 | }
108 |
109 | // StartUserInterface attempts to start a user interface for the libVLC
110 | // instance. Pass an empty string as the name parameter in order to start
111 | // the default interface.
112 | func StartUserInterface(name string) error {
113 | if err := inst.assertInit(); err != nil {
114 | return err
115 | }
116 |
117 | cName := C.CString(name)
118 | defer C.free(unsafe.Pointer(cName))
119 |
120 | if C.libvlc_add_intf(inst.handle, cName) < 0 {
121 | return errOrDefault(getError(), ErrUserInterfaceStart)
122 | }
123 |
124 | return nil
125 | }
126 |
--------------------------------------------------------------------------------
/v3/av.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | // #include
6 | import "C"
7 | import (
8 | "unsafe"
9 | )
10 |
11 | // StereoMode defines stereo modes which can be used by an audio output.
12 | type StereoMode int
13 |
14 | // Stereo modes.
15 | const (
16 | StereoModeError StereoMode = iota - 1
17 | StereoModeNotSet
18 | StereoModeNormal
19 | StereoModeReverse
20 | StereoModeLeft
21 | StereoModeRight
22 | StereoModeDolbySurround
23 | StereoModeHeadphones
24 | )
25 |
26 | // Position defines locations of entities relative to a container.
27 | type Position int
28 |
29 | // Positions.
30 | const (
31 | PositionDisable Position = iota - 1
32 | PositionCenter
33 | PositionLeft
34 | PositionRight
35 | PositionTop
36 | PositionTopLeft
37 | PositionTopRight
38 | PositionBottom
39 | PositionBottomLeft
40 | PositionBottomRight
41 | )
42 |
43 | // DeinterlaceMode defines deinterlacing modes which can be used when
44 | // rendering videos.
45 | //
46 | // For more information see https://wiki.videolan.org/Deinterlacing.
47 | type DeinterlaceMode string
48 |
49 | // Deinterlace modes.
50 | const (
51 | DeinterlaceModeDisable DeinterlaceMode = ""
52 | DeinterlaceModeDiscard DeinterlaceMode = "discard"
53 | DeinterlaceModeBlend DeinterlaceMode = "blend"
54 | DeinterlaceModeMean DeinterlaceMode = "mean"
55 | DeinterlaceModeBob DeinterlaceMode = "bob"
56 | DeinterlaceModeLinear DeinterlaceMode = "linear"
57 | DeinterlaceModeX DeinterlaceMode = "x"
58 | DeinterlaceModeYadif DeinterlaceMode = "yadif"
59 | DeinterlaceModeYadif2x DeinterlaceMode = "yadif2x"
60 | DeinterlaceModePhosphor DeinterlaceMode = "phosphor"
61 | DeinterlaceModeIVTC DeinterlaceMode = "ivtc"
62 | )
63 |
64 | // AudioOutput contains information regarding an audio output.
65 | type AudioOutput struct {
66 | Name string
67 | Description string
68 | }
69 |
70 | // AudioOutputList returns the list of available audio outputs.
71 | // In order to change the audio output of a media player instance,
72 | // use the Player.SetAudioOutput method.
73 | func AudioOutputList() ([]*AudioOutput, error) {
74 | if err := inst.assertInit(); err != nil {
75 | return nil, err
76 | }
77 |
78 | cOutputs := C.libvlc_audio_output_list_get(inst.handle)
79 | if cOutputs == nil {
80 | return nil, errOrDefault(getError(), ErrAudioOutputListMissing)
81 | }
82 |
83 | var outputs []*AudioOutput
84 | for n := cOutputs; n != nil; n = n.p_next {
85 | outputs = append(outputs, &AudioOutput{
86 | Name: C.GoString(n.psz_name),
87 | Description: C.GoString(n.psz_description),
88 | })
89 | }
90 |
91 | C.libvlc_audio_output_list_release(cOutputs)
92 | return outputs, nil
93 | }
94 |
95 | // AudioOutputDevice contains information regarding an audio output device.
96 | type AudioOutputDevice struct {
97 | Name string
98 | Description string
99 | }
100 |
101 | // ListAudioOutputDevices returns the list of available devices for the
102 | // specified audio output. Use the AudioOutputList method in order to obtain
103 | // the list of available audio outputs. In order to change the audio output
104 | // device of a media player instance, use Player.SetAudioOutputDevice.
105 | //
106 | // NOTE: Not all audio outputs support this. An empty list of devices does
107 | // not imply that the specified audio output does not work.
108 | // Some audio output devices in the list might not work in some circumstances.
109 | // By default, it is recommended to not specify any explicit audio device.
110 | func ListAudioOutputDevices(output string) ([]*AudioOutputDevice, error) {
111 | if err := inst.assertInit(); err != nil {
112 | return nil, err
113 | }
114 |
115 | cOutput := C.CString(output)
116 | defer C.free(unsafe.Pointer(cOutput))
117 | return parseAudioOutputDeviceList(C.libvlc_audio_output_device_list_get(inst.handle, cOutput))
118 | }
119 |
120 | func parseAudioOutputDeviceList(cDevices *C.libvlc_audio_output_device_t) ([]*AudioOutputDevice, error) {
121 | if cDevices == nil {
122 | return nil, errOrDefault(getError(), ErrAudioOutputDeviceListMissing)
123 | }
124 |
125 | var devices []*AudioOutputDevice
126 | for n := cDevices; n != nil; n = n.p_next {
127 | devices = append(devices, &AudioOutputDevice{
128 | Name: C.GoString(n.psz_device),
129 | Description: C.GoString(n.psz_description),
130 | })
131 | }
132 |
133 | C.libvlc_audio_output_device_list_release(cDevices)
134 | return devices, nil
135 | }
136 |
137 | // ModuleDescription contains information about a libVLC module.
138 | type ModuleDescription struct {
139 | Name string
140 | ShortName string
141 | LongName string
142 | Help string
143 | }
144 |
145 | // ListAudioFilters returns the list of available audio filters.
146 | func ListAudioFilters() ([]*ModuleDescription, error) {
147 | if err := inst.assertInit(); err != nil {
148 | return nil, err
149 | }
150 |
151 | return parseFilterList(C.libvlc_audio_filter_list_get(inst.handle))
152 | }
153 |
154 | // ListVideoFilters returns the list of available video filters.
155 | func ListVideoFilters() ([]*ModuleDescription, error) {
156 | if err := inst.assertInit(); err != nil {
157 | return nil, err
158 | }
159 |
160 | return parseFilterList(C.libvlc_video_filter_list_get(inst.handle))
161 | }
162 |
163 | func parseFilterList(cFilters *C.libvlc_module_description_t) ([]*ModuleDescription, error) {
164 | if cFilters == nil {
165 | return nil, errOrDefault(getError(), ErrFilterListMissing)
166 | }
167 |
168 | var filters []*ModuleDescription
169 | for n := cFilters; n != nil; n = n.p_next {
170 | filters = append(filters, &ModuleDescription{
171 | Name: C.GoString(n.psz_name),
172 | ShortName: C.GoString(n.psz_shortname),
173 | LongName: C.GoString(n.psz_longname),
174 | Help: C.GoString(n.psz_help),
175 | })
176 | }
177 |
178 | C.libvlc_module_description_list_release(cFilters)
179 | return filters, nil
180 | }
181 |
--------------------------------------------------------------------------------
/v3/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package vlc provides Golang bindings for libVLC version 3.X.
3 |
4 | # Usage
5 |
6 | Initialization
7 |
8 | // Initialize libVLC. Additional command line arguments can be passed in
9 | // to libVLC by specifying them in the Init function.
10 | if err := vlc.Init("--no-video", "--quiet"); err != nil {
11 | log.Fatal(err)
12 | }
13 | defer vlc.Release()
14 |
15 | Player example
16 |
17 | // Create a new player.
18 | player, err := vlc.NewPlayer()
19 | if err != nil {
20 | log.Fatal(err)
21 | }
22 | defer func() {
23 | player.Stop()
24 | player.Release()
25 | }()
26 |
27 | // Add a media file from path or from URL.
28 | // Set player media from path:
29 | // media, err := player.LoadMediaFromPath("localpath/test.mp4")
30 | // Set player media from URL:
31 | media, err := player.LoadMediaFromURL("http://stream-uk1.radioparadise.com/mp3-32")
32 | if err != nil {
33 | log.Fatal(err)
34 | }
35 | defer media.Release()
36 |
37 | // Retrieve player event manager.
38 | manager, err := player.EventManager()
39 | if err != nil {
40 | log.Fatal(err)
41 | }
42 |
43 | // Register the media end reached event with the event manager.
44 | quit := make(chan struct{})
45 | eventCallback := func(event vlc.Event, userData interface{}) {
46 | close(quit)
47 | }
48 |
49 | eventID, err := manager.Attach(vlc.MediaPlayerEndReached, eventCallback, nil)
50 | if err != nil {
51 | log.Fatal(err)
52 | }
53 | defer manager.Detach(eventID)
54 |
55 | // Start playing the media.
56 | if err = player.Play(); err != nil {
57 | log.Fatal(err)
58 | }
59 |
60 | <-quit
61 |
62 | List player example
63 |
64 | // Create a new list player.
65 | player, err := vlc.NewListPlayer()
66 | if err != nil {
67 | log.Fatal(err)
68 | }
69 | defer func() {
70 | player.Stop()
71 | player.Release()
72 | }()
73 |
74 | // Create a new media list.
75 | list, err := vlc.NewMediaList()
76 | if err != nil {
77 | log.Fatal(err)
78 | }
79 | defer list.Release()
80 |
81 | err = list.AddMediaFromPath("localpath/test1.mp3")
82 | if err != nil {
83 | log.Fatal(err)
84 | }
85 |
86 | err = list.AddMediaFromURL("http://stream-uk1.radioparadise.com/mp3-32")
87 | if err != nil {
88 | log.Fatal(err)
89 | }
90 |
91 | // Set player media list.
92 | if err = player.SetMediaList(list); err != nil {
93 | log.Fatal(err)
94 | }
95 |
96 | // Media files can be added to the list after the list has been added
97 | // to the player. The player will play these files as well.
98 | err = list.AddMediaFromPath("localpath/test2.mp3")
99 | if err != nil {
100 | log.Fatal(err)
101 | }
102 |
103 | // Retrieve player event manager.
104 | manager, err := player.EventManager()
105 | if err != nil {
106 | log.Fatal(err)
107 | }
108 |
109 | // Register the media end reached event with the event manager.
110 | quit := make(chan struct{})
111 | eventCallback := func(event vlc.Event, userData interface{}) {
112 | close(quit)
113 | }
114 |
115 | eventID, err := manager.Attach(vlc.MediaListPlayerPlayed, eventCallback, nil)
116 | if err != nil {
117 | log.Fatal(err)
118 | }
119 | defer manager.Detach(eventID)
120 |
121 | // Start playing the media list.
122 | if err = player.Play(); err != nil {
123 | log.Fatal(err)
124 | }
125 |
126 | <-quit
127 |
128 | Handling multiple events example
129 |
130 | // Create a new player.
131 | player, err := vlc.NewPlayer()
132 | if err != nil {
133 | log.Fatal(err)
134 | }
135 | defer func() {
136 | player.Stop()
137 | player.Release()
138 | }()
139 |
140 | // Add a media file from path or from URL.
141 | // Set player media from path:
142 | // media, err := player.LoadMediaFromPath("test.mp3")
143 | // Set player media from URL:
144 | media, err := player.LoadMediaFromURL("http://stream-uk1.radioparadise.com/mp3-32")
145 | if err != nil {
146 | log.Fatal(err)
147 | }
148 | defer media.Release()
149 |
150 | // Retrieve player event manager.
151 | manager, err := player.EventManager()
152 | if err != nil {
153 | log.Fatal(err)
154 | }
155 |
156 | // Create event handler.
157 | quit := make(chan struct{})
158 | eventCallback := func(event vlc.Event, userData interface{}) {
159 | switch event {
160 | case vlc.MediaPlayerEndReached:
161 | log.Println("Player end reached")
162 | close(quit)
163 | case vlc.MediaPlayerTimeChanged:
164 | media, err := player.Media()
165 | if err != nil {
166 | log.Println(err)
167 | break
168 | }
169 |
170 | stats, err := media.Stats()
171 | if err != nil {
172 | log.Println(err)
173 | break
174 | }
175 |
176 | log.Printf("%+v\n", stats)
177 | }
178 | }
179 |
180 | // Register events with the event manager.
181 | events := []vlc.Event{
182 | vlc.MediaPlayerTimeChanged,
183 | vlc.MediaPlayerEndReached,
184 | }
185 |
186 | var eventIDs []vlc.EventID
187 | for _, event := range events {
188 | eventID, err := manager.Attach(event, eventCallback, nil)
189 | if err != nil {
190 | log.Fatal(err)
191 | }
192 |
193 | eventIDs = append(eventIDs, eventID)
194 | }
195 |
196 | // De-register attached events.
197 | defer func() {
198 | for _, eventID := range eventIDs {
199 | manager.Detach(eventID)
200 | }
201 | }()
202 |
203 | // Start playing the media.
204 | if err = player.Play(); err != nil {
205 | log.Fatal(err)
206 | }
207 |
208 | <-quit
209 | */
210 | package vlc
211 |
--------------------------------------------------------------------------------
/v3/equalizer.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | import "C"
6 |
7 | // EqualizerPresetCount returns the number of available equalizer presets.
8 | func EqualizerPresetCount() uint {
9 | return uint(C.libvlc_audio_equalizer_get_preset_count())
10 | }
11 |
12 | // EqualizerPresetName returns the name of the equalizer preset with the
13 | // specified index. The index must be a number greater than or equal to 0
14 | // and less than EqualizerPresetCount(). The function returns an empty string
15 | // for invalid indices.
16 | func EqualizerPresetName(index uint) string {
17 | return C.GoString(C.libvlc_audio_equalizer_get_preset_name(C.uint(index)))
18 | }
19 |
20 | // EqualizerPresetNames returns the names of all available equalizer presets,
21 | // sorted by their indices in ascending order.
22 | func EqualizerPresetNames() []string {
23 | // Get preset count.
24 | count := EqualizerPresetCount()
25 |
26 | // Get preset names.
27 | names := make([]string, 0, count)
28 | for i := uint(0); i < count; i++ {
29 | names = append(names, EqualizerPresetName(i))
30 | }
31 |
32 | return names
33 | }
34 |
35 | // EqualizerBandCount returns the number of distinct equalizer frequency bands.
36 | func EqualizerBandCount() uint {
37 | return uint(C.libvlc_audio_equalizer_get_band_count())
38 | }
39 |
40 | // EqualizerBandFrequency returns the frequency of the equalizer band with the
41 | // specified index. The index must be a number greater than or equal to 0 and
42 | // less than EqualizerBandCount(). The function returns -1 for invalid indices.
43 | func EqualizerBandFrequency(index uint) float64 {
44 | return float64(C.libvlc_audio_equalizer_get_band_frequency(C.uint(index)))
45 | }
46 |
47 | // EqualizerBandFrequencies returns the frequencies of all available equalizer
48 | // bands, sorted by their indices in ascending order.
49 | func EqualizerBandFrequencies() []float64 {
50 | // Get band count.
51 | count := EqualizerBandCount()
52 |
53 | // Get band frequencies.
54 | frequencies := make([]float64, 0, count)
55 | for i := uint(0); i < count; i++ {
56 | frequencies = append(frequencies, EqualizerBandFrequency(i))
57 | }
58 |
59 | return frequencies
60 | }
61 |
62 | // Equalizer represents an audio equalizer. Use Player.SetEqualizer to assign
63 | // the equalizer to a player instance.
64 | type Equalizer struct {
65 | equalizer *C.libvlc_equalizer_t
66 | }
67 |
68 | // NewEqualizer returns a new equalizer with all frequency values set to zero.
69 | func NewEqualizer() (*Equalizer, error) {
70 | equalizer := C.libvlc_audio_equalizer_new()
71 | if equalizer == nil {
72 | return nil, errOrDefault(getError(), ErrEqualizerCreate)
73 | }
74 |
75 | return &Equalizer{equalizer: equalizer}, nil
76 | }
77 |
78 | // NewEqualizerFromPreset returns a new equalizer with the frequency values
79 | // copied from the preset with the specified index. The index must be a number
80 | // greater than or equal to 0 and less than EqualizerPresetCount().
81 | func NewEqualizerFromPreset(index uint) (*Equalizer, error) {
82 | equalizer := C.libvlc_audio_equalizer_new_from_preset(C.uint(index))
83 | if equalizer == nil {
84 | return nil, errOrDefault(getError(), ErrEqualizerCreate)
85 | }
86 |
87 | return &Equalizer{equalizer: equalizer}, nil
88 | }
89 |
90 | // Release destroys the equalizer instance.
91 | func (e *Equalizer) Release() error {
92 | if err := e.assertInit(); err != nil {
93 | return nil
94 | }
95 |
96 | C.libvlc_audio_equalizer_release(e.equalizer)
97 | e.equalizer = nil
98 | return nil
99 | }
100 |
101 | // PreampValue returns the pre-amplification value of the equalizer in Hz.
102 | func (e *Equalizer) PreampValue() (float64, error) {
103 | if err := e.assertInit(); err != nil {
104 | return 0, err
105 | }
106 |
107 | value := C.libvlc_audio_equalizer_get_preamp(e.equalizer)
108 | return float64(value), nil
109 | }
110 |
111 | // SetPreampValue sets the pre-amplification value of the equalizer.
112 | // The specified amplification value is clamped to the [-20.0, 20.0] Hz range.
113 | func (e *Equalizer) SetPreampValue(value float64) error {
114 | if err := e.assertInit(); err != nil {
115 | return err
116 | }
117 |
118 | if C.libvlc_audio_equalizer_set_preamp(e.equalizer, C.float(value)) != 0 {
119 | return errOrDefault(getError(), ErrEqualizerAmpValueSet)
120 | }
121 |
122 | return nil
123 | }
124 |
125 | // AmpValueAtIndex returns the amplification value for the equalizer frequency
126 | // band with the specified index, in Hz. The index must be a number greater
127 | // than or equal to 0 and less than EqualizerBandCount().
128 | func (e *Equalizer) AmpValueAtIndex(index uint) (float64, error) {
129 | if err := e.assertInit(); err != nil {
130 | return 0, err
131 | }
132 |
133 | value := C.libvlc_audio_equalizer_get_amp_at_index(e.equalizer, C.uint(index))
134 | return float64(value), nil
135 | }
136 |
137 | // SetAmpValueAtIndex sets the amplification value for the equalizer frequency
138 | // band with the specified index, in Hz. The index must be a number greater
139 | // than or equal to 0 and less than EqualizerBandCount().
140 | func (e *Equalizer) SetAmpValueAtIndex(value float64, index uint) error {
141 | if err := e.assertInit(); err != nil {
142 | return err
143 | }
144 |
145 | if C.libvlc_audio_equalizer_set_amp_at_index(e.equalizer, C.float(value), C.uint(index)) != 0 {
146 | return errOrDefault(getError(), ErrEqualizerAmpValueSet)
147 | }
148 |
149 | return nil
150 | }
151 |
152 | func (e *Equalizer) assertInit() error {
153 | if e == nil || e.equalizer == nil {
154 | return ErrEqualizerNotInitialized
155 | }
156 |
157 | return nil
158 | }
159 |
--------------------------------------------------------------------------------
/v3/errors.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | import "errors"
4 |
5 | // Generic errors.
6 | var (
7 | ErrInvalid = errors.New("the provided value is not valid")
8 | )
9 |
10 | // Module errors.
11 | var (
12 | ErrModuleInitialize = errors.New("could not initialize module")
13 | ErrModuleNotInitialized = errors.New("module is not initialized")
14 | ErrUserInterfaceStart = errors.New("could not start user interface")
15 | )
16 |
17 | // Player errors.
18 | var (
19 | ErrPlayerCreate = errors.New("could not create player")
20 | ErrPlayerNotInitialized = errors.New("player is not initialized")
21 | ErrPlayerPlay = errors.New("cannot play the requested media")
22 | ErrPlayerSetVolume = errors.New("could not set player volume")
23 | ErrPlayerSetRenderer = errors.New("could not set player renderer")
24 | ErrPlayerSetEqualizer = errors.New("could not set player equalizer")
25 | ErrPlayerInvalidRole = errors.New("invalid player role")
26 | ErrPlayerTitleNotInitialized = errors.New("player title not initialized")
27 | ErrPlayerChapterNotInitialized = errors.New("player chapter not initialized")
28 | )
29 |
30 | // List player errors.
31 | var (
32 | ErrListPlayerCreate = errors.New("could not create list player")
33 | ErrListPlayerNotInitialized = errors.New("list player not initialized")
34 | )
35 |
36 | // Media errors.
37 | var (
38 | ErrMediaCreate = errors.New("could not create media")
39 | ErrMediaNotFound = errors.New("could not find media")
40 | ErrMediaNotInitialized = errors.New("media is not initialized")
41 | ErrMediaListCreate = errors.New("could not create media list")
42 | ErrMediaListNotFound = errors.New("could not find media list")
43 | ErrMediaListNotInitialized = errors.New("media list is not initialized")
44 | ErrMediaListReadOnly = errors.New("media list is read-only")
45 | ErrMediaListActionFailed = errors.New("could not perform media list action")
46 | ErrMissingMediaStats = errors.New("could not get media statistics")
47 | ErrInvalidMediaStats = errors.New("invalid media statistics")
48 | ErrMissingMediaLocation = errors.New("could not get media location")
49 | ErrMissingMediaDimensions = errors.New("could not get media dimensions")
50 | ErrMediaMetaSave = errors.New("could not save media metadata")
51 | ErrMediaParse = errors.New("could not parse media")
52 | ErrMediaNotParsed = errors.New("media is not parsed")
53 | )
54 |
55 | // Media track errors.
56 | var (
57 | ErrMediaTrackNotInitialized = errors.New("media track is not initialized")
58 | ErrMediaTrackNotFound = errors.New("could not find media track")
59 | ErrInvalidMediaTrack = errors.New("invalid media track")
60 | )
61 |
62 | // Event manager errors.
63 | var (
64 | ErrMissingEventManager = errors.New("could not get event manager instance")
65 | ErrInvalidEventCallback = errors.New("invalid event callback")
66 | ErrEventAttach = errors.New("could not attach event")
67 | )
68 |
69 | // Audio/Video errors.
70 | var (
71 | ErrAudioOutputListMissing = errors.New("could not get audio output list")
72 | ErrAudioOutputSet = errors.New("could not set audio output")
73 | ErrAudioOutputDeviceListMissing = errors.New("could not get audio output device list")
74 | ErrAudioOutputDeviceMissing = errors.New("could not get audio output device")
75 | ErrFilterListMissing = errors.New("could not get filter list")
76 | ErrStereoModeSet = errors.New("could not set stereo mode")
77 | ErrVideoViewpointSet = errors.New("could not set video viewpoint")
78 | ErrVideoSnapshot = errors.New("could not take video snapshot")
79 | ErrCursorPositionMissing = errors.New("could not get cursor position")
80 | )
81 |
82 | // Renderer discoverer errors.
83 | var (
84 | ErrRendererDiscovererParse = errors.New("could not parse renderer discoverer")
85 | ErrRendererDiscovererCreate = errors.New("could not create renderer discoverer")
86 | ErrRendererDiscovererNotInitialized = errors.New("renderer discoverer not initialized")
87 | ErrRendererDiscovererStart = errors.New("could not start renderer discoverer")
88 | ErrRendererNotInitialized = errors.New("renderer not initialized")
89 | )
90 |
91 | // Media discoverer errors.
92 | var (
93 | ErrMediaDiscovererParse = errors.New("could not parse media discoverer")
94 | ErrMediaDiscovererCreate = errors.New("could not create media discoverer")
95 | ErrMediaDiscovererNotInitialized = errors.New("media discoverer not initialized")
96 | ErrMediaDiscovererStart = errors.New("could not start media discoverer")
97 | )
98 |
99 | // Equalizer errors.
100 | var (
101 | ErrEqualizerCreate = errors.New("could not create equalizer")
102 | ErrEqualizerNotInitialized = errors.New("equalizer not initialized")
103 | ErrEqualizerAmpValueSet = errors.New("could not set equalizer amplification value")
104 | )
105 |
--------------------------------------------------------------------------------
/v3/event_manager.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | /*
4 | #cgo LDFLAGS: -lvlc
5 | #include
6 |
7 | typedef const libvlc_event_t constev;
8 | extern void eventDispatch(constev*, void*);
9 |
10 | static inline int eventAttach(libvlc_event_manager_t* em, libvlc_event_type_t et, unsigned long userData) {
11 | return libvlc_event_attach(em, et, eventDispatch, (void*)userData);
12 | }
13 | static inline int eventDetach(libvlc_event_manager_t* em, libvlc_event_type_t et, unsigned long userData) {
14 | libvlc_event_detach(em, et, eventDispatch, (void*)userData);
15 | }
16 | */
17 | import "C"
18 |
19 | import (
20 | "unsafe"
21 | )
22 |
23 | // EventManager wraps a libvlc event manager.
24 | type EventManager struct {
25 | manager *C.libvlc_event_manager_t
26 | }
27 |
28 | // newEventManager returns a new event manager instance.
29 | func newEventManager(manager *C.libvlc_event_manager_t) *EventManager {
30 | return &EventManager{
31 | manager: manager,
32 | }
33 | }
34 |
35 | // Attach registers a callback for an event notification.
36 | func (em *EventManager) Attach(event Event, callback EventCallback, userData interface{}) (EventID, error) {
37 | return em.attach(event, callback, nil, userData)
38 | }
39 |
40 | // attach registers callbacks for an event notification.
41 | func (em *EventManager) attach(event Event, externalCallback EventCallback,
42 | internalCallback internalEventCallback, userData interface{}) (EventID, error) {
43 | if err := inst.assertInit(); err != nil {
44 | return 0, err
45 | }
46 | if externalCallback == nil && internalCallback == nil {
47 | return 0, ErrInvalidEventCallback
48 | }
49 |
50 | id := inst.events.add(event, externalCallback, internalCallback, userData)
51 | if C.eventAttach(em.manager, C.libvlc_event_type_t(event), C.ulong(id)) != 0 {
52 | return 0, errOrDefault(getError(), ErrEventAttach)
53 | }
54 |
55 | return id, nil
56 | }
57 |
58 | // Detach unregisters the specified event notification.
59 | func (em *EventManager) Detach(eventIDs ...EventID) {
60 | if err := inst.assertInit(); err != nil {
61 | return
62 | }
63 |
64 | for _, eventID := range eventIDs {
65 | ctx, ok := inst.events.get(eventID)
66 | if !ok {
67 | continue
68 | }
69 |
70 | inst.events.remove(eventID)
71 | C.eventDetach(em.manager, C.libvlc_event_type_t(ctx.event), C.ulong(eventID))
72 | }
73 | }
74 |
75 | //export eventDispatch
76 | func eventDispatch(event *C.constev, userData unsafe.Pointer) {
77 | if err := inst.assertInit(); err != nil {
78 | return
79 | }
80 |
81 | ctx, ok := inst.events.get(EventID(uintptr(userData)))
82 | if !ok {
83 | return
84 | }
85 |
86 | // Execute external callback.
87 | if ctx.externalCallback != nil {
88 | ctx.externalCallback(ctx.event, ctx.userData)
89 | }
90 |
91 | // Execute internal callback.
92 | if ctx.internalCallback != nil {
93 | ctx.internalCallback(event, ctx.userData)
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/v3/event_registry.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | import "C"
6 | import "sync"
7 |
8 | // EventID uniquely identifies a registered event.
9 | type EventID uint64
10 |
11 | // EventCallback represents an event notification callback function.
12 | type EventCallback func(Event, interface{})
13 |
14 | type internalEventCallback func(*C.libvlc_event_t, interface{})
15 |
16 | type eventContext struct {
17 | event Event
18 | externalCallback EventCallback
19 | internalCallback internalEventCallback
20 | userData interface{}
21 | }
22 |
23 | type eventRegistry struct {
24 | sync.RWMutex
25 |
26 | contexts map[EventID]*eventContext
27 | sequence EventID
28 | }
29 |
30 | func newEventRegistry() *eventRegistry {
31 | return &eventRegistry{
32 | contexts: map[EventID]*eventContext{},
33 | }
34 | }
35 |
36 | func (er *eventRegistry) get(id EventID) (*eventContext, bool) {
37 | if id == 0 {
38 | return nil, false
39 | }
40 |
41 | er.RLock()
42 | ctx, ok := er.contexts[id]
43 | er.RUnlock()
44 |
45 | return ctx, ok
46 | }
47 |
48 | func (er *eventRegistry) add(event Event, externalCallback EventCallback,
49 | internalCallback internalEventCallback, userData interface{}) EventID {
50 | er.Lock()
51 |
52 | er.sequence++
53 | id := er.sequence
54 |
55 | er.contexts[id] = &eventContext{
56 | event: event,
57 | externalCallback: externalCallback,
58 | internalCallback: internalCallback,
59 | userData: userData,
60 | }
61 |
62 | er.Unlock()
63 | return id
64 | }
65 |
66 | func (er *eventRegistry) remove(id EventID) {
67 | if id == 0 {
68 | return
69 | }
70 |
71 | er.Lock()
72 | delete(er.contexts, id)
73 | er.Unlock()
74 | }
75 |
--------------------------------------------------------------------------------
/v3/events.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // Event represents an event that can occur inside libvlc.
4 | type Event int
5 |
6 | // Media events.
7 | const (
8 | // MediaMetaChanged is triggered when the metadata of a media item changes.
9 | MediaMetaChanged Event = iota
10 |
11 | // MediaSubItemAdded is triggered when a Subitem is added to a media item.
12 | MediaSubItemAdded
13 |
14 | // MediaDurationChanged is triggered when the duration
15 | // of a media item changes.
16 | MediaDurationChanged
17 |
18 | // MediaParsedChanged is triggered when the parsing state
19 | // of a media item changes.
20 | MediaParsedChanged
21 |
22 | // MediaFreed is triggered when a media item is freed.
23 | MediaFreed
24 |
25 | // MediaStateChanged is triggered when the state of the media item changes.
26 | MediaStateChanged
27 |
28 | // MediaSubItemTreeAdded is triggered when a Subitem tree is
29 | // added to a media item.
30 | MediaSubItemTreeAdded
31 |
32 | // MediaThumbnailGenerated is triggered when a thumbnail
33 | // generation is completed.
34 | MediaThumbnailGenerated
35 | )
36 |
37 | // Player events.
38 | const (
39 | MediaPlayerMediaChanged Event = 0x100 + iota
40 | MediaPlayerNothingSpecial
41 | MediaPlayerOpening
42 | MediaPlayerBuffering
43 | MediaPlayerPlaying
44 | MediaPlayerPaused
45 | MediaPlayerStopped
46 | MediaPlayerForward
47 | MediaPlayerBackward
48 | MediaPlayerEndReached
49 | MediaPlayerEncounteredError
50 | MediaPlayerTimeChanged
51 | MediaPlayerPositionChanged
52 | MediaPlayerSeekableChanged
53 | MediaPlayerPausableChanged
54 | MediaPlayerTitleChanged
55 | MediaPlayerSnapshotTaken
56 | MediaPlayerLengthChanged
57 | MediaPlayerVout
58 | MediaPlayerScrambledChanged
59 | MediaPlayerESAdded
60 | MediaPlayerESDeleted
61 | MediaPlayerESSelected
62 | MediaPlayerCorked
63 | MediaPlayerUncorked
64 | MediaPlayerMuted
65 | MediaPlayerUnmuted
66 | MediaPlayerAudioVolume
67 | MediaPlayerAudioDevice
68 | MediaPlayerChapterChanged
69 | )
70 |
71 | // Media list events.
72 | const (
73 | // MediaListItemAdded is triggered when a media item is added to a media list.
74 | MediaListItemAdded Event = 0x200 + iota
75 |
76 | // MediaListWillAddItem is triggered when a media item is about to get
77 | // added to a media list.
78 | MediaListWillAddItem
79 |
80 | // MediaListItemDeleted is triggered when a media item is deleted
81 | // from a media list.
82 | MediaListItemDeleted
83 |
84 | // MediaListWillDeleteItem is triggered when a media item is about to get
85 | // deleted from a media list.
86 | MediaListWillDeleteItem
87 |
88 | // MediaListEndReached is triggered when a media list has reached the end.
89 | MediaListEndReached
90 | )
91 |
92 | // Deprecated events.
93 | const (
94 | MediaListViewItemAdded = 0x300 + iota
95 | MediaListViewWillAddItem
96 | MediaListViewItemDeleted
97 | MediaListViewWillDeleteItem
98 | )
99 |
100 | const (
101 | // MediaListPlayerPlayed is triggered when playback of the media list
102 | // of the list player has ended.
103 | MediaListPlayerPlayed = 0x400 + iota
104 |
105 | // MediaListPlayerNextItemSet is triggered when the current item
106 | // of a media list player has changed to a different item.
107 | MediaListPlayerNextItemSet
108 |
109 | // MediaListPlayerStopped is triggered when playback
110 | // of a media list player is stopped programmatically.
111 | MediaListPlayerStopped
112 | )
113 |
114 | // Deprecated events.
115 | const (
116 | MediaDiscovererStarted Event = 0x500 + iota
117 | MediaDiscovererEnded
118 | )
119 |
120 | // Renderer events.
121 | const (
122 | // RendererDiscovererItemAdded is triggered when a new renderer item is
123 | // found by a renderer discoverer. The renderer item is valid until deleted.
124 | RendererDiscovererItemAdded Event = 0x502 + iota
125 |
126 | // RendererDiscovererItemDeleted is triggered when a previously discovered
127 | // renderer item was deleted by a renderer discoverer. The renderer item
128 | // is no longer valid.
129 | RendererDiscovererItemDeleted
130 | )
131 |
132 | // VideoLAN Manager events.
133 | const (
134 | VlmMediaAdded Event = 0x600 + iota
135 | VlmMediaRemoved
136 | VlmMediaChanged
137 | VlmMediaInstanceStarted
138 | VlmMediaInstanceStopped
139 | VlmMediaInstanceStatusInit
140 | VlmMediaInstanceStatusOpening
141 | VlmMediaInstanceStatusPlaying
142 | VlmMediaInstanceStatusPause
143 | VlmMediaInstanceStatusEnd
144 | VlmMediaInstanceStatusError
145 | )
146 |
--------------------------------------------------------------------------------
/v3/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/adrg/libvlc-go/v3
2 |
3 | go 1.13
4 |
--------------------------------------------------------------------------------
/v3/list_player.go:
--------------------------------------------------------------------------------
1 | //go:build !legacy
2 | // +build !legacy
3 |
4 | package vlc
5 |
6 | // #cgo LDFLAGS: -lvlc
7 | // #include
8 | // #include
9 | import "C"
10 |
11 | // PlaybackMode defines playback modes for a media list.
12 | type PlaybackMode uint
13 |
14 | // Playback modes.
15 | const (
16 | Default PlaybackMode = iota
17 | Loop
18 | Repeat
19 | )
20 |
21 | // Validate checks if the playback mode valid.
22 | func (pm PlaybackMode) Validate() error {
23 | if pm > Repeat {
24 | return ErrInvalid
25 | }
26 |
27 | return nil
28 | }
29 |
30 | // ListPlayer is an enhanced media player used to play media lists.
31 | type ListPlayer struct {
32 | player *C.libvlc_media_list_player_t
33 | list *MediaList
34 | }
35 |
36 | // NewListPlayer creates a new list player instance.
37 | func NewListPlayer() (*ListPlayer, error) {
38 | if err := inst.assertInit(); err != nil {
39 | return nil, err
40 | }
41 |
42 | player := C.libvlc_media_list_player_new(inst.handle)
43 | if player == nil {
44 | return nil, errOrDefault(getError(), ErrListPlayerCreate)
45 | }
46 |
47 | return &ListPlayer{player: player}, nil
48 | }
49 |
50 | // Release destroys the list player instance.
51 | func (lp *ListPlayer) Release() error {
52 | if err := lp.assertInit(); err != nil {
53 | return nil
54 | }
55 |
56 | C.libvlc_media_list_player_release(lp.player)
57 | lp.player = nil
58 |
59 | return nil
60 | }
61 |
62 | // Player returns the underlying Player instance of the list player.
63 | func (lp *ListPlayer) Player() (*Player, error) {
64 | if err := lp.assertInit(); err != nil {
65 | return nil, err
66 | }
67 |
68 | player := C.libvlc_media_list_player_get_media_player(lp.player)
69 | if player == nil {
70 | return nil, errOrDefault(getError(), ErrPlayerNotInitialized)
71 | }
72 |
73 | // This call will not release the player. Instead, it will decrement the
74 | // reference count increased by libvlc_media_list_player_get_media_player.
75 | C.libvlc_media_player_release(player)
76 |
77 | return &Player{player: player}, nil
78 | }
79 |
80 | // SetPlayer sets the underlying Player instance of the list player.
81 | func (lp *ListPlayer) SetPlayer(player *Player) error {
82 | if err := lp.assertInit(); err != nil {
83 | return err
84 | }
85 | if err := player.assertInit(); err != nil {
86 | return err
87 | }
88 |
89 | C.libvlc_media_list_player_set_media_player(lp.player, player.player)
90 | return nil
91 | }
92 |
93 | // Play plays the current media list.
94 | func (lp *ListPlayer) Play() error {
95 | if err := lp.assertInit(); err != nil {
96 | return err
97 | }
98 | if lp.IsPlaying() {
99 | return nil
100 | }
101 |
102 | C.libvlc_media_list_player_play(lp.player)
103 | return getError()
104 | }
105 |
106 | // PlayNext plays the next media in the current media list.
107 | func (lp *ListPlayer) PlayNext() error {
108 | if err := lp.assertInit(); err != nil {
109 | return err
110 | }
111 |
112 | if C.libvlc_media_list_player_next(lp.player) < 0 {
113 | return errOrDefault(getError(), ErrPlayerPlay)
114 | }
115 |
116 | return nil
117 | }
118 |
119 | // PlayPrevious plays the previous media in the current media list.
120 | func (lp *ListPlayer) PlayPrevious() error {
121 | if err := lp.assertInit(); err != nil {
122 | return err
123 | }
124 |
125 | if C.libvlc_media_list_player_previous(lp.player) < 0 {
126 | return errOrDefault(getError(), ErrPlayerPlay)
127 | }
128 |
129 | return nil
130 | }
131 |
132 | // PlayAtIndex plays the media at the specified index from the
133 | // current media list.
134 | func (lp *ListPlayer) PlayAtIndex(index uint) error {
135 | if err := lp.assertInit(); err != nil {
136 | return err
137 | }
138 |
139 | idx := C.int(index)
140 | if C.libvlc_media_list_player_play_item_at_index(lp.player, idx) < 0 {
141 | return errOrDefault(getError(), ErrPlayerPlay)
142 | }
143 |
144 | return nil
145 | }
146 |
147 | // PlayItem plays the specified media item. The item must be part of the
148 | // current media list of the player.
149 | func (lp *ListPlayer) PlayItem(m *Media) error {
150 | if err := lp.assertInit(); err != nil {
151 | return err
152 | }
153 | if err := m.assertInit(); err != nil {
154 | return err
155 | }
156 |
157 | if C.libvlc_media_list_player_play_item(lp.player, m.media) < 0 {
158 | return errOrDefault(getError(), ErrMediaNotFound)
159 | }
160 |
161 | return nil
162 | }
163 |
164 | // IsPlaying returns a boolean value specifying if the player is currently
165 | // playing.
166 | func (lp *ListPlayer) IsPlaying() bool {
167 | if err := lp.assertInit(); err != nil {
168 | return false
169 | }
170 |
171 | return C.libvlc_media_list_player_is_playing(lp.player) != 0
172 | }
173 |
174 | // Stop cancels the currently playing media list, if there is one.
175 | func (lp *ListPlayer) Stop() error {
176 | if err := lp.assertInit(); err != nil {
177 | return err
178 | }
179 |
180 | C.libvlc_media_list_player_stop(lp.player)
181 | return getError()
182 | }
183 |
184 | // SetPause sets the pause state of the list player.
185 | // Pass in `true` to pause the current media, or `false` to resume it.
186 | func (lp *ListPlayer) SetPause(pause bool) error {
187 | if err := lp.assertInit(); err != nil {
188 | return err
189 | }
190 |
191 | C.libvlc_media_list_player_set_pause(lp.player, C.int(boolToInt(pause)))
192 | return getError()
193 | }
194 |
195 | // TogglePause pauses/resumes the player.
196 | // Calling this method has no effect if there is no media.
197 | func (lp *ListPlayer) TogglePause() error {
198 | if err := lp.assertInit(); err != nil {
199 | return err
200 | }
201 |
202 | C.libvlc_media_list_player_pause(lp.player)
203 | return getError()
204 | }
205 |
206 | // SetPlaybackMode sets the player playback mode for the media list.
207 | // By default, it plays the media list once and then stops.
208 | func (lp *ListPlayer) SetPlaybackMode(mode PlaybackMode) error {
209 | if err := lp.assertInit(); err != nil {
210 | return err
211 | }
212 | if err := mode.Validate(); err != nil {
213 | return err
214 | }
215 |
216 | C.libvlc_media_list_player_set_playback_mode(
217 | lp.player,
218 | C.libvlc_playback_mode_t(mode),
219 | )
220 | return nil
221 | }
222 |
223 | // MediaState returns the state of the current media.
224 | func (lp *ListPlayer) MediaState() (MediaState, error) {
225 | if err := lp.assertInit(); err != nil {
226 | return MediaNothingSpecial, err
227 | }
228 |
229 | return MediaState(C.libvlc_media_list_player_get_state(lp.player)), nil
230 | }
231 |
232 | // MediaList returns the current media list of the player, if one exists.
233 | func (lp *ListPlayer) MediaList() *MediaList {
234 | return lp.list
235 | }
236 |
237 | // SetMediaList sets the media list to be played.
238 | func (lp *ListPlayer) SetMediaList(ml *MediaList) error {
239 | if err := lp.assertInit(); err != nil {
240 | return err
241 | }
242 | if err := ml.assertInit(); err != nil {
243 | return err
244 | }
245 |
246 | lp.list = ml
247 | C.libvlc_media_list_player_set_media_list(lp.player, ml.list)
248 | return nil
249 | }
250 |
251 | // EventManager returns the event manager responsible for the list player.
252 | func (lp *ListPlayer) EventManager() (*EventManager, error) {
253 | if err := lp.assertInit(); err != nil {
254 | return nil, err
255 | }
256 |
257 | manager := C.libvlc_media_list_player_event_manager(lp.player)
258 | if manager == nil {
259 | return nil, ErrMissingEventManager
260 | }
261 |
262 | return newEventManager(manager), nil
263 | }
264 |
265 | func (lp *ListPlayer) assertInit() error {
266 | if lp == nil || lp.player == nil {
267 | return ErrListPlayerNotInitialized
268 | }
269 |
270 | return nil
271 | }
272 |
--------------------------------------------------------------------------------
/v3/logo.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | /*
4 | #cgo LDFLAGS: -lvlc
5 | #include
6 | #include
7 | */
8 | import "C"
9 | import (
10 | "fmt"
11 | "image"
12 | "image/png"
13 | "os"
14 | "strings"
15 | "time"
16 | "unsafe"
17 | )
18 |
19 | // LogoFile represents a logo file which can be used as a media player's logo.
20 | // The logo of a player can also be composed of a series of alternating files.
21 | type LogoFile struct {
22 | path string
23 | displayDuration time.Duration
24 | opacity int
25 | }
26 |
27 | // NewLogoFileFromPath returns a new logo file with the specified path.
28 | // The file is displyed for the provided duration. If the specified display
29 | // duration is negative, the global display duration set on the logo the file
30 | // is applied to is used.
31 | // The provided opacity must be a value between 0 (transparent) and 255 (opaque).
32 | // If the specified opacity is negative, the global opacity set on the logo
33 | // the file is applied to is used.
34 | func NewLogoFileFromPath(path string, displayDuration time.Duration, opacity int) (*LogoFile, error) {
35 | if path == "" {
36 | return nil, ErrInvalid
37 | }
38 |
39 | return &LogoFile{
40 | path: path,
41 | displayDuration: displayDuration,
42 | opacity: opacity,
43 | }, nil
44 | }
45 |
46 | // NewLogoFileFromImage returns a new logo file with the specified image.
47 | // The file is displyed for the provided duration. If the specified display
48 | // duration is negative, the global display duration set on the logo the file
49 | // is applied to is used.
50 | // The provided opacity must be a value between 0 (transparent) and 255 (opaque).
51 | // If the specified opacity is negative, the global opacity set on the logo
52 | // the file is applied to is used.
53 | func NewLogoFileFromImage(img image.Image, displayDuration time.Duration, opacity int) (*LogoFile, error) {
54 | if img == nil {
55 | return nil, ErrInvalid
56 | }
57 |
58 | // Create temporary file.
59 | f, err := os.CreateTemp("", "logo_*.png")
60 | if err != nil {
61 | return nil, err
62 | }
63 |
64 | // Encode logo image to temporary file.
65 | if err := png.Encode(f, img); err != nil {
66 | return nil, err
67 | }
68 |
69 | // Close temporary file.
70 | path := f.Name()
71 | if err := f.Close(); err != nil {
72 | return nil, err
73 | }
74 |
75 | return NewLogoFileFromPath(path, displayDuration, opacity)
76 | }
77 |
78 | // Logo represents a logo that can be displayed over a media instance.
79 | //
80 | // For more information see https://wiki.videolan.org/Documentation:Modules/logo.
81 | type Logo struct {
82 | player *Player
83 | }
84 |
85 | func newLogo(player *Player) *Logo {
86 | return &Logo{
87 | player: player,
88 | }
89 | }
90 |
91 | // Enable enables or disables the logo. By default, the logo is disabled.
92 | func (l *Logo) Enable(enable bool) error {
93 | return l.setInt(C.libvlc_logo_enable, boolToInt(enable))
94 | }
95 |
96 | // SetFiles sets the sequence of files to be displayed for the logo.
97 | func (l *Logo) SetFiles(files ...*LogoFile) error {
98 | fileFmts := make([]string, 0, len(files))
99 | for _, file := range files {
100 | if file == nil {
101 | continue
102 | }
103 | fileFmt := file.path
104 | if file.displayDuration >= 0 {
105 | fileFmt = fmt.Sprintf("%s,%d", fileFmt, file.displayDuration.Milliseconds())
106 | }
107 | if file.opacity >= 0 {
108 | fileFmt = fmt.Sprintf("%s,%d", fileFmt, file.opacity)
109 | }
110 |
111 | fileFmts = append(fileFmts, fileFmt)
112 | }
113 |
114 | if len(fileFmts) == 0 {
115 | return nil
116 | }
117 |
118 | return l.setString(C.libvlc_logo_file, strings.Join(fileFmts, ";"))
119 | }
120 |
121 | // Position returns the position of the logo, relative to its container.
122 | // Default: vlc.PositionTopLeft.
123 | func (l *Logo) Position() (Position, error) {
124 | iVal, err := l.getInt(C.libvlc_logo_position)
125 | if err != nil {
126 | return PositionDisable, err
127 | }
128 |
129 | switch {
130 | case iVal >= 8:
131 | iVal -= 2
132 | case iVal >= 4:
133 | iVal--
134 | }
135 |
136 | if iVal < 0 {
137 | return PositionTopLeft, nil
138 | }
139 | return Position(iVal), nil
140 | }
141 |
142 | // SetPosition sets the position of the logo, relative to its container.
143 | func (l *Logo) SetPosition(position Position) error {
144 | switch {
145 | case position >= PositionBottom:
146 | position += 2
147 | case position >= PositionTop:
148 | position++
149 | }
150 |
151 | return l.setInt(C.libvlc_logo_position, int(position))
152 | }
153 |
154 | // X returns the X coordinate of the logo. The returned value is
155 | // relative to the position of the logo inside its container, i.e. the
156 | // position set using Logo.SetPosition method.
157 | // Default: 0.
158 | func (l *Logo) X() (int, error) {
159 | return l.getInt(C.libvlc_logo_x)
160 | }
161 |
162 | // SetX sets the X coordinate of the logo. The value is specified
163 | // relative to the position of the logo inside its container, i.e. the
164 | // position set using the `Logo.SetPosition` method.
165 | //
166 | // NOTE: the method has no effect if the position of the logo is set to
167 | // `vlc.PositionCenter`, `vlc.PositionTop` or `vlc.PositionBottom`.
168 | func (l *Logo) SetX(x int) error {
169 | return l.setInt(C.libvlc_logo_x, x)
170 | }
171 |
172 | // Y returns the Y coordinate of the logo. The returned value is
173 | // relative to the position of the logo inside its container, i.e. the
174 | // position set using the `Logo.SetPosition` method.
175 | // Default: 0.
176 | func (l *Logo) Y() (int, error) {
177 | return l.getInt(C.libvlc_logo_y)
178 | }
179 |
180 | // SetY sets the Y coordinate of the logo. The value is specified
181 | // relative to the position of the logo inside its container.
182 | //
183 | // NOTE: the method has no effect if the position of the logo is set to
184 | // `vlc.PositionCenter`, `vlc.PositionLeft` or `vlc.PositionRight`.
185 | func (l *Logo) SetY(y int) error {
186 | return l.setInt(C.libvlc_logo_y, y)
187 | }
188 |
189 | // Opacity returns the global opacity of the logo.
190 | // The returned opacity is a value between 0 (transparent) and 255 (opaque).
191 | // The global opacity can be overridden by each provided logo file.
192 | // Default: 255.
193 | func (l *Logo) Opacity() (int, error) {
194 | return l.getInt(C.libvlc_logo_opacity)
195 | }
196 |
197 | // SetOpacity sets the global opacity of the logo. If an opacity override is
198 | // not specified when setting the logo files, the global opacity is used. The
199 | // opacity is specified as an integer between 0 (transparent) and 255 (opaque).
200 | // The global opacity can be overridden by each provided logo file.
201 | func (l *Logo) SetOpacity(opacity int) error {
202 | return l.setInt(C.libvlc_logo_opacity, opacity)
203 | }
204 |
205 | // DisplayDuration returns the global duration for which a logo file
206 | // is set to be displayed before displaying the next one (if one is available).
207 | // The global display duration can be overridden by each provided logo file.
208 | // Default: 1s.
209 | func (l *Logo) DisplayDuration() (time.Duration, error) {
210 | iVal, err := l.getInt(C.libvlc_logo_delay)
211 | return time.Duration(iVal) * time.Millisecond, err
212 | }
213 |
214 | // SetDisplayDuration sets the duration for which to display a logo file
215 | // before displaying the next one (if one is available).
216 | // The global display duration can be overridden by each provided logo file.
217 | func (l *Logo) SetDisplayDuration(displayDuration time.Duration) error {
218 | return l.setInt(C.libvlc_logo_delay, int(displayDuration.Milliseconds()))
219 | }
220 |
221 | // RepeatCount returns the number of times the logo sequence is set
222 | // to be repeated.
223 | func (l *Logo) RepeatCount() (int, error) {
224 | return l.getInt(C.libvlc_logo_repeat)
225 | }
226 |
227 | // SetRepeatCount sets the number of times the logo sequence should repeat.
228 | // Pass in `-1` to repeat the logo sequence indefinitely, `0` to disable logo
229 | // sequence looping or a positive number to repeat the logo sequence a specific
230 | // number of times.
231 | // Default: -1 (the logo sequence is repeated indefinitely).
232 | func (l *Logo) SetRepeatCount(count int) error {
233 | if count > 0 {
234 | count++
235 | }
236 |
237 | return l.setInt(C.libvlc_logo_repeat, count)
238 | }
239 |
240 | func (l *Logo) getInt(option C.uint) (int, error) {
241 | if err := l.player.assertInit(); err != nil {
242 | return 0, err
243 | }
244 |
245 | return int(C.libvlc_video_get_logo_int(l.player.player, option)), nil
246 | }
247 |
248 | func (l *Logo) setInt(option C.uint, val int) error {
249 | if err := l.player.assertInit(); err != nil {
250 | return err
251 | }
252 |
253 | C.libvlc_video_set_logo_int(l.player.player, option, C.int(val))
254 | return nil
255 | }
256 |
257 | func (l *Logo) setString(option C.uint, val string) error {
258 | if err := l.player.assertInit(); err != nil {
259 | return err
260 | }
261 |
262 | cVal := C.CString(val)
263 | defer C.free(unsafe.Pointer(cVal))
264 |
265 | C.libvlc_video_set_logo_string(l.player.player, option, cVal)
266 | return nil
267 | }
268 |
--------------------------------------------------------------------------------
/v3/marquee.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | /*
4 | #cgo LDFLAGS: -lvlc
5 | #include
6 | #include
7 | */
8 | import "C"
9 | import (
10 | "image/color"
11 | "time"
12 | "unsafe"
13 | )
14 |
15 | // Marquee represents a marquee text than can be displayed over a media
16 | // instance, along with its visual properties.
17 | //
18 | // For more information see https://wiki.videolan.org/Documentation:Modules/marq.
19 | type Marquee struct {
20 | player *Player
21 | }
22 |
23 | func newMarquee(player *Player) *Marquee {
24 | return &Marquee{
25 | player: player,
26 | }
27 | }
28 |
29 | // Enable enables or disables the marquee. By default, the marquee is disabled.
30 | func (m *Marquee) Enable(enable bool) error {
31 | return m.setInt(C.libvlc_marquee_Enable, boolToInt(enable))
32 | }
33 |
34 | // Text returns the marquee text.
35 | // Default: "".
36 | func (m *Marquee) Text() (string, error) {
37 | return m.getString(C.libvlc_marquee_Text)
38 | }
39 |
40 | // SetText sets the marquee text.
41 | // The specified text can contain time format string sequences which are
42 | // converted to the requested time values at runtime. Most of the time
43 | // conversion specifiers supported by the `strftime` C function can be used.
44 | //
45 | // Common time format string sequences:
46 | // %Y = year, %m = month, %d = day, %H = hour, %M = minute, %S = second.
47 | // For more information see https://en.cppreference.com/w/c/chrono/strftime.
48 | func (m *Marquee) SetText(text string) error {
49 | return m.setString(C.libvlc_marquee_Text, text)
50 | }
51 |
52 | // Color returns the marquee text color.
53 | // Opacity information is included in the returned color.
54 | // Default: white.
55 | func (m *Marquee) Color() (color.Color, error) {
56 | // Get color.
57 | rgb, err := m.getInt(C.libvlc_marquee_Color)
58 | if err != nil {
59 | return nil, err
60 | }
61 |
62 | // Get alpha.
63 | alpha, err := m.getInt(C.libvlc_marquee_Opacity)
64 | if err != nil {
65 | return nil, err
66 | }
67 |
68 | return color.RGBA{
69 | R: uint8((rgb >> 16) & 0x0ff),
70 | G: uint8((rgb >> 8) & 0x0ff),
71 | B: uint8((rgb) & 0x0ff),
72 | A: uint8(alpha & 0x0ff),
73 | }, err
74 | }
75 |
76 | // SetColor sets the color of the marquee text. The opacity of the text
77 | // is also set, based on the alpha value of the color.
78 | func (m *Marquee) SetColor(color color.Color) error {
79 | r, g, b, a := color.RGBA()
80 |
81 | // Set color.
82 | rgb := int((((r >> 8) & 0x0ff) << 16) |
83 | (((g >> 8) & 0x0ff) << 8) |
84 | ((b >> 8) & 0x0ff))
85 | if err := m.setInt(C.libvlc_marquee_Color, rgb); err != nil {
86 | return err
87 | }
88 |
89 | // Set alpha.
90 | alpha := int((a >> 8) & 0x0ff)
91 | if err := m.setInt(C.libvlc_marquee_Opacity, alpha); err != nil {
92 | return err
93 | }
94 |
95 | return nil
96 | }
97 |
98 | // Opacity returns the opacity of the marquee text.
99 | // The returned opacity is a value between 0 (transparent) and 255 (opaque).
100 | // Default: 255.
101 | func (m *Marquee) Opacity() (int, error) {
102 | return m.getInt(C.libvlc_marquee_Opacity)
103 | }
104 |
105 | // SetOpacity sets the opacity of the marquee text. The opacity is specified
106 | // as an integer between 0 (transparent) and 255 (opaque).
107 | func (m *Marquee) SetOpacity(opacity int) error {
108 | return m.setInt(C.libvlc_marquee_Opacity, opacity)
109 | }
110 |
111 | // Position returns the position of the marquee, relative to its container.
112 | // Default: vlc.PositionTopLeft.
113 | func (m *Marquee) Position() (Position, error) {
114 | iVal, err := m.getInt(C.libvlc_marquee_Position)
115 | if err != nil {
116 | return PositionDisable, err
117 | }
118 |
119 | switch {
120 | case iVal >= 8:
121 | iVal -= 2
122 | case iVal >= 4:
123 | iVal--
124 | }
125 |
126 | if iVal < 0 {
127 | return PositionTopLeft, nil
128 | }
129 | return Position(iVal), nil
130 | }
131 |
132 | // SetPosition sets the position of the marquee, relative to its container.
133 | func (m *Marquee) SetPosition(position Position) error {
134 | switch {
135 | case position >= PositionBottom:
136 | position += 2
137 | case position >= PositionTop:
138 | position++
139 | }
140 |
141 | return m.setInt(C.libvlc_marquee_Position, int(position))
142 | }
143 |
144 | // X returns the X coordinate of the marquee text. The returned value is
145 | // relative to the position of the marquee inside its container, i.e. the
146 | // position set using the `Marquee.SetPosition` method.
147 | // Default: 0.
148 | func (m *Marquee) X() (int, error) {
149 | return m.getInt(C.libvlc_marquee_X)
150 | }
151 |
152 | // SetX sets the X coordinate of the marquee text. The value is specified
153 | // relative to the position of the marquee inside its container.
154 | //
155 | // NOTE: the method has no effect if the position of the marquee is set to
156 | // `vlc.PositionCenter`, `vlc.PositionTop` or `vlc.PositionBottom`.
157 | func (m *Marquee) SetX(x int) error {
158 | return m.setInt(C.libvlc_marquee_X, x)
159 | }
160 |
161 | // Y returns the Y coordinate of the marquee text. The returned value is
162 | // relative to the position of the marquee inside its container, i.e. the
163 | // position set using the `Marquee.SetPosition` method.
164 | // Default: 0.
165 | func (m *Marquee) Y() (int, error) {
166 | return m.getInt(C.libvlc_marquee_Y)
167 | }
168 |
169 | // SetY sets the Y coordinate of the marquee text. The value is specified
170 | // relative to the position of the marquee inside its container.
171 | //
172 | // NOTE: the method has no effect if the position of the marquee is set to
173 | // `vlc.PositionCenter`, `vlc.PositionLeft` or `vlc.PositionRight`.
174 | func (m *Marquee) SetY(y int) error {
175 | return m.setInt(C.libvlc_marquee_Y, y)
176 | }
177 |
178 | // Size returns the font size used to render the marquee text.
179 | // Default: 0 (default font size is used).
180 | func (m *Marquee) Size() (int, error) {
181 | return m.getInt(C.libvlc_marquee_Size)
182 | }
183 |
184 | // SetSize sets the font size used to render the marquee text.
185 | func (m *Marquee) SetSize(size int) error {
186 | return m.setInt(C.libvlc_marquee_Size, size)
187 | }
188 |
189 | // RefreshInterval returns the interval between marquee text updates.
190 | // The marquee text refreshes mainly when using time format string sequences.
191 | // Default: 1s.
192 | func (m *Marquee) RefreshInterval() (time.Duration, error) {
193 | iVal, err := m.getInt(C.libvlc_marquee_Refresh)
194 | return time.Duration(iVal) * time.Millisecond, err
195 | }
196 |
197 | // SetRefreshInterval sets the interval between marquee text updates.
198 | // The marquee text refreshes mainly when using time format string sequences.
199 | func (m *Marquee) SetRefreshInterval(refreshInterval time.Duration) error {
200 | return m.setInt(C.libvlc_marquee_Refresh, int(refreshInterval.Milliseconds()))
201 | }
202 |
203 | // DisplayDuration returns the duration for which the marquee text
204 | // is set to be displayed.
205 | // Default: 0 (the marquee is displayed indefinitely).
206 | func (m *Marquee) DisplayDuration() (time.Duration, error) {
207 | iVal, err := m.getInt(C.libvlc_marquee_Timeout)
208 | return time.Duration(iVal) * time.Millisecond, err
209 | }
210 |
211 | // SetDisplayDuration sets the duration for which to display the marquee text.
212 | func (m *Marquee) SetDisplayDuration(displayDuration time.Duration) error {
213 | return m.setInt(C.libvlc_marquee_Timeout, int(displayDuration.Milliseconds()))
214 | }
215 |
216 | func (m *Marquee) getInt(option C.uint) (int, error) {
217 | if err := m.player.assertInit(); err != nil {
218 | return 0, err
219 | }
220 |
221 | return int(C.libvlc_video_get_marquee_int(m.player.player, option)), nil
222 | }
223 |
224 | func (m *Marquee) setInt(option C.uint, val int) error {
225 | if err := m.player.assertInit(); err != nil {
226 | return err
227 | }
228 |
229 | C.libvlc_video_set_marquee_int(m.player.player, option, C.int(val))
230 | return nil
231 | }
232 |
233 | func (m *Marquee) getString(option C.uint) (string, error) {
234 | if err := m.player.assertInit(); err != nil {
235 | return "", err
236 | }
237 |
238 | cVal := C.libvlc_video_get_marquee_string(m.player.player, option)
239 | if cVal == nil {
240 | return "", errOrDefault(getError(), ErrInvalid)
241 | }
242 | defer C.free(unsafe.Pointer(cVal))
243 |
244 | return C.GoString(cVal), nil
245 | }
246 |
247 | func (m *Marquee) setString(option C.uint, val string) error {
248 | if err := m.player.assertInit(); err != nil {
249 | return err
250 | }
251 |
252 | cVal := C.CString(val)
253 | defer C.free(unsafe.Pointer(cVal))
254 |
255 | C.libvlc_video_set_marquee_string(m.player.player, option, cVal)
256 | return nil
257 | }
258 |
--------------------------------------------------------------------------------
/v3/media_discoverer.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | // #include
6 | import "C"
7 | import (
8 | "unsafe"
9 | )
10 |
11 | // MediaDiscoveryCallback is used by media discovery services to report
12 | // discovery events. The callback provides the event, the media instance,
13 | // and the index at which the action takes place in the media list of the
14 | // discovery service.
15 | //
16 | // The available events are:
17 | // - MediaListWillAddItem
18 | // - MediaListItemAdded
19 | // - MediaListWillDeleteItem
20 | // - MediaListItemDeleted
21 | type MediaDiscoveryCallback func(Event, *Media, int)
22 |
23 | // MediaDiscoveryCategory defines categories of media discovery services.
24 | type MediaDiscoveryCategory uint
25 |
26 | // Media discovery categories.
27 | const (
28 | // Devices (e.g. portable devices supporting MTP, discs).
29 | MediaDiscoveryDevices MediaDiscoveryCategory = iota
30 |
31 | // LAN/WAN services (e.g. UPnP, SMB, SAP).
32 | MediaDiscoveryLAN
33 |
34 | // Internet services (e.g. podcasts, radio stations).
35 | MediaDiscoveryInternet
36 |
37 | // Local directories.
38 | MediaDiscoveryLocal
39 | )
40 |
41 | // MediaDiscovererDescriptor contains information about a media
42 | // discovery service. Pass the `Name` field to the NewMediaDiscoverer
43 | // method in order to create a new discovery service instance.
44 | type MediaDiscovererDescriptor struct {
45 | Name string
46 | LongName string
47 | Category MediaDiscoveryCategory
48 | }
49 |
50 | // ListMediaDiscoverers returns a list of descriptors identifying the
51 | // available media discovery services of the specified category.
52 | func ListMediaDiscoverers(category MediaDiscoveryCategory) ([]*MediaDiscovererDescriptor, error) {
53 | if err := inst.assertInit(); err != nil {
54 | return nil, err
55 | }
56 |
57 | // Get media discoverer descriptors.
58 | var cDescriptors **C.libvlc_media_discoverer_description_t
59 |
60 | count := int(C.libvlc_media_discoverer_list_get(inst.handle, C.libvlc_media_discoverer_category_t(category), &cDescriptors))
61 | if count <= 0 || cDescriptors == nil {
62 | return nil, nil
63 | }
64 | defer C.libvlc_media_discoverer_list_release(cDescriptors, C.size_t(count))
65 |
66 | // Parse media discoverer descriptors.
67 | descriptors := make([]*MediaDiscovererDescriptor, 0, count)
68 | for i := 0; i < count; i++ {
69 | // Get current media discoverer descriptor.
70 | cDescriptorPtr := unsafe.Pointer(uintptr(unsafe.Pointer(cDescriptors)) +
71 | uintptr(i)*unsafe.Sizeof(*cDescriptors))
72 | if cDescriptorPtr == nil {
73 | return nil, ErrMediaDiscovererParse
74 | }
75 |
76 | cDescriptor := *(**C.libvlc_media_discoverer_description_t)(cDescriptorPtr)
77 | if cDescriptor == nil {
78 | return nil, ErrMediaDiscovererParse
79 | }
80 |
81 | // Parse media discoverer descriptor.
82 | descriptors = append(descriptors, &MediaDiscovererDescriptor{
83 | Name: C.GoString(cDescriptor.psz_name),
84 | LongName: C.GoString(cDescriptor.psz_longname),
85 | Category: MediaDiscoveryCategory(cDescriptor.i_cat),
86 | })
87 | }
88 |
89 | return descriptors, nil
90 | }
91 |
92 | // MediaDiscoverer represents a media discovery service.
93 | // Discovery services use different discovery protocols (e.g. MTP, UPnP, SMB)
94 | // in order to find available media instances.
95 | type MediaDiscoverer struct {
96 | discoverer *C.libvlc_media_discoverer_t
97 | stopFunc func()
98 | }
99 |
100 | // NewMediaDiscoverer instantiates the media discovery service identified
101 | // by the specified name. Use the ListMediaDiscoverers method to obtain the
102 | // list of available discovery service descriptors.
103 | //
104 | // NOTE: Call the Release method on the discovery service instance in
105 | // order to free the allocated resources.
106 | func NewMediaDiscoverer(name string) (*MediaDiscoverer, error) {
107 | if err := inst.assertInit(); err != nil {
108 | return nil, err
109 | }
110 |
111 | cName := C.CString(name)
112 | defer C.free(unsafe.Pointer(cName))
113 |
114 | discoverer := C.libvlc_media_discoverer_new(inst.handle, cName)
115 | if discoverer == nil {
116 | return nil, errOrDefault(getError(), ErrMediaDiscovererCreate)
117 | }
118 |
119 | return &MediaDiscoverer{
120 | discoverer: discoverer,
121 | }, nil
122 | }
123 |
124 | // Release stops and destroys the media discovery service along
125 | // with all the media found by the instance.
126 | func (md *MediaDiscoverer) Release() error {
127 | if err := md.assertInit(); err != nil {
128 | return nil
129 | }
130 |
131 | // Stop discovery service.
132 | md.stop()
133 |
134 | // Release discovery service.
135 | C.libvlc_media_discoverer_release(md.discoverer)
136 | md.discoverer = nil
137 |
138 | return nil
139 | }
140 |
141 | // Start starts the media discovery service and reports discovery
142 | // events through the specified callback function.
143 | //
144 | // NOTE: The Stop and Release methods should not be called from the callback
145 | // function. Doing so will result in undefined behavior.
146 | func (md *MediaDiscoverer) Start(cb MediaDiscoveryCallback) error {
147 | if cb == nil {
148 | return ErrInvalidEventCallback
149 | }
150 |
151 | // Stop discovery service, if started.
152 | if err := md.Stop(); err != nil {
153 | return err
154 | }
155 |
156 | // Retrieve media list.
157 | ml, err := md.MediaList()
158 | if err != nil {
159 | return err
160 | }
161 |
162 | // Retrieve media list event manager.
163 | manager, err := ml.EventManager()
164 | if err != nil {
165 | return err
166 | }
167 |
168 | // Create event callback.
169 | eventCallback := func(event *C.libvlc_event_t, userData interface{}) {
170 | if err := md.assertInit(); err != nil {
171 | return
172 | }
173 | if event == nil {
174 | return
175 | }
176 |
177 | // Parse event media.
178 | cMedia := *(**C.libvlc_media_t)(unsafe.Pointer(&event.u[0]))
179 | if cMedia == nil {
180 | return
181 | }
182 | media := &Media{media: cMedia}
183 |
184 | // Parse event media index.
185 | cIndex := (*C.int)(unsafe.Pointer(uintptr(unsafe.Pointer(&event.u[0])) +
186 | unsafe.Sizeof(cMedia)))
187 | if cIndex == nil {
188 | return
189 | }
190 | index := int(*cIndex)
191 |
192 | switch event := Event(event._type); event {
193 | case MediaListWillAddItem, MediaListItemAdded,
194 | MediaListWillDeleteItem, MediaListItemDeleted:
195 | cb(event, media, index)
196 | }
197 | }
198 |
199 | // Attach discovery service events.
200 | events := []Event{
201 | MediaListWillAddItem,
202 | MediaListItemAdded,
203 | MediaListWillDeleteItem,
204 | MediaListItemDeleted,
205 | }
206 |
207 | eventIDs := make([]EventID, 0, len(events))
208 | for _, event := range events {
209 | eventID, err := manager.attach(event, nil, eventCallback, nil)
210 | if err != nil {
211 | return err
212 | }
213 |
214 | eventIDs = append(eventIDs, eventID)
215 | }
216 | defer func() {
217 | if md.stopFunc == nil {
218 | manager.Detach(eventIDs...)
219 | }
220 | }()
221 |
222 | // Start discovery service.
223 | if C.libvlc_media_discoverer_start(md.discoverer) < 0 {
224 | return errOrDefault(getError(), ErrMediaDiscovererStart)
225 | }
226 |
227 | md.stopFunc = func() {
228 | // Detach events.
229 | manager.Detach(eventIDs...)
230 |
231 | // Stop discovery service.
232 | C.libvlc_media_discoverer_stop(md.discoverer)
233 | }
234 |
235 | return nil
236 | }
237 |
238 | // Stop stops the discovery service.
239 | func (md *MediaDiscoverer) Stop() error {
240 | if err := md.assertInit(); err != nil {
241 | return err
242 | }
243 |
244 | md.stop()
245 | return nil
246 | }
247 |
248 | // IsRunning returns true if the media discovery service is running.
249 | func (md *MediaDiscoverer) IsRunning() bool {
250 | if err := md.assertInit(); err != nil {
251 | return false
252 | }
253 |
254 | return C.libvlc_media_discoverer_is_running(md.discoverer) != 0
255 | }
256 |
257 | // MediaList returns the media list associated with the discovery service,
258 | // which contains the found media instances.
259 | //
260 | // NOTE: The returned media list is read-only.
261 | func (md *MediaDiscoverer) MediaList() (*MediaList, error) {
262 | if err := md.assertInit(); err != nil {
263 | return nil, err
264 | }
265 |
266 | ml := C.libvlc_media_discoverer_media_list(md.discoverer)
267 | if ml == nil {
268 | return nil, errOrDefault(getError(), ErrMediaListNotFound)
269 | }
270 |
271 | // This call will not release the media list. Instead, it will decrement
272 | // the reference count increased by libvlc_media_discoverer_media_list.
273 | C.libvlc_media_list_release(ml)
274 |
275 | return &MediaList{list: ml}, nil
276 | }
277 |
278 | func (md *MediaDiscoverer) stop() {
279 | if md.stopFunc != nil {
280 | md.stopFunc()
281 | md.stopFunc = nil
282 | }
283 | }
284 |
285 | func (md *MediaDiscoverer) assertInit() error {
286 | if md == nil || md.discoverer == nil {
287 | return ErrMediaDiscovererNotInitialized
288 | }
289 |
290 | return nil
291 | }
292 |
--------------------------------------------------------------------------------
/v3/media_list.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | import "C"
6 | import "io"
7 |
8 | // MediaList represents a collection of media files.
9 | type MediaList struct {
10 | list *C.libvlc_media_list_t
11 | }
12 |
13 | // NewMediaList creates an empty media list.
14 | func NewMediaList() (*MediaList, error) {
15 | if err := inst.assertInit(); err != nil {
16 | return nil, err
17 | }
18 |
19 | var list *C.libvlc_media_list_t
20 | if list = C.libvlc_media_list_new(inst.handle); list == nil {
21 | return nil, errOrDefault(getError(), ErrMediaListCreate)
22 | }
23 |
24 | return &MediaList{list: list}, nil
25 | }
26 |
27 | // Release destroys the media list instance.
28 | func (ml *MediaList) Release() error {
29 | if err := ml.assertInit(); err != nil {
30 | return nil
31 | }
32 |
33 | C.libvlc_media_list_release(ml.list)
34 | ml.list = nil
35 |
36 | return nil
37 | }
38 |
39 | // AddMedia adds the provided Media instance at the end of the media list.
40 | func (ml *MediaList) AddMedia(m *Media) error {
41 | if err := m.assertInit(); err != nil {
42 | return err
43 | }
44 |
45 | // Check if media list is read-only.
46 | isReadOnly, err := ml.IsReadOnly()
47 | if err != nil {
48 | return err
49 | }
50 | if isReadOnly {
51 | return ErrMediaListReadOnly
52 | }
53 |
54 | // Lock media list.
55 | if err := ml.Lock(); err != nil {
56 | return err
57 | }
58 | defer ml.unlock()
59 |
60 | // Add the media to the list.
61 | if C.libvlc_media_list_add_media(ml.list, m.media) < 0 {
62 | return errOrDefault(getError(), ErrMediaListActionFailed)
63 | }
64 |
65 | return nil
66 | }
67 |
68 | // AddMediaFromPath loads the media file at the specified path and adds it at
69 | // the end of the media list.
70 | func (ml *MediaList) AddMediaFromPath(path string) error {
71 | media, err := NewMediaFromPath(path)
72 | if err != nil {
73 | return err
74 | }
75 |
76 | // Add the media to the list.
77 | if err := ml.AddMedia(media); err != nil {
78 | media.release()
79 | return err
80 | }
81 |
82 | return nil
83 | }
84 |
85 | // AddMediaFromURL loads the media file at the specified URL and adds it at
86 | // the end of the the media list.
87 | func (ml *MediaList) AddMediaFromURL(url string) error {
88 | media, err := NewMediaFromURL(url)
89 | if err != nil {
90 | return err
91 | }
92 |
93 | if err := ml.AddMedia(media); err != nil {
94 | media.release()
95 | return err
96 | }
97 |
98 | return nil
99 | }
100 |
101 | // AddMediaFromReadSeeker loads the media from the provided read
102 | // seeker and adds it at the end of the media list.
103 | func (ml *MediaList) AddMediaFromReadSeeker(r io.ReadSeeker) error {
104 | media, err := NewMediaFromReadSeeker(r)
105 | if err != nil {
106 | return err
107 | }
108 |
109 | if err := ml.AddMedia(media); err != nil {
110 | media.release()
111 | return err
112 | }
113 |
114 | return nil
115 | }
116 |
117 | // InsertMedia inserts the provided Media instance in the list,
118 | // at the specified index.
119 | func (ml *MediaList) InsertMedia(m *Media, index uint) error {
120 | if err := m.assertInit(); err != nil {
121 | return err
122 | }
123 |
124 | // Check if media list is read-only.
125 | isReadOnly, err := ml.IsReadOnly()
126 | if err != nil {
127 | return err
128 | }
129 | if isReadOnly {
130 | return ErrMediaListReadOnly
131 | }
132 |
133 | // Lock media list.
134 | if err := ml.Lock(); err != nil {
135 | return err
136 | }
137 | defer ml.unlock()
138 |
139 | // Insert the media in the list.
140 | if C.libvlc_media_list_insert_media(ml.list, m.media, C.int(index)) < 0 {
141 | return errOrDefault(getError(), ErrMediaListActionFailed)
142 | }
143 |
144 | return nil
145 | }
146 |
147 | // InsertMediaFromPath loads the media file at the provided path and inserts
148 | // it in the list, at the specified index.
149 | func (ml *MediaList) InsertMediaFromPath(path string, index uint) error {
150 | media, err := NewMediaFromPath(path)
151 | if err != nil {
152 | return err
153 | }
154 |
155 | // Insert the media in the list.
156 | if err := ml.InsertMedia(media, index); err != nil {
157 | media.release()
158 | return err
159 | }
160 |
161 | return nil
162 | }
163 |
164 | // InsertMediaFromURL loads the media file at the provided URL and inserts
165 | // it in the list, at the specified index.
166 | func (ml *MediaList) InsertMediaFromURL(url string, index uint) error {
167 | media, err := NewMediaFromURL(url)
168 | if err != nil {
169 | return err
170 | }
171 |
172 | // Insert the media in the list.
173 | if err := ml.InsertMedia(media, index); err != nil {
174 | media.release()
175 | return err
176 | }
177 |
178 | return nil
179 | }
180 |
181 | // InsertMediaFromReadSeeker loads the media from the provided read
182 | // seeker and inserts it in the list, at the specified index.
183 | func (ml *MediaList) InsertMediaFromReadSeeker(r io.ReadSeeker, index uint) error {
184 | media, err := NewMediaFromReadSeeker(r)
185 | if err != nil {
186 | return err
187 | }
188 |
189 | // Insert the media in the list.
190 | if err := ml.InsertMedia(media, index); err != nil {
191 | media.release()
192 | return err
193 | }
194 |
195 | return nil
196 | }
197 |
198 | // RemoveMediaAtIndex removes the media item at the specified index
199 | // from the list.
200 | func (ml *MediaList) RemoveMediaAtIndex(index uint) error {
201 | // Check if media list is read-only.
202 | isReadOnly, err := ml.IsReadOnly()
203 | if err != nil {
204 | return err
205 | }
206 | if isReadOnly {
207 | return ErrMediaListReadOnly
208 | }
209 |
210 | // Lock media list.
211 | if err := ml.Lock(); err != nil {
212 | return err
213 | }
214 | defer ml.unlock()
215 |
216 | // Remove the media from the list.
217 | if C.libvlc_media_list_remove_index(ml.list, C.int(index)) < 0 {
218 | return errOrDefault(getError(), ErrMediaListActionFailed)
219 | }
220 |
221 | return nil
222 | }
223 |
224 | // MediaAtIndex returns the media item at the specified index from the list.
225 | func (ml *MediaList) MediaAtIndex(index uint) (*Media, error) {
226 | // Lock media list.
227 | if err := ml.Lock(); err != nil {
228 | return nil, err
229 | }
230 | defer ml.unlock()
231 |
232 | // Retrieve the media at the specified index.
233 | media := C.libvlc_media_list_item_at_index(ml.list, C.int(index))
234 | if media == nil {
235 | return nil, errOrDefault(getError(), ErrMediaListActionFailed)
236 | }
237 |
238 | // This call will not release the media. Instead, it will decrement
239 | // the reference count increased by libvlc_media_list_item_at_index.
240 | C.libvlc_media_release(media)
241 |
242 | return &Media{media}, nil
243 | }
244 |
245 | // IndexOfMedia returns the index of the specified media item in the list.
246 | //
247 | // NOTE: The same instance of a media item can be present multiple times
248 | // in the list. The method returns the first matched index.
249 | func (ml *MediaList) IndexOfMedia(m *Media) (int, error) {
250 | if err := m.assertInit(); err != nil {
251 | return 0, err
252 | }
253 |
254 | if err := ml.Lock(); err != nil {
255 | return 0, err
256 | }
257 | defer ml.unlock()
258 |
259 | // Retrieve the index of the media.
260 | idx := int(C.libvlc_media_list_index_of_item(ml.list, m.media))
261 | if idx < 0 {
262 | return 0, errOrDefault(getError(), ErrMediaNotFound)
263 | }
264 |
265 | return idx, nil
266 | }
267 |
268 | // Count returns the number of media items in the list.
269 | func (ml *MediaList) Count() (int, error) {
270 | // Lock media list.
271 | if err := ml.Lock(); err != nil {
272 | return 0, err
273 | }
274 | defer ml.unlock()
275 |
276 | // Retrieve media count.
277 | return int(C.libvlc_media_list_count(ml.list)), nil
278 | }
279 |
280 | // IsReadOnly specifies if the media list can be modified.
281 | func (ml *MediaList) IsReadOnly() (bool, error) {
282 | if err := ml.assertInit(); err != nil {
283 | return false, err
284 | }
285 |
286 | return C.libvlc_media_list_is_readonly(ml.list) != C.int(0), nil
287 | }
288 |
289 | // AssociatedMedia returns the media instance associated with the list,
290 | // if one exists. A media instance is automatically associated with the
291 | // list of its sub-items.
292 | //
293 | // NOTE: Do not call Release on the returned media instance.
294 | func (ml *MediaList) AssociatedMedia() (*Media, error) {
295 | if err := ml.assertInit(); err != nil {
296 | return nil, err
297 | }
298 |
299 | media := C.libvlc_media_list_media(ml.list)
300 | if media == nil {
301 | return nil, errOrDefault(getError(), ErrMediaNotFound)
302 | }
303 |
304 | // This call will not release the media. Instead, it will decrement
305 | // the reference count increased by libvlc_media_list_media.
306 | C.libvlc_media_release(media)
307 |
308 | return &Media{media: media}, nil
309 | }
310 |
311 | // AssociateMedia associates the specified media with the media list instance.
312 | //
313 | // NOTE: If another media instance is already associated with the list,
314 | // it will be released.
315 | func (ml *MediaList) AssociateMedia(m *Media) error {
316 | if err := ml.assertInit(); err != nil {
317 | return err
318 | }
319 | if err := m.assertInit(); err != nil {
320 | return err
321 | }
322 |
323 | C.libvlc_media_list_set_media(ml.list, m.media)
324 | return nil
325 | }
326 |
327 | // Lock makes the caller the current owner of the media list.
328 | func (ml *MediaList) Lock() error {
329 | if err := ml.assertInit(); err != nil {
330 | return err
331 | }
332 |
333 | C.libvlc_media_list_lock(ml.list)
334 | return nil
335 | }
336 |
337 | // Unlock releases ownership of the media list.
338 | func (ml *MediaList) Unlock() error {
339 | if err := ml.assertInit(); err != nil {
340 | return err
341 | }
342 |
343 | ml.unlock()
344 | return nil
345 | }
346 |
347 | // EventManager returns the event manager responsible for the media list.
348 | func (ml *MediaList) EventManager() (*EventManager, error) {
349 | if err := ml.assertInit(); err != nil {
350 | return nil, err
351 | }
352 |
353 | manager := C.libvlc_media_list_event_manager(ml.list)
354 | if manager == nil {
355 | return nil, ErrMissingEventManager
356 | }
357 |
358 | return newEventManager(manager), nil
359 | }
360 |
361 | func (ml *MediaList) assertInit() error {
362 | if ml == nil || ml.list == nil {
363 | return ErrMediaListNotInitialized
364 | }
365 |
366 | return nil
367 | }
368 |
369 | func (ml *MediaList) unlock() {
370 | C.libvlc_media_list_unlock(ml.list)
371 | }
372 |
--------------------------------------------------------------------------------
/v3/media_track.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | import "C"
6 | import (
7 | "unsafe"
8 | )
9 |
10 | // VideoOrientation represents the orientation of a video media track.
11 | type VideoOrientation int
12 |
13 | // Video orientations.
14 | const (
15 | // Normal.
16 | OrientationTopLeft VideoOrientation = iota
17 |
18 | // Flipped horizontally.
19 | OrientationTopRight
20 |
21 | // Flipped vertically.
22 | OrientationBottomLeft
23 |
24 | // Rotated 180 degrees.
25 | OrientationBottomRight
26 |
27 | // Transposed.
28 | OrientationLeftTop
29 |
30 | // Rotated 90 degrees anti-clockwise.
31 | OrientationLeftBottom
32 |
33 | // Rotated 90 degrees clockwise.
34 | OrientationRightTop
35 |
36 | // Anti-transposed.
37 | OrientationRightBottom
38 | )
39 |
40 | // VideoProjection represents the projection mode of a video media track.
41 | type VideoProjection int
42 |
43 | // Video projections.
44 | const (
45 | ProjectionRectangular VideoProjection = 0
46 | ProjectionEquirectangular VideoProjection = 1
47 | ProjectionCubemapLayoutStandard VideoProjection = 0x100
48 | )
49 |
50 | // VideoViewpoint contains viewpoint information for a video media track.
51 | type VideoViewpoint struct {
52 | Yaw float64 // Viewpoint yaw in degrees [-180-180].
53 | Pitch float64 // Viewpoint pitch in degrees [-90-90].
54 | Roll float64 // Viewpoint roll in degrees [-180-180].
55 | FOV float64 // Viewpoint field of view in degrees [0-180]. Default: 80.
56 | }
57 |
58 | // MediaTrackType represents the type of a media track.
59 | type MediaTrackType int
60 |
61 | // Media track types.
62 | const (
63 | MediaTrackUnknown MediaTrackType = iota - 1
64 | MediaTrackAudio
65 | MediaTrackVideo
66 | MediaTrackText
67 | )
68 |
69 | // MediaTrackDescriptor contains information about a media track.
70 | type MediaTrackDescriptor struct {
71 | ID int // Media track identifier.
72 | Description string // Description of the media track.
73 | }
74 |
75 | // MediaAudioTrack contains information specific to audio media tracks.
76 | type MediaAudioTrack struct {
77 | Channels uint // number of audio channels.
78 | Rate uint // audio sample rate.
79 | }
80 |
81 | // MediaVideoTrack contains information specific to video media tracks.
82 | type MediaVideoTrack struct {
83 | Width uint // video width.
84 | Height uint // video height.
85 | Orientation VideoOrientation // video orientation.
86 | Projection VideoProjection // video projection mode.
87 | Pose VideoViewpoint // video initial viewpoint.
88 |
89 | // Aspect ratio information.
90 | AspectRatioNum uint // aspect ratio numerator.
91 | AspectRatioDen uint // aspect ratio denominator.
92 |
93 | // Frame rate information.
94 | FrameRateNum uint // frame rate numerator.
95 | FrameRateDen uint // frame rate denominator.
96 | }
97 |
98 | // MediaSubtitleTrack contains information specific to subtitle media tracks.
99 | type MediaSubtitleTrack struct {
100 | Encoding string // character encoding of the subtitle.
101 | }
102 |
103 | // MediaTrack contains information regarding a media track.
104 | type MediaTrack struct {
105 | ID int // Media track identifier.
106 | Type MediaTrackType // Media track type.
107 | BitRate uint // Media track bit rate.
108 |
109 | // libVLC representation of the four-character code of the codec used by
110 | // the media track.
111 | Codec uint
112 |
113 | // The original four-character code of the codec used by the media track,
114 | // extracted from the container.
115 | OriginalCodec uint
116 |
117 | // Codec profile (real audio flavor, MPEG audio layer, H264 profile, etc.).
118 | // NOTE: Profile values are codec specific.
119 | Profile int
120 |
121 | // Stream restriction level (resolution, bitrate, codec features, etc.).
122 | // NOTE: Level values are codec specific.
123 | Level int
124 |
125 | Language string // Media track language name.
126 | Description string // Description of the media track.
127 |
128 | // Type specific information.
129 | Audio *MediaAudioTrack
130 | Video *MediaVideoTrack
131 | Subtitle *MediaSubtitleTrack
132 | }
133 |
134 | // CodecDescription returns the description of the codec used by the media track.
135 | func (mt *MediaTrack) CodecDescription() (string, error) {
136 | if err := mt.assertInit(); err != nil {
137 | return "", err
138 | }
139 |
140 | codec := mt.Codec
141 | if codec == 0 {
142 | codec = mt.OriginalCodec
143 | }
144 |
145 | // Get codec description.
146 | return C.GoString(C.libvlc_media_get_codec_description(
147 | C.libvlc_track_type_t(mt.Type),
148 | C.uint(codec),
149 | )), nil
150 | }
151 |
152 | func (mt *MediaTrack) assertInit() error {
153 | if mt == nil {
154 | return ErrMediaTrackNotInitialized
155 | }
156 |
157 | return nil
158 | }
159 |
160 | func parseMediaTrack(cTrack *C.libvlc_media_track_t) (*MediaTrack, error) {
161 | if cTrack == nil {
162 | return nil, ErrMediaTrackNotInitialized
163 | }
164 |
165 | mt := &MediaTrack{
166 | ID: int(cTrack.i_id),
167 | Type: MediaTrackType(cTrack.i_type),
168 | BitRate: uint(cTrack.i_bitrate),
169 | Codec: uint(cTrack.i_codec),
170 | OriginalCodec: uint(cTrack.i_original_fourcc),
171 | Profile: int(cTrack.i_profile),
172 | Level: int(cTrack.i_level),
173 | Language: C.GoString(cTrack.psz_language),
174 | Description: C.GoString(cTrack.psz_description),
175 | }
176 |
177 | switch mt.Type {
178 | case MediaTrackAudio:
179 | audio := *(**C.libvlc_audio_track_t)(unsafe.Pointer(&cTrack.anon0[0]))
180 | if audio == nil {
181 | break
182 | }
183 |
184 | mt.Audio = &MediaAudioTrack{
185 | Channels: uint(audio.i_channels),
186 | Rate: uint(audio.i_rate),
187 | }
188 | case MediaTrackVideo:
189 | video := *(**C.libvlc_video_track_t)(unsafe.Pointer(&cTrack.anon0[0]))
190 | if video == nil {
191 | break
192 | }
193 |
194 | mt.Video = &MediaVideoTrack{
195 | Width: uint(video.i_width),
196 | Height: uint(video.i_height),
197 | AspectRatioNum: uint(video.i_sar_num),
198 | AspectRatioDen: uint(video.i_sar_den),
199 | FrameRateNum: uint(video.i_frame_rate_num),
200 | FrameRateDen: uint(video.i_frame_rate_den),
201 | Orientation: VideoOrientation(video.i_orientation),
202 | Projection: VideoProjection(video.i_projection),
203 | Pose: VideoViewpoint{
204 | Yaw: float64(video.pose.f_yaw),
205 | Pitch: float64(video.pose.f_pitch),
206 | Roll: float64(video.pose.f_roll),
207 | FOV: float64(video.pose.f_field_of_view),
208 | },
209 | }
210 | case MediaTrackText:
211 | subtitle := *(**C.libvlc_subtitle_track_t)(unsafe.Pointer(&cTrack.anon0[0]))
212 | if subtitle == nil {
213 | break
214 | }
215 |
216 | mt.Subtitle = &MediaSubtitleTrack{
217 | Encoding: C.GoString(subtitle.psz_encoding),
218 | }
219 | }
220 |
221 | return mt, nil
222 | }
223 |
224 | func parseMediaTrackDescriptorList(cDescriptors *C.libvlc_track_description_t) ([]*MediaTrackDescriptor, error) {
225 | if cDescriptors == nil {
226 | return nil, nil
227 | }
228 |
229 | var descriptors []*MediaTrackDescriptor
230 | for n := cDescriptors; n != nil; n = n.p_next {
231 | descriptors = append(descriptors, &MediaTrackDescriptor{
232 | ID: int(n.i_id),
233 | Description: C.GoString(n.psz_name),
234 | })
235 | }
236 |
237 | C.libvlc_track_description_list_release(cDescriptors)
238 | return descriptors, nil
239 | }
240 |
--------------------------------------------------------------------------------
/v3/object_registry.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #include
4 | import "C"
5 | import (
6 | "sync"
7 | "unsafe"
8 | )
9 |
10 | type objectID = unsafe.Pointer
11 |
12 | type objectContext struct {
13 | refs uint
14 | data interface{}
15 | }
16 |
17 | type objectRegistry struct {
18 | sync.RWMutex
19 |
20 | contexts map[objectID]*objectContext
21 | }
22 |
23 | func newObjectRegistry() *objectRegistry {
24 | return &objectRegistry{
25 | contexts: map[objectID]*objectContext{},
26 | }
27 | }
28 |
29 | func (or *objectRegistry) get(id objectID) (interface{}, bool) {
30 | if id == nil {
31 | return nil, false
32 | }
33 |
34 | or.RLock()
35 | ctx, ok := or.contexts[id]
36 | or.RUnlock()
37 |
38 | if !ok {
39 | return nil, false
40 | }
41 | return ctx.data, ok
42 | }
43 |
44 | func (or *objectRegistry) add(data interface{}) objectID {
45 | or.Lock()
46 |
47 | var id objectID = C.malloc(C.size_t(1))
48 | or.contexts[id] = &objectContext{
49 | refs: 1,
50 | data: data,
51 | }
52 |
53 | or.Unlock()
54 | return id
55 | }
56 |
57 | func (or *objectRegistry) incRefs(id objectID) {
58 | if id == nil {
59 | return
60 | }
61 |
62 | or.Lock()
63 |
64 | ctx, ok := or.contexts[id]
65 | if ok {
66 | ctx.refs++
67 | }
68 |
69 | or.Unlock()
70 | }
71 |
72 | func (or *objectRegistry) decRefs(id objectID) {
73 | if id == nil {
74 | return
75 | }
76 |
77 | or.Lock()
78 |
79 | ctx, ok := or.contexts[id]
80 | if ok {
81 | ctx.refs--
82 | if ctx.refs == 0 {
83 | delete(or.contexts, id)
84 | C.free(id)
85 | }
86 | }
87 |
88 | or.Unlock()
89 | }
90 |
--------------------------------------------------------------------------------
/v3/renderer.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | import "C"
6 |
7 | // RendererType represents the type of a renderer.
8 | type RendererType string
9 |
10 | // Renderer types.
11 | const (
12 | RendererChromecast RendererType = "chromecast"
13 | )
14 |
15 | // RendererFlags contains flags describing a renderer (e.g. capabilities).
16 | type RendererFlags struct {
17 | AudioEnabled bool
18 | VideoEnabled bool
19 | }
20 |
21 | // Renderer represents a medium capable of rendering media files.
22 | type Renderer struct {
23 | renderer *C.libvlc_renderer_item_t
24 | }
25 |
26 | // Name returns the name of the renderer.
27 | func (r *Renderer) Name() (string, error) {
28 | if err := r.assertInit(); err != nil {
29 | return "", nil
30 | }
31 |
32 | return C.GoString(C.libvlc_renderer_item_name(r.renderer)), nil
33 | }
34 |
35 | // Type returns the type of the renderer.
36 | func (r *Renderer) Type() (RendererType, error) {
37 | if err := r.assertInit(); err != nil {
38 | return "", nil
39 | }
40 |
41 | return RendererType(C.GoString(C.libvlc_renderer_item_type(r.renderer))), nil
42 | }
43 |
44 | // Flags returns the flags of the renderer.
45 | func (r *Renderer) Flags() (*RendererFlags, error) {
46 | if err := r.assertInit(); err != nil {
47 | return nil, err
48 | }
49 |
50 | flags := C.libvlc_renderer_item_flags(r.renderer)
51 |
52 | return &RendererFlags{
53 | AudioEnabled: (flags | C.LIBVLC_RENDERER_CAN_AUDIO) != 0,
54 | VideoEnabled: (flags | C.LIBVLC_RENDERER_CAN_VIDEO) != 0,
55 | }, nil
56 | }
57 |
58 | // IconURI returns the icon URI of the renderer.
59 | func (r *Renderer) IconURI() (string, error) {
60 | if err := r.assertInit(); err != nil {
61 | return "", nil
62 | }
63 |
64 | return C.GoString(C.libvlc_renderer_item_icon_uri(r.renderer)), nil
65 | }
66 |
67 | func (r *Renderer) hold() {
68 | if err := r.assertInit(); err != nil {
69 | return
70 | }
71 |
72 | C.libvlc_renderer_item_hold(r.renderer)
73 | }
74 |
75 | func (r *Renderer) release() {
76 | if err := r.assertInit(); err != nil {
77 | return
78 | }
79 |
80 | C.libvlc_renderer_item_release(r.renderer)
81 | }
82 |
83 | func (r *Renderer) assertInit() error {
84 | if r == nil || r.renderer == nil {
85 | return ErrRendererNotInitialized
86 | }
87 |
88 | return nil
89 | }
90 |
--------------------------------------------------------------------------------
/v3/renderer_discoverer.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | // #include
6 | import "C"
7 | import (
8 | "unsafe"
9 | )
10 |
11 | // RendererDiscoveryCallback is used by renderer discovery services to
12 | // report discovery events.
13 | //
14 | // The available events are:
15 | // - RendererDiscovererItemAdded
16 | // - RendererDiscovererItemDeleted
17 | type RendererDiscoveryCallback func(Event, *Renderer)
18 |
19 | // RendererDiscovererDescriptor contains information about a renderer
20 | // discovery service. Pass the `Name` field to the NewRendererDiscoverer
21 | // method in order to create a new discovery service instance.
22 | type RendererDiscovererDescriptor struct {
23 | Name string
24 | LongName string
25 | }
26 |
27 | // ListRendererDiscoverers returns a list of descriptors identifying the
28 | // available renderer discovery services.
29 | func ListRendererDiscoverers() ([]*RendererDiscovererDescriptor, error) {
30 | if err := inst.assertInit(); err != nil {
31 | return nil, err
32 | }
33 |
34 | // Get renderer discoverer descriptors.
35 | var cDescriptors **C.libvlc_rd_description_t
36 |
37 | count := int(C.libvlc_renderer_discoverer_list_get(inst.handle, &cDescriptors))
38 | if count <= 0 || cDescriptors == nil {
39 | return nil, nil
40 | }
41 | defer C.libvlc_renderer_discoverer_list_release(cDescriptors, C.size_t(count))
42 |
43 | // Parse renderer discoverer descriptors.
44 | descriptors := make([]*RendererDiscovererDescriptor, 0, count)
45 | for i := 0; i < count; i++ {
46 | // Get current renderer discoverer descriptor.
47 | cDescriptorPtr := unsafe.Pointer(uintptr(unsafe.Pointer(cDescriptors)) +
48 | uintptr(i)*unsafe.Sizeof(*cDescriptors))
49 | if cDescriptorPtr == nil {
50 | return nil, ErrRendererDiscovererParse
51 | }
52 |
53 | cDescriptor := *(**C.libvlc_rd_description_t)(cDescriptorPtr)
54 | if cDescriptor == nil {
55 | return nil, ErrRendererDiscovererParse
56 | }
57 |
58 | // Parse renderer discoverer descriptor.
59 | descriptors = append(descriptors, &RendererDiscovererDescriptor{
60 | Name: C.GoString(cDescriptor.psz_name),
61 | LongName: C.GoString(cDescriptor.psz_longname),
62 | })
63 | }
64 |
65 | return descriptors, nil
66 | }
67 |
68 | // RendererDiscoverer represents a renderer discovery service.
69 | // Discovery services use different discovery protocols (e.g. mDNS)
70 | // in order to find available media renderers (e.g. Chromecast).
71 | type RendererDiscoverer struct {
72 | discoverer *C.libvlc_renderer_discoverer_t
73 | renderers map[*C.libvlc_renderer_item_t]*Renderer
74 | stopFunc func()
75 | }
76 |
77 | // NewRendererDiscoverer instantiates the renderer discovery service
78 | // identified by the specified name. Use the ListRendererDiscoverers
79 | // method to obtain the list of available discovery service descriptors.
80 | //
81 | // NOTE: Call the Release method on the discovery service instance in
82 | // order to free the allocated resources.
83 | func NewRendererDiscoverer(name string) (*RendererDiscoverer, error) {
84 | if err := inst.assertInit(); err != nil {
85 | return nil, err
86 | }
87 |
88 | cName := C.CString(name)
89 | defer C.free(unsafe.Pointer(cName))
90 |
91 | discoverer := C.libvlc_renderer_discoverer_new(inst.handle, cName)
92 | if discoverer == nil {
93 | return nil, errOrDefault(getError(), ErrRendererDiscovererCreate)
94 | }
95 |
96 | return &RendererDiscoverer{
97 | discoverer: discoverer,
98 | renderers: map[*C.libvlc_renderer_item_t]*Renderer{},
99 | }, nil
100 | }
101 |
102 | // Release stops and destroys the renderer discovery service along
103 | // with all the renderers found by the instance.
104 | func (rd *RendererDiscoverer) Release() error {
105 | if err := rd.assertInit(); err != nil {
106 | return nil
107 | }
108 |
109 | // Stop discovery service.
110 | rd.stop()
111 |
112 | // Release renderers.
113 | for _, renderer := range rd.renderers {
114 | renderer.release()
115 | }
116 | rd.renderers = nil
117 |
118 | // Release discovery service.
119 | C.libvlc_renderer_discoverer_release(rd.discoverer)
120 | rd.discoverer = nil
121 |
122 | return nil
123 | }
124 |
125 | // Start starts the renderer discovery service and reports discovery
126 | // events through the specified callback function.
127 | //
128 | // NOTE: The Stop and Release methods should not be called from the callback
129 | // function. Doing so will result in undefined behavior.
130 | func (rd *RendererDiscoverer) Start(cb RendererDiscoveryCallback) error {
131 | if cb == nil {
132 | return ErrInvalidEventCallback
133 | }
134 |
135 | // Stop discovery service, if started.
136 | if err := rd.Stop(); err != nil {
137 | return err
138 | }
139 |
140 | // Retrieve event manager.
141 | manager, err := rd.eventManager()
142 | if err != nil {
143 | return err
144 | }
145 |
146 | // Create event callback.
147 | eventCallback := func(event *C.libvlc_event_t, userData interface{}) {
148 | if err := rd.assertInit(); err != nil {
149 | return
150 | }
151 | if event == nil {
152 | return
153 | }
154 |
155 | cRenderer := *(**C.libvlc_renderer_item_t)(unsafe.Pointer(&event.u[0]))
156 | if cRenderer == nil {
157 | return
158 | }
159 |
160 | renderer, ok := rd.renderers[cRenderer]
161 | if !ok {
162 | renderer = &Renderer{renderer: cRenderer}
163 | renderer.hold()
164 | rd.renderers[cRenderer] = renderer
165 | }
166 |
167 | switch event := Event(event._type); event {
168 | case RendererDiscovererItemAdded:
169 | cb(event, renderer)
170 | case RendererDiscovererItemDeleted:
171 | cb(event, renderer)
172 | delete(rd.renderers, cRenderer)
173 | renderer.release()
174 | }
175 | }
176 |
177 | // Attach discovery service events.
178 | events := []Event{
179 | RendererDiscovererItemAdded, RendererDiscovererItemDeleted,
180 | }
181 |
182 | eventIDs := make([]EventID, 0, len(events))
183 | for _, event := range events {
184 | eventID, err := manager.attach(event, nil, eventCallback, nil)
185 | if err != nil {
186 | return err
187 | }
188 |
189 | eventIDs = append(eventIDs, eventID)
190 | }
191 | defer func() {
192 | if rd.stopFunc == nil {
193 | manager.Detach(eventIDs...)
194 | }
195 | }()
196 |
197 | // Start discovery service.
198 | if C.libvlc_renderer_discoverer_start(rd.discoverer) < 0 {
199 | return errOrDefault(getError(), ErrRendererDiscovererStart)
200 | }
201 |
202 | rd.stopFunc = func() {
203 | // Detach events.
204 | manager.Detach(eventIDs...)
205 |
206 | // Stop discovery service.
207 | C.libvlc_renderer_discoverer_stop(rd.discoverer)
208 | }
209 |
210 | return nil
211 | }
212 |
213 | // Stop stops the discovery service.
214 | func (rd *RendererDiscoverer) Stop() error {
215 | if err := rd.assertInit(); err != nil {
216 | return err
217 | }
218 |
219 | rd.stop()
220 | return nil
221 | }
222 |
223 | func (rd *RendererDiscoverer) stop() {
224 | if rd.stopFunc != nil {
225 | rd.stopFunc()
226 | rd.stopFunc = nil
227 | }
228 | }
229 |
230 | // eventManager returns the event manager responsible for the renderer
231 | // discovery service.
232 | func (rd *RendererDiscoverer) eventManager() (*EventManager, error) {
233 | if err := rd.assertInit(); err != nil {
234 | return nil, err
235 | }
236 |
237 | manager := C.libvlc_renderer_discoverer_event_manager(rd.discoverer)
238 | if manager == nil {
239 | return nil, ErrMissingEventManager
240 | }
241 |
242 | return newEventManager(manager), nil
243 | }
244 |
245 | func (rd *RendererDiscoverer) assertInit() error {
246 | if rd == nil || rd.discoverer == nil {
247 | return ErrRendererDiscovererNotInitialized
248 | }
249 |
250 | return nil
251 | }
252 |
--------------------------------------------------------------------------------
/v3/utils.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | // #include
6 | import "C"
7 | import (
8 | "errors"
9 | "net/url"
10 | "path/filepath"
11 | "runtime"
12 | "strings"
13 | )
14 |
15 | func getError() error {
16 | msg := C.libvlc_errmsg()
17 | if msg == nil {
18 | return nil
19 | }
20 |
21 | err := errors.New(C.GoString(msg))
22 | C.libvlc_clearerr()
23 | return err
24 | }
25 |
26 | func errOrDefault(err, defaultErr error) error {
27 | if err != nil {
28 | return err
29 | }
30 |
31 | return defaultErr
32 | }
33 |
34 | func boolToInt(value bool) int {
35 | if value {
36 | return 1
37 | }
38 |
39 | return 0
40 | }
41 |
42 | func urlToPath(mrl string) (string, error) {
43 | url, err := url.Parse(mrl)
44 | if err != nil {
45 | return "", err
46 | }
47 | if url.Scheme != "file" {
48 | return mrl, nil
49 | }
50 | path := filepath.Clean(url.Path)
51 |
52 | if runtime.GOOS == "windows" {
53 | sep := string(filepath.Separator)
54 | if url.Host != "" {
55 | path = strings.Repeat(sep, 2) + filepath.Join(url.Host, path)
56 | } else {
57 | path = strings.TrimLeft(path, sep)
58 | }
59 | }
60 |
61 | return path, nil
62 | }
63 |
--------------------------------------------------------------------------------
/v3/version.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #include
5 | // #include
6 | import "C"
7 | import "fmt"
8 |
9 | // VersionInfo contains details regarding the version of the libVLC module.
10 | type VersionInfo struct {
11 | Major uint
12 | Minor uint
13 | Patch uint
14 | Extra uint
15 | }
16 |
17 | // String returns a string representation of the version.
18 | func (v VersionInfo) String() string {
19 | return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
20 | }
21 |
22 | // Runtime returns the runtime version of libVLC, usually including
23 | // the codename of the build.
24 | //
25 | // NOTE: Due to binary backward compatibility, the runtime version may be
26 | // more recent than the build version.
27 | func (v VersionInfo) Runtime() string {
28 | return C.GoString(C.libvlc_get_version())
29 | }
30 |
31 | // Changeset returns the changeset identifier for the current libVLC build.
32 | func (v VersionInfo) Changeset() string {
33 | return C.GoString(C.libvlc_get_changeset())
34 | }
35 |
36 | // Compiler returns information regarding the compiler used to build libVLC.
37 | func (v VersionInfo) Compiler() string {
38 | return C.GoString(C.libvlc_get_compiler())
39 | }
40 |
41 | var moduleVersion = VersionInfo{
42 | Major: C.LIBVLC_VERSION_MAJOR,
43 | Minor: C.LIBVLC_VERSION_MINOR,
44 | Patch: C.LIBVLC_VERSION_REVISION,
45 | Extra: C.LIBVLC_VERSION_EXTRA,
46 | }
47 |
--------------------------------------------------------------------------------
/v3/vlc.go:
--------------------------------------------------------------------------------
1 | package vlc
2 |
3 | // #cgo LDFLAGS: -lvlc
4 | // #cgo CFLAGS: -w
5 | // #include
6 | // #include
7 | import "C"
8 | import (
9 | "unsafe"
10 | )
11 |
12 | type instance struct {
13 | handle *C.libvlc_instance_t
14 | events *eventRegistry
15 | objects *objectRegistry
16 | }
17 |
18 | func (i *instance) assertInit() error {
19 | if i == nil || i.handle == nil {
20 | return ErrModuleNotInitialized
21 | }
22 |
23 | return nil
24 | }
25 |
26 | var inst *instance
27 |
28 | // Init creates an instance of the libVLC module.
29 | // Must be called only once and the module instance must be released using
30 | // the Release function.
31 | func Init(args ...string) error {
32 | if inst != nil {
33 | return nil
34 | }
35 |
36 | argc := len(args)
37 | argv := make([]*C.char, argc)
38 |
39 | for i, arg := range args {
40 | argv[i] = C.CString(arg)
41 | }
42 | defer func() {
43 | for i := range argv {
44 | C.free(unsafe.Pointer(argv[i]))
45 | }
46 | }()
47 |
48 | handle := C.libvlc_new(C.int(argc), *(***C.char)(unsafe.Pointer(&argv)))
49 | if handle == nil {
50 | return errOrDefault(getError(), ErrModuleInitialize)
51 | }
52 |
53 | inst = &instance{
54 | handle: handle,
55 | events: newEventRegistry(),
56 | objects: newObjectRegistry(),
57 | }
58 |
59 | return nil
60 | }
61 |
62 | // Release destroys the instance created by the Init function.
63 | func Release() error {
64 | if inst == nil {
65 | return nil
66 | }
67 |
68 | C.libvlc_release(inst.handle)
69 | inst = nil
70 | return nil
71 | }
72 |
73 | // Version returns details regarding the version of the libVLC module.
74 | func Version() VersionInfo {
75 | return moduleVersion
76 | }
77 |
78 | // SetAppName sets the human-readable application name and the HTTP user agent.
79 | // The specified user agent is used when a protocol requires it.
80 | func SetAppName(name, userAgent string) error {
81 | if err := inst.assertInit(); err != nil {
82 | return err
83 | }
84 |
85 | cName, cUserAgent := C.CString(name), C.CString(userAgent)
86 | C.libvlc_set_user_agent(inst.handle, cName, cUserAgent)
87 |
88 | C.free(unsafe.Pointer(cName))
89 | C.free(unsafe.Pointer(cUserAgent))
90 | return nil
91 | }
92 |
93 | // SetAppID sets metadata for identifying the application.
94 | func SetAppID(id, version, icon string) error {
95 | if err := inst.assertInit(); err != nil {
96 | return err
97 | }
98 |
99 | cID, cVersion, cIcon := C.CString(id), C.CString(version), C.CString(icon)
100 | C.libvlc_set_app_id(inst.handle, cID, cVersion, cIcon)
101 |
102 | C.free(unsafe.Pointer(cID))
103 | C.free(unsafe.Pointer(cVersion))
104 | C.free(unsafe.Pointer(cIcon))
105 | return nil
106 | }
107 |
108 | // StartUserInterface attempts to start a user interface for the libVLC
109 | // instance. Pass an empty string as the name parameter in order to start
110 | // the default interface.
111 | func StartUserInterface(name string) error {
112 | if err := inst.assertInit(); err != nil {
113 | return err
114 | }
115 |
116 | cName := C.CString(name)
117 | defer C.free(unsafe.Pointer(cName))
118 |
119 | if C.libvlc_add_intf(inst.handle, cName) < 0 {
120 | return errOrDefault(getError(), ErrUserInterfaceStart)
121 | }
122 |
123 | return nil
124 | }
125 |
--------------------------------------------------------------------------------