Refactored ViEFileRecorder.

Types and arguments will be done in a  later CL.

Review URL: http://webrtc-codereview.appspot.com/317008

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1206 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
mflodman@webrtc.org 2011-12-15 15:31:47 +00:00
parent 03c06505fb
commit 091029ba26
2 changed files with 262 additions and 302 deletions

View File

@ -8,274 +8,233 @@
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* vie_file_recorder.cc
*
*/
#include "vie_file_recorder.h"
#include "critical_section_wrapper.h"
#include "trace.h"
#include "tick_util.h"
#include "file_player.h"
#include "file_recorder.h"
#include "vie_defines.h"
#include "video_engine/vie_file_recorder.h"
#include "modules/utility/interface/file_player.h"
#include "modules/utility/interface/file_recorder.h"
#include "system_wrappers/interface/critical_section_wrapper.h"
#include "system_wrappers/interface/tick_util.h"
#include "system_wrappers/interface/trace.h"
#include "video_engine/vie_defines.h"
namespace webrtc {
ViEFileRecorder::ViEFileRecorder(int instanceID)
: _ptrCritSec(CriticalSectionWrapper::CreateCriticalSection()),
_fileRecorder(NULL), _isFirstFrameRecorded(false),
_isOutStreamStarted(false), _instanceID(instanceID), _frameDelay(0),
_audioChannel(-1), _audioSource(NO_AUDIO),
_veFileInterface(NULL)
{
: recorder_cs_(CriticalSectionWrapper::CreateCriticalSection()),
file_recorder_(NULL),
is_first_frame_recorded_(false),
is_out_stream_started_(false),
instance_id_(instanceID),
frame_delay_(0),
audio_channel_(-1),
audio_source_(NO_AUDIO),
voe_file_interface_(NULL) {
}
ViEFileRecorder::~ViEFileRecorder()
{
ViEFileRecorder::~ViEFileRecorder() {
StopRecording();
delete _ptrCritSec;
delete recorder_cs_;
}
int ViEFileRecorder::StartRecording(const char* fileNameUTF8,
const VideoCodec& codecInst,
AudioSource audioSource,
int audioChannel,
const webrtc::CodecInst audioCodecInst,
VoiceEngine* vePtr,
const webrtc::FileFormats fileFormat)
{
CriticalSectionScoped lock(*_ptrCritSec);
int ViEFileRecorder::StartRecording(const char* file_nameUTF8,
const VideoCodec& codec_inst,
AudioSource audio_source,
int audio_channel,
const CodecInst audio_codec_inst,
VoiceEngine* voe_ptr,
const FileFormats file_format) {
CriticalSectionScoped lock(*recorder_cs_);
if (_fileRecorder)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID,
"ViEFileRecorder::StartRecording() failed, already recording.");
if (file_recorder_) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StartRecording() - already recording.");
return -1;
}
_fileRecorder = FileRecorder::CreateFileRecorder(_instanceID, fileFormat);
if (!_fileRecorder)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID,
"ViEFileRecorder::StartRecording() failed to create file recoder.");
file_recorder_ = FileRecorder::CreateFileRecorder(instance_id_, file_format);
if (!file_recorder_) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StartRecording() failed to create recoder.");
return -1;
}
int error = _fileRecorder->StartRecordingVideoFile(fileNameUTF8,
audioCodecInst,
codecInst,
int error = file_recorder_->StartRecordingVideoFile(file_nameUTF8,
audio_codec_inst,
codec_inst,
AMRFileStorage,
audioSource == NO_AUDIO);
if (error)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID,
"ViEFileRecorder::StartRecording() failed to StartRecordingVideoFile.");
FileRecorder::DestroyFileRecorder(_fileRecorder);
_fileRecorder = NULL;
audio_source == NO_AUDIO);
if (error) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StartRecording() failed to "
"StartRecordingVideoFile.");
FileRecorder::DestroyFileRecorder(file_recorder_);
file_recorder_ = NULL;
return -1;
}
_audioSource = audioSource;
if (vePtr && audioSource != NO_AUDIO) // VeInterface have been provided and we want to record audio
{
_veFileInterface = VoEFile::GetInterface(vePtr);
if (!_veFileInterface)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID,
"ViEFileRecorder::StartRecording() failed to get VEFile interface");
audio_source_ = audio_source;
if (voe_ptr && audio_source != NO_AUDIO) {
// VoE interface has been provided and we want to record audio.
voe_file_interface_ = VoEFile::GetInterface(voe_ptr);
if (!voe_file_interface_) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StartRecording() failed to get VEFile "
"interface");
return -1;
}
// always drive VoE in L16
CodecInst engineAudioCodecInst = { 96, // .pltype
"L16", // .plname
audioCodecInst.plfreq, // .plfreq
audioCodecInst.plfreq / 100, // .pacsize (10ms)
1, // .channels
audioCodecInst.plfreq * 16 // .rate
};
switch (audioSource)
{
// Always L16.
CodecInst engine_audio_codec_inst = {96, "L16", audio_codec_inst.plfreq,
audio_codec_inst.plfreq / 100, 1,
audio_codec_inst.plfreq * 16 };
switch (audio_source) {
case MICROPHONE:
error
= _veFileInterface->StartRecordingMicrophone(
this,
&engineAudioCodecInst);
error = voe_file_interface_->StartRecordingMicrophone(
this, &engine_audio_codec_inst);
break;
case PLAYOUT:
error
= _veFileInterface->StartRecordingPlayout(
audioChannel,
this,
&engineAudioCodecInst);
error = voe_file_interface_->StartRecordingPlayout(
audio_channel, this, &engine_audio_codec_inst);
break;
case NO_AUDIO:
break;
default:
assert(!"Unknown audioSource");
assert(!"Unknown audio_source");
}
if (error != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID,
"ViEFileRecorder::StartRecording() failed to start recording audio");
FileRecorder::DestroyFileRecorder(_fileRecorder);
_fileRecorder = NULL;
if (error != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StartRecording() failed to start recording"
" audio");
FileRecorder::DestroyFileRecorder(file_recorder_);
file_recorder_ = NULL;
return -1;
}
_isOutStreamStarted = true;
_audioChannel = audioChannel;
is_out_stream_started_ = true;
audio_channel_ = audio_channel;
}
_isFirstFrameRecorded = false;
is_first_frame_recorded_ = false;
return 0;
}
int ViEFileRecorder::StopRecording()
{
int ViEFileRecorder::StopRecording() {
int error = 0;
// Stop recording audio
// Note - we can not hold the _ptrCritSect while accessing VE functions. It might cause deadlock in Write
if (_veFileInterface)
{
switch (_audioSource)
{
// We can not hold the ptr_cs_ while accessing VoE functions. It might cause
// deadlock in Write.
if (voe_file_interface_) {
switch (audio_source_) {
case MICROPHONE:
error = _veFileInterface->StopRecordingMicrophone();
error = voe_file_interface_->StopRecordingMicrophone();
break;
case PLAYOUT:
error = _veFileInterface->StopRecordingPlayout(_audioChannel);
error = voe_file_interface_->StopRecordingPlayout(audio_channel_);
break;
case NO_AUDIO:
break;
default:
assert(!"Unknown audioSource");
assert(!"Unknown audio_source");
}
if (error != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceID,
"ViEFileRecorder::StopRecording() failed to stop recording audio");
if (error != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StopRecording() failed to stop recording "
"audio");
}
}
CriticalSectionScoped lock(*_ptrCritSec);
if (_veFileInterface)
{
_veFileInterface->Release();
_veFileInterface = NULL;
CriticalSectionScoped lock(*recorder_cs_);
if (voe_file_interface_) {
voe_file_interface_->Release();
voe_file_interface_ = NULL;
}
if (_fileRecorder)
{
if (_fileRecorder->IsRecording())
{
int error = _fileRecorder->StopRecording();
if (error)
{
if (file_recorder_) {
if (file_recorder_->IsRecording()) {
int error = file_recorder_->StopRecording();
if (error) {
return -1;
}
}
FileRecorder::DestroyFileRecorder(_fileRecorder);
_fileRecorder = NULL;
FileRecorder::DestroyFileRecorder(file_recorder_);
file_recorder_ = NULL;
}
_isFirstFrameRecorded = false;
_isOutStreamStarted = false;
is_first_frame_recorded_ = false;
is_out_stream_started_ = false;
return 0;
}
void ViEFileRecorder::SetFrameDelay(int frameDelay)
{
CriticalSectionScoped lock(*_ptrCritSec);
_frameDelay = frameDelay;
void ViEFileRecorder::SetFrameDelay(int frame_delay) {
CriticalSectionScoped lock(*recorder_cs_);
frame_delay_ = frame_delay;
}
bool ViEFileRecorder::RecordingStarted()
{
CriticalSectionScoped lock(*_ptrCritSec);
return _fileRecorder && _fileRecorder->IsRecording();
bool ViEFileRecorder::RecordingStarted() {
CriticalSectionScoped lock(*recorder_cs_);
return file_recorder_ && file_recorder_->IsRecording();
}
bool ViEFileRecorder::FirstFrameRecorded()
{
CriticalSectionScoped lock(*_ptrCritSec);
return _isFirstFrameRecorded;
bool ViEFileRecorder::FirstFrameRecorded() {
CriticalSectionScoped lock(*recorder_cs_);
return is_first_frame_recorded_;
}
bool ViEFileRecorder::IsRecordingFileFormat(const webrtc::FileFormats fileFormat)
{
CriticalSectionScoped lock(*_ptrCritSec);
return (_fileRecorder->RecordingFileFormat() == fileFormat) ? true : false;
bool ViEFileRecorder::IsRecordingFileFormat(const FileFormats file_format) {
CriticalSectionScoped lock(*recorder_cs_);
return (file_recorder_->RecordingFileFormat() == file_format) ? true : false;
}
/*******************************************************************************
* void RecordVideoFrame()
*
* Records incoming decoded video frame to AVI-file.
*
*/
void ViEFileRecorder::RecordVideoFrame(const VideoFrame& videoFrame)
{
CriticalSectionScoped lock(*_ptrCritSec);
void ViEFileRecorder::RecordVideoFrame(const VideoFrame& video_frame) {
CriticalSectionScoped lock(*recorder_cs_);
if (_fileRecorder && _fileRecorder->IsRecording())
{
if (!IsRecordingFileFormat(webrtc::kFileFormatAviFile))
{
if (file_recorder_ && file_recorder_->IsRecording()) {
if (!IsRecordingFileFormat(kFileFormatAviFile))
return;
}
//Compensate for frame delay in order to get audiosync when recording local video.
const WebRtc_UWord32 timeStamp = videoFrame.TimeStamp();
const WebRtc_Word64 renderTimeStamp = videoFrame.RenderTimeMs();
VideoFrame& unconstVideoFrame =
const_cast<VideoFrame&> (videoFrame);
unconstVideoFrame.SetTimeStamp(timeStamp - 90 * _frameDelay);
unconstVideoFrame.SetRenderTime(renderTimeStamp - _frameDelay);
// Compensate for frame delay in order to get audio/video sync when
// recording local video.
const WebRtc_UWord32 time_stamp = video_frame.TimeStamp();
const WebRtc_Word64 render_time_stamp = video_frame.RenderTimeMs();
VideoFrame& unconst_video_frame = const_cast<VideoFrame&>(video_frame);
unconst_video_frame.SetTimeStamp(time_stamp - 90 * frame_delay_);
unconst_video_frame.SetRenderTime(render_time_stamp - frame_delay_);
_fileRecorder->RecordVideoToFile(unconstVideoFrame);
file_recorder_->RecordVideoToFile(unconst_video_frame);
unconstVideoFrame.SetRenderTime(renderTimeStamp);
unconstVideoFrame.SetTimeStamp(timeStamp);
unconst_video_frame.SetRenderTime(render_time_stamp);
unconst_video_frame.SetTimeStamp(time_stamp);
}
}
// ---------------------
// From OutStream
// ---------------------
// 10 ms block of PCM 16
bool ViEFileRecorder::Write(const void* buf, int len)
{
if (!_isOutStreamStarted)
bool ViEFileRecorder::Write(const void* buf, int len) {
if (!is_out_stream_started_)
return true;
// always L16 from VoCE
if (len % (2 * 80)) // 2 bytes 80 samples
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _audioChannel,
// Always 10 ms L16 from VoE.
if (len % (2 * 80)) {
// Not 2 bytes 80 samples.
WEBRTC_TRACE(kTraceError, kTraceVideo, audio_channel_,
"Audio length not supported: %d.", len);
return true;
}
AudioFrame audioFrame;
WebRtc_UWord16 lengthInSamples = len / 2;
audioFrame.UpdateFrame(_audioChannel, 0, (const WebRtc_Word16*) buf,
lengthInSamples, lengthInSamples * 100,
AudioFrame audio_frame;
WebRtc_UWord16 length_in_samples = len / 2;
audio_frame.UpdateFrame(audio_channel_, 0,
static_cast<const WebRtc_Word16*>(buf),
length_in_samples, length_in_samples * 100,
AudioFrame::kUndefined,
AudioFrame::kVadUnknown);
CriticalSectionScoped lock(*_ptrCritSec);
if (_fileRecorder && _fileRecorder->IsRecording())
{
TickTime tickTime = TickTime::Now();
_fileRecorder->RecordAudioToFile(audioFrame, &tickTime);
}
return true; // Always return true!
CriticalSectionScoped lock(*recorder_cs_);
if (file_recorder_ && file_recorder_->IsRecording()) {
TickTime tick_time = TickTime::Now();
file_recorder_->RecordAudioToFile(audio_frame, &tick_time);
}
int ViEFileRecorder::Rewind()
{
// Always return true to continue recording.
return true;
}
int ViEFileRecorder::Rewind() {
// Not supported!
return -1;
}
} // namespace webrtc
} // namespace webrtc

View File

@ -8,57 +8,58 @@
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* vie_file_recorder.h
*/
#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_RECORDER_H_
#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_RECORDER_H_
#ifndef WEBRTC_VIDEO_ENGINE_VIE_FILE_RECORDER_H_
#define WEBRTC_VIDEO_ENGINE_VIE_FILE_RECORDER_H_
#include "modules/utility/interface/file_recorder.h"
#include "typedefs.h"
#include "file_recorder.h"
#include "vie_file.h"
#include "voe_file.h"
#include "video_engine/main/interface/vie_file.h"
#include "voice_engine/main/interface/voe_file.h"
namespace webrtc {
class CriticalSectionWrapper;
class ViEFileRecorder: protected webrtc::OutStream // for audio
{
class ViEFileRecorder : protected OutStream {
public:
ViEFileRecorder(int channelId);
explicit ViEFileRecorder(int channel_id);
~ViEFileRecorder();
int StartRecording(const char* fileNameUTF8,
const webrtc::VideoCodec& codecInst,
AudioSource audioSource, int audioChannel,
const webrtc::CodecInst audioCodecInst,
VoiceEngine* vePtr,
const webrtc::FileFormats fileFormat = webrtc::kFileFormatAviFile);
int StartRecording(const char* file_nameUTF8,
const VideoCodec& codec_inst,
AudioSource audio_source, int audio_channel,
const CodecInst audio_codec_inst,
VoiceEngine* voe_ptr,
const FileFormats file_format = kFileFormatAviFile);
int StopRecording();
void SetFrameDelay(int frameDelay);
void SetFrameDelay(int frame_delay);
bool RecordingStarted();
void RecordVideoFrame(const VideoFrame& videoFrame);
// Records incoming decoded video frame to file.
void RecordVideoFrame(const VideoFrame& video_frame);
protected:
bool FirstFrameRecorded();
bool IsRecordingFileFormat(const webrtc::FileFormats fileFormat);
// From webrtc::OutStream
bool IsRecordingFileFormat(const FileFormats file_format);
// Implements OutStream.
bool Write(const void* buf, int len);
int Rewind();
private:
CriticalSectionWrapper* _ptrCritSec;
CriticalSectionWrapper* recorder_cs_;
FileRecorder* _fileRecorder;
bool _isFirstFrameRecorded;
bool _isOutStreamStarted;
int _instanceID;
int _frameDelay;
int _audioChannel;
AudioSource _audioSource;
VoEFile* _veFileInterface;
FileRecorder* file_recorder_;
bool is_first_frame_recorded_;
bool is_out_stream_started_;
int instance_id_;
int frame_delay_;
int audio_channel_;
AudioSource audio_source_;
VoEFile* voe_file_interface_;
};
} // namespace webrtc
#endif // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_FILE_RECORDER_H_
#endif // WEBRTC_VIDEO_ENGINE_VIE_FILE_RECORDER_H_