Chủ Nhật, 24 tháng 1, 2010

// // Leave a Comment

Media Player C# using MCI

I) Giới thiệu

Trong nhiều trường hợp, bạn cần sử dụng âm thanh trong ứng dụng của mình để thông báo hay tạo một hiệu ứng nào đó. Bạn nghĩ tới việc sử dụng lớp System.Media.SoundPlayer cho yêu cầu này, và bạn nhận ra nó có một hạn chế là chỉ chơi được các định dạng .wav. Một giải pháp khác là bạn dùng control Window Media Player có sẵn trong Windows, đây là một giải pháp hay. Nhưng nếu bạn không muốn lệ thuộc vào control này, bạn cần tìm một con đường khác và có thể bạn sẽ tìm được nó khi đọc phần tiếp theo của bài viết này.

Trong bài này, tôi sẽ trình bày cách tạo một chương trình để chơi các định dạng âm thanh và video với các chức năng cơ bản như play, pause, stop, seek…thông qua Media Control Interface (MCI). Để biết thêm các thông tin và cách sử dụng MCI bạn có thể tham khảo trên MSDN của Microsoft.

MCI Player

Giao diện mô phỏng của ứng dụng sau khi hoàn thành.

II) Thiết kế

Trước tiên, để ứng dụng của bạn OOP hơn, hãy tạo một lớp để quản lý chức năng chơi nhạc, ví dụ ở đây tôi đặt tên lớp là MciPlayer. Lớp này sẽ chứa những hàm cơ bản để ta điều khiển quá trình chơi nhạc.

Để sử dụng được MCI bạn cần thêm hàm API mciSendString nằm trong tập tin winmm.dll của Windows. Hãy thêm namespace System.Runtime.InteropServices vào trước khi import tập tin winmm.dll. Đây là đoạn mã import thư viện winmm.dll và khai báo hàm API mciSendString để sử dụng trong chương trình.

[DllImport("winmm.dll")]

private static extern long mciSendString(string strCommand, StringBuilder strReturn, int iReturnLength, IntPtr hwndCallback);

Trong đó bạn cần chú ý đển tham số strCommand, đây là chuỗi chứa lệnh MCI cần thực hiện. Bạn có thể xem danh sách lệnh tại địa chỉ bên dưới

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_multimedia_command_strings.asp

Sau đây là các phương thức căn bản trong lớp MciPlayer của ta.

1) Mở media:

public void Open(string filePath)

{

string sCommand = “open \”" + filePath +”\” type mpegvideo alias YinYangMedia”;

mciSendString(sCommand, null, 0, IntPtr.Zero);

}

Trong chuỗi sCommand, chú ý rằng đường dẫn tập tin media của bạn phải chứa trong ngoặc kép nên ta phải dùng chuỗi \” để bao phần filePath lại. Ở đây chuỗi mpegvideo để xác định rằng chúng ta có thể chơi hầu hết các định dạng media hiện nay như mp3, avi, wav, mpeg, mpg and wmv…Ở đây tôi sử dụng tên định danh YinYangMedia cho tập tin Media, bạn có thể thay đổi tên khác tùy thích nhưng phải thống nhất trong những lần gọi hàm khác.

2) Play, Pause, Stop, Seek, Close media:

public void Play()

{

mciSendString(“play YinYangMedia”, null, 0, IntPtr.Zero);

}

public void Pause()

{

mciSendString(“pause YinYangMedia”, null, 0, IntPtr.Zero);

}

public void Stop()

{

try{

mciSendString(“stop YinYangMedia”, null, 0, IntPtr.Zero); }catch{}

}

public void Seek(long value)

{

value = value * 1000;

mciSendString(“seek YinYangMedia to ” + value.ToString(), null, 0, IntPtr.Zero);

Play();

}

public void Close()

{

try{

mciSendString(“close YinYangMedia”, null, 0, IntPtr.Zero);

}catch {}

}

Phương thức Seek sẽ nhảy đến vị trí xác định bằng tham số value truyền vào và play tại vị trí đó, tham số value truyền vào có đơn vị là giây vì thế ta nhân với 1000 để chuyển sang mili giây.

Trường hợp bạn muốn chơi một file media khác, trước tiên bạn cần đóng (close) media hiện tại. Để tiện hơn bạn có thể thêm phương thức Close() vào đầu phương thức Open() phía trên.

3) Hiển thị cửa sổ xem video

Chức năng play trên chỉ đơn giản làm nhiệm vụ phát âm thanh. Nếu bạn đang chơi một file video và cần hiển thị hình ảnh, hãy sử dụng phương thức sau:

public void DisplayMediaWindow()

{

mciSendString(“put YinYangMedia”, null, 0, IntPtr.Zero);

}

Phương thức này sẽ mở cửa sổ video với kích thước mặc định, nếu bạn muốn xác định vị trí và kích thước của cửa sổ được mở, hãy overload hoặc sửa lại phương thức này như sau:

