Import Upstream version 0.11.3

This commit is contained in:
rtlhq 2022-09-24 23:29:46 +08:00
commit 36f66f4b7c
89 changed files with 10528 additions and 0 deletions

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
.svn
Makefile
CMakeTmp
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
cmake_uninstall.cmake
lib/
*.o
*.so
*.user
build

2
.krazy Normal file
View File

@ -0,0 +1,2 @@
SKIP /build
SKIP /src/vlc.desktop.cmake

34
AUTHORS Normal file
View File

@ -0,0 +1,34 @@
The phonon-VLC authors are:
---------------------------
Harald Sitter
Casian Andrei
Ben Cooksley
Jean-Baptiste Kempf
Mark Kretschmann
Martin T. H. Sandsmark
Patrick von Reth
Andreas Hartmetz
Rémi Duraffort
Colin Guthrie
Fathi Boudra
Patrick Spendrin
Rémi Denis-Courmont
Arno Rehn
Kamil Klimek
Michael Forney
Raphael Kubo da Costa
Alex Neundorf
Benoit Calvez
Myriam Schweingruber
Romain Perier
Valentin Rusu
Albert Astals Cid
Alejandro Wainzinger
Alexander Potashev
Andrius da Costa Ribas
Arnaud Le Roy
Locke Shinseiko
Pino Toscano
Ralf Habacker
Thiago Macieira

56
CMakeLists.txt Normal file
View File

@ -0,0 +1,56 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(PhononVLC VERSION 0.11.3)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(FeatureSummary)
# ECM
find_package(ECM 5.60 NO_MODULE)
set_package_properties(ECM PROPERTIES
TYPE REQUIRED
DESCRIPTION "Extra CMake Modules"
URL "https://api.kde.org/frameworks/extra-cmake-modules/html/index.html")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
include(KDEInstallDirs)
include(ECMPoQmTools)
include(KDECMakeSettings)
include(KDECompilerSettings)
include(ECMSetupVersion)
# Phonon
find_package(Phonon4Qt5 4.10.60 NO_MODULE)
set_package_properties(Phonon4Qt5 PROPERTIES
TYPE REQUIRED
DESCRIPTION "Phonon core library"
URL "https://api.kde.org/phonon/html/index.html")
find_package(Phonon4Qt5Experimental 4.10.60 NO_MODULE)
set_package_properties(Phonon4Qt5Experimental PROPERTIES
TYPE OPTIONAL
DESCRIPTION "Phonon experimental library"
URL "https://api.kde.org/phonon/html/index.html")
if(Phonon4Qt5Experimental_FOUND)
set(PHONON_EXPERIMENTAL TRUE)
endif()
# LibVLC
find_package(LIBVLC 2.1.0)
set_package_properties(LIBVLC PROPERTIES
TYPE REQUIRED
DESCRIPTION "VLC C library"
URL "http://git.videolan.org")
ecm_setup_version(PROJECT VARIABLE_PREFIX PHONON_VLC)
# PVLC only uses static mimetype lists, they are created by cmake, hooray.
include(MimeTypes.cmake)
add_subdirectory(src)
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po")
ecm_install_po_files_as_qm(po)
endif()
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)

462
COPYING.LIB Normal file
View File

@ -0,0 +1,462 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations
below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it
becomes a de-facto standard. To achieve this, non-free programs must
be allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control
compilation and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at least
three years, to give the same user the materials specified in
Subsection 6a, above, for a charge no more than the cost of
performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply, and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License
may add an explicit geographical distribution limitation excluding those
countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS

2
Messages.sh Normal file
View File

@ -0,0 +1,2 @@
#! /usr/bin/env bash
$EXTRACT_TR_STRINGS $(find . -name "*.cpp" -o -name "*.h") -o $podir/phonon_vlc_qt.pot

165
MimeTypes.cmake Normal file
View File

@ -0,0 +1,165 @@
# Copyright (C) 2012, Harald Sitter <sitter@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
set(PHONON_VLC_MIME_TYPES
application/mpeg4-iod
application/mpeg4-muxcodetable
application/mxf
application/ogg
application/ram
application/sdp
application/vnd.apple.mpegurl
application/vnd.ms-asf
application/vnd.ms-wpl
application/vnd.rn-realmedia
application/vnd.rn-realmedia-vbr
application/x-cd-image
application/x-extension-m4a
application/x-extension-mp4
application/x-flac
application/x-flash-video
application/x-matroska
application/x-ogg
application/x-quicktime-media-link
application/x-quicktimeplayer
application/x-shockwave-flash
application/xspf+xml
audio/3gpp
audio/3gpp2
audio/AMR
audio/AMR-WB
audio/aac
audio/ac3
audio/basic
audio/dv
audio/eac3
audio/flac
audio/m4a
audio/midi
audio/mp1
audio/mp2
audio/mp3
audio/mp4
audio/mpeg
audio/mpegurl
audio/mpg
audio/ogg
audio/opus
audio/scpls
audio/vnd.dolby.heaac.1
audio/vnd.dolby.heaac.2
audio/vnd.dolby.mlp
audio/vnd.dts
audio/vnd.dts.hd
audio/vnd.rn-realaudio
audio/vorbis
audio/wav
audio/webm
audio/x-aac
audio/x-adpcm
audio/x-aiff
audio/x-ape
audio/x-flac
audio/x-gsm
audio/x-it
audio/x-m4a
audio/x-matroska
audio/x-mod
audio/x-mp1
audio/x-mp2
audio/x-mp3
audio/x-mpeg
audio/x-mpegurl
audio/x-mpg
audio/x-ms-asf
audio/x-ms-asx
audio/x-ms-wax
audio/x-ms-wma
audio/x-musepack
audio/x-pn-aiff
audio/x-pn-au
audio/x-pn-realaudio
audio/x-pn-realaudio-plugin
audio/x-pn-wav
audio/x-pn-windows-acm
audio/x-real-audio
audio/x-realaudio
audio/x-s3m
audio/x-scpls
audio/x-shorten
audio/x-speex
audio/x-tta
audio/x-vorbis
audio/x-vorbis+ogg
audio/x-wav
audio/x-wavpack
audio/x-xm
image/vnd.rn-realpix
misc/ultravox
text/google-video-pointer
text/x-google-video-pointer
video/3gp
video/3gpp
video/3gpp2
video/avi
video/divx
video/dv
video/fli
video/flv
video/mp2t
video/mp4
video/mp4v-es
video/mpeg
video/mpeg-system
video/msvideo
video/ogg
video/quicktime
video/vnd.divx
video/vnd.mpegurl
video/vnd.rn-realvideo
video/webm
video/x-anim
video/x-avi
video/x-flc
video/x-fli
video/x-flv
video/x-m4v
video/x-matroska
video/x-mpeg
video/x-mpeg-system
video/x-mpeg2
video/x-ms-asf
video/x-ms-asf-plugin
video/x-ms-asx
video/x-ms-wm
video/x-ms-wmv
video/x-ms-wmx
video/x-ms-wvx
video/x-msvideo
video/x-nsv
video/x-ogm
video/x-ogm+ogg
video/x-theora
video/x-theora+ogg
x-content/audio-cdda
x-content/audio-player
x-content/video-dvd
x-content/video-svcd
x-content/video-vcd
)
macro(CREATE_C_ARRAY var list)
set(ret "")
foreach(str ${PHONON_VLC_MIME_TYPES})
if(NOT ret)
set(ret "\"${str}\"")
else(NOT ret)
set(ret "${ret}, \"${str}\"")
endif(NOT ret)
endforeach(str)
set(${var} "{${ret}, 0}")
endmacro(CREATE_C_ARRAY var list)
CREATE_C_ARRAY(PHONON_VLC_MIME_TYPES_C_ARRAY ${PHONON_VLC_MIME_TYPES})

View File

@ -0,0 +1,22 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

89
cmake/FindKDEWin.cmake Normal file
View File

@ -0,0 +1,89 @@
# - Try to find the KDEWIN library
#
# Once done this will define
#
# KDEWIN_FOUND - system has KDEWIN
# KDEWIN_INCLUDES - the KDEWIN include directories
# KDEWIN_LIBRARIES - The libraries needed to use KDEWIN
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
# Copyright (c) 2007-2009, Ralf Habacker, <ralf.habacker@freenet.de>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
if (WIN32)
if(WINCE)
FIND_PACKAGE(WCECOMPAT REQUIRED)
endif(WINCE)
if (NOT KDEWIN_LIBRARY)
find_path(KDEWIN_INCLUDE_DIR kdewin_export.h
${KDE4_INCLUDE_DIR}
${CMAKE_INCLUDE_PATH}
${CMAKE_INSTALL_PREFIX}/include
)
# search for kdewin in the default install directory for applications (default of (n)make install)
FILE(TO_CMAKE_PATH "${CMAKE_LIBRARY_PATH}" _cmakeLibraryPathCmakeStyle)
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_TOLOWER)
if (CMAKE_BUILD_TYPE_TOLOWER MATCHES debug)
set (LIBRARY_NAME kdewind)
else(CMAKE_BUILD_TYPE_TOLOWER MATCHES debug)
set (LIBRARY_NAME kdewin)
endif (CMAKE_BUILD_TYPE_TOLOWER MATCHES debug)
find_library(KDEWIN_LIBRARY
NAMES ${LIBRARY_NAME}
PATHS
${KDE4_LIB_DIR}
${_cmakeLibraryPathCmakeStyle}
${CMAKE_INSTALL_PREFIX}/lib
NO_SYSTEM_ENVIRONMENT_PATH
)
endif (NOT KDEWIN_LIBRARY)
if (KDEWIN_LIBRARY AND KDEWIN_INCLUDE_DIR)
set(KDEWIN_FOUND TRUE)
# add needed system libs
if(NOT WINCE)
set(KDEWIN_LIBRARIES ${KDEWIN_LIBRARY} user32 shell32 ws2_32 netapi32 userenv)
else(NOT WINCE)
set(KDEWIN_LIBRARIES ${KDEWIN_LIBRARY} ws2 ${WCECOMPAT_LIBRARIES})
endif(NOT WINCE)
if (MINGW)
#mingw compiler
set(KDEWIN_INCLUDES ${KDEWIN_INCLUDE_DIR} ${KDEWIN_INCLUDE_DIR}/mingw ${QT_INCLUDES})
else (MINGW)
# msvc compiler
# add the MS SDK include directory if available
file(TO_CMAKE_PATH "$ENV{MSSDK}" MSSDK_DIR)
if (WINCE)
set(KDEWIN_INCLUDES ${KDEWIN_INCLUDE_DIR} ${KDEWIN_INCLUDE_DIR}/msvc ${WCECOMPAT_INCLUDE_DIR} ${QT_INCLUDES} ${MSSDK_DIR})
else(WINCE)
set(KDEWIN_INCLUDES ${KDEWIN_INCLUDE_DIR} ${KDEWIN_INCLUDE_DIR}/msvc ${QT_INCLUDES} ${MSSDK_DIR})
endif(WINCE)
endif (MINGW)
endif (KDEWIN_LIBRARY AND KDEWIN_INCLUDE_DIR)
# required for configure
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${KDEWIN_INCLUDES})
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${KDEWIN_LIBRARIES})
if (KDEWIN_FOUND)
if (NOT KDEWin_FIND_QUIETLY)
message(STATUS "Found KDEWin library: ${KDEWIN_LIBRARY}")
endif (NOT KDEWin_FIND_QUIETLY)
else (KDEWIN_FOUND)
if (KDEWin_FIND_REQUIRED)
message(FATAL_ERROR "Could NOT find KDEWin library\nPlease install it first")
endif (KDEWin_FIND_REQUIRED)
endif (KDEWIN_FOUND)
endif (WIN32)

118
cmake/FindLIBVLC.cmake Normal file
View File

@ -0,0 +1,118 @@
# CMake module to search for LIBVLC (VLC library)
#
# Copyright (C) 2011-2018, Harald Sitter <sitter@kde.org>
# Copyright (C) 2010, Rohit Yadav <rohityadav89@gmail.com>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
# If it's found it sets LIBVLC_FOUND to TRUE
# and following variables are set:
# LIBVLC_INCLUDE_DIR
# LIBVLC_LIBRARY
# LIBVLC_VERSION
if(NOT LIBVLC_MIN_VERSION)
set(LIBVLC_MIN_VERSION "0.0")
endif(NOT LIBVLC_MIN_VERSION)
# find_path and find_library normally search standard locations
# before the specified paths. To search non-standard paths first,
# FIND_* is invoked first with specified paths and NO_DEFAULT_PATH
# and then again with no specified paths to search the default
# locations. When an earlier FIND_* succeeds, subsequent FIND_*s
# searching for the same item do nothing.
if (NOT WIN32)
find_package(PkgConfig)
pkg_check_modules(PC_LIBVLC libvlc)
set(LIBVLC_DEFINITIONS ${PC_LIBVLC_CFLAGS_OTHER})
endif (NOT WIN32)
#Put here path to custom location
#example: /home/user/vlc/include etc..
find_path(LIBVLC_INCLUDE_DIR vlc/vlc.h
HINTS "$ENV{LIBVLC_INCLUDE_PATH}" ${PC_LIBVLC_INCLUDEDIR} ${PC_LIBVLC_INCLUDE_DIRS}
PATHS
"$ENV{LIB_DIR}/include"
"$ENV{LIB_DIR}/include/vlc"
"/usr/include"
"/usr/include/vlc"
"/usr/local/include"
"/usr/local/include/vlc"
#mingw
c:/msys/local/include
)
find_path(LIBVLC_INCLUDE_DIR PATHS "${CMAKE_INCLUDE_PATH}/vlc" NAMES vlc.h
HINTS ${PC_LIBVLC_INCLUDEDIR} ${PC_LIBVLC_INCLUDE_DIRS})
#Put here path to custom location
#example: /home/user/vlc/lib etc..
find_library(LIBVLC_LIBRARY NAMES vlc libvlc
HINTS "$ENV{LIBVLC_LIBRARY_PATH}" ${PC_LIBVLC_LIBDIR} ${PC_LIBVLC_LIBRARY_DIRS}
PATHS
"$ENV{LIB_DIR}/lib"
#mingw
c:/msys/local/lib
)
find_library(LIBVLC_LIBRARY NAMES vlc libvlc)
find_library(LIBVLCCORE_LIBRARY NAMES vlccore libvlccore
HINTS "$ENV{LIBVLC_LIBRARY_PATH}" ${PC_LIBVLC_LIBDIR} ${PC_LIBVLC_LIBRARY_DIRS}
PATHS
"$ENV{LIB_DIR}/lib"
#mingw
c:/msys/local/lib
)
find_library(LIBVLCCORE_LIBRARY NAMES vlccore libvlccore)
set(LIBVLC_VERSION ${PC_LIBVLC_VERSION})
if (NOT LIBVLC_VERSION)
file(READ "${LIBVLC_INCLUDE_DIR}/vlc/libvlc_version.h" _libvlc_version_h)
string(REGEX MATCH "# define LIBVLC_VERSION_MAJOR +\\(([0-9])\\)" _dummy "${_libvlc_version_h}")
set(_version_major "${CMAKE_MATCH_1}")
string(REGEX MATCH "# define LIBVLC_VERSION_MINOR +\\(([0-9])\\)" _dummy "${_libvlc_version_h}")
set(_version_minor "${CMAKE_MATCH_1}")
string(REGEX MATCH "# define LIBVLC_VERSION_REVISION +\\(([0-9])\\)" _dummy "${_libvlc_version_h}")
set(_version_revision "${CMAKE_MATCH_1}")
# Optionally, one could also parse LIBVLC_VERSION_EXTRA, but it does not
# seem to be used by libvlc.pc.
set(LIBVLC_VERSION "${_version_major}.${_version_minor}.${_version_revision}")
endif (NOT LIBVLC_VERSION)
if (LIBVLC_INCLUDE_DIR AND LIBVLC_LIBRARY AND LIBVLCCORE_LIBRARY)
set(LIBVLC_FOUND TRUE)
endif (LIBVLC_INCLUDE_DIR AND LIBVLC_LIBRARY AND LIBVLCCORE_LIBRARY)
if (LIBVLC_VERSION STRLESS "${LIBVLC_MIN_VERSION}")
message(WARNING "LibVLC version not found: version searched: ${LIBVLC_MIN_VERSION}, found ${LIBVLC_VERSION}\nUnless you are on Windows this is bound to fail.")
# TODO: only activate once version detection can be garunteed (which is currently not the case on windows)
# set(LIBVLC_FOUND FALSE)
endif (LIBVLC_VERSION STRLESS "${LIBVLC_MIN_VERSION}")
if (NOT LIBVLC_FIND_QUIETLY)
message(STATUS "Found LibVLC include-dir path: ${LIBVLC_INCLUDE_DIR}")
message(STATUS "Found LibVLC library path:${LIBVLC_LIBRARY}")
message(STATUS "Found LibVLCcore library path:${LIBVLCCORE_LIBRARY}")
message(STATUS "Found LibVLC version: ${LIBVLC_VERSION} (searched for: ${LIBVLC_MIN_VERSION})")
endif (NOT LIBVLC_FIND_QUIETLY)
if(LIBVLC_FOUND AND NOT TARGET LibVLC::LibVLC)
add_library(LibVLC::LibVLC UNKNOWN IMPORTED)
set_target_properties(LibVLC::LibVLC PROPERTIES
IMPORTED_LOCATION "${LIBVLC_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${LIBVLC_INCLUDE_DIR}"
)
endif()
if(LIBVLC_FOUND AND NOT TARGET LibVLC::Core)
add_library(LibVLC::Core UNKNOWN IMPORTED)
set_target_properties(LibVLC::Core PROPERTIES
IMPORTED_LOCATION "${LIBVLCCORE_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${LIBVLC_INCLUDE_DIR}"
)
endif()

46
po/ca/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,46 @@
# Translation of phonon_vlc_qt.po to Catalan
# Copyright (C) 2011-2019 This_file_is_part_of_KDE
# This file is distributed under the license LGPL version 2.1 or
# version 3 or later versions approved by the membership of KDE e.V.
#
# Josep Ma. Ferrer <txemaq@gmail.com>, 2011, 2012, 2019.
# Antoni Bella Pérez <antonibella5@yahoo.com>, 2019.
msgid ""
msgstr ""
"Project-Id-Version: phonon-vlc\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:43+0200\n"
"PO-Revision-Date: 2019-08-07 10:31+0200\n"
"Last-Translator: Antoni Bella Pérez <antonibella5@yahoo.com>\n"
"Language-Team: Catalan <kde-i18n-ca@kde.org>\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 19.07.70\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Accelerator-Marker: &\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Ha fallat en inicialitzar la «libVLC»"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Ha fallat en iniciar el dorsal VLC de Phonon.\n"
"\n"
"Això normalment vol dir que hi ha un problema amb la instal·lació del VLC. "
"Si us plau, informeu de l'error al distribuïdor."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Predeterminat"

View File

@ -0,0 +1,46 @@
# Translation of phonon_vlc_qt.po to Catalan (Valencian)
# Copyright (C) 2011-2019 This_file_is_part_of_KDE
# This file is distributed under the license LGPL version 2.1 or
# version 3 or later versions approved by the membership of KDE e.V.
#
# Josep Ma. Ferrer <txemaq@gmail.com>, 2011, 2012, 2019.
# Antoni Bella Pérez <antonibella5@yahoo.com>, 2019.
msgid ""
msgstr ""
"Project-Id-Version: phonon-vlc\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:43+0200\n"
"PO-Revision-Date: 2019-08-07 10:31+0200\n"
"Last-Translator: Antoni Bella Pérez <antonibella5@yahoo.com>\n"
"Language-Team: Catalan <kde-i18n-ca@kde.org>\n"
"Language: ca@valencia\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 19.07.70\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Accelerator-Marker: &\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Ha fallat en inicialitzar la «libVLC»"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Ha fallat en iniciar el dorsal VLC de Phonon.\n"
"\n"
"Això normalment vol dir que hi ha un problema amb la instal·lació del VLC. "
"Per favor, informeu de l'error al distribuïdor."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Predeterminat"

44
po/cs/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,44 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
# Vít Pelčák <vit@pelcak.org>, 2011, 2012, 2019.
# Lukáš Tinkl <lukas@kde.org>, 2012.
# Tomáš Chvátal <tomas.chvatal@gmail.com>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-07-18 15:19+0200\n"
"Last-Translator: Vit Pelcak <vit@pelcak.org>\n"
"Language-Team: Czech <kde-i18n-doc@kde.org>\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 19.04.2\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Inicializace libVLC selhala"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Podpůrná vrstva Phononu VLC nemohla být spuštěna.\n"
"\n"
"To obvykle znamená problém s instalací VLC. Prosím, nahlaste chybu tvůrci "
"vaší distribuce."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Výchozí"

37
po/da/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,37 @@
# Martin Schlander <mschlander@opensuse.org>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"PO-Revision-Date: 2020-04-08 21:14+0200\n"
"Last-Translator: Martin Schlander <mschlander@opensuse.org>\n"
"Language-Team: Danish <kde-i18n-doc@kde.org>\n"
"Language: da\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Lokalize 18.12.3\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "LibVLC kunne ikke initialisere"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Phonons VLC-motor kunne ikke starte.\n"
"\n"
"Dette skyldes normalt et problem med din VLC-installation. Rapportér "
"venligst fejlen til din distributør."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Standard"

42
po/de/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,42 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Burkhard Lück <lueck@hube-lueck.de>, 2018, 2019.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-07-05 15:28+0200\n"
"Last-Translator: Burkhard Lück <lueck@hube-lueck.de>\n"
"Language-Team: German <kde-i18n-de@kde.org>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Lokalize 18.12.3\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "LibVLC kann nicht initialisiert werden"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Das VLC-Backend von Phonon kann nicht gestartet werden.\n"
"\n"
"Das weist meisten auf ein Problem mit Ihrer VLC-Installation hin. Berichten "
"Sie diesen Fehler bitte bei Ihrem Distributor."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Standard"

42
po/en_GB/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,42 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Steve Allewell <steve.allewell@gmail.com>, 2017, 2019.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-08-03 17:00+0100\n"
"Last-Translator: Steve Allewell <steve.allewell@gmail.com>\n"
"Language-Team: British English <kde-l10n-en_gb@kde.org>\n"
"Language: en_GB\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Lokalize 19.07.70\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "LibVLC Failed to Initialise"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Default"

44
po/es/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,44 @@
# Spanish translations for phonon_vlc.po package.
# Copyright (C) 2017 This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Automatically generated, 2017.
# Eloy Cuadra <ecuadra@eloihr.net>, 2017, 2019.
msgid ""
msgstr ""
"Project-Id-Version: phonon_vlc\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-07-09 19:06+0200\n"
"Last-Translator: Eloy Cuadra <ecuadra@eloihr.net>\n"
"Language-Team: Spanish <kde-l10n-es@kde.org>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Lokalize 19.04.2\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Ha fallado la inicialización de LibVLC"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Ha fallado el inicio del motor VLC de Phonon.\n"
"\n"
"Esto suele significar que hay un problema en su instalación de VLC. Por "
"favor, informe del error a su distribuidor."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Por omisión"

42
po/et/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,42 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Marek Laane <bald@smail.ee>, 2011, 2012, 2019.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:43+0200\n"
"PO-Revision-Date: 2019-11-08 00:18+0200\n"
"Last-Translator: Marek Laane <qiilaq69@gmail.com>\n"
"Language-Team: Estonian <kde-et@lists.linux.ee>\n"
"Language: et\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 19.08.1\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "LibVLC initsialiseerimine nurjus"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Phononi VLC taustaprogrammi käivitamine nurjus.\n"
"\n"
"Tavaliselt tähendab see probleemi sinu VLC paigaldusega, palun anna veast "
"teada oma distributsiooni pakkujale."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Vaikimisi"

41
po/eu/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,41 @@
# Translation of phonon_vlc_qt.po to Euskara/Basque (eu).
# KDE euskaratzeko proiektuaren arduraduna <xalba@euskalnet.net>.
#
# Translators:
# Iñigo Salvador Azurmendi <xalba@euskalnet.net>, 2019.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"PO-Revision-Date: 2019-07-07 22:18+0200\n"
"Last-Translator: Iñigo Salvador Azurmendi <xalba@euskalnet.net>\n"
"Language-Team: Basque <kde-i18n-eu@kde.org>\n"
"Language: eu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Lokalize 19.04.2\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "LibVLC hasieratzea huts egin du"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Phonon-en VLC bizkarraldekoa abiatzea huts egin du.\n"
"\n"
"Honek adierazi ohi du zure instalaziorekin arazo bat dagoela, bidali akats "
"txosten bat zure banatzaileari."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Lehenetsia"

47
po/fi/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,47 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
# Lasse Liehu <lasse.liehu@gmail.com>, 2011, 2013.
# Tommi Nieminen <translator@legisign.org>, 2019.
#
# KDE Finnish translation sprint participants:
# Author: Artnay
# Author: Rytilahti
msgid ""
msgstr ""
"Project-Id-Version: phonon_vlc\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-07-30 23:06+0200\n"
"Last-Translator: Tommi Nieminen <translator@legisign.org>\n"
"Language-Team: Finnish <kde-i18n-doc@kde.org>\n"
"Language: fi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-POT-Import-Date: 2012-12-01 22:27:40+0000\n"
"X-Generator: Lokalize 2.0\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "LibVLC:n alustus epäonnistui"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Phononin VLC-taustajärjestelmän käynnistys epäonnistui.\n"
"\n"
"Tämä tarkoittaa yleensä, että VLC-asennus on virheellinen. Ilmoita viasta "
"jakelullesi."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Oletus"

48
po/fr/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,48 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
# Geoffray Levasseur <geoffray.levasseurbrandin@numericable.fr>, 2011, 2012, 2013.
# xavier <ktranslator31@yahoo.fr>, 2013.
# Simon Depiets <sdepiets@gmail.com>, 2019.
# Xavier Besnard <xavier.besnard@neuf.fr>, 2021.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2021-01-13 17:49+0100\n"
"Last-Translator: Xavier Besnard <xavier.besnard@neuf.fr>\n"
"Language-Team: French <kde-francophone@kde.org>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Lokalize 20.12.0\n"
"X-Environment: kde\n"
"X-Accelerator-Marker: &\n"
"X-Text-Markup: qtrich\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "L'initialisation de « LibVLC » a échoué."
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Le démarrage du moteur « VLC » de Phonon a échoué.\n"
"\n"
"Ceci signifie généralement qu'il y a un problème avec votre installation de "
"VLC. Veuillez donc rapporter un bogue à votre distributeur."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Par défaut"

42
po/gl/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,42 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
# Marce Villarino <mvillarino@kde-espana.es>, 2011, 2012, 2014.
# Adrián Chaves (Gallaecio) <adrian@chaves.io>, 2017, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-07-06 20:23+0200\n"
"Last-Translator: Adrián Chaves (Gallaecio) <adrian@chaves.io>\n"
"Language-Team: Galician <kde-i18n-doc@kde.org>\n"
"Language: gl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Non se puido inicializar LibVLC"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Non se puido iniciar a infraestrutura de VLC para Phonon.\n"
"\n"
"Xeralmente isto indica que hai algún problema coa instalación do VLC. Envíe "
"un informe do fallo ao distribuidor."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Predeterminado"

37
po/hu/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,37 @@
# Kristóf Kiszel <kiszel.kristof@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"PO-Revision-Date: 2021-01-02 10:00+0100\n"
"Last-Translator: Kristóf Kiszel <kiszel.kristof@gmail.com>\n"
"Language-Team: Hungarian <kde-l10n-hu@kde.org>\n"
"Language: hu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Lokalize 21.03.70\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "A LibVLC inicializálása meghiúsult"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Nem sikerült elindítani a Phono VLC modulját.\n"
"\n"
"Ez általában azt jelenti, hogy hiba van a VLC telepítésével. Jelentse a "
"hibát a disztribúció fejlesztőinek."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Alapértelmezett"

41
po/id/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,41 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
# Wantoyo <wantoyek@gmail.com>, 2018, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-07-04 21:10+0700\n"
"Last-Translator: Wantoyo <wantoyek@gmail.com>\n"
"Language-Team: Indonesian <kde-i18n-doc@kde.org>\n"
"Language: id\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "LibVLC Gagal Mengnisialisasi"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Backend phonon VLC gagal dimulaikan.\n"
"\n"
"Ini mungkin biasanya bermasalah dengan penginstalan VLC-mu, silakan laporkan "
"bug kepada distributormu."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Baku"

41
po/it/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,41 @@
# translation of phonon_vlc.po to Italian
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the phonon_vlc package.
# Luigi Toscano <luigi.toscano@tiscali.it>, 2011, 2012, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: phonon_vlc\n"
"PO-Revision-Date: 2019-07-04 12:51+0200\n"
"Last-Translator: Luigi Toscano <luigi.toscano@tiscali.it>\n"
"Language-Team: Italian <kde-i18n-it@kde.org>\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Lokalize 18.12.2\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Inizializzazione di LibVLC non riuscita"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Si è verificato un errore durante l'esecuzione del motore VLC di Phonon.\n"
"\n"
"Questo di solito indica un problema nell'installazione di VLC, segnala il "
"bug presso il tuo distributore."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Predefinito"

41
po/ko/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,41 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
# Shinjo Park <kde@peremen.name>, 2011, 2013, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-07-18 23:25+0200\n"
"Last-Translator: Shinjo Park <kde@peremen.name>\n"
"Language-Team: Korean <kde-kr@kde.org>\n"
"Language: ko\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Qt-Contexts: true\n"
"X-Generator: Lokalize 18.12.3\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "LibVLC를 초기화할 수 없음"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Phonon VLC 백엔드를 시작할 수 없습니다.\n"
"\n"
"VLC 설치에 문제가 있는 것 같으므로 배포자에게 문의하십시오."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "기본값"

42
po/nl/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,42 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Freek de Kruijf <freekdekruijf@kde.nl>, 2011, 2012, 2019.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-07-04 21:28+0200\n"
"Last-Translator: Freek de Kruijf <freekdekruijf@kde.nl>\n"
"Language-Team: Dutch <kde-i18n-nl@kde.org>\n"
"Language: nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 19.04.2\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Initialisatie van LibVLC is mislukt"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Het opstarten van de VLC-backend van Phonon is mislukt.\n"
"\n"
"Dit betekent meestal een probleem met uw VLC-installatie, aub. een "
"bugrapport indienen bij uw leverancier."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Standaard"

44
po/nn/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,44 @@
# Translation of phonon_vlc_qt to Norwegian Nynorsk
#
# Karl Ove Hufthammer <karl@huftis.org>, 2015, 2019.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-07-17 20:51+0200\n"
"Last-Translator: Karl Ove Hufthammer <karl@huftis.org>\n"
"Language-Team: Norwegian Nynorsk <l10n-no@lister.huftis.org>\n"
"Language: nn\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Lokalize 19.04.2\n"
"X-Environment: kde\n"
"X-Accelerator-Marker: &\n"
"X-Text-Markup: qtrich\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Klarte ikkje starta LibVLC"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Klarte ikkje starta VLC-motoren til Phonon.\n"
"\n"
"Ein vanleg grunn er at VLC ikkje er rett installert. Meld eventuelt frå som "
"ein feil i distroen din."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Standard"

