Révision 2436
tmp/org.txm.backtomedia.rcp/vlcj-4.1.0/pom.xml (revision 2436) | ||
---|---|---|
1 |
<!-- |
|
2 |
vlcj pom. |
|
3 |
|
|
4 |
Add the following content to your own project pom.xml file: |
|
5 |
|
|
6 |
<dependencies> |
|
7 |
<dependency> |
|
8 |
<groupId>uk.co.caprica</groupId> |
|
9 |
<artifactId>vlcj</artifactId> |
|
10 |
<version>4.1.0</version> |
|
11 |
</dependency> |
|
12 |
</dependencies> |
|
13 |
--> |
|
14 |
|
|
15 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|
16 |
|
|
17 |
<modelVersion>4.0.0</modelVersion> |
|
18 |
|
|
19 |
<parent> |
|
20 |
<groupId>org.sonatype.oss</groupId> |
|
21 |
<artifactId>oss-parent</artifactId> |
|
22 |
<version>9</version> |
|
23 |
</parent> |
|
24 |
|
|
25 |
<groupId>uk.co.caprica</groupId> |
|
26 |
<artifactId>vlcj</artifactId> |
|
27 |
<version>4.1.0</version> |
|
28 |
|
|
29 |
<name>vlcj</name> |
|
30 |
<description>Java Framework for the vlc Media Player.</description> |
|
31 |
<url>http://capricasoftware.co.uk/projects/vlcj</url> |
|
32 |
<inceptionYear>2009</inceptionYear> |
|
33 |
|
|
34 |
<packaging>jar</packaging> |
|
35 |
|
|
36 |
<licenses> |
|
37 |
<license> |
|
38 |
<name>GPL v3</name> |
|
39 |
<url>http://www.gnu.org/licenses/gpl-3.0.html</url> |
|
40 |
<distribution>repo</distribution> |
|
41 |
</license> |
|
42 |
</licenses> |
|
43 |
|
|
44 |
<organization> |
|
45 |
<name>Caprica Software Limited</name> |
|
46 |
<url>http://www.capricasoftware.co.uk</url> |
|
47 |
</organization> |
|
48 |
|
|
49 |
<developers> |
|
50 |
<developer> |
|
51 |
<id>mark</id> |
|
52 |
<name>Mark Lee</name> |
|
53 |
<email>mark.lee@capricasoftware.co.uk</email> |
|
54 |
<url>https://github.com/caprica/vlcj</url> |
|
55 |
<organization>Caprica Software Limited</organization> |
|
56 |
<organizationUrl>http://www.capricasoftware.co.uk</organizationUrl> |
|
57 |
<roles> |
|
58 |
<role>architect</role> |
|
59 |
<role>developer</role> |
|
60 |
<role>owner</role> |
|
61 |
</roles> |
|
62 |
<timezone>0</timezone> |
|
63 |
</developer> |
|
64 |
</developers> |
|
65 |
|
|
66 |
<issueManagement> |
|
67 |
<system>Github</system> |
|
68 |
<url>https://github.com/caprica/vlcj/issues</url> |
|
69 |
</issueManagement> |
|
70 |
|
|
71 |
<scm> |
|
72 |
<connection>scm:git:git@github.com:caprica/vlcj.git</connection> |
|
73 |
<developerConnection>scm:git:git@github.com:caprica/vlcj.git</developerConnection> |
|
74 |
<url>git@github.com:caprica/vlcj.git</url> |
|
75 |
</scm> |
|
76 |
|
|
77 |
<properties> |
|
78 |
<vlcjNatives.version>4.1.0</vlcjNatives.version> |
|
79 |
<vlcjOsxStubs.version>1.0.0</vlcjOsxStubs.version> |
|
80 |
</properties> |
|
81 |
|
|
82 |
<dependencies> |
|
83 |
<dependency> |
|
84 |
<groupId>uk.co.caprica</groupId> |
|
85 |
<artifactId>vlcj-natives</artifactId> |
|
86 |
<version>${vlcjNatives.version}</version> |
|
87 |
</dependency> |
|
88 |
<dependency> |
|
89 |
<groupId>uk.co.caprica</groupId> |
|
90 |
<artifactId>vlcj-osx-stubs</artifactId> |
|
91 |
<version>${vlcjOsxStubs.version}</version> |
|
92 |
<scope>provided</scope> |
|
93 |
</dependency> |
|
94 |
</dependencies> |
|
95 |
|
|
96 |
<build> |
|
97 |
<pluginManagement> |
|
98 |
<plugins> |
|
99 |
<plugin> |
|
100 |
<groupId>org.eclipse.m2e</groupId> |
|
101 |
<artifactId>lifecycle-mapping</artifactId> |
|
102 |
<version>1.0.0</version> |
|
103 |
<configuration> |
|
104 |
<lifecycleMappingMetadata> |
|
105 |
<pluginExecutions> |
|
106 |
<pluginExecution> |
|
107 |
<pluginExecutionFilter> |
|
108 |
<groupId>org.apache.maven.plugins</groupId> |
|
109 |
<artifactId>maven-enforcer-plugin</artifactId> |
|
110 |
<versionRange>[1.0.0,)</versionRange> |
|
111 |
<goals> |
|
112 |
<goal>enforce</goal> |
|
113 |
</goals> |
|
114 |
</pluginExecutionFilter> |
|
115 |
<action> |
|
116 |
<ignore /> |
|
117 |
</action> |
|
118 |
</pluginExecution> |
|
119 |
</pluginExecutions> |
|
120 |
</lifecycleMappingMetadata> |
|
121 |
</configuration> |
|
122 |
</plugin> |
|
123 |
</plugins> |
|
124 |
</pluginManagement> |
|
125 |
<plugins> |
|
126 |
<plugin> |
|
127 |
<groupId>org.apache.maven.plugins</groupId> |
|
128 |
<artifactId>maven-resources-plugin</artifactId> |
|
129 |
<version>3.1.0</version> |
|
130 |
<configuration> |
|
131 |
<encoding>UTF-8</encoding> |
|
132 |
</configuration> |
|
133 |
</plugin> |
|
134 |
<plugin> |
|
135 |
<groupId>org.apache.maven.plugins</groupId> |
|
136 |
<artifactId>maven-compiler-plugin</artifactId> |
|
137 |
<version>3.8.0</version> |
|
138 |
<configuration> |
|
139 |
<source>1.6</source> |
|
140 |
<target>1.6</target> |
|
141 |
<encoding>UTF-8</encoding> |
|
142 |
<compilerArgument>-Xlint:serial</compilerArgument> |
|
143 |
</configuration> |
|
144 |
</plugin> |
|
145 |
<plugin> |
|
146 |
<groupId>org.apache.maven.plugins</groupId> |
|
147 |
<artifactId>maven-jar-plugin</artifactId> |
|
148 |
<version>3.1.1</version> |
|
149 |
<configuration> |
|
150 |
<archive> |
|
151 |
<manifest> |
|
152 |
<addClasspath>true</addClasspath> |
|
153 |
</manifest> |
|
154 |
</archive> |
|
155 |
</configuration> |
|
156 |
<executions> |
|
157 |
<execution> |
|
158 |
<goals> |
|
159 |
<goal>test-jar</goal> |
|
160 |
</goals> |
|
161 |
<configuration> |
|
162 |
<useDefaultManifestFile>false</useDefaultManifestFile> |
|
163 |
<archive> |
|
164 |
<addMavenDescriptor>false</addMavenDescriptor> |
|
165 |
<manifestEntries> |
|
166 |
<Class-Path>${project.artifactId}-${project.version}.jar</Class-Path> |
|
167 |
</manifestEntries> |
|
168 |
</archive> |
|
169 |
</configuration> |
|
170 |
</execution> |
|
171 |
</executions> |
|
172 |
</plugin> |
|
173 |
<plugin> |
|
174 |
<groupId>org.apache.maven.plugins</groupId> |
|
175 |
<artifactId>maven-source-plugin</artifactId> |
|
176 |
<version>3.0.1</version> |
|
177 |
<executions> |
|
178 |
<execution> |
|
179 |
<id>attach-sources</id> |
|
180 |
<goals> |
|
181 |
<goal>jar-no-fork</goal> |
|
182 |
<goal>test-jar-no-fork</goal> |
|
183 |
</goals> |
|
184 |
</execution> |
|
185 |
</executions> |
|
186 |
</plugin> |
|
187 |
<plugin> |
|
188 |
<groupId>org.apache.maven.plugins</groupId> |
|
189 |
<artifactId>maven-javadoc-plugin</artifactId> |
|
190 |
<version>3.0.1</version> |
|
191 |
<configuration> |
|
192 |
<author>true</author> |
|
193 |
<charset>UTF-8</charset> |
|
194 |
<doctitle>${project.name} ${project.version} API Documentation</doctitle> |
|
195 |
<docfilessubdirs>true</docfilessubdirs> |
|
196 |
<encoding>UTF-8</encoding> |
|
197 |
<footer>(C)2019 Caprica Software Limited</footer> |
|
198 |
<show>public</show> |
|
199 |
<quiet>true</quiet> |
|
200 |
<failOnError>true</failOnError> |
|
201 |
<additionalOptions>-html5</additionalOptions> |
|
202 |
</configuration> |
|
203 |
<executions> |
|
204 |
<execution> |
|
205 |
<id>attach-javadocs</id> |
|
206 |
<goals> |
|
207 |
<goal>jar</goal> |
|
208 |
</goals> |
|
209 |
</execution> |
|
210 |
</executions> |
|
211 |
</plugin> |
|
212 |
<plugin> |
|
213 |
<groupId>org.apache.maven.plugins</groupId> |
|
214 |
<artifactId>maven-assembly-plugin</artifactId> |
|
215 |
<version>3.1.0</version> |
|
216 |
<configuration> |
|
217 |
<attach>false</attach> |
|
218 |
</configuration> |
|
219 |
<executions> |
|
220 |
<execution> |
|
221 |
<id>user_distribution</id> |
|
222 |
<phase>package</phase> |
|
223 |
<goals> |
|
224 |
<goal>single</goal> |
|
225 |
</goals> |
|
226 |
<configuration> |
|
227 |
<descriptors> |
|
228 |
<descriptor>src/main/assembly/dist.xml</descriptor> |
|
229 |
</descriptors> |
|
230 |
</configuration> |
|
231 |
</execution> |
|
232 |
</executions> |
|
233 |
</plugin> |
|
234 |
<plugin> |
|
235 |
<groupId>org.apache.maven.plugins</groupId> |
|
236 |
<artifactId>maven-dependency-plugin</artifactId> |
|
237 |
<version>3.1.1</version> |
|
238 |
<executions> |
|
239 |
<execution> |
|
240 |
<id>copy-dependencies</id> |
|
241 |
<phase>package</phase> |
|
242 |
<goals> |
|
243 |
<goal>copy-dependencies</goal> |
|
244 |
</goals> |
|
245 |
<configuration> |
|
246 |
<includeScope>runtime</includeScope> |
|
247 |
<outputDirectory>${project.build.directory}/dependencies</outputDirectory> |
|
248 |
<overWriteReleases>false</overWriteReleases> |
|
249 |
<overWriteSnapshots>false</overWriteSnapshots> |
|
250 |
<overWriteIfNewer>true</overWriteIfNewer> |
|
251 |
</configuration> |
|
252 |
</execution> |
|
253 |
</executions> |
|
254 |
</plugin> |
|
255 |
<plugin> |
|
256 |
<artifactId>jdeb</artifactId> |
|
257 |
<groupId>org.vafer</groupId> |
|
258 |
<version>1.7</version> |
|
259 |
<executions> |
|
260 |
<execution> |
|
261 |
<phase>package</phase> |
|
262 |
<goals> |
|
263 |
<goal>jdeb</goal> |
|
264 |
</goals> |
|
265 |
<configuration> |
|
266 |
<verbose>true</verbose> |
|
267 |
<dataSet> |
|
268 |
<data> |
|
269 |
<src>${project.build.directory}/${project.build.finalName}.jar</src> |
|
270 |
<type>file</type> |
|
271 |
<mapper> |
|
272 |
<type>perm</type> |
|
273 |
<prefix>/usr/share/vlcj/lib</prefix> |
|
274 |
</mapper> |
|
275 |
</data> |
|
276 |
<data> |
|
277 |
<src>${project.build.directory}/dependencies</src> |
|
278 |
<type>directory</type> |
|
279 |
<mapper> |
|
280 |
<type>perm</type> |
|
281 |
<prefix>/usr/share/vlcj/lib</prefix> |
|
282 |
</mapper> |
|
283 |
</data> |
|
284 |
<data> |
|
285 |
<src>README.md</src> |
|
286 |
<type>file</type> |
|
287 |
<mapper> |
|
288 |
<type>perm</type> |
|
289 |
<prefix>/usr/share/doc/vlcj</prefix> |
|
290 |
</mapper> |
|
291 |
</data> |
|
292 |
<data> |
|
293 |
<src>doc/copyright</src> |
|
294 |
<type>file</type> |
|
295 |
<mapper> |
|
296 |
<type>perm</type> |
|
297 |
<prefix>/usr/share/doc/vlcj</prefix> |
|
298 |
</mapper> |
|
299 |
</data> |
|
300 |
</dataSet> |
|
301 |
</configuration> |
|
302 |
</execution> |
|
303 |
</executions> |
|
304 |
</plugin> |
|
305 |
</plugins> |
|
306 |
<resources> |
|
307 |
<resource> |
|
308 |
<directory>src/main/resources</directory> |
|
309 |
<filtering>true</filtering> |
|
310 |
<excludes> |
|
311 |
<exclude>.gitignore</exclude> |
|
312 |
</excludes> |
|
313 |
</resource> |
|
314 |
</resources> |
|
315 |
</build> |
|
316 |
|
|
317 |
</project> |
tmp/org.txm.backtomedia.rcp/vlcj-4.1.0/README.md (revision 2436) | ||
---|---|---|
1 |
 |
|
2 |
|
|
3 |
*You are currently looking at the development branch for vlcj-4.0.0, if you are looking for the previous version of vlcj |
|
4 |
you should switch to the [vlcj-3.x branch](https://github.com/caprica/vlcj/tree/vlcj-3.x).* |
|
5 |
|
|
6 |
vlcj |
|
7 |
==== |
|
8 |
|
|
9 |
The vlcj project provides a Java framework to allow an instance of a native [VLC](http://www.videolan.org/vlc "VLC") |
|
10 |
media player to be embedded in a Java application. |
|
11 |
|
|
12 |
You get more than just simple bindings, you also get a higher level framework that hides a lot of the complexities of |
|
13 |
working with LibVLC. |
|
14 |
|
|
15 |
vlcj is primarily developed and therefore extensively tested on Linux - it does also work just fine on Windows and |
|
16 |
OSX, although there may be some limitations on OSX. |
|
17 |
|
|
18 |
Additionally, whilst not supported as one of the main platforms, this version of vlcj has been tested and shown to be |
|
19 |
working on contemporary Raspberry Pi builds. |
|
20 |
|
|
21 |
At least JDK 1.6 is required. |
|
22 |
|
|
23 |
*This version of vlcj requires VLC 3.0.0 as a minimum, no earlier version is supported.* |
|
24 |
|
|
25 |
This is the open source vlcj project page, see also the 'official' |
|
26 |
[home page](http://capricasoftware.co.uk/projects/vlcj "Official vlcj home page at Caprica Software") where you can find |
|
27 |
more information as well as some new simple tutorials. |
|
28 |
|
|
29 |
News |
|
30 |
==== |
|
31 |
|
|
32 |
- 5th April, 2019 - vlcj 4.1.0 release, this release brings JNA "direct mapping" which should give a modest performance boost |
|
33 |
- 1st April, 2019 - vlcj 4.0.8 released, fixes an issue with the BufferedImage in the CallbackMediaPlayerComponent |
|
34 |
- 24th March, 2019 - vlcj 4.0.7 released, minor change to allow to change the callback video surface image painter after creation |
|
35 |
- 18th March, 2019 - published a Yeoman generator for vlcj starter projects, see [generator-vlcj](https://github.com/caprica/generator-vlcj) |
|
36 |
- 5th March, 2019 - vlcj 4.0.6 released, fixes issues with image painters when using CallbackMediaPlayerComponent |
|
37 |
- 4th March, 2019 - vlcj 4.0.5 released, fixes a problem using ByteBuffer on Java8 |
|
38 |
- 4th March, 2019 - vlcj 4.0.4 released, audio callbacks can now optionally manage audio volume, some minor API changes |
|
39 |
- 1st March, 2019 - vlcj 4.0.3 released, fixes a problem with native discovery directory providers and minor API changes |
|
40 |
- 28th February, 2019 - vlcj 4.0.2 released, resolves a potential deadlock (upgrade to this version strongly recommended) |
|
41 |
- 27th February, 2019 - vlcj 4.0.1 released, primarily fixes a small number of minor public API issues |
|
42 |
- 20th February, 2019 - vlcj 4.0.0 released |
|
43 |
|
|
44 |
All releases are at available at [Maven Central](https://search.maven.org/search?q=a:vlcj). |
|
45 |
|
|
46 |
You can follow @capricasoftware on Twitter for more vlcj news. |
|
47 |
|
|
48 |
vlcj-4 |
|
49 |
====== |
|
50 |
|
|
51 |
vlcj-4 has a new API, but there is still a lot of similarity with vlcj-3 and under the covers there is still mostly the |
|
52 |
same mature and stable implementation. |
|
53 |
|
|
54 |
The vlcj-4 API is now pretty much stable, although some changes may be made depending on feedback and usage after the |
|
55 |
first release of 4.0.0 is let loose into the wild - but no further *major* API changes are planned or expected. |
|
56 |
|
|
57 |
If you are interested in using vlcj-4, now is a good time to start. |
|
58 |
|
|
59 |
vlcj-4.1 |
|
60 |
======== |
|
61 |
|
|
62 |
vlcj-4.1 brings JNA "direct mapping" which should give a modest performance boost at the expense of less helpful error |
|
63 |
messages if things go wrong when loading the native LibVLC library. |
|
64 |
|
|
65 |
If you wish to stay with "traditional" JNA bindings, then stick with the latest vlcj-4.0.x. |
|
66 |
|
|
67 |
This direct mapping approach will be used in all future versions of vlcj, meaning vlcj-4.1.x, vlcj-5.x and later. |
|
68 |
|
|
69 |
Major New Features |
|
70 |
------------------ |
|
71 |
|
|
72 |
Headline changes: |
|
73 |
|
|
74 |
- full support for 360 degree video, changing pitch, yaw, roll, field-of-view |
|
75 |
- full support for discovery and usage of alternate media renderers, e.g. Chromecast |
|
76 |
- full support for media-slave API to set subtitle tracks and additional/alternate audio tracks |
|
77 |
- full support for integrated native dialogs, e.g. you can now be prompted for credentials when accessing a protected |
|
78 |
stream |
|
79 |
- use any AWT Component as a video surface, not just a Canvas (Window will work on OSX, with limitations) |
|
80 |
- easy to add support for alternate video surfaces, e.g. an SWT Composite |
|
81 |
- major changes and improvements to the so-called "direct-rendering" media players, the direct audio and video media |
|
82 |
players are no longer separate components and are now instead intrinsic to the standard media player. For video, a |
|
83 |
new "Callback" video surface brings a vastly improved implementation, an optional related component provides a good |
|
84 |
default implementation for direct-rendering and an easy way to deal with re-sizing of the video, with easy extension |
|
85 |
points for custom video "painters" |
|
86 |
- improvements to full-screen support with sensible default implementations provided for Linux, Windows and OSX, all |
|
87 |
using a native solution to provide the best result |
|
88 |
- automatic handling of subitems (e.g. when playing a YouTube video or a streaming playlist) is now intrinsic to the |
|
89 |
media player and requires no involvement of the client application |
|
90 |
- simplified native library discovery, now intrinsic to the media player factory and it should just work out-of-the-box |
|
91 |
in the vast majority of cases |
|
92 |
- API support for multiple logos (in series, not concurrent) |
|
93 |
- logo and marquee now work without having to explicitly enable the respective native modules |
|
94 |
- there is now better support for media generally (e.g. using media without a media player, for parsing meta data etc), |
|
95 |
and also better support for media-lists (e.g. it should now be easier to manage your own play-lists) |
|
96 |
|
|
97 |
There have also been a lot of more general improvements to freshen up the codebase, make it more maintainable for the |
|
98 |
future, and to clear some legacy issues that have dogged the project for quite some time. |
|
99 |
|
|
100 |
For a full list of changes in this release, check the release milestones: |
|
101 |
|
|
102 |
- [vlcj 4.0.0 release milestone](https://github.com/caprica/vlcj/milestone/14?closed=1) |
|
103 |
- [vlcj 4.0.1 release milestone](https://github.com/caprica/vlcj/milestone/32?closed=1) |
|
104 |
- [vlcj 4.0.2 release milestone](https://github.com/caprica/vlcj/milestone/33?closed=1) |
|
105 |
- [vlcj 4.0.3 release milestone](https://github.com/caprica/vlcj/milestone/34?closed=1) |
|
106 |
- [vlcj 4.0.4 release milestone](https://github.com/caprica/vlcj/milestone/35?closed=1) |
|
107 |
- [vlcj 4.0.5 release milestone](https://github.com/caprica/vlcj/milestone/36?closed=1) |
|
108 |
- [vlcj 4.0.6 release milestone](https://github.com/caprica/vlcj/milestone/37?closed=1) |
|
109 |
- [vlcj 4.0.7 release milestone](https://github.com/caprica/vlcj/milestone/38?closed=1) |
|
110 |
- [vlcj 4.0.8 release milestone](https://github.com/caprica/vlcj/milestone/40?closed=1) |
|
111 |
|
|
112 |
vlcj 4.1.0+ uses JNA direct-mapping: |
|
113 |
|
|
114 |
- [vlcj 4.1.0 release milestone](https://github.com/caprica/vlcj/milestone/39?closed=1) |
|
115 |
|
|
116 |
Despite all of these changes, running on JDK 1.6 is still supported! |
|
117 |
|
|
118 |
Known Issues |
|
119 |
------------ |
|
120 |
|
|
121 |
- `CallbackMediaPlayerComponent` does not properly render media that does not have a sample-aspect-ratio (SAR) 1:1, |
|
122 |
this mostly affects DVD ISO, you can still provide your own implementation that handles other SAR's if you need to. |
|
123 |
In any case, using the callback media player with DVD ISO is somewhat of a niche combination and for the vast |
|
124 |
majority of media types this will not be an issue. This may be improved in a later release. The fundamental problem |
|
125 |
right now is that there is simply no *reliable* way to know the SAR - SAR does appear eventually in track information |
|
126 |
but there is no concrete link between that SAR track information and the currently playing video track. This is an |
|
127 |
issue in the underlying native library. |
|
128 |
|
|
129 |
- When using the new alternate renderer API, if you attempt to play another media while a media is already being sent |
|
130 |
to something like Chromecast you may experience problems - even if you stop the current media first. The cause of |
|
131 |
this is currently unknown, but it may be a native issue. |
|
132 |
|
|
133 |
API Breakage (vlcj-3) |
|
134 |
--------------------- |
|
135 |
|
|
136 |
This is the *tenth year* of the project, the API has been pretty much static for that entire time. The codebase has |
|
137 |
evolved gradually and incrementally in that time and resulted sometimes in sub-optimal implementations and choices, as |
|
138 |
well as some generally unwieldy individual classes containing literally thousands of lines of code. Keeping the API |
|
139 |
fixed for those almost ten years also locked in some long-standing architectural issues that simply could not be |
|
140 |
resolved. |
|
141 |
|
|
142 |
The decision to break backwards compatibility with the vlcj-3 API was not taken lightly, but the results have been worth |
|
143 |
it. All legacy architectural issues have been resolved, the giant god-classes have been factored to more manageable |
|
144 |
chunks, and ongoing maintenance will be much easier. |
|
145 |
|
|
146 |
The price for these improvements is some API breakage, sorry. |
|
147 |
|
|
148 |
The short version of the situation is that vlcj-4 can *not* be considered a drop-in upgrade for any vlcj-3 applications. |
|
149 |
If you want to move to vlcj-4 with your existing applications, you *will* be impacted, at best you will need to use new |
|
150 |
names for existing methods, at worst although very unlikely you may have to make some *deep* changes in your own |
|
151 |
codebase. |
|
152 |
|
|
153 |
There is no automatic migration tool. |
|
154 |
|
|
155 |
The longer version of the situation is documented more fully in |
|
156 |
[this ticket](https://github.com/caprica/vlcj/issues/681). |
|
157 |
|
|
158 |
Tutorials |
|
159 |
--------- |
|
160 |
|
|
161 |
New tutorials for vlcj-4 are available [here](http://capricasoftware.co.uk/projects/vlcj-4/tutorials). |
|
162 |
|
|
163 |
There are simple tests or demo applications available for pretty much every aspect of vlcj functionality, these are |
|
164 |
provided in the |
|
165 |
[project test sources](https://github.com/caprica/vlcj/tree/master/src/test/java/uk/co/caprica/vlcj/test). |
|
166 |
|
|
167 |
There is also a major demo application available at the [vlcj-player](https://github.com/caprica/vlcj-player) project |
|
168 |
page. |
|
169 |
|
|
170 |
Building vlcj - sun.misc.Unsafe |
|
171 |
------------------------------- |
|
172 |
|
|
173 |
Currently the target supported JDK is still 1.6, since there are no new language or platform features used in vlcj |
|
174 |
that need anything past 1.6. There is no particularly strong reason to keep supporting 1.6, but there is no particular |
|
175 |
reason to abandon it either. |
|
176 |
|
|
177 |
On the other hand, the project is at the moment built with OpenJDK 11 on Linux and cross-compiled to 1.6. This will |
|
178 |
work just fine when using Maven to build the project from the command-line, or when working with Eclipse. |
|
179 |
|
|
180 |
However, if you use IntelliJ IDEA you may encounter some compilation problems... |
|
181 |
|
|
182 |
When compiling, IDEA will complain that package sun.misc does not exist - the `Unsafe` class from this package is |
|
183 |
required for the "direct" media players. |
|
184 |
|
|
185 |
This can be worked around in a number of ways: |
|
186 |
|
|
187 |
- use source and target JDK 1.10 in the pom.xml, which IDEA will then incorporate into the project |
|
188 |
- use JDK 1.9 and convert the project to use the Java Module System and add jdk.unsupported as a required module |
|
189 |
- change the IDEA compiler settings to *uncheck* the "Use '--release' option for cross-compilation (Java 9 and later)" |
|
190 |
|
|
191 |
The latter option is probably the simplest to deal with. |
|
192 |
|
|
193 |
When compiling with Maven it is simply not possible to suppress the warnings about using sun.misc.Unsafe. |
|
194 |
|
|
195 |
Maven Dependency |
|
196 |
---------------- |
|
197 |
|
|
198 |
Add the following Maven dependency to your own project pom.xml: |
|
199 |
|
|
200 |
``` |
|
201 |
<dependency> |
|
202 |
<groupId>uk.co.caprica</groupId> |
|
203 |
<artifactId>vlcj</artifactId> |
|
204 |
<version>4.1.0</version> |
|
205 |
</dependency> |
|
206 |
``` |
|
207 |
|
|
208 |
The core vlcj project now no longer contains the required JNA bindings to LibVLC, these are provided instead by the |
|
209 |
separate [vlcj-natives](https://github.com/caprica/vlcj-natives) project. The vlcj core project therefore has a new |
|
210 |
required dependency on the vlcj-natives project. |
|
211 |
|
|
212 |
If you are using Maven (or similar) to manage your dependencies, the vlcj-natives dependency will be handled |
|
213 |
automatically for you (you only need to explicitly add vlcj to your project, not vlcj-natives). |
|
214 |
|
|
215 |
If you are installing vlcj manually, then you will need to include the new vlcj-natives jar file along with the existing |
|
216 |
vlcj jar file. |
|
217 |
|
|
218 |
Threading Model |
|
219 |
--------------- |
|
220 |
|
|
221 |
This section is very important. |
|
222 |
|
|
223 |
With vlcj-4, every native event coming from LibVLC is processed on the native callback thread. This should give some |
|
224 |
small performance gains when compared with vlcj-3. |
|
225 |
|
|
226 |
The critical issue is that it is generally not permitted to call back into LibVLC from the event callback thread. Doing |
|
227 |
so may cause subtle failures or outright hard JVM crashes. |
|
228 |
|
|
229 |
A prime example of the sort of trap waiting for you is the very common case of handling a media player "finished" event |
|
230 |
so that you can then play the next item in a play-list: |
|
231 |
|
|
232 |
``` |
|
233 |
mediaPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() { |
|
234 |
@Override |
|
235 |
public void finished(MediaPlayer mediaPlayer) { |
|
236 |
mediaPlayer.media().play(nextMrl); // <-- This is VERY BAD INDEED |
|
237 |
} |
|
238 |
}); |
|
239 |
``` |
|
240 |
|
|
241 |
In this example, the `finished` method is being invoked on a native callback thread owned by LibVLC. The implementation |
|
242 |
of this method is calling back into LibVLC when it invokes `play`. This is very likely to cause a JVM crash and |
|
243 |
kill your application. |
|
244 |
|
|
245 |
In cases such as this, you should make use of an asynchronous task-executor queue conveniently provided by the |
|
246 |
`MediaPlayer` object passed to the listener method: |
|
247 |
|
|
248 |
``` |
|
249 |
mediaPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() { |
|
250 |
@Override |
|
251 |
public void finished(final MediaPlayer mediaPlayer) { |
|
252 |
mediaPlayer.submit(new Runnable() { |
|
253 |
@Override |
|
254 |
public void run() { |
|
255 |
mediaPlayer.media().play(nextMrl); |
|
256 |
} |
|
257 |
}); |
|
258 |
} |
|
259 |
}); |
|
260 |
``` |
|
261 |
|
|
262 |
You should *not* use this mechanism for *all* of your event handlers, *only those that will call back into LibVLC*. |
|
263 |
|
|
264 |
Other high-level vlcj components may also provide their own asynchronous task executor, it is not limited to the media |
|
265 |
player. |
|
266 |
|
|
267 |
An added caveat for vlcj-4 is that when you implement event handling you must be sure to execute quickly, and to not |
|
268 |
block the native thread with any long-running operation. |
|
269 |
|
|
270 |
Your event handler implementations must *not* throw an `Exception`, failure of your event handlers to catch and handle |
|
271 |
any thrown exception may prevent other listeners from being notified of the event. |
|
272 |
|
|
273 |
If you are attempting to use multiple media players in your application, or using media players from multiple threads, |
|
274 |
you may need to take some extra care so that you do not have multiple threads calling into LibVLC concurrently. You may |
|
275 |
encounter subtle bugs and races that are very difficult to diagnose. |
|
276 |
|
|
277 |
In addition, you must take care not to update Swing UI components from the native thread - all Swing UI updates are |
|
278 |
supposed to go via the Swing Event Dispatch Thread (EDT). |
|
279 |
|
|
280 |
You can achieve this in the usual way by using `SwingUtilities#invokeLater` in your event handler: |
|
281 |
|
|
282 |
``` |
|
283 |
mediaPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() { |
|
284 |
@Override |
|
285 |
public void finished(MediaPlayer mediaPlayer) { |
|
286 |
SwingUtilities.invokeLater(new Runnable() { |
|
287 |
@Override |
|
288 |
public void run() { |
|
289 |
// ...change UI state here... |
|
290 |
} |
|
291 |
}); |
|
292 |
} |
|
293 |
}); |
|
294 |
``` |
|
295 |
|
|
296 |
Garbage Collection |
|
297 |
------------------ |
|
298 |
|
|
299 |
This section is also very important. |
|
300 |
|
|
301 |
Ordinarily when developing with Java you will be used to not thinking about the scope and life-cycle of the objects that |
|
302 |
you create, instead you will rely on the garbage collector in the Java Virtual Machine to just take of things for you. |
|
303 |
|
|
304 |
With vlcj's `MediaPlayerFactory`, `MediaPlayer`, and associated classes, you must take care to prevent those objects |
|
305 |
from being garbage collected - if you do not, at best your media player will simply unexpectedly stop working and at |
|
306 |
worst you may see a fatal JVM crash. |
|
307 |
|
|
308 |
Those vlcj objects wrap a native resource (e.g. a native media player). Those media player resources know nothing about |
|
309 |
any JVM. So just because a native media player is still "alive" it will not prevent your object instance from being |
|
310 |
garbage collected. If your object instance does get garbage collected, the native resource still has no idea, and will |
|
311 |
will keeping sending native events back to the JVM via a callback. If your object is gone, that native callback has |
|
312 |
nowhere to go and will most likely crash your JVM. |
|
313 |
|
|
314 |
A very common mistake is to declare vlcj objects on the local heap in some sort of initialisation method: |
|
315 |
|
|
316 |
``` |
|
317 |
private void setup() { |
|
318 |
MediaPlayerFactory factory = new MediaPlayerFactory(); |
|
319 |
EmbeddedMediaPlayer mediaPlayer = factory.mediaPlayers().newEmbeddedMediaPlayer(); |
|
320 |
// ... other initialisation ... |
|
321 |
} |
|
322 |
``` |
|
323 |
|
|
324 |
When this method returns, the `factory` and `mediaPlayer` objects go out of scope and become eligible for garbage |
|
325 |
collection. The garbage collection may happen immediately, or some time later. |
|
326 |
|
|
327 |
The most common solution is to change those local heap declarations to class fields: |
|
328 |
|
|
329 |
``` |
|
330 |
private MediaPlayerFactory factory; |
|
331 |
|
|
332 |
private EmbeddedMediaPlayer mediaPlayer; |
|
333 |
|
|
334 |
private void setup() { |
|
335 |
factory = new MediaPlayerFactory(); |
|
336 |
mediaPlayer = factory.mediaPlayers().newEmbeddedMediaPlayer(); |
|
337 |
// ... other initialisation ... |
|
338 |
} |
|
339 |
|
|
340 |
``` |
|
341 |
|
|
342 |
This is fine and will work in most cases, but you must still make sure that the enclosing class does not itself get |
|
343 |
garbage collected! |
|
344 |
|
|
345 |
See this [vlcj garbage collection tutorial](http://capricasoftware.co.uk/projects/vlcj-4/tutorials/garbage-collection) |
|
346 |
for more information. |
|
347 |
|
|
348 |
Privacy Considerations |
|
349 |
---------------------- |
|
350 |
|
|
351 |
When parsing media, depending on configuration, it may be possible that a remote network access is made for meta data |
|
352 |
and album/cover art. This may unintentionally expose sensitive data regarding the media being parsed. |
|
353 |
|
|
354 |
To affirmatively prevent all network access for meta data, consider using the `--no-metadata-network-access` argument |
|
355 |
when creating a `MediaPlayerFactory`. |
|
356 |
|
|
357 |
It should also be possible to prevent such network accesses by using appropriate `ParseFlag` values when requesting to |
|
358 |
parse media. |
|
359 |
|
|
360 |
Even with network access disabled, some media cover art may still appear locally (e.g. ~/.cache/vlc) - this does not |
|
361 |
necessarily mean that a remote network request was made for the cover art, rather the art that was already embedded in |
|
362 |
the media file was extracted to this temporary cache directory. |
|
363 |
|
|
364 |
In any case, you need to be aware of this issue and inform users of your application about it. |
|
365 |
|
|
366 |
Documentation |
|
367 |
------------- |
|
368 |
|
|
369 |
Tutorials will be made available, not yet, at the |
|
370 |
[official project page](http://capricasoftware.co.uk/projects/vlcj/tutorials). |
|
371 |
|
|
372 |
The vlcj project page is at [github](http://caprica.github.com/vlcj "vlcj at github"). |
|
373 |
|
|
374 |
Online Javadoc is available here: |
|
375 |
|
|
376 |
JNA direct-mapping: |
|
377 |
|
|
378 |
* [4.1.0 (current)](http://caprica.github.com/vlcj/javadoc/4.1.0/index.html "4.1.0 Javadoc") |
|
379 |
|
|
380 |
JNA traditional mapping: |
|
381 |
|
|
382 |
* [4.0.8 (current)](http://caprica.github.com/vlcj/javadoc/4.0.8/index.html "4.0.8 Javadoc") |
|
383 |
* [4.0.7](http://caprica.github.com/vlcj/javadoc/4.0.7/index.html "4.0.7 Javadoc") |
|
384 |
* [4.0.6](http://caprica.github.com/vlcj/javadoc/4.0.6/index.html "4.0.6 Javadoc") |
|
385 |
* [4.0.5](http://caprica.github.com/vlcj/javadoc/4.0.5/index.html "4.0.5 Javadoc") |
|
386 |
* [4.0.4](http://caprica.github.com/vlcj/javadoc/4.0.4/index.html "4.0.4 Javadoc") |
|
387 |
* [4.0.3](http://caprica.github.com/vlcj/javadoc/4.0.3/index.html "4.0.3 Javadoc") |
|
388 |
* [4.0.2](http://caprica.github.com/vlcj/javadoc/4.0.2/index.html "4.0.2 Javadoc") |
|
389 |
* [4.0.1](http://caprica.github.com/vlcj/javadoc/4.0.1/index.html "4.0.1 Javadoc") |
|
390 |
* [4.0.0](http://caprica.github.com/vlcj/javadoc/4.0.0/index.html "4.0.0 Javadoc") |
|
391 |
|
|
392 |
Examples |
|
393 |
-------- |
|
394 |
|
|
395 |
There are many examples in the vlcj test sources showing how to use vlcj. |
|
396 |
|
|
397 |
For a more complete example of a feature-rich media player built with vlcj, |
|
398 |
see [vlcj-player](https://github.com/caprica/vlcj-player). |
|
399 |
|
|
400 |
Related Projects |
|
401 |
---------------- |
|
402 |
|
|
403 |
* [vlcj-natives](https://github.com/caprica/vlcj-natives) |
|
404 |
* [vlcj-player](https://github.com/caprica/vlcj-player) |
|
405 |
* [vlcj-javafx](https://github.com/caprica/vlcj-javafx) |
|
406 |
* [vlcj-mrls](https://github.com/caprica/vlcj-mrls) |
|
407 |
* [vlcj-file-filters](https://github.com/caprica/vlcj-file-filters) |
|
408 |
* [vlcj-swt](https://github.com/caprica/vlcj-swt) |
|
409 |
* [vlcj-swt-demo](https://github.com/caprica/vlcj-swt-demo) |
|
410 |
* [vlcj-swt-swing](https://github.com/caprica/vlcj-swt-swing) |
|
411 |
* [vlcj-info](https://github.com/caprica/vlcj-info) |
|
412 |
* [vlcj-radio-demo](https://github.com/caprica/vlcj-radio-demo) |
|
413 |
* [generator-vlcj](https://github.com/caprica/generator-vlcj) |
|
414 |
|
|
415 |
Support |
|
416 |
------- |
|
417 |
|
|
418 |
Development of vlcj is carried out by [Caprica Software](http://www.capricasoftware.co.uk). |
|
419 |
|
|
420 |
Free support for Open Source and non-commercial projects is generally provided - you can |
|
421 |
use [github issues](https://github.com/caprica/vlcj/issues "vlcj github issues") for this purpose. |
|
422 |
|
|
423 |
Support for commercial projects is provided exclusively on commercial terms - send an email to the following address for |
|
424 |
more information: |
|
425 |
|
|
426 |
> mark [dot] lee [at] capricasoftware [dot] co [dot] uk |
|
427 |
|
|
428 |
License |
|
429 |
------- |
|
430 |
|
|
431 |
The vlcj framework is provided under the GPL, version 3 or later. |
|
432 |
|
|
433 |
If you want to consider a commercial license for vlcj that allows you to use and redistribute vlcj without complying |
|
434 |
with the GPL then send an email to the address below: |
|
435 |
|
|
436 |
> mark [dot] lee [at] capricasoftware [dot] co [dot] uk |
|
437 |
|
|
438 |
Contributors |
|
439 |
------------ |
|
440 |
|
|
441 |
Contributions are welcome and will always be licensed according to the Open Source license terms of the project (currently GPL). |
|
442 |
|
|
443 |
However, for a contribution to be accepted you must agree to transfer any copyright so that your contribution does not |
|
444 |
impede our ability to provide commercial licenses for vlcj. |
tmp/org.txm.backtomedia.rcp/vlcj-4.1.0/swt/SwtMediaPlayerFactory.java (revision 2436) | ||
---|---|---|
1 |
/* |
|
2 |
* This file is part of VLCJ. |
|
3 |
* |
|
4 |
* VLCJ is free software: you can redistribute it and/or modify |
|
5 |
* it under the terms of the GNU General Public License as published by |
|
6 |
* the Free Software Foundation, either version 3 of the License, or |
|
7 |
* (at your option) any later version. |
|
8 |
* |
|
9 |
* VLCJ is distributed in the hope that it will be useful, |
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
* GNU General Public License for more details. |
|
13 |
* |
|
14 |
* You should have received a copy of the GNU General Public License |
|
15 |
* along with VLCJ. If not, see <http://www.gnu.org/licenses/>. |
|
16 |
* |
|
17 |
* Copyright 2009-2019 Caprica Software Limited. |
|
18 |
*/ |
|
19 |
|
|
20 |
package uk.co.caprica.vlcj.factory.swt; |
|
21 |
|
|
22 |
import uk.co.caprica.vlcj.factory.discovery.NativeDiscovery; |
|
23 |
import uk.co.caprica.vlcj.factory.MediaPlayerFactory; |
|
24 |
|
|
25 |
import java.util.Collection; |
|
26 |
|
|
27 |
// FIXME should we build an SwtEmbeddedMediaPlayerComponent that extends Composite, similar to how we extend JPanel for SWT? |
|
28 |
|
|
29 |
/** |
|
30 |
* Extension to the default {@link MediaPlayerFactory} that provides SWT components. |
|
31 |
*/ |
|
32 |
public class SwtMediaPlayerFactory extends MediaPlayerFactory { |
|
33 |
|
|
34 |
private final SwtApi swtApi; |
|
35 |
|
|
36 |
public SwtMediaPlayerFactory(NativeDiscovery discovery, String... libvlcArgs) { |
|
37 |
super(discovery, libvlcArgs); |
|
38 |
|
|
39 |
this.swtApi = new SwtApi(this); |
|
40 |
} |
|
41 |
|
|
42 |
public SwtMediaPlayerFactory(String... libvlcArgs) { |
|
43 |
this(null, libvlcArgs); |
|
44 |
} |
|
45 |
|
|
46 |
public SwtMediaPlayerFactory(NativeDiscovery discovery, Collection<String> libvlcArgs) { |
|
47 |
this(discovery, libvlcArgs.toArray(new String[libvlcArgs.size()])); |
|
48 |
} |
|
49 |
|
|
50 |
public SwtMediaPlayerFactory(Collection<String> libvlcArgs) { |
|
51 |
this(null, libvlcArgs.toArray(new String[libvlcArgs.size()])); |
|
52 |
} |
|
53 |
|
|
54 |
/** |
|
55 |
* |
|
56 |
* |
|
57 |
* @return |
|
58 |
*/ |
|
59 |
public final SwtApi swt() { |
|
60 |
return swtApi; |
|
61 |
} |
|
62 |
|
|
63 |
@Override |
|
64 |
public void onBeforeRelease() { |
|
65 |
swtApi.release(); |
|
66 |
} |
|
67 |
|
|
68 |
} |
|
0 | 69 |
tmp/org.txm.backtomedia.rcp/vlcj-4.1.0/swt/BaseApi.java (revision 2436) | ||
---|---|---|
1 |
/* |
|
2 |
* This file is part of VLCJ. |
|
3 |
* |
|
4 |
* VLCJ is free software: you can redistribute it and/or modify |
|
5 |
* it under the terms of the GNU General Public License as published by |
|
6 |
* the Free Software Foundation, either version 3 of the License, or |
|
7 |
* (at your option) any later version. |
|
8 |
* |
|
9 |
* VLCJ is distributed in the hope that it will be useful, |
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
* GNU General Public License for more details. |
|
13 |
* |
|
14 |
* You should have received a copy of the GNU General Public License |
|
15 |
* along with VLCJ. If not, see <http://www.gnu.org/licenses/>. |
|
16 |
* |
|
17 |
* Copyright 2009-2019 Caprica Software Limited. |
|
18 |
*/ |
|
19 |
|
|
20 |
package uk.co.caprica.vlcj.factory.swt; |
|
21 |
|
|
22 |
abstract class BaseApi { |
|
23 |
|
|
24 |
protected final SwtMediaPlayerFactory factory; |
|
25 |
|
|
26 |
BaseApi(SwtMediaPlayerFactory factory) { |
|
27 |
this.factory = factory; |
|
28 |
} |
|
29 |
|
|
30 |
protected void release() {} |
|
31 |
|
|
32 |
} |
|
0 | 33 |
tmp/org.txm.backtomedia.rcp/vlcj-4.1.0/swt/SwtApi.java (revision 2436) | ||
---|---|---|
1 |
/* |
|
2 |
* This file is part of VLCJ. |
|
3 |
* |
|
4 |
* VLCJ is free software: you can redistribute it and/or modify |
|
5 |
* it under the terms of the GNU General Public License as published by |
|
6 |
* the Free Software Foundation, either version 3 of the License, or |
|
7 |
* (at your option) any later version. |
|
8 |
* |
|
9 |
* VLCJ is distributed in the hope that it will be useful, |
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
* GNU General Public License for more details. |
|
13 |
* |
|
14 |
* You should have received a copy of the GNU General Public License |
|
15 |
* along with VLCJ. If not, see <http://www.gnu.org/licenses/>. |
|
16 |
* |
|
17 |
* Copyright 2009-2019 Caprica Software Limited. |
|
18 |
*/ |
|
19 |
|
|
20 |
package uk.co.caprica.vlcj.factory.swt; |
|
21 |
|
|
22 |
import org.eclipse.swt.widgets.Composite; |
|
23 |
import uk.co.caprica.vlcj.player.embedded.videosurface.VideoSurfaceAdapters; |
|
24 |
import uk.co.caprica.vlcj.player.embedded.videosurface.swt.CompositeVideoSurface; |
|
25 |
|
|
26 |
/** |
|
27 |
* |
|
28 |
*/ |
|
29 |
public final class SwtApi extends BaseApi { |
|
30 |
|
|
31 |
/** |
|
32 |
* |
|
33 |
* |
|
34 |
* @param mediaPlayerFactory |
|
35 |
*/ |
|
36 |
public SwtApi(SwtMediaPlayerFactory mediaPlayerFactory) { |
|
37 |
super(mediaPlayerFactory); |
|
38 |
} |
|
39 |
|
|
40 |
/** |
|
41 |
* |
|
42 |
* |
|
43 |
* @param composite |
|
44 |
* @return |
|
45 |
*/ |
|
46 |
public CompositeVideoSurface newCompositeVideoSurface(Composite composite) { |
|
47 |
return new CompositeVideoSurface(composite, VideoSurfaceAdapters.getVideoSurfaceAdapter()); |
|
48 |
} |
|
49 |
|
|
50 |
} |
|
0 | 51 |
tmp/org.txm.backtomedia.rcp/vlcj-4.1.0/vlcplayer/VLCPlayer.java (revision 2436) | ||
---|---|---|
1 |
package org.txm.backtomedia.editors.vlcplayer; |
|
2 |
|
|
3 |
import static uk.co.caprica.vlcj.binding.LibVlc.libvlc_new; |
|
4 |
import static uk.co.caprica.vlcj.binding.LibVlc.libvlc_release; |
|
5 |
|
|
6 |
import java.io.File; |
|
7 |
import java.time.LocalTime; |
|
8 |
import java.time.format.DateTimeFormatter; |
|
9 |
|
|
10 |
import org.eclipse.osgi.util.NLS; |
|
11 |
import org.eclipse.swt.SWT; |
|
12 |
import org.eclipse.swt.events.DisposeEvent; |
|
13 |
import org.eclipse.swt.events.DisposeListener; |
|
14 |
import org.eclipse.swt.events.SelectionEvent; |
|
15 |
import org.eclipse.swt.events.SelectionListener; |
|
16 |
import org.eclipse.swt.layout.GridData; |
|
17 |
import org.eclipse.swt.layout.GridLayout; |
|
18 |
import org.eclipse.swt.widgets.Button; |
|
19 |
import org.eclipse.swt.widgets.Composite; |
|
20 |
import org.eclipse.swt.widgets.FileDialog; |
|
21 |
import org.eclipse.swt.widgets.Label; |
|
22 |
import org.eclipse.swt.widgets.Scale; |
|
23 |
import org.txm.backtomedia.commands.function.TripleRangeSlider; |
|
24 |
import org.txm.backtomedia.preferences.BackToMediaPreferences; |
|
25 |
import org.txm.utils.logger.Log; |
|
26 |
|
|
27 |
import com.sun.jna.StringArray; |
|
28 |
|
|
29 |
import uk.co.caprica.vlcj.binding.LibC; |
|
30 |
import uk.co.caprica.vlcj.binding.RuntimeUtil; |
|
31 |
import uk.co.caprica.vlcj.binding.internal.libvlc_instance_t; |
|
32 |
import uk.co.caprica.vlcj.factory.discovery.NativeDiscovery; |
|
33 |
import uk.co.caprica.vlcj.factory.discovery.strategy.NativeDiscoveryStrategy; |
|
34 |
import uk.co.caprica.vlcj.factory.swt.SwtMediaPlayerFactory; |
|
35 |
import uk.co.caprica.vlcj.media.MediaRef; |
|
36 |
import uk.co.caprica.vlcj.player.base.MediaPlayer; |
|
37 |
import uk.co.caprica.vlcj.player.base.MediaPlayerEventAdapter; |
|
38 |
import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent; |
|
39 |
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer; |
|
40 |
import uk.co.caprica.vlcj.player.embedded.videosurface.swt.CompositeVideoSurface; |
|
41 |
import uk.co.caprica.vlcj.support.version.LibVlcVersion; |
|
42 |
import vlcplayerrcp.MessagesMP; |
|
43 |
|
|
44 |
public class VLCPlayer extends Composite { |
|
45 |
|
|
46 |
static { // force native libs discovery -> fix Mac OS X init |
|
47 |
NativeDiscovery discovery = new NativeDiscovery() { |
|
48 |
|
|
49 |
@Override |
|
50 |
protected void onFound(String path, NativeDiscoveryStrategy strategy) { |
|
51 |
Log.finer("VLC NativeDiscovery: onFound " + path + " " + strategy); |
|
52 |
} |
|
53 |
|
|
54 |
@Override |
|
55 |
protected void onNotFound() { |
|
56 |
Log.finer("VLC NativeDiscovery: Not found."); |
|
57 |
} |
|
58 |
}; |
|
59 |
boolean found = discovery.discover(); |
|
60 |
Log.finer("VLC NativeDiscovery: the discovery was succesfull ? " + found); |
|
61 |
if (found) { |
|
62 |
libvlc_instance_t instance = libvlc_new(0, new StringArray(new String[0])); |
|
63 |
Log.finer("VLC NativeDiscovery: VLC instance is " + instance); |
|
64 |
if (instance != null) { |
|
65 |
libvlc_release(instance); |
|
66 |
} |
|
67 |
else { |
|
68 |
Log.warning(NLS.bind("** Impossible to use your VLC [{0}] (please check that you have at least VLC version 3.0).", instance)); |
|
69 |
} |
|
70 |
Log.finer("VLC NativeDiscovery: VLC version is " + new LibVlcVersion().getVersion()); |
|
71 |
} |
|
72 |
else { |
|
73 |
Log.warning("** Impossible to find VLC (please check that you have at least VLC version 3.0)."); |
|
74 |
} |
|
75 |
} |
|
76 |
|
|
77 |
protected static final String NOMEDIA = ""; //$NON-NLS-1$ |
|
78 |
|
|
79 |
private EmbeddedMediaPlayer vlcPlayer; |
|
80 |
|
|
81 |
private Composite videoComposite; |
|
82 |
|
|
83 |
private CompositeVideoSurface playerCanvas; |
|
84 |
|
|
85 |
private Scale rateField; |
|
86 |
|
|
87 |
private Label rateValueLabel; |
|
88 |
|
|
89 |
private Scale volumeField; |
|
90 |
|
|
91 |
private Label volumeValueLabel; |
|
92 |
|
|
93 |
private Button playButton; |
|
94 |
|
|
95 |
private Button repeatButton; |
|
96 |
|
|
97 |
protected String currentlyPlayed = ""; //$NON-NLS-1$ |
|
98 |
|
|
99 |
// private String startTime, endTime; |
|
100 |
private int start, end; |
|
101 |
|
|
102 |
protected boolean hasEnded = false; |
|
103 |
|
|
104 |
private String previouslyPlayed = ""; //$NON-NLS-1$ |
|
105 |
|
|
106 |
private boolean repeat = false; |
|
107 |
|
|
108 |
protected int volume = 100; |
|
109 |
|
|
110 |
private Button stopButton; |
|
111 |
|
|
112 |
Label timeLabel; |
|
113 |
|
|
114 |
TripleRangeSlider timeRange; |
|
115 |
|
|
116 |
boolean firstLengthEvent = true; |
|
117 |
|
|
118 |
long previous = 0; |
|
119 |
|
|
120 |
long time, mins, secs; |
|
121 |
|
|
122 |
private SwtMediaPlayerFactory factory; |
|
123 |
|
|
124 |
|
|
125 |
static { |
|
126 |
// uncomment to enable VLC logs |
|
127 |
// Logger.setLevel(Level.TRACE); |
|
128 |
} |
|
129 |
|
|
130 |
public EmbeddedMediaPlayer getEmbeddedMediaPlayer() { |
|
131 |
return vlcPlayer; |
|
132 |
} |
|
133 |
|
|
134 |
public VLCPlayer(Composite parent, int style) { |
|
135 |
super(parent, style); |
|
136 |
this.setLayout(new GridLayout(11, false)); |
|
137 |
|
|
138 |
// THE PLAYER |
|
139 |
// if (RuntimeUtil.isMac()) { |
|
140 |
// try { |
|
141 |
// LibC.INSTANCE.setenv("VLC_PLUGIN_PATH", "/Applications/VLC.app/Contents/MacOS/plugins", 1); |
|
142 |
// } |
|
143 |
// catch (Exception ex) { |
|
144 |
// ex.printStackTrace(); |
|
145 |
// } |
|
146 |
// } |
|
147 |
videoComposite = new Composite(this, SWT.EMBEDDED | SWT.NO_BACKGROUND); |
|
148 |
GridData gdata = new GridData(SWT.FILL, SWT.FILL, true, true); |
|
149 |
gdata.horizontalSpan = 11; |
|
150 |
videoComposite.setLayoutData(gdata); |
|
151 |
|
|
152 |
factory = new SwtMediaPlayerFactory(); |
|
153 |
playerCanvas = factory.swt().newCompositeVideoSurface(videoComposite); |
|
154 |
|
|
155 |
EmbeddedMediaPlayerComponent e = new EmbeddedMediaPlayerComponent(); |
|
156 |
vlcPlayer = e.mediaPlayer(); |
|
157 |
vlcPlayer.videoSurface().set(playerCanvas); |
|
158 |
|
|
159 |
videoComposite.addDisposeListener(new DisposeListener() { |
|
160 |
|
|
161 |
@Override |
|
162 |
public void widgetDisposed(DisposeEvent e) { |
|
163 |
// vlcPlayer.submit(new Runnable() { |
|
164 |
// |
|
165 |
// @Override |
|
166 |
// public void run() { |
|
167 |
// // vlcPlayer.controls().stop(); |
|
168 |
// } |
|
169 |
// }); |
|
170 |
vlcPlayer.controls().stop(); |
|
171 |
vlcPlayer.release(); |
|
172 |
factory.release(); |
|
173 |
} |
|
174 |
}); |
|
175 |
|
|
176 |
// THE CONTROL BUTTONS |
|
177 |
playButton = new Button(this, SWT.PUSH); |
|
178 |
GridData playLayoutData = new GridData(SWT.FILL, SWT.CENTER, false, false); |
|
179 |
playButton.setLayoutData(playLayoutData); |
|
180 |
playButton.setText(MessagesMP.play); |
|
181 |
playButton.addSelectionListener(new SelectionListener() { |
|
182 |
|
|
183 |
@Override |
|
184 |
public void widgetSelected(SelectionEvent e) { |
|
185 |
vlcPlayer.submit(new Runnable() { |
|
186 |
|
|
187 |
@Override |
|
188 |
public void run() { |
|
189 |
if (currentlyPlayed.length() == 0) { |
|
190 |
selectMedia(); |
|
191 |
playButton.setText(MessagesMP.pause); |
|
192 |
} |
|
193 |
else if (vlcPlayer.status().isPlaying()) { |
|
194 |
vlcPlayer.controls().pause(); |
|
195 |
playButton.setText(MessagesMP.resume); |
|
196 |
} |
|
197 |
else if (hasEnded) { |
|
198 |
replay(); |
|
199 |
} |
|
200 |
else { |
|
201 |
vlcPlayer.controls().play(); |
|
202 |
playButton.setText(MessagesMP.pause); |
|
203 |
} |
|
204 |
} |
|
205 |
}); |
|
206 |
} |
|
207 |
|
|
208 |
@Override |
|
209 |
public void widgetDefaultSelected(SelectionEvent e) {} |
|
210 |
}); |
|
211 |
|
|
212 |
// Button browseButton = new Button(this,SWT.PUSH); |
|
213 |
// browseButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); |
|
214 |
// browseButton.setText("Open..."); |
|
215 |
// browseButton.addSelectionListener(new SelectionListener() { |
|
216 |
// @Override |
|
217 |
// public void widgetSelected(SelectionEvent e) { |
|
218 |
// selectMedia(); |
|
219 |
// } |
|
220 |
// |
|
221 |
// @Override |
|
222 |
// public void widgetDefaultSelected(SelectionEvent e) {} |
|
223 |
// }); |
|
224 |
|
|
225 |
stopButton = new Button(this, SWT.PUSH); |
|
226 |
stopButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); |
|
227 |
stopButton.setText(MessagesMP.stop); |
|
228 |
stopButton.addSelectionListener(new SelectionListener() { |
|
229 |
|
|
230 |
@Override |
|
231 |
public void widgetSelected(SelectionEvent e) { |
|
232 |
stop(); |
|
233 |
} |
|
234 |
|
|
235 |
@Override |
|
236 |
public void widgetDefaultSelected(SelectionEvent e) {} |
|
237 |
}); |
|
238 |
|
|
239 |
timeLabel = new Label(this, SWT.NONE); |
|
240 |
timeLabel.setText("00:00"); //$NON-NLS-1$ |
|
241 |
|
|
242 |
timeRange = new TripleRangeSlider(this, SWT.None); |
|
243 |
timeRange.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); |
|
244 |
timeRange.setToolTipText(MessagesMP.time_range); |
|
245 |
timeRange.addSelectionListener(new SelectionListener() { |
|
246 |
|
|
247 |
@Override |
|
248 |
public void widgetSelected(SelectionEvent e) { |
|
249 |
TripleRangeSlider.SELECTED_KNOB sk = timeRange.getLastSelectedKnob(); |
|
250 |
switch (sk) { |
|
251 |
case UPPER: |
|
252 |
end = timeRange.getUpperValue(); |
|
253 |
|
|
254 |
if (end < time) { |
|
255 |
// System.out.println("Upper changed: fix time"); |
|
256 |
time = end; |
|
257 |
vlcPlayer.controls().setTime(time); |
|
258 |
} |
|
259 |
break; |
|
260 |
case LOWER: |
|
261 |
start = timeRange.getLowerValue(); |
|
262 |
if (start > time) { |
|
263 |
// System.out.println("Lower changed: fix time"); |
|
264 |
time = start; |
|
265 |
vlcPlayer.controls().setTime(time); |
|
266 |
} |
|
267 |
break; |
|
268 |
case MIDDLE: |
|
269 |
|
|
270 |
time = timeRange.getMiddleValue(); |
|
271 |
// System.out.println("Middle changed: fix time: "+time); |
|
272 |
vlcPlayer.controls().setTime(time); |
|
273 |
break; |
|
274 |
default: |
|
275 |
// nothing |
|
276 |
} |
|
277 |
// System.out.println("time range: "+start+" -> "+end+" time="+time); |
|
278 |
} |
|
279 |
|
|
280 |
@Override |
|
281 |
public void widgetDefaultSelected(SelectionEvent e) {} |
|
282 |
}); |
|
283 |
|
|
284 |
repeatButton = new Button(this, SWT.CHECK); |
|
285 |
repeatButton.setText(MessagesMP.repeat); |
|
286 |
repeat = BackToMediaPreferences.getInstance().getBoolean(BackToMediaPreferences.REPEAT); |
|
287 |
repeatButton.setSelection(repeat); |
|
288 |
repeatButton.addSelectionListener(new SelectionListener() { |
|
289 |
|
|
290 |
@Override |
|
291 |
public void widgetSelected(SelectionEvent e) { |
|
292 |
repeat = repeatButton.getSelection(); |
|
293 |
} |
|
294 |
|
|
295 |
@Override |
|
296 |
public void widgetDefaultSelected(SelectionEvent e) {} |
|
297 |
}); |
|
298 |
|
|
299 |
Label l = new Label(this, SWT.NONE); |
|
300 |
l.setText(MessagesMP.rate); |
|
301 |
|
|
302 |
rateField = new Scale(this, SWT.BORDER); |
|
303 |
GridData gdata4 = new GridData(SWT.FILL, SWT.CENTER, false, false); |
|
304 |
gdata4.widthHint = 100; |
|
305 |
rateField.setLayoutData(gdata4); |
|
306 |
rateField.setMaximum(140); |
|
307 |
rateField.setMinimum(70); |
|
308 |
rateField.setSelection(100); |
|
309 |
rateField.setPageIncrement(5); |
|
310 |
|
|
311 |
rateField.addSelectionListener(new SelectionListener() { |
|
312 |
|
|
313 |
@Override |
|
314 |
public void widgetSelected(SelectionEvent e) { |
|
315 |
float rate = rateField.getSelection() / 100.0f; |
|
316 |
vlcPlayer.controls().setRate(rate); |
|
317 |
rateValueLabel.setText("" + rateField.getSelection() + "%"); |
|
318 |
} |
|
319 |
|
|
320 |
@Override |
|
321 |
public void widgetDefaultSelected(SelectionEvent e) {} |
|
322 |
}); |
|
323 |
|
|
324 |
rateValueLabel = new Label(this, SWT.NONE); |
|
325 |
rateValueLabel.setText("100%");//$NON-NLS-1$ |
|
326 |
|
|
327 |
l = new Label(this, SWT.NONE); |
|
328 |
l.setText(MessagesMP.volume); |
|
329 |
|
|
330 |
volumeField = new Scale(this, SWT.BORDER); |
|
331 |
gdata4 = new GridData(SWT.FILL, SWT.CENTER, false, false); |
|
332 |
gdata4.widthHint = 100; |
|
333 |
volumeField.setLayoutData(gdata4); |
|
334 |
volumeField.setMinimum(0); |
|
335 |
volumeField.setMaximum(100); |
|
336 |
volumeField.setSelection(volume); |
|
337 |
volumeField.setPageIncrement(5); |
|
338 |
volumeField.addSelectionListener(new SelectionListener() { |
|
339 |
|
|
340 |
@Override |
|
341 |
public void widgetSelected(SelectionEvent e) { |
|
342 |
vlcPlayer.audio().setVolume(volumeField.getSelection()); |
|
343 |
volume = volumeField.getSelection(); |
|
344 |
volumeValueLabel.setText("" + volume + "%"); |
|
345 |
} |
|
346 |
|
|
347 |
@Override |
|
348 |
public void widgetDefaultSelected(SelectionEvent e) {} |
|
349 |
}); |
|
350 |
|
|
351 |
volumeValueLabel = new Label(this, SWT.NONE); |
|
352 |
volumeValueLabel.setText("100%"); |
|
353 |
|
|
354 |
vlcPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() { |
|
355 |
|
|
356 |
@Override |
|
357 |
public void opening(MediaPlayer mediaPlayer) { |
|
358 |
Log.finer("Opening media..."); |
|
359 |
} |
|
360 |
|
|
361 |
@Override |
|
362 |
public void finished(MediaPlayer mediaPlayer) { |
|
363 |
Log.finer("Finished playing media..."); |
|
364 |
mediaPlayer.submit(new Runnable() { |
|
365 |
|
|
366 |
@Override |
|
367 |
public void run() { |
|
368 |
if (repeat) { |
|
369 |
replay(); |
|
370 |
} |
|
371 |
else { |
|
372 |
hasEnded = true; |
|
373 |
} |
|
374 |
} |
|
375 |
}); |
|
376 |
} |
|
377 |
}); |
|
378 |
|
|
379 |
vlcPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() { |
|
380 |
|
|
381 |
@Override |
|
382 |
public void timeChanged(MediaPlayer mediaPlayer, final long arg1) { |
|
383 |
|
|
384 |
mediaPlayer.submit(new Runnable() { |
|
385 |
|
|
386 |
@Override |
|
387 |
public void run() { |
|
388 |
time = arg1; |
|
389 |
if (previous == time) { |
|
390 |
return; |
|
391 |
} |
|
392 |
previous = time; |
|
393 |
|
|
394 |
timeLabel.getDisplay().syncExec(new Runnable() { |
|
395 |
|
|
396 |
@Override |
|
397 |
public void run() { |
|
398 |
if (timeRange.isDisposed()) { |
|
399 |
return; |
|
400 |
} |
|
401 |
if (!timeRange.isDragMiddleKnob()) { |
|
402 |
timeRange.setMiddleValue((int) time); |
|
403 |
} |
|
404 |
updateTimeLabel(); |
|
405 |
|
|
406 |
if (arg1 > end && end != start) { |
|
407 |
// System.out.println("Time > end :"+arg1 +" > "+end); |
|
408 |
if (repeat) { |
|
409 |
vlcPlayer.controls().setTime(start); |
|
410 |
} |
|
411 |
else { |
|
412 |
vlcPlayer.controls().stop(); |
|
413 |
} |
|
414 |
} |
|
415 |
} |
|
416 |
}); |
|
417 |
} |
|
418 |
}); |
|
419 |
} |
|
420 |
|
|
421 |
@Override |
|
422 |
public void lengthChanged(MediaPlayer mediaPlayer, final long arg1) { |
|
423 |
|
|
424 |
mediaPlayer.submit(new Runnable() { |
|
425 |
|
|
426 |
@Override |
|
427 |
public void run() { |
|
428 |
if (firstLengthEvent) { |
|
429 |
firstLengthEvent = false; |
|
430 |
|
|
431 |
// initialize time range widget limits |
|
432 |
timeRange.getDisplay().syncExec(new Runnable() { |
|
433 |
|
|
434 |
@Override |
|
435 |
public void run() { |
|
436 |
if (timeRange.isDisposed()) return; |
|
437 |
timeRange.setMaximum((int) arg1); |
|
438 |
// if (start == end) end = (int)arg1; |
|
439 |
|
|
440 |
|
|
441 |
if (end > 0 && start != end) { |
|
442 |
timeRange.setUpperValue(end); |
|
443 |
} |
|
444 |
else { |
|
445 |
timeRange.setUpperValue((int) arg1); |
|
446 |
} |
|
447 |
|
|
448 |
timeRange.setLowerValue(start); |
|
449 |
// System.out.println("Range: "+start+" -> "+end+" song length "+arg1); |
|
450 |
} |
|
451 |
}); |
|
452 |
} |
|
453 |
} |
|
454 |
}); |
|
455 |
} |
|
456 |
}); |
|
457 |
} |
|
458 |
|
|
459 |
private void updateTimeLabel() { |
|
460 |
mins = time / 60000; |
|
461 |
secs = (time / 1000) % 60; |
|
462 |
timeLabel.setText(String.format("%02d:%02d", mins, secs)); //$NON-NLS-1$ |
|
463 |
timeLabel.update(); |
|
464 |
} |
|
465 |
|
|
466 |
protected void replay() { |
|
467 |
if (currentlyPlayed.length() > 0) { |
|
468 |
// this.play(currentlyPlayed, startTime, endTime); |
|
469 |
vlcPlayer.submit(new Runnable() { |
|
470 |
|
|
471 |
@Override |
|
472 |
public void run() { |
|
473 |
vlcPlayer.controls().setTime(start); |
|
474 |
} |
|
475 |
}); |
|
476 |
|
|
477 |
playButton.setText(MessagesMP.pause); |
|
478 |
} |
|
479 |
} |
|
480 |
|
|
481 |
protected void selectMedia() { |
|
482 |
Log.fine(MessagesMP.select_file); |
|
483 |
|
|
484 |
FileDialog fd = new FileDialog(VLCPlayer.this.getShell(), SWT.OPEN); |
|
485 |
fd.setText(MessagesMP.select_file_title); |
|
486 |
File f = new File(previouslyPlayed); |
|
487 |
if (f.isDirectory()) fd.setFilterPath(f.getPath()); |
|
488 |
else fd.setFilterPath(f.getParent()); |
|
489 |
|
|
490 |
String[] filterExt = { "*.*", "*.mp3", "*.mp4", "*.avi" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
|
491 |
fd.setFilterExtensions(filterExt); |
|
492 |
String selected = fd.open(); |
|
493 |
if (selected == null) { |
|
494 |
System.out.println(MessagesMP.cancel); |
|
495 |
return; |
|
496 |
} |
|
497 |
|
|
498 |
currentlyPlayed = selected; |
|
499 |
previouslyPlayed = selected; |
|
500 |
Log.fine(MessagesMP.opening + currentlyPlayed); |
|
501 |
play(currentlyPlayed, 0, 0); |
|
502 |
} |
|
503 |
|
|
504 |
/** |
|
505 |
* |
|
506 |
* @param mrl |
|
507 |
* @param time msec start time |
|
508 |
* @param endtime msec end time |
|
509 |
*/ |
|
510 |
public void play(String mrl, int time, int endtime) { |
|
511 |
Log.fine(MessagesMP.bind(MessagesMP.playing, new Object[] { mrl, time, endtime })); |
|
512 |
play(mrl, "" + time / 1000.0f, "" + endtime / 1000.0f); //$NON-NLS-1$ //$NON-NLS-2$ |
|
513 |
} |
|
514 |
|
|
515 |
public void play(String mrl, int time) { |
|
516 |
play(mrl, time, time); |
|
517 |
} |
|
518 |
|
|
519 |
public void hideStopButton() { |
|
520 |
if (this.stopButton != null && !this.stopButton.isDisposed()) { |
|
521 |
this.stopButton.dispose(); |
|
522 |
} |
|
523 |
} |
|
524 |
|
|
525 |
DateTimeFormatter hhmmssFormatter = DateTimeFormatter.ISO_LOCAL_TIME; |
|
526 |
|
|
527 |
/** |
|
528 |
* |
|
529 |
* @param mrl |
|
530 |
* @param startTime "0.0" or ""hh:mm:ss" format |
|
531 |
* @param endTime "0.0" or ""hh:mm:ss" format |
|
532 |
*/ |
|
533 |
public boolean play(String mrl, String startTime, String endTime) { |
|
534 |
|
|
535 |
if (startTime.matches("[0-9]+.[0-9]+")) { |
|
536 |
start = (int) (1000 * Float.parseFloat(startTime)); |
|
537 |
} |
|
538 |
else if (startTime.matches("[0-9]+:[0-9]+:[0-9]+")) { |
|
539 |
if (startTime.indexOf(":") == 1) { |
|
540 |
startTime = "0" + startTime; |
|
541 |
} |
|
542 |
LocalTime time1 = LocalTime.parse(startTime, hhmmssFormatter); |
Formats disponibles : Unified diff