好吧,声明一下,本文需要修改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等格式了,具体这里就不再阐述了。