Example #1
0
        // The '1' indicates there should only be 1 processing thread.
        // AudioDelayAsync doesn't support more than 1 thread.
        public AudioDelayAsync()
            : base(1)
        {
            Trace("AudioDelayAsync Constructor");

            m_pbDelayBuffer = IntPtr.Zero;
            m_cbDelayBuffer = 0;
            m_pbDelayPtr    = IntPtr.Zero;
            m_dwDelay       = DEFAULT_DELAY;
            m_cbTailSamples = 0;
            m_rtTimestamp   = -1;

            // Add some attributes to the MFTs attribute list.
            IMFAttributes ia = Attributes;
            MFError       throwonhr;

            throwonhr = ia.SetUINT32(MF_AUDIODELAY_WET_DRY_MIX, DEFAULT_WET_DRY_MIX);
            throwonhr = ia.SetUINT32(MF_AUDIODELAY_DELAY_LENGTH, DEFAULT_DELAY);

            m_Alignment      = 0;
            m_AvgBytesPerSec = 0;
            m_SamplesPerSec  = 0;
            m_BitsPerSample  = 0;
            m_NumChannels    = 0;
        }
Example #2
0
        // Token: 0x06000942 RID: 2370 RVA: 0x0001AFC4 File Offset: 0x000191C4
        private static IMFSinkWriter CreateSinkWriter(string outputFile)
        {
            IMFAttributes imfattributes = MediaFoundationApi.CreateAttributes(1);

            imfattributes.SetUINT32(MediaFoundationAttributes.MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, 1);
            IMFSinkWriter result;

            try
            {
                MediaFoundationInterop.MFCreateSinkWriterFromURL(outputFile, null, imfattributes, out result);
            }
            catch (COMException exception)
            {
                if (exception.GetHResult() == -1072875819)
                {
                    throw new ArgumentException("Was not able to create a sink writer for this file extension");
                }
                throw;
            }
            finally
            {
                Marshal.ReleaseComObject(imfattributes);
            }
            return(result);
        }
        private static IMFTranscodeProfile CreateProfile(AudioFormat audioOutput, VideoFormat videoOutput, Guid containerType)
        {
            IMFTranscodeProfile profile = null;

            // Create a transcode profile
            MFHelper.MFCreateTranscodeProfile(out profile);

            // Create and set the audio attributes
            profile.SetAudioAttributes(SimpleFastEncode.CreateAudioAttributes(audioOutput));

            // Create and set the video attributes
            profile.SetVideoAttributes(SimpleFastEncode.CreateVideoAttributes(videoOutput));

            // Create the container attributes
            IMFAttributes containerAttributes = null;

            MFHelper.MFCreateAttributes(out containerAttributes, 2);
            containerAttributes.SetUINT32(new Guid(Consts.MF_TRANSCODE_TOPOLOGYMODE), 1);
            containerAttributes.SetGUID(new Guid(Consts.MF_TRANSCODE_CONTAINERTYPE), containerType);

            // Set them in the transcoding profile
            profile.SetContainerAttributes(containerAttributes);

            return(profile);
        }
        private static IMFAttributes CreateVideoAttributes(VideoFormat videoOutput)
        {
            IMFAttributes videoAttributes = null;

            MFHelper.MFCreateAttributes(out videoAttributes, 0);
            videoAttributes.SetGUID(new Guid(Consts.MF_MT_SUBTYPE), videoOutput.Subtype);

            PackedINT32 pixelAspectRatio = new PackedINT32(1, 1);

            // Set the argument attributes
            videoAttributes.SetUINT64(new Guid(Consts.MF_MT_FRAME_RATE), videoOutput.FrameRate.Packed);
            videoAttributes.SetUINT64(new Guid(Consts.MF_MT_FRAME_SIZE), videoOutput.FrameSize.Packed);
            videoAttributes.SetUINT64(new Guid(Consts.MF_MT_PIXEL_ASPECT_RATIO), pixelAspectRatio.Packed);
            videoAttributes.SetUINT32(new Guid(Consts.MF_MT_INTERLACE_MODE), videoOutput.InterlaceMode);
            videoAttributes.SetUINT32(new Guid(Consts.MF_MT_AVG_BITRATE), videoOutput.AvgBitRate);

            return(videoAttributes);
        }
        /// <summary>
        /// Associates a UInt32 value with a key.
        /// </summary>
        /// <param name="attributes">A valid IMFAttributes instance.</param>
        /// <param name="guidKey">Guid that identifies the value to set.</param>
        /// <param name="value">New value for this key.</param>
        /// <returns>If this function succeeds, it returns the S_OK member. Otherwise, it returns another HResult's member that describe the error.</returns>
        public static HResult SetUINT32(this IMFAttributes attributes, Guid guidKey, uint value)
        {
            if (attributes == null)
            {
                throw new ArgumentNullException("attributes");
            }

            return(attributes.SetUINT32(guidKey, unchecked ((int)value)));
        }
