webrtc/video_engine/main/source/vie_file_impl.cc

1286 lines
43 KiB
C++

/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* vie_file_impl.cc
*/
#include "vie_file_impl.h"
// Defines
#include "vie_defines.h"
// Includes
#include "condition_variable_wrapper.h"
#include "critical_section_wrapper.h"
#include "jpeg.h"
#include "trace.h"
#include "vie_capturer.h"
#include "vie_channel.h"
#include "vie_channel_manager.h"
#include "vie_encoder.h"
#include "vie_errors.h"
#include "vie_file_image.h"
#include "vie_file_player.h"
#include "vie_file_recorder.h"
#include "vie_impl.h"
#include "vie_input_manager.h"
#include "vie_render_manager.h"
namespace webrtc
{
// ----------------------------------------------------------------------------
// GetInterface
// ----------------------------------------------------------------------------
ViEFile* ViEFile::GetInterface(VideoEngine* videoEngine)
{
#ifdef WEBRTC_VIDEO_ENGINE_FILE_API
if (videoEngine == NULL)
{
return NULL;
}
VideoEngineImpl* vieImpl = reinterpret_cast<VideoEngineImpl*> (videoEngine);
ViEFileImpl* vieFileImpl = vieImpl;
(*vieFileImpl)++; // Increase ref count
return vieFileImpl;
#else
return NULL;
#endif
}
// ----------------------------------------------------------------------------
// Release
//
// Releases the interface, i.e. reduces the reference counter. The number of
// remaining references is returned, -1 if released too many times.
// ----------------------------------------------------------------------------
int ViEFileImpl::Release()
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId,
"ViEFile::Release()");
(*this)--; // Decrease ref count
WebRtc_Word32 refCount = GetCount();
if (refCount < 0)
{
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId,
"ViEFile release too many times");
SetLastError(kViEAPIDoesNotExist);
return -1;
}
WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId,
"ViEFile reference count: %d", refCount);
return refCount;
}
// ----------------------------------------------------------------------------
// Constructor
// ----------------------------------------------------------------------------
ViEFileImpl::ViEFileImpl()
{
WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId,
"ViEFileImpl::ViEFileImpl() Ctor");
}
// ----------------------------------------------------------------------------
// Destructor
// ----------------------------------------------------------------------------
ViEFileImpl::~ViEFileImpl()
{
WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId,
"ViEFileImpl::~ViEFileImpl() Dtor");
}
// ----------------------------------------------------------------------------
// StartPlayFile
// ----------------------------------------------------------------------------
// Play file
int ViEFileImpl::StartPlayFile(const char* fileNameUTF8, int& fileId,
const bool loop /*= false*/,
const webrtc::FileFormats fileFormat
/*= webrtc::kFileFormatAviFile*/)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s",
__FUNCTION__);
if (!IsInitialized())
{
SetLastError(kViENotInitialized);
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s - ViE instance %d not initialized", __FUNCTION__,
_instanceId);
return -1;
}
VoiceEngine* voice = _channelManager.GetVoiceEngine();
const WebRtc_Word32 result = _inputManager.CreateFilePlayer(fileNameUTF8,
loop,
fileFormat,
voice, fileId);
if (result != 0)
{
SetLastError(result);
return -1;
}
return 0;
}
int ViEFileImpl::StopPlayFile(const int fileId)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId),
"%s(fileId: %d)", __FUNCTION__, fileId);
{
ViEInputManagerScoped is(_inputManager);
ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId);
if (ptrViEFilePlayer == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s: File with id %d is not playing.", __FUNCTION__,
fileId);
SetLastError(kViEFileNotPlaying);
return -1;
}
}
// Destroy the capture device
return _inputManager.DestroyFilePlayer(fileId);
}
int ViEFileImpl::RegisterObserver(int fileId, ViEFileObserver& observer)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId),
"%s(fileId: %d)", __FUNCTION__, fileId);
ViEInputManagerScoped is(_inputManager);
ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId);
if (ptrViEFilePlayer == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s: File with id %d is not playing.", __FUNCTION__,
fileId);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (ptrViEFilePlayer->IsObserverRegistered())
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, fileId),
"%s: Observer already registered", __FUNCTION__);
SetLastError(kViEFileObserverAlreadyRegistered);
return -1;
}
if (ptrViEFilePlayer->RegisterObserver(observer) != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, fileId),
"%s: Failed to register observer", __FUNCTION__, fileId);
SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::DeregisterObserver(int fileId, ViEFileObserver& observer)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId),
"%s(fileId: %d)", __FUNCTION__, fileId);
ViEInputManagerScoped is(_inputManager);
ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId);
if (ptrViEFilePlayer == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s: File with id %d is not playing.", __FUNCTION__,
fileId);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (!ptrViEFilePlayer->IsObserverRegistered())
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, fileId), "%s: No Observer registered",
__FUNCTION__);
SetLastError(kViEFileObserverNotRegistered);
return -1;
}
if (ptrViEFilePlayer->DeRegisterObserver() != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, fileId),
"%s: Failed to deregister observer", __FUNCTION__, fileId);
SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::SendFileOnChannel(const int fileId, const int videoChannel)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId),
"%s(fileId: %d)", __FUNCTION__, fileId);
ViEChannelManagerScoped cs(_channelManager);
ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel);
if (ptrViEEncoder == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Channel %d doesn't exist", __FUNCTION__,
videoChannel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEInputManagerScoped is(_inputManager);
if (is.FrameProvider(ptrViEEncoder) != NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Channel %d already connected to a capture device or "
"file.", __FUNCTION__, videoChannel);
SetLastError(kViEFileInputAlreadyConnected);
return -1;
}
ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId);
if (ptrViEFilePlayer == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s: File with id %d is not playing.", __FUNCTION__,
fileId);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (ptrViEFilePlayer->RegisterFrameCallback(videoChannel, ptrViEEncoder)
!= 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s: Failed to register frame callback.", __FUNCTION__,
fileId);
SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::StopSendFileOnChannel(const int videoChannel)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId),
"%s(videoChannel: %d)", __FUNCTION__, videoChannel);
ViEChannelManagerScoped cs(_channelManager);
ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel);
if (ptrViEEncoder == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Channel %d doesn't exist", __FUNCTION__,
videoChannel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEInputManagerScoped is(_inputManager);
ViEFrameProviderBase* frameProvider = is.FrameProvider(ptrViEEncoder);
if (frameProvider == NULL
|| frameProvider->Id() < kViEFileIdBase
|| frameProvider->Id() > kViEFileIdMax)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: No file connected to Channel %d", __FUNCTION__,
videoChannel);
SetLastError(kViEFileNotConnected);
return -1;
}
if (frameProvider->DeregisterFrameCallback(ptrViEEncoder) != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Failed to deregister file from channel %d",
__FUNCTION__, videoChannel);
SetLastError(kViEFileUnknownError);
}
return 0;
}
int ViEFileImpl::StartPlayFileAsMicrophone(const int fileId,
const int audioChannel,
bool mixMicrophone /*= false*/,
float volumeScaling /*= 1*/)
{
ViEInputManagerScoped is(_inputManager);
ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId);
if (ptrViEFilePlayer == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s: File with id %d is not playing.", __FUNCTION__,
fileId);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (ptrViEFilePlayer->SendAudioOnChannel(audioChannel, mixMicrophone,
volumeScaling) != 0)
{
SetLastError(kViEFileVoEFailure);
return -1;
}
return 0;
}
int ViEFileImpl::StopPlayFileAsMicrophone(const int fileId,
const int audioChannel)
{
ViEInputManagerScoped is(_inputManager);
ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId);
if (ptrViEFilePlayer == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s: File with id %d is not playing.", __FUNCTION__,
fileId);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (ptrViEFilePlayer->StopSendAudioOnChannel(audioChannel) != 0)
{
SetLastError(kViEFileVoEFailure);
return -1;
}
return 0;
}
int ViEFileImpl::StartPlayAudioLocally(const int fileId,
const int audioChannel,
float volumeScaling /*=1*/)
{
ViEInputManagerScoped is(_inputManager);
ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId);
if (ptrViEFilePlayer == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s: File with id %d is not playing.", __FUNCTION__,
fileId);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (ptrViEFilePlayer->PlayAudioLocally(audioChannel, volumeScaling) != 0)
{
SetLastError(kViEFileVoEFailure);
return -1;
}
return 0;
}
int ViEFileImpl::StopPlayAudioLocally(const int fileId, const int audioChannel)
{
ViEInputManagerScoped is(_inputManager);
ViEFilePlayer* ptrViEFilePlayer = is.FilePlayer(fileId);
if (ptrViEFilePlayer == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId),
"%s: File with id %d is not playing.", __FUNCTION__,
fileId);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (ptrViEFilePlayer->StopPlayAudioLocally(audioChannel) != 0)
{
SetLastError(kViEFileVoEFailure);
return -1;
}
return 0;
}
// ----------------------------------------------------------------------------
// StartRecordOutgoingVideo
// ----------------------------------------------------------------------------
int ViEFileImpl::StartRecordOutgoingVideo(const int videoChannel,
const char* fileNameUTF8,
AudioSource audioSource,
const webrtc::CodecInst& audioCodec,
const VideoCodec& videoCodec,
const webrtc::FileFormats fileFormat
/*= webrtc::kFileFormatAviFile*/)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s videoChannel: %d)",
__FUNCTION__, videoChannel);
ViEChannelManagerScoped cs(_channelManager);
ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel);
if (ptrViEEncoder == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Channel %d doesn't exist", __FUNCTION__,
videoChannel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& fileRecorder = ptrViEEncoder->GetOutgoingFileRecorder();
if (fileRecorder.RecordingStarted())
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Already recording outgoing video on channel %d",
__FUNCTION__, videoChannel);
SetLastError(kViEFileAlreadyRecording);
return -1;
}
WebRtc_Word32 veChannelId = -1;
VoiceEngine* vePtr = NULL;
if (audioSource != NO_AUDIO)
{
ViEChannel* ptrViEChannel = cs.Channel(videoChannel);
veChannelId = ptrViEChannel->VoiceChannel();
vePtr = _channelManager.GetVoiceEngine();
if (!vePtr)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Can't access voice engine. Have SetVoiceEngine "
"been called?", __FUNCTION__);
SetLastError(kViEFileVoENotSet);
return -1;
}
}
if (fileRecorder.StartRecording(fileNameUTF8, videoCodec, audioSource,
veChannelId, audioCodec, vePtr,
fileFormat) != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Failed to start recording. Check arguments.",
__FUNCTION__);
SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::StopRecordOutgoingVideo(const int videoChannel)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s videoChannel: %d)",
__FUNCTION__, videoChannel);
ViEChannelManagerScoped cs(_channelManager);
ViEEncoder* ptrViEEncoder = cs.Encoder(videoChannel);
if (ptrViEEncoder == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Channel %d doesn't exist", __FUNCTION__,
videoChannel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& fileRecorder = ptrViEEncoder->GetOutgoingFileRecorder();
if (!fileRecorder.RecordingStarted())
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Channel %d is not recording.", __FUNCTION__,
videoChannel);
SetLastError(kViEFileNotRecording);
return -1;
}
if (fileRecorder.StopRecording() != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Failed to stop recording of channel %d.",
__FUNCTION__, videoChannel);
SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::StopRecordIncomingVideo(const int videoChannel)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s videoChannel: %d)",
__FUNCTION__, videoChannel);
ViEChannelManagerScoped cs(_channelManager);
ViEChannel* ptrViEChannel = cs.Channel(videoChannel);
if (ptrViEChannel == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Channel %d doesn't exist", __FUNCTION__,
videoChannel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& fileRecorder = ptrViEChannel->GetIncomingFileRecorder();
if (!fileRecorder.RecordingStarted())
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Channel %d is not recording.", __FUNCTION__,
videoChannel);
SetLastError(kViEFileNotRecording);
ptrViEChannel->ReleaseIncomingFileRecorder();
return -1;
}
if (fileRecorder.StopRecording() != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Failed to stop recording of channel %d.",
__FUNCTION__, videoChannel);
SetLastError(kViEFileUnknownError);
ptrViEChannel->ReleaseIncomingFileRecorder();
return -1;
}
// Let the channel know we are no longer recording
ptrViEChannel->ReleaseIncomingFileRecorder();
return 0;
}
int ViEFileImpl::StartRecordIncomingVideo(const int videoChannel,
const char* fileNameUTF8,
AudioSource audioSource,
const webrtc::CodecInst& audioCodec,
const VideoCodec& videoCodec,
const webrtc::FileFormats fileFormat
/*= webrtc::kFileFormatAviFile*/)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s videoChannel: %d)",
__FUNCTION__, videoChannel);
ViEChannelManagerScoped cs(_channelManager);
ViEChannel* ptrViEChannel = cs.Channel(videoChannel);
if (ptrViEChannel == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Channel %d doesn't exist", __FUNCTION__,
videoChannel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& fileRecorder = ptrViEChannel->GetIncomingFileRecorder();
if (fileRecorder.RecordingStarted())
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Already recording outgoing video on channel %d",
__FUNCTION__, videoChannel);
SetLastError(kViEFileAlreadyRecording);
return -1;
}
WebRtc_Word32 veChannelId = -1;
VoiceEngine* vePtr = NULL;
if (audioSource != NO_AUDIO)
{
veChannelId = ptrViEChannel->VoiceChannel();
vePtr = _channelManager.GetVoiceEngine();
if (!vePtr)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Can't access voice engine. Have SetVoiceEngine "
"been called?", __FUNCTION__);
SetLastError(kViEFileVoENotSet);
return -1;
}
}
if (fileRecorder.StartRecording(fileNameUTF8, videoCodec, audioSource,
veChannelId, audioCodec, vePtr, fileFormat)
!= 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s: Failed to start recording. Check arguments.",
__FUNCTION__);
SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
// ============================================================================
// File information
// ============================================================================
// ----------------------------------------------------------------------------
// GetFileInformation
//
//
// ----------------------------------------------------------------------------
int ViEFileImpl::GetFileInformation(const char* fileName,
VideoCodec& videoCodec,
webrtc::CodecInst& audioCodec,
const webrtc::FileFormats fileFormat
/*= webrtc::kFileFormatAviFile*/)
{
return ViEFilePlayer::GetFileInformation(
_instanceId, (WebRtc_Word8*) fileName,
videoCodec, audioCodec, fileFormat);
}
// ============================================================================
// Snapshot
// ============================================================================
// ----------------------------------------------------------------------------
int ViEFileImpl::GetRenderSnapshot(const int videoChannel,
const char* fileNameUTF8)
{
// gain access to the renderer for the specified channel and get it's
// current frame
ViERenderManagerScoped rs(_renderManager);
ViERenderer* ptrRender = rs.Renderer(videoChannel);
if (!ptrRender)
{
return -1;
}
VideoFrame videoFrame;
if (-1 == ptrRender->GetLastRenderedFrame(videoChannel, videoFrame))
{
return -1;
}
const int JPEG_FORMAT = 0;
int format = JPEG_FORMAT;
switch (format)
{
case JPEG_FORMAT:
{
// *** JPEGEncoder writes the jpeg file for you (no control
// over it) and does not return you the buffer
// *** Thusly, we are not going to be writing to the disk here
JpegEncoder jpegEncoder;
if (-1 == jpegEncoder.SetFileName(fileNameUTF8))
{
// could not set filename for whatever reason
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
"\tCould not open output file '%s' for writing!",
fileNameUTF8);
return -1;
}
if (-1 == jpegEncoder.Encode(videoFrame.Buffer(),
videoFrame.Length(),
videoFrame.Width(),
videoFrame.Height()))
{
// could not encode i420->jpeg
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
"\tCould not encode i420 -> jpeg file '%s' for "
"writing!", fileNameUTF8);
return -1;
}
break;
}
default:
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceFile, _instanceId,
"\tUnsupported file format for %s", __FUNCTION__);
return -1;
break;
}
}
return 0;
}
// ----------------------------------------------------------------------------
//
// GetRenderSnapshot
// ----------------------------------------------------------------------------
int ViEFileImpl::GetRenderSnapshot(const int videoChannel, ViEPicture& picture)
{
// gain access to the renderer for the specified channel and get it's
// current frame
ViERenderManagerScoped rs(_renderManager);
ViERenderer* ptrRender = rs.Renderer(videoChannel);
if (!ptrRender)
{
return -1;
}
VideoFrame videoFrame;
if (-1 == ptrRender->GetLastRenderedFrame(videoChannel, videoFrame))
{
return -1;
}
// copy from VideoFrame class to ViEPicture struct
int bufferLength = (int) (videoFrame.Width() * videoFrame.Height() * 1.5);
picture.data
= (WebRtc_UWord8*) malloc(bufferLength * sizeof(WebRtc_UWord8));
memcpy(picture.data, videoFrame.Buffer(), bufferLength);
picture.size = bufferLength;
picture.width = videoFrame.Width();
picture.height = videoFrame.Height();
picture.type = kVideoI420;
return 0;
}
// ----------------------------------------------------------------------------
//
//
// GetCaptureDeviceSnapshot
// ----------------------------------------------------------------------------
int ViEFileImpl::GetCaptureDeviceSnapshot(const int captureId,
const char* fileNameUTF8)
{
ViEInputManagerScoped is(_inputManager);
ViECapturer* ptrCapture = is.Capture(captureId);
if (!ptrCapture)
{
return -1;
}
VideoFrame videoFrame;
if (GetNextCapturedFrame(captureId, videoFrame) == -1)
{
// Failed to get a snapshot...
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
"Could not gain acces to capture device %d video frame "
"%s:%d", captureId, __FUNCTION__);
return -1;
}
const int JPEG_FORMAT = 0;
int format = JPEG_FORMAT;
switch (format)
{
case JPEG_FORMAT:
{
// *** JPEGEncoder writes the jpeg file for you (no control
// over it) and does not return you the buffer
// *** Thusly, we are not going to be writing to the disk here
JpegEncoder jpegEncoder;
if (-1 == jpegEncoder.SetFileName(fileNameUTF8))
{
// could not set filename for whatever reason
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
"\tCould not open output file '%s' for writing!",
fileNameUTF8);
return -1;
}
if (-1 == jpegEncoder.Encode(videoFrame.Buffer(),
videoFrame.Length(),
videoFrame.Width(),
videoFrame.Height()))
{
// could not encode i420->jpeg
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
"\tCould not encode i420 -> jpeg file '%s' for "
"writing!", fileNameUTF8);
return -1;
}
break;
}
default:
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceFile, _instanceId,
"\tUnsupported file format for %s", __FUNCTION__);
return -1;
break;
}
}
return 0;
}
// ----------------------------------------------------------------------------
//
//
// GetCaptureDeviceSnapshot
// ----------------------------------------------------------------------------
int ViEFileImpl::GetCaptureDeviceSnapshot(const int captureId,
ViEPicture& picture)
{
VideoFrame videoFrame;
ViEInputManagerScoped is(_inputManager);
ViECapturer* ptrCapture = is.Capture(captureId);
if (!ptrCapture)
{
return -1;
}
if (GetNextCapturedFrame(captureId, videoFrame) == -1)
{
// Failed to get a snapshot...
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, _instanceId,
"Could not gain acces to capture device %d video frame "
"%s:%d", captureId, __FUNCTION__);
return -1;
}
// copy from VideoFrame class to ViEPicture struct
int bufferLength = (int) (videoFrame.Width() * videoFrame.Height() * 1.5);
picture.data
= (WebRtc_UWord8*) malloc(bufferLength * sizeof(WebRtc_UWord8));
memcpy(picture.data, videoFrame.Buffer(), bufferLength);
picture.size = bufferLength;
picture.width = videoFrame.Width();
picture.height = videoFrame.Height();
picture.type = kVideoI420;
return 0;
}
// ----------------------------------------------------------------------------
//
//
// FreePicture
// ----------------------------------------------------------------------------
int ViEFileImpl::FreePicture(ViEPicture& picture)
{
if (picture.data)
free(picture.data);
picture.data = NULL;
picture.size = 0;
picture.width = 0;
picture.height = 0;
picture.type = kVideoUnknown;
return 0;
}
// ============================================================================
// Capture device images
// ============================================================================
// ----------------------------------------------------------------------------
//
//
// SetCaptureDeviceImage
// ----------------------------------------------------------------------------
int ViEFileImpl::SetCaptureDeviceImage(const int captureId,
const char* fileNameUTF8)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId,
"%s(captureId: %d)", __FUNCTION__, captureId);
ViEInputManagerScoped is(_inputManager);
ViECapturer* ptrCapture = is.Capture(captureId);
if (!ptrCapture)
{
SetLastError(kViEFileInvalidCaptureId);
return -1;
}
VideoFrame captureImage;
if (ViEFileImage::ConvertJPEGToVideoFrame(
ViEId(_instanceId, captureId), fileNameUTF8, captureImage) != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, captureId),
"%s(captureId: %d) Failed to open file.", __FUNCTION__,
captureId);
SetLastError(kViEFileInvalidFile);
return -1;
}
if (ptrCapture->SetCaptureDeviceImage(captureImage))
{
SetLastError(kViEFileSetCaptureImageError);
return -1;
}
return 0;
}
// ----------------------------------------------------------------------------
//
//
// SetCaptureDeviceImage
// ----------------------------------------------------------------------------
int ViEFileImpl::SetCaptureDeviceImage(const int captureId,
const ViEPicture& picture)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId,
"%s(captureId: %d)", __FUNCTION__, captureId);
if (picture.type != kVideoI420)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, captureId),
"%s(captureId: %d) Not a valid picture type.",
__FUNCTION__, captureId);
SetLastError(kViEFileInvalidArgument);
return -1;
}
ViEInputManagerScoped is(_inputManager);
ViECapturer* ptrCapture = is.Capture(captureId);
if (!ptrCapture)
{
SetLastError(kViEFileSetCaptureImageError);
return -1;
}
VideoFrame captureImage;
if (ViEFileImage::ConvertPictureToVideoFrame(
ViEId(_instanceId,captureId), picture, captureImage) != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, captureId),
"%s(captureId: %d) Failed to use picture.", __FUNCTION__,
captureId);
SetLastError(kViEFileInvalidFile);
return -1;
}
if (ptrCapture->SetCaptureDeviceImage(captureImage))
{
SetLastError(kViEFileInvalidCapture);
return -1;
}
return 0;
}
// ============================================================================
// Render images
// ============================================================================
// ----------------------------------------------------------------------------
//
//
// SetRenderStartImage
// ----------------------------------------------------------------------------
int ViEFileImpl::SetRenderStartImage(const int videoChannel,
const char* fileNameUTF8)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)",
__FUNCTION__, videoChannel);
ViERenderManagerScoped rs(_renderManager);
ViERenderer* ptrRender = rs.Renderer(videoChannel);
if (!ptrRender)
{
SetLastError(kViEFileInvalidRenderId);
return -1;
}
VideoFrame startImage;
if (ViEFileImage::ConvertJPEGToVideoFrame(
ViEId(_instanceId, videoChannel), fileNameUTF8, startImage) != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s(videoChannel: %d) Failed to open file.", __FUNCTION__,
videoChannel);
SetLastError(kViEFileInvalidFile);
return -1;
}
if (ptrRender->SetRenderStartImage(startImage) != 0)
{
SetLastError(kViEFileSetStartImageError);
return -1;
}
return 0;
}
// ----------------------------------------------------------------------------
//
//
// SetRenderStartImage
// ----------------------------------------------------------------------------
int ViEFileImpl::SetRenderStartImage(const int videoChannel,
const ViEPicture& picture)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)",
__FUNCTION__, videoChannel);
if (picture.type != kVideoI420)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s(videoChannel: %d) Not a valid picture type.",
__FUNCTION__, videoChannel);
SetLastError(kViEFileInvalidArgument);
return -1;
}
ViERenderManagerScoped rs(_renderManager);
ViERenderer* ptrRender = rs.Renderer(videoChannel);
if (!ptrRender)
{
SetLastError(kViEFileInvalidRenderId);
return -1;
}
VideoFrame startImage;
if (ViEFileImage::ConvertPictureToVideoFrame(
ViEId(_instanceId, videoChannel), picture, startImage) != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s(videoChannel: %d) Failed to use picture.",
__FUNCTION__, videoChannel);
SetLastError(kViEFileInvalidCapture);
return -1;
}
if (ptrRender->SetRenderStartImage(startImage) != 0)
{
SetLastError(kViEFileSetStartImageError);
return -1;
}
return 0;
}
// ============================================================================
// Timeout image
// ============================================================================
// ----------------------------------------------------------------------------
//
//
// SetRenderTimeoutImage
// ----------------------------------------------------------------------------
int ViEFileImpl::SetRenderTimeoutImage(const int videoChannel,
const char* fileNameUTF8,
const unsigned int timeoutMs)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)",
__FUNCTION__, videoChannel);
ViERenderManagerScoped rs(_renderManager);
ViERenderer* ptrRender = rs.Renderer(videoChannel);
if (!ptrRender)
{
SetLastError(kViEFileInvalidRenderId);
return -1;
}
VideoFrame timeoutImage;
if (ViEFileImage::ConvertJPEGToVideoFrame(
ViEId(_instanceId,videoChannel), fileNameUTF8, timeoutImage) != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s(videoChannel: %d) Failed to open file.", __FUNCTION__,
videoChannel);
SetLastError(kViEFileInvalidFile);
return -1;
}
WebRtc_Word32 timeoutTime = timeoutMs;
if (timeoutMs < kViEMinRenderTimeoutTimeMs)
{
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s(videoChannel: %d) Invalid timeoutMs, using %d.",
__FUNCTION__, videoChannel, kViEMinRenderTimeoutTimeMs);
timeoutTime = kViEMinRenderTimeoutTimeMs;
}
if (timeoutMs > kViEMaxRenderTimeoutTimeMs)
{
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s(videoChannel: %d) Invalid timeoutMs, using %d.",
__FUNCTION__, videoChannel, kViEMaxRenderTimeoutTimeMs);
timeoutTime = kViEMaxRenderTimeoutTimeMs;
}
if (ptrRender->SetTimeoutImage(timeoutImage, timeoutTime) != 0)
{
SetLastError(kViEFileSetRenderTimeoutError);
return -1;
}
return 0;
}
int ViEFileImpl::SetRenderTimeoutImage(const int videoChannel,
const ViEPicture& picture,
const unsigned int timeoutMs)
{
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)",
__FUNCTION__, videoChannel);
if (picture.type != kVideoI420)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s(videoChannel: %d) Not a valid picture type.",
__FUNCTION__, videoChannel);
SetLastError(kViEFileInvalidArgument);
return -1;
}
ViERenderManagerScoped rs(_renderManager);
ViERenderer* ptrRender = rs.Renderer(videoChannel);
if (!ptrRender)
{
SetLastError(kViEFileSetRenderTimeoutError);
return -1;
}
VideoFrame timeoutImage;
if (ViEFileImage::ConvertPictureToVideoFrame(
ViEId(_instanceId, videoChannel), picture, timeoutImage) != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s(videoChannel: %d) Failed to use picture.",
__FUNCTION__, videoChannel);
SetLastError(kViEFileInvalidCapture);
return -1;
}
WebRtc_Word32 timeoutTime = timeoutMs;
if (timeoutMs < kViEMinRenderTimeoutTimeMs)
{
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s(videoChannel: %d) Invalid timeoutMs, using %d.",
__FUNCTION__, videoChannel, kViEMinRenderTimeoutTimeMs);
timeoutTime = kViEMinRenderTimeoutTimeMs;
}
if (timeoutMs > kViEMaxRenderTimeoutTimeMs)
{
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s(videoChannel: %d) Invalid timeoutMs, using %d.",
__FUNCTION__, videoChannel, kViEMaxRenderTimeoutTimeMs);
timeoutTime = kViEMaxRenderTimeoutTimeMs;
}
if (ptrRender->SetTimeoutImage(timeoutImage, timeoutTime) != 0)
{
SetLastError(kViEFileSetRenderTimeoutError);
return -1;
}
return 0;
}
WebRtc_Word32 ViEFileImpl::GetNextCapturedFrame(WebRtc_Word32 captureId,
VideoFrame& videoFrame)
{
ViEInputManagerScoped is(_inputManager);
ViECapturer* ptrCapture = is.Capture(captureId);
if (!ptrCapture)
{
return -1;
}
ViECaptureSnapshot* snapShot = new ViECaptureSnapshot();
ptrCapture->RegisterFrameCallback(-1, snapShot);
bool snapshotTaken =
snapShot->GetSnapshot(videoFrame, kViECaptureMaxSnapshotWaitTimeMs);
// Check once again if it has been destroyed...
ptrCapture->DeregisterFrameCallback(snapShot);
delete snapShot;
snapShot = NULL;
if (snapshotTaken)
{
return 0;
}
return -1;
}
ViECaptureSnapshot::ViECaptureSnapshot() :
_crit(*CriticalSectionWrapper::CreateCriticalSection()),
_conditionVaraible(*ConditionVariableWrapper::CreateConditionVariable()),
_ptrVideoFrame(NULL)
{
}
ViECaptureSnapshot::~ViECaptureSnapshot()
{
_crit.Enter();
_crit.Leave();
delete &_crit;
if (_ptrVideoFrame)
{
delete _ptrVideoFrame;
_ptrVideoFrame = NULL;
}
}
bool ViECaptureSnapshot::GetSnapshot(VideoFrame& videoFrame,
unsigned int maxWaitTime)
{
_crit.Enter();
_ptrVideoFrame = new VideoFrame();
if (_conditionVaraible.SleepCS(_crit, maxWaitTime))
{
// Snapshot taken
videoFrame.SwapFrame(*_ptrVideoFrame);
delete _ptrVideoFrame;
_ptrVideoFrame = NULL;
_crit.Leave();
return true;
}
return false;
}
void ViECaptureSnapshot::DeliverFrame(int id, VideoFrame& videoFrame,
int numCSRCs,
const WebRtc_UWord32 CSRC[kRtpCsrcSize])
{
CriticalSectionScoped cs(_crit);
if (!_ptrVideoFrame)
{
return;
}
_ptrVideoFrame->SwapFrame(videoFrame);
_conditionVaraible.WakeAll();
return;
}
} // namespace webrtc