A Guide To The Windows MCI
Introduction
The Windows MCI was developed by
Microsoft and Intel and was introduced properly into Windows 95. Ever since then
it has been the tool that programmers have used to open, save, record and play
multimedia. The Windows MCI is a unique tool in that when programming it you use
statements and syntax that makes sense and is plain English. This guide is
designed to help Visual Basic programmers master the Windows MCI and gain a firm
understanding of how it works, how to programme it and use it to enhance their
own programs.
1. The
Windows MCI - What is it?
The Windows MCI is a shorthand
term used to describe the Windows Multimedia Control Interface. It acts as a
translator interpreting the commands sent to it and translating these commands
so that Windows can play a multimedia file. Currently the Windows MCI
supports almost hundred individual commands and can be used to play today's most
popular formats such as MP3, MPEG and WindowsMedia.
2. The
Windows MCI - How do I programme it?
To programme the Windows MCI you
will need:
-
Visual Basic, I recommend
version 6 however 5 and 4 should work ok. I am currently unaware because of
the changes in Visual Basic.NET whether the syntax used later will work but it
should.
-
A good understanding of the
Visual Basic environment.
-
A lot of patience!
3. The
Windows MCI - The different parts
There are several different
parts which make up the Windows MCI. These include the different devices used to
play the different file types, the decoding engines used to break down the file
so it can be played and additional parts which allow you to find out additional
information about a file e.g. bitrate, length, title, author etc.
4. The
Windows MCI - Let's get coding!!!
Ok, now you understand the
basics of the Windows MCI we can begin to code the Windows MCI to play some
media. Firstly we need some media files to use as tests, ideally a wav, mp3,
mpeg and wma file. Please note that all code shown here was designed to be
inside a private module and relate to a form, you will need to alter this in
order to make it private form or public module.
5. The
Windows MCI - Form Design
We will not begin to use the
Windows MCI to modify files, the following must be done before we can proceed,
design the following now:
Form Component |
Name |
Caption |
|
|
|
Form |
Form1 |
Windows MCI
Programming |
PictureBox |
Picture1 |
N/A |
CommandButton |
Command1 |
Open Media |
CommandButton |
Command2 |
Play Media |
CommandButton |
Command3 |
Pause Media |
CommandButton |
Command4 |
Stop Media |
CommandButton |
Command4 |
Close Media |
CommonDialog |
CMDialog1 |
N/A |
The picture box will be used as a video screen
and the command buttons will contain the commands you need to send to the
Windows MCI.
6. The
Windows MCI - Communication
Before we can begin to code the
Windows MCI we need to allow Visual Basic to talk to it. To do this we need to
call a function, this function is the mciSendString function and is listed
below, add it to a module now.
Private
Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal
lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength
As Long, ByVal hwndCallback As Long) As Long
The mciSendString allows the Visual Basic to
send a string of commands to the Windows MCI which tells it to get the file's
length, to stop playing etc. You use mciSendString to send a command in the
format of command, returnstring, callback.
7. The
Windows MCI - Opening Files
Before we can begin to open
files we need to add a few more functions to our module:
Private
Declare Function GetShortPathName Lib "Kernel32" Alias "GetShortPathNameA" (ByVal
lpszLongPath As String, ByVal lpszShortPath As String, ByVal cchBuffer As Long)
As Long
Open Command1's code window and type the following,
it will be explained later:
Dim
MediaFilename As String
Dim MediaFilenameSize As String
Dim TempFile As String * 255
Dim GetShortFile As Long
Dim CompleteFilename As String
Form1.CMDialog1.FileName = ""
Form1.CMDialog1.Filter = "All Media Files|*.*"
Form1.CMDialog1.Action = 1
If Form1.CMDialog1.FileName = "" Then Exit Sub
MediaFilename = Form1.CMDialog1.FileName
If MediaFilename = "" Then Exit Sub
GetShortFile = GetShortPathName(MediaFilename, TempFile, 255)
CompleteFilename = left$(TempFile, GetShortFile)
So what does all that mean? Well when broken
down its quite simple. The first paragraph contains the individual declarations.
The second contains the information used to determine the filename to open. The
third paragraph checks to see that a valid file can be opened and then converts
it into the 8.3 filename format. This is return to dos as the original Windows
MCI was programmed when the 8.3 format was very much alive and so when opening
files we have to convert them into this format for the Windows MCI to understand
the file. At this stage we have a file which has been converted into the 8.3
format but we want to open the file, enter this into the code beneath the above
code:
If
LCase(Right(CompleteFilename, 4)) = ".wav" Or LCase(Right(CompleteFilename, 5))
= ".wave" Then
Call CompleteOpen(CompleteFilename, "waveaudio", True)
ElseIf LCase(Right(CompleteFilename, 4)) = ".mid" Or
LCase(Right(CompleteFilename, 5)) = ".midi" Or LCase(Right(CompleteFilename, 4))
= ".rmi" Then
Call CompleteOpen(CompleteFilename, "sequencer", True)
ElseIf LCase(Right(CompleteFilename, 4)) = ".mp3" Or
LCase(Right(CompleteFilename, 4)) = ".mp2" Or LCase(Right(CompleteFilename, 4))
= ".mp1" Or LCase(Right(CompleteFilename, 4)) = ".snd" Or
LCase(Right(CompleteFilename, 4)) = ".aif" Or LCase(Right(CompleteFilename, 5))
= ".aiff" Or LCase(Right(CompleteFilename, 5)) = ".aifc" Or
LCase(Right(CompleteFilename, 3)) = ".au" Or LCase(Right(CompleteFilename, 4)) =
".enc" Or LCase(Right(CompleteFilename, 4)) = ".mv1" Then
Call CompleteOpen(CompleteFilename, "MPEGVideo", True)
ElseIf LCase(Right(CompleteFilename, 4)) = ".avi" Then
Call CompleteOpen(CompleteFilename, "avivideo", False)
ElseIf LCase(Right(CompleteFilename, 4)) = ".vcd" Or
LCase(Right(CompleteFilename, 4)) = ".dat" Then
Call CompleteOpen(CompleteFilename, "videodisc", False)
ElseIf LCase(Right(CompleteFilename, 4)) = ".mpg" Or
LCase(Right(CompleteFilename, 4)) = ".mpe" Or LCase(Right(CompleteFilename, 4))
= ".mpa" Or LCase(Right(CompleteFilename, 5)) = ".mpeg" Or
LCase(Right(CompleteFilename, 4)) = ".mov" Or LCase(Right(CompleteFilename, 3))
= ".qt" Or LCase(Right(CompleteFilename, 4)) = ".asf" Or
LCase(Right(CompleteFilename, 4)) = ".asx" Or LCase(Right(CompleteFilename, 5))
= ".mpv2" Or LCase(Right(CompleteFilename, 5)) = ".mp2v" Or
LCase(Right(CompleteFilename, 4)) = ".wax" Or LCase(Right(CompleteFilename, 4))
= ".wvx" Or LCase(Right(CompleteFilename, 4)) = ".wmx" Then
Call CompleteOpen(CompleteFilename, "MPEGVideo", False)
ElseIf LCase(Right(CompleteFilename, 4)) = ".wmv" Or
LCase(Right(CompleteFilename, 4)) = ".wma" Or LCase(Right(CompleteFilename, 3))
= ".wm" Or LCase(Right(CompleteFilename, 4)) = ".wmp" Then
Call CompleteOpen(CompleteFilename, "MPEGVideo", False)
Else
MsgBox "Media File type or Compression not supported! If you are attempting to
open RealMedia this is currently impossible because RealVideo and RealAudio are
not decoded through the Windows MCI but through separate dynamic link
libraries.", vbInformation, "Error"
End If
As you can see their is a lot of code above but all it does is determine the
file type and send the final open commands to the Windows MCI in a separate sub
called CompleteOpen. If the file is a wave file then it sends to the Windows MCI
the command open the file as "waveaudio" (this is the device the Windows
MCI uses to play wave files) and then the command True. This command is
something I added to tell me later whether the file was just audio or whether it
was video. The code above will allow you determine every file type the Windows
MCI supports (I think? Please note RealMedia cannot be opened because it does
not use the Windows MCI but uses separate dll files which include the decoding
algorithms this also applies to the new and upcoming ogg vorbis format(s) .
Now after all this code we can actually tell
the Windows MCI to open the file!
Public
Sub CompleteOpen(FileName, Device, AudioOnly)
Dim MCIString As String
Dim MCICommand As String
Dim ReturnString As String
Dim CallBack As Long
ReturnString = Space$(128)
If AudioOnly Then
MCIString = "open " & Device & "!" & FileName & " alias mpeg"
MCICommand = mciSendString(MCIString, ReturnString, 128, CallBack)
Else
MCIString = "open " & Device & "!" & FileName & " alias mpeg parent " &
Form1.Picture1.hwnd & " style child"
MCICommand = mciSendString(MCIString, ReturnString, 128, CallBack)
End If
End Sub
The code above opens the file and loads it into the Windows
MCI memory notice that we refer to the file as mpeg. This allows us to use
commands in the future so that the Windows MCI can open more than one file. From
here we can learn about the file's length and other features however we need to
tell the Windows MCI to play the file in order to see or hear it. The following
code will allow use to do that.
Dim MCIString As String
Dim MCICommand As String
Dim ReturnString As String
Dim CallBack As Long
ReturnString = Space$(128)
MCIString = "play mpeg from 0"
MCICommand = mciSendString(MCIString, ReturnString, 128, CallBack)
So as you can see we have sent another
command to the Windows MCI telling it to play the file "mpeg" from 0 (the
beginning). Next comes the code to allow us to pause it.
Dim
MCIString As String
Dim MCICommand As String
Dim ReturnString As String
Dim CallBack As Long
ReturnString = Space$(128)
MCIString = "pause mpeg"
MCICommand = mciSendString(MCIString, ReturnString, 128, CallBack)
and to stop it...
Dim
MCIString As String
Dim MCICommand As String
Dim ReturnString As String
Dim CallBack As Long
ReturnString = Space$(128)
MCIString = "stop mpeg"
MCICommand = mciSendString(MCIString, ReturnString, 128, CallBack)
and finally to close the Windows MCI (clear the memory)...
Dim
MCIString As String
Dim MCICommand As String
Dim ReturnString As String
Dim CallBack As Long
ReturnString = Space$(128)
MCIString = "stop mpeg"
MCICommand = mciSendString(MCIString, ReturnString, 128, CallBack)
MCIString = "close mpeg"
MCICommand = mciSendString(MCIString, ReturnString, 128, CallBack)
You can now open, play, pause, stop and
close media. This concludes part 1 of the programming the Windows MCI Guide. In
part 2 you will learn how to use progress bars and timers to monitor files and
extract information such as the file's length, author, bitrate and title!
NEW ADDITION - Some people asked
about how to get the correct size of the video and to resize the PictureBox, I
will be addressing this issue in the part 3 however the following code
provided by Jason Hensley will allow you to do this:
Dim
MCIString As String
Dim MCICommand As String
Dim ReturnString As String
Dim CallBack As Long
ReturnString = Space$(128)
MCIString = "where mpeg destination"
MCICommand = mciSendString(MCIString, ReturnString, 128, CallBack)
' The ReturnString will return a value which looks something like this 0 0 175
200, each value represents left, top, width, height. From here you can extract
the values and 'resize the textbox accordingly.
Part 2 - Monitoring &
Reading The Windows MCI
Welcome back all! So as I can
see a lot of people enjoyed this guide thus the result is the next edition. In
this part we will look at the Windows MCI and how we can use it monitor media
status and read the tags of media files. First we had better begin with the
media status monitoring to do this we require:
Form Component |
Name |
Caption |
|
|
|
Progress Bar |
Status |
N/A |
Timer |
Timer1 |
N/A |
Label |
Label1 |
Title |
Label |
Label2 |
Author |
Label |
Label3 |
Album |
Label |
Label4 |
Comment |
Now we can begin to implement the controls so
that they show the status of the Windows MCI. To do this we must first set the
progress bar's Max value. We get this value by running the following code:
Dim MCIString As
String
Dim MCICommand As String
Dim ReturnString As String
Dim CallBack As Long
Dim Sound As Single
ReturnString = Space$(128)
MCIString = "status mpeg length"
MCICommand = mciSendString(MCIString, ReturnString, 128, CallBack)
Form1.Status.Max = Val(ReturnString) / 2
This will allow us to set the progress bar's max
value. Next we need to implement code to update the progress bar each time the
media is played and to set the Value figure we do this by using the following
code:
Dim MCIString As String
Dim MCICommand As String
Dim ReturnString As String
Dim CallBack As Long
Dim Sound As Single
ReturnString = Space$(128)
MCIString = "status mpeg position"
MCICommand = mciSendString(MCIString, ReturnString, 128, CallBack)
Form1.Status.Value = Val(ReturnString) / 2
Place the above code in a timer and set the
timer interval to 1. Place the code above into a separate sub and run it when
you open the file.
Reading Media Tags - MP3 Files
In our module enter a new sub called ReadMP3 and
input the following code:
Dim fNum As Integer
Dim sTagIdent As String * 3
Dim sTitle As String * 30
Dim sArtist As String * 30
Dim sAlbum As String * 30
Dim sYear As String * 4
Dim sComment As String * 30
fNum = FreeFile
Open "c:\MySong.mp3" For Binary As fNum
Seek #fNum, LOF(fNum) - 127
Get #fNum, , sTagIdent
If sTagIdent = "TAG" Then
Get #fNum, , sTitle
Get #fNum, , sArtist
Get #fNum, , sAlbum
Get #fNum, , sYear
Get #fNum, , sComment
End If
Close #fNum
Form1.Label1.Caption = "Title: " & sTitle
Form1.Label2.Caption = "Artist: " & sArtist
Form1.Label3.Caption = "Album: " & sAlbum
Form1.Label4.Caption = "Comment: " & sComment
That's it for part 2 in part 3 we will
explore the aspects of video in our media guide. Thank you for all the people
who voted and provided feedback, I would appreciate both!
Part 3
Right lets play with that video, firstly we will
need to resize the video to fit the picture. You can set this manually with code
however I ran into problems, the code to do it a better way is as follows (you
will need 4 text boxes and their text value must be empty):
Private Declare
Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Public Sub ResizeMedia(hwnd As Long, MCIAlias As String, Left As Long, Top As
Long, Width As Long, Height As Long)
Dim MCIString As String
Dim MCICommand As String
Dim ReturnString As String
Dim CallBack As Long
Dim Sound As Single
ReturnString = Space$(128)
If Width = 0 Or Height = 0 Then
Dim rec As RECT
Call GetWindowRect(hwnd, rec)
Width = rec.Right - rec.Left
Height = rec.Bottom - rec.Top
End If
MCIString = "put mpeg window at " & Left & " " & Top & " " & Width & " " &
Height
MCICommand = mciSendString(MCIString, ReturnString, 128, CallBack)
End Sub
Call
ResizeMedia(Form1.Picture1.hwnd, "mpeg", Val(Form1.txtleft), Val(Form1.txttop),
Val(Form1.txtwidth), Val(Form1.txtheight))
' or you could
use
Call ResizeMedia(Form1.Picture1.hwnd, "mpeg", 0, 0, 1200, 2800)
Copyright (c) 2002 IceWeb Systems
Much thanks goes to PSC
programmers Abdullah Al-Ahdul and Jason Hensley!
|