with this code, you can read mkv with multiples audio streams & subtitles
but this methods don't works with a lot of avi because the AVI Splitter of microsoft can't select streams , but it works with ogg splitter well
in DSCore.cs:
in VideoPlayerVMR7.cs :
again in videoplayervmr7.cs:
That's all , if you want more information contact me be msn messsenger
Update : this code works good if you have haali media splitter with avi splitter enabled (during the installation he ask you if you want..)
So Downlaod this splitter:
http://haali.cs.msu.ru/mkv/MatroskaSplitter.exe
and mkv and avi will be fully multiple stream ready ;-)
I have made a package with the modified files and the sources, just decompress it in your media portal folder:
http://modos.echanblard.org/StreamCoreMod.rar
(note : the modifications in source are between "//BEGINS" and "//ENDS" tags)
but this methods don't works with a lot of avi because the AVI Splitter of microsoft can't select streams , but it works with ogg splitter well
in DSCore.cs:
Code:
[ComVisible(true), ComImport,
Guid("56a86899-0ad4-11ce-b03a-0020af0ba770"),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
public interface IMediaFilter
{
#region "IPersist Methods"
[PreserveSig]
int GetClassID(
[Out] out Guid pClassID );
#endregion
[PreserveSig]
int Stop();
[PreserveSig]
int Pause();
[PreserveSig]
int Run( long tStart );
[PreserveSig]
int GetState( int dwMilliSecsTimeout, out int filtState );
[PreserveSig]
int SetSyncSource( [In] IReferenceClock pClock );
[PreserveSig]
int GetSyncSource( [Out] out IReferenceClock pClock );
}
//BEGINS
[Flags]
public enum AMStreamSelectInfoFlags
{
Enabled = 0x01,
Exclusive = 0x02
}
/// <summary>
/// From _AMSTREAMSELECTENABLEFLAGS
/// </summary>
[Flags]
public enum AMStreamSelectEnableFlags
{
Enable = 0x01,
EnableAll = 0x02
}
[Guid("c1960960-17f5-11d1-abe1-00a0c905f375"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAMStreamSelect
{
[PreserveSig]
int Count([Out] out int pcStreams);
[PreserveSig]
int Info(
[In] int lIndex,
[Out] out AMMediaType ppmt,
[Out] out AMStreamSelectInfoFlags pdwFlags,
[Out] out int plcid,
[Out] out int pdwGroup,
[Out, MarshalAs(UnmanagedType.LPWStr)] out string ppszName,
[Out, MarshalAs(UnmanagedType.IUnknown)] out object ppObject,
[Out, MarshalAs(UnmanagedType.IUnknown)] out object ppUnk
);
[PreserveSig]
int Enable(
[In] int lIndex,
[In] AMStreamSelectEnableFlags dwFlags
);
}
//ENDS
Code:
void OnGraphNotify()
{
if (mediaEvt==null) return;
int p1, p2, hr = 0;
DsEvCode code;
do
{
hr = mediaEvt.GetEvent( out code, out p1, out p2, 0 );
if( hr < 0 )
break;
hr = mediaEvt.FreeEventParams( code, p1, p2 );
if( code == DsEvCode.Complete || code== DsEvCode.ErrorAbort)
{
MovieEnded(false);
return;
}
}
while( hr == 0 );
}
//BEGINS
/*
public override int SubtitleStreams
{
get {
int ret = 0;
if (this.vobSub != null)
{
vobSub.get_LanguageCount(out ret);
}
return ret;
}
}
public override int CurrentSubtitleStream
{
get {
int ret = 0;
if (vobSub != null)
{
vobSub.get_SelectedLanguage(out ret);
}
return ret;
}
set {
if (this.vobSub != null)
{
vobSub.put_SelectedLanguage(value);
}
}
}
public override string SubtitleLanguage(int iStream)
{
string ret = Strings.Unknown;
if (vobSub != null)
{
IntPtr curNamePtr;
vobSub.get_LanguageName(iStream, out curNamePtr);
if (curNamePtr != IntPtr.Zero)
{
ret = Marshal.PtrToStringUni(curNamePtr);
Marshal.FreeCoTaskMem(curNamePtr);
}
}
return ret;
}
public override bool EnableSubtitle
{
get
{
bool ret = false;
if (this.vobSub != null)
{
int hr = vobSub.get_HideSubtitles(out ret);
if (hr == 0)
{
ret = !ret;
}
}
return ret;
}
set
{
if (this.vobSub != null)
{
bool hide = !value;
int hr = vobSub.put_HideSubtitles(hide);
}
}
}
*/
//STREAM INFOS STRUCT
protected struct FilterStreamInfos
{
public int Id;
public string Name;
public bool Current;
public string Filter;
};
//VARIABLES
protected const int MAX_VIDEOSTREAMS = 20;
protected const int MAX_AUDIOSTREAMS = 20;
protected const int MAX_SUBSTREAMS = 20;
protected int cStreams_Audio=0;
protected int cStreams_Video=0;
protected int cStreams_Sub=0;
protected FilterStreamInfos[] sStreams_Audio;
protected FilterStreamInfos[] sStreams_Video;
protected FilterStreamInfos[] sStreams_Sub;
protected FilterStreamInfos sStreams_Sub_No_Subtitle; //Haali use a stream to disable subtitles
//IPLAYER INTERFACE
//AUDIO
public override int AudioStreams
{
get { return cStreams_Audio;}
}
public override int CurrentAudioStream
{
get
{
for (int i=0;i<cStreams_Audio;i++)if (sStreams_Audio[i].Current)return i;
return 0;
}
set
{
for (int i=0;i<cStreams_Audio;i++)if (sStreams_Audio[i].Current)sStreams_Audio[i].Current=false;
sStreams_Audio[value].Current=true;
EnableStream(sStreams_Audio[value].Id,0,sStreams_Audio[value].Filter);
EnableStream(sStreams_Audio[value].Id,AMStreamSelectEnableFlags.Enable,sStreams_Audio[value].Filter);
return;
}
}
public override string AudioLanguage(int iStream)
{
return sStreams_Audio[iStream].Name;
}
//SUBTITLES
public override int SubtitleStreams
{
get
{
//DVD
if (this.vobSub != null)
{ int ret;
vobSub.get_LanguageCount(out ret);
return ret;
}
//AVI & MKV
return cStreams_Sub;
}
}
public override int CurrentSubtitleStream
{
get
{
//DVD
if (vobSub!=null)
{
int ret=0;
vobSub.get_SelectedLanguage(out ret);
return ret;
}
//AVI & MKV
for (int i=0;i<cStreams_Sub;i++)
if (sStreams_Sub[i].Current)
return i;
return 0;
}
set
{
//DVD
if (vobSub!=null){
vobSub.put_SelectedLanguage(value);
return;
}
//AVI & MKV
for (int i=0;i<cStreams_Sub;i++)
sStreams_Sub[i].Current=false;
sStreams_Sub[value].Current=true;
EnableStream(sStreams_Sub[value].Id,0,sStreams_Sub[value].Filter);
EnableStream(sStreams_Sub[value].Id,AMStreamSelectEnableFlags.Enable,sStreams_Sub[value].Filter);
return;
}
}
public override string SubtitleLanguage(int iStream)
{
//DVD
if (vobSub != null)
{
string ret = Strings.Unknown;
IntPtr curNamePtr;
vobSub.get_LanguageName(iStream, out curNamePtr);
if (curNamePtr != IntPtr.Zero)
{
ret = Marshal.PtrToStringUni(curNamePtr);
Marshal.FreeCoTaskMem(curNamePtr);
}
return ret;
}
//AVI & MKV
return sStreams_Sub[iStream].Name;
}
public override bool EnableSubtitle
{
get
{
bool ret = false;
if (this.vobSub != null)
{
int hr = vobSub.get_HideSubtitles(out ret);
if (hr == 0)
{
ret = !ret;
}
}
else
{
return !sStreams_Sub_No_Subtitle.Current;
}
return ret;
}
set
{
if (this.vobSub != null)
{
bool hide = !value;
int hr = vobSub.put_HideSubtitles(hide);
}
else
{
int CurrentSub=CurrentSubtitleStream;
if (CurrentSub>=0 && cStreams_Sub>=1)
{
sStreams_Sub_No_Subtitle.Current=!value;
EnableStream(sStreams_Sub_No_Subtitle.Id,0,sStreams_Sub_No_Subtitle.Filter);
EnableStream(sStreams_Sub[CurrentSub].Id,0,sStreams_Sub[CurrentSub].Filter);
if (value)
EnableStream(sStreams_Sub[CurrentSub].Id,AMStreamSelectEnableFlags.Enable,sStreams_Sub[CurrentSub].Filter);
else
EnableStream(sStreams_Sub_No_Subtitle.Id,AMStreamSelectEnableFlags.Enable,sStreams_Sub_No_Subtitle.Filter);
}
}
}
}
//GETTING STREAM INFORMATIONS
public IBaseFilter GetFilterByName(string name)
{
int hr=0;
IEnumFilters ienumFilt=null;
IBaseFilter foundfilter;
uint iFetched=0;
try
{
hr=graphBuilder.EnumFilters(out ienumFilt);
if (hr==0 && ienumFilt!=null)
{
ienumFilt.Reset();
do
{
hr=ienumFilt.Next(1,out foundfilter,out iFetched);
if (hr==0 && iFetched==1)
{
FilterInfo filter_infos=new FilterInfo();
foundfilter.QueryFilterInfo(filter_infos);
if (filter_infos.achName.LastIndexOf(name)!=-1)
{
Marshal.ReleaseComObject(ienumFilt);ienumFilt=null;
return foundfilter;
}
Marshal.ReleaseComObject(foundfilter);
}
} while (iFetched==1 && hr==0);
if (ienumFilt!=null)
Marshal.ReleaseComObject(ienumFilt);
ienumFilt=null;
}
}
catch(Exception)
{
}
finally
{
if (ienumFilt!=null)
Marshal.ReleaseComObject(ienumFilt);
}
return null;
}
public bool AnalyseStreams()
{
//INITIALIZE
sStreams_Sub_No_Subtitle.Id=0;
sStreams_Sub_No_Subtitle.Filter="";
cStreams_Audio=0;
cStreams_Video=0;
cStreams_Sub=0;
sStreams_Audio=new FilterStreamInfos[MAX_AUDIOSTREAMS];
sStreams_Video=new FilterStreamInfos[MAX_VIDEOSTREAMS];
sStreams_Sub=new FilterStreamInfos[MAX_SUBSTREAMS];
//RETRIEVING THE CURRENT SPLITTER
string filter="Ogg Splitter";
IBaseFilter foundfilter=GetFilterByName(filter);
if (foundfilter==null && GetFilterByName("Splitter")==null){ //MICROSOFT AVI SPLITTER MADE CRASH THIS FUNCTION SO CHECK IT
filter=(m_strCurrentFile.Length>=64)?m_strCurrentFile.Substring(0,64):m_strCurrentFile; //HAALI MEDIA SPLITTER
foundfilter=GetFilterByName(filter);
}
try{
if (foundfilter!=null)
{
int cStreams=0;
IAMStreamSelect pStrm = (IAMStreamSelect)foundfilter;
pStrm.Count(out cStreams);
//GET STREAMS
for (int istream=0;istream<cStreams;istream++)
{
AMMediaType sType;AMStreamSelectInfoFlags sFlag;
int sPDWGroup,sPLCid;string sName;
object pppunk,ppobject;
//STREAM INFO
pStrm.Info(istream,out sType,out sFlag,out sPLCid,
out sPDWGroup,out sName,out pppunk,out ppobject);
//VIDEO
if (sPDWGroup==0 && cStreams_Video<MAX_VIDEOSTREAMS)
{
sStreams_Video[cStreams_Video].Name=sName;
sStreams_Video[cStreams_Video].Id=istream;
sStreams_Video[cStreams_Video].Filter=filter;
sStreams_Video[cStreams_Video].Current=false;
if (cStreams_Video==0)
{
sStreams_Video[cStreams_Video].Current=true;
pStrm.Enable(istream,0);
pStrm.Enable(istream,AMStreamSelectEnableFlags.Enable);
}
cStreams_Video++;
}
else
//AUDIO
if (sPDWGroup==1 && cStreams_Audio<MAX_AUDIOSTREAMS)
{
sStreams_Audio[cStreams_Audio].Name=sName;
sStreams_Audio[cStreams_Audio].Id=istream;
sStreams_Audio[cStreams_Audio].Filter=filter;
sStreams_Audio[cStreams_Audio].Current=false;
if (cStreams_Audio==0)
{
sStreams_Audio[cStreams_Audio].Current=true;
pStrm.Enable(istream,0);
pStrm.Enable(istream,AMStreamSelectEnableFlags.Enable);
}
cStreams_Audio++;
}
else
//SUBTITLE
if (sPDWGroup==2 && cStreams_Sub<MAX_SUBSTREAMS && sName.LastIndexOf("off")==-1 && sName.LastIndexOf("No ")==-1&& sName.LastIndexOf("Miscellaneous ")==-1)
{
sStreams_Sub[cStreams_Sub].Name=sName;
sStreams_Sub[cStreams_Sub].Id=istream;
sStreams_Sub[cStreams_Sub].Filter=filter;
sStreams_Sub[cStreams_Sub].Current=false;
if (cStreams_Sub==0)
{
sStreams_Sub[cStreams_Sub].Current=true;
pStrm.Enable(istream,0);
pStrm.Enable(istream,AMStreamSelectEnableFlags.Enable);
}
cStreams_Sub++;
}
else
//NO SUBTITILE TAG
if (sPDWGroup==2 && cStreams_Sub<MAX_SUBSTREAMS && (sName.LastIndexOf("off")!=-1 || sName.LastIndexOf("No ")!=-1))
{
sStreams_Sub_No_Subtitle.Id=istream;
sStreams_Sub_No_Subtitle.Current=false;
sStreams_Sub_No_Subtitle.Filter=filter;
sStreams_Sub_No_Subtitle.Name=sName;
}
}
Marshal.ReleaseComObject(foundfilter);
}
}
catch
{
}
if (foundfilter!=null)
Marshal.ReleaseComObject(foundfilter);
return true;
}
public bool EnableStream(int Id,AMStreamSelectEnableFlags dwFlags,string Filter)
{
try
{
if (Filter.Length<10)return false;
IBaseFilter foundfilter=GetFilterByName(Filter);
if (foundfilter!=null)
{
IAMStreamSelect pStrm = (IAMStreamSelect)foundfilter;
pStrm.Enable(Id,dwFlags);
pStrm=null;
Marshal.ReleaseComObject(foundfilter);
}
}
catch
{
}
return true;
}
//ENDS
again in videoplayervmr7.cs:
Code:
public override bool Play(string strFile)
{
updateTimer=DateTime.Now;
m_speedRate = 10000;
m_bVisible=false;
m_iVolume=100;
m_state=PlayState.Init;
m_strCurrentFile=strFile;
m_bFullScreen=true;
m_ar=GUIGraphicsContext.ARType;
m_bUpdateNeeded=true;
Log.Write("VideoPlayer:play {0}", strFile);
//lock ( typeof(VideoPlayerVMR7) )
{
GC.Collect();
CloseInterfaces();
GC.Collect();
m_bStarted=false;
if( ! GetInterfaces() )
{
m_strCurrentFile="";
return false;
}
int hr = mediaEvt.SetNotifyWindow( GUIGraphicsContext.ActiveForm, WM_GRAPHNOTIFY, IntPtr.Zero );
if (hr < 0)
{
Error.SetError("Unable to play movie", "Can not set notifications");
m_strCurrentFile="";
CloseInterfaces();
return false;
}
if (videoWin!=null)
{
videoWin.put_Owner( GUIGraphicsContext.ActiveForm );
videoWin.put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
videoWin.put_MessageDrain(GUIGraphicsContext.form.Handle);
}
if (basicVideo!=null)
{
hr = basicVideo.GetVideoSize( out m_iVideoWidth, out m_iVideoHeight );
if (hr < 0)
{
Error.SetError("Unable to play movie", "Can not find movie width/height");
m_strCurrentFile="";
CloseInterfaces();
return false;
}
}
/*
GUIGraphicsContext.DX9Device.Clear( ClearFlags.Target, Color.Black, 1.0f, 0);
try
{
// Show the frame on the primary surface.
GUIGraphicsContext.DX9Device.Present();
}
catch(DeviceLostException)
{
}*/
DirectShowUtil.SetARMode(graphBuilder, AmAspectRatioMode.AM_ARMODE_STRETCHED);
DsROT.AddGraphToRot( graphBuilder, out rotCookie ); // graphBuilder capGraph
// DsUtils.DumpFilters(graphBuilder);
hr = mediaCtrl.Run();
if (hr < 0)
{
Error.SetError("Unable to play movie", "Unable to start movie");
m_strCurrentFile="";
CloseInterfaces();
return false;
}
GUIMessage msg=new GUIMessage(GUIMessage.MessageType.GUI_MSG_PLAYBACK_STARTED,0,0,0,0,0,null);
msg.Label=strFile;
GUIWindowManager.SendThreadMessage(msg);
m_state=PlayState.Playing;
GUIGraphicsContext.IsFullScreenVideo=true;
m_iPositionX=GUIGraphicsContext.VideoWindow.X;
m_iPositionY=GUIGraphicsContext.VideoWindow.Y;
m_iWidth =GUIGraphicsContext.VideoWindow.Width;
m_iHeight =GUIGraphicsContext.VideoWindow.Height;
m_ar =GUIGraphicsContext.ARType;
m_bUpdateNeeded=true;
SetVideoWindow();
mediaPos.get_Duration(out m_dDuration);
Log.Write("VideoPlayer:Duration:{0}",m_dDuration);
//BEGINS
AnalyseStreams();
//ENDS
OnInitialized();
}
return true;
}
That's all , if you want more information contact me be msn messsenger
Update : this code works good if you have haali media splitter with avi splitter enabled (during the installation he ask you if you want..)
So Downlaod this splitter:
http://haali.cs.msu.ru/mkv/MatroskaSplitter.exe
and mkv and avi will be fully multiple stream ready ;-)
I have made a package with the modified files and the sources, just decompress it in your media portal folder:
http://modos.echanblard.org/StreamCoreMod.rar
(note : the modifications in source are between "//BEGINS" and "//ENDS" tags)