From 91653df0bf9abad5d67635db6576a559f742576c Mon Sep 17 00:00:00 2001
From: Miklos Vajna <vmiklos@collabora.com>
Date: Wed, 24 Aug 2022 13:53:38 +0200
Subject: [PATCH] Related: tdf#149971 svx: support explicitly provided
 snapshots for media shapes

Snapshots / previews for media objects are used when the shape's video
is not playing. This is generated by seeking to the 3rd second in the
video, probably to avoid initial black frames.

The trouble is that PowerPoint takes the initial frame (at least in case
of the bugdoc), so our snapshot doesn't match the reference.

We already import a bitmap snapshot from PPTX files since commit
e2d46da076f43a7c0d56fc486b9f15339243f7c9 (avmedia: add doc model for
bitmap fill of slide narrations, 2021-01-21), fix the problem by
changing the snapshot generation to prefer this bitmap over generating
one from the video.

The crop properties of this bitmap / the video are still not yet handled
from PPTX.

(cherry picked from commit 8fa1d453c94cdbb03dac646fb8db2ebd1a0e84bd)

Change-Id: Id985eaaaad5e4222d9a98203d054e08a0f97a0f7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138967
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
---
 svx/source/svdraw/svdomedia.cxx      |   9 +++++++++
 3 files changed, 32 insertions(+)
 create mode 100644 svx/qa/unit/data/video-snapshot.pptx

