{
/// <summary>
/// Létezik e média detektor
/// </summary>
public bool Active
{
get { return MediaDet != null; }
}
/// <summary>
/// A jelenleg kiválasztott stream médiatúpusa
/// </summary>
public Guid? CurrentStream
{
get
{
Reset();
if (Active)
{
int CurrentStream;
if (MediaDet.get_CurrentStream(out CurrentStream) == 0)
{
AMMediaType MdType = new AMMediaType();
if (MediaDet.get_StreamMediaType(MdType) == 0)
{
Guid GuidMT = MdType.majorType;
DsUtils.FreeAMMediaType(MdType);
return GuidMT;
}
}
}
return null;
}
set
{
Reset();
if (Active && value != null)
{
EnumMediaTypes(
delegate(int CurrentStream, AMMediaType MediaType)
{
if (MediaType.majorType == value)
{
MediaDet.put_CurrentStream(CurrentStream);
return true;
}
return false;
}
);
}
}
}
private string FFileName;
/// <summary>
/// Médiafájl neve
/// </summary>
public string FileName
{
get { return FFileName; }
set
{
FFileName = value;
// az előző detektort a süllyesztőbe küldjük 🙂
Destroy();
if (FFileName != null)
{
// minden egyes alkalommal (minden fájlra) külön példányt kell létrehozni,
// ugyanis a put_FileName() nem hívható meg egy példányon, csak egyszer
MediaDet = new DirectShowLib.DES.MediaDet() as IMediaDet;
if (Active)
{
int HResult = MediaDet.put_Filename(FFileName);
if (HResult < 0)
{
Destroy();
DsError.ThrowExceptionForHR(HResult);
}
}
}
}
}
/// <summary>
/// A forrás-szűrő, amit a médiadetektor éppen használ
/// </summary>
public BaseFilter SourceFilter
{
get
{
Reset();
if (Active)
{
object Filter;
if (MediaDet.get_Filter(out Filter) == 0)
return new BaseFilter((IBaseFilter)Filter);
}
return null;
}
set
{
Reset();
if (Active && value != null)
DsError.ThrowExceptionForHR(MediaDet.put_Filter(value.Filter));
}
}
/// <summary>
/// Képkockasebesség (fps)
/// </summary>
public double? FrameRate
{
get
{
Reset();
if (Active)
{
double Value;
if (MediaDet.get_FrameRate(out Value) == 0)
return Value;
}
return null;
}
}
/// <summary>
/// Stream hossza
/// </summary>
public double? StreamLength
{
get
{
Reset();
if (Active)
{
double Value;
if (MediaDet.get_StreamLength(out Value) == 0)
return Value;
}
return null;
}
}
/// <summary>
/// A fájl médiatípusa
/// </summary>
public MediaTypeEnum MediaType
{
get
{
Reset();
bool AudioStream = false;
bool VideoStream = false;
// médiatípusok átnézése
EnumMediaTypes(
delegate (int CurrentStream, AMMediaType MediaType)
{
if (MediaType.majorType == DirectShowLib.MediaType.Video)
VideoStream = true;
else if (MediaType.majorType == DirectShowLib.MediaType.Audio)
AudioStream = true;
return false;
}
);
if (VideoStream && AudioStream)
return MediaTypeEnum.mtAudioVideo;
else if (VideoStream)
return MediaTypeEnum.mtVideo;
else if (AudioStream)
return MediaTypeEnum.mtAudio;
else
return MediaTypeEnum.mtOther;
}
}
/// <summary>
/// Videóinformációk
/// Ha nem nyerhető ki, pl. nincs videó stream, akkor null értéket ad vissza
/// </summary>
public VideoInfoHeader VideoInfo
{
get
{
Reset();
if (Active)
{
CurrentStream = DirectShowLib.MediaType.Video;
// ha sikerült a videóstreamet beállítani (azaz van neki olyan)
if (CurrentStream == DirectShowLib.MediaType.Video)
{
AMMediaType MdType = new AMMediaType();
if (MediaDet.get_StreamMediaType(MdType) == 0)
{
VideoInfoHeader VideoInf = (VideoInfoHeader)Marshal.PtrToStructure(MdType.formatPtr, typeof(VideoInfoHeader));
DsUtils.FreeAMMediaType(MdType);
return VideoInf;
}
}
}
return null;
}
}
/// <summary>
/// Audio információk
/// Ha nem nyerhető ki, pl. nincs audio stream, akkor null értéket ad vissza
/// </summary>
public WaveFormatEx AudioInfo
{
get
{
Reset();
if (Active)
{
CurrentStream = DirectShowLib.MediaType.Audio;
// ha sikerült az audiostreamet beállítani (azaz van neki olyan)
if (CurrentStream == DirectShowLib.MediaType.Audio)
{
AMMediaType MdType = new AMMediaType();
if (MediaDet.get_StreamMediaType(MdType) == 0)
{
WaveFormatEx AudioInf = (WaveFormatEx)Marshal.PtrToStructure(MdType.formatPtr, typeof(WaveFormatEx));
DsUtils.FreeAMMediaType(MdType);
return AudioInf;
}
}
}
return null;
}
}
#endregion
}
A referenciaszámláló szépen számolgatja a grabbeléssel kapcsolatos tagfüggvények hívását, s bármilyen más tevékenység esetén előtte ellenőrzi, hogy el lehet e érni e még az adott dolgokat, azaz nem váltottunk e át grabbelési üzemmódba. Igaz ez az EnumMediaTypes()-ra is, ezért van mindenhol ott a Reset() minden előtt. Viszont ennek köszönhetően nem kell ezt írni például, hogy:
MediaDetector Detector = new MediaDetector();
Detector.FileName = MPlayer.FileName;
pbVideoBitmap1.Image = Detector.GetBitmap(10);
Detector.FileName = MPlayer.FileName;
pbVideoBitmap2.Image = Detector.GetBitmap(20);
Detector.FileName = MPlayer.FileName;
pbVideoBitmap3.Image = Detector.GetBitmap(30);
Elég csak ennyi (ami amúgy is a normális lenne):
MediaDetector Detector = new MediaDetector(MPlayer.FileName);
pbVideoBitmap1.Image = Detector.GetBitmap(10);
pbVideoBitmap2.Image = Detector.GetBitmap(20);
pbVideoBitmap3.Image = Detector.GetBitmap(30);
Minden további nélkül elérhetők a médiatípussal kapcsolatos, illetve videó és audió adatokkal kapcsolatos információk is, pl.:
Detector.EnumMediaTypes(
delegate(int CurrentStream, AMMediaType MediaType)
{
MessageBox.Show(MediaType.majorType.ToString());
return false;
}
);
WaveFormatEx W = Detector.AudioInfo;
if (W != null)
MessageBox.Show(W.nChannels.ToString());
Továbbá az EnumMediaTypes()-t úgy írtam meg, hogy megszakítható legyen (return true), nem mintha nagyon számítana, mivel úgy se sok van, de ha megvan amit keresünk, akkor felesleges átszánkózni a többin is. A keresett típus és a stream azonosítóját is átadja, hasonló módon, mint Win32 alatt a CALLBACK függvények voltak.
Most már a médiadetektorunk megvan, még jöhet egy videólejátszó extra kiegészítés a VMR-el, egy DVD lejátszó menükezelővel, illetve egy felvételrögzítő control és ezzel a DirectShow általános szolgáltatásait már elérhetővé is sikerült tenni .NET alatt. Persze most Adobe Premiert nem fogok írni, de ahhoz is a DirectShow-ban kellene hozzáfogni.
Még néhány apró dolog azoknak, akik Delphi-t használtak csak eddig, s nem ismerik még a Visual Studio kódszerkesztő lehetőségeit, például tulajdonságok gyors létrehozásához elég beírni, hogy prop és tab. A konstruktor ugyanígy ctor és tab. Van rengeteg ilyen Delphiben automatikus kódsablonoknak elnevezett szerűség a C#-ban is.
Ami még tervbe szerepelt, hogy most ugyan nem használtam, de majd szükségünk lesz a generikus típusokra is. Ez egy olyan szép dolog, amiért már jónéhány Delphi fejlesztő az első kiadás óta rimánkodik. Majd később részletesen beszélünk ezekről is, addig is aki nézegeti elárulom, hogy a Delphi Highlander (.NET 2.0) megvalósítása hogy festett volna, ha kiadták volna:
type
GenericType<T: MyClass, IMyInterface, constructor> = class(List<T>)
Ez ekvivalens ezzel a C# kóddal:
public
class GenericType<T> : List<T> where T : MyClass, IMyInterface, new()
Ez egy olyan generikus listát reprezentál, ahol T jelöli a típust, amire különböző megszorítások vannak, mégpedig, hogy a MyClass-ból kell származnia és implementálnia kell az IMyInterface-t, továbbá rendelkeznie kell egy paraméter nélküli konstruktorral. Ez az egyik nagy újítása a .NET 2.0-nak.