38
po/pl/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,38 @@
# Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>, 2019.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"PO-Revision-Date: 2019-07-13 06:38+0200\n"
"Last-Translator: Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>\n"
"Language-Team: Polish <kde-i18n-doc@kde.org>\n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\n"
"X-Generator: Lokalize 19.07.70\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Nie udało się zainicjować LibVLC"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Nie udało się uruchomić silnika VLC Phonona.\n"
"\n"
"Zazwyczaj oznacza to kłopot z wgranym VLC. Należy zgłosić to do dystrybutora "
"tego pakietu."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Domyślne"

43
po/pt/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,43 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: phonon_vlc\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:43+0200\n"
"PO-Revision-Date: 2019-07-04 11:08+0100\n"
"Last-Translator: José Nuno Coelho Pires <zepires@gmail.com>\n"
"Language-Team: Portuguese <kde-i18n-pt@kde.org>\n"
"Language: pt\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POFile-SpellExtra: LibVLC VLC\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Não Foi Possível Inicializar a LibVLC"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Não foi possível iniciar a infra-estrutura de VLC para o Phonon.\n"
"\n"
"Isto normalmente significa que há um problema na sua instalação do VLC; "
"comunique por favor um erro à sua distribuição."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Predefinição"

37
po/pt_BR/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,37 @@
# Luiz Fernando Ranghetti <elchevive@opensuse.org>, 2019.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"PO-Revision-Date: 2019-07-04 12:19-0300\n"
"Last-Translator: Luiz Fernando Ranghetti <elchevive@opensuse.org>\n"
"Language-Team: Portuguese <kde-i18n-pt_BR@kde.org>\n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Lokalize 19.04.2\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Falha ao inicializar a LibVLC"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Não foi possível iniciar a infraestrutura VLC do Phonon.\n"
"\n"
"Isto normalmente significa que há um problema na sua instalação do VLC. "
"Comunique este erro à sua distribuição."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Padrão"

42
po/ro/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,42 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
# Sergiu Bivol <sergiu@cip.md>, 2011, 2020.
# Cristian Oneț <onet.cristian@gmail.com>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"PO-Revision-Date: 2020-09-13 13:16+0100\n"
"Last-Translator: Sergiu Bivol <sergiu@cip.md>\n"
"Language-Team: Romanian\n"
"Language: ro\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < "
"20)) ? 1 : 2;\n"
"X-Generator: Lokalize 19.12.3\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Inițializarea LibVLC a eșuat"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Pornirea platformei VLC pentru Phonon a eșuat.\n"
"\n"
"De obicei, aceasta indică o problemă cu instalarea VLC. Raportați o eroare "
"la distribuitorul dumneavoastră."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Implicit"

38
po/ru/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,38 @@
# Alexander Yavorsky <kekcuha@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"PO-Revision-Date: 2020-05-05 18:06+0300\n"
"Last-Translator: Alexander Yavorsky <kekcuha@gmail.com>\n"
"Language-Team: Russian <kde-russian@lists.kde.ru>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Generator: Lokalize 20.04.0\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Не удалось инициализировать LibVLC"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Не удалось запустить модуль поддержки VLC для Phonon.\n"
"\n"
"Обычно это связано с неправильной установкой VLC. Пожалуйста, сообщите об "
"ошибке разработчикам вашего дистрибутива."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "По умолчанию"

42
po/sk/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,42 @@
# translation of phonon_vlc.po to Slovak
# Roman Paholik <wizzardsk@gmail.com>, 2012.
# Roman Paholík <wizzardsk@gmail.com>, 2012.
# Matej Mrenica <matejm98mthw@gmail.com>, 2019.
msgid ""
msgstr ""
"Project-Id-Version: phonon_vlc\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-08-08 12:07+0200\n"
"Last-Translator: Matej Mrenica <matejm98mthw@gmail.com>\n"
"Language-Team: Slovak <kde-i18n-doc@kde.org>\n"
"Language: sk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 19.07.90\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Zlyhala inicializácia LibVLC"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Zlyhalo spustenie Phonon VLC backendu.\n"
"\n"
"Toto obyčajne znamená problém s vašou inštaláciou VLC, prosím zadajte chybu "
"s vašim poskytovateľom."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Predvolené"

48
po/sl/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,48 @@
# Slovenian translation of phonon_vlc.
# Copyright (C) 2011 Free Software Foundation, Inc.
#
#
# Klemen Košir <klemen.kosir@gmx.com>, 2011.
# Andrej Vernekar <andrej.vernekar@gmail.com>, 2012.
# Andrej Mernik <andrejm@ubuntu.si>, 2013.
# Matjaž Jeran <matjaz.jeran@amis.net>, 2019.
msgid ""
msgstr ""
"Project-Id-Version: phonon_vlc\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: 2021-03-19 15:54+0100\n"
"Last-Translator: Matjaž Jeran <matjaz.jeran@amis.net>\n"
"Language-Team: Slovenian <lugos-slo@lugos.si>\n"
"Language: sl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Translator: Andrej Mernik <andrejm@ubuntu.si>\n"
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100>=3 && n"
"%100<=4 ? 2 : 3);\n"
"X-Generator: Poedit 2.4.2\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Začetnih vrednosti knjižnice libVLC ni bilo mogoče nastaviti"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Zaledja VLC za Phonon ni bilo mogoče zagnati.\n"
"\n"
"Razlog za to napako je ponavadi težava z namestitvijo programa VLC. Prosimo "
"sporočite napako vašemu distributerju."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Privzeto"

42
po/sv/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,42 @@
# Copyright (C) YEAR This_file_is_part_of_KDE
# This file is distributed under the same license as the PACKAGE package.
#
# Stefan Asserhäll <stefan.asserhall@bredband.net>, 2017, 2019.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-07-04 17:31+0100\n"
"Last-Translator: Stefan Asserhäll <stefan.asserhall@bredband.net>\n"
"Language-Team: Swedish <kde-i18n-doc@kde.org>\n"
"Language: sv\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Lokalize 2.0\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Initiering av libVLC misslyckades"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Phonons VLC-gränssnitt misslyckades starta.\n"
"\n"
"Det betyder oftast ett problem med installationen av VLC. Rapportera gärna "
"felet till din distributör."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Förval"

45
po/uk/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,45 @@
# Translation of phonon_vlc_qt.po to Ukrainian
# Copyright (C) 2011-2019 This_file_is_part_of_KDE
# This file is distributed under the license LGPL version 2.1 or
# version 3 or later versions approved by the membership of KDE e.V.
#
# Yuri Chornoivan <yurchor@ukr.net>, 2011, 2012, 2013, 2019.
msgid ""
msgstr ""
"Project-Id-Version: phonon_vlc_qt\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2019-07-01 01:50+0200\n"
"PO-Revision-Date: 2019-07-04 19:57+0300\n"
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"Language-Team: Ukrainian <kde-i18n-uk@kde.org>\n"
"Language: uk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n"
"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Lokalize 19.07.70\n"
"X-Qt-Contexts: true\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "Не вдалося ініціалізувати LibVLC"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Не вдалося запустити модуль VLC Phonon.\n"
"\n"
"Зазвичай, такі проблеми пов’язано з працездатністю встановленого вами VLC, "
"будь ласка, повідомте про цю ваду розробникам вашого дистрибутива."
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "Типовий"

38
po/zh_CN/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,38 @@
msgid ""
msgstr ""
"Project-Id-Version: kdeorg\n"
"PO-Revision-Date: 2021-03-14 15:44\n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: kdeorg\n"
"X-Crowdin-Project-ID: 269464\n"
"X-Crowdin-Language: zh-CN\n"
"X-Crowdin-File: /kf5-stable/messages/phonon-vlc/phonon_vlc_qt.pot\n"
"X-Crowdin-File-ID: 24358\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "LibVLC 初始化失败"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"无法启动 Phonon 的 VLC 后端。\n"
"\n"
"这通常表示 VLC 安装有问题,请向软件包发行者报告问题。"
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "默认"

36
po/zh_TW/phonon_vlc_qt.po Normal file
View File

@ -0,0 +1,36 @@
# pan93412 <pan93412@gmail.com>, 2019.
msgid ""
msgstr ""
"Project-Id-Version: pan 93412\n"
"PO-Revision-Date: 2019-10-19 15:18+0800\n"
"Last-Translator: pan93412 <pan93412@gmail.com>\n"
"Language-Team: Chinese <zh-l10n@lists.linux.org.tw>\n"
"Language: zh_TW\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Lokalize 19.08.2\n"
#: src/backend.cpp:132
msgctxt "Phonon::VLC::Backend|"
msgid "LibVLC Failed to Initialize"
msgstr "LibVLC 初始化失敗"
#: src/backend.cpp:133
msgctxt "Phonon::VLC::Backend|"
msgid ""
"Phonon's VLC backend failed to start.\n"
"\n"
"This usually means a problem with your VLC installation, please report a bug "
"with your distributor."
msgstr ""
"Phonon 的 VLC 後端介面啟動失敗。\n"
"\n"
"通常這表示您的 VLC 安裝有問題。請向您的套件維護者回報。"
#: src/devicemanager.cpp:214
msgctxt "Phonon::VLC::DeviceManager|"
msgid "Default"
msgstr "預設"

4
src/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.svn
Makefile
moc_*
phonon_vlc_*

95
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,95 @@
if (MSVC OR (WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel"))
set (CMAKE_MODULE_PATH ${CMAKE_INSTALL_PREFIX}/share/apps/cmake/modules)
find_package(KDEWin)
if (KDEWIN_FOUND)
include_directories(${KDEWIN_INCLUDES}/msvc)
link_libraries(${KDEWIN_LIBRARIES})
else (KDEWIN_FOUND)
include(CheckIncludeFileCXX)
check_include_file_cxx(inttypes.h HAVE_INTTYPES)
check_include_file_cxx(stdint.h HAVE_STDINT)
if ( NOT HAVE_STDINT AND NOT HAVE_INTTYPES )
message (FATAL_ERROR "You don't have stdint.h and inttypes.h\n\t get them from http://code.google.com/p/baseutils/source/browse/#svn/trunk/msvc,\n\t or get kdewin http://websvn.kde.org/trunk/kdesupport/kdewin/")
endif ( NOT HAVE_STDINT AND NOT HAVE_INTTYPES )
endif (KDEWIN_FOUND)
endif (MSVC OR (WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel"))
# NB: This is evaluated in the build system because the phonon headers
# change behavior based on the defines, meaning the defines must already be set
# by the time the headers are pre-processed!
if(${PHONON_VERSION} VERSION_GREATER "4.9.50")
message(STATUS "Building against Phonon 4.10 API")
set(BACKEND_VERSION_DEFINE -DPHONON_BACKEND_VERSION_4_10)
# Older not supported because backend doesn't build with older cmake rigging anwyay.
endif()
add_definitions(${BACKEND_VERSION_DEFINE}) # also automatically used for moc
set(phonon_vlc_SRCS
audio/audiooutput.cpp
audio/audiodataoutput.cpp
audio/volumefadereffect.cpp
backend.cpp
devicemanager.cpp
effect.cpp
effectmanager.cpp
media.cpp
mediacontroller.cpp
mediaobject.cpp
mediaplayer.cpp
sinknode.cpp
streamreader.cpp
# video/videodataoutput.cpp
video/videowidget.cpp
video/videomemorystream.cpp
utils/debug.cpp
utils/libvlc.cpp
)
if(NOT ${LIBVLC_VERSION} VERSION_LESS "2.2.0")
list(APPEND phonon_vlc_SRCS equalizereffect.cpp)
endif()
if(PHONON_EXPERIMENTAL)
list(APPEND phonon_vlc_SRCS video/videodataoutput.cpp)
endif()
if(APPLE)
list(APPEND phonon_vlc_SRCS
video/mac/nsvideoview.mm
video/mac/vlcmacwidget.mm)
endif()
ecm_create_qm_loader(phonon_vlc_SRCS phonon_vlc_qt)
add_library(phonon_vlc MODULE ${phonon_vlc_SRCS})
target_include_directories(phonon_vlc
PRIVATE
# Extra include. We use some internal stuff for easy chroma conversion.
${LIBVLC_INCLUDE_DIR}/vlc/plugins
)
target_link_libraries(phonon_vlc
Phonon::phonon4qt5
Qt5::Core
Qt5::Widgets
LibVLC::Core
LibVLC::LibVLC
)
if(PHONON_EXPERIMENTAL)
target_link_libraries(phonon_vlc Phonon::phonon4qt5experimental)
endif()
install(TARGETS phonon_vlc DESTINATION ${PHONON_BACKEND_DIR})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/utils/mime.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/utils/mime.h @ONLY)
# Instead of desktop files we are embedding the information into the plugin itself.
# We have no KDE technology to help with finding the actual libraries anyway, so
# we need to have the library path anyway.
# Also see qtplugin/Q_PLUGIN_METADATA documentation.
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/phonon-vlc.json.in
${CMAKE_CURRENT_BINARY_DIR}/phonon-vlc.json @ONLY)

View File

@ -0,0 +1,164 @@
/*
Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>
Copyright (C) 2010 Ben Cooksley <sourtooth@gmail.com>
Copyright (C) 2011 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), Nokia Corporation
(or its successors, if any) and the KDE Free Qt Foundation, which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "audiodataoutput.h"
#include "media.h"
namespace Phonon {
namespace VLC {
AudioDataOutput::AudioDataOutput(QObject *parent)
: QObject(parent)
{
m_sampleRate = 44100;
connect(this, SIGNAL(sampleReadDone()), this, SLOT(sendData()));
// Register channels
m_channels.append(Phonon::AudioDataOutput::LeftChannel);
m_channels.append(Phonon::AudioDataOutput::RightChannel);
m_channels.append(Phonon::AudioDataOutput::CenterChannel);
m_channels.append(Phonon::AudioDataOutput::LeftSurroundChannel);
m_channels.append(Phonon::AudioDataOutput::RightSurroundChannel);
m_channels.append(Phonon::AudioDataOutput::SubwooferChannel);
}
AudioDataOutput::~AudioDataOutput()
{
}
int AudioDataOutput::dataSize() const
{
return m_dataSize;
}
int AudioDataOutput::sampleRate() const
{
return m_sampleRate;
}
void AudioDataOutput::setDataSize(int size)
{
m_dataSize = size;
}
void AudioDataOutput::handleAddToMedia(Media *media)
{
media->addOption(QString(":sout=#duplicate{dst=display,dst='transcode{vcodec=none,acodec=s16l,samplerate=%1}"
":smem{audio-prerender-callback=%2,"
"audio-postrender-callback=%3,"
"audio-data=%4,"
"time-sync=true}'}"
).arg(QString::number(m_sampleRate),
QString::number((long long int) INTPTR_FUNC(AudioDataOutput::lock)),
QString::number((long long int) INTPTR_FUNC(AudioDataOutput::unlock)),
QString::number((long long int) INTPTR_PTR(this))));
}
void AudioDataOutput::lock(AudioDataOutput *cw, quint8 **pcm_buffer , quint32 size)
{
cw->m_locker.lock();
*pcm_buffer = new quint8[size];
}
void AudioDataOutput::unlock(AudioDataOutput *cw, quint8 *pcm_buffer,
quint32 channelCount, quint32 rate,
quint32 sampleCount, quint32 bits_per_sample,
quint32 size, qint64 pts)
{
Q_UNUSED(size);
Q_UNUSED(pts);
// (bytesPerChannelPerSample * channels * read_samples) + (bytesPerChannelPerSample * read_channels)
int bytesPerChannelPerSample = bits_per_sample / 8;
cw->m_sampleRate = rate;
cw->m_channelCount = channelCount;
for (quint32 readSamples = 0; readSamples < sampleCount; ++readSamples) {
// Prepare a sample buffer, and initialise it
quint16 sampleBuffer[6];
for (int initialised = 0; initialised < 6; ++initialised) {
sampleBuffer[initialised] = 0;
}
int bufferPosition = (bytesPerChannelPerSample * channelCount * readSamples);
for (quint32 readChannels = 0; readChannels < channelCount; ++readChannels) {
quint32 complet = 0;
for (int readBytes = 0; readBytes < bytesPerChannelPerSample; ++readBytes) {
// Read from the pcm_buffer into the per channel internal buffer
quint32 complet_temp = 0;
complet_temp = pcm_buffer[bufferPosition];
complet_temp <<= (8 * readBytes);
complet += complet_temp;
++bufferPosition;
}
sampleBuffer[readChannels] = complet;
}
if (channelCount == 1) {
cw->m_channelSamples[1].append(qint16(sampleBuffer[0]));
}
for (quint32 readChannels = 0; readChannels < channelCount; ++readChannels) {
cw->m_channelSamples[readChannels].append(qint16(sampleBuffer[readChannels]));
}
// Finished reading one sample
}
delete pcm_buffer;
cw->m_locker.unlock();
emit cw->sampleReadDone();
}
void AudioDataOutput::sendData()
{
m_locker.lock();
int chan_count = m_channelCount;
if (m_channelCount == 1) {
chan_count = 2;
}
while (m_channelSamples[0].count() > m_dataSize) {
QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > m_data;
for (int position = 0; position < chan_count; position++) {
Phonon::AudioDataOutput::Channel chan = m_channels.value(position);
QVector<qint16> data = m_channelSamples[position].mid(0, m_dataSize);
m_channelSamples[position].remove(0, data.count());
m_data.insert(chan, data);
}
emit dataReady(m_data);
}
m_locker.unlock();
}
} // namespace VLC
} // namespace Phonon
#include "moc_audiodataoutput.cpp"

162
src/audio/audiodataoutput.h Normal file
View File

@ -0,0 +1,162 @@
/*
Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>
Copyright (C) 2010 Ben Cooksley <sourtooth@gmail.com>
Copyright (C) 2011 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), Nokia Corporation
(or its successors, if any) and the KDE Free Qt Foundation, which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef Phonon_VLC_AUDIODATAOUTPUT_H
#define Phonon_VLC_AUDIODATAOUTPUT_H
#include <QtCore/QMutex>
#include <QtCore/QObject>
#include <phonon/audiodataoutput.h>
#include <phonon/audiodataoutputinterface.h>
#include "sinknode.h"
namespace Phonon {
namespace VLC {
/** \brief Implementation for AudioDataOutput using libVLC
*
* This class makes the capture of raw audio data possible. It sets special options
* for the libVLC Media Object when connecting to it, and then captures libVLC events
* to get the audio data and send it further with the dataReady() signal.
*
* As a sink node, it can be connected to media objects.
*
* The frontend Phonon::AudioDataOutput object is unused.
*
* See the Phonon documentation for details.
*
* \see AudioOutput
* \see SinkNode
*
* \author Martin Sandsmark <sandsmark@samfundet.no>
*/
class AudioDataOutput : public QObject, public SinkNode, public AudioDataOutputInterface
{
Q_OBJECT
Q_INTERFACES(Phonon::AudioDataOutputInterface)
public:
/**
* Creates an audio data output. The sample rate is set to 44100 Hz.
* The available audio channels are registered. These are:
* \li Left \li Right \li Center \li LeftSurround \li RightSurround \li Subwoofer
*/
explicit AudioDataOutput(QObject *parent);
~AudioDataOutput();
Phonon::AudioDataOutput *frontendObject() const
{
return m_frontend;
}
void setFrontendObject(Phonon::AudioDataOutput *frontend)
{
m_frontend = frontend;
}
public Q_SLOTS:
/**
* \return The currently used number of samples passed through the signal.
*/
int dataSize() const;
/**
* \return The current sample rate in Hz.
*/
int sampleRate() const;
/**
* Sets the number of samples to be passed in one signal emission.
*/
void setDataSize(int size);
/**
* Adds special options to the libVLC Media Object to adapt it to give audio data
* directly. There are two callbacks used: lock(), unlock().
*
* \see lock()
* \see unlock()
* \reimp
*/
void handleAddToMedia(Media *media);
signals:
void dataReady(const QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > &data);
void dataReady(const QMap<Phonon::AudioDataOutput::Channel, QVector<float> > &data);
void endOfMedia(int remainingSamples);
void sampleReadDone();
private Q_SLOTS:
/**
* Looks at the channel samples generated in lock() and creates the QMap required for
* the dataReady() signal. Then the signal is emitted. This repeats as long as there is
* data remaining.
*
* \see lock()
*/
void sendData();
private:
/**
* This is a VLC prerender callback. The m_locker mutex is locked, and a new buffer is prepared
* for the incoming audio data.
*
* \param cw The AudioDataOutput for this callback
* \param pcm_buffer The new data buffer
* \param size Size for the incoming data
*
* \see unlock()
*/
static void lock(AudioDataOutput *cw, quint8 **pcm_buffer , quint32 size);
/**
* This is a VLC postrender callback. Interprets the data received in m_buffer,
* separating the samples and channels. Finally, the buffer is freed and m_locker
* is unlocked. Now the audio data output is ready for sending data.
*
* \param cw The AudioDataOutput for this callback
*
* \see lock()
* \see sendData()
*/
static void unlock(AudioDataOutput *cw, quint8 *pcm_buffer,
quint32 channelCount, quint32 rate,
quint32 sampleCount, quint32 bits_per_sample,
quint32 size, qint64 pts);
int m_dataSize;
int m_sampleRate;
Phonon::AudioDataOutput *m_frontend;
QMutex m_locker;
int m_channelCount;
QVector<qint16> m_channelSamples[6];
QList<Phonon::AudioDataOutput::Channel> m_channels;
};
} // namespace VLC
} // namespace Phonon
#endif // Phonon_VLC_AUDIODATAOUTPUT_H

250
src/audio/audiooutput.cpp Normal file
View File

@ -0,0 +1,250 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2013-2018 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "audiooutput.h"
#include <phonon/pulsesupport.h>
#include <vlc/vlc.h>
#include "backend.h"
#include "utils/debug.h"
#include "devicemanager.h"
#include "mediaobject.h"
#include "media.h"
namespace Phonon {
namespace VLC {
AudioOutput::AudioOutput(QObject *parent)
: QObject(parent)
, m_volume(0.75)
, m_explicitVolume(false)
, m_muted(false)
, m_category(Phonon::NoCategory)
{
}
AudioOutput::~AudioOutput()
{
}
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0))
static libvlc_media_player_role categoryToRole(Category category)
{
switch(category) {
case NoCategory:
return libvlc_role_None;
case NotificationCategory:
return libvlc_role_Notification;
case MusicCategory:
return libvlc_role_Music;
case VideoCategory:
return libvlc_role_Video;
case CommunicationCategory:
return libvlc_role_Communication;
case GameCategory:
return libvlc_role_Game;
case AccessibilityCategory:
return libvlc_role_Accessibility;
}
return libvlc_role_None;
}
#endif
void AudioOutput::handleConnectToMediaObject(MediaObject *mediaObject)
{
Q_UNUSED(mediaObject);
setOutputDeviceImplementation();
if (!PulseSupport::getInstance()->isActive()) {
// Rely on libvlc for updates if PASupport is not active
connect(m_player, SIGNAL(mutedChanged(bool)),
this, SLOT(onMutedChanged(bool)));
connect(m_player, SIGNAL(volumeChanged(float)),
this, SLOT(onVolumeChanged(float)));
applyVolume();
}
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0))
libvlc_media_player_set_role(*m_player, categoryToRole(m_category));
#endif
}
void AudioOutput::handleAddToMedia(Media *media)
{
media->addOption(":audio");
PulseSupport *pulse = PulseSupport::getInstance();
if (pulse && pulse->isActive()) {
pulse->setupStreamEnvironment(m_streamUuid);
}
}
qreal AudioOutput::volume() const
{
return m_volume;
}
void AudioOutput::setVolume(qreal volume)
{
if (m_player) {
debug() << "async setting of volume to" << volume;
m_volume = volume;
m_explicitVolume = true;
applyVolume();
#if (LIBVLC_VERSION_INT < LIBVLC_VERSION(2, 2, 2, 0))
emit volumeChanged(m_volume);
#endif
}
}
void AudioOutput::setMuted(bool mute)
{
if (mute == m_player->mute()) {
// Make sure we actually have propagated the mutness into the frontend.
onMutedChanged(mute);
return;
}
m_player->setMute(mute);
}
void AudioOutput::setCategory(Category category)
{
m_category = category;
}
int AudioOutput::outputDevice() const
{
return m_device.index();
}
bool AudioOutput::setOutputDevice(int deviceIndex)
{
const AudioOutputDevice device = AudioOutputDevice::fromIndex(deviceIndex);
if (!device.isValid()) {
error() << Q_FUNC_INFO << "Unable to find the output device with index" << deviceIndex;
return false;
}
return setOutputDevice(device);
}
bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice)
{
debug() << Q_FUNC_INFO;
if (!newDevice.isValid()) {
error() << "Invalid audio output device";
return false;
}
if (newDevice == m_device)
return true;
m_device = newDevice;
if (m_player) {
setOutputDeviceImplementation();
}
return true;
}
void AudioOutput::setStreamUuid(QString uuid)
{
DEBUG_BLOCK;
debug() << uuid;
m_streamUuid = uuid;
}
void AudioOutput::setOutputDeviceImplementation()
{
Q_ASSERT(m_player);
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 0, 0))
// VLC 2.2 has the PulseSupport overrides always disabled because of
// incompatibility. Also see backend.cpp for more detals.
// To get access to the correct activity state we need to temporarily
// enable pulse and then disable it again. This is necessary because isActive
// is in fact isActive&isEnabled.............
PulseSupport::getInstance()->enable(true);
const bool pulseActive = PulseSupport::getInstance()->isActive();
PulseSupport::getInstance()->enable(false);
#else
const bool pulseActive = PulseSupport::getInstance()->isActive();
#endif
if (pulseActive) {
m_player->setAudioOutput("pulse");
debug() << "Setting aout to pulse";
return;
}
const QVariant dalProperty = m_device.property("deviceAccessList");
if (!dalProperty.isValid()) {
error() << "Device" << m_device.property("name") << "has no access list";
return;
}
const DeviceAccessList deviceAccessList = dalProperty.value<DeviceAccessList>();
if (deviceAccessList.isEmpty()) {
error() << "Device" << m_device.property("name") << "has an empty access list";
return;
}
// ### we're not trying the whole access list (could mean same device on different soundsystems)
const DeviceAccess &firstDeviceAccess = deviceAccessList.first();
QByteArray soundSystem = firstDeviceAccess.first;
debug() << "Setting output soundsystem to" << soundSystem;
m_player->setAudioOutput(soundSystem);
QByteArray deviceName = firstDeviceAccess.second.toLatin1();
if (!deviceName.isEmpty()) {
// print the name as possibly messed up by toLatin1() to see conversion problems
debug() << "Setting output device to" << deviceName << '(' << m_device.property("name") << ')';
m_player->setAudioOutputDevice(soundSystem, deviceName);
}
}
void AudioOutput::applyVolume()
{
if (m_player && m_explicitVolume) {
const int preVolume = m_player->audioVolume();
const int newVolume = m_volume * 100;
m_player->setAudioVolume(newVolume);
#if (LIBVLC_VERSION_INT < LIBVLC_VERSION(2, 2, 2, 0))
onMutedChanged(m_volume == 0.0);
onVolumeChanged(newVolume);
#endif
debug() << "Volume changed from" << preVolume << "to" << newVolume;
}
}
void AudioOutput::onMutedChanged(bool mute)
{
m_muted = mute;
emit mutedChanged(mute);
}
void AudioOutput::onVolumeChanged(float volume)
{
m_volume = volume;
emit volumeChanged(volume);
}
}
} // Namespace Phonon::VLC

136
src/audio/audiooutput.h Normal file
View File