diff --git a/svx/source/svdraw/svdomedia.cxx b/svx/source/svdraw/svdomedia.cxx
index bc030c7d6d3f..96d12027a060 100644
--- a/svx/source/svdraw/svdomedia.cxx
+++ b/svx/source/svdraw/svdomedia.cxx
@@ -143,6 +143,15 @@ uno::Reference< graphic::XGraphic > const & SdrMediaObj::getSnapshot() const
 #if HAVE_FEATURE_AVMEDIA
     if( !m_xImpl->m_xCachedSnapshot.is() )
     {
+        Graphic aGraphic = m_xImpl->m_MediaProperties.getGraphic();
+        if (!aGraphic.IsNone())
+        {
+            // We have an explicit graphic for this media object, then go with that instead of
+            // generating our own one.
+            m_xImpl->m_xCachedSnapshot = aGraphic.GetXGraphic();
+            return m_xImpl->m_xCachedSnapshot;
+        }
+
         OUString aRealURL = m_xImpl->m_MediaProperties.getTempURL();
         if( aRealURL.isEmpty() )
             aRealURL = m_xImpl->m_MediaProperties.getURL();
--
2.35.3

From 2a0c3f70aca0493f334d2af59a2dc23727e571ff Mon Sep 17 00:00:00 2001
From: Miklos Vajna <vmiklos@collabora.com>
Date: Thu, 25 Aug 2022 14:01:43 +0200
Subject: [PATCH] Related: tdf#149971 avmedia: add doc model and render for
 crop of media objects

It is possible to provide an explicit preview of media objects since
commit 8fa1d453c94cdbb03dac646fb8db2ebd1a0e84bd (Related: tdf#149971
svx: support explicitly provided snapshots for media shapes,
2022-08-24), however they can't be cropped.

This means that media shapes from PPTX with cropping show unexpected
content and can also have a buggy aspect ratio.

Extend avmedia::MediaItem to store cropping and take it into account
when returning the preview bitmap in SdrMediaObj::getSnapshot(). PPTX
import works out of the box, as oox/ already tried to set a cropping
property on the media shape.

This is just the preview, the cropping of the video itself is not yet
implemented.

(cherry picked from commit b6f0fd6a2f459ead2268e07bfd86db7e303b323f)

Conflicts:
	svx/source/unodraw/unoprov.cxx

Change-Id: I8db3e0dcf252613d56eb0e6139adf097e53b15cc
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138968
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
---
 avmedia/source/framework/mediaitem.cxx |  17 +++++++++++++++
 include/avmedia/mediaitem.hxx          |   8 +++++--
 svx/source/svdraw/svdomedia.cxx        |  21 +++++++++++++++++++
 svx/source/unodraw/unoprov.cxx         |   1 +
 svx/source/unodraw/unoshap4.cxx        |  28 +++++++++++++++++++++++--
 7 files changed, 77 insertions(+), 4 deletions(-)

diff --git a/avmedia/source/framework/mediaitem.cxx b/avmedia/source/framework/mediaitem.cxx
index 0a53cf5d4d39..ac8c09b79871 100644
--- a/avmedia/source/framework/mediaitem.cxx
+++ b/avmedia/source/framework/mediaitem.cxx
@@ -30,6 +30,7 @@
 #include <com/sun/star/uri/UriReferenceFactory.hpp>
 #include <com/sun/star/uri/XUriReference.hpp>
 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
+#include <com/sun/star/text/GraphicCrop.hpp>

 #include <sal/log.hxx>

@@ -64,6 +65,7 @@ struct MediaItem::Impl
     bool                    m_bMute;
     css::media::ZoomLevel m_eZoom;
     Graphic m_aGraphic;
+    text::GraphicCrop m_aCrop;

     explicit Impl(AVMediaSetMask nMaskSet)
         : m_nMaskSet( nMaskSet )
@@ -107,6 +109,7 @@ bool MediaItem::operator==( const SfxPoolItem& rItem ) const
         && m_pImpl->m_Referer == rOther.m_pImpl->m_Referer
         && m_pImpl->m_sMimeType == rOther.m_pImpl->m_sMimeType
         && m_pImpl->m_aGraphic == rOther.m_pImpl->m_aGraphic
+        && m_pImpl->m_aCrop == rOther.m_pImpl->m_aCrop
         && m_pImpl->m_eState == rOther.m_pImpl->m_eState
         && m_pImpl->m_fDuration == rOther.m_pImpl->m_fDuration
         && m_pImpl->m_fTime == rOther.m_pImpl->m_fTime
@@ -193,6 +196,9 @@ bool MediaItem::merge(const MediaItem& rMediaItem)
     if (nMaskSet & AVMediaSetMask::GRAPHIC)
         bChanged |= setGraphic(rMediaItem.getGraphic());

+    if (nMaskSet & AVMediaSetMask::CROP)
+        bChanged |= setCrop(rMediaItem.getCrop());
+
     if( AVMediaSetMask::STATE & nMaskSet )
         bChanged |= setState( rMediaItem.getState() );

@@ -275,6 +281,17 @@ bool MediaItem::setGraphic(const Graphic& rGraphic)

 const Graphic & MediaItem::getGraphic() const { return m_pImpl->m_aGraphic; }

+bool MediaItem::setCrop(const text::GraphicCrop& rCrop)
+{
+    m_pImpl->m_nMaskSet |= AVMediaSetMask::CROP;
+    bool bChanged = rCrop != m_pImpl->m_aCrop;
+    if (bChanged)
+        m_pImpl->m_aCrop = rCrop;
+    return bChanged;
+}
+
+const text::GraphicCrop& MediaItem::getCrop() const { return m_pImpl->m_aCrop; }
+
 bool MediaItem::setState(MediaState eState)
 {
     m_pImpl->m_nMaskSet |= AVMediaSetMask::STATE;
diff --git a/include/avmedia/mediaitem.hxx b/include/avmedia/mediaitem.hxx
index ab9418607cb7..9578974aaa99 100644
--- a/include/avmedia/mediaitem.hxx
+++ b/include/avmedia/mediaitem.hxx
@@ -32,6 +32,7 @@ namespace com::sun::star::embed { class XStorage; }
 namespace com::sun::star::frame { class XModel; }
 namespace com::sun::star::io { class XInputStream; }
 namespace com::sun::star::io { class XStream; }
+namespace com::sun::star::text { struct GraphicCrop; }
 class Graphic;

 enum class AVMediaSetMask
@@ -47,11 +48,12 @@ enum class AVMediaSetMask
     URL         = 0x080,
     MIME_TYPE   = 0x100,
     GRAPHIC     = 0x200,
-    ALL         = 0x3ff,
+    CROP        = 0x400,
+    ALL         = 0x7ff,
 };
 namespace o3tl
 {
-    template<> struct typed_flags<AVMediaSetMask> : is_typed_flags<AVMediaSetMask, 0x3ff> {};
+    template<> struct typed_flags<AVMediaSetMask> : is_typed_flags<AVMediaSetMask, 0x7ff> {};
 }


@@ -119,6 +121,8 @@ public:
     OUString                getMimeType() const;
     bool setGraphic(const Graphic& rGraphic);
     const Graphic & getGraphic() const;
+    bool setCrop(const css::text::GraphicCrop& rCrop);
+    const css::text::GraphicCrop& getCrop() const;
     const OUString&         getTempURL() const;

     const OUString&         getReferer() const;
diff --git a/svx/source/svdraw/svdomedia.cxx b/svx/source/svdraw/svdomedia.cxx
index 96d12027a060..cb78eee47766 100644
--- a/svx/source/svdraw/svdomedia.cxx
+++ b/svx/source/svdraw/svdomedia.cxx
@@ -21,6 +21,8 @@

 #include <svx/svdomedia.hxx>

+#include <com/sun/star/text/GraphicCrop.hpp>
+
 #include <rtl/ustring.hxx>
 #include <rtl/ustrbuf.hxx>
 #include <sal/log.hxx>
@@ -146,6 +148,20 @@ uno::Reference< graphic::XGraphic > const & SdrMediaObj::getSnapshot() const
         Graphic aGraphic = m_xImpl->m_MediaProperties.getGraphic();
         if (!aGraphic.IsNone())
         {
+            Size aPref = aGraphic.GetPrefSize();
+            Size aPixel = aGraphic.GetSizePixel();
+            const text::GraphicCrop& rCrop = m_xImpl->m_MediaProperties.getCrop();
+            if (rCrop.Bottom > 0 || rCrop.Left > 0 || rCrop.Right > 0 || rCrop.Top > 0)
+            {
+                tools::Long nLeft = aPixel.getWidth() * rCrop.Left / aPref.getWidth();
+                tools::Long nTop = aPixel.getHeight() * rCrop.Top / aPref.getHeight();
+                tools::Long nRight = aPixel.getWidth() * rCrop.Right / aPref.getWidth();
+                tools::Long nBottom = aPixel.getHeight() * rCrop.Bottom / aPref.getHeight();
+                BitmapEx aBitmapEx = aGraphic.GetBitmapEx();
+                aBitmapEx.Crop({nLeft, nTop, aPixel.getWidth() - nRight, aPixel.getHeight() - nBottom});
+                aGraphic = aBitmapEx;
+            }
+
             // We have an explicit graphic for this media object, then go with that instead of
             // generating our own one.
             m_xImpl->m_xCachedSnapshot = aGraphic.GetXGraphic();
@@ -338,6 +354,11 @@ void SdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem& rNewProper
         m_xImpl->m_MediaProperties.setGraphic(rNewProperties.getGraphic());
     }

+    if (nMaskSet & AVMediaSetMask::CROP)
+    {
+        m_xImpl->m_MediaProperties.setCrop(rNewProperties.getCrop());
+    }
+
     if( ( AVMediaSetMask::URL & nMaskSet ) &&
         ( rNewProperties.getURL() != getURL() ))
     {
diff --git a/svx/source/unodraw/unoprov.cxx b/svx/source/unodraw/unoprov.cxx
index b459280c8b01..55631bdbc200 100644
--- a/svx/source/unodraw/unoprov.cxx
+++ b/svx/source/unodraw/unoprov.cxx
@@ -736,6 +736,7 @@ static SfxItemPropertyMapEntry const * ImplGetSvxMediaShapePropertyMap()
         { u"MediaMimeType", OWN_ATTR_MEDIA_MIMETYPE, cppu::UnoType<OUString>::get(), 0, 0},
         { u"FallbackGraphic", OWN_ATTR_FALLBACK_GRAPHIC, cppu::UnoType<css::graphic::XGraphic>::get(), css::beans::PropertyAttribute::READONLY, 0},
         { u"" UNO_NAME_GRAPHOBJ_GRAPHIC,   OWN_ATTR_VALUE_GRAPHIC     , cppu::UnoType<css::graphic::XGraphic>::get(), 0, 0},
+        { u"" UNO_NAME_GRAPHIC_GRAPHICCROP, SDRATTR_GRAFCROP     , cppu::UnoType<css::text::GraphicCrop>::get(), 0, 0},
         { u"", 0, css::uno::Type(), 0, 0 }
     };

diff --git a/svx/source/unodraw/unoshap4.cxx b/svx/source/unodraw/unoshap4.cxx
index 865ce0a3ee5b..50a2a7a09a12 100644
--- a/svx/source/unodraw/unoshap4.cxx
+++ b/svx/source/unodraw/unoshap4.cxx
@@ -783,7 +783,8 @@ bool SvxMediaShape::setPropertyValueImpl( const OUString& rName, const SfxItemPr
     if( ((pProperty->nWID >= OWN_ATTR_MEDIA_URL) && (pProperty->nWID <= OWN_ATTR_MEDIA_ZOOM))
         || (pProperty->nWID == OWN_ATTR_MEDIA_STREAM)
         || (pProperty->nWID == OWN_ATTR_MEDIA_MIMETYPE)
-        || (pProperty->nWID == OWN_ATTR_VALUE_GRAPHIC))
+        || (pProperty->nWID == OWN_ATTR_VALUE_GRAPHIC)
+        || (pProperty->nWID == SDRATTR_GRAFCROP))
     {
         SdrMediaObj* pMedia = static_cast< SdrMediaObj* >( GetSdrObject() );
         ::avmedia::MediaItem aItem;
@@ -886,6 +887,19 @@ bool SvxMediaShape::setPropertyValueImpl( const OUString& rName, const SfxItemPr
 #endif
         break;

+        case SDRATTR_GRAFCROP:
+#if HAVE_FEATURE_AVMEDIA
+        {
+            text::GraphicCrop aCrop;
+            if (rValue >>= aCrop)
+            {
+                bOk = true;
+                aItem.setCrop(aCrop);
+            }
+        }
+#endif
+        break;
+
         case OWN_ATTR_MEDIA_STREAM:
 #if HAVE_FEATURE_AVMEDIA
             try
@@ -942,7 +956,8 @@ bool SvxMediaShape::getPropertyValueImpl( const OUString& rName, const SfxItemPr
         || (pProperty->nWID == OWN_ATTR_MEDIA_TEMPFILEURL)
         || (pProperty->nWID == OWN_ATTR_MEDIA_MIMETYPE)
         || (pProperty->nWID == OWN_ATTR_FALLBACK_GRAPHIC)
-        || (pProperty->nWID == OWN_ATTR_VALUE_GRAPHIC))
+        || (pProperty->nWID == OWN_ATTR_VALUE_GRAPHIC)
+        || (pProperty->nWID == SDRATTR_GRAFCROP))
     {
         SdrMediaObj* pMedia = static_cast< SdrMediaObj* >( GetSdrObject() );
         const ::avmedia::MediaItem aItem( pMedia->getMediaProperties() );
@@ -1025,6 +1040,15 @@ bool SvxMediaShape::getPropertyValueImpl( const OUString& rName, const SfxItemPr
 #endif
             break;

+            case SDRATTR_GRAFCROP:
+#if HAVE_FEATURE_AVMEDIA
+            {
+                text::GraphicCrop aCrop = aItem.getCrop();
+                rValue <<= aCrop;
+            }
+#endif
+            break;
+
             case OWN_ATTR_FALLBACK_GRAPHIC:
                 rValue <<= pMedia->getSnapshot();
                 break;
--
2.35.3

From 6894da107db06c66356e52844c4a8d263e0a64d8 Mon Sep 17 00:00:00 2001
From: Miklos Vajna <vmiklos@collabora.com>
Date: Fri, 26 Aug 2022 10:24:39 +0200
Subject: [PATCH] tdf#149971 avmedia: implement video crop support in the
 gsteamer backend

If a media shape had cropping defined, we already took that into account
when presenting a preview for it, but not during video playback.

The reason for this is that the preview may be set by a file importer
(e.g. PPTX) explicitly, in which case the preview is a bitmap we get
without any video processing.

As a start, implement video crop for the gstreamer backend (used on
Linux), and also pass in the media item (containing crop and other
properties) both during the edit view (MediaWindowImpl) and presenting
(ViewMediaShape). We pass in the whole media item, so in case later
other filters (e.g. black-and-white) are wanted, we have all that info
in the backends already.

Other backends (avmediaMacAVF and avmediawin) are untouched so far.
svx/qa/unit/data/video-snapshot.pptx is modified to have a yellow border
when cropping is unimplemented, which is now not visible with the
gtreamer backend, matching PowerPoint behavior. PPTX export was working
out of the box already.

(cherry picked from commit 916848d877a788d02e2e7c980872314839101798)

Conflicts:
	avmedia/source/viewer/mediawindow_impl.cxx

Change-Id: If26b7a4391bcffe9cbddd9933e1bab69be52924e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138969
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
---
 avmedia/Library_avmediagst.mk                 |   1 +
 avmedia/source/gstreamer/gstplayer.cxx        |  30 ++++++++++++++++++
 avmedia/source/viewer/mediawindow_impl.cxx    |   8 ++++-
 avmedia/source/viewer/mediawindow_impl.hxx    |   1 +
 .../source/engine/shapes/viewmediashape.cxx   |  14 +++++++-
 7 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/avmedia/Library_avmediagst.mk b/avmedia/Library_avmediagst.mk
index 699d0197b50e..93ad7514f94b 100644
--- a/avmedia/Library_avmediagst.mk
+++ b/avmedia/Library_avmediagst.mk
@@ -33,6 +33,7 @@ $(eval $(call gb_Library_use_libraries,avmediagst,\
 	salhelper \
 	tl \
 	vcl \
+	avmedia \
 ))

 $(eval $(call gb_Library_add_exception_objects,avmediagst,\
diff --git a/avmedia/source/gstreamer/gstplayer.cxx b/avmedia/source/gstreamer/gstplayer.cxx
index 397fe8809d93..6884654b6be3 100644
--- a/avmedia/source/gstreamer/gstplayer.cxx
+++ b/avmedia/source/gstreamer/gstplayer.cxx
@@ -29,6 +29,8 @@
 #include <vector>
 #include <math.h>

+#include <com/sun/star/text/GraphicCrop.hpp>
+
 #include <cppuhelper/supportsservice.hxx>
 #include <sal/log.hxx>
 #include <rtl/string.hxx>
@@ -36,6 +38,8 @@
 #include <vcl/svapp.hxx>
 #include <vcl/syschild.hxx>
 #include <vcl/sysdata.hxx>
+#include <vcl/graph.hxx>
+#include <avmedia/mediaitem.hxx>

 #include "gstplayer.hxx"
 #include "gstframegrabber.hxx"
@@ -866,6 +870,32 @@ uno::Reference< ::media::XPlayerWindow > SAL_CALL Player::createPlayerWindow( co
         g_object_set(G_OBJECT(mpPlaybin), "video-sink", pVideosink, nullptr);
         g_object_set(G_OBJECT(mpPlaybin), "force-aspect-ratio", FALSE, nullptr);

+        if ((rArguments.getLength() >= 4) && (rArguments[3] >>= pIntPtr) && pIntPtr)
+        {
+            auto pItem = reinterpret_cast<const avmedia::MediaItem*>(pIntPtr);
+            Graphic aGraphic = pItem->getGraphic();
+            const text::GraphicCrop& rCrop = pItem->getCrop();
+            if (!aGraphic.IsNone() && (rCrop.Bottom > 0 || rCrop.Left > 0 || rCrop.Right > 0 || rCrop.Top > 0))
+            {
+                // The media item has a non-empty cropping set. Try to crop the video accordingly.
+                Size aPref = aGraphic.GetPrefSize();
+                Size aPixel = aGraphic.GetSizePixel();
+                tools::Long nLeft = aPixel.getWidth() * rCrop.Left / aPref.getWidth();
+                tools::Long nTop = aPixel.getHeight() * rCrop.Top / aPref.getHeight();
+                tools::Long nRight = aPixel.getWidth() * rCrop.Right / aPref.getWidth();
+                tools::Long nBottom = aPixel.getHeight() * rCrop.Bottom / aPref.getHeight();
+                GstElement* pVideoFilter = gst_element_factory_make("videocrop", nullptr);
+                if (pVideoFilter)
+                {
+                    g_object_set(G_OBJECT(pVideoFilter), "left", nLeft, nullptr);
+                    g_object_set(G_OBJECT(pVideoFilter), "top", nTop, nullptr);
+                    g_object_set(G_OBJECT(pVideoFilter), "right", nRight, nullptr);
+                    g_object_set(G_OBJECT(pVideoFilter), "bottom", nBottom, nullptr);
+                    g_object_set(G_OBJECT(mpPlaybin), "video-filter", pVideoFilter, nullptr);
+                }
+            }
+        }
+
         if (!mbUseGtkSink)
         {
             mnWindowID = pEnvData->GetWindowHandle(pParentWindow->ImplGetFrame());
diff --git a/avmedia/source/viewer/mediawindow_impl.cxx b/avmedia/source/viewer/mediawindow_impl.cxx
index fcc06488e913..0a0e80dc0d3f 100644
--- a/avmedia/source/viewer/mediawindow_impl.cxx
+++ b/avmedia/source/viewer/mediawindow_impl.cxx
@@ -30,6 +30,7 @@
 #include <sal/log.hxx>
 #include <comphelper/processfactory.hxx>
 #include <tools/diagnose_ex.h>
+#include <comphelper/scopeguard.hxx>
 #include <tools/urlobj.hxx>
 #include <unotools/securityoptions.hxx>
 #include <vcl/bitmapex.hxx>
@@ -307,6 +308,9 @@ void MediaWindowImpl::updateMediaItem( MediaItem& rItem ) const

 void MediaWindowImpl::executeMediaItem( const MediaItem& rItem )
 {
+    mpItem = &rItem;
+    comphelper::ScopeGuard g([this] { this->mpItem = nullptr; });
+
     const AVMediaSetMask nMaskSet = rItem.getMaskSet();

     // set URL first
@@ -427,7 +431,9 @@ void MediaWindowImpl::onURLChanged()
         uno::Sequence<uno::Any> aArgs{
             uno::Any(nParentWindowHandle),
             uno::Any(awt::Rectangle(aPoint.X(), aPoint.Y(), aSize.Width(), aSize.Height())),
-            uno::Any(reinterpret_cast<sal_IntPtr>(mpChildWindow.get()))
+            uno::Any(reinterpret_cast<sal_IntPtr>(mpChildWindow.get())),
+            // Media item contains media properties, e.g. cropping.
+            uno::Any(reinterpret_cast<sal_IntPtr>(mpItem))
         };

         try
diff --git a/avmedia/source/viewer/mediawindow_impl.hxx b/avmedia/source/viewer/mediawindow_impl.hxx
index 8bceebb08d15..aa95fde22444 100644
--- a/avmedia/source/viewer/mediawindow_impl.hxx
+++ b/avmedia/source/viewer/mediawindow_impl.hxx
@@ -150,6 +150,7 @@ private:
     VclPtr<MediaWindowControl> mpMediaWindowControl;
     std::unique_ptr<BitmapEx> mpEmptyBmpEx;
     std::unique_ptr<BitmapEx> mpAudioBmpEx;
+    const MediaItem* mpItem = nullptr;
 };

 }} // end namespace avmedia::priv
diff --git a/slideshow/source/engine/shapes/viewmediashape.cxx b/slideshow/source/engine/shapes/viewmediashape.cxx
index 52a86be889d7..0b24b12b2812 100644
--- a/slideshow/source/engine/shapes/viewmediashape.cxx
+++ b/slideshow/source/engine/shapes/viewmediashape.cxx
@@ -36,6 +36,8 @@
 #include <canvas/canvastools.hxx>
 #include <cppcanvas/canvas.hxx>
 #include <avmedia/mediawindow.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdomedia.hxx>

 #include <com/sun/star/awt/XWindow.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
@@ -441,10 +443,20 @@ namespace slideshow::internal

                             aAWTRect.X = aAWTRect.Y = 0;

+                            SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape);
+                            auto pMediaObj = dynamic_cast<SdrMediaObj*>(pObj);
+                            const avmedia::MediaItem* pMediaItem = nullptr;
+                            if (pMediaObj)
+                            {
+                                pMediaItem = &pMediaObj->getMediaProperties();
+                            }
+
                             uno::Sequence< uno::Any >   aArgs{
                                 uno::Any(nParentWindowHandle),
                                 uno::Any(aAWTRect),
-                                uno::Any(reinterpret_cast< sal_IntPtr >( mpMediaWindow.get() ))
+                                uno::Any(reinterpret_cast< sal_IntPtr >( mpMediaWindow.get() )),
+                                // Media item contains media properties, e.g. cropping.
+                                uno::Any(reinterpret_cast< sal_IntPtr >( pMediaItem ))
                             };

                             mxPlayerWindow.set( mxPlayer->createPlayerWindow( aArgs ) );
--
2.35.3

From 3b88c304dce2e9d64b9d19b25ed57df5b581e834 Mon Sep 17 00:00:00 2001
From: Miklos Vajna <vmiklos@collabora.com>
Date: Mon, 29 Aug 2022 09:23:22 +0200
Subject: [PATCH] avmedia: implement video crop support in the ODP filter

And also import/export the video preview as well. The naming follows the
style used for table shape previews.

The preview is important, since the cropping is relative to the bitmap's
preferred logic size.

(cherry picked from commit cbc6e67d3c88fb6ae39c304604a98eaa504f19cc)

Conflicts:
	xmloff/qa/unit/draw.cxx
	xmloff/source/draw/shapeexport.cxx

Change-Id: I6115284c1f4cf342b3296cd0ac3beb70a809fd1b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138970
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
---
 include/svx/unoshape.hxx               |   2 +
 svx/source/unodraw/unoshap4.cxx        |  25 ++++++++++++
 xmloff/source/draw/shapeexport.cxx     |  54 ++++++++++++++++++++++++-
 xmloff/source/draw/ximpshap.cxx        |  14 ++++++-
 7 files changed, 146 insertions(+), 2 deletions(-)
 create mode 100644 xmloff/qa/unit/data/video-snapshot.odp

diff --git a/include/svx/unoshape.hxx b/include/svx/unoshape.hxx
index 3d3d5bea3a9b..b8d50458a4a1 100644
--- a/include/svx/unoshape.hxx
+++ b/include/svx/unoshape.hxx
@@ -843,6 +843,8 @@ private:
     // override these for special property handling in subcasses. Return true if property is handled
     virtual bool setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue ) override;
     virtual bool getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue ) override;
+    bool getPropertyStateImpl(const SfxItemPropertyMapEntry* pProperty,
+                              css::beans::PropertyState& rState) override;

     OUString referer_;
 };
diff --git a/svx/source/unodraw/unoshap4.cxx b/svx/source/unodraw/unoshap4.cxx
index 50a2a7a09a12..a5f2516161ac 100644
--- a/svx/source/unodraw/unoshap4.cxx
+++ b/svx/source/unodraw/unoshap4.cxx
@@ -1064,4 +1064,29 @@ bool SvxMediaShape::getPropertyValueImpl( const OUString& rName, const SfxItemPr
     }
 }

+bool SvxMediaShape::getPropertyStateImpl(const SfxItemPropertyMapEntry* pProperty,
+                                         css::beans::PropertyState& rState)
+{
+#if HAVE_FEATURE_AVMEDIA
+    if (pProperty->nWID == SDRATTR_GRAFCROP)
+    {
+        auto pMedia = static_cast<SdrMediaObj*>(GetSdrObject());
+        const avmedia::MediaItem& rItem = pMedia->getMediaProperties();
+        const text::GraphicCrop& rCrop = rItem.getCrop();
+        if (rCrop.Bottom > 0 || rCrop.Left > 0 || rCrop.Right > 0 || rCrop.Top > 0)
+        {
+            // The media has a crop, expose it to UNO-based export filters.
+            rState = beans::PropertyState_DIRECT_VALUE;
+        }
+        else
+        {
+            rState = beans::PropertyState_AMBIGUOUS_VALUE;
+        }
+        return true;
+    }
+#endif
+
+    return SvxShape::getPropertyStateImpl(pProperty, rState);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/draw/shapeexport.cxx b/xmloff/source/draw/shapeexport.cxx
index d47ea15b2758..0f3e86ee8d5a 100644
--- a/xmloff/source/draw/shapeexport.cxx
+++ b/xmloff/source/draw/shapeexport.cxx
@@ -99,6 +99,7 @@
 #include <tools/globname.hxx>
 #include <tools/helpers.hxx>
 #include <tools/diagnose_ex.h>
+#include <vcl/graph.hxx>

 #include <xmloff/contextid.hxx>
 #include <xmloff/families.hxx>
@@ -3387,7 +3388,7 @@ void XMLShapeExport::ImpExportMediaShape(
     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, sMimeType );

     // write plugin
-    SvXMLElementExport aPluginOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true);
+    auto pPluginOBJ = std::make_unique<SvXMLElementExport>(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true);

     // export parameters
     const OUString aFalseStr(  "false"  ), aTrueStr(  "true"  );
@@ -3437,6 +3438,57 @@ void XMLShapeExport::ImpExportMediaShape(
         delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
     }

+    pPluginOBJ.reset();
+
+    uno::Reference<graphic::XGraphic> xGraphic;
+    xPropSet->getPropertyValue("Graphic") >>= xGraphic;
+    Graphic aGraphic(xGraphic);
+    if (!aGraphic.IsNone())
+    {
+        // The media has a preview, export it.
+        uno::Reference<embed::XStorage> xPictureStorage;
+        uno::Reference<embed::XStorage> xStorage;
+        uno::Reference<io::XStream> xPictureStream;
+        OUString sPictureName;
+        xStorage.set(GetExport().GetTargetStorage(), uno::UNO_SET_THROW);
+        xPictureStorage.set(
+            xStorage->openStorageElement("Pictures", embed::ElementModes::READWRITE),
+            uno::UNO_SET_THROW);
+        sal_Int32 nIndex = 0;
+        while (true)
+        {
+            sPictureName = "MediaPreview" + OUString::number(++nIndex) + ".png";
+            if (!xPictureStorage->hasByName(sPictureName))
+            {
+                break;
+            }
+        }
+
+        xPictureStream.set(
+            xPictureStorage->openStreamElement(sPictureName, ::embed::ElementModes::READWRITE),
+            uno::UNO_SET_THROW);
+
+        uno::Reference<uno::XComponentContext> xContext = GetExport().getComponentContext();
+        uno::Reference<graphic::XGraphicProvider> xProvider(
+            graphic::GraphicProvider::create(xContext));
+        uno::Sequence<beans::PropertyValue> aArgs{
+            comphelper::makePropertyValue("MimeType", OUString("image/png")),
+            comphelper::makePropertyValue("OutputStream", xPictureStream->getOutputStream())
+        };
+        xProvider->storeGraphic(xGraphic, aArgs);
+        if (xPictureStorage.is())
+        {
+            uno::Reference<embed::XTransactedObject> xTrans(xPictureStorage, uno::UNO_QUERY);
+            if (xTrans.is())
+                xTrans->commit();
+        }
+        OUString sURL = "Pictures/" + sPictureName;
+        mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL);
+        mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
+        mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
+        mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
+        SvXMLElementExport aImageElem(GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, false, true);
+    }
 }

 void XMLShapeExport::ImpExport3DSceneShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx
index 76ca2c4fe4d9..442116980270 100644
--- a/xmloff/source/draw/ximpshap.cxx
+++ b/xmloff/source/draw/ximpshap.cxx
@@ -2908,6 +2908,12 @@ void SdXMLPluginShapeContext::startFastElement (sal_Int32 /*nElement*/,
     if( !mxShape.is() )
         return;

+    if (mbMedia)
+    {
+        // The media may have a crop, apply it.
+        SetStyle(/*bSupportsStyle=*/false);
+    }
+
     SetLayer();

     if(bIsPresShape)
@@ -3302,6 +3308,7 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLFrameShapeContext
             pShapeContext->setHyperlink( msHyperlink );

         auto nToken = nElement & TOKEN_MASK;
+        bool bMedia = false;
         // Ignore gltf model if necessary and so the fallback image will be imported
         if( nToken == XML_PLUGIN )
         {
@@ -3311,10 +3318,15 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLFrameShapeContext
                 mxImplContext = nullptr;
                 return new SvXMLImportContext(GetImport());
             }
+            else if (pPluginContext && pPluginContext->getMimeType() == "application/vnd.sun.star.media")
+            {
+                // The media may have a preview, import it.
+                bMedia = true;
+            }
         }

         mxImplContext = xContext;
-        mbSupportsReplacement = (nToken == XML_OBJECT ) || (nToken == XML_OBJECT_OLE);
+        mbSupportsReplacement = (nToken == XML_OBJECT ) || (nToken == XML_OBJECT_OLE) || bMedia;
         setSupportsMultipleContents(nToken == XML_IMAGE);

         if(getSupportsMultipleContents() && dynamic_cast< SdXMLGraphicObjectShapeContext* >(xContext.get()))
--
2.35.3

