|
Hi,
Thanks for your reply.Both YUY2 and MJPG format supported in my device.
Using IMFMediaTypeHandler::SetCurrentMediaType,i changed resolution and format.After change media type,I could not see any changes occur on my preview window.Default media type only streaming.
What should i do to affect changes in my application? Please give me a sample application for reference.
Thanks in advance.
With best regards,
Ambika
|
|
|
|
|
Hi Ambika,
Sorry for a late answer. I cannot understand which resolution you try to set. Is it supported by your device? Look at the next code how it is done in my code:
510 long videoDevice::setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex)
511 {
512 IMFPresentationDescriptor *pPD = NULL;
513 IMFStreamDescriptor *pSD = NULL;
514 IMFMediaTypeHandler *pHandler = NULL;
515 IMFMediaType *pType = NULL;
516
517 HRESULT hr = pSource->CreatePresentationDescriptor(&pPD);
518 if (FAILED(hr))
519 {
520 goto done;
521 }
522
523 BOOL fSelected;
524 hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD);
525 if (FAILED(hr))
526 {
527 goto done;
528 }
529
530 hr = pSD->GetMediaTypeHandler(&pHandler);
531 if (FAILED(hr))
532 {
533 goto done;
534 }
535
536 hr = pHandler->GetMediaTypeByIndex((DWORD)dwFormatIndex, &pType);
537 if (FAILED(hr))
538 {
539 goto done;
540 }
541
542 hr = pHandler->SetCurrentMediaType(pType);
543
544 done:
545 SafeReleaseAllCount(&pPD);
546 SafeRelease(&pSD);
547 SafeRelease(&pHandler);
548 SafeRelease(&pType);
549 return hr;
550 }
551
Check the state of hr after hr = pHandler->SetCurrentMediaType(pType);
With best regards,
Evgeny
|
|
|
|
|
Hi Evgeny,
Sorry for late reply.
I have solved the problem.I'm able to switch all resolutions supported in my usb device.
I'm facing one more problem(i.e)I couldn't capture an image from image stream(still pin).
My video input device contains 2 streams.One is for preview and another one is for still.
Below steps, i have tried to build the topology.
1)Created Presentation descriptor interface.
2)Deselected the preview stream and selected the image stream.
3)Retrieves a stream descriptor for a selected stream in the presentation.
4)Created source node and added it to the topology.
5)Created SampleGrabber sink node and added it to the topology.
6)Connect source and sink node.(Eg: pSourceNode->ConnectOutput(0, pGrabberNode, 0);)
6)Set the topology.
7)After receive TOPOLOGY_STATUS_READY event,i started the session.
8)IMFMediaEvent gives E_INVALIDARG(0x80070057) error.This error is not related to media session.
Can you please tell me,why am i getting this error?Am i missing anything to build the topology?
I have searched many sites regarding this issue,but no luck.Most of them,capturing an image from preview pin,not from image stream.
Please help me to solve this problem.Sample code is more helpful to solve this.
Thanks in advance.
Regards,
Ambika
|
|
|
|
|
Hi,
I understand your problem, and I also faced with it.
However, I could not give you the correct solution.
The fact is that after receiving of TOPOLOGY_STATUS_READY event the topology resolved
correctly, but receiving E_INVALIDARG error means that the instance of MFSession sends sample request
to the MFSource in incorrect way.
Some time ago I wrote two MFSource for project - one for Screen Capturing and another for capturing MJPEG network broadcasting and spent much time on research of implementation IMFSource, IMFStreamDescriptor, and other interfaces.
I know that Session sends request and information about time - time stamp, duration, position and others.
In my view the problem is that stream, which is associated with still capture has wrong MajorType - MFMediaType_Video.
The fact is that Media Foundation has another MajorType which more suitable for still image - MFMediaType_Image.
The different MajorTypes have different schemes of working with MFSource. For example, MFMediaType_Image type does not have duration and position, and sending such arguments must be considered as error.
So, As I said previously, I do not have the solution, but I can advise to try special software for tracing the Media Foundation request - mftrack.exe. It can log all requests in the local session of Media Foundation in you application.
However, In my view there is only way for resolving such problem - write own version of the MFSession - yes it is very difficult task, but it is the only way to take control over sending request to the MFSource and correct it for the cases of live video and still image. I do not have other ideas about it, because the error is emitted in the moment of starting of MFSource.
With best,
Evgeny
|
|
|
|
|
Well yes, you make some interesting points, but, for example, Intel did extend x8086 to x80186, to 286,386,4...5... and on, because code is just code, a code for "add" doesn´t need to evolve, but the hardware that runs it can be improved... while maintaining compatibility!!
DirectShow isn´t old, its still very new, it uses COM, it is object-oriented, extendable, and the filters are still be added, the ffdshow and the new project.
Microsoft could do what Intel did, extend it, improve it, without breaking applications!
But, as you say, exactly as you say, Microsoft don´t want users to have direct and powerful control of the hardware for media apps!
This is horrible news for developers, Microsoft will enslave us to the whims of their marketing hacks for ever!
So support DShow, it works great on Windows 7 and 8, and will work on Windows 9 and 10 even if we have to add the dlls!
Don´t let Microsoft walk all over us, that´s what I say!
|
|
|
|
|
DirectShow is still supported by Windows 8, problems may occur because of not having the correct codecs installed.
Officially, Microsoft have stated that they are "gradually implementing Media Foundation" with the aim of replacing DirectShow at some future point, but as of May 2014 Media Foundation is far from ready to replace DirectShow.
Media Foundation will have extensive media rights management support, so that the big content producers can make sure their movies cannot be copied; this looks like the driving force behind Media Foundation.
The real problem with this sample is that it is very slow, requiring multiple transfers of large frames of video to reach a display surface.
Under DirectShow, the IAMMultiMediaStream interface support direct capture to an IDirectDrawSurface and supports full frame rate video capture direct to a surface with very little CPU overhead.
This is meant to be possible with MediaFoundation but I haven´t been able to compile the MFCapture sample even on Visual Studio 2012 because of errors that list up.
To Microsoft "If it ain´t broken, don´t fix it!"
Please pressurise Microsoft to support our DirectShow applications indefinitely.
There is no such thing as "old code", look at our DNA, it has the best code in it, perfect code, and its millions of years old. We don´t want to re-invent the wheel just because Microsoft marketing hacks have some "plan" to make more money!
|
|
|
|
|
Hi,
Your ideas are not bad. However, you are missed the last trend of the Microsoft - creating environment of the Windows - Windows Store and Windows RT. It includes protection of media content, protection of access for the devices and others. If you worked with progamming language Java or C# than you know that "sandbox" is fundament of the them. Powerful DirestShow with deep access to devices blow up this trend for protection of system. I read the blog of the "Itseez" company which spent much time on porting OpenCV on ARM Windows RT and find that Media Foundation - is only API for working on this platform.
"Please pressurise Microsoft to support our DirectShow applications indefinitely." - It is like ask Intel to continue produce x8086 proc.
|
|
|
|
|
Microsoft are again trying to dump a working API, DShow, for commercial interest, to stricly control media licensing, and to force developers to use Windows.
The millions of hours wasted by coders to learn MediaFoundation, find all its bugs, etc etc etc, as we had done with DShow before it became stable, will be a pain for all of us!
Your security concerns that DShow give too deep access to media hardware can easily be addressed by Microsoft adding code to prevent abuse, rather than trying to force thousands of coders to learn a new and impèrfect (as always) API.
|
|
|
|
|
Your analogy of comparing DShow with 16-bit x86 systems is absurd!
Firstly, DShow supports more media formats by a factor of at least 4x compared to MediaFoundation, it also, thanks to FFDShow, runs on all modern CPU platforms, and finally it works perfectly, is fast, stable, whereas Media Foundation is a mess, and unstable, with little codec support.
If it works, don't "fix it", Microsoft just want more control over media playback, its all about money as usual, not about supporting developers.
|
|
|
|
|
Hello Evgeny,
when i set up a device, close it, and then set up the same devcie, close it...
for (int i = 0; i < 100; i++)
{
if(VI->setupDevice(0, 640, 480, 60))
{
VI->closeDevice(0);
Sleep(500);
}
}
i found that the memory has been increased about 40kb every time...
is there any memory block has not been released in closeDevice?
|
|
|
|
|
Hi,
I spent some time on the review of the code and debugging it, but I didn't find any marks of the memory leak. However, you are right - calling function _CrtDumpMemoryLeaks(); shows memory leak. I think that it a memory leak at the libraries of VS2012.
I have written the simple code WITHOUT using of videoInput
int _tmain(int argc, _TCHAR* argv[])
{
_CrtDumpMemoryLeaks();
while(true)
{
char c = cvWaitKey(33);
if(c == 27)
break;
}
return 0;
}
And I have got the next output listing
Detected memory leaks!
Dumping objects ->
{310} normal block at 0x0069D890, 47 bytes long.
Data: <JPEG-2000 Code S> 4A 50 45 47 2D 32 30 30 30 20 43 6F 64 65 20 53
{309} normal block at 0x0069D850, 4 bytes long.
Data: <jpc > 6A 70 63 00
{308} normal block at 0x0069D810, 4 bytes long.
Data: <jpc > 6A 70 63 00
{307} normal block at 0x0069D7A0, 51 bytes long.
Data: <JPEG-2000 JP2 Fi> 4A 50 45 47 2D 32 30 30 30 20 4A 50 32 20 46 69
{306} normal block at 0x0069D760, 4 bytes long.
Data: <jp2 > 6A 70 32 00
{305} normal block at 0x0069D720, 4 bytes long.
Data: <jp2 > 6A 70 32 00
{304} normal block at 0x0069D670, 56 bytes long.
Data: <h yX > 68 97 79 58 00 00 00 00 00 00 00 00 CD CD CD CD
{303} normal block at 0x0069D2A8, 908 bytes long.
Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 80 02 00 00
{302} normal block at 0x0069D1F8, 56 bytes long.
Data: <h yX > 68 97 79 58 00 00 00 00 00 00 00 00 CD CD CD CD
{301} normal block at 0x0069CE30, 908 bytes long.
The code does not call any method of the videoInput and Dump pointed on the code which is bound with JPEG-2000 Code. This dump is showed after loading C:\Windows\SysWOW64\msctf.dll
.
However, if you have another idea or you use another technique for detecting of the memory leak, I would be glad to have some advised.
P.S.
I just want say that today I have found the great news about my project "videoInput" - it has been included into the open source project OpenCV - the most power project of the computer vision. They have taken almost 95% of the code and added some interesting improvements. You can find it on the next link: OpenCV.
For me it is a great Honour.
Evgeny
|
|
|
|
|
Hi
i used the task manager in Win 7, and i found the memory has been increased about 40kb every time
VIDEODEVICE 0: Device is setuped
VIDEODEVICE 0: Device is stopped
VIDEODEVICE 0: Device is setuped
VIDEODEVICE 0: Device is stopped
VIDEODEVICE 0: Device is setuped
VIDEODEVICE 0: Device is stopped
VIDEODEVICE 0: Device is setuped
VIDEODEVICE 0: Device is stopped
VIDEODEVICE 0: Device is setuped
VIDEODEVICE 0: Device is stopped
...
|
|
|
|
|
Hello Evgeny,
I have some plrblems running the TestvideoInput under Windows 7 OS, i am using the integrated camera, When
countLeftFrames is greater than 60, then it should switch to the next section, that is reusing of the same video device,
but it comes out a message
'Unhandled exception at 0x3183fdac in videoInputTest.exe: 0xC0000005: Access violation reading location 0xfeeefef6'
Then I use the source code for deubug, i find that the code
hr = checkDevice(pAttributes, &vd_pActivate);
has a problem.
I think my problem is the same as sanjeev.567, for function
template <class T> void SafeRelease(T **ppT)
{
if (*ppT)
{
ULONG e = (*ppT)->Release();
*ppT = NULL;
}
}
the variable e is 4.
The link TestvideoInput[^] is out of date, so would you please help me how to solve the problem, thanks!
|
|
|
|
|
Hi,
I am sorry for late with answer.
Thank you for the message with info about memory leak in code. I have corrected the code and the article. You can find new code by the next link:
videoInputVS2012.zip.
|
|
|
|
|
Thanks for your reply.
I download the latest source files from http://www.codeproject.com/KB/audio-video/559437/videoInputVS2012.zip
for Win7 OS and vs2010, there is no definition for macro 'MEVideoCaptureDeviceRemoved', so i just comment the block
#if 0
if (met == MEVideoCaptureDeviceRemoved)
{
DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: MEVideoCaptureDeviceRemoved \n", ig_DeviceID);
break;
}
#endif
then i run the TestVideoInput project,
***** VIDEOINPUT LIBRARY - 2013 (Author: Evgeny Pereguda) *****
VIDEOINPUT SPY MODE!
SETUP: Looking For Capture Devices
SETUP: 0) Integrated Camera
SETUP: 1 Device(s) found
VIDEODEVICE 0: Device is setuped
IMAGEGRABBER VIDEODEVICE 0: Creating instance of ImageGrabber
IMAGEGRABBERTHREAD VIDEODEVICE 0: Initialization of instance of the ImageGrabber
class
IMAGEGRABBERTHREAD VIDEODEVICE 0: Creating of the instance of ImageGrabberThread
IMAGEGRABBERTHREAD VIDEODEVICE 0: Thread for grabbing images is started
IMAGEGRABBER VIDEODEVICE 0: Start Grabbing of the images
IMAGEGRABBER VIDEODEVICE 0: Stopping of of grabbing of images
IMAGEGRABBERTHREAD VIDEODEVICE 0: Destroing ImageGrabberThread
an error occured at
hr = ig_pSession->GetEvent(0, &pEvent);
i don't know if it is the block commented that cause the error, and then
if i use vs2010 and win7 OS, how to solve the macro definition problem? thanks!
|
|
|
|
|
Hi,
It is not easy to give you a correct answer because I use vs2012 and Win7 for development projects. However I can give you some advices:
1. Do you use Windows SDK for you project? I use Windows Kit 8. Almost all headers of Media foundation are part of Windows SDK (Kit). Try to download the suitable Windows SDK from Microsoft site.
2. MEVideoCaptureDeviceRemoved - is not macro. It is enum in mfobjects.h. You can copy this enum which is given below in Common.h or just use numerical integral = 800 . This numerical code is generated when video device is unplugged.
enum __MIDL___MIDL_itf_mfobjects_0000_0012_0001
{
MEUnknown = 0,
MEError = 1,
MEExtendedType = 2,
MENonFatalError = 3,
MEGenericV1Anchor = MENonFatalError,
MESessionUnknown = 100,
MESessionTopologySet = 101,
MESessionTopologiesCleared = 102,
MESessionStarted = 103,
MESessionPaused = 104,
MESessionStopped = 105,
MESessionClosed = 106,
MESessionEnded = 107,
MESessionRateChanged = 108,
MESessionScrubSampleComplete = 109,
MESessionCapabilitiesChanged = 110,
MESessionTopologyStatus = 111,
MESessionNotifyPresentationTime = 112,
MENewPresentation = 113,
MELicenseAcquisitionStart = 114,
MELicenseAcquisitionCompleted = 115,
MEIndividualizationStart = 116,
MEIndividualizationCompleted = 117,
MEEnablerProgress = 118,
MEEnablerCompleted = 119,
MEPolicyError = 120,
MEPolicyReport = 121,
MEBufferingStarted = 122,
MEBufferingStopped = 123,
MEConnectStart = 124,
MEConnectEnd = 125,
MEReconnectStart = 126,
MEReconnectEnd = 127,
MERendererEvent = 128,
MESessionStreamSinkFormatChanged = 129,
MESessionV1Anchor = MESessionStreamSinkFormatChanged,
MESourceUnknown = 200,
MESourceStarted = 201,
MEStreamStarted = 202,
MESourceSeeked = 203,
MEStreamSeeked = 204,
MENewStream = 205,
MEUpdatedStream = 206,
MESourceStopped = 207,
MEStreamStopped = 208,
MESourcePaused = 209,
MEStreamPaused = 210,
MEEndOfPresentation = 211,
MEEndOfStream = 212,
MEMediaSample = 213,
MEStreamTick = 214,
MEStreamThinMode = 215,
MEStreamFormatChanged = 216,
MESourceRateChanged = 217,
MEEndOfPresentationSegment = 218,
MESourceCharacteristicsChanged = 219,
MESourceRateChangeRequested = 220,
MESourceMetadataChanged = 221,
MESequencerSourceTopologyUpdated = 222,
MESourceV1Anchor = MESequencerSourceTopologyUpdated,
MESinkUnknown = 300,
MEStreamSinkStarted = 301,
MEStreamSinkStopped = 302,
MEStreamSinkPaused = 303,
MEStreamSinkRateChanged = 304,
MEStreamSinkRequestSample = 305,
MEStreamSinkMarker = 306,
MEStreamSinkPrerolled = 307,
MEStreamSinkScrubSampleComplete = 308,
MEStreamSinkFormatChanged = 309,
MEStreamSinkDeviceChanged = 310,
MEQualityNotify = 311,
MESinkInvalidated = 312,
MEAudioSessionNameChanged = 313,
MEAudioSessionVolumeChanged = 314,
MEAudioSessionDeviceRemoved = 315,
MEAudioSessionServerShutdown = 316,
MEAudioSessionGroupingParamChanged = 317,
MEAudioSessionIconChanged = 318,
MEAudioSessionFormatChanged = 319,
MEAudioSessionDisconnected = 320,
MEAudioSessionExclusiveModeOverride = 321,
MESinkV1Anchor = MEAudioSessionExclusiveModeOverride,
MECaptureAudioSessionVolumeChanged = 322,
MECaptureAudioSessionDeviceRemoved = 323,
MECaptureAudioSessionFormatChanged = 324,
MECaptureAudioSessionDisconnected = 325,
MECaptureAudioSessionExclusiveModeOverride = 326,
MECaptureAudioSessionServerShutdown = 327,
MESinkV2Anchor = MECaptureAudioSessionServerShutdown,
METrustUnknown = 400,
MEPolicyChanged = 401,
MEContentProtectionMessage = 402,
MEPolicySet = 403,
METrustV1Anchor = MEPolicySet,
MEWMDRMLicenseBackupCompleted = 500,
MEWMDRMLicenseBackupProgress = 501,
MEWMDRMLicenseRestoreCompleted = 502,
MEWMDRMLicenseRestoreProgress = 503,
MEWMDRMLicenseAcquisitionCompleted = 506,
MEWMDRMIndividualizationCompleted = 508,
MEWMDRMIndividualizationProgress = 513,
MEWMDRMProximityCompleted = 514,
MEWMDRMLicenseStoreCleaned = 515,
MEWMDRMRevocationDownloadCompleted = 516,
MEWMDRMV1Anchor = MEWMDRMRevocationDownloadCompleted,
METransformUnknown = 600,
METransformNeedInput = ( METransformUnknown + 1 ) ,
METransformHaveOutput = ( METransformNeedInput + 1 ) ,
METransformDrainComplete = ( METransformHaveOutput + 1 ) ,
METransformMarker = ( METransformDrainComplete + 1 ) ,
MEByteStreamCharacteristicsChanged = 700,
MEVideoCaptureDeviceRemoved = 800,
MEVideoCaptureDevicePreempted = 801,
MEReservedMax = 10000
} ;
3. About error when stopping.
IMAGEGRABBER VIDEODEVICE 0: Start Grabbing of the images
IMAGEGRABBER VIDEODEVICE 0: Stopping of of grabbing of images
IMAGEGRABBERTHREAD VIDEODEVICE 0: Destroing ImageGrabberThread
an error occured at
hr = ig_pSession->GetEvent(0, &pEvent);
After "Stopping of of grabbing of images" the code must generate "MESessionStopped". The code for this
void ImageGrabber::stopGrabbing()
{
if(ig_pSession)
ig_pSession->Stop();
DebugPrintOut *DPO = &DebugPrintOut::getInstance();
DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Stopping of of grabbing of images\n", ig_DeviceID);
}
where ig_pSession - is current IMESession pointer. Check the value of it by debugging ImageGrabber.cpp.
After calling method
ig_pSession->Stop(); the main thread is slept for 0.5 sec
void videoDevice::closeDevice()
{
if(vd_IsSetuped)
{
vd_IsSetuped = false;
vd_pSource->Stop();
if(vd_LockOut == RawDataLock)
{
vd_pImGrTh->stop();
Sleep(500);
vd_pImGrTh.reset(0);
SafeReleaseAllCount(&vd_pSource);
}
SafeRelease(&vd_pSource);
vd_LockOut = OpenLock;
DebugPrintOut *DPO = &DebugPrintOut::getInstance();
DPO->printOut(L"VIDEODEVICE %i: Device is stopped \n", vd_CurrentNumber);
}
}
For 0.5 second the code
hr = ig_pSession->GetEvent(0, &pEvent);
must generate pEvent with num code
if (met == MESessionStopped)
{
DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionStopped \n", ig_DeviceID);
break;
}
and break out from the while loop, and the pointer vd_pSource is released fully -
SafeReleaseAllCount(&vd_pSource); . But in your case the while loop is not break out and after the vd_pSource is released fully, the code
hr = ig_pSession->GetEvent(0, &pEvent); uses the pointer ig_pSession which is released already.
I cannot give you the solving of this problem, but I can advice to you to do a debugging of processing of the pointer ig_pSession - you compiler generate code, which has invalid process of this pointer.
Evgeny
|
|
|
|
|
In debug mode, i checked the code step by step, vd_pSource is NULL after
SafeReleaseAllCount(&vd_pSource);
and then everything is OK, but without debug, the error appeared all the same
I replace the thread sleep time for 1.5 sec, that is
Sleep(1500);
then everything is ok whether it is under debug mode or release mode,
i was wondering is it the sleep time that cause the problem?
|
|
|
|
|
Hi,
This problem is not bound with Sleep() function on direct way. The fact is that in the program there is two threads: thread of the main program, where methods of videoInput are called and thread of grabbing, where there is code
hr = ig_pSession->GetEvent(0, &pEvent); . function Sleep(500) is used for synchronization of threads - the grabbing thread must catch the event of stopping session - MESessionStopped for 0.5 second. I thought that half second is enough for stopping the session of capturing of device. However. in you case it takes more than 0.5 second. Of course, it would be better to use mutix or semafor for synchronization of two threads, but I did not have much time on it. And I thought that these elements of synchronization can make dead block in case of there is not existence of event - MESessionStopped. I thought that it would be better to have exception which can be processed by try - catch than have dead lock of threads. However, I have idea to include these type synchronization.
Evgeny
modified 25-Apr-14 3:55am.
|
|
|
|
|
Hi,
I just want say that after some thinking I have made decision that it is not professional to use Sleep() function for the purpose of synchronization of the threads. I have corrected code and include in it mutex and wait function. It works OK on my comp. If you want - you can get modificated version on updated page.
if(vd_LockOut == RawDataLock)
{
vd_pImGrTh->stop();
WaitForSingleObject(vd_pImGrTh->getMutexHandle(), 5000);
vd_pImGrTh.reset(0);
SafeReleaseAllCount(&vd_pSource);
}
|
|
|
|
|
thanks a lot, i will have a try.
|
|
|
|
|
After more and more reaserch i found that site.
BUT still i can't pass 640x480 resolution. Is it possible to get full resolution with this lib on Windows 8 tablet with Intel ISP?
|
|
|
|
|
Hi,
I developed the code only for Windows 8 Desktop and I did not work on tablet version.
However, I can say one thing - I am sure on 100% that old code on DirectShow will not work on tablet. The COMPANY invests much force in Media Foundation framework.
I advise you to debug the code in Visual Studio and direct info on consol.
|
|
|
|
|
This is Windows 8 x86 tablet. I'm not interested in metro, only desktop app. DirectShow gives me resolutionn of 448x252px. Before i've tried OpenCV - 640x480 max.
There is no camera in device manager/imaging devices, only Intel ISP 2300. OV2720/OV8830 can be found in system devices.
Buil-in metro camera app works but i want control it from my program.
|
|
|
|
|
You can try to get the list of supported capture format by calling functions:
unsigned int getCountFormats(unsigned int deviceID);
MediaType getFormat(unsigned int deviceID, int unsigned id);
You will get the amount of the supported formats and the inform about of format in structure MediaType.
|
|
|
|
|
Thank you so much for this library, it works pretty well and saves so much time.
I found one little quirk so far which caused some confuison to me: While changing camera/video parameters i noticed, that the getParametrs method always sets the current values to the default value. Is this behaviour intended?
Cheers,
Heinrich.
|
|
|
|
|