Example #6
0
        protected void SetTargetStream(Stream stream, MFMediaType inputMediaType, MFMediaType targetMediaType, Guid containerType)
        {
            IMFAttributes attributes = null;

            try
            {
                _targetStream = MediaFoundationCore.IStreamToByteStream(new ComStream(stream));

                MFByteStreamCapsFlags flags = MFByteStreamCapsFlags.None;
                int result = _targetStream.GetCapabilities(ref flags);

                attributes = MediaFoundationCore.CreateEmptyAttributes(2);
                attributes.SetUINT32(MediaFoundationAttributes.MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, 1);
                attributes.SetGUID(MediaFoundationAttributes.MF_TRANSCODE_CONTAINERTYPE, containerType);

                _sinkWriter = MediaFoundationCore.CreateSinkWriterFromMFByteStream(_targetStream, attributes);

                _streamIndex = _sinkWriter.AddStream(targetMediaType);
                _sinkWriter.SetInputMediaType(_streamIndex, inputMediaType, null);

                _inputMediaType       = inputMediaType;
                _targetMediaType      = targetMediaType;
                _sourceBytesPerSecond = inputMediaType.AverageBytesPerSecond;

                //initialize the sinkwriter
                _sinkWriter.BeginWriting();
            }
            catch (Exception)
            {
                if (_sinkWriter != null)
                {
                    _sinkWriter.Dispose();
                    _sinkWriter = null;
                }
                if (_targetStream != null)
                {
                    _targetStream.Close();
                    Marshal.ReleaseComObject(_targetStream);
                    _targetStream = null;
                }
                throw;
            }
            finally
            {
                if (attributes != null)
                {
                    Marshal.ReleaseComObject(attributes);
                }
            }
        }
Example #7
0
        public void initialize(int streamId, IMFMediaType mediaType)
        {
            //process input.
            ThrowIfError(MFExtern.MFGetAttributeSize(mediaType, MFAttributesClsid.MF_MT_FRAME_SIZE, out _videoWitdh, out _videoHeight));
            ThrowIfError(MFExtern.MFGetAttributeRatio(mediaType, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO, out _videoRatioN, out _videoRatioD));
            ThrowIfError(pDecoderTransform.SetInputType(streamId, mediaType, MFTSetTypeFlags.None));

            //process output
            IMFMediaType h264OutputType;

            ThrowIfError(MFExtern.MFCreateMediaType(out h264OutputType));
            ThrowIfError(h264OutputType.SetGUID(MF_MT_MAJOR_TYPE, MFMediaType.Video));
            ThrowIfError(h264OutputType.SetGUID(MF_MT_SUBTYPE, MFMediaType.YUY2));

            IMFAttributes attr = h264OutputType as IMFAttributes;

            ThrowIfError(MFExtern.MFSetAttributeSize(attr, MF_MT_FRAME_SIZE, _videoWitdh, _videoHeight));
            ThrowIfError(MFExtern.MFSetAttributeRatio(attr, MF_MT_FRAME_RATE, 30, 1));
            ThrowIfError(MFExtern.MFSetAttributeRatio(attr, MF_MT_PIXEL_ASPECT_RATIO, _videoRatioN, _videoRatioD));
            ThrowIfError(attr.SetUINT32(MF_MT_INTERLACE_MODE, 2));

            ThrowIfError(pDecoderTransform.SetOutputType(streamId, h264OutputType, MFTSetTypeFlags.None));

            MFTInputStatusFlags mftStatus;

            ThrowIfError(pDecoderTransform.GetInputStatus(streamId, out mftStatus));

            if (MFTInputStatusFlags.AcceptData != mftStatus)
            {
                throw new Exception("H.264 decoder MFT is not accepting data.\n");
            }

            ThrowIfError(pDecoderTransform.ProcessMessage(MFTMessageType.CommandFlush, IntPtr.Zero));
            ThrowIfError(pDecoderTransform.ProcessMessage(MFTMessageType.NotifyBeginStreaming, IntPtr.Zero));
            ThrowIfError(pDecoderTransform.ProcessMessage(MFTMessageType.NotifyStartOfStream, IntPtr.Zero));

            ThrowIfError(MFExtern.MFCreateSample(out _mftOutSample));

            _mftOutBufferContainer = new MFTOutputDataBuffer[1];
            //todo:set the stream id again when receive media stream later.
            _mftOutBufferContainer[0].dwStreamID = streamId;
            _mftOutBufferContainer[0].dwStatus   = 0;
            _mftOutBufferContainer[0].pEvents    = null;
            _mftOutBufferContainer[0].pSample    = Marshal.GetIUnknownForObject(_mftOutSample);

            _videoStreamId   = streamId;
            _streamMediaType = mediaType;
        }
