[
]关于这个问题,我可以自己回答么?呵呵。昨晚查了一晚上资料,还看了MPlayer.pas的源码,看到它是用的mcisendcommand来实现的操作,具体代码如下:
property Length: Longint read GetLength;
......
function TMediaPlayer.GetLength: Longint;
var
StatusParm: TMCI_Status_Parms;
begin
CheckIfOpen;
{raises exception if device is not open}
FFlags := mci_Wait or mci_Status_Item;
StatusParm.dwItem := mci_Status_Length;
FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
Result := StatusParm.dwReturn;
end;
关于mcisendcommand的语法可以在win32 api中查到
而在csdn文章 http://www.csdn.net/develop/read_article.asp?id=14940
中描述了MPlayer控件设计中的一个错误,其中还提到“而且MediaPlay.Length的长度也不正确”,可惜无法和原作者联系。
于是自己动手,用mcisendstring写了一个getMP3Len函数来获取mp3长度,发现与mediaplayer的length属性返回值是一样的。
百思不得其解之际用cooleditor把那首mp3打开,发现其采样率竟然只有37kbps。用winamp播放,拖动,才发现这首mp3制作不好,采样率是变化的!
于是计算了一下:
3,605,771bytes*8bits/byte/37*1024bps=761s=12.69min
终于明白了,mci api计算播放时间不过是将文件大小除以采样率;
于是用cooledit将采样率恒定,另存,再次用mediaplayer.length检测长度,就正确了。
但是问题并没有结束,为什么winamp和explorer都可以给出正确的长度呢?可见他们都不是用的mci api来做的,于是继续查找资料,发现在可以通过directX sdk来操作媒体文件:
g_pGraphBuilder: IGraphBuilder = nil;
g_pMediaControl: IMediaControl = nil;
// 播放状态设置.
g_pMediaSeeking: IMediaSeeking = nil;
// 播放位置.
g_pAudioControl: IBasicAudio = nil;
// 音量/平衡设置.
g_pVideoWindow: IVideoWindow = nil;
//设置播放窗体.
PLAYING: boolean = false;
//判断是否正在播放
function Initdxcom: boolean;
begin
Result := false;
// 初始化COM接口
if failed(CoInitialize(nil)) then
exit;
// 创建DirectShow Graph
if failed(CoCreateInstance(OLE2.TGUID(CLSID_FilterGraph), nil, CLSCTX_INPROC, OLE2.TGUID(IID_IGraphBuilder), g_pGraphBuilder)) then
exit;
// 获取IMediaControl 接口
if failed(g_pGraphBuilder.QueryInterface(IID_IMediaControl, g_pMediaControl)) then
exit;
// 获取IMediaSeeking 接口
if failed(g_pGraphBuilder.QueryInterface(IID_IMediaSeeking, g_pMediaSeeking)) then
exit;
// 获取IBasicAudio 接口
if failed(g_pGraphBuilder.QueryInterface(IID_IBasicAudio, g_pAudioControl)) then
exit;
// 获取IVideowindow 接口
if failed(g_pGraphBuilder.QueryInterface(IID_IVideoWindow, g_pVideoWindow)) then
exit;
// 所有接口获取成功
Result := true;
end;
然后渲染:
_hr := g_pGraphBuilder.renderfile(@wfile, nil);
// 建立了一个能够播放文件的Filter Graph
渲染后就可以进行各种播放操作和状态查询
但是需要uses DirectShow,可是我的delphi中没有,所以也没能够实验。但是我觉得这种方法所获得媒体长度应该是更真实的。
谁能告诉我如何才能进行directshow编程,不胜感激!
hmisty 2003.7.25