Commit ff0a4df6 authored by Ghislain MARY's avatar Ghislain MARY

Video renderer set using the MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID method.

parent 19e89be6
/*
IVideoDispatcher.h
mediastreamer2 library - modular sound and video processing and streaming
Windows Audio Session API sound card plugin for mediastreamer2
Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
#include <windows.h>
namespace Mediastreamer2
{
namespace WP8Video
{
public interface class IVideoDispatcher {
public:
void OnSampleReceived(Windows::Storage::Streams::IBuffer ^pBuffer, UINT64 hnsPresentationTime);
};
}
}
/*
IVideoRenderer.h
mediastreamer2 library - modular sound and video processing and streaming
Windows Audio Session API sound card plugin for mediastreamer2
Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
#include "IVideoDispatcher.h"
namespace Mediastreamer2
{
namespace WP8Video
{
public interface class IVideoRenderer
{
public:
void Start(Platform::String^ format, int width, int height);
void Stop();
void ChangeFormat(Platform::String^ format, int width, int height);
IVideoDispatcher^ GetDispatcher();
};
}
}
/*
VideoBuffer.h
mediastreamer2 library - modular sound and video processing and streaming
Windows Audio Session API sound card plugin for mediastreamer2
Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
#include <windows.h>
#include <wrl.h>
#include <wrl/implements.h>
#include <wrl/client.h>
#include <robuffer.h>
#include <windows.storage.streams.h>
namespace Mediastreamer2
{
namespace WP8Video
{
/// <summary>
/// The purpose of this class is to transform byte buffers into an IBuffer
/// </summary>
class VideoBuffer : public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >,
ABI::Windows::Storage::Streams::IBuffer,
Windows::Storage::Streams::IBufferByteAccess,
Microsoft::WRL::FtmBase>
{
public:
virtual ~VideoBuffer() {
if (mBuffer) {
delete[] mBuffer;
mBuffer = NULL;
}
}
STDMETHODIMP RuntimeClassInitialize(BYTE* pBuffer, UINT size) {
mSize = size;
mBuffer = new BYTE[size];
memcpy((void*)mBuffer, (void*)pBuffer, size);
return S_OK;
}
STDMETHODIMP Buffer(BYTE **value) {
*value = mBuffer;
return S_OK;
}
STDMETHODIMP get_Capacity(UINT32 *value) {
*value = mSize;
return S_OK;
}
STDMETHODIMP get_Length(UINT32 *value) {
*value = mSize;
return S_OK;
}
STDMETHODIMP put_Length(UINT32 value) {
if(value > mSize) {
return E_INVALIDARG;
}
mSize = value;
return S_OK;
}
static Windows::Storage::Streams::IBuffer^ GetIBuffer(Microsoft::WRL::ComPtr<VideoBuffer> spVideoBuffer) {
auto iinspectable = reinterpret_cast<IInspectable*>(spVideoBuffer.Get());
return reinterpret_cast<Windows::Storage::Streams::IBuffer^>(iinspectable);
}
private:
UINT32 mSize;
BYTE* mBuffer;
};
}
}
......@@ -3,88 +3,95 @@ using System;
using System.Diagnostics;
using System.Windows;
namespace mswp8vid
using Mediastreamer2.WP8Video;
namespace Mediastreamer2
{
internal class VideoRenderer
namespace WP8Video
{
internal VideoRenderer()
public class VideoRenderer : IVideoRenderer
{
Random rand = new Random();
this.streamId = rand.Next(0, 65535);
mswp8vid.Globals.Instance.renderStarted += Start;
mswp8vid.Globals.Instance.renderStopped += Stop;
mswp8vid.Globals.Instance.renderFormatChanged += ChangeFormat;
}
public Uri RemoteStreamUri
{
get
public VideoRenderer()
{
return new Uri("ms-media-stream-id:MediaStreamer-" + this.streamId);
Random rand = new Random();
this.streamId = rand.Next(0, 65535);
}
}
public static Uri FrontFacingCameraStreamUri = new Uri("ms-media-stream-id:camera-FrontFacing");
public static Uri RearFacingCameraStreamUri = new Uri("ms-media-stream-id:camera-RearFacing");
private void Start(String format, int width, int height)
{
if (this.isRendering)
public Uri RemoteStreamUri
{
return;
get
{
return new Uri("ms-media-stream-id:MediaStreamer-" + this.streamId);
}
}
Deployment.Current.Dispatcher.BeginInvoke(() =>
public static Uri FrontFacingCameraStreamUri = new Uri("ms-media-stream-id:camera-FrontFacing");
public static Uri RearFacingCameraStreamUri = new Uri("ms-media-stream-id:camera-RearFacing");
public void Start(String format, int width, int height)
{
try
if (this.isRendering)
{
if (this.mediastreamer == null)
{
this.mediastreamer = MediaStreamerFactory.CreateMediaStreamer(this.streamId);
}
this.streamSource = new VideoStreamSource(format, width, height);
this.mediastreamer.SetSource(this.streamSource);
this.isRendering = true;
return;
}
catch (Exception e)
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
Debug.WriteLine("[MSWP8Vid] VideoRenderer.Start() failed: " + e.Message);
}
});
}
try
{
if (this.mediastreamer == null)
{
this.mediastreamer = MediaStreamerFactory.CreateMediaStreamer(this.streamId);
}
this.streamSource = new VideoStreamSource(format, width, height);
this.mediastreamer.SetSource(this.streamSource);
this.isRendering = true;
}
catch (Exception e)
{
Debug.WriteLine("[MSWP8Vid] VideoRenderer.Start() failed: " + e.Message);
}
});
}
private void Stop()
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
public void Stop()
{
if (!this.isRendering)
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
return;
}
if (!this.isRendering)
{
return;
}
this.streamSource.Shutdown();
this.streamSource.Dispose();
this.streamSource = null;
this.mediastreamer.Dispose();
this.mediastreamer = null;
this.isRendering = false;
});
}
this.streamSource.Shutdown();
this.streamSource.Dispose();
this.streamSource = null;
this.mediastreamer.Dispose();
this.mediastreamer = null;
this.isRendering = false;
});
}
private void ChangeFormat(String format, int width, int height)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
public void ChangeFormat(String format, int width, int height)
{
if (this.streamSource != null)
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
this.streamSource.ChangeFormat(format, width, height);
}
});
}
if (this.streamSource != null)
{
this.streamSource.ChangeFormat(format, width, height);
}
});
}
private bool isRendering;
private int streamId;
private MediaStreamer mediastreamer;
private VideoStreamSource streamSource;
public IVideoDispatcher GetDispatcher()
{
return this.streamSource;
}
private bool isRendering;
private int streamId;
private MediaStreamer mediastreamer;
private VideoStreamSource streamSource;
}
}
}
This diff is collapsed.
......@@ -25,9 +25,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/msticker.h"
#include "mediastreamer2/msvideo.h"
#include "mswp8dis.h"
#include "VideoBuffer.h"
using namespace Microsoft::WRL;
using namespace mswp8vid;
using namespace Mediastreamer2::WP8Video;
......@@ -68,7 +70,7 @@ bool MSWP8Dis::smInstantiated = false;
MSWP8Dis::MSWP8Dis()
: mIsInitialized(false), mIsActivated(false), mIsStarted(false), mWidth(MS_VIDEO_SIZE_CIF_W), mHeight(MS_VIDEO_SIZE_CIF_H),
mRfc3984Unpacker(nullptr), mBitstreamSize(65536), mSPS(nullptr), mPPS(nullptr)
mRfc3984Unpacker(nullptr), mBitstreamSize(65536), mSPS(nullptr), mPPS(nullptr), mRenderer(nullptr)
{
if (smInstantiated) {
ms_error("[MSWP8Dis] A video display filter is already instantiated. A second one can not be created.");
......@@ -111,7 +113,9 @@ void MSWP8Dis::start()
if (!mIsStarted && mIsActivated) {
mIsStarted = true;
Platform::String^ format = ref new Platform::String(L"H264");
Globals::Instance->startRendering(format, mWidth, mHeight);
if (mRenderer != nullptr) {
mRenderer->Start(format, mWidth, mHeight);
}
}
}
......@@ -119,7 +123,9 @@ void MSWP8Dis::stop()
{
if (mIsStarted) {
mIsStarted = false;
Globals::Instance->stopRendering();
if (mRenderer != nullptr) {
mRenderer->Stop();
}
}
}
......@@ -137,10 +143,17 @@ int MSWP8Dis::feed(MSFilter *f)
int size = nalusToFrame(&nalus, &need_reinit);
if (need_reinit) {
Platform::String^ format = ref new Platform::String(L"H264");
Globals::Instance->changeRenderingFormat(format, mWidth, mHeight);
if (mRenderer != nullptr) {
mRenderer->ChangeFormat(format, mWidth, mHeight);
}
}
if (size > 0) {
Globals::Instance->VideoSampleDispatcher->writeSample(mBitstream, size, f->ticker->time * 10000LL);
if ((size > 0) && (mRenderer != nullptr)) {
IVideoDispatcher^ dispatcher = mRenderer->GetDispatcher();
if (dispatcher != nullptr) {
ComPtr<VideoBuffer> spVideoBuffer = NULL;
MakeAndInitialize<VideoBuffer>(&spVideoBuffer, (BYTE *)mBitstream, size);
dispatcher->OnSampleReceived(VideoBuffer::GetIBuffer(spVideoBuffer), f->ticker->time * 10000LL);
}
}
}
}
......@@ -149,6 +162,11 @@ int MSWP8Dis::feed(MSFilter *f)
return 0;
}
void MSWP8Dis::setVideoRenderer(IVideoRenderer^ renderer)
{
mRenderer = renderer;
}
int MSWP8Dis::nalusToFrame(MSQueue *nalus, bool *new_sps_pps)
{
mblk_t *im;
......@@ -319,65 +337,3 @@ void MSWP8Dis::updateVideoSizeFromSPS()
ms_message("Change video size from SPS: %ux%u", mWidth, mHeight);
MS_UNUSED(dummy);
}
DisplayEventDispatcher::DisplayEventDispatcher()
{
}
DisplayEventDispatcher::~DisplayEventDispatcher()
{
}
void DisplayEventDispatcher::writeSample(BYTE* bytes, int byteCount, UINT64 hnsPresentationTime)
{
ComPtr<NativeBuffer> spNativeBuffer = NULL;
BYTE* pBuf = new BYTE[byteCount];
memcpy((void*)pBuf, (void*)bytes, byteCount);
MakeAndInitialize<NativeBuffer>(&spNativeBuffer, pBuf, byteCount, TRUE);
sampleReceived(NativeBuffer::GetIBufferFromNativeBuffer(spNativeBuffer), hnsPresentationTime);
}
Globals^ Globals::singleton = nullptr;
Globals::Globals()
: videoSampleDispatcher(ref new DisplayEventDispatcher())
{
}
Globals::~Globals()
{
}
Globals^ Globals::Instance::get()
{
if (Globals::singleton == nullptr) {
Globals::singleton = ref new Globals();
}
return Globals::singleton;
}
DisplayEventDispatcher^ Globals::VideoSampleDispatcher::get()
{
return this->videoSampleDispatcher;
}
void Globals::startRendering(Platform::String^ format, int width, int height)
{
renderStarted(format, width, height);
}
void Globals::stopRendering()
{
renderStopped();
}
void Globals::changeRenderingFormat(Platform::String^ format, int width, int height)
{
renderFormatChanged(format, width, height);
}
......@@ -31,159 +31,44 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/rfc3984.h"
#include "IVideoRenderer.h"
namespace mswp8vid
{
public delegate void SampleReceivedEventHandler(Windows::Storage::Streams::IBuffer ^pBuffer, UINT64 hnsPresentationTime);
public ref class DisplayEventDispatcher sealed {
public:
DisplayEventDispatcher();
virtual ~DisplayEventDispatcher();
void writeSample(BYTE* bytes, int byteCount, UINT64 hnsPresentationTime);
event SampleReceivedEventHandler^ sampleReceived;
};
/// <summary>
/// The purpose of this class is to transform byte buffers into an IBuffer
/// </summary>
class NativeBuffer : public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >,
ABI::Windows::Storage::Streams::IBuffer,
Windows::Storage::Streams::IBufferByteAccess,
Microsoft::WRL::FtmBase>
{
public:
virtual ~NativeBuffer() {
if (m_pBuffer && m_bIsOwner) {
delete[] m_pBuffer;
m_pBuffer = NULL;
}
}
STDMETHODIMP RuntimeClassInitialize(BYTE* pBuffer, UINT totalSize, BOOL fTakeOwnershipOfPassedInBuffer) {
m_uLength = totalSize;
m_uFullSize = totalSize;
m_pBuffer = pBuffer;
m_bIsOwner = fTakeOwnershipOfPassedInBuffer;
return S_OK;
}
STDMETHODIMP Buffer(BYTE **value) {
*value = m_pBuffer;
return S_OK;
}
STDMETHODIMP get_Capacity(UINT32 *value) {
*value = m_uFullSize;
return S_OK;
}
STDMETHODIMP get_Length(UINT32 *value) {
*value = m_uLength;
return S_OK;
}
STDMETHODIMP put_Length(UINT32 value) {
if(value > m_uFullSize) {
return E_INVALIDARG;
}
m_uLength = value;
return S_OK;
}
static Windows::Storage::Streams::IBuffer^ GetIBufferFromNativeBuffer(Microsoft::WRL::ComPtr<NativeBuffer> spNativeBuffer) {
auto iinspectable = reinterpret_cast<IInspectable*>(spNativeBuffer.Get());
return reinterpret_cast<Windows::Storage::Streams::IBuffer^>(iinspectable);
}
static BYTE* GetBytesFromIBuffer(Windows::Storage::Streams::IBuffer^ buffer) {
auto iinspectable = (IInspectable*)reinterpret_cast<IInspectable*>(buffer);
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> spBuffAccess;
HRESULT hr = iinspectable->QueryInterface(__uuidof(Windows::Storage::Streams::IBufferByteAccess), (void **)&spBuffAccess);
if (hr == S_OK) {
UCHAR * pReadBuffer;
spBuffAccess->Buffer(&pReadBuffer);
return pReadBuffer;
}
return nullptr;
}
private:
UINT32 m_uLength;
UINT32 m_uFullSize;
BYTE* m_pBuffer;
BOOL m_bIsOwner;
};
public delegate void RenderStarted(Platform::String^ format, int width, int height);
public delegate void RenderStopped();
public delegate void RenderFormatChanged(Platform::String^ format, int width, int height);
public ref class Globals sealed
{
public:
// Get the single instance of this class
static property Globals^ Instance
{
Globals^ get();
}
// The singleton display event dispatcher object.
property DisplayEventDispatcher^ VideoSampleDispatcher
{
DisplayEventDispatcher^ get();
}
event RenderStarted^ renderStarted;
event RenderStopped^ renderStopped;
event RenderFormatChanged^ renderFormatChanged;
void startRendering(Platform::String^ format, int width, int height);
void stopRendering();
void changeRenderingFormat(Platform::String^ format, int width, int height);
private:
Globals();
~Globals();
static Globals^ singleton; // The single instance of this class
DisplayEventDispatcher^ videoSampleDispatcher;
};
class MSWP8Dis {
public:
MSWP8Dis();
virtual ~MSWP8Dis();
int activate();
int deactivate();
bool isStarted() { return mIsStarted; }
void start();
void stop();
int feed(MSFilter *f);
private:
int nalusToFrame(MSQueue *nalus, bool *new_sps_pps);
void enlargeBitstream(int newSize);
bool checkSPSChange(mblk_t *sps);
bool checkPPSChange(mblk_t *pps);
void updateSPS(mblk_t *sps);
void updatePPS(mblk_t *pps);
void updateVideoSizeFromSPS();
static bool smInstantiated;
bool mIsInitialized;
bool mIsActivated;
bool mIsStarted;
int mWidth;
int mHeight;
Rfc3984Context *mRfc3984Unpacker;
int mBitstreamSize;
uint8_t *mBitstream;
mblk_t *mSPS;
mblk_t *mPPS;
};
class MSWP8Dis {
public:
MSWP8Dis();
virtual ~MSWP8Dis();
int activate();
int deactivate();
bool isStarted() { return mIsStarted; }
void start();
void stop();
int feed(MSFilter *f);
void setVideoRenderer(Mediastreamer2::WP8Video::IVideoRenderer^ renderer);
private:
int nalusToFrame(MSQueue *nalus, bool *new_sps_pps);
void enlargeBitstream(int newSize);
bool checkSPSChange(mblk_t *sps);
bool checkPPSChange(mblk_t *pps);
void updateSPS(mblk_t *sps);
void updatePPS(mblk_t *pps);
void updateVideoSizeFromSPS();
static bool smInstantiated;
bool mIsInitialized;
bool mIsActivated;
bool mIsStarted;
int mWidth;
int mHeight;
Rfc3984Context *mRfc3984Unpacker;
int mBitstreamSize;
uint8_t *mBitstream;
mblk_t *mSPS;
mblk_t *mPPS;
Mediastreamer2::WP8Video::IVideoRenderer^ mRenderer;
};
}
......@@ -27,8 +27,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mswp8cap.h"
#include "mswp8dis.h"
#include "IVideoRenderer.h"
using namespace mswp8vid;
using namespace Mediastreamer2::WP8Video;
/******************************************************************************
......@@ -274,9 +277,29 @@ static int ms_wp8dis_support_decoding(MSFilter *f, void *arg) {
return 0;
}
template <class T> class RefToPtrProxy
{
public:
RefToPtrProxy(T obj) : mObj(obj) {}
~RefToPtrProxy() { mObj = nullptr; }
T Ref() { return mObj; }
private:
T mObj;
};
static int ms_wp8dis_set_native_window_id(MSFilter *f, void *arg) {
MSWP8Dis *w = static_cast<MSWP8Dis *>(f->data);
unsigned long *ptr = (unsigned long *)arg;
RefToPtrProxy<IVideoRenderer^> *proxy = reinterpret_cast< RefToPtrProxy<IVideoRenderer^> *>(*ptr);
IVideoRenderer^ renderer = (proxy) ? proxy->Ref() : nullptr;
w->setVideoRenderer(renderer);
return 0;
}
static MSFilterMethod ms_wp8dis_methods[] = {
{ MS_VIDEO_DISPLAY_SUPPORT_DECODING, ms_wp8dis_support_decoding },
{ 0, NULL }
{ MS_VIDEO_DISPLAY_SUPPORT_DECODING, ms_wp8dis_support_decoding },
{ MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID, ms_wp8dis_set_native_window_id },
{ 0, NULL }
};
......
......@@ -85,6 +85,7 @@
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
<IgnoreSpecificDefaultLibraries>ole32.lib</IgnoreSpecificDefaultLibraries>
<WindowsMetadataFile>$(OutDir)Mediastreamer2.WP8Video.winmd</WindowsMetadataFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
......@@ -111,6 +112,7 @@
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
<IgnoreSpecificDefaultLibraries>ole32.lib</IgnoreSpecificDefaultLibraries>
<WindowsMetadataFile>$(OutDir)Mediastreamer2.WP8Video.winmd</WindowsMetadataFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
......@@ -133,6 +135,7 @@
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
<IgnoreSpecificDefaultLibraries>ole32.lib</IgnoreSpecificDefaultLibraries>
<WindowsMetadataFile>$(OutDir)Mediastreamer2.WP8Video.winmd</WindowsMetadataFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
......@@ -159,6 +162,7 @@
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImportLibrary>$(TargetDir)$(TargetName)_dll.lib</ImportLibrary>
<IgnoreSpecificDefaultLibraries>ole32.lib</IgnoreSpecificDefaultLibraries>
<WindowsMetadataFile>$(OutDir)Mediastreamer2.WP8Video.winmd</WindowsMetadataFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup Condition="'$(Platform)'=='ARM'">
......@@ -184,8 +188,11 @@
<ClCompile Include="..\..\mswp8cap.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\IVideoDispatcher.h" />
<ClInclude Include="..\..\IVideoRenderer.h" />