Example #8
0
        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Set the flip type on our rotator transform in the EVR control
        /// </summary>
        /// <param name="flipType">the fliptype to use</param>
        /// <history>
        ///    01 Nov 18  Cynic - Originally Written
        /// </history>
        private void SetFlipModeOnTransform(RotateFlipType flipType)
        {
            // get the attribute container from the transform in the EVR player
            IMFAttributes attributeContainer = ctlTantaEVRFilePlayer1.GetTransformAttributes();

            if (attributeContainer == null)
            {
                return;
            }

            // set the fliptype as an int32. Attributes cannot contain enums
            HResult hr = attributeContainer.SetUINT32(clsidFlipMode, (int)flipType);

            // release it
            System.Runtime.InteropServices.Marshal.ReleaseComObject(attributeContainer);
        }
        private IMFSinkWriter CreateSinkWriter(string url)
        {
            var factory = (IMFReadWriteClassFactory)(new MFReadWriteClassFactory());

            // Create the attributes
            IMFAttributes attributes = MediaFoundationApi.CreateAttributes(1);

            attributes.SetUINT32(MediaFoundationAttributes.MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, 1);

            object sinkWriterObject;
            // TODO: need to move the class IDs into their own class for use in cases like this
            var guidMFSinkWriter  = new Guid("a3bbfb17-8273-4e52-9e0e-9739dc887990");
            var guidIMFSinkWriter = new Guid("3137f1cd-fe5e-4805-a5d8-fb477448cb3d");

            factory.CreateInstanceFromURL(guidMFSinkWriter, url, attributes, guidIMFSinkWriter, out sinkWriterObject);
            Marshal.ReleaseComObject(factory);
            return((IMFSinkWriter)sinkWriterObject);
        }
        private void CreateReaderAndWriter()
        {
            object        sourceReaderObject = null;
            object        sinkWriterObject   = null;
            IMFAttributes attributes         = null;

            // Create the class factory
            IMFReadWriteClassFactory factory = (IMFReadWriteClassFactory)(new MFReadWriteClassFactory());

            // Create the attributes
            MFHelper.MFCreateAttributes(out attributes, 1);
            attributes.SetUINT32(new Guid(Consts.MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS), 1);

            // Use the factory to create the Source Reader
            factory.CreateInstanceFromURL(new Guid(CLSID.MFSourceReader), this.sourceFilename, attributes, new Guid(IID.IMFSourceReader), out sourceReaderObject);
            this.sourceReader = (IMFSourceReader)sourceReaderObject;

            // Use the factory to create the Sink Writer
            factory.CreateInstanceFromURL(new Guid(CLSID.MFSinkWriter), this.targetFilename, attributes, new Guid(IID.IMFSinkWriter), out sinkWriterObject);
            this.sinkWriter = (IMFSinkWriter)sinkWriterObject;
        }
