Laden...

[Tutorial] Audio- und Videowiedergabe mit MCI

Erstellt von maxE vor 18 Jahren Letzter Beitrag vor 15 Jahren 93.488 Views
M
maxE Themenstarter:in
456 Beiträge seit 2004
vor 18 Jahren
[Tutorial] Audio- und Videowiedergabe mit MCI

Audio- und Videowiedergabe mit MCI

Einleitung

Da immer wieder die Frage auftaucht, wie man denn MP3s, WMAs, Videos und CDs am einfachsten abspielen kann, habe ich mich entschlossen diesen Artikel zu schreiben.
Windows bietet ein sehr leistungsfähiges Interface zur Wiedergabe von digitalen Medien.
Diese Library ist bei jeder Windowsinstallation vorhanden.

Benötigte DLL-Importe

Um die gesamte Schnittstelle anzusprechen, brauch man nur eine C-Funktion, die wir mit Hilfe von DllImport einbinden:


[DllImport("winmm.dll")]
private static extern int mciSendString(string cmd, StringBuilder ret, int retLen, IntPtr hwnd);

Parameter:*_cmd _: Kommandostring, welches an den MCI Treiber übergeben wird (Dazu später mehr). *ret: Enthält Rückgabewert des ausgeführten Kommandos. Vor allem für Statusabfragen wichtig. *retLen: Länge des Rückgabewertes. *hwnd: Fensterhandle. Einige Kommandos erzeugen Events für die Windows-Nachrichtenschleife, wenn ein notify-Flag an das Kommando gehängt wird. Man kann sich zum Beispiel benachrichtigen lassen, wenn ein Mp3-Stream beendet wurde.

Nun gut, ich habe etwas gelogen 😉
Wir werden für die Fehlerbehandlung noch eine 2. Funktion benötigen:


[DllImport("winmm.dll")]
private static extern int mciGetErrorString(int errCode, StringBuilder errText, int errLen);

Diese gibt uns lokalisierte Fehlertexte für einen bestimmten Fehlercode zurück. Wie das funktioniert, kann man im Quelltext nachlesen.

Kommandostrings

Wie schon gesagt, basiert MCI auf Kommandostrings, die mit mciSendString(…) versand werden. Zu den wichtigsten Kommandos gehören:

open
play
stop
pause
close

All diesen Kommandos können noch zusätzliche Parameter übergeben werden, die das Verhalten des Befehls genauer spezifizieren.
Beim open Kommando sieht das dann so aus:

open “C:\Videos\test.avi“ type mpegvideo alias VideoStream

Dieser Befehl öffnet die Datei test.avi und macht sie unter dem Alias VideoStream verfügbar. Diese Aliase sind für die weitere Ansteuerung über Kommandos wichtig. So kann man die Wiedergabe mit

play VideoStream fullscreen

beginnen und mit

stop VideoStream

wieder anhalten.

close VideoStream

schließt unseren Stream.

Das schöne an der Sache ist, dass diese Syntax für fast alle Medientypen mehr oder minder identisch ist. Auch MP3s und CDs lassen sich damit abspielen (siehe Quellcode).

Der zusätzliche Parameter fullscreen im Play-Kommando ist optional und entscheidet nur darüber, ob das Video im Vollbildmodus abgespielt wird oder nicht.

Für Audio-CDs kann man auch die CD Klappe öffnen und schließen. Dazu sendet man einfach folgende Kommandos:

set cdaudio door open

und

set cdaudio door closed

Alle Befehlsstrings zu behandeln, würde hier wohl den Rahmen sprengen. Auf MSDN werden sie alle ausführlich beschrieben:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_mci_reference.asp

Beispielprogramm

Ich habe für diesen Artikel einen kleinen Multimedia-Player geschrieben, der die Verwendung der MCI-Bibliothek demonstriert:

// Update (18.06.05): Habe einen Bug im Programm entfernt. Der Player sollte jetzt besser mit aufretenden Fehlern umgehen (z.B. wenn keine CD eingelegt ist)

I am Jack's smirking revenge.
I am Jack's raging bile duct.
I am Jack's cold sweat.
I am Jack's complete lack of surprise.
I am Jack's broken heart.
I am Jack's wasted life.

2.921 Beiträge seit 2005
vor 18 Jahren

Ja damit kann man vor allem auch gut CD-Laufwerk auf/zu machen und z.B. den Motor anhalten. 😉

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

A
196 Beiträge seit 2005
vor 18 Jahren

Ich möchte gerne alle mp3s aus einem Ordner abspielen.

public void getlieder()
		{
			String[] files=Directory.GetFiles(Data.musik,"*.mp3");
			foreach(string name in files)
			{
				//System.Windows.Forms.Application.DoEvents();
				if(this._play==true)
				{
					this.name=name;
					string cmd = "open \"" + name + "\" type " + "mpegvideo" + " alias \"" + name + "\"";
					int errCode = mciSendString(cmd, null, 0, IntPtr.Zero);
					CheckError(errCode);
					this.SetTimeFormat("m");
					String time=this.GetLength();
					this.Play(time);
			                                System.Threading.Thread.Sleep(int.Parse(time));
					
				}
				else
				{
						break;
				}
			}
		}

So werden zwar alle Lieder abgespielt aber es dauert immer etwas bis ein neues Lied anfängt.
Habt ihr bessere Vorschläge?

PS.: Der Musikplayer läuft als Thread neben den eigentlichen Programm.

S
125 Beiträge seit 2005
vor 18 Jahren

Hallo Leute.

Ich hab ebenfalls eine Frage.

Ich setze mit


			mciCommand = "set \"" + currentTrack + "\" time format ms";
			mciErrorCode = mciSendString(mciCommand, null, 0, IntPtr.Zero);

das Zeitformat auf Millisekunden
und lese mit


		private string GetLength()
		{
			Console.WriteLine(currentTrack);

			StringBuilder buffer = new StringBuilder(256);
			mciCommand = "status \"" + currentTrack + "\" length";
			mciErrorCode = mciSendString(mciCommand, buffer, 256, IntPtr.Zero);
			return buffer.ToString();
		}

die Länge des Tracks ein.

Leider ist der zurückgegebene String leer ("").
Weiß jemand wieso? Ich hab es genau wie in dem Beispiel im Anhang. Dort funktioniert es auch wunderbar.

Was mach ich falsch?

Mfg SGT_BOB

*************************
Ich bin root, ich darf das... 😜
root>_
*************************

M
maxE Themenstarter:in
456 Beiträge seit 2004
vor 18 Jahren

Ich häng in diesem MCI Kram nicht so tief drinn, aber es kann an ein deinem geöffnetem Gerät liegen. Nicht alle Geräte unterstützen alle Zeitformate.
CD-Devices haben üblicherweise das Format Track:Minute:Second:Millisecond.

I am Jack's smirking revenge.
I am Jack's raging bile duct.
I am Jack's cold sweat.
I am Jack's complete lack of surprise.
I am Jack's broken heart.
I am Jack's wasted life.

S
125 Beiträge seit 2005
vor 18 Jahren

Hi maxE.

Erst mal danke für die Antwort. Aber dein Beispiel funktioniert ja. Ich öffne das selbe MP3-File. Beim Beispiel-Programm funztes, bei meinem bekomme ich einen Fehlercode (263, glaub ich) zurück.

Noch irgendeine Ahnung?

Mfg SGT_BOB

EDIT:

Hat sich gerade erledigt. Ich weiß zwar nicht wieso, aber ich habe es jetzt geschafft. 😁 Danke trotzdem.

*************************
Ich bin root, ich darf das... 😜
root>_
*************************

L
113 Beiträge seit 2004
vor 18 Jahren

moin,

hab dazu noch mal eine frage, kennt sich hier wer zufällig mit der Quartz.dll aus?

hätte da noch ein paar fragen und würde mich übner hilfe sehr freuen!

1.) ich kann 2 stuecke zur gleichen Zeit abspielen, sehr ungünstig!
2.) pause hat ne zeitverzögerung von knapp 10sec, viel zu lange!!!

S
1 Beiträge seit 2006
vor 17 Jahren
Video in das Hauptfenster einbauen

Hallo,

mit Interesse habe ich diesen Artikel gelesen und danch gleich ausprobiert. Ich kann auch Videos abspielen. nun stoße ich jedoch auf ein Problem: die Videos werden in einem separaten Fenster geöffnet. Ich hätte aber gerne, dass das Video in meinem Hauptfenster (vielleicht in irgensdeinem Control) in einer definierten Größe abgespielt wird. Wie stellt man soetwas an?

Gruß, Slowflyer

S
298 Beiträge seit 2006
vor 17 Jahren

Hi,

du kannst dem MCI ein Handle von z.B. einer Picturebox übergeben in der die Wiedergabe dann ablaufen soll.

[DllImport("winmm.dll")]
private static extern int mciSendString(string cmd, StringBuilder ret, int retLen, IntPtr hwnd);

einfach dem IntPtr hwnd z.B. ein PictureBox.handle übergeben anstatt eines IntPtr.Zero

Gruß SkySurfer

Es gibt 11 Arten von Menschen:

  • Die, die binär verstehen
  • Die, die es nicht tun
  • Die, die Witze darüber machen
W
3 Beiträge seit 2006
vor 17 Jahren

Sehr guter Beitrag, hat mich wirklich weiter gebracht. 👍

Ich habe allerdings noch nicht herausgefunden, wie ich abfragen kann wann ein Titel zuende gespielt wurde. Vielleicht kann mir da jemand helfen...danke im voraus.

S
753 Beiträge seit 2006
vor 17 Jahren

Hallo,
mir geht es genauso, ich suche ein Event oder ähnliches, was mir sagt, ob das Lied gerade zu ende gespielt worden ist, oder nicht.
Im Moment sehe ich da nur die Möglichkeit zu vergleichen ob getcurrentPos == getLength ist

Life is a short

Z
38 Beiträge seit 2007
vor 16 Jahren

ich wollte fragen wie ich statt einer datei einfach den teil der zur zeit gerade über meine soundkarte ausgegeben wird. abgreifen kann um ihn dann so über das netzwerk zu verschicken und an einem anderen rechner mithilfe von mci abspielen kann

gruß zeax

4.221 Beiträge seit 2005
vor 16 Jahren

Als Ergänzung dieses Tutorials...

Hier noch ein Link wie man auch die Events von MCI nutzen kann.

Mp3 Stream abspielen

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

D
43 Beiträge seit 2007
vor 16 Jahren

Hi Leute,

zu dem Pointer mit der PictureBox.
Ich hab die Funktionen der MCI aus deinem Beispiel Code direkt übernommen. Das einzige was ich daran geändert habe ist das dich dem ganzen noch einen Konstruktor spendiert habe bei dem ich dann den IntPtr einer Picture Box übergebe der dann in der Klasse als private Variable gespeichert wird.
Außerdem habe ich alle IntPtr.Zero durch den Variablennamen ersetzt. Doch wenn ich nun mit meiner Funktion eine Video ansehen will, öffnet er mir dieses immer noch in einem separatem Fenster.

Woran kann das liegen?

Gruß
Durin-V

Die drei Erzfeinde eines jeden Programmierers:

  1. Tageslicht
  2. Frischluft
  3. das Gebrüll der Vögel
795 Beiträge seit 2006
vor 16 Jahren

Du musst das Handle der PictureBox (oder Form oder sonstwas) im CommandString mit übergeben :

mciSendString("open \"" + name + "\" type mpegvideo alias \"" + name + "\" parent " + pictureBox1.Handle.ToInt32().ToString() + " style child", null, 0, IntPtr.Zero);

Nun zu meiner Frage: Wie findet man die Originalgröße des Videos heraus?

Gruß, Christian.

`There are 10 types of people in the world: Those, who think they understand the binary system Those who don't even have heard about it And those who understand "Every base is base 10"`
C
62 Beiträge seit 2004
vor 16 Jahren

Hallo!

Ich habe ein Problem mit der Wiedergabe...wenn ich das Beispielprogramm verwende funktionniert es ohne Probleme, kopiere ich allerdings die SimpleAudioVideoPlayback.cs in ein anderes Projekt und erstelle dort eine neue Instanz und rufe Open() auf, bekomme ich einen Fehler:

Unbekanntes Problem beim Laden des angegebenen Gerätetreibers.


static void Main(string[] args)
{
   MCIPlayback m = new MCIPlayback();            
   m.Open(@"C:\c.mp3", "mpegvideo");
}

Weiß jemand, woran das liegen könnte? Hat es vielleicht damit zu tun, dass es einmal eine Windowsapplikation ist, und das andere mal liegt die Datei in einer DLL und wird von obiger Main aufgerufen?

C
62 Beiträge seit 2004
vor 16 Jahren

Ok, ich habe den Fehler gefunden:

Aus irgendeinem Grund muss das Programm, das ausgeführt wird und diese MCI-Sachen aufruft mit [STAThread] gekennzeichnet sein.

Kriegt man dieses Problem noch in den Griff?! Ansonsten bin ich soweit fertig! 🙂

F
17 Beiträge seit 2007
vor 16 Jahren

Original von Schamese
Nun zu meiner Frage: Wie findet man die Originalgröße des Videos heraus?

Gruß, Christian.

Würde mich auch interessieren.

Aber was ich auch wissen will: Kann man das Video 'verkleinern', sodass, wenn man das Form mit der Picturebox (die das Video anzeigt) verkleinert, das Video nicht einfach abgeschnitten wird, sondern sich mit verkleinert.

C
11 Beiträge seit 2007
vor 16 Jahren

Dock doch einfach mal die Picturebox in der Form so das die Picutrebox immer die ganze Form füllt.

Mfg

193 Beiträge seit 2005
vor 16 Jahren

Original von confused
Ok, ich habe den Fehler gefunden:

Aus irgendeinem Grund muss das Programm, das ausgeführt wird und diese MCI-Sachen aufruft mit [STAThread] gekennzeichnet sein.

Kriegt man dieses Problem noch in den Griff?! Ansonsten bin ich soweit fertig! 🙂

Danke! Hat mir echt weitergehofen!

Edit:
Achja: und kann man die Lautstärke verändern oder muss das über den Wave-Kanal erledigt werden?

Visit me @ www.beremote.net

193 Beiträge seit 2005
vor 16 Jahren

Aaalso:
Man kann die Lautstärke verändern.
Die MCI-SendStrings sind wie folgt:
Linker Audiokanal:
mciSendString(string.Concat("setaudio MediaFile left volume to ", value), null, 0, 0);

Rechter Audiokanal:
mciSendString(string.Concat("setaudio MediaFile right volume to ", value), null, 0, 0);

Master Kanal:
mciSendString(string.Concat("setaudio MediaFile volume to ", value), null, 0, 0);

value hat dabei einen Wert von 0 bis 1000

Zusätzlich kann man angeblich noch Bass und Treble verändern, aber bei mir funktioniert es nicht. Trotzdem hier die Strings dafür (auch hier hat Value einen Wert von 0 bis 1000):
mciSendString(string.Concat("setaudio MediaFile bass to ", value), null, 0, 0);
mciSendString(string.Concat("setaudio MediaFile treble to ", value), null, 0, 0);

Visit me @ www.beremote.net

W
33 Beiträge seit 2007
vor 16 Jahren

Ist die winmm.dll standardmäßig bei allen Windows-Versionen (ab 98) nach der Neuinstallation mit dabei? Muss wissen ob mciSendString universell einsetzbar ist für versch. OS-Versionen

795 Beiträge seit 2006
vor 16 Jahren

MCI gibt es imho seit Win3.1x. Man muss nur die Audiocodecs nachinstallieren, die man braucht.

Gruß, Christian.

`There are 10 types of people in the world: Those, who think they understand the binary system Those who don't even have heard about it And those who understand "Every base is base 10"`
T
1 Beiträge seit 2009
vor 15 Jahren

Hallo,
dieser Thread ist zwar schon etwas älter, ich habe aber trotzdem noch eine Frage dazu. Und zwar möchte ich bestimmte Frames des Videos als Bitmap, Color-Array oder vergleichbares bekommen, diese bearbeiten und wieder in ein video(avi) speichern. Auch den Sound möchte ich entfernen und wieder hinzufügen können. Ist dies mit MCI möglich oder kennt ihr noch andere Möglichkeiten?
Ich hoffe sehr, dass mir jemand weiterhelfen kann, ich google nämlich schon seit längerem und das einzige vernünftige, was ich bekommen habe ist das hier:
http://www.codeproject.com/KB/audio-video/avifilewrapper.aspx
Leider gab es hier aber zu oft AVIs, die nicht geöffnet werden konnten.

mfg

TimeOver

Hi Leute
bin 14 Jahre alt, intressiere mich seit ich 10 bin für die Programmierung und programmiere seit ich 13 bin selber

Meine Kentnisse:
html, css, php, mysql, C#, XNA und ein wenig C++

F
10.010 Beiträge seit 2004
vor 15 Jahren

Nein, MCI ist nicht für Videobearbeitung gedacht.

Wenn Du dir mal Projekte wie VirtualDup und CO anschaust, wirst Du feststellen,
das das alles nicht wirklich einfach ist.