@ -0,0 +1,136 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2013 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_AUDIOOUTPUT_H
#define PHONON_VLC_AUDIOOUTPUT_H
#include <QtCore/QObject>
#include <phonon/audiooutputinterface.h>
#include "sinknode.h"
namespace Phonon {
namespace VLC {
/** \brief AudioOutput implementation for Phonon-VLC
*
* This class is a SinkNode that implements the AudioOutputInterface from Phonon. It
* supports setting the volume and the audio output device.
*
* There are signals for the change of the volume or for when an audio device failed.
*
* See the Phonon::AudioOutputInterface documentation for details.
*
* \see AudioDataOutput
*/
class AudioOutput : public QObject, public SinkNode, public AudioOutputInterface
{
Q_OBJECT
Q_INTERFACES(Phonon::AudioOutputInterface)
public:
/**
* Creates an AudioOutput with the given backend object. The volume is set to 1.0
*
* \param p_back Parent backend
* \param p_parent A parent object
*/
explicit AudioOutput(QObject *parent);
~AudioOutput();
/** \reimp */
void handleConnectToMediaObject(MediaObject *mediaObject);
/** \reimp */
void handleAddToMedia(Media *media);
/**
* \return The current volume for this audio output.
*/
qreal volume() const;
/**
* Sets the volume of the audio output. See the Phonon::AudioOutputInterface::setVolume() documentation
* for details.
*/
void setVolume(qreal volume);
/**
* \return The index of the current audio output device from the list obtained from the backend object.
*/
int outputDevice() const;
/**
* Sets the current output device for this audio output. The validity of the device index
* is verified before attempting to change the device.
*
* \param device The index of the device, obtained from the backend's audio device list
* \return \c true if succeeded, or no change was made
* \return \c false if failed
*/
bool setOutputDevice(int);
/**
* Sets the current output device for this audio output.
*
* \param device The device to set; it should be valid and contain an usable deviceAccessList property
* \return \c true if succeeded, or no change was made
* \return \c false if failed
*/
bool setOutputDevice(const AudioOutputDevice &newDevice);
void setStreamUuid(QString uuid);
void setMuted(bool mute);
virtual void setCategory(Phonon::Category category);
signals:
void volumeChanged(qreal volume);
void audioDeviceFailed();
void mutedChanged(bool mute);
private slots:
/**
* Sets the volume to m_volume.
*/
void applyVolume();
void onMutedChanged(bool mute);
void onVolumeChanged(float volume);
private:
/**
* We can only really set the output device once we have a libvlc_media_player, which comes
* from our SinkNode.
*/
void setOutputDeviceImplementation();
qreal m_volume;
// Set after first setVolume to indicate volume was set manually.
bool m_explicitVolume;
bool m_muted;
AudioOutputDevice m_device;
QString m_streamUuid;
Category m_category;
};
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_AUDIOOUTPUT_H

View File

@ -0,0 +1,127 @@
/* This file is part of the KDE project.
*
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2013 Martin Sandsmark <martin.sandsmark@kde.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 or 3 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "volumefadereffect.h"
#include <mediaplayer.h>
#include "utils/debug.h"
#include <QtCore/QTimeLine>
#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
namespace Phonon
{
namespace VLC
{
VolumeFaderEffect::VolumeFaderEffect(QObject *parent)
: QObject(parent)
, SinkNode()
, m_fadeCurve(Phonon::VolumeFaderEffect::Fade3Decibel)
, m_fadeFromVolume(0)
, m_fadeToVolume(0)
{
m_fadeTimeline = new QTimeLine(1000, this);
connect(m_fadeTimeline, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetVolume(qreal)));
}
VolumeFaderEffect::~VolumeFaderEffect()
{
}
float VolumeFaderEffect::volume() const
{
Q_ASSERT(m_player);
return m_player->audioVolume() / 100.0f;
}
void VolumeFaderEffect::slotSetVolume(qreal volume)
{
float gstVolume = m_fadeFromVolume + (volume * (m_fadeToVolume - m_fadeFromVolume));
setVolumeInternal(gstVolume);
}
Phonon::VolumeFaderEffect::FadeCurve VolumeFaderEffect::fadeCurve() const
{
return m_fadeCurve;
}
void VolumeFaderEffect::setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve pFadeCurve)
{
m_fadeCurve = pFadeCurve;
QEasingCurve fadeCurve;
switch(pFadeCurve) {
case Phonon::VolumeFaderEffect::Fade3Decibel:
fadeCurve = QEasingCurve::InQuad;
break;
case Phonon::VolumeFaderEffect::Fade6Decibel:
fadeCurve = QEasingCurve::Linear;
break;
case Phonon::VolumeFaderEffect::Fade9Decibel:
fadeCurve = QEasingCurve::OutCubic;
break;
case Phonon::VolumeFaderEffect::Fade12Decibel:
fadeCurve = QEasingCurve::OutQuart;
break;
}
m_fadeTimeline->setEasingCurve(fadeCurve);
}
void VolumeFaderEffect::fadeTo(float targetVolume, int fadeTime)
{
Q_ASSERT(m_player);
abortFade();
m_fadeToVolume = targetVolume;
m_fadeFromVolume = m_player->audioVolume() / 100.0f;
// Don't call QTimeLine::setDuration() with zero.
// It is not supported and breaks fading.
if (fadeTime <= 0) {
debug() << "Called with retarded fade time " << fadeTime;
setVolumeInternal(targetVolume);
return;
}
m_fadeTimeline->setDuration(fadeTime);
m_fadeTimeline->start();
}
void VolumeFaderEffect::setVolume(float v)
{
abortFade();
setVolumeInternal(v);
}
void VolumeFaderEffect::abortFade()
{
m_fadeTimeline->stop();
}
void VolumeFaderEffect::setVolumeInternal(float v)
{
if (m_player)
m_player->setAudioFade(v);
else
warning() << Q_FUNC_INFO << this << "no m_player set";
}
}
} //namespace Phonon::VLC
#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
#include "moc_volumefadereffect.cpp"

View File

@ -0,0 +1,71 @@
/* This file is part of the KDE project.
*
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2013 Martin Sandsmark <martin.sandsmark@kde.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 or 3 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_VOLUMEFADEREFFECT_H
#define PHONON_VLC_VOLUMEFADEREFFECT_H
#include <phonon/volumefaderinterface.h>
#include <QtCore/QTime>
#include <QtCore/QPointer>
#include "sinknode.h"
class QTimeLine;
namespace Phonon {
class MediaObject;
namespace VLC {
class VolumeFaderEffect : public QObject, public SinkNode, public VolumeFaderInterface
{
Q_OBJECT
Q_INTERFACES(Phonon::VolumeFaderInterface)
public:
explicit VolumeFaderEffect(QObject *parent = 0);
~VolumeFaderEffect();
// VolumeFaderInterface:
float volume() const;
Phonon::VolumeFaderEffect::FadeCurve fadeCurve() const;
void setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve fadeCurve);
void fadeTo(float volume, int fadeTime);
void setVolume(float v);
QPointer<MediaObject> mediaObject() { return m_mediaObject; }
private slots:
void slotSetVolume(qreal v);
private:
void abortFade();
inline void setVolumeInternal(float v);
Phonon::VolumeFaderEffect::FadeCurve m_fadeCurve;
float m_fadeFromVolume;
float m_fadeToVolume;
QTimeLine *m_fadeTimeline;
};
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_VOLUMEFADEREFFECT_H

365
src/backend.cpp Normal file
View File

@ -0,0 +1,365 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
Copyright (C) 2011-2013 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "backend.h"
#include <QApplication>
#include <QIcon>
#include <QLatin1Literal>
#include <QMessageBox>
#include <QtPlugin>
#include <QVariant>
#include <phonon/GlobalDescriptionContainer>
#include <phonon/pulsesupport.h>
#include <vlc/libvlc_version.h>
#include "audio/audiooutput.h"
#include "audio/audiodataoutput.h"
#include "audio/volumefadereffect.h"
#include "config.h"
#include "devicemanager.h"
#include "effect.h"
#include "effectmanager.h"
#include "mediaobject.h"
#include "sinknode.h"
#include "utils/debug.h"
#include "utils/libvlc.h"
#include "utils/mime.h"
#ifdef PHONON_EXPERIMENTAL
#include "video/videodataoutput.h"
#endif
#include "video/videowidget.h"
namespace Phonon
{
namespace VLC
{
Backend *Backend::self;
Backend::Backend(QObject *parent, const QVariantList &)
: QObject(parent)
, m_deviceManager(0)
, m_effectManager(0)
{
self = this;
// Backend information properties
setProperty("identifier", QLatin1String("phonon_vlc"));
setProperty("backendName", QLatin1String("VLC"));
setProperty("backendComment", QLatin1String("VLC backend for Phonon"));
setProperty("backendVersion", QLatin1String(PHONON_VLC_VERSION));
setProperty("backendIcon", QLatin1String("vlc"));
setProperty("backendWebsite", QLatin1String("https://commits.kde.org/phonon-vlc"));
// Check if we should enable debug output
int debugLevel = qgetenv("PHONON_BACKEND_DEBUG").toInt();
if (debugLevel > 3) // 3 is maximum
debugLevel = 3;
Debug::setMinimumDebugLevel((Debug::DebugLevel)((int) Debug::DEBUG_NONE - 1 - debugLevel));
debug() << "Constructing Phonon-VLC Version" << PHONON_VLC_VERSION;
// Actual libVLC initialisation
if (LibVLC::init()) {
debug() << "Using VLC version" << libvlc_get_version();
if (!qApp->applicationName().isEmpty()) {
QString userAgent =
QString("%0/%1 (Phonon/%2; Phonon-VLC/%3)").arg(
qApp->applicationName(),
qApp->applicationVersion(),
PHONON_VERSION_STR,
PHONON_VLC_VERSION);
libvlc_set_user_agent(pvlc_libvlc,
qApp->applicationName().toUtf8().constData(),
userAgent.toUtf8().constData());
} else {
qWarning("WARNING: Setting the user agent for streaming and"
" PulseAudio requires you to set QCoreApplication::applicationName()");
}
PulseSupport::getInstance()->enable(true);
const bool pulseActive = PulseSupport::getInstance()->isActive();
PulseSupport::getInstance()->enable(false);
if (!qApp->applicationName().isEmpty()) {
const QString id = QString("org.kde.phonon.%1").arg(qApp->applicationName());
const QString version = qApp->applicationVersion();
QString icon;
if (!qApp->windowIcon().isNull()){
// Try to get the fromTheme() name of the QIcon.
icon = qApp->windowIcon().name();
}
if (icon.isEmpty()) {
// If we failed to get a proper icon name, use the appname instead.
icon = qApp->applicationName().toLower();
}
libvlc_set_app_id(pvlc_libvlc,
id.toUtf8().constData(),
version.toUtf8().constData(),
icon.toUtf8().constData());
} else if (pulseActive) {
qWarning("WARNING: Setting PulseAudio context information requires you"
" to set QCoreApplication::applicationName(),"
" QCoreApplication::applicationVersion() and"
" QGuiApplication::windowIcon().");
}
} else {
#ifdef __GNUC__
#warning TODO - this error message is as useful as a knife at a gun fight
#endif
QMessageBox msg;
msg.setIcon(QMessageBox::Critical);
msg.setWindowTitle(tr("LibVLC Failed to Initialize"));
msg.setText(tr("Phonon's VLC backend failed to start."
"\n\n"
"This usually means a problem with your VLC installation,"
" please report a bug with your distributor."));
msg.setDetailedText(LibVLC::errorMessage());
msg.exec();
fatal() << "Phonon::VLC::vlcInit: Failed to initialize VLC";
}
#if (LIBVLC_VERSION_INT < LIBVLC_VERSION(2, 2, 2, 0))
// VLC 2.2 changed the stream creation order around internally which breaks
// the Pulseaudio hijacking. Since VLC upstream doesn't feel like giving us
// any more property control we now consider this feature unsupported. As
// such whatever properties VLC sets will be what pulse knows about us.
// Initialise PulseAudio support
PulseSupport *pulse = PulseSupport::getInstance();
pulse->enable(true);
connect(pulse, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
SIGNAL(objectDescriptionChanged(ObjectDescriptionType)));
#endif
m_deviceManager = new DeviceManager(this);
m_effectManager = new EffectManager(this);
}
Backend::~Backend()
{
if (LibVLC::self)
delete LibVLC::self;
if (GlobalAudioChannels::self)
delete GlobalAudioChannels::self;
if (GlobalSubtitles::self)
delete GlobalSubtitles::self;
PulseSupport::shutdown();
}
QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
{
if (!LibVLC::self || !pvlc_libvlc)
return 0;
switch (c) {
case MediaObjectClass:
return new MediaObject(parent);
case AudioOutputClass:
return new AudioOutput(parent);
#if (LIBVLC_VERSION_INT < LIBVLC_VERSION(2, 0, 0, 0))
// Broken >= 2.0
// https://trac.videolan.org/vlc/ticket/6992
case AudioDataOutputClass:
return new AudioDataOutput(parent);
#endif
#ifdef PHONON_EXPERIMENTAL
case VideoDataOutputClass:
return new VideoDataOutput(parent);
#endif
case VideoGraphicsObjectClass:
return nullptr; // No longer supported
case EffectClass:
return effectManager()->createEffect(args[0].toInt(), parent);
case VideoWidgetClass:
return new VideoWidget(qobject_cast<QWidget *>(parent));
// case VolumeFaderEffectClass:
#ifdef __GNUC__
#warning VFE crashes and has volume bugs ... deactivated
// return new VolumeFaderEffect(parent);
#endif
}
warning() << "Backend class" << c << "is not supported by Phonon VLC :(";
return 0;
}
QStringList Backend::availableMimeTypes() const
{
if (m_supportedMimeTypes.isEmpty())
const_cast<Backend *>(this)->m_supportedMimeTypes = mimeTypeList();
return m_supportedMimeTypes;
}
QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
{
QList<int> list;
switch (type) {
case Phonon::AudioChannelType: {
list << GlobalAudioChannels::instance()->globalIndexes();
}
break;
case Phonon::AudioOutputDeviceType:
case Phonon::AudioCaptureDeviceType:
case Phonon::VideoCaptureDeviceType: {
return deviceManager()->deviceIds(type);
}
break;
case Phonon::EffectType: {
QList<EffectInfo> effectList = effectManager()->effects();
for (int eff = 0; eff < effectList.size(); ++eff) {
list.append(eff);
}
}
break;
case Phonon::SubtitleType: {
list << GlobalSubtitles::instance()->globalIndexes();
}
break;
}
return list;
}
QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
{
QHash<QByteArray, QVariant> ret;
switch (type) {
case Phonon::AudioChannelType: {
const AudioChannelDescription description = GlobalAudioChannels::instance()->fromIndex(index);
ret.insert("name", description.name());
ret.insert("description", description.description());
}
break;
case Phonon::AudioOutputDeviceType:
case Phonon::AudioCaptureDeviceType:
case Phonon::VideoCaptureDeviceType: {
// Index should be unique, even for different categories
return deviceManager()->deviceProperties(index);
}
break;
case Phonon::EffectType: {
const QList<EffectInfo> effectList = effectManager()->effects();
if (index >= 0 && index <= effectList.size()) {
const EffectInfo &effect = effectList.at(index);
ret.insert("name", effect.name());
ret.insert("description", effect.description());
ret.insert("author", effect.author());
} else {
Q_ASSERT(1); // Since we use list position as ID, this should not happen
}
}
break;
case Phonon::SubtitleType: {
const SubtitleDescription description = GlobalSubtitles::instance()->fromIndex(index);
ret.insert("name", description.name());
ret.insert("description", description.description());
ret.insert("type", description.property("type"));
}
break;
}
return ret;
}
bool Backend::startConnectionChange(QSet<QObject *> objects)
{
//FIXME
foreach(QObject * object, objects) {
debug() << "Object:" << object->metaObject()->className();
}
// There is nothing we can do but hope the connection changes will not take too long
// so that buffers would underrun
// But we should be pretty safe the way xine works by not doing anything here.
return true;
}
bool Backend::connectNodes(QObject *source, QObject *sink)
{
debug() << "Backend connected" << source->metaObject()->className() << "to" << sink->metaObject()->className();
SinkNode *sinkNode = dynamic_cast<SinkNode *>(sink);
if (sinkNode) {
MediaObject *mediaObject = qobject_cast<MediaObject *>(source);
if (mediaObject) {
// Connect the SinkNode to a MediaObject
sinkNode->connectToMediaObject(mediaObject);
return true;
}
VolumeFaderEffect *effect = qobject_cast<VolumeFaderEffect *>(source);
if (effect) {
sinkNode->connectToMediaObject(effect->mediaObject());
return true;
}
}
warning() << "Linking" << source->metaObject()->className() << "to" << sink->metaObject()->className() << "failed";
return false;
}
bool Backend::disconnectNodes(QObject *source, QObject *sink)
{
SinkNode *sinkNode = dynamic_cast<SinkNode *>(sink);
if (sinkNode) {
MediaObject *const mediaObject = qobject_cast<MediaObject *>(source);
if (mediaObject) {
// Disconnect the SinkNode from a MediaObject
sinkNode->disconnectFromMediaObject(mediaObject);
return true;
}
VolumeFaderEffect *const effect = qobject_cast<VolumeFaderEffect *>(source);
if (effect) {
sinkNode->disconnectFromMediaObject(effect->mediaObject());
return true;
}
}
return false;
}
bool Backend::endConnectionChange(QSet<QObject *> objects)
{
foreach(QObject *object, objects) {
debug() << "Object:" << object->metaObject()->className();
}
return true;
}
DeviceManager *Backend::deviceManager() const
{
return m_deviceManager;
}
EffectManager *Backend::effectManager() const
{
return m_effectManager;
}
} // namespace VLC
} // namespace Phonon

158
src/backend.h Normal file
View File

@ -0,0 +1,158 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
Copyright (C) 2011 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef Phonon_VLC_BACKEND_H
#define Phonon_VLC_BACKEND_H
#include <QtCore/QStringList>
#include <phonon/objectdescription.h>
#include <phonon/backendinterface.h>
class LibVLC;
namespace Phonon
{
namespace VLC
{
class DeviceManager;
class EffectManager;
/** \brief Backend class for Phonon-VLC.
*
* This class provides the special objects created by the backend and information about
* various things that the backend supports. An object of this class is the root for
* the backend plugin.
*
* Phonon will request the backend to create objects of various classes, like MediaObject,
* AudioOutput, VideoWidget, Effect. There are also methods to handle the connections between
* these objects.
*
* This class also provides information about the devices and effects that the backend supports.
* These are audio output devices, audio capture devices, video capture devices, effects.
*/
class Backend : public QObject, public BackendInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.kde.phonon.vlc" FILE "phonon-vlc.json")
Q_INTERFACES(Phonon::BackendInterface)
public:
/**
* Instance. Since there is no backend instance without actual Backend object
* this class behaves likes a singleton.
*/
static Backend *self;
/**
* Constructs the backend. Sets the backend properties, fetches the debug level from the
* environment, initializes libVLC, constructs the device and effect managers, initializes
* PulseAudio support.
*
* \param parent A parent object for the backend (passed to the QObject constructor)
*/
explicit Backend(QObject *parent = 0, const QVariantList & = QVariantList());
virtual ~Backend();
/// \return The device manager that is associated with this backend object
DeviceManager *deviceManager() const;
/// \return The effect manager that is associated with this backend object.
EffectManager *effectManager() const;
/**
* Creates a backend object of the desired class and with the desired parent. Extra arguments can be provided.
*
* \param c The class of object that is to be created
* \param parent The object that will be the parent of the new object
* \param args Optional arguments for the object creation
* \return The desired object or NULL if the class is not implemented.
*/
QObject *createObject(BackendInterface::Class, QObject *parent, const QList<QVariant> &args);
/// \returns a list of all available mimetypes (hardcoded)
QStringList availableMimeTypes() const;
/**
* Returns a list of indexes for the desired object types. It specifies a list of objects
* of a particular category that the backend knows about. These indexes can be used with
* objectDescriptionProperties() to get the properties of a particular object.
*
* \param type The type of objects for the list
*/
QList<int> objectDescriptionIndexes(ObjectDescriptionType type) const;
/**
* Returns a list of properties for a particular object of the desired category.
*
* \param type The type of object for the index
* \param index The index for the object of the desired type
* \return The property list. If the object is inexistent, an empty list is returned.
*/
QHash<QByteArray, QVariant> objectDescriptionProperties(ObjectDescriptionType type, int index) const;
/**
* Called when a connection between nodes is about to be changed
*
* \param objects A set of objects that will be involved in the change
*/
bool startConnectionChange(QSet<QObject *>);
/**
* Connects two media nodes. The sink is informed that it should connect itself to the source.
*
* \param source The source media node for the connection
* \param sink The sink media node for the connection
* \return True if the connection was successful
*/
bool connectNodes(QObject *, QObject *);
/**
* Disconnects two previously connected media nodes. It disconnects the sink node from the source node.
*
* \param source The source node for the disconnection
* \param sink The sink node for the disconnection
* \return True if the disconnection was successful
*/
bool disconnectNodes(QObject *, QObject *);
/**
* Called after a connection between nodes has been changed
*
* \param objects Nodes involved in the disconnection
*/
bool endConnectionChange(QSet<QObject *>);
Q_SIGNALS:
void objectDescriptionChanged(ObjectDescriptionType);
private:
mutable QStringList m_supportedMimeTypes;
DeviceManager *m_deviceManager;
EffectManager *m_effectManager;
};
} // namespace VLC
} // namespace Phonon
#endif // Phonon_VLC_BACKEND_H

27
src/config.h.cmake Normal file
View File

@ -0,0 +1,27 @@
/*
Copyright (C) 2019 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_CONFIG_H
#define PHONON_VLC_CONFIG_H
// I'd really love to have inline constexpr QStringViews here, I'm unsure what
// that requires vis-a-vis compiler support though :(
#cmakedefine PHONON_VLC_VERSION "@PHONON_VLC_VERSION@"
#cmakedefine PHONON_EXPERIMENTAL
#endif // PHONON_VLC_CONFIG_H

340
src/devicemanager.cpp Normal file
View File

@ -0,0 +1,340 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2010 vlc-phonon AUTHORS <kde-multimedia@kde.org>
Copyright (C) 2011 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "devicemanager.h"
#include <phonon/pulsesupport.h>
#include <vlc/vlc.h>
#include "backend.h"
#include "utils/debug.h"
#include "utils/libvlc.h"
#include "utils/vstring.h"
namespace Phonon
{
namespace VLC
{
/*
* Device Info
*/
DeviceInfo::DeviceInfo(const QString &name, bool isAdvanced)
{
// Get an id
static int counter = 0;
m_id = counter++;
// Get name and description for the device
m_name = name;
m_isAdvanced = isAdvanced;
m_capabilities = None;
// A default device should never be advanced
if (name.startsWith(QLatin1String("default"), Qt::CaseInsensitive))
m_isAdvanced = false;
}
int DeviceInfo::id() const
{
return m_id;
}
const QString& DeviceInfo::name() const
{
return m_name;
}
const QString& DeviceInfo::description() const
{
return m_description;
}
bool DeviceInfo::isAdvanced() const
{
return m_isAdvanced;
}
void DeviceInfo::setAdvanced(bool advanced)
{
m_isAdvanced = advanced;
}
const DeviceAccessList& DeviceInfo::accessList() const
{
return m_accessList;
}
void DeviceInfo::addAccess(const DeviceAccess& access)
{
if (m_accessList.isEmpty())
m_description = access.first + ": " + access.second;
m_accessList.append(access);
}
quint16 DeviceInfo::capabilities() const
{
return m_capabilities;
}
void DeviceInfo::setCapabilities(quint16 cap)
{
m_capabilities = cap;
}
/*
* Device Manager
*/
DeviceManager::DeviceManager(Backend *parent)
: QObject(parent)
, m_backend(parent)
{
Q_ASSERT(parent);
updateDeviceList();
}
DeviceManager::~DeviceManager()
{
}
QList<int> DeviceManager::deviceIds(ObjectDescriptionType type)
{
DeviceInfo::Capability capability = DeviceInfo::None;
switch (type) {
case Phonon::AudioOutputDeviceType:
capability = DeviceInfo::AudioOutput;
break;
case Phonon::AudioCaptureDeviceType:
capability = DeviceInfo::AudioCapture;
break;
case Phonon::VideoCaptureDeviceType:
capability = DeviceInfo::VideoCapture;
break;
default: ;
}
QList<int> ids;
foreach (const DeviceInfo &device, m_devices) {
if (device.capabilities() & capability)
ids.append(device.id());
}
return ids;
}
QHash<QByteArray, QVariant> DeviceManager::deviceProperties(int id)
{
QHash<QByteArray, QVariant> properties;
foreach (const DeviceInfo &device, m_devices) {
if (device.id() == id) {
properties.insert("name", device.name());
properties.insert("description", device.description());
properties.insert("isAdvanced", device.isAdvanced());
properties.insert("deviceAccessList", QVariant::fromValue<Phonon::DeviceAccessList>(device.accessList()));
properties.insert("discovererIcon", "vlc");
if (device.capabilities() & DeviceInfo::AudioOutput) {
properties.insert("icon", QLatin1String("audio-card"));
}
if (device.capabilities() & DeviceInfo::AudioCapture) {
properties.insert("hasaudio", true);
properties.insert("icon", QLatin1String("audio-input-microphone"));
}
if (device.capabilities() & DeviceInfo::VideoCapture) {
properties.insert("hasvideo", true);
properties.insert("icon", QLatin1String("camera-web"));
}
break;
}
}
return properties;
}
const DeviceInfo *DeviceManager::device(int id) const
{
for (int i = 0; i < m_devices.size(); i ++) {
if (m_devices[i].id() == id)
return &m_devices[i];
}
return NULL;
}
static QList<QByteArray> vlcAudioOutBackends()
{
QList<QByteArray> ret;
VLC_FOREACH_LIST(audio_output, aout) {
QByteArray name(aout->psz_name);
if (!ret.contains(name))
ret.append(name);
}
return ret;
}
void DeviceManager::updateDeviceList()
{
QList<DeviceInfo> newDeviceList;
if (!LibVLC::self || !pvlc_libvlc)
return;
QList<QByteArray> audioOutBackends = vlcAudioOutBackends();
PulseSupport *pulse = PulseSupport::getInstance();
if (pulse && pulse->isUsable()) {
if (audioOutBackends.contains("pulse")) {
DeviceInfo defaultAudioOutputDevice(tr("Default"), false);
defaultAudioOutputDevice.setCapabilities(DeviceInfo::AudioOutput);
defaultAudioOutputDevice.addAccess(DeviceAccess("pulse", "default"));
newDeviceList.append(defaultAudioOutputDevice);
pulse->request(true);
return;
} else {
pulse->enable(false);
}
}
QList<QByteArray> knownSoundSystems;
// Whitelist - Order has no particular impact.
// NOTE: if listing was not intercepted by the PA code above we also need
// to try injecting the pulse aout as otherwise the user would have to
// use the fake PA device in ALSA to output through PA (kind of silly).
knownSoundSystems << QByteArray("pulse")
<< QByteArray("alsa")
<< QByteArray("oss")
<< QByteArray("jack")
<< QByteArray("aout_directx") // Windows up to VLC 2.0
<< QByteArray("directsound") // Windows from VLC 2.1 upwards
<< QByteArray("auhal"); // Mac
foreach (const QByteArray &soundSystem, knownSoundSystems) {
if (!audioOutBackends.contains(soundSystem)) {
debug() << "Sound system" << soundSystem << "not supported by libvlc";
continue;
}
// FIXME: there is a rather ungodly amount of code duplication going
// on here.
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 0, 0))
bool hasDevices = false;
VLC_FOREACH(audio_output_device,
device,
libvlc_audio_output_device_list_get(pvlc_libvlc, soundSystem),
libvlc_audio_output_device_list_release) {
QString idName = QString::fromUtf8(device->psz_device);
QString longName = QString::fromUtf8(device->psz_description);
debug() << "found device" << soundSystem << idName << longName;
DeviceInfo info(longName, true);
info.addAccess(DeviceAccess(soundSystem, idName));
info.setCapabilities(DeviceInfo::AudioOutput);
newDeviceList.append(info);
hasDevices = true;
}
if (!hasDevices) {
debug() << "manually injecting sound system" << soundSystem;
DeviceInfo info(QString::fromUtf8(soundSystem), false);
info.addAccess(DeviceAccess(soundSystem, ""));
info.setCapabilities(DeviceInfo::AudioOutput);
newDeviceList.append(info);
}
#else
const int deviceCount = libvlc_audio_output_device_count(pvlc_libvlc, soundSystem);
for (int i = 0; i < deviceCount; i++) {
VString idName(libvlc_audio_output_device_id(libvlc, soundSystem, i));
VString longName(libvlc_audio_output_device_longname(pvlc_libvlc, soundSystem, i));
debug() << "found device" << soundSystem << idName << longName;
DeviceInfo info(longName, true);
info.addAccess(DeviceAccess(soundSystem, idName));
info.setCapabilities(DeviceInfo::AudioOutput);
newDeviceList.append(info);
}
// libVLC gives no devices for some sound systems, like OSS
if (deviceCount == 0) {
debug() << "manually injecting sound system" << soundSystem;
// NOTE: Do not mark manually injected devices as advanced.
// libphonon filters advanced devices from the default
// selection which on systems such as OSX or Windows can
// lead to an empty device list as the injected device is
// the only available one.
DeviceInfo info(QString::fromUtf8(soundSystem), false);
info.addAccess(DeviceAccess(soundSystem, ""));
info.setCapabilities(DeviceInfo::AudioOutput);
newDeviceList.append(info);
}
#endif
}
/*
* Compares the list with the devices available at the moment with the last list. If
* a new device is seen, a signal is emitted. If a device disappeared, another signal
* is emitted.
*/
// Search for added devices
for (int i = 0; i < newDeviceList.count(); ++i) {
int id = newDeviceList[i].id();
if (!listContainsDevice(m_devices, id)) {
// This is a new device, add it
m_devices.append(newDeviceList[i]);
emit deviceAdded(id);
debug() << "Added backend device" << newDeviceList[i].name();
}
}
// Search for removed devices
for (int i = m_devices.count() - 1; i >= 0; --i) {
int id = m_devices[i].id();
if (!listContainsDevice(newDeviceList, id)) {
emit deviceRemoved(id);
m_devices.removeAt(i);
}
}
}
bool DeviceManager::listContainsDevice(const QList<DeviceInfo> &list, int id)
{
foreach (const DeviceInfo &d, list) {
if (d.id() == id)
return true;
}
return false;
}
}
}

146
src/devicemanager.h Normal file
View File

@ -0,0 +1,146 @@
/*
Copyright (C) 2009-2010 vlc-phonon AUTHORS <kde-multimedia@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef Phonon_VLC_DEVICEMANAGER_H
#define Phonon_VLC_DEVICEMANAGER_H
#include <QtCore/QObject>
#include <phonon/ObjectDescription>
namespace Phonon
{
namespace VLC
{
class Backend;
/** \brief Container for information about devices supported by libVLC
*
* It includes a (hopefully unique) device identifier, a name identifier, a
* description, a hardware identifier (may be a platform dependent device name),
* and other relevant info.
*/
class DeviceInfo
{
public:
enum Capability {
None = 0x0000,
AudioOutput = 0x0001,
AudioCapture = 0x0002,
VideoCapture = 0x0004
};
public:
/**
* Constructs a device info object and sets it's device identifiers.
*/
explicit DeviceInfo(const QString &name, bool isAdvanced = true);
int id() const;
const QString& name() const;
const QString& description() const;
bool isAdvanced() const;
void setAdvanced(bool advanced);
const DeviceAccessList& accessList() const;
void addAccess(const DeviceAccess &access);
quint16 capabilities() const;
void setCapabilities(quint16 cap);
private:
int m_id;
QString m_name;
QString m_description;
bool m_isAdvanced;
DeviceAccessList m_accessList;
quint16 m_capabilities;
};
/** \brief Keeps track of audio/video devices that libVLC supports
*
* This class maintains a device list. Types of devices:
* \li audio output devices
* \li audio capture devices
* \li video capture devices
*
* Methods are provided to retrieve information about these devices.
*
* \see EffectManager
*/
class DeviceManager : public QObject
{
Q_OBJECT
public:
/**
* Constructs a device manager and immediately updates the devices.
*/
explicit DeviceManager(Backend *parent);
/**
* Clears all the devices before destroying.
*/
virtual ~DeviceManager();
/**
* \param type Only devices with a capability of this type are returned
* The following are supported:
* \li AudioOutputDeviceType
* \li AudioCaptureDeviceType
* \li VideoCaptureDeviceType
*
* \return A list of device identifiers that have capabilities that
* match the desired type
*
* \note The capture devices are temporarily not implemented / removed
*/
QList<int> deviceIds(ObjectDescriptionType type);
/**
* \param id The identifier for the device
* \return Object description properties for a device
*/
QHash<QByteArray, QVariant> deviceProperties(int id);
/**
* \param id The identifier for the device
* \return Pointer to DeviceInfo, or NULL if the id is invalid
*/
const DeviceInfo *device(int id) const;
signals:
void deviceAdded(int);
void deviceRemoved(int);
public slots:
/**
* Update the current list of active devices. It probes for audio output devices,
* audio capture devices, video capture devices. The methods depend on the
* device types.
*/
void updateDeviceList();
private:
static bool listContainsDevice(const QList<DeviceInfo> &list, int id);
private:
Backend *m_backend;
QList<DeviceInfo> m_devices;
};
}
} // namespace Phonon::VLC
#endif // Phonon_VLC_DEVICEMANAGER_H

225
src/effect.cpp Normal file
View File

@ -0,0 +1,225 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "effect.h"
#include "effectmanager.h"
#include "mediaobject.h"
namespace Phonon
{
namespace VLC
{
Effect::Effect(EffectManager *p_em, int i_effectId, QObject *p_parent)
: QObject(p_parent)
, SinkNode()
{
Q_UNUSED(p_em);
Q_UNUSED(i_effectId);
// p_effectManager = p_em;
// const QList<EffectInfo> effects = p_effectManager->effects();
// if (i_effectId >= 0 && i_effectId < effects.size()) {
// i_effect_filter = effects[ i_effectId ]->filter();
// effect_type = effects[ i_effectId ]->type();
// setupEffectParams();
// } else {
// // effect ID out of range
// Q_ASSERT(0);
// }
}
Effect::~Effect()
{
parameterList.clear();
}
void Effect::handleConnectToMediaObject(MediaObject *)
{
switch (effect_type) {
case EffectInfo::AudioEffect:
// libvlc_audio_filter_add(p_vlc_instance, (libvlc_audio_filter_names_t)i_effect_filter, vlc_exception);
// vlcExceptionRaised();
break;
case EffectInfo::VideoEffect:
// libvlc_video_filter_add(p_vlc_current_media_player, (libvlc_video_filter_names_t)i_effect_filter, vlc_exception);
// vlcExceptionRaised();
break;
}
}
void Effect::handleDisconnectFromMediaObject(MediaObject *)
{
switch (effect_type) {
case EffectInfo::AudioEffect:
// libvlc_audio_filter_remove(p_vlc_instance, (libvlc_audio_filter_names_t)i_effect_filter, vlc_exception);
// vlcExceptionRaised();
break;
case EffectInfo::VideoEffect:
// libvlc_video_filter_remove(p_vlc_current_media_player, (libvlc_video_filter_names_t)i_effect_filter, vlc_exception);
// vlcExceptionRaised();
break;
}
}
void Effect::setupEffectParams()
{
// libvlc_filter_parameter_list_t *p_list;
switch (effect_type) {
case EffectInfo::AudioEffect:
// p_list = libvlc_audio_filter_get_parameters(p_vlc_instance, (libvlc_audio_filter_names_t)i_effect_filter, vlc_exception );
// vlcExceptionRaised();
break;
case EffectInfo::VideoEffect:
// p_list = libvlc_video_filter_get_parameters(p_vlc_instance, (libvlc_video_filter_names_t)i_effect_filter, vlc_exception );
// vlcExceptionRaised();
break;
}
// if( !p_list )
// return;
// int i_index = 0;
// libvlc_filter_parameter_list_t *p_parameter_list = p_list;
// while (p_parameter_list) {
// switch (p_parameter_list->var_type) {
// case LIBVLC_BOOL: {
// const QString description = p_parameter_list->psz_description;
// parameterList.append(Phonon::EffectParameter(
// i_index,
// QString(p_parameter_list->psz_parameter_name),
// Phonon::EffectParameter::ToggledHint, // hints
// QVariant((bool) p_parameter_list->default_value.b_bool),
// QVariant((bool) false),
// QVariant((bool) true),
// QVariantList(),
// description));
// break;
// }
// case LIBVLC_INT: {
// const QString description = p_parameter_list->psz_description;
// parameterList.append(Phonon::EffectParameter(
// i_index,
// QString(p_parameter_list->psz_parameter_name),
// EffectParameter::IntegerHint, // hints
// QVariant((int) p_parameter_list->default_value.i_int),
// QVariant((int) p_parameter_list->min_value.i_int),
// QVariant((int) p_parameter_list->max_value.i_int),
// QVariantList(),
// description));
// break;
// }
// case LIBVLC_FLOAT: {
// const QString description = p_parameter_list->psz_description;
// parameterList.append(Phonon::EffectParameter(
// i_index,
// QString(p_parameter_list->psz_parameter_name),
// 0, // hints
// QVariant((double) p_parameter_list->default_value.f_float),
// QVariant((double) p_parameter_list->min_value.f_float),
// QVariant((double) p_parameter_list->max_value.f_float),
// QVariantList(),
// description));
// break;
// }
// case LIBVLC_STRING: {
// const QString description = p_parameter_list->psz_description;
// parameterList.append(Phonon::EffectParameter(
// i_index,
// QString(p_parameter_list->psz_parameter_name),
// 0, // hints
// QVariant((const char *) p_parameter_list->default_value.psz_string),
// NULL,
// NULL,
// QVariantList(),
// description));
// break;
// }
// }
// i_index++;
// p_parameter_list = p_parameter_list->p_next;
// }
// libvlc_filter_parameters_release(p_list);
}
QList<EffectParameter> Effect::parameters() const
{
return parameterList;
}
QVariant Effect::parameterValue(const EffectParameter &param) const
{
Q_UNUSED(param);
return QVariant();
}
void Effect::setParameterValue(const EffectParameter &param, const QVariant &newValue)
{
Q_UNUSED(param);
Q_UNUSED(newValue);
// libvlc_value_t value;
// libvlc_var_type_t type;
// switch (param.type()) {
// case QVariant::Bool:
// value.b_bool = newValue.toBool();
// type = LIBVLC_BOOL;
// break;
// case QVariant::Int:
// value.i_int = newValue.toInt();
// type = LIBVLC_INT;
// break;
// case QVariant::Double:
// value.f_float = (float) newValue.toDouble();
// type = LIBVLC_FLOAT;
// break;
// case QVariant::String:
// value.psz_string = newValue.toString().toAscii().data();
// type = LIBVLC_STRING;
// break;
// default:
// break;
// }
// switch (effect_type) {
// case EffectInfo::AudioEffect:
// libvlc_audio_filter_set_parameter(
// p_vlc_instance,
// // (libvlc_audio_filter_names_t) i_effect_filter,
// param.name().toAscii().data(),
// type,
// value,
// vlc_exception);
// vlcExceptionRaised();
// break;
// case EffectInfo::VideoEffect:
// libvlc_video_filter_set_parameter(
// p_vlc_current_media_player,
// (libvlc_video_filter_names_t) i_effect_filter,
// param.name().toAscii().data(),
// type,
// value,
// vlc_exception);
// vlcExceptionRaised();
// break;
// }
}
}
} // Namespace Phonon::VLC

80
src/effect.h Normal file
View File

@ -0,0 +1,80 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_EFFECT_H
#define PHONON_VLC_EFFECT_H
#include "sinknode.h"
#include "effectmanager.h"
#include <phonon/effectinterface.h>
#include <phonon/effectparameter.h>
namespace Phonon
{
namespace VLC
{
class EffectManager;
/** \brief Effect implementation for Phonon-VLC
*
* There are methods to get or set the effect parameters, implemented for
* the EffectInterface. See the Phonon documentation for details.
*
* As a sink node, it provides methods to handle the connection to a media object.
*
* An effect manager is the parent of each effect.
*
* \see EffectManager
* \see VolumeFaderEffect
*/
class Effect : public QObject, public SinkNode, public EffectInterface
{
Q_OBJECT
Q_INTERFACES(Phonon::EffectInterface)
public:
Effect(EffectManager *p_em, int i_effectId, QObject *p_parent);
~Effect();
void setupEffectParams();
QList<EffectParameter> parameters() const;
QVariant parameterValue(const EffectParameter &param) const;
void setParameterValue(const EffectParameter &param, const QVariant &newValue);
/** \reimp */
void handleConnectToMediaObject(MediaObject *p_media_object);
/** \reimp */
void handleDisconnectFromMediaObject(MediaObject *p_media_object);
private:
EffectManager *p_effectManager;
int i_effect_filter;
EffectInfo::Type effect_type;
QList<Phonon::EffectParameter> parameterList;
};
}
} // Namespace Phonon::VLC
#endif // PHONON_VLC_EFFECT_H

135
src/effectmanager.cpp Normal file
View File

@ -0,0 +1,135 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
Copyright (C) 2011 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "effectmanager.h"
#include <vlc/vlc.h>
#include <vlc/libvlc_version.h>
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 0, 0))
#include "equalizereffect.h"
#endif
#include "utils/debug.h"
#include "utils/libvlc.h"
namespace Phonon {
namespace VLC {
EffectInfo::EffectInfo(const QString &name, const QString &description,
const QString &author, int filter, Type type)
: m_name(name)
, m_description(description)
, m_author(author)
, m_filter(filter)
, m_type(type)
{}
EffectManager::EffectManager(QObject *parent)
: QObject(parent)
{
if (!pvlc_libvlc)
return;
updateEffects();
}
EffectManager::~EffectManager()
{
m_audioEffectList.clear();
m_videoEffectList.clear();
// EffectsList holds the same pointers as audio and video, so qDeleteAll on
// this container would cause a double freeing.
m_effectList.clear();
}
const QList<EffectInfo> EffectManager::audioEffects() const
{
return m_audioEffectList;
}
const QList<EffectInfo> EffectManager::videoEffects() const
{
return m_videoEffectList;
}
const QList<EffectInfo> EffectManager::effects() const
{
return m_effectList;
}
QObject *EffectManager::createEffect(int id, QObject *parent)
{
Q_UNUSED(id);
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 0, 0))
return new EqualizerEffect(parent);
#else
Q_UNUSED(parent);
#endif
return 0;
}
void EffectManager::updateEffects()
{
DEBUG_BLOCK;
m_effectList.clear();
m_audioEffectList.clear();
m_videoEffectList.clear();
// Generic effect activation etc is entirely kaput and equalizer has specific
// API anyway, so we simply manually insert it \o/
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 0, 0))
const QString eqName = QString("equalizer-%1bands").arg(QString::number(libvlc_audio_equalizer_get_band_count()));
m_audioEffectList.append(EffectInfo(
eqName,
QString(""),
QString(""),
0,
EffectInfo::AudioEffect));
#endif
// int moduleCount = -1;
// VLC_FOREACH_MODULE(module, libvlc_audio_filter_list_get(libvlc)) {
// m_audioEffectList.append(new EffectInfo(module->psz_longname,
// module->psz_help,
// QString(),
// ++moduleCount,
// EffectInfo::AudioEffect));
// }
// moduleCount = -1;
// VLC_FOREACH_MODULE(module, libvlc_video_filter_list_get(libvlc)) {
// m_videoEffectList.append(new EffectInfo(module->psz_longname,
// module->psz_help,
// QString(),
// ++moduleCount,
// EffectInfo::VideoEffect));
// }
m_effectList.append(m_audioEffectList);
m_effectList.append(m_videoEffectList);
}
} // namespace VLC
} // namespace Phonon

119
src/effectmanager.h Normal file
View File

@ -0,0 +1,119 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
Copyright (C) 2011 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef Phonon_VLC_EFFECTMANAGER_H
#define Phonon_VLC_EFFECTMANAGER_H
#include <QtCore/QObject>
namespace Phonon {
namespace VLC {
class Backend;
class EffectManager;
/// Holds information about an effect
class EffectInfo
{
public:
enum Type {AudioEffect, VideoEffect};
EffectInfo(const QString &name,
const QString &description,
const QString &author,
int filter,
Type type);
QString name() const {
return m_name;
}
QString description() const {
return m_description;
}
QString author() const {
return m_author;
}
int filter() const {
return m_filter;
}
Type type() const {
return m_type;
}
private:
QString m_name;
QString m_description;
QString m_author;
int m_filter;
Type m_type;
};
/** \brief Manages a list of effects.
*
* \see EffectInfo
*/
class EffectManager : public QObject
{
Q_OBJECT
public:
/**
* Creates a new effect manager. It creates the lists of effects.
*
* \param backend A parent backend object for the effect manager
*
* \warning Currently it doesn't add any effects, everything is disabled.
* \see EffectInfo
*/
explicit EffectManager(QObject *parent = 0);
/// Deletes all the effects from the lists and destroys the effect manager.
~EffectManager();
/// Returns a list of available audio effects
const QList<EffectInfo> audioEffects() const;
/// Returns a list of available video effects
const QList<EffectInfo> videoEffects() const;
/// Returns a list of available effects
const QList<EffectInfo> effects() const;
QObject *createEffect(int id, QObject *parent);
private:
/// Generates the aggegated list of effects from both video and audio
void updateEffects();
QList<EffectInfo> m_effectList;
QList<EffectInfo> m_audioEffectList;
QList<EffectInfo> m_videoEffectList;
bool m_equalizerEnabled;
};
} // namespace VLC
} // namespace Phonon
#endif // Phonon_VLC_EFFECTMANAGER_H

80
src/equalizereffect.cpp Normal file
View File

@ -0,0 +1,80 @@
/*
Copyright (C) 2013 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "equalizereffect.h"
#include "mediaplayer.h"
#include "utils/debug.h"
namespace Phonon {
namespace VLC {
EqualizerEffect::EqualizerEffect(QObject *parent)
: QObject(parent)
, SinkNode()
, EffectInterface()
, m_equalizer(libvlc_audio_equalizer_new())
{
// Amarok decided to make up rules because phonon didn't manage to
// pre-amp string needs to be pre-amp
// bands need to be xxHz
// That way they can be consistently mapped to localized/formatted strings.
EffectParameter preamp(-1, "pre-amp", 0 /* hint */, 0.0f, -20.0f, 20.0f);
m_bands.append(preamp);
const unsigned int bandCount = libvlc_audio_equalizer_get_band_count();
for (unsigned int i = 0; i < bandCount; ++i) {
const float frequency = libvlc_audio_equalizer_get_band_frequency(i);
const QString name = QString("%1Hz").arg(QString::number(frequency));
EffectParameter parameter(i, name, 0 /* hint */, 0.0f, -20.0f, 20.0f);
m_bands.append(parameter);
}
}
EqualizerEffect::~EqualizerEffect()
{
libvlc_audio_equalizer_release(m_equalizer);
}
QList<EffectParameter> EqualizerEffect::parameters() const
{
return m_bands;
}
QVariant EqualizerEffect::parameterValue(const EffectParameter &parameter) const
{
return libvlc_audio_equalizer_get_amp_at_index(m_equalizer, parameter.id());
}
void EqualizerEffect::setParameterValue(const EffectParameter &parameter,
const QVariant &newValue)
{
if (parameter.id() == -1)
libvlc_audio_equalizer_set_preamp(m_equalizer, newValue.toFloat());
else
libvlc_audio_equalizer_set_amp_at_index(m_equalizer, newValue.toFloat(), parameter.id());
}
void EqualizerEffect::handleConnectToMediaObject(MediaObject *mediaObject)
{
Q_UNUSED(mediaObject);
m_player->setEqualizer(m_equalizer);
}
} // namespace VLC
} // namespace Phonon

55
src/equalizereffect.h Normal file
View File

@ -0,0 +1,55 @@
/*
Copyright (C) 2013 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_EQUALIZEREFFECT_H
#define PHONON_VLC_EQUALIZEREFFECT_H
#include <QtCore/QObject>
#include <phonon/effectinterface.h>
#include <phonon/effectparameter.h>
#include <vlc/vlc.h>
#include "sinknode.h"
namespace Phonon {
namespace VLC {
class EqualizerEffect : public QObject, public SinkNode, public EffectInterface
{
Q_OBJECT
Q_INTERFACES(Phonon::EffectInterface)
public:
explicit EqualizerEffect(QObject *parent = 0);
~EqualizerEffect();
QList<EffectParameter> parameters() const;
QVariant parameterValue(const EffectParameter &parameter) const;
void setParameterValue(const EffectParameter &parameter, const QVariant &newValue);
void handleConnectToMediaObject(MediaObject *mediaObject);
private:
libvlc_equalizer_t *m_equalizer;
QList <EffectParameter> m_bands;
};
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_EQUALIZEREFFECT_H

109
src/media.cpp Normal file
View File

@ -0,0 +1,109 @@
/*
Copyright (C) 2011 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "media.h"
#include <QtCore/QDebug>
#include <vlc/vlc.h>
#include "utils/debug.h"
#include "utils/libvlc.h"
#include "utils/vstring.h"
namespace Phonon {
namespace VLC {
Media::Media(const QByteArray &mrl, QObject *parent) :
QObject(parent),
m_media(libvlc_media_new_location(pvlc_libvlc, mrl.constData())),
m_mrl(mrl)
{
Q_ASSERT(m_media);
libvlc_event_manager_t *manager = libvlc_media_event_manager(m_media);
libvlc_event_type_t events[] = {
libvlc_MediaMetaChanged,
libvlc_MediaSubItemAdded,
libvlc_MediaDurationChanged,
libvlc_MediaParsedChanged,
libvlc_MediaFreed,
libvlc_MediaStateChanged
};
const int eventCount = sizeof(events) / sizeof(*events);
for (int i = 0; i < eventCount; ++i) {
libvlc_event_attach(manager, events[i], event_cb, this);
}
}
Media::~Media()
{
if (m_media) {
libvlc_media_release(m_media);
m_media = 0;
}
}
void Media::addOption(const QString &option)
{
libvlc_media_add_option_flag(m_media,
option.toUtf8().data(),
libvlc_media_option_trusted);
}
QString Media::meta(libvlc_meta_t meta)
{
return VString(libvlc_media_get_meta(m_media, meta)).toQString();
}
void Media::event_cb(const libvlc_event_t *event, void *opaque)
{
Media *that = reinterpret_cast<Media *>(opaque);
Q_ASSERT(that);
switch (event->type) {
case libvlc_MediaDurationChanged:
QMetaObject::invokeMethod(
that, "durationChanged",
Qt::QueuedConnection,
Q_ARG(qint64, event->u.media_duration_changed.new_duration));
break;
case libvlc_MediaMetaChanged:
QMetaObject::invokeMethod(
that, "metaDataChanged",
Qt::QueuedConnection);
break;
case libvlc_MediaSubItemAdded:
case libvlc_MediaParsedChanged:
case libvlc_MediaFreed:
case libvlc_MediaStateChanged:
default:
break;
QString msg = QString("Unknown event: ") + QString(libvlc_event_type_name(event->type));
Q_ASSERT_X(false, "event_cb", qPrintable(msg));
break;
}
}
void Media::setCdTrack(int track)
{
debug() << "setting CDDA track" << track;
addOption(QLatin1String(":cdda-track="), QVariant(track));
}
} // namespace VLC
} // namespace Phonon

77
src/media.h Normal file
View File

@ -0,0 +1,77 @@
/*
Copyright (C) 2011 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_MEDIA_H
#define PHONON_VLC_MEDIA_H
#include <QtCore/QObject>
#include <QtCore/QStringBuilder>
#include <QtCore/QVariant>
#include <vlc/libvlc.h>
#include <vlc/libvlc_media.h>
#define INTPTR_PTR(x) reinterpret_cast<intptr_t>(x)
#define INTPTR_FUNC(x) reinterpret_cast<intptr_t>(&x)
namespace Phonon {
namespace VLC {
class Media : public QObject
{
Q_OBJECT
public:
explicit Media(const QByteArray &mrl, QObject *parent = 0);
~Media();
inline libvlc_media_t *libvlc_media() const { return m_media; }
inline operator libvlc_media_t *() const { return m_media; }
inline void addOption(const QString &option, const QVariant &argument)
{
addOption(option % argument.toString());
}
inline void addOption(const QString &option, intptr_t functionPtr)
{
QString optionWithPtr = option;
optionWithPtr.append(QString::number(static_cast<qint64>(functionPtr)));
addOption(optionWithPtr);
}
void addOption(const QString &option);
QString meta(libvlc_meta_t meta);
void setCdTrack(int track);
signals:
void durationChanged(qint64 duration);
void metaDataChanged();
private:
static void event_cb(const libvlc_event_t *event, void *opaque);
libvlc_media_t *m_media;
libvlc_state_t m_state;
QByteArray m_mrl;
};
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_MEDIA_H

497
src/mediacontroller.cpp Normal file
View File

@ -0,0 +1,497 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
Copyright (C) 2011-2018 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mediacontroller.h"
#include <phonon/GlobalDescriptionContainer>
#include <QTimer>
#include "utils/debug.h"
#include "utils/libvlc.h"
#include "mediaplayer.h"
namespace Phonon {
namespace VLC {
#ifdef __GNUC__
#warning titles and chapters not covered by globaldescriptioncontainer!!
#endif
MediaController::MediaController()
: m_subtitleAutodetect(true)
, m_subtitleEncoding("UTF-8")
, m_subtitleFontChanged(false)
, m_player(0)
, m_refreshTimer(new QTimer(dynamic_cast<QObject *>(this)))
, m_attemptingAutoplay(false)
{
GlobalSubtitles::instance()->register_(this);
GlobalAudioChannels::instance()->register_(this);
resetMembers();
}
MediaController::~MediaController()
{
GlobalSubtitles::instance()->unregister_(this);
GlobalAudioChannels::instance()->unregister_(this);
}
bool MediaController::hasInterface(Interface iface) const
{
switch (iface) {
case AddonInterface::NavigationInterface:
return true;
break;
case AddonInterface::ChapterInterface:
return true;
break;
case AddonInterface::AngleInterface:
return false;
break;
case AddonInterface::TitleInterface:
return true;
break;
case AddonInterface::SubtitleInterface:
return true;
break;
case AddonInterface::AudioChannelInterface:
return true;
break;
}
warning() << "Interface" << iface << "is not supported by Phonon VLC :(";
return false;
}
QVariant MediaController::interfaceCall(Interface iface, int i_command, const QList<QVariant> & arguments)
{
DEBUG_BLOCK;
switch (iface) {
case AddonInterface::ChapterInterface:
switch (static_cast<AddonInterface::ChapterCommand>(i_command)) {
case AddonInterface::availableChapters:
return availableChapters();
case AddonInterface::chapter:
return currentChapter();
case AddonInterface::setChapter:
if (arguments.isEmpty() || !arguments.first().canConvert(QVariant::Int)) {
error() << Q_FUNC_INFO << "arguments invalid";
return false;
}
setCurrentChapter(arguments.first().toInt());
return true;
}
break;
case AddonInterface::TitleInterface:
switch (static_cast<AddonInterface::TitleCommand>(i_command)) {
case AddonInterface::availableTitles:
return availableTitles();
case AddonInterface::title:
return currentTitle();
case AddonInterface::setTitle:
if (arguments.isEmpty() || !arguments.first().canConvert(QVariant::Int)) {
error() << Q_FUNC_INFO << "arguments invalid";
return false;
}
setCurrentTitle(arguments.first().toInt());
return true;
case AddonInterface::autoplayTitles:
return autoplayTitles();
case AddonInterface::setAutoplayTitles:
if (arguments.isEmpty() || !arguments.first().canConvert(QVariant::Bool)) {
error() << Q_FUNC_INFO << " arguments invalid";
return false;
}
setAutoplayTitles(arguments.first().toBool());
return true;
}
break;
case AddonInterface::AngleInterface:
warning() << "AddonInterface::AngleInterface not supported!";
break;
case AddonInterface::SubtitleInterface:
switch (static_cast<AddonInterface::SubtitleCommand>(i_command)) {
case AddonInterface::availableSubtitles:
return QVariant::fromValue(availableSubtitles());
case AddonInterface::currentSubtitle:
return QVariant::fromValue(currentSubtitle());
case AddonInterface::setCurrentSubtitle:
if (arguments.isEmpty() || !arguments.first().canConvert<SubtitleDescription>()) {
error() << Q_FUNC_INFO << "arguments invalid";
return false;
}
setCurrentSubtitle(arguments.first().value<SubtitleDescription>());
return true;
case AddonInterface::setCurrentSubtitleFile:
if (arguments.isEmpty() || !arguments.first().canConvert<QUrl>()) {
error() << Q_FUNC_INFO << " arguments invalid";
return false;
}
setCurrentSubtitleFile(arguments.first().value<QUrl>());
case AddonInterface::subtitleAutodetect:
return QVariant::fromValue(subtitleAutodetect());
case AddonInterface::setSubtitleAutodetect:
if (arguments.isEmpty() || !arguments.first().canConvert<bool>()) {
error() << Q_FUNC_INFO << " arguments invalid";
return false;
}
setSubtitleAutodetect(arguments.first().value<bool>());
return true;
case AddonInterface::subtitleEncoding:
return subtitleEncoding();
case AddonInterface::setSubtitleEncoding:
if (arguments.isEmpty() || !arguments.first().canConvert<QString>()) {
error() << Q_FUNC_INFO << " arguments invalid";
return false;
}
setSubtitleEncoding(arguments.first().value<QString>());
return true;
case AddonInterface::subtitleFont:
return subtitleFont();
case AddonInterface::setSubtitleFont:
if (arguments.isEmpty() || !arguments.first().canConvert<QFont>()) {
error() << Q_FUNC_INFO << " arguments invalid";
return false;
}
setSubtitleFont(arguments.first().value<QFont>());
return true;
}
break;
case AddonInterface::AudioChannelInterface:
switch (static_cast<AddonInterface::AudioChannelCommand>(i_command)) {
case AddonInterface::availableAudioChannels:
return QVariant::fromValue(availableAudioChannels());
case AddonInterface::currentAudioChannel:
return QVariant::fromValue(currentAudioChannel());
case AddonInterface::setCurrentAudioChannel:
if (arguments.isEmpty() || !arguments.first().canConvert<AudioChannelDescription>()) {
error() << Q_FUNC_INFO << "arguments invalid";
return false;
}
setCurrentAudioChannel(arguments.first().value<AudioChannelDescription>());
return true;
}
break;
}
error() << Q_FUNC_INFO << "unsupported AddonInterface::Interface:" << iface;
return QVariant();
}
void MediaController::resetMediaController()
{
resetMembers();
emit availableAudioChannelsChanged();
emit availableSubtitlesChanged();
emit availableTitlesChanged(0);
emit availableChaptersChanged(0);
}
void MediaController::resetMembers()
{
m_currentAudioChannel = Phonon::AudioChannelDescription();
GlobalAudioChannels::self->clearListFor(this);
m_currentSubtitle = Phonon::SubtitleDescription();
GlobalSubtitles::instance()->clearListFor(this);
m_currentChapter = 0;
m_availableChapters = 0;
m_currentTitle = 1;
m_availableTitles = 0;
m_attemptingAutoplay = false;
}
// ----------------------------- Audio Channel ------------------------------ //
void MediaController::setCurrentAudioChannel(const Phonon::AudioChannelDescription &audioChannel)
{
const int localIndex = GlobalAudioChannels::instance()->localIdFor(this, audioChannel.index());
if (!m_player->setAudioTrack(localIndex))
error() << "libVLC:" << LibVLC::errorMessage();
else
m_currentAudioChannel = audioChannel;
}
QList<Phonon::AudioChannelDescription> MediaController::availableAudioChannels() const
{
return GlobalAudioChannels::instance()->listFor(this);
}
Phonon::AudioChannelDescription MediaController::currentAudioChannel() const
{
return m_currentAudioChannel;
}
void MediaController::refreshAudioChannels()
{
GlobalAudioChannels::instance()->clearListFor(this);
const int currentChannelId = m_player->audioTrack();
int idCount = 0;
VLC_FOREACH_TRACK(it, m_player->audioTrackDescription()) {
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0))
idCount= it->i_id;
#else
// LibVLC's internal ID is broken, so we simply count up as internally
// the setter will simply go by position in list anyway.
#endif
GlobalAudioChannels::instance()->add(this, idCount, QString::fromUtf8(it->psz_name), "");
if (idCount == currentChannelId) {
#ifdef __GNUC__
#warning GlobalDescriptionContainer does not allow reverse resolution from local to descriptor!
#endif
const QList<AudioChannelDescription> list = GlobalAudioChannels::instance()->listFor(this);
foreach (const AudioChannelDescription &descriptor, list) {
if (descriptor.name() == QString::fromUtf8(it->psz_name)) {
m_currentAudioChannel = descriptor;
}
}
}
++idCount;
}
emit availableAudioChannelsChanged();
}
// -------------------------------- Subtitle -------------------------------- //
void MediaController::setCurrentSubtitle(const Phonon::SubtitleDescription &subtitle)
{
DEBUG_BLOCK;
QString type = subtitle.property("type").toString();
debug() << subtitle;
if (type == "file") {
QString filename = subtitle.property("name").toString();
if (!filename.isEmpty()) {
if (!m_player->setSubtitle(filename))
error() << "libVLC:" << LibVLC::errorMessage();
else
m_currentSubtitle = subtitle;
// There is no subtitle event inside libvlc so let's send our own event...
GlobalSubtitles::instance()->add(this, m_currentSubtitle);
emit availableSubtitlesChanged();
}
} else {
const int localIndex = GlobalSubtitles::instance()->localIdFor(this, subtitle.index());
debug () << "localid" << localIndex;
if (!m_player->setSubtitle(localIndex))
error() << "libVLC:" << LibVLC::errorMessage();
else
m_currentSubtitle = subtitle;
}
}
void MediaController::setCurrentSubtitleFile(const QUrl &url)
{
const QString file = url.toLocalFile();
if (!m_player->setSubtitle(file))
error() << "libVLC failed to set subtitle file:" << LibVLC::errorMessage();
// Unfortunately the addition of SPUs does not trigger an event in the
// VLC mediaplayer, yet the actual addition to the descriptor is async.
// So for the time being our best shot at getting an up-to-date list of SPUs
// is shooting in the dark and hoping we hit something.
// Refresha after 1, 2 and 5 seconds. If we have no updated list after 5
// seconds we are out of luck.
// https://trac.videolan.org/vlc/ticket/9796
QObject *mediaObject = dynamic_cast<QObject *>(this); // MediaObject : QObject, MediaController
m_refreshTimer->singleShot(1 * 1000, mediaObject, SLOT(refreshDescriptors()));
m_refreshTimer->singleShot(2 * 1000, mediaObject, SLOT(refreshDescriptors()));
m_refreshTimer->singleShot(5 * 1000, mediaObject, SLOT(refreshDescriptors()));
}
QList<Phonon::SubtitleDescription> MediaController::availableSubtitles() const
{
return GlobalSubtitles::instance()->listFor(this);
}
Phonon::SubtitleDescription MediaController::currentSubtitle() const
{
return m_currentSubtitle;
}
void MediaController::refreshSubtitles()
{
DEBUG_BLOCK;
GlobalSubtitles::instance()->clearListFor(this);
const int currentSubtitleId = m_player->subtitle();
VLC_FOREACH_TRACK(it, m_player->videoSubtitleDescription()) {
debug() << "found subtitle" << it->psz_name << "[" << it->i_id << "]";
GlobalSubtitles::instance()->add(this, it->i_id, QString::fromUtf8(it->psz_name), "");
if (it->i_id == currentSubtitleId) {
#ifdef __GNUC__
#warning GlobalDescriptionContainer does not allow reverse resolution from local to descriptor!
#endif
const QList<SubtitleDescription> list = GlobalSubtitles::instance()->listFor(this);
foreach (const SubtitleDescription &descriptor, list) {
if (descriptor.name() == QString::fromUtf8(it->psz_name)) {
m_currentSubtitle = descriptor;
}
}
}
}
emit availableSubtitlesChanged();
}
bool MediaController::subtitleAutodetect() const
{
return m_subtitleAutodetect;
}
void MediaController::setSubtitleAutodetect(bool enabled)
{
m_subtitleAutodetect = enabled;
}
QString MediaController::subtitleEncoding() const
{
return m_subtitleEncoding;
}
void MediaController::setSubtitleEncoding(const QString &encoding)
{
m_subtitleEncoding = encoding;
}
QFont MediaController::subtitleFont() const
{
return m_subtitleFont;
}
void MediaController::setSubtitleFont(const QFont &font)
{
m_subtitleFontChanged = true;
m_subtitleFont = font;
}
// --------------------------------- Title ---------------------------------- //
void MediaController::setCurrentTitle(int title)
{
DEBUG_BLOCK;
m_currentTitle = title;
switch (source().discType()) {
case Cd:
m_player->setCdTrack(title);
return;
case Dvd:
case Vcd:
case BluRay:
m_player->setTitle(title);
return;
case NoDisc:
warning() << "Current media source is not a CD, DVD or VCD!";
return;
}
warning() << "MediaSource does not support setting of tile in this version of Phonon VLC!"
<< "Type is" << source().discType();
}
int MediaController::availableTitles() const
{
return m_availableTitles;
}
int MediaController::currentTitle() const
{
return m_currentTitle;
}
void MediaController::setAutoplayTitles(bool autoplay)
{
m_autoPlayTitles = autoplay;
}
bool MediaController::autoplayTitles() const
{
return m_autoPlayTitles;
}
void MediaController::refreshTitles()
{
m_availableTitles = 0;
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0))
SharedTitleDescriptions list = m_player->titleDescription();
for (unsigned int i = 0; i < list->size(); ++i) {
++m_availableTitles;
emit availableTitlesChanged(m_availableTitles);
}
#else
VLC_FOREACH_TRACK(it, m_player->titleDescription()) {
++m_availableTitles;
emit availableTitlesChanged(m_availableTitles);
}
#endif
}
// -------------------------------- Chapter --------------------------------- //
void MediaController::setCurrentChapter(int chapter)
{
m_currentChapter = chapter;
m_player->setChapter(chapter);
}
int MediaController::availableChapters() const
{
return m_availableChapters;
}
int MediaController::currentChapter() const
{
return m_currentChapter;
}
// We need to rebuild available chapters when title is changed
void MediaController::refreshChapters(int title)
{
m_availableChapters = 0;
// Get the description of available chapters for specific title
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0))
SharedChapterDescriptions list = m_player->videoChapterDescription(title);
for (unsigned int i = 0; i < list->size(); ++i) {
++m_availableChapters;
emit availableChaptersChanged(m_availableChapters);
}
#else
VLC_FOREACH_TRACK(it, m_player->videoChapterDescription(title)) {
++m_availableChapters;
emit availableChaptersChanged(m_availableChapters);
}
#endif
}
// --------------------------------- Angle ---------------------------------- //
// NOT SUPPORTED IN LIBVLC //
} // namespace VLC
} // namespace Phonon

156
src/mediacontroller.h Normal file
View File

@ -0,0 +1,156 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_MEDIACONTROLLER_H
#define PHONON_VLC_MEDIACONTROLLER_H
#include <phonon/AddonInterface>
#include <phonon/MediaSource>
#include <phonon/ObjectDescription>
#include <QtGui/QFont>
class QTimer;
namespace Phonon {
namespace VLC {
class MediaPlayer;
/**
* \brief Interface for AddonInterface.
*
* Provides a bridge between Phonon's AddonInterface and MediaController.
*
* This class cannot inherit from QObject has MediaObject already inherit from QObject.
* This is a Qt limitation: there is no possibility to inherit virtual Qobject :/
* See http://doc.trolltech.com/qq/qq15-academic.html
* Phonon implementation got the same problem.
*
* \see MediaObject
*/
class MediaController : public AddonInterface
{
public:
MediaController();
virtual ~MediaController();
bool hasInterface(Interface iface) const;
QVariant interfaceCall(Interface iface, int i_command, const QList<QVariant> & arguments = QList<QVariant>());
/**
* Overloaded by MediaObject through MediaObjectInterface.
* Access to the media source is necessary to identify the type of the source
* and behave accordingly.
*
* For example setTitle calls need to work on both DVDs and CDs, however
* in libvlc titles and tracks are two different concepts.
*/
virtual MediaSource source() const = 0;
// MediaController signals
virtual void availableSubtitlesChanged() = 0;
virtual void availableAudioChannelsChanged() = 0;
virtual void availableChaptersChanged(int) = 0;
virtual void availableTitlesChanged(int) = 0;
void titleAdded(int id, const QString &name);
void chapterAdded(int titleId, const QString &name);
protected:
// AudioChannel
void setCurrentAudioChannel(const Phonon::AudioChannelDescription &audioChannel);
QList<Phonon::AudioChannelDescription> availableAudioChannels() const;
Phonon::AudioChannelDescription currentAudioChannel() const;
void refreshAudioChannels();
// Subtitle
void setCurrentSubtitle(const Phonon::SubtitleDescription &subtitle);
void setCurrentSubtitleFile(const QUrl &url);
QList<Phonon::SubtitleDescription> availableSubtitles() const;
Phonon::SubtitleDescription currentSubtitle() const;
void refreshSubtitles();
bool subtitleAutodetect() const;
void setSubtitleAutodetect(bool enabled);
QString subtitleEncoding() const;
void setSubtitleEncoding(const QString &encoding);
QFont subtitleFont() const;
void setSubtitleFont(const QFont &font);
// Chapter
void setCurrentChapter(int chapterNumber);
int availableChapters() const;
int currentChapter() const;
void refreshChapters(int title);
// Title
void setCurrentTitle(int titleNumber);
int availableTitles() const;
int currentTitle() const;
void setAutoplayTitles(bool autoplay);
bool autoplayTitles() const;
void refreshTitles();
/**
* Clear all member variables and emit appropriate signals.
* This is used each time we restart the video.
*
* \see resetMembers
*/
void resetMediaController();
/**
* Reset all member variables.
*
* \see resetMediaController
*/
void resetMembers();
Phonon::AudioChannelDescription m_currentAudioChannel;
Phonon::SubtitleDescription m_currentSubtitle;
int m_currentChapter;
int m_availableChapters;
int m_currentTitle;
int m_availableTitles;
bool m_autoPlayTitles;
bool m_subtitleAutodetect;
QString m_subtitleEncoding;
bool m_subtitleFontChanged;
QFont m_subtitleFont;
// MediaPlayer
MediaPlayer *m_player;
QTimer *m_refreshTimer;
bool m_attemptingAutoplay;
};
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_MEDIACONTROLLER_H

844
src/mediaobject.cpp Normal file
View File

@ -0,0 +1,844 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2010 Ben Cooksley <sourtooth@gmail.com>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
Copyright (C) 2010-2021 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mediaobject.h"
#include <QtCore/QDir>
#include <QtCore/QStringBuilder>
#include <QtCore/QUrl>
#include <phonon/pulsesupport.h>
#include <vlc/libvlc_version.h>
#include <vlc/vlc.h>
#include "utils/debug.h"
#include "utils/libvlc.h"
#include "media.h"
#include "sinknode.h"
#include "streamreader.h"
//Time in milliseconds before sending aboutToFinish() signal
//2 seconds
static const int ABOUT_TO_FINISH_TIME = 2000;
namespace Phonon {
namespace VLC {
MediaObject::MediaObject(QObject *parent)
: QObject(parent)
, m_nextSource(MediaSource(QUrl()))
, m_streamReader(0)
, m_state(Phonon::StoppedState)
, m_tickInterval(0)
, m_transitionTime(0)
, m_media(0)
{
qRegisterMetaType<QMultiMap<QString, QString> >("QMultiMap<QString, QString>");
m_player = new MediaPlayer(this);
Q_ASSERT(m_player);
if (!m_player->libvlc_media_player())
error() << "libVLC:" << LibVLC::errorMessage();
// Player signals.
connect(m_player, SIGNAL(seekableChanged(bool)), this, SIGNAL(seekableChanged(bool)));
connect(m_player, SIGNAL(timeChanged(qint64)), this, SLOT(timeChanged(qint64)));
connect(m_player, SIGNAL(stateChanged(MediaPlayer::State)), this, SLOT(updateState(MediaPlayer::State)));
connect(m_player, SIGNAL(hasVideoChanged(bool)), this, SLOT(onHasVideoChanged(bool)));
connect(m_player, SIGNAL(bufferChanged(int)), this, SLOT(setBufferStatus(int)));
connect(m_player, SIGNAL(timeChanged(qint64)), this, SLOT(timeChanged(qint64)));
// Internal Signals.
connect(this, SIGNAL(moveToNext()), SLOT(moveToNextSource()));
connect(m_refreshTimer, SIGNAL(timeout()), this, SLOT(refreshDescriptors()));
resetMembers();
}
MediaObject::~MediaObject()
{
unloadMedia();
// Shutdown the pulseaudio mainloop before the MediaPlayer gets destroyed
// (it is a child of the MO). There appears to be a peculiar race condition
// between the pa_thread_mainloop used by VLC and the pa_glib_mainloop used
// by Phonon's PulseSupport where for a very short time frame after the
// former was stopped and freed the latter can run and fall over
// Invalid read from eventfd: Bad file descriptor
// Code should not be reached at pulsecore/fdsem.c:157, function flush(). Aborting.
// Since we don't use PulseSupport since VLC 2.2 we can simply force a
// loop shutdown even when the application isn't about to terminate.
// The instance gets created again anyway.
PulseSupport::shutdown();
}
void MediaObject::resetMembers()
{
// default to -1, so that streams won't break and to comply with the docs (-1 if unknown)
m_totalTime = -1;
m_hasVideo = false;
m_seekpoint = 0;
m_prefinishEmitted = false;
m_aboutToFinishEmitted = false;
m_lastTick = 0;
m_timesVideoChecked = 0;
m_buffering = false;
m_stateAfterBuffering = ErrorState;
resetMediaController();
// Forcefully shutdown plusesupport to prevent crashing between the PS PA glib mainloop
// and the VLC PA threaded mainloop. See destructor.
PulseSupport::shutdown();
}
void MediaObject::play()
{
DEBUG_BLOCK;
switch (m_state) {
case PlayingState:
// Do not do anything if we are already playing (as per documentation).
return;
case PausedState:
m_player->resume();
break;
default:
setupMedia();
if (m_player->play())
error() << "libVLC:" << LibVLC::errorMessage();
break;
}
}
void MediaObject::pause()
{
DEBUG_BLOCK;
switch (m_state) {
case BufferingState:
case PlayingState:
m_player->pause();
break;
case PausedState:
return;
default:
debug() << "doing paused play";
setupMedia();
m_player->pausedPlay();
break;
}
}
void MediaObject::stop()
{
DEBUG_BLOCK;
if (m_streamReader)
m_streamReader->unlock();
m_nextSource = MediaSource(QUrl());
m_player->stop();
}
void MediaObject::seek(qint64 milliseconds)
{
DEBUG_BLOCK;
switch (m_state) {
case PlayingState:
case PausedState:
case BufferingState:
break;
default:
// Seeking while not being in a playingish state is cached for later.
m_seekpoint = milliseconds;
return;
}
debug() << "seeking" << milliseconds << "msec";
m_player->setTime(milliseconds);
const qint64 time = currentTime();
const qint64 total = totalTime();
// Reset last tick marker so we emit time even after seeking
if (time < m_lastTick)
m_lastTick = time;
if (time < total - m_prefinishMark)
m_prefinishEmitted = false;
if (time < total - ABOUT_TO_FINISH_TIME)
m_aboutToFinishEmitted = false;
}
void MediaObject::timeChanged(qint64 time)
{
const qint64 totalTime = m_totalTime;
switch (m_state) {
case PlayingState:
case BufferingState:
case PausedState:
emitTick(time);
default:
break;
}
if (m_state == PlayingState || m_state == BufferingState) { // Buffering is concurrent
if (time >= totalTime - m_prefinishMark) {
if (!m_prefinishEmitted) {
m_prefinishEmitted = true;
emit prefinishMarkReached(totalTime - time);
}
}
// Note that when the totalTime is <= 0 we cannot calculate any sane delta.
if (totalTime > 0 && time >= totalTime - ABOUT_TO_FINISH_TIME)
emitAboutToFinish();
}
}
void MediaObject::emitTick(qint64 time)
{
if (m_tickInterval == 0) // Make sure we do not ever emit ticks when deactivated.\]
return;
if (time + m_tickInterval >= m_lastTick) {
m_lastTick = time;
emit tick(time);
}
}
void MediaObject::loadMedia(const QByteArray &mrl)
{
DEBUG_BLOCK;
// Initial state is loading, from which we quickly progress to stopped because
// libvlc does not provide feedback on loading and the media does not get loaded
// until we play it.
// FIXME: libvlc should really allow for this as it can cause unexpected delay
// even though the GUI might indicate that playback should start right away.
changeState(Phonon::LoadingState);
m_mrl = mrl;
debug() << "loading encoded:" << m_mrl;
// We do not have a loading state generally speaking, usually the backend
// is exepected to go to loading state and then at some point reach stopped,
// at which point playback can be started.
// See state enum documentation for more information.
changeState(Phonon::StoppedState);
}
void MediaObject::loadMedia(const QString &mrl)
{
loadMedia(mrl.toUtf8());
}
qint32 MediaObject::tickInterval() const
{
return m_tickInterval;
}
/**
* Supports runtime changes.
* If the user goes to tick(0) we stop the timer, otherwise we fire it up.
*/
void MediaObject::setTickInterval(qint32 interval)
{
m_tickInterval = interval;
}
qint64 MediaObject::currentTime() const
{
qint64 time = -1;
switch (state()) {
case Phonon::PausedState:
case Phonon::BufferingState:
case Phonon::PlayingState:
time = m_player->time();
break;
case Phonon::StoppedState:
case Phonon::LoadingState:
time = 0;
break;
case Phonon::ErrorState:
time = -1;
break;
}
return time;
}
Phonon::State MediaObject::state() const
{
return m_state;
}
Phonon::ErrorType MediaObject::errorType() const
{
return Phonon::NormalError;
}
MediaSource MediaObject::source() const
{
return m_mediaSource;
}
void MediaObject::setSource(const MediaSource &source)
{
DEBUG_BLOCK;
// Reset previous streamereaders
if (m_streamReader) {
m_streamReader->unlock();
delete m_streamReader;
m_streamReader = 0;
// For streamreaders we exchanage the player's seekability with the
// reader's so here we change it back.
// Note: the reader auto-disconnects due to destruction.
connect(m_player, SIGNAL(seekableChanged(bool)), this, SIGNAL(seekableChanged(bool)));
}
// Reset previous isScreen flag
m_isScreen = false;
m_mediaSource = source;
QByteArray url;
switch (source.type()) {
case MediaSource::Invalid:
error() << Q_FUNC_INFO << "MediaSource Type is Invalid:" << source.type();
break;
case MediaSource::Empty:
error() << Q_FUNC_INFO << "MediaSource is empty.";
break;
case MediaSource::LocalFile:
case MediaSource::Url:
debug() << "MediaSource::Url:" << source.url();
if (source.url().scheme().isEmpty()) {
url = "file://";
// QUrl considers url.scheme.isEmpty() == url.isRelative(),
// so to be sure the url is not actually absolute we just
// check the first character
if (!source.url().toString().startsWith('/'))
url.append(QFile::encodeName(QDir::currentPath()) + '/');
}
url += source.url().toEncoded();
loadMedia(url);
break;
case MediaSource::Disc:
switch (source.discType()) {
case Phonon::NoDisc:
error() << Q_FUNC_INFO << "the MediaSource::Disc doesn't specify which one (Phonon::NoDisc)";
return;
case Phonon::Cd:
loadMedia(QLatin1Literal("cdda://") % m_mediaSource.deviceName());
break;
case Phonon::Dvd:
loadMedia(QLatin1Literal("dvd://") % m_mediaSource.deviceName());
break;
case Phonon::Vcd:
loadMedia(QLatin1Literal("vcd://") % m_mediaSource.deviceName());
break;
case Phonon::BluRay:
loadMedia(QLatin1Literal("bluray://") % m_mediaSource.deviceName());
break;
}
break;
case MediaSource::CaptureDevice: {
QByteArray driverName;
QString deviceName;
if (source.deviceAccessList().isEmpty()) {
error() << Q_FUNC_INFO << "No device access list for this capture device";
break;
}
// TODO try every device in the access list until it works, not just the first one
driverName = source.deviceAccessList().first().first;
deviceName = source.deviceAccessList().first().second;
if (driverName == QByteArray("v4l2")) {
loadMedia(QLatin1Literal("v4l2://") % deviceName);
} else if (driverName == QByteArray("alsa")) {
/*
* Replace "default" and "plughw" and "x-phonon" with "hw" for capture device names, because
* VLC does not want to open them when using default instead of hw.
* plughw also does not work.
*
* TODO investigate what happens
*/
if (deviceName.startsWith(QLatin1String("default"))) {
deviceName.replace(0, 7, "hw");
}
if (deviceName.startsWith(QLatin1String("plughw"))) {
deviceName.replace(0, 6, "hw");
}
if (deviceName.startsWith(QLatin1String("x-phonon"))) {
deviceName.replace(0, 8, "hw");
}
loadMedia(QLatin1Literal("alsa://") % deviceName);
} else if (driverName == "screen") {
loadMedia(QLatin1Literal("screen://") % deviceName);
// Set the isScreen flag needed to add extra options in playInternal
m_isScreen = true;
} else {
error() << Q_FUNC_INFO << "Unsupported MediaSource::CaptureDevice:" << driverName;
break;
}
break;
}
case MediaSource::Stream:
m_streamReader = new StreamReader(this);
// LibVLC refuses to emit seekability as it does a try-and-seek approach
// to work around this we exchange the player's seekability signal
// for the readers
// https://bugs.kde.org/show_bug.cgi?id=293012
connect(m_streamReader, SIGNAL(streamSeekableChanged(bool)), this, SIGNAL(seekableChanged(bool)));
disconnect(m_player, SIGNAL(seekableChanged(bool)), this, SIGNAL(seekableChanged(bool)));
// Only connect now to avoid seekability detection before we are connected.
m_streamReader->connectToSource(source);
loadMedia(QByteArray("imem://"));
break;
}
debug() << "Sending currentSourceChanged";
emit currentSourceChanged(m_mediaSource);
}
void MediaObject::setNextSource(const MediaSource &source)
{
DEBUG_BLOCK;
debug() << source.url();
m_nextSource = source;
// This function is not ever called by the consumer but only libphonon.
// Furthermore libphonon only calls this function in its aboutToFinish slot,
// iff sources are already in the queue. In case our aboutToFinish was too
// late we may already be stopped when the slot gets activated.
// Therefore we need to make sure that we move to the next source iff
// this function is called when we are in stoppedstate.
if (m_state == StoppedState)
moveToNext();
}
qint32 MediaObject::prefinishMark() const
{
return m_prefinishMark;
}
void MediaObject::setPrefinishMark(qint32 msecToEnd)
{
m_prefinishMark = msecToEnd;
if (currentTime() < totalTime() - m_prefinishMark) {
// Not about to finish
m_prefinishEmitted = false;
}
}
qint32 MediaObject::transitionTime() const
{
return m_transitionTime;
}
void MediaObject::setTransitionTime(qint32 time)
{
m_transitionTime = time;
}
void MediaObject::emitAboutToFinish()
{
if (!m_aboutToFinishEmitted) {
// Track is about to finish
m_aboutToFinishEmitted = true;
emit aboutToFinish();
}
}
// State changes are force queued by libphonon.
void MediaObject::changeState(Phonon::State newState)
{
DEBUG_BLOCK;
// State not changed
if (newState == m_state)
return;
debug() << m_state << "-->" << newState;
#ifdef __GNUC__
#warning do we actually need m_seekpoint? if a consumer seeks before playing state that is their problem?!
#endif
// Workaround that seeking needs to work before the file is being played...
// We store seeks and apply them when going to seek (or discard them on reset).
if (newState == PlayingState) {
if (m_seekpoint != 0) {
seek(m_seekpoint);
m_seekpoint = 0;
}
}
// State changed
Phonon::State previousState = m_state;
m_state = newState;
emit stateChanged(m_state, previousState);
}
void MediaObject::moveToNextSource()
{
DEBUG_BLOCK;
setSource(m_nextSource);
// The consumer may set an invalid source as final source to force a
// queued stop, regardless of how fast the consumer is at actually calling
// stop. Such a source must not cause an actual move (moving ~= state
// changes towards playing) but instead we only set the source to reflect
// that we got the setNextSource call.
if (hasNextTrack())
play();
m_nextSource = MediaSource(QUrl());
}
inline bool MediaObject::hasNextTrack()
{
return m_nextSource.type() != MediaSource::Invalid && m_nextSource.type() != MediaSource::Empty;
}
inline void MediaObject::unloadMedia()
{
if (m_media) {
m_media->disconnect(this);
m_media->deleteLater();
m_media = 0;
}
}
void MediaObject::setupMedia()
{
DEBUG_BLOCK;
unloadMedia();
resetMembers();
// Create a media with the given MRL
m_media = new Media(m_mrl, this);
if (!m_media)
error() << "libVLC:" << LibVLC::errorMessage();
if (m_isScreen) {
m_media->addOption(QLatin1String("screen-fps=24.0"));
m_media->addOption(QLatin1String("screen-caching=300"));
}
if (source().discType() == Cd && m_currentTitle > 0)
m_media->setCdTrack(m_currentTitle);
if (m_streamReader)
// StreamReader is no sink but a source, for this we have no concept right now
// also we do not need one since the reader is the only source we have.
// Consequently we need to manually tell the StreamReader to attach to the Media.
m_streamReader->addToMedia(m_media);
if (!m_subtitleAutodetect)
m_media->addOption(QLatin1String(":no-sub-autodetect-file"));
if (m_subtitleEncoding != QLatin1String("UTF-8")) // utf8 is phonon default, so let vlc handle it
m_media->addOption(QLatin1String(":subsdec-encoding="), m_subtitleEncoding);
if (!m_subtitleFontChanged) // Update font settings
m_subtitleFont = QFont();
#ifdef __GNUC__
#warning freetype module is not working as expected - font api not working
#endif
// BUG: VLC's freetype module doesn't pick up per-media options
// vlc -vvvv --freetype-font="Comic Sans MS" multiple_sub_sample.mkv :freetype-font=Arial
// https://trac.videolan.org/vlc/ticket/9797
m_media->addOption(QLatin1String(":freetype-font="), m_subtitleFont.family());
m_media->addOption(QLatin1String(":freetype-fontsize="), m_subtitleFont.pointSize());
if (m_subtitleFont.bold())
m_media->addOption(QLatin1String(":freetype-bold"));
else
m_media->addOption(QLatin1String(":no-freetype-bold"));
foreach (SinkNode *sink, m_sinks) {
sink->addToMedia(m_media);
}
// Connect to Media signals. Disconnection is done at unloading.
connect(m_media, SIGNAL(durationChanged(qint64)),
this, SLOT(updateDuration(qint64)));
connect(m_media, SIGNAL(metaDataChanged()),
this, SLOT(updateMetaData()));
// Update available audio channels/subtitles/angles/chapters/etc...
// i.e everything from MediaController
// There is no audio channel/subtitle/angle/chapter events inside libvlc
// so let's send our own events...
// This will reset the GUI
resetMediaController();
// Play
m_player->setMedia(m_media);
}
QString MediaObject::errorString() const
{
return libvlc_errmsg();
}
bool MediaObject::hasVideo() const
{
// Cached: sometimes 4.0.0-dev sends the vout event but then
// has_vout is still false. Guard against this by simply always reporting
// the last hasVideoChanged value. If that is off we can still drop into
// libvlc in case it changed meanwhile.
return m_hasVideo || m_player->hasVideoOutput();
}
bool MediaObject::isSeekable() const
{
if (m_streamReader)
return m_streamReader->streamSeekable();
return m_player->isSeekable();
}
void MediaObject::updateDuration(qint64 newDuration)
{
// This here cache is needed because we need to provide -1 as totalTime()
// for as long as we do not get a proper update through this slot.
// VLC reports -1 with no media but 0 if it does not know the duration, so
// apps that assume 0 = unknown get screwed if they query too early.
// http://bugs.tomahawk-player.org/browse/TWK-1029
m_totalTime = newDuration;
emit totalTimeChanged(m_totalTime);
}
void MediaObject::updateMetaData()
{
QMultiMap<QString, QString> metaDataMap;
const QString artist = m_media->meta(libvlc_meta_Artist);
const QString title = m_media->meta(libvlc_meta_Title);
const QString nowPlaying = m_media->meta(libvlc_meta_NowPlaying);
// Streams sometimes have the artist and title munged in nowplaying.
// With ALBUM = Title and TITLE = NowPlaying it will still show up nicely in Amarok.
if (artist.isEmpty() && !nowPlaying.isEmpty()) {
metaDataMap.insert(QLatin1String("ALBUM"), title);
metaDataMap.insert(QLatin1String("TITLE"), nowPlaying);
} else {
metaDataMap.insert(QLatin1String("ALBUM"), m_media->meta(libvlc_meta_Album));
metaDataMap.insert(QLatin1String("TITLE"), title);
}
metaDataMap.insert(QLatin1String("ARTIST"), artist);
metaDataMap.insert(QLatin1String("DATE"), m_media->meta(libvlc_meta_Date));
metaDataMap.insert(QLatin1String("GENRE"), m_media->meta(libvlc_meta_Genre));
metaDataMap.insert(QLatin1String("TRACKNUMBER"), m_media->meta(libvlc_meta_TrackNumber));
metaDataMap.insert(QLatin1String("DESCRIPTION"), m_media->meta(libvlc_meta_Description));
metaDataMap.insert(QLatin1String("COPYRIGHT"), m_media->meta(libvlc_meta_Copyright));
metaDataMap.insert(QLatin1String("URL"), m_media->meta(libvlc_meta_URL));
metaDataMap.insert(QLatin1String("ENCODEDBY"), m_media->meta(libvlc_meta_EncodedBy));
if (metaDataMap == m_vlcMetaData) {
// No need to issue any change, the data is the same
return;
}
m_vlcMetaData = metaDataMap;
emit metaDataChanged(metaDataMap);
}
void MediaObject::updateState(MediaPlayer::State state)
{
DEBUG_BLOCK;
debug() << state;
debug() << "attempted autoplay?" << m_attemptingAutoplay;
if (m_attemptingAutoplay) {
switch (state) {
case MediaPlayer::PlayingState:
case MediaPlayer::PausedState:
m_attemptingAutoplay = false;
break;
case MediaPlayer::ErrorState:
debug() << "autoplay failed, must be end of media.";
// The error should not be reflected to the consumer. So we swap it
// for finished() which is actually what is happening here.
// Or so we think ;)
state = MediaPlayer::EndedState;
--m_currentTitle;
break;
default:
debug() << "not handling as part of autplay:" << state;
break;
}
}
switch (state) {
case MediaPlayer::NoState:
changeState(LoadingState);
break;
case MediaPlayer::OpeningState:
changeState(LoadingState);
break;
case MediaPlayer::BufferingState:
changeState(BufferingState);
break;
case MediaPlayer::PlayingState:
changeState(PlayingState);
break;
case MediaPlayer::PausedState:
changeState(PausedState);
break;
case MediaPlayer::StoppedState:
changeState(StoppedState);
break;
case MediaPlayer::EndedState:
if (hasNextTrack()) {
moveToNextSource();
} else if (source().discType() == Cd && m_autoPlayTitles && !m_attemptingAutoplay) {
debug() << "trying to simulate autoplay";
m_attemptingAutoplay = true;
m_player->setCdTrack(++m_currentTitle);
} else {
m_attemptingAutoplay = false;
emitAboutToFinish();
emit finished();
changeState(StoppedState);
}
break;
case MediaPlayer::ErrorState:
debug() << errorString();
emitAboutToFinish();
emit finished();
changeState(ErrorState);
break;
}
if (m_buffering) {
switch (state) {
case MediaPlayer::BufferingState:
break;
case MediaPlayer::PlayingState:
debug() << "Restoring buffering state after state change to Playing";
changeState(BufferingState);
m_stateAfterBuffering = PlayingState;
break;
case MediaPlayer::PausedState:
debug() << "Restoring buffering state after state change to Paused";
changeState(BufferingState);
m_stateAfterBuffering = PausedState;
break;
default:
debug() << "Buffering aborted!";
m_buffering = false;
break;
}
}
return;
}
void MediaObject::onHasVideoChanged(bool hasVideo)
{
DEBUG_BLOCK;
if (m_hasVideo != hasVideo) {
m_hasVideo = hasVideo;
emit hasVideoChanged(m_hasVideo);
} else {
// We can simply return if we are have the appropriate caching already.
// Otherwise we'd do pointless rescans of mediacontroller stuff.
// MC and MO are force-reset on media changes anyway.
return;
}
refreshDescriptors();
}
void MediaObject::setBufferStatus(int percent)
{
// VLC does not have a buffering state (surprise!) but instead only sends the
// event (surprise!). Hence we need to simulate the state change.
// Problem with BufferingState is that it is actually concurrent to Playing or Paused
// meaning that while you are buffering you can also pause, thus triggering
// a state change to paused. To handle this we let updateState change the
// state accordingly (as we need to allow the UI to update itself, and
// immediately after that we change back to buffering again.
// This loop can only be interrupted by a state change to !Playing & !Paused
// or by reaching a 100 % buffer caching (i.e. full cache).
m_buffering = true;
if (m_state != BufferingState) {
m_stateAfterBuffering = m_state;
changeState(BufferingState);
}
emit bufferStatus(percent);
// Transit to actual state only after emission so the signal is still
// delivered while in BufferingState.
if (percent >= 100) { // http://trac.videolan.org/vlc/ticket/5277
m_buffering = false;
changeState(m_stateAfterBuffering);
}
}
void MediaObject::refreshDescriptors()
{
if (m_player->titleCount() > 0)
refreshTitles();
if (hasVideo()) {
refreshAudioChannels();
refreshSubtitles();
if (m_player->videoChapterCount() > 0)
refreshChapters(m_player->title());
}
}
qint64 MediaObject::totalTime() const
{
return m_totalTime;
}
void MediaObject::addSink(SinkNode *node)
{
Q_ASSERT(!m_sinks.contains(node));
m_sinks.append(node);
}
void MediaObject::removeSink(SinkNode *node)
{
Q_ASSERT(node);
m_sinks.removeAll(node);
}
} // namespace VLC
} // namespace Phonon

347
src/mediaobject.h Normal file
View File

