1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
;
50 SfxPoolItem
* MediaItem::CreateDefault() { return new MediaItem
; }
52 struct MediaItem::Impl
55 OUString m_TempFileURL
;
58 AVMediaSetMask m_nMaskSet
;
62 sal_Int16 m_nVolumeDB
;
65 css::media::ZoomLevel m_eZoom
;
68 explicit Impl(AVMediaSetMask nMaskSet
)
69 : m_nMaskSet( nMaskSet
)
70 , m_eState( MediaState::Stop
)
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
,
128 const IntlWrapper
& ) const
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
) };
153 bool MediaItem::PutValue( const css::uno::Any
& rVal
, sal_uInt8
)
155 uno::Sequence
< uno::Any
> aSeq
;
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
;
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());
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
;
231 m_pImpl
->m_URL
= rURL
;
232 m_pImpl
->m_TempFileURL
= rTempURL
;
233 m_pImpl
->m_Referer
= rReferer
;
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
;
258 m_pImpl
->m_sMimeType
= rMimeType
;
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
;
272 m_pImpl
->m_aGraphic
= rGraphic
;
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
;
283 m_pImpl
->m_eState
= eState
;
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
;
297 m_pImpl
->m_fDuration
= fDuration
;
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
;
311 m_pImpl
->m_fTime
= fTime
;
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
;
325 m_pImpl
->m_bLoop
= bLoop
;
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
;
339 m_pImpl
->m_bMute
= bMute
;
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
;
353 m_pImpl
->m_nVolumeDB
= nDB
;
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
;
367 m_pImpl
->m_eZoom
= eZoom
;
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
);
386 sal_Int32
const nSegments(xSourceURI
->getPathSegmentCount());
389 filename
= xSourceURI
->getPathSegment(nSegments
- 1);
392 if (!::comphelper::OStorageHelper::IsValidZipEntryFileName(
393 filename
, false) || !filename
.getLength())
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
))
411 sal_Int32
const nIndex(rFilename
.lastIndexOf('.'));
414 basename
= rFilename
.copy(0, nIndex
);
415 suffix
= rFilename
.copy(nIndex
);
417 sal_Int32
count(0); // sigh... try to generate non-existent name
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
),
430 uno::Reference
< beans::XPropertySet
> const xStreamProps(xStream
,
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));
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
);
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");
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
;
497 catch (uno::Exception
const&)
500 "Exception while trying to embed media");
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");
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
<< "'");
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", "");
540 o_rTempFileURL
= tempFileURL
;
544 MediaTempFile::~MediaTempFile()
546 ::osl::File::remove(m_TempFileURL
);
549 } // namespace avmedia
551 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */