通用平台应用程序录制失败时视频效果

时间:2017-03-22 22:26:19

标签: c++ uwp

在通用平台应用上使用mediacapture类,我试图在录制中添加叠加效果。叠加效果在预览中正常工作,如果我在开始记录之前设置效果,则可以进行录制。如果我尝试在录制期间设置效果,系统会生成异常:"为媒体类型指定的数据无效,不一致或不受此对象支持#34;。什么会导致它仅在活动记录会话期间失败?

            VideoEffectDefinition^ effect = ref new VideoEffectDefinition("CompositionEffectLibrary.CompositionEffect", props);
        if (mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic == VideoDeviceCharacteristic::AllStreamsIdentical ||
            mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic == VideoDeviceCharacteristic::PreviewRecordStreamsIdentical)
        {
            // This effect will modify both the preview and the record streams, because they are the same stream.
            create_task(mediaCapture->AddVideoEffectAsync(effect, MediaStreamType::VideoRecord))
                .then([this](IMediaExtension^ mediaExtension)
            {
            });
        }

        else
        {
            create_task(mediaCapture->AddVideoEffectAsync(effect, MediaStreamType::VideoRecord))
                .then([this, effect](IMediaExtension^ mediaExtension)
            {
                auto mediaCapture = m_mediaCaptureMgr.Get();
                create_task(mediaCapture->AddVideoEffectAsync(effect, MediaStreamType::VideoPreview))
                    .then([this](IMediaExtension^ mediaExtension)
                {
                });
            });
        } // else

    return true;

我使用固定的VideoStabilization效果运行程序,没有任何问题,因此它似乎与使用自定义类有关。我也包括它。没有编译错误或警告,并使用Win2D包。

C ++ Effect Class

public ref class CompositionEffect sealed : public IBasicVideoEffect
{
    CanvasDevice^ _canvasDevice = nullptr;
    CanvasBitmap^ _overlayBitmap = nullptr;
    IRandomAccessStream^ _overlayStream;
    int _offsetX;
    int _offsetY;
    int _width;
    int _height;
    bool _atTop;
    int _position;
    float _opacity;
    bool _layerCreated = false;
    CanvasActiveLayer^ _activeLayer = nullptr;
    Vector<VideoEncodingProperties^>^ _videoEncProps;

public:
    CompositionEffect()
    {
        VideoEncodingProperties^ encodingProperties = ref new VideoEncodingProperties();
        encodingProperties->Subtype = "ARGB32";
        _videoEncProps = ref new Vector<VideoEncodingProperties^>{ encodingProperties };
    }

    property bool IsReadOnly
    {
        virtual bool get() { return true; }
    }

    property IVectorView<VideoEncodingProperties^> ^SupportedEncodingProperties
    {
        virtual IVectorView<VideoEncodingProperties^> ^get() { return _videoEncProps->GetView(); }
    }

    property MediaMemoryTypes SupportedMemoryTypes
    {
        virtual MediaMemoryTypes get() { return MediaMemoryTypes::Gpu; }
    }

    property bool TimeIndependent
    {
        virtual bool get() { return true; }
    }

    // Get positional information from loaded image
    virtual void CompositionEffect::SetEncodingProperties(VideoEncodingProperties^ encodingProperties, IDirect3DDevice^ device)
    {
        if (_canvasDevice != nullptr)
            return;

        _canvasDevice = CanvasDevice::CreateFromDirect3D11Device(device);

        create_task(CanvasBitmap::LoadAsync(_canvasDevice, _overlayStream)).then([this](CanvasBitmap^ bmp)
        {
            _overlayBitmap = bmp;

            // overlay at left side of source
            if (_position == 0)
            {
                _offsetX = 0;
            }

            // overlay at right side of source
            else if (_position == 2)
            {
                _offsetX = _width - bmp->SizeInPixels.Width;
            }

            // overlay at center of source
            else
            {
                _offsetX = (_width - bmp->SizeInPixels.Width) / 2;
            }

            // Set overlay vertical position
            if (_atTop)
            {
                _offsetY = 0;
            }

            else
            {
                _offsetY = (_height - bmp->SizeInPixels.Height);
            }
        });
    }

    virtual void Close(MediaEffectClosedReason reason)
    {
    }

    virtual void DiscardQueuedFrames() { }

    // Draw overlay image over source image at specified coordinates
    virtual void ProcessFrame(ProcessVideoFrameContext^ context)
    {           

        IDirect3DSurface^ outputSurface = context->OutputFrame->Direct3DSurface;
        CanvasRenderTarget^ renderTarget = CanvasRenderTarget::CreateFromDirect3D11Surface(_canvasDevice, outputSurface);
        CanvasDrawingSession^ drawSession = renderTarget->CreateDrawingSession();
        _activeLayer = drawSession->CreateLayer(_opacity);

        if (_overlayBitmap != nullptr)
        {
            drawSession->DrawImage(_overlayBitmap, (float)_offsetX, (float)_offsetY);
        }

        delete(_activeLayer);
    }

    // Set the operational parameters of the effect
    virtual void SetProperties(IPropertySet^ configuration) 
    {
        _overlayStream = (IRandomAccessStream^)configuration->Lookup("bitmap");
        _width = (int)configuration->Lookup("width");
        _height = (int)configuration->Lookup("height");
        _opacity = (float)(int)configuration->Lookup("opacity");
        _opacity /= 100;
        _atTop = (bool)configuration->Lookup("attop");
        _position = (int)configuration->Lookup("position");
    }

};

我在C#中编写了一个简单的例子并在我的开发机器上进行了尝试,并且对于为媒体类型指定的&#34;数据失败的方式相同...&#34;信息。然后我把程序放在另一台机器上,它工作得很好????我为Cpu而不是Gpu设置了效果,因此在运行相同的4.6框架的平台上表现不同是没有意义的。以下是测试计划TestVideoApp2

的链接

我发现了一些有关此问题的其他信息。看来输入流设置为YUY2。我把它更改为NV12,它开始工作了。不幸的是,我改变了相机,即使新相机支持这种输出格式,它也因无效的媒体类型而失败。它似乎与输入媒体类型与效果支持的媒体类型有关。不确定这里的关系是什么,但正在取得一些进展。也许有人知道视频输入与效果媒体类型应该是什么才能正常工作。

好的,似乎我必须在输入帧中将输入格式从相机(YUY2或NV12)更改为ARGB32,并在退出时可能返回NV12,并将YUY2或NV12设置为支持的类型。失败的是支持的效果媒体类型是ARGB32,并且正在击中录制的NV12媒体流输入过滤器类型。这听起来合理吗?是否有更直接的方法,因为这可能会非常痛苦。

通过将效果的输入格式设置为YUY2然后通过SoftwareBitmap.Convert将其转换为BGR8,我找到了解决问题的方法。从那里我通过像素字节数组手动完成效果,然后在从ProcessFrame返回之前转换回YUY2。这似乎现在工作正常。不幸的是,我不能使用Win2D,因为它不支持YUY2。我想要一个GPU解决方案,但目前CPU解决方案似乎解决了我的迫切需求。也许其他人可能能够使用GPU提出解决方案。

0 个答案:

没有答案