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