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.

Change-Id: If26b7a4391bcffe9cbddd9933e1bab69be52924e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138867
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
diff --git a/avmedia/Library_avmediagst.mk b/avmedia/Library_avmediagst.mk
index 923c474..fcbaeeb 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 49a3a33..7d7602b 100644
--- a/avmedia/source/gstreamer/gstplayer.cxx
+++ b/avmedia/source/gstreamer/gstplayer.cxx
@@ -30,6 +30,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>
@@ -37,6 +39,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"
@@ -889,6 +893,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 4bbad78..b74033e 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 <comphelper/diagnose_ex.hxx>
#include <comphelper/scopeguard.hxx>
#include <tools/urlobj.hxx>
#include <unotools/securityoptions.hxx>
#include <vcl/bitmapex.hxx>
@@ -298,6 +299,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
@@ -418,7 +422,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 8bceebb..aa95fde 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 f9257c3..4c5b9f5 100644
--- a/slideshow/source/engine/shapes/viewmediashape.cxx
+++ b/slideshow/source/engine/shapes/viewmediashape.cxx
@@ -37,6 +37,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>
@@ -442,10 +444,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 ) );
diff --git a/svx/qa/unit/data/video-snapshot.pptx b/svx/qa/unit/data/video-snapshot.pptx
index a212f10..76f7c0d 100644
--- a/svx/qa/unit/data/video-snapshot.pptx
+++ b/svx/qa/unit/data/video-snapshot.pptx
Binary files differ
diff --git a/svx/qa/unit/svdraw.cxx b/svx/qa/unit/svdraw.cxx
index a2bee4a..dacf558 100644
--- a/svx/qa/unit/svdraw.cxx
+++ b/svx/qa/unit/svdraw.cxx
@@ -502,9 +502,9 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testVideoSnapshot)
    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: rgba[ff0000ff]
    // - Actual  : rgba[000000ff]
    // i.e. the preview was black, not red; since we seeked 3 secs into the video, while PowerPoint
    // i.e. the preview was black, not ~red; since we seeked 3 secs into the video, while PowerPoint
    // doesn't do that.
    CPPUNIT_ASSERT_EQUAL(Color(0xff, 0x0, 0x0), rBitmap.GetPixelColor(0, 0));
    CPPUNIT_ASSERT_EQUAL(Color(0xfe, 0x0, 0x0), rBitmap.GetPixelColor(0, 0));

    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: 321