Update git submodules
[LibreOffice.git] / avmedia / source / framework / mediaitem.cxx
blob0a53cf5d4d39a995bdfb26264ae3f831099cda22
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <avmedia/mediaitem.hxx>
22 #include <com/sun/star/uno/Sequence.hxx>
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/embed/ElementModes.hpp>
26 #include <com/sun/star/embed/XTransactedObject.hpp>
27 #include <com/sun/star/frame/XModel.hpp>
28 #include <com/sun/star/document/XStorageBasedDocument.hpp>
29 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
30 #include <com/sun/star/uri/UriReferenceFactory.hpp>
31 #include <com/sun/star/uri/XUriReference.hpp>
32 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
34 #include <sal/log.hxx>
36 #include <ucbhelper/content.hxx>
38 #include <comphelper/processfactory.hxx>
39 #include <comphelper/storagehelper.hxx>
40 #include <mediamisc.hxx>
41 #include <osl/file.hxx>
42 #include <tools/diagnose_ex.h>
43 #include <vcl/graph.hxx>
45 using namespace ::com::sun::star;
47 namespace avmedia
50 SfxPoolItem* MediaItem::CreateDefault() { return new MediaItem; }
52 struct MediaItem::Impl
54 OUString m_URL;
55 OUString m_TempFileURL;
56 OUString m_Referer;
57 OUString m_sMimeType;
58 AVMediaSetMask m_nMaskSet;
59 MediaState m_eState;
60 double m_fTime;
61 double m_fDuration;
62 sal_Int16 m_nVolumeDB;
63 bool m_bLoop;
64 bool m_bMute;
65 css::media::ZoomLevel m_eZoom;
66 Graphic m_aGraphic;
68 explicit Impl(AVMediaSetMask nMaskSet)
69 : m_nMaskSet( nMaskSet )
70 , m_eState( MediaState::Stop )
71 , m_fTime( 0.0 )
72 , m_fDuration( 0.0 )
73 , m_nVolumeDB( 0 )
74 , m_bLoop( false )
75 , m_bMute( false )
76 , m_eZoom( css::media::ZoomLevel_NOT_AVAILABLE )
82 MediaItem::MediaItem( sal_uInt16 i_nWhich, AVMediaSetMask nMaskSet )
83 : SfxPoolItem( i_nWhich )
84 , m_pImpl( new Impl(nMaskSet) )
89 MediaItem::MediaItem( const MediaItem& rItem )
90 : SfxPoolItem( rItem )
91 , m_pImpl( new Impl(*rItem.m_pImpl) )
96 MediaItem::~MediaItem()
101 bool MediaItem::operator==( const SfxPoolItem& rItem ) const
103 assert( SfxPoolItem::operator==(rItem));
104 MediaItem const& rOther(static_cast< const MediaItem& >(rItem));
105 return m_pImpl->m_nMaskSet == rOther.m_pImpl->m_nMaskSet
106 && m_pImpl->m_URL == rOther.m_pImpl->m_URL
107 && m_pImpl->m_Referer == rOther.m_pImpl->m_Referer
108 && m_pImpl->m_sMimeType == rOther.m_pImpl->m_sMimeType
109 && m_pImpl->m_aGraphic == rOther.m_pImpl->m_aGraphic
110 && m_pImpl->m_eState == rOther.m_pImpl->m_eState
111 && m_pImpl->m_fDuration == rOther.m_pImpl->m_fDuration
112 && m_pImpl->m_fTime == rOther.m_pImpl->m_fTime
113 && m_pImpl->m_nVolumeDB == rOther.m_pImpl->m_nVolumeDB
114 && m_pImpl->m_bLoop == rOther.m_pImpl->m_bLoop
115 && m_pImpl->m_bMute == rOther.m_pImpl->m_bMute
116 && m_pImpl->m_eZoom == rOther.m_pImpl->m_eZoom;
119 MediaItem* MediaItem::Clone( SfxItemPool* ) const
121 return new MediaItem( *this );
124 bool MediaItem::GetPresentation( SfxItemPresentation,
125 MapUnit,
126 MapUnit,
127 OUString& rText,
128 const IntlWrapper& ) const
130 rText.clear();
131 return false;
134 bool MediaItem::QueryValue( css::uno::Any& rVal, sal_uInt8 ) const
136 uno::Sequence< uno::Any > aSeq{ uno::Any(m_pImpl->m_URL),
137 uno::Any(static_cast<sal_uInt32>(m_pImpl->m_nMaskSet)),
138 uno::Any(static_cast< sal_Int32 >( m_pImpl->m_eState )),
139 uno::Any(m_pImpl->m_fTime),
140 uno::Any(m_pImpl->m_fDuration),
141 uno::Any(m_pImpl->m_nVolumeDB),
142 uno::Any(m_pImpl->m_bLoop),
143 uno::Any(m_pImpl->m_bMute),
144 uno::Any(m_pImpl->m_eZoom),
145 uno::Any(m_pImpl->m_sMimeType) };
147 rVal <<= aSeq;
149 return true;
153 bool MediaItem::PutValue( const css::uno::Any& rVal, sal_uInt8 )
155 uno::Sequence< uno::Any > aSeq;
156 bool bRet = false;
158 if( ( rVal >>= aSeq ) && ( aSeq.getLength() == 10 ) )
160 sal_Int32 nInt32 = 0;
162 aSeq[ 0 ] >>= m_pImpl->m_URL;
163 aSeq[ 1 ] >>= nInt32;
164 m_pImpl->m_nMaskSet = static_cast<AVMediaSetMask>(nInt32);
165 aSeq[ 2 ] >>= nInt32;
166 m_pImpl->m_eState = static_cast< MediaState >( nInt32 );
167 aSeq[ 3 ] >>= m_pImpl->m_fTime;
168 aSeq[ 4 ] >>= m_pImpl->m_fDuration;
169 aSeq[ 5 ] >>= m_pImpl->m_nVolumeDB;
170 aSeq[ 6 ] >>= m_pImpl->m_bLoop;
171 aSeq[ 7 ] >>= m_pImpl->m_bMute;
172 aSeq[ 8 ] >>= m_pImpl->m_eZoom;
173 aSeq[ 9 ] >>= m_pImpl->m_sMimeType;
175 bRet = true;
178 return bRet;
181 bool MediaItem::merge(const MediaItem& rMediaItem)
183 bool bChanged = false;
185 const AVMediaSetMask nMaskSet = rMediaItem.getMaskSet();
187 if( AVMediaSetMask::URL & nMaskSet )
188 bChanged |= setURL(rMediaItem.getURL(), rMediaItem.getTempURL(), rMediaItem.getReferer());
190 if( AVMediaSetMask::MIME_TYPE & nMaskSet )
191 bChanged |= setMimeType(rMediaItem.getMimeType());
193 if (nMaskSet & AVMediaSetMask::GRAPHIC)
194 bChanged |= setGraphic(rMediaItem.getGraphic());
196 if( AVMediaSetMask::STATE & nMaskSet )
197 bChanged |= setState( rMediaItem.getState() );
199 if( AVMediaSetMask::DURATION & nMaskSet )
200 bChanged |= setDuration(rMediaItem.getDuration());
202 if( AVMediaSetMask::TIME & nMaskSet )
203 bChanged |= setTime(rMediaItem.getTime());
205 if( AVMediaSetMask::LOOP & nMaskSet )
206 bChanged |= setLoop(rMediaItem.isLoop());
208 if( AVMediaSetMask::MUTE & nMaskSet )
209 bChanged |= setMute(rMediaItem.isMute());
211 if( AVMediaSetMask::VOLUMEDB & nMaskSet )
212 bChanged |= setVolumeDB(rMediaItem.getVolumeDB());
214 if( AVMediaSetMask::ZOOM & nMaskSet )
215 bChanged |= setZoom(rMediaItem.getZoom());
217 return bChanged;
220 AVMediaSetMask MediaItem::getMaskSet() const
222 return m_pImpl->m_nMaskSet;
225 bool MediaItem::setURL(const OUString& rURL, const OUString& rTempURL, const OUString& rReferer)
227 m_pImpl->m_nMaskSet |= AVMediaSetMask::URL;
228 bool bChanged = rURL != m_pImpl->m_URL || rTempURL != m_pImpl->m_TempFileURL || rReferer != m_pImpl->m_Referer;
229 if (bChanged)
231 m_pImpl->m_URL = rURL;
232 m_pImpl->m_TempFileURL = rTempURL;
233 m_pImpl->m_Referer = rReferer;
235 return bChanged;
238 const OUString& MediaItem::getURL() const
240 return m_pImpl->m_URL;
243 const OUString& MediaItem::getTempURL() const
245 return m_pImpl->m_TempFileURL;
248 const OUString& MediaItem::getReferer() const
250 return m_pImpl->m_Referer;
253 bool MediaItem::setMimeType(const OUString& rMimeType)
255 m_pImpl->m_nMaskSet |= AVMediaSetMask::MIME_TYPE;
256 bool bChanged = rMimeType != m_pImpl->m_sMimeType;
257 if (bChanged)
258 m_pImpl->m_sMimeType = rMimeType;
259 return bChanged;
262 OUString MediaItem::getMimeType() const
264 return !m_pImpl->m_sMimeType.isEmpty() ? m_pImpl->m_sMimeType : AVMEDIA_MIMETYPE_COMMON;
267 bool MediaItem::setGraphic(const Graphic& rGraphic)
269 m_pImpl->m_nMaskSet |= AVMediaSetMask::GRAPHIC;
270 bool bChanged = rGraphic != m_pImpl->m_aGraphic;
271 if (bChanged)
272 m_pImpl->m_aGraphic = rGraphic;
273 return bChanged;
276 const Graphic & MediaItem::getGraphic() const { return m_pImpl->m_aGraphic; }
278 bool MediaItem::setState(MediaState eState)
280 m_pImpl->m_nMaskSet |= AVMediaSetMask::STATE;
281 bool bChanged = eState != m_pImpl->m_eState;
282 if (bChanged)
283 m_pImpl->m_eState = eState;
284 return bChanged;
287 MediaState MediaItem::getState() const
289 return m_pImpl->m_eState;
292 bool MediaItem::setDuration(double fDuration)
294 m_pImpl->m_nMaskSet |= AVMediaSetMask::DURATION;
295 bool bChanged = fDuration != m_pImpl->m_fDuration;
296 if (bChanged)
297 m_pImpl->m_fDuration = fDuration;
298 return bChanged;
301 double MediaItem::getDuration() const
303 return m_pImpl->m_fDuration;
306 bool MediaItem::setTime(double fTime)
308 m_pImpl->m_nMaskSet |= AVMediaSetMask::TIME;
309 bool bChanged = fTime != m_pImpl->m_fTime;
310 if (bChanged)
311 m_pImpl->m_fTime = fTime;
312 return bChanged;
315 double MediaItem::getTime() const
317 return m_pImpl->m_fTime;
320 bool MediaItem::setLoop(bool bLoop)
322 m_pImpl->m_nMaskSet |= AVMediaSetMask::LOOP;
323 bool bChanged = bLoop != m_pImpl->m_bLoop;
324 if (bChanged)
325 m_pImpl->m_bLoop = bLoop;
326 return bChanged;
329 bool MediaItem::isLoop() const
331 return m_pImpl->m_bLoop;
334 bool MediaItem::setMute(bool bMute)
336 m_pImpl->m_nMaskSet |= AVMediaSetMask::MUTE;
337 bool bChanged = bMute != m_pImpl->m_bMute;
338 if (bChanged)
339 m_pImpl->m_bMute = bMute;
340 return bChanged;
343 bool MediaItem::isMute() const
345 return m_pImpl->m_bMute;
348 bool MediaItem::setVolumeDB(sal_Int16 nDB)
350 m_pImpl->m_nMaskSet |= AVMediaSetMask::VOLUMEDB;
351 bool bChanged = nDB != m_pImpl->m_nVolumeDB;
352 if (bChanged)
353 m_pImpl->m_nVolumeDB = nDB;
354 return bChanged;
357 sal_Int16 MediaItem::getVolumeDB() const
359 return m_pImpl->m_nVolumeDB;
362 bool MediaItem::setZoom(css::media::ZoomLevel eZoom)
364 m_pImpl->m_nMaskSet |= AVMediaSetMask::ZOOM;
365 bool bChanged = eZoom != m_pImpl->m_eZoom;
366 if (bChanged)
367 m_pImpl->m_eZoom = eZoom;
368 return bChanged;
371 css::media::ZoomLevel MediaItem::getZoom() const
373 return m_pImpl->m_eZoom;
376 OUString GetFilename(OUString const& rSourceURL)
378 uno::Reference<uri::XUriReferenceFactory> const xUriFactory(
379 uri::UriReferenceFactory::create(
380 comphelper::getProcessComponentContext()));
381 uno::Reference<uri::XUriReference> const xSourceURI(
382 xUriFactory->parse(rSourceURL), uno::UNO_SET_THROW);
384 OUString filename;
386 sal_Int32 const nSegments(xSourceURI->getPathSegmentCount());
387 if (0 < nSegments)
389 filename = xSourceURI->getPathSegment(nSegments - 1);
392 if (!::comphelper::OStorageHelper::IsValidZipEntryFileName(
393 filename, false) || !filename.getLength())
395 filename = "media";
397 return filename;
401 uno::Reference<io::XStream>
402 CreateStream(uno::Reference<embed::XStorage> const& xStorage,
403 OUString const& rFilename)
405 OUString filename(rFilename);
407 if (xStorage->hasByName(filename))
409 OUString basename;
410 OUString suffix;
411 sal_Int32 const nIndex(rFilename.lastIndexOf('.'));
412 if (0 < nIndex)
414 basename = rFilename.copy(0, nIndex);
415 suffix = rFilename.copy(nIndex);
417 sal_Int32 count(0); // sigh... try to generate non-existent name
420 ++count;
421 filename = basename + OUString::number(count) + suffix;
423 while (xStorage->hasByName(filename));
426 uno::Reference<io::XStream> const xStream(
427 xStorage->openStreamElement(filename,
428 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE),
429 uno::UNO_SET_THROW);
430 uno::Reference< beans::XPropertySet > const xStreamProps(xStream,
431 uno::UNO_QUERY);
432 if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
433 xStreamProps->setPropertyValue("MediaType", uno::Any(OUString(
434 //FIXME how to detect real media type?
435 //but currently xmloff has this one hardcoded anyway...
436 "application/vnd.sun.star.media")));
437 xStreamProps->setPropertyValue( // turn off compression
438 "Compressed", uno::Any(false));
440 return xStream;
444 bool EmbedMedia(uno::Reference<frame::XModel> const& xModel,
445 OUString const& rSourceURL, OUString & o_rEmbeddedURL, uno::Reference<io::XInputStream> const& xInputStream)
449 uno::Reference<document::XStorageBasedDocument> const xSBD(xModel,
450 uno::UNO_QUERY_THROW);
451 uno::Reference<embed::XStorage> const xStorage(
452 xSBD->getDocumentStorage(), uno::UNO_SET_THROW);
454 OUString const media("Media");
455 uno::Reference<embed::XStorage> const xSubStorage(
456 xStorage->openStorageElement(media, embed::ElementModes::WRITE));
458 OUString filename(GetFilename(rSourceURL));
460 uno::Reference<io::XStream> const xStream(
461 CreateStream(xSubStorage, filename), uno::UNO_SET_THROW);
462 uno::Reference<io::XOutputStream> const xOutStream(
463 xStream->getOutputStream(), uno::UNO_SET_THROW);
465 if (xInputStream.is())
467 // Throw Exception if failed.
468 ::comphelper::OStorageHelper::CopyInputToOutput(xInputStream, xOutStream);
470 else
472 ::ucbhelper::Content sourceContent(rSourceURL,
473 uno::Reference<ucb::XCommandEnvironment>(),
474 comphelper::getProcessComponentContext());
476 if (!sourceContent.openStream(xOutStream)) // copy file to storage
478 SAL_INFO("avmedia", "openStream to storage failed");
479 return false;
483 uno::Reference<embed::XTransactedObject> const xSubTransaction(
484 xSubStorage, uno::UNO_QUERY);
485 if (xSubTransaction.is()) {
486 xSubTransaction->commit();
488 uno::Reference<embed::XTransactedObject> const xTransaction(
489 xStorage, uno::UNO_QUERY);
490 if (xTransaction.is()) {
491 xTransaction->commit();
494 o_rEmbeddedURL = "vnd.sun.star.Package:" + media + "/" + filename;
495 return true;
497 catch (uno::Exception const&)
499 SAL_WARN("avmedia",
500 "Exception while trying to embed media");
502 return false;
505 bool CreateMediaTempFile(uno::Reference<io::XInputStream> const& xInStream,
506 OUString& o_rTempFileURL, std::u16string_view rDesiredExtension)
508 OUString tempFileURL;
509 ::osl::FileBase::RC const err =
510 ::osl::FileBase::createTempFile(nullptr, nullptr, & tempFileURL);
511 if (::osl::FileBase::E_None != err)
513 SAL_WARN("avmedia", "cannot create temp file");
514 return false;
517 if (!rDesiredExtension.empty())
519 OUString newTempFileURL = tempFileURL + rDesiredExtension;
520 if (osl::File::move(tempFileURL, newTempFileURL) != osl::FileBase::E_None)
522 SAL_WARN("avmedia", "Could not rename file '" << tempFileURL << "' to '" << newTempFileURL << "'");
523 return false;
525 tempFileURL = newTempFileURL;
530 ::ucbhelper::Content tempContent(tempFileURL,
531 uno::Reference<ucb::XCommandEnvironment>(),
532 comphelper::getProcessComponentContext());
533 tempContent.writeStream(xInStream, true); // copy stream to file
535 catch (uno::Exception const&)
537 TOOLS_WARN_EXCEPTION("avmedia", "");
538 return false;
540 o_rTempFileURL = tempFileURL;
541 return true;
544 MediaTempFile::~MediaTempFile()
546 ::osl::File::remove(m_TempFileURL);
549 } // namespace avmedia
551 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */