Ejemplo n.º 1
0
        /// <summary>
        /// Converts the specified wave format into the appropriate Media Foundation audio media type.
        /// </summary>
        /// <param name="format">Input wave format to convert.</param>
        /// <returns>Media Foundation type resulting from conversion.</returns>
        internal static IMFMediaType CreateMediaType(WaveFormat format)
        {
            IMFMediaType mediaType = null;

            Guid guidSubType = GetMediaSubtype(format);

            if (guidSubType != Guid.Empty)
            {
                // Create the empty media type.
                mediaType = NativeMethods.MFCreateMediaType();

                // Calculate derived values.
                uint blockAlign     = (uint)(format.Channels * (format.BitsPerSample / 8));
                uint bytesPerSecond = (uint)(blockAlign * format.SamplesPerSec);

                // Set attributes on the type.
                mediaType.SetGUID(Guids.MFMTMajorType, Guids.MFMediaTypeAudio);
                mediaType.SetGUID(Guids.MFMTSubType, guidSubType);
                mediaType.SetUINT32(Guids.MFMTAudioNumChannels, format.Channels);
                mediaType.SetUINT32(Guids.MFMTAudioSamplesPerSecond, format.SamplesPerSec);
                mediaType.SetUINT32(Guids.MFMTAudioBlockAlignment, blockAlign);
                mediaType.SetUINT32(Guids.MFMTAudioAvgBytesPerSecond, bytesPerSecond);
                mediaType.SetUINT32(Guids.MFMTAudioBitsPerSample, format.BitsPerSample);
                mediaType.SetUINT32(Guids.MFMTAllSamplesIndependent, 1);
            }

            return(mediaType);
        }
Ejemplo n.º 2
0
        private void CreateH264Decoder()
        {
            HResult hr;
            // create H.264 decoder

            var comobject = new ResamplerMediaComObject();

            decodertransform = (IMFTransform)comobject;

            // setup input media type for decoder
            MFExtern.MFCreateMediaType(out decinputmediatype);

            // setup media type manualy
            IMFMediaType testdecinputmediatype, testdecoutputmediatype;

            decinputmediatype.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video);
            decinputmediatype.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MFMediaType.H264);
            decinputmediatype.SetUINT32(MFAttributesClsid.MF_MT_INTERLACE_MODE, (int)MFVideoInterlaceMode.Progressive);

            MFExtern.MFSetAttributeSize(decinputmediatype, MFAttributesClsid.MF_MT_FRAME_SIZE, VIDEO_SAMPLE_WIDTH, VIDEO_SAMPLE_HEIGHT);
            uint fixedSampleSize = VIDEO_SAMPLE_WIDTH * (16 * ((VIDEO_SAMPLE_HEIGHT + 15) / 16)) + VIDEO_SAMPLE_WIDTH * (VIDEO_SAMPLE_HEIGHT / 2);//for Y, U and V

            decinputmediatype.SetUINT32(MFAttributesClsid.MF_MT_SAMPLE_SIZE, fixedSampleSize);
            decinputmediatype.SetUINT32(MFAttributesClsid.MF_MT_DEFAULT_STRIDE, VIDEO_SAMPLE_WIDTH);
            decinputmediatype.SetUINT32(MFAttributesClsid.MF_MT_FIXED_SIZE_SAMPLES, 1);
            decinputmediatype.SetUINT32(MFAttributesClsid.MF_MT_ALL_SAMPLES_INDEPENDENT, 1);
            MFExtern.MFSetAttributeRatio(decinputmediatype, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO, 1, 1);

            hr = decodertransform.SetInputType(0, decinputmediatype, 0);

            decodertransform.GetInputAvailableType(0, 0, out testdecinputmediatype);

            // setup media type for output of decoder
            MFExtern.MFCreateMediaType(out decoutputmediatype);
            decoutputmediatype.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video);
            decoutputmediatype.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MFMediaType.IYUV);
            MFExtern.MFSetAttributeSize(decoutputmediatype, MFAttributesClsid.MF_MT_FRAME_SIZE, VIDEO_SAMPLE_WIDTH, VIDEO_SAMPLE_HEIGHT);
            MFExtern.MFSetAttributeRatio(decoutputmediatype, MFAttributesClsid.MF_MT_FRAME_RATE, 30, 1);
            MFExtern.MFSetAttributeRatio(decoutputmediatype, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
            decoutputmediatype.SetUINT32(MFAttributesClsid.MF_MT_INTERLACE_MODE, 2);

            hr = decodertransform.SetOutputType(0, decoutputmediatype, 0);
            decodertransform.GetOutputAvailableType(0, 0, out testdecoutputmediatype);

            decodertransform.GetInputStatus(0, out mftStatus);
            if (mftStatus != MFTInputStatusFlags.AcceptData)
            {
                Debug.WriteLine("DECODER NOT ACCEPT INPUT DATA");
                return;
            }
            else
            {
                Debug.WriteLine("PROCESS INPUT DONE>>>> " + mftStatus);
            }

            decodertransform.ProcessMessage(MFTMessageType.CommandFlush, (IntPtr)null);
            decodertransform.ProcessMessage(MFTMessageType.NotifyBeginStreaming, (IntPtr)null);
            decodertransform.ProcessMessage(MFTMessageType.NotifyStartOfStream, (IntPtr)null);
        }
Ejemplo n.º 3
0
        HResult ConfigureEncoder(
            EncodingParameters eparams,
            IMFMediaType pType,
            IMFSinkWriter pWriter,
            out int pdwStreamIndex
            )
        {
            HResult hr = HResult.S_OK;

            IMFMediaType pType2 = null;

            hr = MFExtern.MFCreateMediaType(out pType2);

            if (Succeeded(hr))
            {
                hr = pType2.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video);
            }

            if (Succeeded(hr))
            {
                hr = pType2.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, eparams.subtype);
            }

            if (Succeeded(hr))
            {
                hr = pType2.SetUINT32(MFAttributesClsid.MF_MT_AVG_BITRATE, eparams.bitrate);
            }

            if (Succeeded(hr))
            {
                hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_FRAME_SIZE);
            }

            if (Succeeded(hr))
            {
                hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_FRAME_RATE);
            }

            if (Succeeded(hr))
            {
                hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO);
            }

            if (Succeeded(hr))
            {
                hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_INTERLACE_MODE);
            }

            pdwStreamIndex = 0;
            if (Succeeded(hr))
            {
                hr = pWriter.AddStream(pType2, out pdwStreamIndex);
            }

            SafeRelease(pType2);

            return(hr);
        }
        private void NegotiateStream(uint streamIndex, Guid majorType, Guid[] possibleSubtypes)
        {
            IMFMediaType outputMediaType = null;
            Exception    lastException   = null;
            bool         foundValidType  = false;

            foreach (Guid subType in possibleSubtypes)
            {
                try
                {
                    // Create a partial media type
                    MFHelper.MFCreateMediaType(out outputMediaType);
                    outputMediaType.SetGUID(new Guid(Consts.MF_MT_MAJOR_TYPE), majorType);
                    outputMediaType.SetGUID(new Guid(Consts.MF_MT_SUBTYPE), subType);

                    // Set it as the current media type in source reader
                    this.sourceReader.SetCurrentMediaType(streamIndex, IntPtr.Zero, outputMediaType);

                    // Get the full media type from Source Reader
                    this.sourceReader.GetCurrentMediaType(streamIndex, out outputMediaType);

                    // Set it as the input media type in Sink Writer
                    this.sinkWriter.SetInputMediaType(this.streamsInfo[streamIndex].OutputStreamIndex, outputMediaType, null);

                    // If no exceptions were thrown a suitable media type was found
                    foundValidType = true;

                    // Break from the loop so no more media types are tried
                    break;
                }
                catch (Exception ex)
                {
                    // Something went wrong, the loop will continue and the next type will be tried
                    lastException = ex;
                }
            }

            // If FormatFound is false no suitable type was found and the operation can't continue
            if (foundValidType == false)
            {
                if (lastException != null)
                {
                    throw new Exception(lastException.Message, lastException);
                }
                else
                {
                    throw new Exception("Unknown error occurred");
                }
            }
        }
Ejemplo n.º 5
0
        public HRESULT SetGUID(Guid guidKey, Guid guidValue)
        {
            var hr = _type.SetGUID(guidKey, guidValue);

            Trace("key: " + guidKey.ToName() + " value: " + guidValue.ToName() + " hr: " + hr);
            return(hr);
        }
        private IMFMediaType CreateTargetVideoMediaType()
        {
            IMFMediaType mediaType = null;

            MFHelper.MFCreateMediaType(out mediaType);

            mediaType.SetGUID(new Guid(Consts.MF_MT_MAJOR_TYPE), new Guid(Consts.MFMediaType_Video));

            mediaType.SetGUID(new Guid(Consts.MF_MT_SUBTYPE), this.videoOutput.Subtype);
            mediaType.SetUINT64(new Guid(Consts.MF_MT_FRAME_SIZE), this.videoOutput.FrameSize.Packed);
            mediaType.SetUINT64(new Guid(Consts.MF_MT_FRAME_RATE), this.videoOutput.FrameRate.Packed);
            mediaType.SetUINT64(new Guid(Consts.MF_MT_PIXEL_ASPECT_RATIO), this.videoOutput.PixelAspectRatio.Packed);
            mediaType.SetUINT32(new Guid(Consts.MF_MT_AVG_BITRATE), this.videoOutput.AvgBitRate);
            mediaType.SetUINT32(new Guid(Consts.MF_MT_INTERLACE_MODE), this.videoOutput.InterlaceMode);

            return(mediaType);
        }
Ejemplo n.º 7
0
        //-------------------------------------------------------------------
        // TryMediaType
        //
        // Test a proposed video format.
        //-------------------------------------------------------------------
        protected HResult TryMediaType(IMFMediaType pType)
        {
            HResult hr = HResult.S_OK;

            bool bFound = false;
            Guid subtype;

            hr = pType.GetGUID(MFAttributesClsid.MF_MT_SUBTYPE, out subtype);
            if (Failed(hr))
            {
                return(hr);
            }

            // Do we support this type directly?
            if (m_draw.IsFormatSupported(subtype))
            {
                bFound = true;
            }
            else
            {
                // Can we decode this media type to one of our supported
                // output formats?

                for (int i = 0; ; i++)
                {
                    // Get the i'th format.
                    hr = m_draw.GetFormat(i, out subtype);
                    if (Failed(hr))
                    {
                        break;
                    }

                    hr = pType.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, subtype);
                    if (Failed(hr))
                    {
                        break;
                    }

                    // Try to set this type on the source reader.
                    hr = m_pReader.SetCurrentMediaType((int)MF_SOURCE_READER.FirstVideoStream, null, pType);
                    if (Succeeded(hr))
                    {
                        bFound = true;
                        break;
                    }
                }
            }

            if (bFound)
            {
                hr = m_draw.SetVideoType(pType);
            }

            return(hr);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Given an input media type, create the associated output type.
        /// </summary>
        /// <param name="inType">The input type from which to create the output type</param>
        /// <returns>An output type generated from the input type.</returns>
        protected override IMFMediaType CreateOutputFromInput()
        {
            MFError      throwonhr;
            IMFMediaType pOutputType = CloneMediaType(InputType);

            throwonhr = pOutputType.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, m_MediaSubtypesOut[0]);
            throwonhr = pOutputType.SetUINT32(MFAttributesClsid.MF_MT_DEFAULT_STRIDE, m_StrideOut);
            throwonhr = pOutputType.SetUINT32(MFAttributesClsid.MF_MT_SAMPLE_SIZE, m_cbImageSizeOutput);

            return(pOutputType);
        }
Ejemplo n.º 9
0
        //-------------------------------------------------------------------
        // TryMediaType
        //
        // Test a proposed video format.
        //-------------------------------------------------------------------
        protected int TryMediaType(IMFMediaType pType)
        {
            int hr = S_Ok;

            bool bFound = false;
            Guid subtype;

            hr = pType.GetGUID(MFAttributesClsid.MF_MT_SUBTYPE, out subtype);
            if (Failed(hr))
            {
                return hr;
            }

            // Do we support this type directly?
            if (m_draw.IsFormatSupported(subtype))
            {
                bFound = true;
            }
            else
            {
                // Can we decode this media type to one of our supported
                // output formats?

                for (int i = 0; ; i++)
                {
                    // Get the i'th format.
                    hr = m_draw.GetFormat(i, out subtype);
                    if (Failed(hr)) { break; }

                    hr = pType.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, subtype);
                    if (Failed(hr)) { break; }

                    // Try to set this type on the source reader.
                    hr = m_pReader.SetCurrentMediaType((int)MF_SOURCE_READER.FirstVideoStream, IntPtr.Zero, pType);
                    if (Succeeded(hr))
                    {
                        bFound = true;
                        break;
                    }
                }
            }

            if (bFound)
            {
                hr = m_draw.SetVideoType(pType);
            }

            return hr;
        }
        private IMFMediaType CreateTargetAudioMediaType()
        {
            IMFMediaType mediaType = null;

            if (audioOutput.Subtype.Equals(new Guid(Consts.MFAudioFormat_AAC)))
            {
                // Create the AAC media type
                MFHelper.MFCreateMediaType(out mediaType);

                mediaType.SetGUID(new Guid(Consts.MF_MT_MAJOR_TYPE), new Guid(Consts.MFMediaType_Audio));

                mediaType.SetGUID(new Guid(Consts.MF_MT_SUBTYPE), this.audioOutput.Subtype);
                mediaType.SetUINT32(new Guid(Consts.MF_MT_AUDIO_AVG_BYTES_PER_SECOND), this.audioOutput.AvgBytePerSecond);
                mediaType.SetUINT32(new Guid(Consts.MF_MT_AUDIO_NUM_CHANNELS), this.audioOutput.NumOfChannels);
                mediaType.SetUINT32(new Guid(Consts.MF_MT_AUDIO_SAMPLES_PER_SECOND), this.audioOutput.SamplesPerSecond);
                mediaType.SetUINT32(new Guid(Consts.MF_MT_AUDIO_BLOCK_ALIGNMENT), this.audioOutput.BlockAlignment);
                mediaType.SetUINT32(new Guid(Consts.MF_MT_AUDIO_BITS_PER_SAMPLE), this.audioOutput.BitsPerSample);
            }
            else
            {
                // Create the WMA media type
                uint   codecConfig         = 0;
                uint   elementsNumber      = 0;
                uint   selectedType        = 0;
                int    avgBitrateDiff      = int.MaxValue;
                uint   avgBytePerSecond    = uint.MaxValue;
                object supportedAttributes = null;

                // Get the available audio ouput types for the required sub type
                IMFCollection availableTypes = null;
                MFHelper.MFTranscodeGetAudioOutputAvailableTypes(audioOutput.Subtype, (uint)Enums.MFT_ENUM_FLAG.MFT_ENUM_FLAG_ALL, codecConfig, out availableTypes);

                // Get the number of types
                availableTypes.GetElementCount(out elementsNumber);

                for (uint elementIndex = 0; elementIndex < elementsNumber; elementIndex++)
                {
                    // Get the next element
                    availableTypes.GetElement(elementIndex, out supportedAttributes);
                    mediaType = (IMFMediaType)supportedAttributes;

                    // Get the byte per second
                    mediaType.GetUINT32(new Guid(Consts.MF_MT_AUDIO_AVG_BYTES_PER_SECOND), out avgBytePerSecond);

                    // If this is better than the last one found remember the index
                    if (Math.Abs((int)avgBytePerSecond - (int)audioOutput.AvgBytePerSecond) < avgBitrateDiff)
                    {
                        selectedType   = elementIndex;
                        avgBitrateDiff = Math.Abs((int)avgBytePerSecond - (int)audioOutput.AvgBytePerSecond);
                    }

                    mediaType = null;
                }

                // Get the best audio type found
                availableTypes.GetElement(selectedType, out supportedAttributes);
                mediaType = (IMFMediaType)supportedAttributes;
            }

            return(mediaType);
        }
Ejemplo n.º 11
0
        HResult ConfigureSourceReader(IMFSourceReaderAsync pReader)
        {
            // The list of acceptable types.
            Guid[] subtypes =
            {
                MFMediaType.NV12,  MFMediaType.YUY2,  MFMediaType.UYVY,
                MFMediaType.RGB32, MFMediaType.RGB24, MFMediaType.IYUV
            };

            HResult hr             = HResult.S_OK;
            bool    bUseNativeType = false;

            Guid subtype;

            IMFMediaType pType = null;

            // If the source's native format matches any of the formats in
            // the list, prefer the native format.

            // Note: The camera might support multiple output formats,
            // including a range of frame dimensions. The application could
            // provide a list to the user and have the user select the
            // camera's output format. That is outside the scope of this
            // sample, however.

            hr = pReader.GetNativeMediaType(
                MF_SOURCE_READER_FIRST_VIDEO_STREAM,
                0,  // Type index
                out pType
                );

            if (Failed(hr))
            {
                goto done;
            }

            hr = pType.GetGUID(MFAttributesClsid.MF_MT_SUBTYPE, out subtype);

            if (Failed(hr))
            {
                goto done;
            }

            for (int i = 0; i < subtypes.Length; i++)
            {
                if (subtype == subtypes[i])
                {
                    hr = pReader.SetCurrentMediaType(
                        MF_SOURCE_READER_FIRST_VIDEO_STREAM,
                        null,
                        pType
                        );

                    bUseNativeType = true;
                    break;
                }
            }

            if (!bUseNativeType)
            {
                // None of the native types worked. The camera might offer
                // output of a compressed type such as MJPEG or DV.

                // Try adding a decoder.

                for (int i = 0; i < subtypes.Length; i++)
                {
                    hr = pType.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, subtypes[i]);

                    if (Failed(hr))
                    {
                        goto done;
                    }

                    hr = pReader.SetCurrentMediaType(
                        MF_SOURCE_READER_FIRST_VIDEO_STREAM,
                        null,
                        pType
                        );

                    if (Succeeded(hr))
                    {
                        break;
                    }
                }
            }

done:
            SafeRelease(pType);
            return(hr);
        }
Ejemplo n.º 12
0
        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Starts capture of the data to a file.
        ///
        /// Because this code is intended for demo purposes and in the interests of
        /// reducing complexity it is extremely linear and step-by-step. Doubtless
        /// there is much refactoring that could be done.
        ///
        /// </summary>
        /// <history>
        ///    01 Nov 18  Cynic - Started
        /// </history>
        private void CaptureToFile()
        {
            HResult       hr;
            IMFMediaType  videoType     = null;
            IMFMediaType  encoderType   = null;
            TantaMFDevice currentDevice = null;

            try
            {
                // get the current video device.
                currentDevice = ctlTantaVideoPicker1.CurrentDevice;
                if (currentDevice == null)
                {
                    MessageBox.Show("No current video device. Are there any video devices on this system?");
                    return;
                }

                // check our output filename is correct and usable
                if ((textBoxCaptureFileNameAndPath == null) || (textBoxCaptureFileNameAndPath.Text.Length == 0))
                {
                    MessageBox.Show("No Capture Filename and path. Cannot continue.");
                    return;
                }
                string pwszFileName = textBoxCaptureFileNameAndPath.Text;
                // check the path is rooted
                if (Path.IsPathRooted(pwszFileName) == false)
                {
                    MessageBox.Show("No Capture Filename and path is not rooted. A full directory and path is required. Cannot continue.");
                    return;
                }

                // create a new call back handler. This, once we get it all wired up, will act
                // as a pump to move the data from the source to the sink
                workingSourceReaderCallBackHandler = new TantaSourceReaderCallbackHandler();

                // the following code will create a SourceReader which is tied to a camera on the system,
                // a SinkWriter which is tied to a file output and will hook up the two. Because we are using
                // a SourceReader and SourceWriter we do not have the usual Topology or Pipeline. The SourceReader
                // and SourceWriter are connected directly (input to output) in the code below and transfer their
                // data via the callback handler. The callback handler also requests the next sample from
                // the SourceReader when it has written the data to the sink. Note however it is possible
                // that the SourceReader can automatically bring in a Transform for format conversion. This
                // is done internally and you never deal with it - other than perhaps making it available
                // to the process if it is not globally available.

                // create the source reader
                workingSourceReader = TantaWMFUtils.CreateSourceReaderAsyncFromDevice(currentDevice, workingSourceReaderCallBackHandler);
                if (workingSourceReader == null)
                {
                    MessageBox.Show("CreateSourceReaderAsyncFromDevice did not return a media source. Cannot continue.");
                    return;
                }

                // open up the sink Writer
                workingSinkWriter = OpenSinkWriter(pwszFileName);
                if (workingSinkWriter == null)
                {
                    MessageBox.Show("OpenSinkWriter workingSinkWriter == null. Cannot continue.");
                    return;
                }

                // now set the source and the sink in the callback handler. It needs to know these
                // in order to operate
                workingSourceReaderCallBackHandler.SourceReader = workingSourceReader;
                workingSourceReaderCallBackHandler.SinkWriter   = workingSinkWriter;
                workingSourceReaderCallBackHandler.InitForFirstSample();
                workingSourceReaderCallBackHandler.SourceReaderAsyncCallBackError = HandleSourceReaderAsyncCallBackErrors;

                // now we configure the video source. It will probably offer a lot of different types
                // this example offers two modes: one mode where you choose the format and mode and
                // effectively just say "Use this one". The other uses the general case where we
                // present a list of reasonable types we can accept and then let it auto
                // configure itself from one of those. Of course if it autoconfigures itself we
                // don't know which one it has chosen. This is why, you will later see the video
                // source being interrogated after the configuration so we know which one we hit.

                if (radioButtonUseSpecified.Checked == true)
                {
                    // we saved the video format container here - this is just the last one that came in
                    if ((radioButtonUseSpecified.Tag == null) || ((radioButtonUseSpecified.Tag is TantaMFVideoFormatContainer) == false))
                    {
                        MessageBox.Show("No source video device and format selected. Cannot continue.");
                        return;
                    }
                    // get the container
                    TantaMFVideoFormatContainer videoFormatCont = (radioButtonUseSpecified.Tag as TantaMFVideoFormatContainer);
                    // configure the Source Reader to use this format
                    hr = TantaWMFUtils.ConfigureSourceReaderWithVideoFormat(workingSourceReader, videoFormatCont);
                    if (hr != HResult.S_OK)
                    {
                        // we failed
                        MessageBox.Show("Failed on call to ConfigureSourceAsyncReaderWithVideoFormat (a), retVal=" + hr.ToString());
                        return;
                    }
                }
                else
                {
                    // prepare a list of subtypes we are prepared to accept from the video source
                    // device. These will be tested in order - the first match will be used.
                    List <Guid> subTypes = new List <Guid>();
                    subTypes.Add(MFMediaType.NV12);
                    subTypes.Add(MFMediaType.YUY2);
                    subTypes.Add(MFMediaType.UYVY);
                    subTypes.Add(MFMediaType.RGB32);
                    subTypes.Add(MFMediaType.RGB24);
                    subTypes.Add(MFMediaType.IYUV);

                    // make sure the default Media Type is one of the above video formats
                    hr = TantaWMFUtils.ConfigureSourceReaderWithVideoFormat(workingSourceReader, subTypes, false);
                    if (hr != HResult.S_OK)
                    {
                        // we failed
                        MessageBox.Show("Failed on call to ConfigureSourceAsyncReaderWithVideoFormat (b), retVal=" + hr.ToString());
                        return;
                    }
                }

                // if we get here we know the source reader now has a configured format but we might not
                // know which one it is. So we ask it. It will return a video type
                // we will use this later on to configure our sink writer. Note, we have to properly dispose
                // of the videoType object after we use it.
                hr = workingSourceReader.GetCurrentMediaType(TantaWMFUtils.MF_SOURCE_READER_FIRST_VIDEO_STREAM, out videoType);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed on call to GetCurrentMediaType, retVal=" + hr.ToString());
                }

                // now we configure the encoder. This sets up the sink writer so that it knows what format
                // the output data should be written in. The format we give the writer does not
                // need to be the same as the format it outputs to disk - however to make life easier for ourselves
                // we will copy a lot of the settings from the videoType retrieved above

                // create a new empty media type for us to populate
                hr = MFExtern.MFCreateMediaType(out encoderType);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed on call to MFCreateMediaType, retVal=" + hr.ToString());
                }

                // The major type defines the overall category of the media data. Major types include video, audio, script & etc.
                hr = encoderType.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed setting the MF_MT_MAJOR_TYPE, retVal=" + hr.ToString());
                }

                // The subtype GUID defines a specific media format type within a major type. For example, within video,
                // the subtypes include MFMediaType.H264 (MP4), MFMediaType.WMV3 (WMV), MJPEG & etc. Within audio, the
                // subtypes include PCM audio, Windows Media Audio 9, & etc.
                hr = encoderType.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MEDIA_TYPETO_WRITE);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed setting the MF_MT_SUBTYPE, retVal=" + hr.ToString());
                }

                // this is the approximate data rate of the video stream, in bits per second, for a video media type
                // in the MF.Net sample code this is 240000 but I found 2000000 to be much better. I am not sure,
                // at this time, how this value is derived or what the tradeoffs are.
                hr = encoderType.SetUINT32(MFAttributesClsid.MF_MT_AVG_BITRATE, TARGET_BIT_RATE);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed setting the MF_MT_AVG_BITRATE, retVal=" + hr.ToString());
                }

                // populate our new encoding type with the frame size of the videoType selected earlier
                hr = TantaWMFUtils.CopyAttributeData(videoType, encoderType, MFAttributesClsid.MF_MT_FRAME_SIZE);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed copying the MF_MT_FRAME_SIZE, retVal=" + hr.ToString());
                }

                // populate our new encoding type with the frame rate of the video type selected earlier
                hr = TantaWMFUtils.CopyAttributeData(videoType, encoderType, MFAttributesClsid.MF_MT_FRAME_RATE);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed copying the MF_MT_FRAME_RATE, retVal=" + hr.ToString());
                }

                // populate our new encoding type with the pixel aspect ratio of the video type selected earlier
                hr = TantaWMFUtils.CopyAttributeData(videoType, encoderType, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed copying the MF_MT_PIXEL_ASPECT_RATIO, retVal=" + hr.ToString());
                }

                // populate our new encoding type with the interlace mode of the video type selected earlier
                hr = TantaWMFUtils.CopyAttributeData(videoType, encoderType, MFAttributesClsid.MF_MT_INTERLACE_MODE);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed copying the MF_MT_INTERLACE_MODE, retVal=" + hr.ToString());
                }

                // add a stream to the sink writer. The encoderType specifies the format of the samples that will be written
                // to the file. Note that it does not necessarily need to match the input format. To set the input format
                // use SetInputMediaType.
                int sink_stream = 0;
                hr = workingSinkWriter.AddStream(encoderType, out sink_stream);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed adding the output stream, retVal=" + hr.ToString());
                }

                // Windows 10, by default, provides an adequate set of codecs which the Sink Writer can
                // find to write out the MP4 file. This is not true on Windows 7.

                // If we are not on Windows 10 we register (locally) a codec
                // the Sink Writer can find and use. The ColorConvertDMO is supplied by
                // microsoft it is just not available to enumerate on Win7 etc.
                // Making it available locally does not require administrator privs
                // but only this process can see it and it disappears when the process
                // closes
                OperatingSystem os        = Environment.OSVersion;
                int             versionID = ((os.Version.Major * 10) + os.Version.Minor);
                if (versionID < 62)
                {
                    Guid ColorConvertDMOGUID = new Guid("98230571-0087-4204-b020-3282538e57d3");

                    // Register the color converter DSP for this process, in the video
                    // processor category. This will enable the sink writer to enumerate
                    // the color converter when the sink writer attempts to match the
                    // media types.
                    hr = MFExtern.MFTRegisterLocalByCLSID(
                        ColorConvertDMOGUID,
                        MFTransformCategory.MFT_CATEGORY_VIDEO_PROCESSOR,
                        "",
                        MFT_EnumFlag.SyncMFT,
                        0,
                        null,
                        0,
                        null
                        );
                }

                // Set the input format for a stream on the sink writer. Note the use of the stream index here
                // The input format does not have to match the target format that is written to the media sink
                // If the formats do not match, this call attempts to load an transform
                // that can convert from the input format to the target format. If it cannot find one, and this is not
                // a sure thing, it will throw an exception.
                hr = workingSinkWriter.SetInputMediaType(sink_stream, videoType, null);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed on calling SetInputMediaType on the writer, retVal=" + hr.ToString());
                }

                // now we initialize the sink writer for writing. We call this method after configuring the
                // input streams but before we send any data to the sink writer. The underlying media sink must
                // have at least one input stream and we know it does because we set it up earlier
                hr = workingSinkWriter.BeginWriting();
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed on calling BeginWriting on the writer, retVal=" + hr.ToString());
                }

                // Request the first video frame from the media source. The TantaSourceReaderCallbackHandler
                // set up earlier will be invoked and it will continue requesting and processing video
                // frames after that.
                hr = workingSourceReader.ReadSample(
                    TantaWMFUtils.MF_SOURCE_READER_FIRST_VIDEO_STREAM,
                    0,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    IntPtr.Zero
                    );
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed on calling the first ReadSample on the reader, retVal=" + hr.ToString());
                }

                // we are ready to start, flag this
                buttonStartStopCapture.Text = STOP_CAPTURE;
                // disable our screen controls
                SetEnableStateOnScreenControls(false);
            }
            finally
            {
                // setting this to null will cause it to be cleaned up
                currentDevice = null;

                // close and release
                if (videoType != null)
                {
                    Marshal.ReleaseComObject(videoType);
                    videoType = null;
                }

                if (encoderType != null)
                {
                    Marshal.ReleaseComObject(encoderType);
                    encoderType = null;
                }
            }
        }
Ejemplo n.º 13
0
        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        ///  Starts the process of recording. creates the sink writer. We do not
        ///  check to see if the filename is viable or already exists. This is
        ///  assumed to have been done before this call.
        /// </summary>
        /// <param name="outputFileName">the output file name</param>
        /// <param name="incomingVideoMediaType">the incoming media type</param>
        /// <param name="wantTimebaseRebaseIn">if true we rebase all incoming sample
        /// times to zero from the point we started recording and send a copy of the
        /// sample to the sink writer instead of the input sample</param>
        /// <returns>z success, nz fail</returns>
        /// <history>
        ///    01 Nov 18  Cynic - Started
        /// </history>
        public int StartRecording(string outputFileName, IMFMediaType incomingVideoMediaType, bool wantTimebaseRebaseIn)
        {
            HResult      hr;
            IMFMediaType encoderType = null;

            LogMessage("MFTTantaSampleGrabber_Sync, StartRecording called");

            // first stop any recordings now
            StopRecording();

            // check the output file name for sanity
            if ((outputFileName == null) || (outputFileName.Length == 0))
            {
                LogMessage("StartRecording (outputFileName==null)|| (outputFileName.Length==0)");
                return(100);
            }

            // check the media type for sanity
            if (incomingVideoMediaType == null)
            {
                LogMessage("StartRecording videoMediaType == null");
                return(150);
            }

            lock (sinkWriterLockObject)
            {
                // create the sink writer
                workingSinkWriter = OpenSinkWriter(outputFileName, true);
                if (workingSinkWriter == null)
                {
                    LogMessage("StartRecording failed to create sink writer");
                    return(200);
                }

                // now configure the SinkWriter. This sets up the sink writer so that it knows what format
                // the output data should be written in. The format we give the writer does not
                // need to be the same as the format receives as input - however to make life easier for ourselves
                // we will copy a lot of the settings from the videoType retrieved above

                // create a new empty media type for us to populate
                hr = MFExtern.MFCreateMediaType(out encoderType);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed on call to MFCreateMediaType, retVal=" + hr.ToString());
                }

                // The major type defines the overall category of the media data. Major types include video, audio, script & etc.
                hr = encoderType.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed setting the MF_MT_MAJOR_TYPE, retVal=" + hr.ToString());
                }

                // The subtype GUID defines a specific media format type within a major type. For example, within video,
                // the subtypes include MFMediaType.H264 (MP4), MFMediaType.WMV3 (WMV), MJPEG & etc. Within audio, the
                // subtypes include PCM audio, Windows Media Audio 9, & etc.
                hr = encoderType.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MEDIA_TYPETO_WRITE);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed setting the MF_MT_SUBTYPE, retVal=" + hr.ToString());
                }

                // this is the approximate data rate of the video stream, in bits per second, for a
                // video media type. The choice here is somewhat arbitrary but seems to work well.
                hr = encoderType.SetUINT32(MFAttributesClsid.MF_MT_AVG_BITRATE, TARGET_BIT_RATE);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed setting the MF_MT_AVG_BITRATE, retVal=" + hr.ToString());
                }

                // populate our new encoding type with the frame size of the videoType selected earlier
                hr = TantaWMFUtils.CopyAttributeData(incomingVideoMediaType, encoderType, MFAttributesClsid.MF_MT_FRAME_SIZE);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed copying the MF_MT_FRAME_SIZE, retVal=" + hr.ToString());
                }

                // populate our new encoding type with the frame rate of the video type selected earlier
                hr = TantaWMFUtils.CopyAttributeData(incomingVideoMediaType, encoderType, MFAttributesClsid.MF_MT_FRAME_RATE);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed copying the MF_MT_FRAME_RATE, retVal=" + hr.ToString());
                }

                // populate our new encoding type with the pixel aspect ratio of the video type selected earlier
                hr = TantaWMFUtils.CopyAttributeData(incomingVideoMediaType, encoderType, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed copying the MF_MT_PIXEL_ASPECT_RATIO, retVal=" + hr.ToString());
                }

                // populate our new encoding type with the interlace mode of the video type selected earlier
                hr = TantaWMFUtils.CopyAttributeData(incomingVideoMediaType, encoderType, MFAttributesClsid.MF_MT_INTERLACE_MODE);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("Failed copying the MF_MT_INTERLACE_MODE, retVal=" + hr.ToString());
                }

                // add a stream to the sink writer for the output Media type. The
                // incomingVideoMediaType specifies the format of the samples that will
                // be written to the file. Note that it does not necessarily need to
                // match the input format.
                hr = workingSinkWriter.AddStream(encoderType, out sinkWriterVideoStreamId);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("StartRecording Failed adding the output stream(v), retVal=" + hr.ToString());
                }

                // Windows 10, by default, provides an adequate set of codecs which the Sink Writer can
                // find to write out the MP4 file. This is not true on Windows 7.

                // If we are not on Windows 10 we register (locally) a codec
                // the Sink Writer can find and use. The ColorConvertDMO is supplied by
                // microsoft it is just not available to enumerate on Win7 etc.
                // Making it available locally does not require administrator privs
                // but only this process can see it and it disappears when the process
                // closes
                OperatingSystem os        = Environment.OSVersion;
                int             versionID = ((os.Version.Major * 10) + os.Version.Minor);
                if (versionID < 62)
                {
                    Guid ColorConverterDMOGUID = new Guid("98230571-0087-4204-b020-3282538e57d3");

                    // Register the color converter DSP for this process, in the video
                    // processor category. This will enable the sink writer to enumerate
                    // the color converter when the sink writer attempts to match the
                    // media types.
                    hr = MFExtern.MFTRegisterLocalByCLSID(
                        ColorConverterDMOGUID,
                        MFTransformCategory.MFT_CATEGORY_VIDEO_PROCESSOR,
                        "",
                        MFT_EnumFlag.SyncMFT,
                        0,
                        null,
                        0,
                        null
                        );
                }

                // Set the input format for a stream on the sink writer. Note the use of the stream index here
                // The input format does not have to match the target format that is written to the media sink
                // If the formats do not match, this call attempts to load an transform
                // that can convert from the input format to the target format. If it cannot find one, (and this is not
                // a sure thing), it will throw an exception.
                hr = workingSinkWriter.SetInputMediaType(sinkWriterVideoStreamId, incomingVideoMediaType, null);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("StartRecording Failed on calling SetInputMediaType(v) on the writer, retVal=" + hr.ToString());
                }

                // set this flag now
                wantTimebaseRebase = wantTimebaseRebaseIn;

                // now we initialize the sink writer for writing. We call this method after configuring the
                // input streams but before we send any data to the sink writer. The underlying media sink must
                // have at least one input stream and we know it does because we set it up above
                hr = workingSinkWriter.BeginWriting();
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("StartRecording Failed on calling BeginWriting on the writer, retVal=" + hr.ToString());
                }
            }

            return(0);
        }