Example #11
0
        private IMFSourceReader CreateSourceReader(IMFMediaSource mfs)
        {
            IMFSourceReader reader = null;

            try
            {
                MFExtern.MFCreateAttributes(out sourcevideoreaderattribute, 2);

                sourcevideoreaderattribute.SetGUID(MFAttributesClsid.MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, CLSID.MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
                sourcevideoreaderattribute.SetUINT32(MFAttributesClsid.MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, 1);


                MFExtern.MFCreateSourceReaderFromMediaSource(mfs, sourcevideoreaderattribute, out reader);
                //reader.GetCurrentMediaType((int)__MIDL___MIDL_itf_mfreadwrite_0000_0001_0001.MF_SOURCE_READER_FIRST_VIDEO_STREAM, out sourcemeidatype);
            }
            catch (Exception e)
            {
                Debug.WriteLine("ERROR CreateSourceReader", e.StackTrace);
            }
            return(reader);
        }
Example #12
0
        private void Form1_KeyPress(object sender, KeyPressEventArgs e)
        {
            switch (e.KeyChar)
            {
            // Space key toggles between running and paused
            case ' ':
                e.Handled = true;
                if (g_pPlayer.GetState() == CPlayer.PlayerState.Started)
                {
                    g_pPlayer.Pause();
                }
                else if (g_pPlayer.GetState() == CPlayer.PlayerState.Paused)
                {
                    g_pPlayer.Play();
                }
                break;

            case 'r':
                e.Handled = true;
                if (rotateAsyncToolStripMenuItem.Checked)
                {
                    IMFAttributes ia = g_pPlayer.GetVideoAttributes();
                    if (ia != null)
                    {
                        Guid    ClsidRotate = new Guid("AC776FB5-858F-4891-A5DC-FD01E79B5AD6");
                        int     i;
                        HResult hr;
                        hr = ia.GetUINT32(ClsidRotate, out i);
                        if (hr >= 0)
                        {
                            i  = i < 7 ? i + 1 : 0;
                            hr = ia.SetUINT32(ClsidRotate, i);
                        }
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(ia);
                    }
                }
                break;
            }
        }
Example #13
0
 public HResult SetUINT32(Guid guidKey, int unValue)
 {
     return(m_Attribs.SetUINT32(guidKey, unValue));
 }
 /// <summary>
 /// Associates a Boolean value with a key.
 /// </summary>
 /// <param name="attributes">A valid IMFAttributes instance.</param>
 /// <param name="guidKey">Guid that identifies the value to set.</param>
 /// <param name="value">New value for this key.</param>
 /// <remarks>Media Foundation attributes don't support boolean values. This method set them as a 32-bits unsigned integer and store 1 for true and 0 for false.</remarks>
 public static HResult SetBoolean(this IMFAttributes attributes, Guid guidKey, bool value)
 {
     return(attributes.SetUINT32(guidKey, (value ? 1u : 0u)));
 }
        /// <summary>
        ///     Starts the asychronous encode operation
        /// </summary>
        /// <param name="inputURL">Source filename</param>
        /// <param name="outputURL">Targe filename</param>
        /// <param name="audioOutput">Audio format that will be used for audio streams</param>
        /// <param name="videoOutput">Video format that will be used for video streams</param>
        /// <param name="startPosition">Starting position of the contet</param>
        /// <param name="endPosition">Position where the new content will end</param>
        public void Encode(string inputURL, string outputURL, AudioFormat audioOutput, VideoFormat videoOutput, ulong startPosition, ulong endPosition)
        {
            // If busy with other operation ignore and return
            if (this.IsBusy())
            {
                return;
            }

            try
            {
                this.presentationClock = null;
                this.startPosition     = startPosition;
                this.endPosition       = endPosition;

                object objectSource = null;

                // Create the media source using source resolver and the input URL
                uint objectType = default(uint);
                this.mediaSource = null;

                // Init source resolver
                IMFSourceResolver sourceResolver = null;
                MFHelper.MFCreateSourceResolver(out sourceResolver);

                sourceResolver.CreateObjectFromURL(inputURL, Consts.MF_RESOLUTION_MEDIASOURCE, null, out objectType, out objectSource);

                this.mediaSource = (IMFMediaSource)objectSource;

                // Create the media session using a global start time so MF_TOPOLOGY_PROJECTSTOP can be used to stop the session
                this.mediaSession = null;
                IMFAttributes mediaSessionAttributes = null;

                MFHelper.MFCreateAttributes(out mediaSessionAttributes, 1);
                mediaSessionAttributes.SetUINT32(new Guid(Consts.MF_SESSION_GLOBAL_TIME), 1);

                MFHelper.MFCreateMediaSession(mediaSessionAttributes, out this.mediaSession);

                // Create the event handler
                AsyncEventHandler mediaEventHandler = new AsyncEventHandler(this.mediaSession);
                mediaEventHandler.MediaEvent += this.MediaEvent;

                // Get the stream descriptor
                IMFPresentationDescriptor presentationDescriptor = null;
                mediaSource.CreatePresentationDescriptor(out presentationDescriptor);

                // Get the duration
                presentationDescriptor.GetUINT64(new Guid(Consts.MF_PD_DURATION), out this.duration);
                IMFTranscodeProfile transcodeProfile = null;

                Guid containerType = new Guid(Consts.MFTranscodeContainerType_MPEG4);
                if (outputURL.EndsWith(".wmv", StringComparison.OrdinalIgnoreCase) || outputURL.EndsWith(".wma", StringComparison.OrdinalIgnoreCase))
                {
                    containerType = new Guid(Consts.MFTranscodeContainerType_ASF);
                }

                // Generate the transcoding profile
                transcodeProfile = SimpleFastEncode.CreateProfile(audioOutput, videoOutput, containerType);

                // Create the MF topology using the profile
                IMFTopology topology = null;
                MFHelper.MFCreateTranscodeTopology(this.mediaSource, outputURL, transcodeProfile, out topology);

                // Set the end position
                topology.SetUINT64(new Guid(Consts.MF_TOPOLOGY_PROJECTSTART), 0);
                topology.SetUINT64(new Guid(Consts.MF_TOPOLOGY_PROJECTSTOP), (endPosition == 0) ? this.duration : endPosition);

                // Set the session topology
                this.mediaSession.SetTopology((uint)Enums.MFSESSION_SETTOPOLOGY_FLAGS.None, topology);
            }
            catch (Exception ex)
            {
                this.mediaSession = null;

                // Fire the EncodeError event
                if (this.EncodeError != null)
                {
                    this.EncodeError(new Exception(ex.Message, ex));
                }
            }
        }
Example #16
0
        //-------------------------------------------------------------------
        // SetDevice
        //
        // Set up preview for a specified video capture device.
        //-------------------------------------------------------------------

        public HResult SetDevice(MFDevice pDevice)
        {
            HResult hr = HResult.S_OK;

            IMFActivate    pActivate   = pDevice.Activator;
            IMFMediaSource pSource     = null;
            IMFAttributes  pAttributes = null;
            object         o           = null;

            lock (this)
            {
                try
                {
                    // Release the current device, if any.
                    hr = CloseDevice();

                    if (Succeeded(hr))
                    {
                        // Create the media source for the device.
                        hr = pActivate.ActivateObject(typeof(IMFMediaSource).GUID, out o);
                    }

                    if (Succeeded(hr))
                    {
                        pSource = (IMFMediaSource)o;
                    }

                    // Get Symbolic device link
                    m_pwszSymbolicLink = pDevice.SymbolicName;

                    //
                    // Create the source reader.
                    //

                    // Create an attribute store to hold initialization settings.

                    if (Succeeded(hr))
                    {
                        hr = MFExtern.MFCreateAttributes(out pAttributes, 2);
                    }

                    if (Succeeded(hr))
                    {
                        hr = pAttributes.SetUINT32(MFAttributesClsid.MF_READWRITE_DISABLE_CONVERTERS, 1);
                    }

                    if (Succeeded(hr))
                    {
                        hr = pAttributes.SetUnknown(MFAttributesClsid.MF_SOURCE_READER_ASYNC_CALLBACK, this);
                    }

                    IMFSourceReader pRead = null;
                    if (Succeeded(hr))
                    {
                        hr = MFExtern.MFCreateSourceReaderFromMediaSource(pSource, pAttributes, out pRead);
                    }

                    if (Succeeded(hr))
                    {
                        m_pReader = (IMFSourceReaderAsync)pRead;
                    }

                    if (Succeeded(hr))
                    {
                        // Try to find a suitable output type.
                        for (int i = 0; ; i++)
                        {
                            IMFMediaType pType;
                            hr = m_pReader.GetNativeMediaType((int)MF_SOURCE_READER.FirstVideoStream, i, out pType);
                            if (Failed(hr))
                            {
                                break;
                            }

                            try
                            {
                                hr = TryMediaType(pType);
                                if (Succeeded(hr))
                                {
                                    // Found an output type.
                                    break;
                                }
                            }
                            finally
                            {
                                SafeRelease(pType);
                            }
                        }
                    }

                    if (Succeeded(hr))
                    {
                        // Ask for the first sample.
                        hr = m_pReader.ReadSample((int)MF_SOURCE_READER.FirstVideoStream, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
                    }

                    if (Failed(hr))
                    {
                        if (pSource != null)
                        {
                            pSource.Shutdown();

                            // NOTE: The source reader shuts down the media source
                            // by default, but we might not have gotten that far.
                        }
                        CloseDevice();
                    }
                }
                finally
                {
                    SafeRelease(pSource);
                    SafeRelease(pAttributes);
                }
            }

            return(hr);
        }
Example #17
0
        /// <summary>
        /// Opens the Sink Writer object
        /// </summary>
        /// <param name="outputFileName">the filename we write out to</param>
        /// <param name="wantDisableThrottling">if true we set a flag that disabled throttling</param>
        /// <returns>an IMFSinkWriter object or null for fail</returns>
        private IMFSinkWriter OpenSinkWriter(string outputFileName, bool wantDisableThrottling)
        {
            HResult       hr;
            IMFSinkWriter workingWriter      = null;
            IMFAttributes attributeContainer = null;

            if ((outputFileName == null) || (outputFileName.Length == 0))
            {
                // we failed
                throw new Exception("OpenSinkWriter: Invalid filename specified");
            }
            try
            {
                if (wantDisableThrottling == true)
                {
                    // Initialize an attribute store. We will use this to
                    // specify the enumeration parameters.
                    hr = MFExtern.MFCreateAttributes(out attributeContainer, 1);
                    if (hr != HResult.S_OK)
                    {
                        // we failed
                        throw new Exception("OpenSinkWriter: failed on call to MFCreateAttributes, retVal=" + hr.ToString());
                    }
                    if (attributeContainer == null)
                    {
                        // we failed
                        throw new Exception("OpenSinkWriter: attributeContainer == MFAttributesClsid.null");
                    }
                    // setup the attribute container
                    hr = attributeContainer.SetUINT32(MFAttributesClsid.MF_SINK_WRITER_DISABLE_THROTTLING, 1);
                    if (hr != HResult.S_OK)
                    {
                        // we failed
                        throw new Exception("OpenSinkWriter: failed setting up the attributes, retVal=" + hr.ToString());
                    }
                }
                try
                {
                    // Create the sink writer. This takes the URL of an output file or a pointer to a byte stream and
                    // creates the media sink internally. You could also use the more round-about
                    // MFCreateSinkWriterFromMediaSink takes a pointer to a media sink that has already been created by
                    // the application. If you are using one of the built-in media sinks, the MFCreateSinkWriterFromURL
                    // function is preferable, because the caller does not need to configure the media sink.
                    hr = MFExtern.MFCreateSinkWriterFromURL(outputFileName, null, null, out workingWriter);
                    if (hr != HResult.S_OK)
                    {
                        // we failed
                        throw new Exception("OpenSinkWriter: Failed on call to MFCreateSinkWriterFromURL, retVal=" + hr.ToString());
                    }
                    if (workingWriter == null)
                    {
                        // we failed
                        throw new Exception("OpenSinkWriter: Failed to create Sink Writer, Nothing will work.");
                    }
                }
                catch (Exception ex)
                {
                    // note this clean up is in the Catch block not the finally block.
                    // if there are no errors we return it to the caller. The caller
                    // is expected to clean up after itself
                    if (workingWriter != null)
                    {
                        // clean up. Nothing else has this yet
                        Marshal.ReleaseComObject(workingWriter);
                        workingWriter = null;
                    }
                    workingWriter = null;
                    throw ex;
                }
            }
            finally
            {
                if (attributeContainer != null)
                {
                    // clean up.
                    Marshal.ReleaseComObject(attributeContainer);
                }
            }
            return(workingWriter);
        }