public void DisplayMediaWindow(Rectangle rec)

{

mciSendString(“put YinYangMedia window at ” + rec.Left + ” ” + rec.Top +

” ” + rec.Width + ” ” + rec.Height, null, 0, IntPtr.Zero);

}

Phương thức mới này truyền vào đối tượng Rectangle đại diện cho vị trí và kích thước của cửa sổ sẽ mở với gốc tọa độ là góc trên bên trái màn hình. Thay vì truyền vào một Rectangle, bạn cũng có thể overload thêm một phương thức truyền vào 4 tham số xác định vị trí left, top, width và height của cửa sổ.

4) Lấy trạng thái của player

Để xác định xem player của chúng ta đang ở trạng thái nào, bạn hãy viết một phương thức hoặc getter như sau:

public string Status

{

get

{

int length = 128;

StringBuilder strBuffer = new StringBuilder(length);

mciSendString(“status YinYangMedia mode”, strBuffer,

length, IntPtr.Zero);

return strBuffer.ToString();

}

}

Tham số strBuffer là biến lưu kết quả trả về, length là độ dài của độ dài của bộ đệm chứa kết quả tính bằng kí tự.

Bởi vì kết quả là kiểu string và chỉ thuộc một trong 3 trạng thái “playing”,”paused”, “stopped”. Bạn có thể tạo một enum chứa các trạng thái của player này, bổ sung thêm một trạng thái “Ready” nếu như hàm Open thực thi thành công, mỗi khi thực hiện lệnh nào đó, player của chúng ta sẽ tự động thay đổi trạng thái. Ví dụ như sau:

public enum PlayerStatus { Ready, Playing, Paused, Stopped };

Gợi ý: bạn thêm một thuộc tính kiểu PlayerStatus và danh sách các tập tin Media cần chơi vào player, khi chơi hết một bài hãy tiếp tục bài tiếp theo trong danh sách.

5) Lấy chiều dài, vị trí hiện tại của media:

Lấy tổng thời gian cần để chơi hết file tính bằng giây đã được làm tròn.

public long Length

{

get

{

StringBuilder fileleng = new StringBuilder(256);

mciSendString(“status YinYangMedia length”, fileleng, 256, IntPtr.Zero);

try

{

return (long)Math.Floor(Convert.ToDouble(fileleng.ToString().Trim()) / 1000);

}

catch { return 0; }

}

}

Vị trí đang chơi hiện tại của file tính bằng giây

public long Current

{

get

{

StringBuilder fileleng = new StringBuilder(256);

mciSendString(“status YinYangMedia position”, fileleng, 256, IntPtr.Zero);

try

{

return (long)Math.Floor(Convert.ToDouble(fileleng.ToString().Trim()) / 1000);

}

catch { return 0; }

}

}

Để hiển thị theo dạng mm:ss bạn cần viết thêm phương thức để tính số phút và số giây, sau đó format theo định dạng thích hợp. Ví dụ bạn tạo ở Form thực thi hương thức sau để format:

private string FormatSeconds(long seconds)

{

long minus = 0;

if (seconds <>

{

minus = seconds / 60;

seconds = seconds % 60;

return minus.ToString().PadLeft(2, ‘0′)

+ “:” + seconds.ToString().PadLeft(2, ‘0′);

}

// …

Hàm PadLeft sẽ lấp đầy bên trái chuỗi bằng kí tự ‘0’ cho đến khi đủ số kí tự quy định. Giả sử số phút là 1 và giây là 2, kết quả trả về sẽ là ‘01:02’.

Phần cốt lõi của chương trình đã hoàn thành, bạn hãy tạo giao diện và thêm vào một trackBar để kiếm tra phương thức Seek và các chức năng khác của lớp MciPlayer.


Để lấy hoặc thay đổi giá trị volumn bạn có thể sử dụng 2 hàm waveOutGetVolume() và waveOutSetVolume() nằm trong cùng thư viện winmm.dll được sử dụng trong ví dụ trên.
Bạn khai báo 2 hàm trên như sau:

[DllImport("winmm.dll")]
public static extern int waveOutGetVolume(IntPtr hwo, out uint dwVolume);

[DllImport("winmm.dll")]
public static extern int waveOutSetVolume(IntPtr hwo, uint dwVolume);

Tham số hwo bạn có thể đặt là IntPtr.Zero, còn dwVolume của 2 hàm trên chính là giá trị của volumn khi bạn lấy hoặc gán.

III) Phần kết:

Với các chức năng cơ bản của lớp MciPlayer vừa tạo, bạn có thể tự thiết kế cho mình một ứng dụng MultiMedia đa năng như quản lý nhạc, tự động tắt máy, màn hình, tạo playlist sử dụng các collection,…

http://yinyang-it.tk

0 comments: