From kde-commits Sat Oct 03 17:55:12 2009 From: Christoph Pfister Date: Sat, 03 Oct 2009 17:55:12 +0000 To: kde-commits Subject: kdesupport/phonon Message-Id: <1254592512.709705.23904.nullmailer () svn ! kde ! org> X-MARC-Message: https://marc.info/?l=kde-commits&m=125459252023916 SVN commit 1031004 by pfister: add video effect support to phonon this is important for deinterlacing, but allows other types of video effects as well CCMAIL: kretz@kde.org M +15 -0 phonon/backendcapabilities.cpp M +9 -7 phonon/backendcapabilities.h M +2 -3 phonon/effect.cpp M +10 -1 phonon/objectdescription.h M +17 -6 xine/backend.cpp M +88 -14 xine/effect.cpp M +5 -0 xine/effect.h M +0 -64 xine/xinestream.cpp M +0 -1 xine/xinestream.h --- trunk/kdesupport/phonon/phonon/backendcapabilities.cpp #1031003:1031004 @@ -110,6 +110,21 @@ } #endif //QT_NO_PHONON_EFFECT +#ifndef QT_NO_PHONON_EFFECT +QList BackendCapabilities::availableVideoEffects() +{ + BackendInterface *backendIface = qobject_cast(Factory::backend()); + QList ret; + if (backendIface) { + QList deviceIndexes = backendIface->objectDescriptionIndexes(Phonon::VideoEffectType); + foreach (int i, deviceIndexes) { + ret.append(EffectDescription::fromIndex(i, Phonon::VideoEffectType)); + } + } + return ret; +} +#endif //QT_NO_PHONON_EFFECT + } // namespace Phonon QT_END_NAMESPACE --- trunk/kdesupport/phonon/phonon/backendcapabilities.h #1031003:1031004 @@ -172,13 +172,15 @@ PHONON_EXPORT QList availableAudioEffects(); #endif //QT_NO_PHONON_EFFECT -//X /** -//X * Returns descriptions for the video effects the backend supports. -//X * -//X * \return A list of VideoEffectDescription objects that give a name and -//X * description for every supported video effect. -//X */ -//X PHONON_EXPORT QList availableVideoEffects(); + /** + * Returns descriptions for the video effects the backend supports. + * + * \return A list of EffectDescription objects that give a name and + * description for every supported video effect. + */ +#ifndef QT_NO_PHONON_EFFECT + PHONON_EXPORT QList availableVideoEffects(); +#endif //QT_NO_PHONON_EFFECT /** * Returns descriptions for the audio codecs the backend supports. --- trunk/kdesupport/phonon/phonon/effect.cpp #1031003:1031004 @@ -119,9 +119,8 @@ Q_ASSERT(m_backendObject); // set up attributes - const QList parameters = pINTERFACE_CALL(parameters()); - foreach (const EffectParameter &p, parameters) { - pINTERFACE_CALL(setParameterValue(p, parameterValues[p])); + for (QHash::const_iterator it = parameterValues.constBegin(); it != parameterValues.constEnd(); ++it) { + pINTERFACE_CALL(setParameterValue(it.key(), it.value())); } } --- trunk/kdesupport/phonon/phonon/objectdescription.h #1031003:1031004 @@ -76,8 +76,10 @@ * devices even when they are unplugged and provide a unique identifier * that can make backends use the same identifiers. */ - AudioCaptureDeviceType + AudioCaptureDeviceType, + VideoEffectType + //VideoOutputDeviceType, //VideoCaptureDeviceType, //AudioCodecType, @@ -188,6 +190,13 @@ return ObjectDescription(QExplicitlySharedDataPointer(ObjectDescriptionData::fromIndex(T, index))); } + /** \internal + * This function is needed because video and audio effects share the EffectDescription class. + */ + static inline ObjectDescription fromIndex(int index, ObjectDescriptionType type) { //krazy:exclude=inline + return ObjectDescription(QExplicitlySharedDataPointer(ObjectDescriptionData::fromIndex(type, index))); + } + /** * Returns \c true if this ObjectDescription describes the same * as \p otherDescription; otherwise returns \c false. --- trunk/kdesupport/phonon/xine/backend.cpp #1031003:1031004 @@ -237,11 +237,16 @@ const char *const *postPlugins = xine_list_post_plugins_typed(m_xine, XINE_POST_TYPE_AUDIO_FILTER); for (int i = 0; postPlugins[i]; ++i) list << 0x7F000000 + i; - /*const char *const *postVPlugins = xine_list_post_plugins_typed(m_xine, XINE_POST_TYPE_VIDEO_FILTER); - for (int i = 0; postVPlugins[i]; ++i) { + } + break; + case Phonon::VideoEffectType: + { + const char *const *postPlugins = xine_list_post_plugins_typed(m_xine, XINE_POST_TYPE_VIDEO_FILTER); + for (int i = 0; postPlugins[i]; ++i) { list << 0x7E000000 + i; - } */ + } } + break; case Phonon::AudioChannelType: case Phonon::SubtitleType: { @@ -312,14 +317,20 @@ break; } } - /*const char *const *postVPlugins = xine_list_post_plugins_typed(m_xine, XINE_POST_TYPE_VIDEO_FILTER); - for (int i = 0; postVPlugins[i]; ++i) { + } + break; + case Phonon::VideoEffectType: + { + const char *const *postPlugins = xine_list_post_plugins_typed(m_xine, XINE_POST_TYPE_VIDEO_FILTER); + for (int i = 0; postPlugins[i]; ++i) { if (0x7E000000 + i == index) { ret.insert("name", QLatin1String(postPlugins[i])); + ret.insert("description", QLatin1String(xine_get_post_plugin_description(m_xine, postPlugins[i]))); break; } - } */ + } } + break; case Phonon::AudioChannelType: case Phonon::SubtitleType: { --- trunk/kdesupport/phonon/xine/effect.cpp #1031003:1031004 @@ -33,6 +33,10 @@ xine_audio_port_t *EffectXT::audioPort() const { + if (m_isVideoPlugin) { + return 0; + } + const_cast(this)->ensureInstance(); Q_ASSERT(m_plugin); Q_ASSERT(m_plugin->audio_input); @@ -40,6 +44,19 @@ return m_plugin->audio_input[0]; } +xine_video_port_t *EffectXT::videoPort() const +{ + if (!m_isVideoPlugin) { + return 0; + } + + const_cast(this)->ensureInstance(); + Q_ASSERT(m_plugin); + Q_ASSERT(m_plugin->video_input); + Q_ASSERT(m_plugin->video_input[0]); + return m_plugin->video_input[0]; +} + xine_post_out_t *EffectXT::audioOutputPort() const { const_cast(this)->ensureInstance(); @@ -49,15 +66,37 @@ return x; } +xine_post_out_t *EffectXT::videoOutputPort() const +{ + const_cast(this)->ensureInstance(); + Q_ASSERT(m_plugin); + const char *const *portNames = xine_post_list_outputs(m_plugin); + Q_ASSERT(portNames); + Q_ASSERT(portNames[0]); + xine_post_out_t *x = xine_post_output(m_plugin, portNames[0]); + Q_ASSERT(x); + return x; +} + void EffectXT::rewireTo(SourceNodeXT *source) { - if (!source->audioOutputPort()) { - return; + if (m_isVideoPlugin) { + if (!source->videoOutputPort()) { + return; + } + ensureInstance(); + xine_post_in_t *x = xine_post_input(m_plugin, "video"); + Q_ASSERT(x); + xine_post_wire(source->videoOutputPort(), x); + } else { + if (!source->audioOutputPort()) { + return; + } + ensureInstance(); + xine_post_in_t *x = xine_post_input(m_plugin, "audio in"); + Q_ASSERT(x); + xine_post_wire(source->audioOutputPort(), x); } - ensureInstance(); - xine_post_in_t *x = xine_post_input(m_plugin, "audio in"); - Q_ASSERT(x); - xine_post_wire(source->audioOutputPort(), x); } // lazy initialization @@ -79,6 +118,14 @@ return m_fakeAudioPort; } +xine_video_port_t *EffectXT::fakeVideoPort() +{ + if (!m_fakeVideoPort) { + m_fakeVideoPort = xine_open_video_driver(m_xine, "none", XINE_VISUAL_TYPE_NONE, 0); + } + return m_fakeVideoPort; +} + void EffectXT::createInstance() { debug() << Q_FUNC_INFO << "m_pluginName =" << m_pluginName; @@ -88,8 +135,14 @@ return; } - fakeAudioPort(); - m_plugin = xine_post_init(m_xine, m_pluginName, 1, &m_fakeAudioPort, 0); + if (m_isVideoPlugin) { + fakeVideoPort(); + m_plugin = xine_post_init(m_xine, m_pluginName, 1, 0, &m_fakeVideoPort); + } else { + fakeAudioPort(); + m_plugin = xine_post_init(m_xine, m_pluginName, 1, &m_fakeAudioPort, 0); + } + xine_post_in_t *paraInput = xine_post_input(m_plugin, "parameters"); if (!paraInput) { return; @@ -154,13 +207,26 @@ SourceNode(static_cast(SinkNode::threadSafeObject().data())) { K_XT(Effect); - const char *const *postPlugins = xine_list_post_plugins_typed(xt->m_xine, XINE_POST_TYPE_AUDIO_FILTER); - if (effectId >= 0x7F000000) { + + if ((effectId & 0xff000000) == 0x7E000000) { + const char *const *postPlugins = xine_list_post_plugins_typed(xt->m_xine, XINE_POST_TYPE_VIDEO_FILTER); + effectId -= 0x7E000000; + for(int i = 0; postPlugins[i]; ++i) { + if (i == effectId) { + // found it + xt->m_pluginName = postPlugins[i]; + xt->m_isVideoPlugin = true; + break; + } + } + } else if ((effectId & 0xff000000) == 0x7F000000) { + const char *const *postPlugins = xine_list_post_plugins_typed(xt->m_xine, XINE_POST_TYPE_AUDIO_FILTER); effectId -= 0x7F000000; for(int i = 0; postPlugins[i]; ++i) { if (i == effectId) { // found it xt->m_pluginName = postPlugins[i]; + xt->m_isVideoPlugin = false; break; } } @@ -173,8 +239,8 @@ } EffectXT::EffectXT(const char *name) - : SourceNodeXT("Effect"), SinkNodeXT("Effect"), m_plugin(0), m_pluginApi(0), m_fakeAudioPort(0), - m_pluginName(name), m_pluginParams(0) + : SourceNodeXT("Effect"), SinkNodeXT("Effect"), m_plugin(0), m_pluginApi(0), m_fakeAudioPort(0), m_fakeVideoPort(0), + m_pluginName(name), m_pluginParams(0), m_isVideoPlugin(false) { m_xine = Backend::xine(); } @@ -189,6 +255,10 @@ xine_close_audio_driver(m_xine, m_fakeAudioPort); m_fakeAudioPort = 0; } + if (m_fakeVideoPort) { + xine_close_video_driver(m_xine, m_fakeVideoPort); + m_fakeVideoPort = 0; + } } free(m_pluginParams); m_pluginParams = 0; @@ -202,12 +272,14 @@ MediaStreamTypes Effect::inputMediaStreamTypes() const { - return Phonon::Xine::Audio; + K_XT(const Effect); + return (xt->m_isVideoPlugin ? Phonon::Xine::Video : Phonon::Xine::Audio); } MediaStreamTypes Effect::outputMediaStreamTypes() const { - return Phonon::Xine::Audio; + K_XT(const Effect); + return (xt->m_isVideoPlugin ? Phonon::Xine::Video : Phonon::Xine::Audio); } QList Effect::parameters() const @@ -337,9 +409,11 @@ xt2->m_plugin = xt->m_plugin; xt2->m_pluginApi = xt->m_pluginApi; xt2->m_fakeAudioPort = xt->m_fakeAudioPort; + xt2->m_fakeVideoPort = xt->m_fakeVideoPort; xt->m_plugin = 0; xt->m_pluginApi = 0; xt->m_fakeAudioPort = 0; + xt->m_fakeVideoPort = 0; KeepReference<> *keep = new KeepReference<>; keep->addObject(static_cast(xt2)); keep->ready(); --- trunk/kdesupport/phonon/xine/effect.h #1031003:1031004 @@ -44,11 +44,14 @@ EffectXT(const char *name); ~EffectXT(); xine_audio_port_t *audioPort() const; + xine_video_port_t *videoPort() const; xine_post_out_t *audioOutputPort() const; + xine_post_out_t *videoOutputPort() const; void rewireTo(SourceNodeXT *source); virtual void createInstance(); protected: xine_audio_port_t *fakeAudioPort(); + xine_video_port_t *fakeVideoPort(); xine_post_t *m_plugin; xine_post_api_t *m_pluginApi; @@ -57,10 +60,12 @@ void ensureInstance(); xine_audio_port_t *m_fakeAudioPort; + xine_video_port_t *m_fakeVideoPort; mutable QMutex m_mutex; const char *m_pluginName; char *m_pluginParams; QList m_parameterList; + bool m_isVideoPlugin; }; class Effect : public QObject, public EffectInterface, public SinkNode, public SourceNode --- trunk/kdesupport/phonon/xine/xinestream.cpp #1031003:1031004 @@ -143,7 +143,6 @@ SourceNodeXT("MediaObject"), m_stream(0), m_event_queue(0), - m_deinterlacer(0), m_xine(Backend::xineEngineForStream()), m_nullAudioPort(0), m_nullVideoPort(0), @@ -180,9 +179,6 @@ XineStream::~XineStream() { Q_ASSERT(QThread::currentThread() == XineThread::instance()); - if (m_deinterlacer) { - xine_post_dispose(m_xine, m_deinterlacer); - } if(m_event_queue) { xine_event_dispose_queue(m_event_queue); m_event_queue = 0; @@ -288,60 +284,7 @@ return false; } debug() << Q_FUNC_INFO << "xine_open succeeded for m_mrl =" << m_mrl.constData(); - const bool needDeinterlacer = - (m_mrl.startsWith("dvd:/") && Backend::deinterlaceDVD()) || - (m_mrl.startsWith("vcd:/") && Backend::deinterlaceVCD()) || - (m_mrl.startsWith("file:/") && Backend::deinterlaceFile()); - if (m_deinterlacer) { - if (!needDeinterlacer) { - xine_post_dispose(m_xine, m_deinterlacer); - m_deinterlacer = 0; - } - } else if (needDeinterlacer) { - xine_video_port_t *videoPort = 0; - Q_ASSERT(m_mediaObject); - QSet sinks = m_mediaObject->sinks(); - foreach (SinkNode *sink, sinks) { - Q_ASSERT(sink->threadSafeObject()); - if (sink->threadSafeObject()->videoPort()) { - Q_ASSERT(videoPort == 0); - videoPort = sink->threadSafeObject()->videoPort(); - } - } - if (!videoPort) { - debug() << Q_FUNC_INFO << "creating xine_stream with null video port"; - videoPort = nullVideoPort(); - } - m_deinterlacer = xine_post_init(m_xine, "tvtime", 1, 0, &videoPort); - if (m_deinterlacer) { - // set method - xine_post_in_t *paraInput = xine_post_input(m_deinterlacer, "parameters"); - Q_ASSERT(paraInput); - Q_ASSERT(paraInput->data); - xine_post_api_t *api = reinterpret_cast(paraInput->data); - xine_post_api_descr_t *desc = api->get_param_descr(); - char *pluginParams = static_cast(malloc(desc->struct_size)); - api->get_parameters(m_deinterlacer, pluginParams); - for (int i = 0; desc->parameter[i].type != POST_PARAM_TYPE_LAST; ++i) { - xine_post_api_parameter_t &p = desc->parameter[i]; - if (p.type == POST_PARAM_TYPE_INT && 0 == strcmp(p.name, "method")) { - int *value = reinterpret_cast(pluginParams + p.offset); - *value = Backend::deinterlaceMethod(); - break; - } - } - api->set_parameters(m_deinterlacer, pluginParams); - free(pluginParams); - // connect to xine_stream_t - xine_post_in_t *x = xine_post_input(m_deinterlacer, "video"); - Q_ASSERT(x); - xine_post_out_t *videoOutputPort = xine_get_video_source(m_stream); - Q_ASSERT(videoOutputPort); - xine_post_wire(videoOutputPort, x); - } - } - m_lastTimeUpdate.tv_sec = 0; xine_get_pos_length(m_stream, 0, &m_currentTime, &m_totalTime); getStreamInfo(); @@ -1417,10 +1360,6 @@ return true; case Event::UnloadCommand: ev->accept(); - if (m_deinterlacer) { - xine_post_dispose(m_xine, m_deinterlacer); - m_deinterlacer = 0; - } if(m_event_queue) { xine_event_dispose_queue(m_event_queue); m_event_queue = 0; @@ -1697,9 +1636,6 @@ if (!m_stream) { return 0; } - if (m_deinterlacer) { - return xine_post_output(m_deinterlacer, "deinterlaced video"); - } return xine_get_video_source(m_stream); } --- trunk/kdesupport/phonon/xine/xinestream.h #1031003:1031004 @@ -207,7 +207,6 @@ xine_stream_t *m_stream; xine_event_queue_t *m_event_queue; - xine_post_t *m_deinterlacer; mutable XineEngine m_xine; mutable xine_audio_port_t *m_nullAudioPort; mutable xine_video_port_t *m_nullVideoPort;