@ -0,0 +1,347 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
Copyright (C) 2010-2011 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_MEDIAOBJECT_H
#define PHONON_VLC_MEDIAOBJECT_H
#include <QtCore/QObject>
#include <QtCore/QTimer>
#include <phonon/mediaobjectinterface.h>
#include <phonon/addoninterface.h>
#include "mediacontroller.h"
#include "mediaplayer.h"
namespace Phonon
{
namespace VLC
{
class Media;
class SinkNode;
class StreamReader;
/** \brief Implementation for the most important class in Phonon
*
* The MediaObject class is the workhorse for Phonon. It handles what is needed
* to play media. It has a media source object used to configure what media to
* play.
*
* It provides the essential methods setSource(), play(), seek() and additional
* methods to configure the next media source, the transition between sources,
* transition times, ticks, other.
*
* There are numerous signals that provide information about the state of the media
* and of the playing process. The aboutToFinish() and finished() signals are used
* to see when the current media is finished.
*
* This class does not contain methods directly involved with libVLC. This part is
* handled by the VLCMediaObject class. There are protected methods and slots
* inherited by that class, like playInternal(), seekInternal().
* These methods have no implementation here.
*
* For documentation regarding the methods implemented for MediaObjectInterface, see
* the Phonon documentation.
*
* \see Phonon::MediaObjectInterface
* \see VLCMediaObject
*/
class MediaObject : public QObject, public MediaObjectInterface, public MediaController
{
Q_OBJECT
Q_INTERFACES(Phonon::MediaObjectInterface Phonon::AddonInterface)
friend class SinkNode;
public:
/**
* Initializes the members, connects the private slots to their corresponding signals,
* sets the next media source to an empty media source.
*
* \param parent A parent for the QObject
*/
explicit MediaObject(QObject *parent);
~MediaObject();
/**
* Reset members (those that need resetting anyway).
* Should always be called before going to a new source.
*/
void resetMembers();
/**
* If the current state is paused, it resumes playing. Else, the playback
* is commenced.
*/
void play();
/// Pauses the playback for the media player.
void pause();
/// Sets the next media source to an empty one and stops playback.
void stop();
/// \returns \c true when there is a video available, \c false otherwise
bool hasVideo() const;
/// \returns \c true when the MediaObject is seekable, \c false otherwise
bool isSeekable() const;
/// \returns total time (length, duration) of the current MediaSource (-1 if unknown)
qint64 totalTime() const;
/// \returns An error message with the last libVLC error.
QString errorString() const;
/**
* Adds a sink for this media object. During playInternal(), all the sinks
* will have their addToMedia() called.
*
* \see playInternal()
* \see SinkNode::addToMedia()
*/
void addSink(SinkNode *node);
/// Removes a sink from this media object.
void removeSink(SinkNode *node);
/**
* Pushes a seek command to the SeekStack for this media object. The SeekStack then
* calls seekInternal() when it's popped.
*/
void seek(qint64 milliseconds);
/**
* \return The interval between successive tick() signals. If set to 0, the emission
* of these signals is disabled.
*/
qint32 tickInterval() const;
/**
* Sets the interval between successive tick() signals. If set to 0, it disables the
* emission of these signals.
*/
void setTickInterval(qint32 tickInterval);
/**
* \return The current time of the media, depending on the current state.
* If the current state is stopped or loading, 0 is returned.
* If the current state is error or unknown, -1 is returned.
*/
qint64 currentTime() const;
/// \return The current state for this media object.
Phonon::State state() const;
/// All errors are categorized as normal errors.
Phonon::ErrorType errorType() const;
/// \return The current media source for this media object.
MediaSource source() const;
/**
* Sets the current media source for this media object. Depending on the source type,
* the media object loads the specified media. The MRL is passed to loadMedia(), if the media
* is not a stream. The currentSourceChanged() signal
* is emitted.
*
* Supported media source types:
* \li local files
* \li URL
* \li discs (CD, DVD, VCD)
* \li capture devices (V4L)
* \li streams
*
* \param source The media source that will become the current source.
*
* \see loadMedia()
*/
void setSource(const MediaSource &source);
/// Sets the media source that will replace the current one, after the playback for it finishes.
void setNextSource(const MediaSource &source);
qint32 prefinishMark() const;
void setPrefinishMark(qint32 msecToEnd);
qint32 transitionTime() const;
void setTransitionTime(qint32);
void emitAboutToFinish();
signals:
// MediaController signals
void availableSubtitlesChanged();
void availableAudioChannelsChanged();
void availableChaptersChanged(int);
void availableTitlesChanged(int);
void chapterChanged(int chapterNumber);
void titleChanged(int titleNumber);
void durationChanged(qint64 newDuration);
/**
* New widget size computed by VLC.
*
* It should be applied to the widget that contains the VLC video.
*/
void videoWidgetSizeChanged(int i_width, int i_height);
void aboutToFinish();
void bufferStatus(int percentFilled);
void currentSourceChanged(const MediaSource &newSource);
void finished();
void hasVideoChanged(bool b_has_video);
void metaDataChanged(const QMultiMap<QString, QString> & metaData);
void prefinishMarkReached(qint32 msecToEnd);
void seekableChanged(bool seekable);
void stateChanged(Phonon::State newState, Phonon::State oldState);
void tick(qint64 time);
void totalTimeChanged(qint64 newTotalTime);
void moveToNext();
private slots:
/**
* If the new state is different from the current state, the current state is
* changed and the corresponding signal is emitted.
*/
void changeState(Phonon::State newState);
/**
* Checks when the tick(), prefinishMarkReached(), aboutToFinish() signals need to
* be emitted and emits them if necessary.
*
* \param currentTime The current play time for the media, in miliseconds.
*/
void timeChanged(qint64 time);
void emitTick(qint64 time);
/**
* If the next media source is valid, the current source is replaced and playback is commenced.
* The next source is set to an empty source.
*
* \see setNextSource()
*/
void moveToNextSource();
/*** Update media duration time - see comment in CPP */
void updateDuration(qint64 newDuration);
/** Retrieve meta data of a file (i.e ARTIST, TITLE, ALBUM, etc...). */
void updateMetaData();
void updateState(MediaPlayer::State state);
/** Called when the availability of video output changed */
void onHasVideoChanged(bool hasVideo);
void setBufferStatus(int percent);
/** Refreshes all MediaController descriptors if Video is present. */
void refreshDescriptors();
private:
/**
* This method actually calls the functions needed to begin playing the media.
* If another media is already playing, it is discarded. The new media filename is set
* with loadMediaInternal(). A new VLC Media is created and set into the VLC Media Player.
* All the connected sink nodes are connected to the new media. It connects the media object
* to the events for the VLC Media, updates the meta-data, sets up the video widget id, and
* starts playing.
*
* \see loadMediaInternal()
* \see connectToMediaVLCEvents()
* \see updateMetaData()
* \see setVLCWidgetId()
*/
void setupMedia();
/**
* Seeks to the required position. If the state is not playing, the seek position is remembered.
*/
void seekInternal(qint64 milliseconds);
bool hasNextTrack();
/**
* Changes the current state to buffering and sets the new current file.
*
* \param filename The MRL of the media source
*/
void loadMedia(const QByteArray &mrl);
/**
* Overload for loadMedia, converting a QString to a QByteArray.
*
* \param filename The MRL of the media source
*
* \see loadMedia
*/
void loadMedia(const QString &mrl);
/**
* Uninitializes the media
*/
void unloadMedia();
MediaSource m_nextSource;
MediaSource m_mediaSource;
StreamReader *m_streamReader;
Phonon::State m_state;
qint32 m_prefinishMark;
bool m_prefinishEmitted;
bool m_aboutToFinishEmitted;
qint32 m_tickInterval;
qint64 m_lastTick;
qint32 m_transitionTime;
Media *m_media;
qint64 m_totalTime;
QByteArray m_mrl;
QMultiMap<QString, QString> m_vlcMetaData;
QList<SinkNode *> m_sinks;
bool m_hasVideo;
bool m_isScreen;
/**
* Workaround for being able to seek before VLC goes to playing state.
* Seeks before playing are stored in this var, and processed on state change
* to Playing.
*/
qint64 m_seekpoint;
int m_timesVideoChecked;
bool m_buffering;
Phonon::State m_stateAfterBuffering;
};
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_MEDIAOBJECT_H

413
src/mediaplayer.cpp Normal file
View File

@ -0,0 +1,413 @@
/*
Copyright (C) 2011-2018 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mediaplayer.h"
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QMetaType>
#include <QtCore/QString>
#include <QtCore/QTemporaryFile>
#include <QtGui/QImage>
#include <vlc/libvlc_version.h>
#include "utils/libvlc.h"
#include "media.h"
// Callbacks come from a VLC thread. In some cases Qt fails to detect this and
// tries to invoke directly (i.e. from same thread). This can lead to thread
// pollution throughout Phonon, which is very much not desired.
#define P_EMIT_HAS_VIDEO(hasVideo) \
QMetaObject::invokeMethod(\
that, "hasVideoChanged", \
Qt::QueuedConnection, \
Q_ARG(bool, hasVideo))
#define P_EMIT_STATE(__state) \
QMetaObject::invokeMethod(\
that, "stateChanged", \
Qt::QueuedConnection, \
Q_ARG(MediaPlayer::State, __state))
namespace Phonon {
namespace VLC {
MediaPlayer::MediaPlayer(QObject *parent)
: QObject(parent)
, m_media(0)
, m_player(libvlc_media_player_new(pvlc_libvlc))
, m_doingPausedPlay(false)
, m_volume(75)
, m_fadeAmount(1.0f)
{
Q_ASSERT(m_player);
qRegisterMetaType<MediaPlayer::State>("MediaPlayer::State");
libvlc_event_manager_t *manager = libvlc_media_player_event_manager(m_player);
libvlc_event_type_t events[] = {
libvlc_MediaPlayerMediaChanged,
libvlc_MediaPlayerNothingSpecial,
libvlc_MediaPlayerOpening,
libvlc_MediaPlayerBuffering,
libvlc_MediaPlayerPlaying,
libvlc_MediaPlayerPaused,
libvlc_MediaPlayerStopped,
libvlc_MediaPlayerForward,
libvlc_MediaPlayerBackward,
libvlc_MediaPlayerEndReached,
libvlc_MediaPlayerEncounteredError,
libvlc_MediaPlayerTimeChanged,
libvlc_MediaPlayerPositionChanged,
libvlc_MediaPlayerSeekableChanged,
libvlc_MediaPlayerPausableChanged,
libvlc_MediaPlayerTitleChanged,
libvlc_MediaPlayerSnapshotTaken,
libvlc_MediaPlayerLengthChanged,
libvlc_MediaPlayerVout
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0))
, libvlc_MediaPlayerCorked,
libvlc_MediaPlayerUncorked,
libvlc_MediaPlayerMuted,
libvlc_MediaPlayerUnmuted,
libvlc_MediaPlayerAudioVolume
#endif
};
const int eventCount = sizeof(events) / sizeof(*events);
for (int i = 0; i < eventCount; ++i) {
libvlc_event_attach(manager, events[i], event_cb, this);
}
// Deactivate video title overlay (i.e. name of the video displaying
// at start. Since 2.1 that is handled via the API which in general is more
// reliable than setting it via libvlc_new (or so I have been told....)
libvlc_media_player_set_video_title_display(m_player, libvlc_position_disable, 0);
}
MediaPlayer::~MediaPlayer()
{
libvlc_media_player_release(m_player);
}
void MediaPlayer::setMedia(Media *media)
{
m_media = media;
libvlc_media_player_set_media(m_player, *m_media);
}
bool MediaPlayer::play()
{
m_doingPausedPlay = false;
return libvlc_media_player_play(m_player) == 0;
}
void MediaPlayer::pause()
{
m_doingPausedPlay = false;
libvlc_media_player_set_pause(m_player, 1);
}
void MediaPlayer::pausedPlay()
{
m_doingPausedPlay = true;
libvlc_media_player_play(m_player);
}
void MediaPlayer::resume()
{
m_doingPausedPlay = false;
libvlc_media_player_set_pause(m_player, 0);
}
void MediaPlayer::togglePause()
{
libvlc_media_player_pause(m_player);
}
void MediaPlayer::stop()
{
m_doingPausedPlay = false;
libvlc_media_player_stop(m_player);
}
qint64 MediaPlayer::length() const
{
return libvlc_media_player_get_length(m_player);
}
qint64 MediaPlayer::time() const
{
return libvlc_media_player_get_time(m_player);
}
void MediaPlayer::setTime(qint64 newTime)
{
libvlc_media_player_set_time(m_player, newTime);
}
bool MediaPlayer::isSeekable() const
{
return libvlc_media_player_is_seekable(m_player);
}
bool MediaPlayer::hasVideoOutput() const
{
return libvlc_media_player_has_vout(m_player) > 0;
}
bool MediaPlayer::setSubtitle(int subtitle)
{
return libvlc_video_set_spu(m_player, subtitle) == 0;
}
bool MediaPlayer::setSubtitle(const QString &file)
{
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0))
return libvlc_media_player_add_slave(m_player,
libvlc_media_slave_type_subtitle,
file.toUtf8().data(),
true) == 0;
#else
return libvlc_video_set_subtitle_file(m_player, file.toUtf8().data()) == 1;
#endif
}
void MediaPlayer::setTitle(int title)
{
libvlc_media_player_set_title(m_player, title);
}
void MediaPlayer::setChapter(int chapter)
{
libvlc_media_player_set_chapter(m_player, chapter);
}
QImage MediaPlayer::snapshot() const
{
QTemporaryFile tempFile(QDir::tempPath() % QDir::separator() % QLatin1Literal("phonon-vlc-snapshot"));
tempFile.open();
// This function is sync.
if (libvlc_video_take_snapshot(m_player, 0, tempFile.fileName().toLocal8Bit().data(), 0, 0) != 0)
return QImage();
return QImage(tempFile.fileName());
}
bool MediaPlayer::setAudioTrack(int track)
{
return libvlc_audio_set_track(m_player, track) == 0;
}
void MediaPlayer::event_cb(const libvlc_event_t *event, void *opaque)
{
MediaPlayer *that = reinterpret_cast<MediaPlayer *>(opaque);
Q_ASSERT(that);
// Do not forget to register for the events you want to handle here!
switch (event->type) {
case libvlc_MediaPlayerTimeChanged:
QMetaObject::invokeMethod(
that, "timeChanged",
Qt::QueuedConnection,
Q_ARG(qint64, event->u.media_player_time_changed.new_time));
break;
case libvlc_MediaPlayerSeekableChanged:
QMetaObject::invokeMethod(
that, "seekableChanged",
Qt::QueuedConnection,
Q_ARG(bool, event->u.media_player_seekable_changed.new_seekable));
break;
case libvlc_MediaPlayerLengthChanged:
QMetaObject::invokeMethod(
that, "lengthChanged",
Qt::QueuedConnection,
Q_ARG(qint64, event->u.media_player_length_changed.new_length));
break;
case libvlc_MediaPlayerNothingSpecial:
P_EMIT_STATE(NoState);
break;
case libvlc_MediaPlayerOpening:
P_EMIT_STATE(OpeningState);
break;
case libvlc_MediaPlayerBuffering:
QMetaObject::invokeMethod(
that, "bufferChanged",
Qt::QueuedConnection,
Q_ARG(int, event->u.media_player_buffering.new_cache));
break;
case libvlc_MediaPlayerPlaying:
// Intercept state change and apply pausing once playing.
if (that->m_doingPausedPlay) {
that->m_doingPausedPlay = false;
// VLC internally will call stop if a player can not be paused, this
// can lead to deadlocks as stop is partially blocking, to avoid this
// we explicitly do a queued stop whenever a player can not be paused.
// In those situations pausedplay capability can not be provided, so
// applications wanting to do pausedplay will need to handle it anyway
// as faking a paused state when there is none would be a very code
// intense workaround asking for weird abstraction leakage.
// See kde bug 337604.
if (libvlc_media_player_can_pause(that->m_player)) {
that->pause();
} else {
QMetaObject::invokeMethod(that, "stop", Qt::QueuedConnection);
}
} else
P_EMIT_STATE(PlayingState);
break;
case libvlc_MediaPlayerPaused:
P_EMIT_STATE(PausedState);
break;
case libvlc_MediaPlayerStopped:
P_EMIT_STATE(StoppedState);
break;
case libvlc_MediaPlayerEndReached:
P_EMIT_STATE(EndedState);
break;
case libvlc_MediaPlayerEncounteredError:
P_EMIT_STATE(ErrorState);
break;
case libvlc_MediaPlayerVout:
if (event->u.media_player_vout.new_count > 0) {
P_EMIT_HAS_VIDEO(true);
} else {
P_EMIT_HAS_VIDEO(false);
}
break;
case libvlc_MediaPlayerMediaChanged:
break;
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0))
case libvlc_MediaPlayerCorked:
that->pause();
break;
case libvlc_MediaPlayerUncorked:
that->play();
break;
case libvlc_MediaPlayerMuted:
QMetaObject::invokeMethod(
that, "mutedChanged",
Qt::QueuedConnection,
Q_ARG(bool, true));
break;
case libvlc_MediaPlayerUnmuted:
QMetaObject::invokeMethod(
that, "mutedChanged",
Qt::QueuedConnection,
Q_ARG(bool, false));
break;
case libvlc_MediaPlayerAudioVolume:
QMetaObject::invokeMethod(
that, "volumeChanged",
Qt::QueuedConnection,
Q_ARG(float, event->u.media_player_audio_volume.volume));
break;
#endif
case libvlc_MediaPlayerForward:
case libvlc_MediaPlayerBackward:
case libvlc_MediaPlayerPositionChanged:
case libvlc_MediaPlayerPausableChanged:
case libvlc_MediaPlayerTitleChanged:
case libvlc_MediaPlayerSnapshotTaken: // Snapshot call is sync, so this is useless.
default:
break;
QString msg = QString("Unknown event: ") + QString(libvlc_event_type_name(event->type));
Q_ASSERT_X(false, "event_cb", qPrintable(msg));
break;
}
}
QDebug operator<<(QDebug dbg, const MediaPlayer::State &s)
{
QString name;
switch (s) {
case MediaPlayer::NoState:
name = QLatin1String("MediaPlayer::NoState");
break;
case MediaPlayer::OpeningState:
name = QLatin1String("MediaPlayer::OpeningState");
break;
case MediaPlayer::BufferingState:
name = QLatin1String("MediaPlayer::BufferingState");
break;
case MediaPlayer::PlayingState:
name = QLatin1String("MediaPlayer::PlayingState");
break;
case MediaPlayer::PausedState:
name = QLatin1String("MediaPlayer::PausedState");
break;
case MediaPlayer::StoppedState:
name = QLatin1String("MediaPlayer::StoppedState");
break;
case MediaPlayer::EndedState:
name = QLatin1String("MediaPlayer::EndedState");
break;
case MediaPlayer::ErrorState:
name = QLatin1String("MediaPlayer::ErrorState");
break;
}
dbg.nospace() << "State(" << qPrintable(name) << ")";
return dbg.space();
}
void MediaPlayer::setAudioFade(qreal fade)
{
m_fadeAmount = fade;
setVolumeInternal();
}
void MediaPlayer::setAudioVolume(int volume)
{
m_volume = volume;
setVolumeInternal();
}
bool MediaPlayer::mute() const
{
return libvlc_audio_get_mute(m_player);
}
void MediaPlayer::setMute(bool mute)
{
libvlc_audio_set_mute(m_player, mute);
}
void MediaPlayer::setVolumeInternal()
{
libvlc_audio_set_volume(m_player, m_volume * m_fadeAmount);
}
void MediaPlayer::setCdTrack(int track)
{
if (!m_media)
return;
libvlc_media_player_stop(m_player);
m_media->setCdTrack(track);
libvlc_media_player_set_media(m_player, *m_media);
libvlc_media_player_play(m_player);
}
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 0, 0))
void MediaPlayer::setEqualizer(libvlc_equalizer_t *equalizer)
{
libvlc_media_player_set_equalizer(m_player, equalizer);
}
#endif
} // namespace VLC
} // namespace Phonon

277
src/mediaplayer.h Normal file
View File

@ -0,0 +1,277 @@
/*
Copyright (C) 2011-2018 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_MEDIAPLAYER_H
#define PHONON_VLC_MEDIAPLAYER_H
#include <QObject>
#include <QSharedPointer>
#include <QSize>
#include <vlc/libvlc_version.h>
#include <vlc/vlc.h>
class QImage;
class QString;
namespace Phonon {
namespace VLC {
class Media;
template<class VLCArray>
class Descriptions
{
public:
typedef void (*ReleaseFunction) (VLCArray**, unsigned int) ;
Descriptions(VLCArray **data,
unsigned int size,
ReleaseFunction release)
: m_release(release)
, m_data(data)
, m_size(size)
{
}
~Descriptions()
{
m_release(m_data, m_size);
}
unsigned int size() const { return m_size; }
private:
ReleaseFunction m_release;
VLCArray **m_data;
unsigned int m_size;
};
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0))
typedef Descriptions<libvlc_title_description_t> TitleDescriptions;
typedef QSharedPointer<const TitleDescriptions> SharedTitleDescriptions;
typedef Descriptions<libvlc_chapter_description_t> ChapterDescriptions;
typedef QSharedPointer<ChapterDescriptions> SharedChapterDescriptions;
#endif
class MediaPlayer : public QObject
{
Q_OBJECT
public:
enum State {
NoState = 0,
OpeningState,
BufferingState,
PlayingState,
PausedState,
StoppedState,
EndedState,
ErrorState
};
explicit MediaPlayer(QObject *parent = 0);
~MediaPlayer();
inline libvlc_media_player_t *libvlc_media_player() const { return m_player; }
inline operator libvlc_media_player_t *() const { return m_player; }
void setMedia(Media *media);
void setVideoCallbacks();
void setVideoFormatCallbacks();
void setNsObject(void *drawable) { libvlc_media_player_set_nsobject(m_player, drawable); }
void setXWindow(quint32 drawable) { libvlc_media_player_set_xwindow(m_player, drawable); }
void setHwnd(void *drawable) { libvlc_media_player_set_hwnd(m_player, drawable); }
// Playback
bool play();
void pause();
void pausedPlay();
void resume();
void togglePause();
Q_INVOKABLE void stop();
qint64 length() const;
qint64 time() const;
void setTime(qint64 newTime);
bool isSeekable() const;
// Video
QSize videoSize() const
{
unsigned int width;
unsigned int height;
libvlc_video_get_size(m_player, 0, &width, &height);
return QSize(width, height);
}
bool hasVideoOutput() const;
/// Set new video aspect ratio.
/// \param aspect new video aspect-ratio or empty to reset to default
void setVideoAspectRatio(const QByteArray &aspect)
{ libvlc_video_set_aspect_ratio(m_player, aspect.isEmpty() ? 0 : aspect.data()); }
void setVideoAdjust(libvlc_video_adjust_option_t adjust, int value)
{ libvlc_video_set_adjust_int(m_player, adjust, value); }
void setVideoAdjust(libvlc_video_adjust_option_t adjust, float value)
{ libvlc_video_set_adjust_float(m_player, adjust, value); }
int subtitle() const
{ return libvlc_video_get_spu(m_player); }
libvlc_track_description_t *videoSubtitleDescription() const
{ return libvlc_video_get_spu_description(m_player); }
bool setSubtitle(int subtitle);
bool setSubtitle(const QString &file);
int title() const
{ return libvlc_media_player_get_title(m_player); }
int titleCount() const
{ return libvlc_media_player_get_title_count(m_player); }
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0))
SharedTitleDescriptions titleDescription() const
{
libvlc_title_description_t **data;
unsigned int size =
libvlc_media_player_get_full_title_descriptions(m_player, &data);
return SharedTitleDescriptions(
new TitleDescriptions(
data, size,
&libvlc_title_descriptions_release)
);
}
#else // deprecated
libvlc_track_description_t *titleDescription() const
{ return libvlc_video_get_title_description(m_player); }
#endif
void setTitle(int title);
int videoChapterCount() const
{ return libvlc_media_player_get_chapter_count(m_player); }
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0))
SharedChapterDescriptions videoChapterDescription(int title) const
{
libvlc_chapter_description_t **data;
unsigned int size =
libvlc_media_player_get_full_chapter_descriptions(m_player, title, &data);
return SharedChapterDescriptions(
new ChapterDescriptions(
data, size,
&libvlc_chapter_descriptions_release)
);
}
#else // deprecated
libvlc_track_description_t *videoChapterDescription(int title) const
{ return libvlc_video_get_chapter_description(m_player, title); }
#endif
void setChapter(int chapter);
/** Reentrant, through libvlc */
QImage snapshot() const;
// Audio
/// Get current audio volume.
/// \return the software volume in percents (0 = mute, 100 = nominal / 0dB)
int audioVolume() const { return m_volume; }
/// Set new audio volume.
/// \param volume new volume
void setAudioVolume(int volume);
/// \return mutness
bool mute() const;
/**
* Mutes
* @param mute whether to mute or unmute
*/
void setMute(bool mute);
/// Set the fade percentage, between 0 (muted) and 1.0 (no fade)
void setAudioFade(qreal fade);
/// \param name name of the output to set
/// \returns \c true when setting was successful, \c false otherwise
bool setAudioOutput(const QByteArray &name)
{ return libvlc_audio_output_set(m_player, name.data()) == 0; }
/**
* Set audio output device by name.
* \param outputName the aout name (pulse, alsa, oss, etc.)
* \param deviceName the output name (aout dependent)
*/
void setAudioOutputDevice(const QByteArray &outputName, const QByteArray &deviceName)
{ libvlc_audio_output_device_set(m_player, outputName.data(), deviceName.data()); }
int audioTrack() const
{ return libvlc_audio_get_track(m_player); }
libvlc_track_description_t * audioTrackDescription() const
{ return libvlc_audio_get_track_description(m_player); }
bool setAudioTrack(int track);
void setCdTrack(int track);
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 0, 0))
void setEqualizer(libvlc_equalizer_t *equalizer);
#endif
signals:
void lengthChanged(qint64 length);
void seekableChanged(bool seekable);
void stateChanged(MediaPlayer::State state);
void timeChanged(qint64 time);
void bufferChanged(int percent);
/** Emitted when the vout availability has changed */
void hasVideoChanged(bool hasVideo);
void mutedChanged(bool mute);
void volumeChanged(float volume);
private:
static void event_cb(const libvlc_event_t *event, void *opaque);
void setVolumeInternal();
Media *m_media;
libvlc_media_player_t *m_player;
bool m_doingPausedPlay;
int m_volume;
qreal m_fadeAmount;
};
QDebug operator<<(QDebug dbg, const MediaPlayer::State &s);
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_MEDIAPLAYER_H

9
src/phonon-vlc.json.in Normal file
View File

@ -0,0 +1,9 @@
{
"Name": "Phonon VLC",
"Icon": "vlc",
"Version": "@PHONON_VLC_VERSION@",
"Website": "http://www.videolan.org",
"InterfaceVersion": 0,
"InitialPreference": 20
}

81
src/sinknode.cpp Normal file
View File

@ -0,0 +1,81 @@
/*
Copyright (C) 2013 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "sinknode.h"
#include "utils/debug.h"
#include "mediaobject.h"
#include "mediaplayer.h"
namespace Phonon {
namespace VLC {
SinkNode::SinkNode()
: m_mediaObject(0)
, m_player(0)
{
}
SinkNode::~SinkNode()
{
if (m_mediaObject) {
disconnectFromMediaObject(m_mediaObject);
}
}
void SinkNode::connectToMediaObject(MediaObject *mediaObject)
{
if (m_mediaObject) {
error() << Q_FUNC_INFO << "m_mediaObject already connected";
}
m_mediaObject = mediaObject;
m_player = mediaObject->m_player;
m_mediaObject->addSink(this);
// ---> Global handling goes here! Above the derivee handle! <--- //
handleConnectToMediaObject(mediaObject);
}
void SinkNode::disconnectFromMediaObject(MediaObject *mediaObject)
{
handleDisconnectFromMediaObject(mediaObject);
// ---> Global handling goes here! Below the derivee handle! <--- //
if (m_mediaObject != mediaObject) {
error() << Q_FUNC_INFO << "SinkNode was not connected to mediaObject";
}
if (m_mediaObject) {
m_mediaObject->removeSink(this);
}
m_mediaObject = 0;
m_player = 0;
}
void SinkNode::addToMedia(Media *media)
{
// ---> Global handling goes here! Above the derivee handle! <--- //
handleAddToMedia(media);
}
} // namespace VLC
} // namespace Phonon

102
src/sinknode.h Normal file
View File

@ -0,0 +1,102 @@
/*
Copyright (C) 2013 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_SINKNODE_H
#define PHONON_VLC_SINKNODE_H
#include <QPointer>
namespace Phonon {
namespace VLC {
class Media;
class MediaObject;
class MediaPlayer;
/** \brief The sink node is essentialy an output for a media object
*
* This class handles connections for the sink to a media object. It remembers
* the media object and the libVLC media player associated with it.
*
* \see MediaObject
*/
class SinkNode
{
public:
SinkNode();
virtual ~SinkNode();
/**
* Associates the sink node to the provided media object. The m_mediaObject and m_vlcPlayer
* attributes are set, and the sink is added to the media object's sinks.
*
* \param mediaObject The media object to connect to.
*
* \see disconnectFromMediaObject()
*/
void connectToMediaObject(MediaObject *mediaObject);
/**
* Removes this sink from the specified media object's sinks.
*
* \param mediaObject The media object to disconnect from
*
* \see connectToMediaObject()
*/
void disconnectFromMediaObject(MediaObject *mediaObject);
/**
* Does nothing. To be reimplemented in child classes.
*/
void addToMedia(Media *media);
protected:
/**
* Handling function for derived classes.
* \note This handle is executed *after* the global handle.
* Meaning the SinkNode base will be done handling the connect.
* \see connectToMediaObject
*/
virtual void handleConnectToMediaObject(MediaObject *mediaObject) { Q_UNUSED(mediaObject); }
/**
* Handling function for derived classes.
* \note This handle is executed *before* the global handle.
* Meaning the SinkNode base will continue handling the disconnect.
* \see disconnectFromMediaObject
*/
virtual void handleDisconnectFromMediaObject(MediaObject *mediaObject) { Q_UNUSED(mediaObject); }
/**
* Handling function for derived classes.
* \note This handle is executed *after* the global handle.
* Meaning the SinkNode base will be done handling the connect.
* \see addToMedia
*/
virtual void handleAddToMedia(Media *media) { Q_UNUSED(media); }
/** Available while connected to a MediaObject (until disconnected) */
QPointer<MediaObject> m_mediaObject;
/** Available while connected to a MediaObject (until disconnected) */
MediaPlayer *m_player;
};
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_SINKNODE_H

242
src/streamreader.cpp Normal file
View File

@ -0,0 +1,242 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "streamreader.h"
#include <QtCore/QMutexLocker>
#include <phonon/streaminterface.h>
#include "utils/debug.h"
#include "media.h"
#include "mediaobject.h"
#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
namespace Phonon {
namespace VLC {
#define BLOCKSIZE 32768
StreamReader::StreamReader(MediaObject *parent)
: QObject(parent)
, m_pos(0)
, m_size(0)
, m_eos(false)
, m_seekable(false)
, m_unlocked(false)
, m_mediaObject(parent)
{
}
StreamReader::~StreamReader()
{
}
void StreamReader::addToMedia(Media *media)
{
lock(); // Make sure we can lock in read().
media->addOption(QLatin1String("imem-cat=4"));
media->addOption(QLatin1String("imem-data="), INTPTR_PTR(this));
media->addOption(QLatin1String("imem-get="), INTPTR_FUNC(readCallback));
media->addOption(QLatin1String("imem-release="), INTPTR_FUNC(readDoneCallback));
media->addOption(QLatin1String("imem-seek="), INTPTR_FUNC(seekCallback));
// if stream has known size, we may pass it
// imem module will use it and pass it to demux
if (streamSize() > 0) {
media->addOption(QString("imem-size=%1").arg(streamSize()));
}
}
void StreamReader::lock()
{
QMutexLocker lock(&m_mutex);
DEBUG_BLOCK;
m_unlocked = false;
}
void StreamReader::unlock()
{
QMutexLocker lock(&m_mutex);
DEBUG_BLOCK;
m_unlocked = true;
m_waitingForData.wakeAll();
}
int StreamReader::readCallback(void *data, const char *cookie,
int64_t *dts, int64_t *pts, unsigned *flags, // krazy:exclude=typedefs
size_t *bufferSize, void **buffer)
{
Q_UNUSED(cookie);
Q_UNUSED(dts);
Q_UNUSED(pts);
Q_UNUSED(flags);
StreamReader *that = static_cast<StreamReader *>(data);
size_t length = BLOCKSIZE;
*buffer = new char[length];
int size = length;
bool ret = that->read(that->currentPos(), &size, static_cast<char*>(*buffer));
*bufferSize = static_cast<size_t>(size);
return ret ? 0 : -1;
}
int StreamReader::readDoneCallback(void *data, const char *cookie,
size_t bufferSize, void *buffer)
{
Q_UNUSED(data);
Q_UNUSED(cookie);
Q_UNUSED(bufferSize);
delete[] static_cast<char *>(buffer);
return 0;
}
int StreamReader::seekCallback(void *data, const uint64_t pos)
{
StreamReader *that = static_cast<StreamReader *>(data);
if (static_cast<int64_t>(pos) > that->streamSize()) { // krazy:exclude=typedefs
// attempt to seek past the end of our data.
return -1;
}
that->setCurrentPos(pos);
// this should return a true/false, but it doesn't, so assume success.
return 0;
}
quint64 StreamReader::currentBufferSize() const
{
return m_buffer.size();
}
bool StreamReader::read(quint64 pos, int *length, char *buffer)
{
QMutexLocker lock(&m_mutex);
DEBUG_BLOCK;
bool ret = true;
if (m_unlocked) {
return ret;
}
if (currentPos() != pos) {
if (!streamSeekable()) {
return false;
}
setCurrentPos(pos);
}
if (m_buffer.capacity() < *length) {
m_buffer.reserve(*length);
}
while (currentBufferSize() < static_cast<unsigned int>(*length)) {
quint64 oldSize = currentBufferSize();
needData();
m_waitingForData.wait(&m_mutex);
if (oldSize == currentBufferSize()) {
if (m_eos && m_buffer.isEmpty()) {
return false;
}
// We didn't get any more data
*length = static_cast<int>(oldSize);
// If we have some data to return, why tell to reader that we failed?
// Remember that length argument is more like maxSize not requiredSize
ret = true;
}
}
if (m_mediaObject->state() != Phonon::BufferingState &&
m_mediaObject->state() != Phonon::LoadingState) {
enoughData();
}
memcpy(buffer, m_buffer.data(), *length);
m_pos += *length;
// trim the buffer by the amount read
m_buffer = m_buffer.mid(*length);
return ret;
}
void StreamReader::endOfData()
{
m_eos = true;
m_waitingForData.wakeAll();
}
void StreamReader::writeData(const QByteArray &data)
{
QMutexLocker lock(&m_mutex);
DEBUG_BLOCK;
m_buffer.append(data);
m_waitingForData.wakeAll();
}
quint64 StreamReader::currentPos() const
{
return m_pos;
}
void StreamReader::setCurrentPos(qint64 pos)
{
QMutexLocker lock(&m_mutex);
m_pos = pos;
m_buffer.clear(); // Not optimal, but meh
// Do not touch m_size here, it reflects the size of the stream not the size of the buffer,
// and generally seeking does not change the size!
seekStream(pos);
}
void StreamReader::setStreamSize(qint64 newSize)
{
m_size = newSize;
}
qint64 StreamReader::streamSize() const
{
return m_size;
}
void StreamReader::setStreamSeekable(bool seekable)
{
m_seekable = seekable;
emit streamSeekableChanged(seekable);
}
bool StreamReader::streamSeekable() const
{
return m_seekable;
}
} // namespace VLC
} // namespace Phonon
#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM

121
src/streamreader.h Normal file
View File

@ -0,0 +1,121 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_STREAMREADER_H
#define PHONON_STREAMREADER_H
#include <phonon/mediasource.h>
#include <phonon/streaminterface.h>
#include <stdint.h>
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
namespace Phonon
{
class MediaSource;
namespace VLC
{
class Media;
class MediaObject;
/** \brief Class for supporting custom data streams to the backend
*
* This class receives data from a Phonon MediaSource that is a stream.
* When data is requested, it fetches it from the media source and passes it further.
* MediaObject uses this class to pass stream data to libVLC.
*
* It implements Phonon::StreamInterface, necessary for the connection with an
* Phonon::AbstractMediaStream owned by the Phonon::MediaSource. See the Phonon
* documentation for details.
*
* There are callbacks implemented in streamhooks.cpp, for libVLC.
*/
class StreamReader : public QObject, public Phonon::StreamInterface
{
Q_OBJECT
Q_INTERFACES(Phonon::StreamInterface)
public:
explicit StreamReader(MediaObject *parent);
~StreamReader();
void addToMedia(Media *media);
void lock();
void unlock();
static int readCallback(void *data, const char *cookie,
int64_t *dts, int64_t *pts, unsigned *flags, // krazy:exclude=typedefs
size_t *bufferSize, void **buffer);
static int readDoneCallback(void *data, const char *cookie,
size_t bufferSize, void *buffer);
static int seekCallback(void *data, const uint64_t pos);
quint64 currentBufferSize() const;
void writeData(const QByteArray &data);
quint64 currentPos() const;
void setCurrentPos(qint64 pos);
/**
* Requests data from this stream. The stream requests data from the
* Phonon::MediaSource's abstract media stream with the needData() signal.
* If the requested data is available, it is copied into the buffer.
*
* \param pos Position in the stream
* \param length Length of the data requested
* \param buffer A buffer to put the data
*/
bool read(quint64 offset, int *length, char *buffer);
void endOfData();
void setStreamSize(qint64 newSize);
qint64 streamSize() const;
void setStreamSeekable(bool seekable);
bool streamSeekable() const;
signals:
void streamSeekableChanged(bool seekable);
protected:
QByteArray m_buffer;
quint64 m_pos;
quint64 m_size;
bool m_eos;
bool m_seekable;
bool m_unlocked;
QMutex m_mutex;
QWaitCondition m_waitingForData;
MediaObject *m_mediaObject;
};
}
}
#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
#endif // PHONON_STREAMREADER_H

232
src/utils/debug.cpp Normal file
View File

@ -0,0 +1,232 @@
/*
Copyright (c) 2003-2005 Max Howell <max.howell@methylblue.com>
Copyright (c) 2007-2009 Mark Kretschmann <kretschmann@kde.org>
Copyright (c) 2010 Kevin Funk <krf@electrostorm.net>
Copyright (c) 2011 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "debug.h"
#include "debug_p.h"
#include <QtCore/QMutex>
#include <QtCore/QObject>
#include <QApplication>
#ifdef Q_OS_UNIX
# include <unistd.h>
#endif
// Define Application wide prefix
#ifndef APP_PREFIX
#define APP_PREFIX QLatin1String( "PHONON-VLC" )
#endif
#define DEBUG_INDENT_OBJECTNAME QLatin1String("Debug_Indent_object")
QMutex Debug::mutex( QMutex::Recursive );
using namespace Debug;
static bool s_debugColorsEnabled = true;
static DebugLevel s_debugLevel = DEBUG_NONE;
IndentPrivate::IndentPrivate(QObject* parent)
: QObject(parent)
{
setObjectName( DEBUG_INDENT_OBJECTNAME );
}
/**
* We can't use a statically instantiated QString for the indent, because
* static namespaces are unique to each dlopened library. So we piggy back
* the QString on the KApplication instance
*/
IndentPrivate* IndentPrivate::instance()
{
QObject* qOApp = reinterpret_cast<QObject*>(qApp);
QObject* obj = qOApp ? qOApp->findChild<QObject*>( DEBUG_INDENT_OBJECTNAME ) : 0;
return (obj ? static_cast<IndentPrivate*>( obj ) : new IndentPrivate( qApp ));
}
/*
Text color codes (use last digit here)
30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
*/
static int s_colors[] = { 1, 2, 4, 5, 6 }; // no yellow and white for sanity
static int s_colorIndex = 0;
static QString toString( DebugLevel level )
{
switch( level )
{
case DEBUG_WARN:
return "[WARNING]";
case DEBUG_ERROR:
return "[ERROR__]";
case DEBUG_FATAL:
return "[FATAL__]";
default:
return QString();
}
}
static int toColor( DebugLevel level )
{
switch( level ) {
case DEBUG_WARN:
return 3; // red
case DEBUG_ERROR:
case DEBUG_FATAL:
return 1; // yellow
default:
return 0; // default: black
}
}
static QString colorize( const QString &text, int color = s_colorIndex )
{
if( !debugColorEnabled() )
return text;
return QString( "\x1b[00;3%1m%2\x1b[00;39m" ).arg( QString::number(s_colors[color]), text );
}
static QString reverseColorize( const QString &text, int color )
{
if( !debugColorEnabled() )
return text;
return QString( "\x1b[07;3%1m%2\x1b[00;39m" ).arg( QString::number(color), text );
}
QString Debug::indent()
{
return IndentPrivate::instance()->m_string;
}
bool Debug::debugEnabled()
{
return s_debugLevel < DEBUG_NONE;
}
bool Debug::debugColorEnabled()
{
return s_debugColorsEnabled;
}
DebugLevel Debug::minimumDebugLevel()
{
return s_debugLevel;
}
void Debug::setColoredDebug( bool enable )
{
s_debugColorsEnabled = enable;
}
void Debug::setMinimumDebugLevel(DebugLevel level)
{
s_debugLevel = level;
}
QDebug Debug::dbgstream( DebugLevel level )
{
if ( level < s_debugLevel )
return nullDebug();
mutex.lock();
const QString currentIndent = indent();
mutex.unlock();
QString text = QString("%1%2").arg( APP_PREFIX ).arg( currentIndent );
if ( level > DEBUG_INFO )
text.append( ' ' + reverseColorize( toString(level), toColor( level ) ) );
return QDebug( QtDebugMsg ) << qPrintable( text );
}
void Debug::perfLog( const QString &message, const QString &func )
{
#ifdef Q_OS_UNIX
if( !debugEnabled() )
return;
QString str = QString( "MARK: %1: %2 %3" ).arg( qApp->applicationName(), func, message );
access( str.toLocal8Bit().data(), F_OK );
#endif
}
Block::Block( const char *label )
: m_label( label )
, m_color( s_colorIndex )
{
if( !debugEnabled() || DEBUG_INFO < s_debugLevel)
return;
#if QT_VERSION >= 0x040700
m_startTime.start();
#else
m_startTime = QTime::currentTime();
#endif
mutex.lock();
s_colorIndex = (s_colorIndex + 1) % 5;
dbgstream()
<< qPrintable( colorize( QLatin1String( "BEGIN:" ), m_color ) )
<< m_label;
IndentPrivate::instance()->m_string += QLatin1String(" ");
mutex.unlock();
}
Block::~Block()
{
if( !debugEnabled() || DEBUG_INFO < s_debugLevel)
return;
#if QT_VERSION >= 0x040700
const double duration = m_startTime.elapsed() / 1000.0;
#else
const double duration = (double)m_startTime.msecsTo( QTime::currentTime() ) / 1000.0;
#endif
mutex.lock();
IndentPrivate::instance()->m_string.truncate( Debug::indent().length() - 2 );
mutex.unlock();
// Print timing information, and a special message (DELAY) if the method took longer than 5s
if( duration < 5.0 )
{
dbgstream()
<< qPrintable( colorize( QLatin1String( "END__:" ), m_color ) )
<< m_label
<< qPrintable( colorize( QString( "[Took: %3s]")
.arg( QString::number(duration, 'g', 2) ), m_color ) );
}
else
{
dbgstream()
<< qPrintable( colorize( QString( "END__:" ), m_color ) )
<< m_label
<< qPrintable( reverseColorize( QString( "[DELAY Took (quite long) %3s]")
.arg( QString::number(duration, 'g', 2) ), toColor( DEBUG_WARN ) ) );
}
}
void Debug::stamp()
{
static int n = 0;
debug() << "| Stamp: " << ++n << endl;
}

200
src/utils/debug.h Normal file
View File

@ -0,0 +1,200 @@
/*
Copyright (c) 2003-2005 Max Howell <max.howell@methylblue.com>
Copyright (c) 2007-2009 Mark Kretschmann <kretschmann@kde.org>
Copyright (c) 2010 Kevin Funk <krf@electrostorm.net>
Copyright (c) 2011 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_DEBUG_H
#define PHONON_DEBUG_H
// We always want debug output available at runtime
#undef QT_NO_DEBUG_OUTPUT
#undef KDE_NO_DEBUG_OUTPUT
#include <QtCore/QDebug>
#include <QtCore/QMutex>
#if QT_VERSION >= 0x040700
# include <QtCore/QElapsedTimer>
#else
# include <QtCore/QTime>
#endif
// Platform specific macros
#ifdef _WIN32 // krazy:exclude=cpp we really want to check a compiler feature here :P
#define __PRETTY_FUNCTION__ __FUNCTION__
#endif
#ifdef __SUNPRO_CC
#define __PRETTY_FUNCTION__ __FILE__
#endif
/**
* @namespace Debug
* @short kdebug with indentation functionality and convenience macros
* @author Max Howell <max.howell@methylblue.com>
*
* Usage:
*
* #define DEBUG_PREFIX "Blah"
* #include "debug.h"
*
* void function()
* {
* Debug::Block myBlock( __PRETTY_FUNCTION__ );
*
* debug() << "output1" << endl;
* debug() << "output2" << endl;
* }
*
* Will output:
*
* app: BEGIN: void function()
* app: [Blah] output1
* app: [Blah] output2
* app: END: void function(): Took 0.1s
*
* @see Block
* @see CrashHelper
* @see ListStream
*/
namespace Debug
{
extern QMutex mutex;
enum DebugLevel {
DEBUG_INFO = 0,
DEBUG_WARN = 1,
DEBUG_ERROR = 2,
DEBUG_FATAL = 3,
DEBUG_NONE = 4
};
QDebug dbgstream( DebugLevel level = DEBUG_INFO );
bool debugEnabled();
bool debugColorEnabled();
DebugLevel minimumDebugLevel();
void setColoredDebug( bool enable );
void setMinimumDebugLevel( DebugLevel level );
QString indent();
static inline QDebug dbgstreamwrapper( DebugLevel level ) { return dbgstream( level ); }
static inline QDebug debug() { return dbgstreamwrapper( DEBUG_INFO ); }
static inline QDebug warning() { return dbgstreamwrapper( DEBUG_WARN ); }
static inline QDebug error() { return dbgstreamwrapper( DEBUG_ERROR ); }
static inline QDebug fatal() { return dbgstreamwrapper( DEBUG_FATAL ); }
void perfLog( const QString &message, const QString &func );
}
using Debug::debug;
using Debug::warning;
using Debug::error;
using Debug::fatal;
/// Standard function announcer
#define DEBUG_FUNC_INFO { Debug::mutex.lock(); qDebug() << Debug::indent() ; Debug::mutex.unlock(); }
/// Announce a line
#define DEBUG_LINE_INFO { Debug::mutex.lock(); qDebug() << Debug::indent() << "Line: " << __LINE__; Debug::mutex.unlock(); }
/// Convenience macro for making a standard Debug::Block
#define DEBUG_BLOCK Debug::Block uniquelyNamedStackAllocatedStandardBlock( __PRETTY_FUNCTION__ );
/// Performance logging
#define PERF_LOG( msg ) { Debug::perfLog( msg, __PRETTY_FUNCTION__ ); }
class BlockPrivate;
namespace Debug
{
/**
* @class Debug::Block
* @short Use this to label sections of your code
*
* Usage:
*
* void function()
* {
* Debug::Block myBlock( "section" );
*
* debug() << "output1" << endl;
* debug() << "output2" << endl;
* }
*
* Will output:
*
* app: BEGIN: section
* app: [prefix] output1
* app: [prefix] output2
* app: END: section - Took 0.1s
*
*/
class Block
{
public:
explicit Block( const char *name );
~Block();
private:
#if QT_VERSION >= 0x040700
QElapsedTimer m_startTime;
#else
QTime m_startTime;
#endif
const char *m_label;
int m_color;
};
/**
* @name Debug::stamp()
* @short To facilitate crash/freeze bugs, by making it easy to mark code that has been processed
*
* Usage:
*
* {
* Debug::stamp();
* function1();
* Debug::stamp();
* function2();
* Debug::stamp();
* }
*
* Will output (assuming the crash occurs in function2()
*
* app: Stamp: 1
* app: Stamp: 2
*
*/
void stamp();
}
#include <QtCore/QVariant>
namespace Debug
{
/**
* @class Debug::List
* @short You can pass anything to this and it will output it as a list
*
* debug() << (Debug::List() << anInt << aString << aQStringList << aDouble) << endl;
*/
typedef QList<QVariant> List;
}
#endif

57
src/utils/debug_p.h Normal file
View File

@ -0,0 +1,57 @@
/*
Copyright (c) 2010 Kevin Funk <krf@electrostorm.net>
Copyright (c) 2011 Casian Andrei <skeletk13@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEBUGPRIVATE_H
#define DEBUGPRIVATE_H
#include "debug.h"
#include <QtCore/QString>
class IndentPrivate
: public QObject
{
private:
explicit IndentPrivate(QObject* parent = 0);
public:
static IndentPrivate* instance();
QString m_string;
};
/*
* From kdelibs/kdecore/io
*/
class NoDebugStream: public QIODevice
{
// Q_OBJECT
public:
NoDebugStream() { open(WriteOnly); }
bool isSequential() const { return true; }
qint64 readData(char *, qint64) { return 0; /* eof */ }
qint64 readLineData(char *, qint64) { return 0; /* eof */ }
qint64 writeData(const char *, qint64 len) { return len; }
} devnull;
QDebug nullDebug()
{
return QDebug(&devnull);
}
#endif // DEBUGPRIVATE_H

128
src/utils/libvlc.cpp Normal file
View File

@ -0,0 +1,128 @@
/*
Copyright (C) 2011-2012 vlc-phonon AUTHORS <kde-multimedia@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "libvlc.h"
#include <QtCore/QByteArray>
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QSettings>
#include <QtCore/QString>
#include <QtCore/QStringBuilder>
#include <QtCore/QVarLengthArray>
#include <phonon/pulsesupport.h>
#include <vlc/libvlc.h>
#include <vlc/libvlc_version.h>
#include "debug.h"
LibVLC *LibVLC::self;
LibVLC::LibVLC()
: m_vlcInstance(0)
{
}
LibVLC::~LibVLC()
{
if (m_vlcInstance)
libvlc_release(m_vlcInstance);
self = 0;
}
bool LibVLC::init()
{
Q_ASSERT_X(!self, "LibVLC", "there should be only one LibVLC object");
LibVLC::self = new LibVLC;
QList<QByteArray> args;
// Ends up as something like $HOME/.config/Phonon/vlc.conf
const QString configFileName = QSettings("Phonon", "vlc").fileName();
if (QFile::exists(configFileName)) {
args << QByteArray("--config=").append(QFile::encodeName(configFileName));
args << "--no-ignore-config";
}
int debugLevel = qgetenv("PHONON_SUBSYSTEM_DEBUG").toInt();
if (debugLevel > 0) {
args << QByteArray("--verbose=").append(QByteArray::number(debugLevel));
args << QByteArray("--extraintf=logger");
#ifdef Q_WS_WIN
QDir logFilePath(QString(qgetenv("APPDATA")).append("/vlc"));
#else
QDir logFilePath(QDir::homePath().append("/.vlc"));
#endif //Q_WS_WIN
logFilePath.mkdir("log");
const QString logFile = logFilePath.path()
.append("/log/vlc-log-")
.append(QString::number(qApp->applicationPid()))
.append(".txt");
args << QByteArray("--logfile=").append(QFile::encodeName(QDir::toNativeSeparators(logFile)));
}
args << "--no-media-library";
args << "--no-osd";
args << "--no-stats";
// By default VLC will put a picture-in-picture when making a snapshot.
// This is unexpected behaviour for us, so we force it off.
args << "--no-snapshot-preview";
// Do not load xlib dependent modules as we cannot ensure proper init
// order as expected by xlib thus leading to crashes.
// KDE BUG: 240001
args << "--no-xlib";
// Do not preload services discovery modules, we don't use them.
args << "--services-discovery=''";
// The application is meant to manage this. Also, using the builtin
// inhibitor may cause problems on shutdown if VLC tries to uninhibit too
// late in the application lifecycle.
args << "--no-disable-screensaver";
// Allow multiple starts (one gets to wonder whether that makes a difference).
#if !defined(Q_OS_MAC) && (defined(Q_OS_WIN) || !defined(PHONON_NO_DBUS))
args << "--no-one-instance";
#endif
args << "--no-audio";
args << "--no-video";
// 6 seconds disk read buffer (up from vlc 2.1 default of 300ms) when using alsa, prevents most buffer underruns
// when the disk is very busy. We expect the pulse buffer after decoding to solve the same problem.
Phonon::PulseSupport *pulse = Phonon::PulseSupport::getInstance();
if (!pulse || !pulse->isActive()) {
args << "--file-caching=6000";
}
// Build const char* array
QVarLengthArray<const char *, 64> vlcArgs(args.size());
for (int i = 0; i < args.size(); ++i) {
vlcArgs[i] = args.at(i).constData();
}
// Create and initialize a libvlc instance (it should be done only once)
self->m_vlcInstance = libvlc_new(vlcArgs.size(), vlcArgs.constData());
if (!self->m_vlcInstance) {
fatal() << "libVLC: could not initialize";
return false;
}
return true;
}
const char *LibVLC::errorMessage()
{
return libvlc_errmsg();
}

140
src/utils/libvlc.h Normal file
View File

@ -0,0 +1,140 @@
/*
Copyright (C) 2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBVLC_H
#define LIBVLC_H
#include <QtCore/QtGlobal>
#include <QtCore/QStringList>
#include <vlc/libvlc_version.h>
struct libvlc_instance_t;
/**
* Convenience macro accessing the vlc_instance_t via LibVLC::self.
* Please note that init() must have been called whenever using this, as no
* checking of self is conducted (i.e. can be null).
*/
#define pvlc_libvlc LibVLC::self->vlc()
/**
* Foreach loop macro for VLC descriptions.
*
* For this macro to work the type name must be of the form:
* \verbatim libvlc_FOO_t \endverbatim
* *
* \param type the type identifier of VLC (without libvlc and _t)
* \param variable the variable name you want to use
* \param getter the getter from which to get the iterator
* \param releaser, function name to release the list
*/
#define VLC_FOREACH(type, variable, getter, releaser) \
for (libvlc_##type##_t *__libvlc_first_element = getter, *variable = __libvlc_first_element; \
variable; \
variable = variable->p_next, !variable ? releaser(__libvlc_first_element) : (void)0)
// This foreach expects only a type and variable because getter and releaser are generic.
// Also the type is in short form i.e. libvlc_foo_t would be foo.
#define VLC_FOREACH_LIST(type, variable) VLC_FOREACH(type, variable, libvlc_##type##_list_get(pvlc_libvlc), libvlc_##type##_list_release)
// These foreach expect no type because the type is generic, they do however
// expect a getter to allow usage with our wrapper classes and since the getter
// will most likely not be generic.
// For instance libvlc_audio_get_track_description returns a generic
// libvlc_track_description_t pointer. So the specific audio_track function
// relates to the generic track description type.
#define VLC_FOREACH_TRACK(variable, getter) VLC_FOREACH(track_description, variable, getter, libvlc_track_description_list_release)
#define VLC_FOREACH_MODULE(variable, getter) VLC_FOREACH(module_description, variable, getter, libvlc_module_description_list_release)
/**
* \brief Singleton class containing a libvlc instance.
*
* This class is a convenience class implementing the singleton pattern to hold
* an instance of libvlc. This instance is necessary to call various libvlc
* functions (such as creating a new mediaplayer instance).
*
* To initialize the object call init(), this will create the actualy LibVLC
* instance and then try to initialize the libvlc instance itself.
* init() returns false in case the libvlc instance could not be created.
*
* For convenience reasons there is also a libvlc macro which gets the LibVLC
* instance and then the libvlc_instance_t form that. Note that this macro
* does not check whether LibVLC actually got initialized, so it should only
* be used when you can be absolutely sure that init() was already called
*
* \code
* LibVLC::init(0); // init LibVLC
* if (!LibVLC::self) {
* exit(1); // error if self is null
* }
* libvlc_media_player_new(libvlc); // use libvlc macro
* \endcode
*
* \author Harald Sitter <sitter@kde->org>
*/
class LibVLC
{
public:
/**
* The singleton itself. Beware that this returns 0 unless init was called.
*
* \returns LibVLC instance or 0 if there is none.
*
* \see init
*/
static LibVLC *self;
/**
* \returns the contained libvlc instance.
*/
libvlc_instance_t *vlc()
{
return m_vlcInstance;
}
/**
* Construct singleton and initialize and launch the VLC library.
*
* \return VLC initialization result
*/
static bool init();
/**
* \returns the most recent error message of libvlc
*/
static const char *errorMessage();
/**
* Destruct the LibVLC singleton and release the contained libvlc instance.
*/
~LibVLC();
private:
Q_DISABLE_COPY(LibVLC)
/**
* Private default constructor, to create LibVLC call init instead.
*
* \see init
*/
LibVLC();
libvlc_instance_t *m_vlcInstance;
};
#endif // LIBVLC_H

41
src/utils/mime.h.cmake Normal file
View File

@ -0,0 +1,41 @@
/*
Copyright (C) 2012 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_MIME_H
#define PHONON_VLC_MIME_H
#include <QtCore/QStringList>
namespace Phonon {
namespace VLC {
static QStringList mimeTypeList()
{
// In CMake we null-terminate this list for ease of iteration.
const char *c_strings[] = @PHONON_VLC_MIME_TYPES_C_ARRAY@;
QStringList list;
int i = 0;
while (c_strings[i])
list.append(QLatin1String(c_strings[i++]));
return list;
}
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_MIME_H

59
src/utils/vstring.h Normal file
View File

@ -0,0 +1,59 @@
/*
Copyright (C) 2012 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_VSTRING_H
#define PHONON_VLC_VSTRING_H
#include <QtCore/QString>
#include <vlc/libvlc.h>
#include <vlc/libvlc_version.h>
/**
* @brief The VString class wraps around a char* returned from libvlc functions.
* Directly from libvlc functions returned cstrings are unique in two ways.
* For one they are to be freed by the caller, and for another they are always
* UTF8 (as VLC internally only uses UTF8).
*
* Particularly the first point is where VString comes in, it will on destruction
* call libvlc_free to free the string, thus avoiding memleaks.
* Additionally it conveniently converts to QString using either toQString
* or implicit cast to QString which makes it completely transparent to other
* functions. It also prevents you from carrying the cstring out of scope and
* render implicit copies of it invalid once free is called somewhere.
* Both functions use QString::fromUtf8 and are therefore the best way to
* process the string.
*/
class VString
{
public:
explicit VString(char *vlcString) : m_vlcString(vlcString) {}
~VString()
{
libvlc_free(m_vlcString);
}
// VLC internally only uses UTF8!
QString toQString() { return QString::fromUtf8(m_vlcString); }
operator QString() { return toQString(); }
private:
VString() {}
char *m_vlcString;
};
#endif // PHONON_VLC_VSTRING_H

View File

@ -0,0 +1,29 @@
/*
Copyright (C) 2010 Benoit Calvez <benoit@litchis.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NSVIDEOVIEW_H
#define NSVIDEOVIEW_H
#import <Cocoa/Cocoa.h>
@interface VideoView : NSView
- (void)addVoutSubview: (NSView *)view;
- (void)removeVoutSubview: (NSView *)view;
- (BOOL)stretchesVideo;
@end
#endif // NSVIDEOVIEW_H

View File

@ -0,0 +1,37 @@
/*
Copyright (C) 2010 Benoit Calvez <benoit@litchis.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nsvideoview.h"
@implementation VideoView
- (void)addVoutSubview:(NSView *)view
{
[view setFrame:[self bounds]];
[self addSubview:view];
[view setAutoresizingMask: NSViewHeightSizable |NSViewWidthSizable];
}
- (void)removeVoutSubview:(NSView *)view
{
[view removeFromSuperview];
}
- (BOOL)stretchesVideo
{
//Whatever you would want
return NO;
}
@end

View File

@ -0,0 +1,32 @@
/*
Copyright (C) 2010 Benoit Calvez <benoit@litchis.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef VLCMACWIDGET_H
#define VLCMACWIDGET_H
#include <QMacCocoaViewContainer>
#import <qmaccocoaviewcontainer_mac.h>
class VlcMacWidget : public QMacCocoaViewContainer
{
public:
explicit VlcMacWidget(QWidget *parent = 0);
};
#endif // VLCMACWIDGET_H

View File

@ -0,0 +1,39 @@
/*
Copyright (C) 2010 Benoit Calvez <benoit@litchis.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "vlcmacwidget.h"
#import <Cocoa/Cocoa.h>
#import "nsvideoview.h"
#include <QtCore/QtDebug>
VlcMacWidget::VlcMacWidget(QWidget *parent) : QMacCocoaViewContainer(0, parent)
{
// Many Cocoa objects create temporary autorelease objects,
// so create a pool to catch them.
@autoreleasepool {
VideoView *videoView = [[VideoView alloc] init];
this->setCocoaView(videoView);
// Release our reference, since our super class takes ownership and we
// don't need it anymore (except with Qt 5.8.0 because of a regression).
if (strcmp(qVersion(), "5.8.0")) {
[videoView release];
}
}
}

View File

@ -0,0 +1,200 @@
/*
Copyright (C) 2010-2012 Harald Sitter <apachelogger@ubuntu.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), Nokia Corporation
(or its successors, if any) and the KDE Free Qt Foundation, which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "videodataoutput.h"
#include <phonon/medianode.h>
#include <phonon/audiooutput.h>
#include <phonon/experimental/abstractvideodataoutput.h>
#include <QMetaObject>
#include "utils/debug.h"
#include "media.h"
#include "mediaobject.h"
using namespace Phonon::Experimental;
namespace Phonon
{
namespace VLC
{
VideoDataOutput::VideoDataOutput(QObject *parent)
: QObject(parent)
, m_frontend(0)
{
}
VideoDataOutput::~VideoDataOutput()
{
}
void VideoDataOutput::handleConnectToMediaObject(MediaObject *mediaObject)
{
Q_UNUSED(mediaObject);
setCallbacks(m_player);
}
void VideoDataOutput::handleDisconnectFromMediaObject(MediaObject *mediaObject)
{
Q_UNUSED(mediaObject);
unsetCallbacks(m_player);
}
void VideoDataOutput::handleAddToMedia(Media *media)
{
media->addOption(":video");
}
Experimental::AbstractVideoDataOutput *VideoDataOutput::frontendObject() const
{
return m_frontend;
}
void VideoDataOutput::setFrontendObject(Experimental::AbstractVideoDataOutput *frontend)
{
m_frontend = frontend;
}
void *VideoDataOutput::lockCallback(void **planes)
{
m_mutex.lock();
DEBUG_BLOCK;
planes[0] = reinterpret_cast<void *>(m_frame.data0.data());
planes[1] = reinterpret_cast<void *>(m_frame.data1.data());
planes[2] = reinterpret_cast<void *>(m_frame.data2.data());
return 0;
}
void VideoDataOutput::unlockCallback(void *picture, void *const*planes)
{
Q_UNUSED(picture);
Q_UNUSED(planes);
DEBUG_BLOCK;
// For some reason VLC yields BGR24, so we swap it to RGB
if (m_frame.format == Experimental::VideoFrame2::Format_RGB888) {
uchar *data = (uchar *) m_frame.data0.data();
uchar tmp;
for (int i = 0; i < m_frame.data0.size(); i += 3) {
tmp = data[i];
data[i] = data[i+2];
data[i+2] = tmp;
}
}
if (m_frontend)
m_frontend->frameReady(m_frame);
m_mutex.unlock();
}
void VideoDataOutput::displayCallback(void *picture)
{
Q_UNUSED(picture);
DEBUG_BLOCK;
// We send the frame while unlocking as we could loose syncing otherwise.
// With VDO the consumer is expected to ensure syncness while not blocking
// unlock for long periods of time. Good luck with that... -.-
}
static VideoFrame2::Format fourccToFormat(const char *fourcc)
{
if (qstrcmp(fourcc, "RV24"))
return VideoFrame2::Format_RGB888;
else if (qstrcmp(fourcc, "RV32"))
return VideoFrame2::Format_RGB32;
else if (qstrcmp(fourcc, "YV12"))
return VideoFrame2::Format_YV12;
else if (qstrcmp(fourcc, "YUY2"))
return VideoFrame2::Format_YUY2;
else
return VideoFrame2::Format_Invalid;
}
static const vlc_chroma_description_t *setFormat(VideoFrame2::Format format, char **chroma)
{
switch (format) {
case VideoFrame2::Format_Invalid:
*chroma = 0;
return 0;
case VideoFrame2::Format_RGB32:
qstrcpy(*chroma, "RV32");
return vlc_fourcc_GetChromaDescription(VLC_CODEC_RGB32);
case VideoFrame2::Format_RGB888:
qstrcpy(*chroma, "RV24");
return vlc_fourcc_GetChromaDescription(VLC_CODEC_RGB24);
case VideoFrame2::Format_YV12:
qstrcpy(*chroma, "YV12");
return vlc_fourcc_GetChromaDescription(VLC_CODEC_YV12);
case VideoFrame2::Format_YUY2:
qstrcpy(*chroma, "YUY2");
return vlc_fourcc_GetChromaDescription(VLC_CODEC_YUYV);
}
return 0;
}
unsigned VideoDataOutput::formatCallback(char *chroma,
unsigned *width, unsigned *height,
unsigned *pitches, unsigned *lines)
{
DEBUG_BLOCK;
m_frame.width = *width;
m_frame.height = *height;
const vlc_chroma_description_t *chromaDesc = 0;
QSet<VideoFrame2::Format> allowedFormats = m_frontend->allowedFormats();
VideoFrame2::Format suggestedFormat = fourccToFormat(chroma);
if (suggestedFormat != VideoFrame2::Format_Invalid
&& allowedFormats.contains(suggestedFormat)) { // Use suggested
chromaDesc = setFormat(suggestedFormat, &chroma);
m_frame.format = suggestedFormat;
} else { // Pick first and use that
foreach (const VideoFrame2::Format &format, allowedFormats) {
chromaDesc = setFormat(format, &chroma);
if (chroma) {
m_frame.format = format;
break;
}
}
}
Q_ASSERT(chromaDesc);
unsigned int bufferSize = setPitchAndLines(chromaDesc, *width, *height, pitches, lines);
m_frame.data0.resize(pitches[0] * lines[0]);
m_frame.data1.resize(pitches[1] * lines[1]);
m_frame.data2.resize(pitches[2] * lines[0]);
return bufferSize;
}
void VideoDataOutput::formatCleanUpCallback()
{
DEBUG_BLOCK;
}
} // namespace VLC
} // namespace Phonon

View File

@ -0,0 +1,74 @@
/*
Copyright (C) 2012 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef Phonon_VLC_VIDEODATAOUTPUT_H
#define Phonon_VLC_VIDEODATAOUTPUT_H
#include <QMutex>
#include <QObject>
#include <phonon/experimental/videodataoutputinterface.h>
#include <phonon/experimental/videoframe2.h>
#include "sinknode.h"
#include "videomemorystream.h"
namespace Phonon
{
namespace VLC
{
/**
* @author Harald Sitter <apachelogger@ubuntu.com>
*/
class VideoDataOutput : public QObject, public SinkNode,
public Experimental::VideoDataOutputInterface, private VideoMemoryStream
{
Q_OBJECT
Q_INTERFACES(Phonon::Experimental::VideoDataOutputInterface)
public:
explicit VideoDataOutput(QObject *parent);
~VideoDataOutput();
void handleConnectToMediaObject(MediaObject *mediaObject);
void handleDisconnectFromMediaObject(MediaObject *mediaObject);
void handleAddToMedia(Media *media);
Experimental::AbstractVideoDataOutput *frontendObject() const;
void setFrontendObject(Experimental::AbstractVideoDataOutput *frontend);
virtual void *lockCallback(void **planes);
virtual void unlockCallback(void *picture,void *const *planes);
virtual void displayCallback(void *picture);
virtual unsigned formatCallback(char *chroma,
unsigned *width, unsigned *height,
unsigned *pitches,
unsigned *lines);
virtual void formatCleanUpCallback();
private:
Experimental::AbstractVideoDataOutput *m_frontend;
Experimental::VideoFrame2 m_frame;
QByteArray m_buffer;
QMutex m_mutex;
};
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_VIDEODATAOUTPUT_H

View File

@ -0,0 +1,147 @@
/*
Copyright (C) 2012 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "videomemorystream.h"
#include "mediaplayer.h"
namespace Phonon {
namespace VLC {
static inline VideoMemoryStream *p_this(void *opaque) { return static_cast<VideoMemoryStream *>(opaque); }
static inline VideoMemoryStream *p_this(void **opaque) { return static_cast<VideoMemoryStream *>(*opaque); }
#define P_THIS p_this(opaque)
VideoMemoryStream::VideoMemoryStream()
{
}
VideoMemoryStream::~VideoMemoryStream()
{
}
static inline qint64 gcd(qint64 a, qint64 b)
{
while( b )
{
qint64 c = a % b;
a = b;
b = c;
}
return a;
}
static int lcm(int a, int b)
{
return a * b / GCD( a, b );
}
unsigned VideoMemoryStream::setPitchAndLines(const vlc_chroma_description_t *desc,
unsigned width, unsigned height,
unsigned *pitches, unsigned *lines,
unsigned *visiblePitches, unsigned *visibleLines)
{
// Mostly taken from vlc/src/misc/picture.c
// Simple alignment would be an option but I trust the VLC guys they know what they are doing.
int i_modulo_w = 1;
int i_modulo_h = 1;
unsigned int i_ratio_h = 1;
for( unsigned i = 0; i < desc->plane_count; i++ )
{
i_modulo_w = lcm( i_modulo_w, 8 * desc->p[i].w.den );
i_modulo_h = lcm( i_modulo_h, 8 * desc->p[i].h.den );
if( i_ratio_h < desc->p[i].h.den )
i_ratio_h = desc->p[i].h.den;
}
i_modulo_h = lcm( i_modulo_h, 32 );
const int i_width_aligned = ( width + i_modulo_w - 1 ) / i_modulo_w * i_modulo_w;
const int i_height_aligned = ( height + i_modulo_h - 1 ) / i_modulo_h * i_modulo_h;
const int i_height_extra = 2 * i_ratio_h; /* This one is a hack for some ASM functions */
unsigned int bufferSize = 0;
for(unsigned i = 0; i < desc->plane_count; ++i)
{
pitches[i] = i_width_aligned * desc->p[i].w.num / desc->p[i].w.den * desc->pixel_size;
if (visiblePitches)
visiblePitches[i] = width * desc->p[i].w.num / desc->p[i].w.den * desc->pixel_size;
lines[i] = (i_height_aligned + i_height_extra ) * desc->p[i].h.num / desc->p[i].h.den;
if (visibleLines)
visibleLines[i] = height * desc->p[i].h.num / desc->p[i].h.den;
bufferSize += pitches[i] * lines[i];
}
return bufferSize;
}
void VideoMemoryStream::setCallbacks(MediaPlayer *player)
{
libvlc_video_set_callbacks(player->libvlc_media_player(),
lockCallbackInternal,
unlockCallbackInternal,
displayCallbackInternal,
this);
libvlc_video_set_format_callbacks(player->libvlc_media_player(),
formatCallbackInternal,
formatCleanUpCallbackInternal);
}
void VideoMemoryStream::unsetCallbacks(MediaPlayer *player)
{
libvlc_video_set_callbacks(player->libvlc_media_player(),
0,
0,
0,
0);
libvlc_video_set_format_callbacks(player->libvlc_media_player(),
0,
0);
}
void *VideoMemoryStream::lockCallbackInternal(void *opaque, void **planes)
{
return P_THIS->lockCallback(planes);
}
void VideoMemoryStream::unlockCallbackInternal(void *opaque, void *picture, void *const*planes)
{
P_THIS->unlockCallback(picture, planes);
}
void VideoMemoryStream::displayCallbackInternal(void *opaque, void *picture)
{
P_THIS->displayCallback(picture);
}
unsigned VideoMemoryStream::formatCallbackInternal(void **opaque, char *chroma,
unsigned *width, unsigned *height,
unsigned *pitches, unsigned *lines)
{
return P_THIS->formatCallback(chroma, width, height, pitches, lines);
}
void VideoMemoryStream::formatCleanUpCallbackInternal(void *opaque)
{
P_THIS->formatCleanUpCallback();
}
} // namespace VLC
} // namespace Phonon

View File

@ -0,0 +1,83 @@
/*
Copyright (C) 2012 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_VIDEOMEMORYSTREAM_H
#define PHONON_VLC_VIDEOMEMORYSTREAM_H
// VLC 3.0 uses the restrict keyword. restrict is not a thing in C++, so
// depending on the compiler you use an extension keyword or drop it entirely.
#if defined(Q_CC_GNU)
#define restrict __restrict__
#elif defined(Q_CC_MSVC)
#define restrict __restrict
#else
#define restrict
#endif
#include <vlc/plugins/vlc_common.h>
#include <vlc/plugins/vlc_fourcc.h>
namespace Phonon {
namespace VLC {
class MediaPlayer;
class VideoMemoryStream
{
public:
explicit VideoMemoryStream();
virtual ~VideoMemoryStream();
/**
* @returns overall buffersize needed
*/
static unsigned setPitchAndLines(const vlc_chroma_description_t *chromaDescription,
unsigned width, unsigned height,
unsigned *pitches, unsigned *lines,
unsigned *visiblePitches = 0, unsigned *visibleLines = 0);
void setCallbacks(Phonon::VLC::MediaPlayer *player);
void unsetCallbacks(Phonon::VLC::MediaPlayer *player);
protected:
virtual void *lockCallback(void **planes) = 0;
virtual void unlockCallback(void *picture,void *const *planes) = 0;
virtual void displayCallback(void *picture) = 0;
virtual unsigned formatCallback(char *chroma,
unsigned *width, unsigned *height,
unsigned *pitches,
unsigned *lines) = 0;
virtual void formatCleanUpCallback() = 0;
private:
static void *lockCallbackInternal(void *opaque, void **planes);
static void unlockCallbackInternal(void *opaque, void *picture, void *const *planes);
static void displayCallbackInternal(void *opaque, void *picture);
static unsigned formatCallbackInternal(void **opaque, char *chroma,
unsigned *width, unsigned *height,
unsigned *pitches,
unsigned *lines);
static void formatCleanUpCallbackInternal(void *opaque);
};
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_VIDEOMEMORYSTREAM_H

545
src/video/videowidget.cpp Normal file
View File

@ -0,0 +1,545 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
Copyright (C) 2011-2021 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "videowidget.h"
#include <QGuiApplication>
#include <QPainter>
#include <QPaintEvent>
#include <vlc/vlc.h>
#include "utils/debug.h"
#include "mediaobject.h"
#include "media.h"
#include "video/videomemorystream.h"
namespace Phonon {
namespace VLC {
#define DEFAULT_QSIZE QSize(320, 240)
class SurfacePainter : public VideoMemoryStream
{
public:
void handlePaint(QPaintEvent *event)
{
// Mind that locking here is still faster than making this lockfree by
// dispatching QEvents.
// Plus VLC can actually skip frames as necessary.
QMutexLocker lock(&m_mutex);
Q_UNUSED(event);
if (m_frame.isNull()) {
return;
}
QPainter painter(widget);
// When using OpenGL for the QPaintEngine drawing the same QImage twice
// does not actually result in a texture change for one reason or another.
// So we simply create new images for every event. This is plenty cheap
// as the QImage only points to the plane data (it can't even make it
// properly shared as it does not know that the data belongs to a QBA).
// TODO: investigate if this is still necessary. This was added for gwenview, but with Qt 5.15 the problem
// can't be produced.
painter.drawImage(drawFrameRect(), QImage(m_frame));
event->accept();
}
VideoWidget *widget;
private:
virtual void *lockCallback(void **planes)
{
m_mutex.lock();
planes[0] = (void *) m_frame.bits();
return 0;
}
virtual void unlockCallback(void *picture,void *const *planes)
{
Q_UNUSED(picture);
Q_UNUSED(planes);
m_mutex.unlock();
}
virtual void displayCallback(void *picture)
{
Q_UNUSED(picture);
if (widget)
widget->update();
}
virtual unsigned formatCallback(char *chroma,
unsigned *width, unsigned *height,
unsigned *pitches,
unsigned *lines)
{
QMutexLocker lock(&m_mutex);
// Surface rendering is a fallback system used when no efficient rendering implementation is available.
// As such we only support RGB32 for simplicity reasons and this will almost always mean software scaling.
// And since scaling is unavoidable anyway we take the canonical frame size and then scale it on our end via
// QPainter, again, greater simplicity at likely no real extra cost since this is all super inefficient anyway.
// Also, since aspect ratio can be change mid-playback by the user, doing the scaling on our end means we
// don't need to restart the entire player to retrigger format calculation.
// With all that in mind we simply use the canonical size and feed VLC the QImage's pitch and lines as
// effectively the VLC vout is the QImage so its constraints matter.
// per https://wiki.videolan.org/Hacker_Guide/Video_Filters/#Pitch.2C_visible_pitch.2C_planes_et_al.
// it would seem that we can use either real or visible pitches and lines as VLC generally will iterate the
// smallest value when moving data between two entities. i.e. since QImage will at most paint NxM anyway,
// we may just go with its values as calculating the real pitch/line of the VLC picture_t for RV32 wouldn't
// change the maximum pitch/lines we can paint on the output side.
qstrcpy(chroma, "RV32");
m_frame = QImage(*width, *height, QImage::Format_RGB32);
Q_ASSERT(!m_frame.isNull()); // ctor may construct null if allocation fails
m_frame.fill(0);
pitches[0] = m_frame.bytesPerLine();
lines[0] = m_frame.sizeInBytes() / m_frame.bytesPerLine();
return m_frame.sizeInBytes();
}
virtual void formatCleanUpCallback()
{
// Lazy delete the object to avoid callbacks from VLC after deletion.
if (!widget) {
// The widget member is set to null by the widget destructor, so when this condition is true the
// widget had already been destroyed and we can't possibly receive a paint event anymore, meaning
// we need no lock here. If it were any other way we'd have trouble with synchronizing deletion
// without deleting a locked mutex.
delete this;
}
}
QRect scaleToAspect(QRect srcRect, int w, int h) const
{
float width = srcRect.width();
float height = srcRect.width() * (float(h) / float(w));
if (height > srcRect.height()) {
height = srcRect.height();
width = srcRect.height() * (float(w) / float(h));
}
return QRect(0, 0, (int)width, (int)height);
}
QRect drawFrameRect() const
{
QRect widgetRect = widget->rect();
QRect drawFrameRect;
switch (widget->aspectRatio()) {
case Phonon::VideoWidget::AspectRatioWidget:
drawFrameRect = widgetRect;
// No more calculations needed.
return drawFrameRect;
case Phonon::VideoWidget::AspectRatio4_3:
drawFrameRect = scaleToAspect(widgetRect, 4, 3);
break;
case Phonon::VideoWidget::AspectRatio16_9:
drawFrameRect = scaleToAspect(widgetRect, 16, 9);
break;
case Phonon::VideoWidget::AspectRatioAuto:
drawFrameRect = QRect(0, 0, m_frame.width(), m_frame.height());
break;
}
// Scale m_drawFrameRect to fill the widget
// without breaking aspect:
float widgetWidth = widgetRect.width();
float widgetHeight = widgetRect.height();
float frameWidth = widgetWidth;
float frameHeight = drawFrameRect.height() * float(widgetWidth) / float(drawFrameRect.width());
switch (widget->scaleMode()) {
case Phonon::VideoWidget::ScaleAndCrop:
if (frameHeight < widgetHeight) {
frameWidth *= float(widgetHeight) / float(frameHeight);
frameHeight = widgetHeight;
}
break;
case Phonon::VideoWidget::FitInView:
if (frameHeight > widgetHeight) {
frameWidth *= float(widgetHeight) / float(frameHeight);
frameHeight = widgetHeight;
}
break;
}
drawFrameRect.setSize(QSize(int(frameWidth), int(frameHeight)));
drawFrameRect.moveTo(int((widgetWidth - frameWidth) / 2.0f),
int((widgetHeight - frameHeight) / 2.0f));
return drawFrameRect;
}
// Could ReadWriteLock two frames so VLC can write while we paint.
QImage m_frame;
QMutex m_mutex;
};
VideoWidget::VideoWidget(QWidget *parent) :
BaseWidget(parent),
SinkNode(),
m_videoSize(DEFAULT_QSIZE),
m_aspectRatio(Phonon::VideoWidget::AspectRatioAuto),
m_scaleMode(Phonon::VideoWidget::FitInView),
m_filterAdjustActivated(false),
m_brightness(0.0),
m_contrast(0.0),
m_hue(0.0),
m_saturation(0.0),
m_surfacePainter(0)
{
// We want background painting so Qt autofills with black.
setAttribute(Qt::WA_NoSystemBackground, false);
// Required for dvdnav
#ifdef __GNUC__
#warning dragonplayer munches on our mouse events, so clicking in a DVD menu does not work - vlc 1.2 where are thu?
#endif // __GNUC__
setMouseTracking(true);
// setBackgroundColor
QPalette p = palette();
p.setColor(backgroundRole(), Qt::black);
setPalette(p);
setAutoFillBackground(true);
}
VideoWidget::~VideoWidget()
{
if (m_surfacePainter)
m_surfacePainter->widget = 0; // Lazy delete
}
void VideoWidget::handleConnectToMediaObject(MediaObject *mediaObject)
{
connect(mediaObject, SIGNAL(hasVideoChanged(bool)),
SLOT(updateVideoSize(bool)));
connect(mediaObject, SIGNAL(hasVideoChanged(bool)),
SLOT(processPendingAdjusts(bool)));
connect(mediaObject, SIGNAL(currentSourceChanged(MediaSource)),
SLOT(clearPendingAdjusts()));
clearPendingAdjusts();
}
void VideoWidget::handleDisconnectFromMediaObject(MediaObject *mediaObject)
{
// Undo all connections or path creation->destruction->creation can cause
// duplicated connections or getting singals from two different MediaObjects.
disconnect(mediaObject, 0, this, 0);
}
void VideoWidget::handleAddToMedia(Media *media)
{
media->addOption(":video");
if (!m_surfacePainter) {
#if defined(Q_OS_MAC)
m_player->setNsObject(cocoaView());
#elif defined(Q_OS_UNIX)
if (QGuiApplication::platformName().contains(QStringLiteral("xcb"), Qt::CaseInsensitive)) {
m_player->setXWindow(winId());
} else {
enableSurfacePainter();
}
#elif defined(Q_OS_WIN)
m_player->setHwnd((HWND)winId());
#endif
}
}
Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const
{
return m_aspectRatio;
}
void VideoWidget::setAspectRatio(Phonon::VideoWidget::AspectRatio aspect)
{
DEBUG_BLOCK;
if (!m_player)
return;
m_aspectRatio = aspect;
switch (m_aspectRatio) {
// FIXME: find a way to implement aspectratiowidget, it is meant to scale
// and stretch (i.e. scale to window without retaining aspect ratio).
case Phonon::VideoWidget::AspectRatioAuto:
m_player->setVideoAspectRatio(QByteArray());
return;
case Phonon::VideoWidget::AspectRatio4_3:
m_player->setVideoAspectRatio("4:3");
return;
case Phonon::VideoWidget::AspectRatio16_9:
m_player->setVideoAspectRatio("16:9");
return;
}
warning() << "The aspect ratio" << aspect << "is not supported by Phonon VLC.";
}
Phonon::VideoWidget::ScaleMode VideoWidget::scaleMode() const
{
return m_scaleMode;
}
void VideoWidget::setScaleMode(Phonon::VideoWidget::ScaleMode scale)
{
#ifdef __GNUC__
#warning OMG WTF
#endif
m_scaleMode = scale;
switch (m_scaleMode) {
}
warning() << "The scale mode" << scale << "is not supported by Phonon VLC.";
}
qreal VideoWidget::brightness() const
{
return m_brightness;
}
void VideoWidget::setBrightness(qreal brightness)
{
DEBUG_BLOCK;
if (!m_player) {
return;
}
if (!enableFilterAdjust()) {
// Add to pending adjusts
m_pendingAdjusts.insert(QByteArray("setBrightness"), brightness);
return;
}
// VLC operates within a 0.0 to 2.0 range for brightness.
m_brightness = brightness;
m_player->setVideoAdjust(libvlc_adjust_Brightness,
phononRangeToVlcRange(m_brightness, 2.0));
}
qreal VideoWidget::contrast() const
{
return m_contrast;
}
void VideoWidget::setContrast(qreal contrast)
{
DEBUG_BLOCK;
if (!m_player) {
return;
}
if (!enableFilterAdjust()) {
// Add to pending adjusts
m_pendingAdjusts.insert(QByteArray("setContrast"), contrast);
return;
}
// VLC operates within a 0.0 to 2.0 range for contrast.
m_contrast = contrast;
m_player->setVideoAdjust(libvlc_adjust_Contrast, phononRangeToVlcRange(m_contrast, 2.0));
}
qreal VideoWidget::hue() const
{
return m_hue;
}
void VideoWidget::setHue(qreal hue)
{
DEBUG_BLOCK;
if (!m_player) {
return;
}
if (!enableFilterAdjust()) {
// Add to pending adjusts
m_pendingAdjusts.insert(QByteArray("setHue"), hue);
return;
}
// VLC operates within a 0 to 360 range for hue.
// Phonon operates on -1.0 to 1.0, so we need to consider 0 to 180 as
// 0 to 1.0 and 180 to 360 as -1 to 0.0.
// 360/0 (0)
// ___
// / \
// 270 (-.25) | | 90 (.25)
// \___/
// 180 (1/-1)
// (-.25 is 360 minus 90 (vlcValue of .25).
m_hue = hue;
const int vlcValue = static_cast<int>(phononRangeToVlcRange(qAbs(hue), 180.0, false));
int value = 0;
if (hue >= 0)
value = vlcValue;
else
value = 360.0 - vlcValue;
m_player->setVideoAdjust(libvlc_adjust_Hue, value);
}
qreal VideoWidget::saturation() const
{
return m_saturation;
}
void VideoWidget::setSaturation(qreal saturation)
{
DEBUG_BLOCK;
if (!m_player) {
return;
}
if (!enableFilterAdjust()) {
// Add to pending adjusts
m_pendingAdjusts.insert(QByteArray("setSaturation"), saturation);
return;
}
// VLC operates within a 0.0 to 3.0 range for saturation.
m_saturation = saturation;
m_player->setVideoAdjust(libvlc_adjust_Saturation,
phononRangeToVlcRange(m_saturation, 3.0));
}
QWidget *VideoWidget::widget()
{
return this;
}
QSize VideoWidget::sizeHint() const
{
return m_videoSize;
}
void VideoWidget::updateVideoSize(bool hasVideo)
{
if (hasVideo) {
m_videoSize = m_player->videoSize();
updateGeometry();
update();
} else
m_videoSize = DEFAULT_QSIZE;
}
void VideoWidget::setVisible(bool visible)
{
if (window() && window()->testAttribute(Qt::WA_DontShowOnScreen) && !m_surfacePainter) {
enableSurfacePainter();
}
QWidget::setVisible(visible);
}
void VideoWidget::processPendingAdjusts(bool videoAvailable)
{
if (!videoAvailable || !m_mediaObject || !m_mediaObject->hasVideo()) {
return;
}
QHashIterator<QByteArray, qreal> it(m_pendingAdjusts);
while (it.hasNext()) {
it.next();
QMetaObject::invokeMethod(this, it.key().constData(), Q_ARG(qreal, it.value()));
}
m_pendingAdjusts.clear();
}
void VideoWidget::clearPendingAdjusts()
{
m_pendingAdjusts.clear();
}
void VideoWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
if (m_surfacePainter)
m_surfacePainter->handlePaint(event);
}
bool VideoWidget::enableFilterAdjust(bool adjust)
{
DEBUG_BLOCK;
// Need to check for MO here, because we can get called before a VOut is actually
// around in which case we just ignore this.
if (!m_mediaObject || !m_mediaObject->hasVideo()) {
debug() << "no mo or no video!!!";
return false;
}
if ((!m_filterAdjustActivated && adjust) ||
(m_filterAdjustActivated && !adjust)) {
debug() << "adjust: " << adjust;
m_player->setVideoAdjust(libvlc_adjust_Enable, static_cast<int>(adjust));
m_filterAdjustActivated = adjust;
}
return true;
}
float VideoWidget::phononRangeToVlcRange(qreal phononValue, float upperBoundary,
bool shift)
{
// VLC operates on different ranges than Phonon. Phonon always uses a range of
// -1:1 with 0 as the default value.
// It is therefore necessary to convert between the two schemes using sophisticated magic.
// First the incoming range is locked between -1..1, then depending on shift
// either normalized to 0..2 or 0..1 and finally a new value is calculated
// depending on the upperBoundary and the normalized range.
float value = static_cast<float>(phononValue);
float range = 2.0; // The default normalized range will be 0..2 = 2
// Ensure valid range
if (value < -1.0)
value = -1.0;
else if (value > 1.0)
value = 1.0;
if (shift)
value += 1.0; // Shift into 0..2 range
else {
// Chop negative value; normalize to 0..1 = range 1
if (value < 0.0)
value = 0.0;
range = 1.0;
}
return (value * (upperBoundary/range));
}
QImage VideoWidget::snapshot() const
{
DEBUG_BLOCK;
if (m_player)
return m_player->snapshot();
else
return QImage();
}
void VideoWidget::enableSurfacePainter()
{
if (m_surfacePainter) {
return;
}
debug() << "ENABLING SURFACE PAINTING";
m_surfacePainter = new SurfacePainter;
m_surfacePainter->widget = this;
m_surfacePainter->setCallbacks(m_player);
}
} // namespace VLC
} // namespace Phonon

253
src/video/videowidget.h Normal file
View File

@ -0,0 +1,253 @@
/*
Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
Copyright (C) 2011-2019 Harald Sitter <sitter@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PHONON_VLC_VIDEOWIDGET_H
#define PHONON_VLC_VIDEOWIDGET_H
#include <QWidget>
#include <phonon/videowidgetinterface.h>
#ifdef Q_OS_MAC
#include "video/mac/vlcmacwidget.h"
typedef VlcMacWidget BaseWidget;
#else
typedef QWidget BaseWidget;
#endif
#include "sinknode.h"
namespace Phonon {
namespace VLC {
class SurfacePainter;
/** \brief Implements the Phonon VideoWidget MediaNode, responsible for displaying video
*
* Phonon video is displayed using this widget. It implements the VideoWidgetInterface.
* It is connected to a media object that provides the video source. Methods to control
* video settings such as brightness or contrast are provided.
*/
class VideoWidget : public BaseWidget, public SinkNode, public VideoWidgetInterface44
{
Q_OBJECT
Q_INTERFACES(Phonon::VideoWidgetInterface44)
public:
/**
* Constructs a new VideoWidget with the given parent. The video settings members
* are set to their default values.
*/
explicit VideoWidget(QWidget *parent);
/**
* Death to the VideoWidget!
*/
~VideoWidget();
/**
* Connects the VideoWidget to a media object by setting the video widget
* window system identifier of the media object to that of the owned private
* video widget. It also connects the signal from the mediaObject regarding
* a resize of the video.
*
* If the mediaObject was connected to another VideoWidget, the connection is
* lost.
*
* \see MediaObject
* \param mediaObject What media object to connect to
* \reimp
*/
void handleConnectToMediaObject(MediaObject *mediaObject);
/** \reimp */
void handleDisconnectFromMediaObject(MediaObject *mediaObject);
/** \reimp */
void handleAddToMedia(Media *media);
/**
* \return The aspect ratio previously set for the video widget
*/
Phonon::VideoWidget::AspectRatio aspectRatio() const;
/**
* Set the aspect ratio of the video.
* VLC accepted formats are x:y (4:3, 16:9, etc...) expressing the global image aspect.
*/
void setAspectRatio(Phonon::VideoWidget::AspectRatio aspect);
/**
* \return The scale mode previously set for the video widget
*/
Phonon::VideoWidget::ScaleMode scaleMode() const;
/**
* Set how the video is scaled, keeping the aspect ratio into account when the video is resized.
*
* The ScaleMode enumeration describes how to treat aspect ratio during resizing of video.
* \li Phonon::VideoWidget::FitInView - the video will be fitted to fill the view keeping aspect ratio
* \li Phonon::VideoWidget::ScaleAndCrop - the video is scaled
*/
void setScaleMode(Phonon::VideoWidget::ScaleMode scale);
/**
* \return The brightness previously set for the video widget
*/
qreal brightness() const;
/**
* Set the brightness of the video
*/
Q_INVOKABLE void setBrightness(qreal brightness);
/**
* \return The contrast previously set for the video widget
*/
qreal contrast() const;
/**
* Set the contrast of the video
*/
Q_INVOKABLE void setContrast(qreal contrast);
/**
* \return The hue previously set for the video widget
*/
qreal hue() const;
/**
* Set the hue of the video
*/
Q_INVOKABLE void setHue(qreal hue);
/**
* \return The saturation previously set for the video widget
*/
qreal saturation() const;
/**
* Set the saturation of the video
*/
Q_INVOKABLE void setSaturation(qreal saturation);
/**
* \return The owned widget that is used for the actual draw.
*/
QWidget *widget();
/// \reimp
QSize sizeHint() const;
void setVisible(bool visible);
private slots:
/// Updates the sizeHint to match the native size of the video.
/// \param hasVideo \c true when there is a video, \c false otherwise
void updateVideoSize(bool hasVideo);
/**
* Sets all pending video adjusts (hue, brightness etc.) that the application
* wanted to set before the vidoe became available.
*
* \param videoAvailable whether or not video is available at the time of calling
*/
void processPendingAdjusts(bool videoAvailable);
/**
* Clears all pending video adjusts (hue, brightness etc.).
*/
void clearPendingAdjusts();
protected:
/// \reimp
void paintEvent(QPaintEvent *event);
private:
/**
* Sets whether filter adjust is active or not.
*
* \param adjust true if adjust is supposed to be activated, false if not
*
* \returns whether the adjust request was accepted, if not the callee should
* add the request to m_pendingAdjusts for later processing once a video
* became available. Adjusts get accepted always except when
* MediaObject::hasVideo() is false, so it is not related to the
* actual execution of the request.
*/
bool enableFilterAdjust(bool adjust = true);
/**
* Converts a Phonon range to a VLC value range.
*
* A Phonon range is always a qreal between -1.0 and 1.0, a VLC range however
* can be any between 0 and 360. This functon maps the Phonon value to an
* appropriate value within a specified target range.
*
* \param phononValue the incoming Phonon specific value, should be -1.0:1.0
* should it however not be within that range will it be
* manually locked (i.e. exceeding values become either -1.0 or 1.0)
* \param upperBoundary the upper boundary for the target range. The lower
* boundary is currently always assumed to be 0
* \param shift whether or not to shift the Phonon range to positive values
* before mapping to VLC values (useful when our 0 must be a VLC 0).
* Please note that if you do not shift the range will be reduced to
* 0:1, phononValue < 0 will be set to 0.
*
* \returns float usable to VLC
*/
static float phononRangeToVlcRange(qreal phononValue, float upperBoundary,
bool shift = true);
/**
* \return The snapshot of the current video frame.
*/
QImage snapshot() const;
/**
* Enables the mighty surface painter (qpaints frames).
*/
void enableSurfacePainter();
/**
* Pending video adjusts the application tried to set before we actually
* had a video to set them on.
*/
QHash<QByteArray, qreal> m_pendingAdjusts;
/**
* Original size of the video, needed for sizeHint().
*/
QSize m_videoSize;
Phonon::VideoWidget::AspectRatio m_aspectRatio;
Phonon::VideoWidget::ScaleMode m_scaleMode;
bool m_filterAdjustActivated;
qreal m_brightness;
qreal m_contrast;
qreal m_hue;
qreal m_saturation;
SurfacePainter *m_surfacePainter;
};
} // namespace VLC
} // namespace Phonon
#endif // PHONON_VLC_VIDEOWIDGET_H

40
warning-check.rb Executable file
View File

@ -0,0 +1,40 @@
#!/usr/bin/env ruby
# Copyright (C) 2011 Harald Sitter <sitter@kde.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
for file in Dir.glob("src/**")
line_count = 1
has_open_ifdef = false
next if File.directory?(file)
File.open(file, 'r').each_line do | line |
if line =~ /#\s*ifdef\s*__GNUC__\s*/
has_open_ifdef = true
end
if line =~ /#\s*endif\s*/
has_open_ifdef = false
end
if line =~ /#\s*warning\s*/ and not has_open_ifdef
raise("unprotected warning in (#{file}:#{line_count}), please add #ifdef __GNUC__")
end
line_count += 1
end
end
puts ("All good :)")