AsfFormat
This class uses the WMProfileData
class to build a list of profile information items.
The next sample shows how the stream type and the bitrate is retrieved.
hr = profile.GetStreamCount(out streamCount);
if((hr >= 0)&&((streamCount > 0))
{
IWMStreamConfig streamConfig = null;
Guid streamGuid = Guid.Empty;
audio = false;
video = false;
audioBitrate = 0;
videoBitrate = 0;
for(short i = 1;(i <= streamCount)&&(hr >= 0); i++)
{
hr = profile.GetStreamByNumber(i, out streamConfig);
if((hr >= 0)&&(streamConfig != null))
{
hr = streamConfig.GetStreamType(out streamGuid);
if(hr >= 0)
{
if(streamGuid == MediaType.Video)
{
video = true;
hr = streamConfig.GetBitrate(out videoBitrate);
if(hr < 0)
{
videoBitrate = 0;
}
}
else
if(streamGuid == MediaType.Audio)
{
audio = true;
hr = streamConfig.GetBitrate(out audioBitrate);
if(hr < 0)
{
audioBitrate = 0;
}
}
hr = 0; // Allow possible unreadable bitrates
}
}
} // for i
}
The AsfFormat
class has a number of functions that can be used by the application.
With the constructor the class can be initialized.
With the function GetProfileFormatInfo()
, the profile information can be updated
(e.g. show all video formats, or show all video formats having no audio).
This functionality is very useful if the application switches from audio file saving to video file saving.
For video file saving the menu should show a list of profiles which do support at least a video stream.
While for audio file saving the menu should show a list of profiles which support an audio stream and do not support a video stream.
Code changes in Capture.cs
The following code shows the possible use of the AsfFormat
constructor and the GetProfileFormatInfo()
function in the Capture class.
switch(recFileMode)
{
case RecFileModeType.Wmv:
if(asfFormat == null)
{
asfFormat = new AsfFormat(AsfFormat.AsfFormatSelection.Video);
}
else
{
asfFormat.GetProfileFormatInfo(AsfFormat.AsfFormatSelection.Video);
}
break;
case RecFileModeType.Avi:
break;
default:
// Unsupported file format
return;
}
In addition, there is a one liner that changes the extension of the file name.
// Change filename extension
this.filename = Path.ChangeExtension(this.filename, RecFileMode.ToString().ToLower());
In the function renderGraph()
the actual file saving is initialized.
The original Avi file saving is still possible.
To prevent problems with the Windows Media formats, the video compressor is used for Avi file saving only.
For a Windows Media format, no video compressor will be used.
For a Windows Media format the profile information must be retrieved to configure the Asf file writer.
Furthermore, the stream information must be retrieved.
// Render the file writer portion of graph (mux -> file)
// Record captured audio/video in Avi, Wmv or Wma format
Guid mediaSubType; // Media sub type
bool captureAudio = true;
bool captureVideo = true;
IBaseFilter videoCompressorfilter = null;
// Set media sub type and video compressor filter if needed
if(RecFileMode == RecFileModeType.Avi)
{
mediaSubType = MediaSubType.Avi;
// For Avi file saving a video compressor must be used
// If one is selected, that one will be used.
videoCompressorfilter = videoCompressorFilter;
}
else
{
mediaSubType = MediaSubType.Asf;
}
// Intialize the Avi or Asf file writer
hr = captureGraphBuilder.SetOutputFileName( ref mediaSubType, Filename, out muxFilter, out fileWriterFilter );
if( hr < 0 ) Marshal.ThrowExceptionForHR( hr );
// For Wma (and Wmv) a suitable profile must be selected. This
// can be done via a property window, however the muxFilter is
// just created. if needed, the property windows should show up
// right now!
// Another solution is to configure the Asf file writer, the
// use interface must ensure the proper format has been selected.
if((RecFileMode == RecFileModeType.Wma)||
(RecFileMode == RecFileModeType.Wmv))
{
if(this.AsfFormat != null)
{
this.AsfFormat.UpdateAsfAVFormat(this.muxFilter);
this.AsfFormat.GetCurrentAsfAVInfo(out captureAudio, out captureVideo);
}
}
For saving video, the video stream check is performed.
This check will prevent video file saving if an audio only file save was requested.
For Avi only, the video compressor value will be used.
// Render video (video -> mux) if needed or possible
if((VideoDevice != null)&&(captureVideo))
{
// Try interleaved first, because if the device supports it,
// it's the only way to get audio as well as video
cat = PinCategory.Capture;
med = MediaType.Interleaved;
hr = captureGraphBuilder.RenderStream( ref cat, ref med, videoDeviceFilter, videoCompressorfilter, muxFilter );
if( hr < 0 )
{
med = MediaType.Video;
hr = captureGraphBuilder.RenderStream( ref cat, ref med, videoDeviceFilter, videoCompressorfilter, muxFilter );
if ( hr == -2147220969 ) throw new DeviceInUseException( "Video device", hr );
if( hr < 0 ) Marshal.ThrowExceptionForHR( hr );
}
}
For saving audio, the audio stream check is performed.
This check will prevent audio file saving if a video only file save was requested.
// Render audio (audio -> mux) if possible
if((AudioDevice != null)&&(captureAudio))
{
// If this Asf file format than please keep in mind that
// certain Wmv formats do not have an audio stream, so
// when using this code, please ensure you use a format
// which supports audio!
cat = PinCategory.Capture;
med = MediaType.Audio;
hr = captureGraphBuilder.RenderStream( ref cat, ref med, audioDeviceFilter, audioCompressorFilter, muxFilter );
if( hr < 0 ) Marshal.ThrowExceptionForHR( hr );
}
isCaptureRendered = true;
didSomething = true;