好吧,声明一下,本文需要修改RVMedia 本身的源码,RVMedia 4.0.2 本身是不支持这一功能的,所以,如果你想要支持这一功能,需要对 RVMedia 打补丁。因为不想对RVMedia 进行大手术,所以改的内容尽量少,剩下的事情由额外的东西来解决:
1、打开 MRVTypes.pas,为 RVMedia 打第 1 处补丁:
1.1、找到 TCustomRVMicrophone,在其前面定义一个事件类型:
TRVWaveBufferReadyEvent = procedure(Sender: TObject; AData: PByte;ALen: Integer) of object;
这个事件类型,用于将捕获到的 WAV 数据传给事件的响应函数中。
1.2、为 TCustomRVMicrophone 增加一个事件,及触发事件的接口函数 BufferReady:
protected FOnBufferReady: TRVWaveBufferReadyEvent; procedure BufferReady(ABuf: PByte; ASize: Integer); published property OnBufferReady: TRVWaveBufferReadyEvent read FOnBufferReady write FOnBufferReady;
1.3、在 BufferReady 函数中添加下面的代码:
procedure TCustomRVMicrophone.BufferReady(ABuf: PByte; ASize: Integer);
begin
if Assigned(FOnBufferReady) then
FOnBufferReady(Self, ABuf, ASize);
end;
3、实现下面的类,用于完成录制音频数据到 WAV 文件的封装。
uses ...,MRVWinMicrophone, MRVMicrophone, MRVWavFile;
type
TRVWaveRecorder = class
private
FWaveHeader: TWaveHeader;
FDataHeader: TDataHeader;
FWaveStream: TFileStream;
FWaveFile: String;
FMicrophone: TCustomRVMicrophone;
procedure DoBufferReady(ASender: TObject; ABuf: PByte; ALen: Integer);
function GetDuration: Integer;
function GetWaveFile: String;
procedure SetMicrophone(const Value: TCustomRVMicrophone);
procedure SetWaveFile(const Value: String);
procedure PrepareWaveFile;
public
constructor Create; overload;
destructor Destroy; override;
procedure Start;
procedure Stop;
property Microphone: TCustomRVMicrophone read FMicrophone
write SetMicrophone;
property WaveFile: String read FWaveFile write SetWaveFile;
property Duration: Integer read GetDuration;
end;
{ TRVWaveRecorder }
constructor TRVWaveRecorder.Create;
begin
end;
destructor TRVWaveRecorder.Destroy;
begin
Stop;
if Assigned(FMicrophone) then
FMicrophone.OnBufferReady := nil;
inherited;
end;
procedure TRVWaveRecorder.DoBufferReady(ASender: TObject; ABuf: PByte;
ALen: Integer);
begin
if Assigned(FWaveStream) then
begin
Inc(FDataHeader.DataLen, ALen);
FWaveStream.WriteBuffer(ABuf^, ALen);
end;
end;
function TRVWaveRecorder.GetDuration: Integer;
begin
if FWaveHeader.BytesPerSec <> 0 then
Result := FDataHeader.DataLen div FWaveHeader.BytesPerSec
else
Result := 0;
end;
function TRVWaveRecorder.GetWaveFile: String;
begin
if Assigned(FWaveStream) then
Result := FWaveStream.Filename
else
SetLength(Result, 0);
end;
procedure TRVWaveRecorder.PrepareWaveFile;
begin
if not Assigned(FWaveStream) then
FWaveStream := TFileStream.Create(FWaveFile, fmCreate)
else if FWaveStream.Filename <> FWaveFile then
begin
FreeAndNil(FWaveStream);
FWaveStream := TFileStream.Create(FWaveFile, fmCreate);
end;
FWaveStream.Size := 0;
with FWaveHeader do
begin
idRiff := 'RIFF';
RiffLen := 38;
idWave := 'WAVE';
idFmt := 'fmt ';
InfoLen := 16;
WaveType := 1;
Ch := 1;
case Microphone.SamplesPerSec of
rvsps8000:
Freq := 8000;
rvsps11025:
Freq := 11025;
rvsps22050:
Freq := 22050;
rvsps44100:
Freq := 44100;
end;
case Microphone.BitsPerSample of
rvbps8:
Bits := 8;
rvbps16:
Bits := 16;
end;
BytesPerSec := Freq * Bits div 8;
align := Bits div 8;
end;
FWaveStream.WriteBuffer(FWaveHeader, SizeOf(TWaveHeader));
FDataHeader.idData := 'data';
FDataHeader.DataLen := 0;
FWaveStream.WriteBuffer(FDataHeader, SizeOf(FDataHeader));
end;
procedure TRVWaveRecorder.SetMicrophone(const Value: TCustomRVMicrophone);
begin
if FMicrophone <> Value then
begin
if Assigned(FMicrophone) then
FMicrophone.OnBufferReady := nil;
FMicrophone := Value;
if Assigned(FMicrophone) then
begin
FMicrophone.OnBufferReady := DoBufferReady;
if FMicrophone.Active then
PrepareWaveFile;
end;
end;
end;
procedure TRVWaveRecorder.SetWaveFile(const Value: String);
var
ARecording: Boolean;
begin
if Value <> WaveFile then
begin
if Assigned(FMicrophone) then
begin
ARecording := Microphone.Active;
Microphone.Active := False;
end
else
ARecording := False;
if Assigned(FWaveStream) then
FreeAndNil(FWaveStream);
FWaveFile := Value;
if ARecording then
Start;
end;
end;
procedure TRVWaveRecorder.Start;
begin
if Assigned(Microphone) then
begin
PrepareWaveFile;
Microphone.Active := True;
end;
end;
procedure TRVWaveRecorder.Stop;
begin
if Assigned(Microphone) then
begin
Microphone.Active := False;
FWaveStream.Position := 0;
FWaveHeader.RiffLen := FWaveStream.Size - 8;
FWaveStream.WriteBuffer(FWaveHeader, SizeOf(FWaveHeader));
FWaveStream.WriteBuffer(FDataHeader, SizeOf(FDataHeader));
FreeAndNil(FWaveStream);
end;
end;
2、打开 MRVWinMicrophone.pas 文件,打第 2 处补丁:
2.1、找到 RecorderCallBack 函数;
2.2、找到 with 后面的语句,加入对 BufferReady 的调用:
...
with Microphone do
begin
if not Active then
exit;
Microphone.BufferReady(PByte(FWaveHdr.lpData),FWaveHdr.dwBufferLength);//<<<加入这一行
3、OK,现在一切已经就绪,可以创建一个 TRVWaveRecorder 的实例,然后录制音频了。
FWaveRecorder := TRVWaveRecorder.Create; FWaveRecorder.Microphone := mpSource; //开始录制视频 FWaveRecorder.WaveFile:=APath + TempFileName + '.wav'; FWaveRecorder.Start; ... //停止录制视频 FWaveRecorder.Stop;
这样,音频能够捕获,视频也能够抓取,最终也就能形成音频和视频混合的mp4等格式了,具体这里就不再阐述了。
