blob: 28f98544a1ad4836de550f523f45ac6f5fdabf34 [file] [log] [blame]
/*
* Copyright (c) 2012 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.
*/
#include "engine_configurations.h"
#include "video_engine/vie_file_impl.h"
#ifdef WEBRTC_VIDEO_ENGINE_FILE_API
#include "common_video/jpeg/include/jpeg.h"
#include "system_wrappers/interface/condition_variable_wrapper.h"
#include "system_wrappers/interface/critical_section_wrapper.h"
#include "system_wrappers/interface/trace.h"
#include "video_engine/include/vie_errors.h"
#include "video_engine/vie_capturer.h"
#include "video_engine/vie_channel.h"
#include "video_engine/vie_channel_manager.h"
#include "video_engine/vie_defines.h"
#include "video_engine/vie_encoder.h"
#include "video_engine/vie_file_image.h"
#include "video_engine/vie_file_player.h"
#include "video_engine/vie_file_recorder.h"
#include "video_engine/vie_impl.h"
#include "video_engine/vie_input_manager.h"
#include "video_engine/vie_render_manager.h"
#include "video_engine/vie_renderer.h"
#endif
namespace webrtc {
ViEFile* ViEFile::GetInterface(VideoEngine* video_engine) {
#ifdef WEBRTC_VIDEO_ENGINE_FILE_API
if (!video_engine) {
return NULL;
}
VideoEngineImpl* vie_impl = reinterpret_cast<VideoEngineImpl*>(video_engine);
ViEFileImpl* vie_file_impl = vie_impl;
// Increase ref count.
(*vie_file_impl)++;
return vie_file_impl;
#else
return NULL;
#endif
}
#ifdef WEBRTC_VIDEO_ENGINE_FILE_API
int ViEFileImpl::Release() {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_->instance_id(),
"ViEFile::Release()");
// Decrease ref count.
(*this)--;
WebRtc_Word32 ref_count = GetCount();
if (ref_count < 0) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo, shared_data_->instance_id(),
"ViEFile release too many times");
shared_data_->SetLastError(kViEAPIDoesNotExist);
return -1;
}
WEBRTC_TRACE(kTraceInfo, kTraceVideo, shared_data_->instance_id(),
"ViEFile reference count: %d", ref_count);
return ref_count;
}
ViEFileImpl::ViEFileImpl(ViESharedData* shared_data)
: shared_data_(shared_data) {
WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_->instance_id(),
"ViEFileImpl::ViEFileImpl() Ctor");
}
ViEFileImpl::~ViEFileImpl() {
WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_->instance_id(),
"ViEFileImpl::~ViEFileImpl() Dtor");
}
int ViEFileImpl::StartPlayFile(const char* file_nameUTF8,
int& file_id,
const bool loop,
const FileFormats file_format) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s", __FUNCTION__);
if (!shared_data_->Initialized()) {
shared_data_->SetLastError(kViENotInitialized);
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s - ViE instance %d not initialized", __FUNCTION__,
shared_data_->instance_id());
return -1;
}
VoiceEngine* voice = shared_data_->channel_manager()->GetVoiceEngine();
const WebRtc_Word32 result = shared_data_->input_manager()->CreateFilePlayer(
file_nameUTF8, loop, file_format, voice, file_id);
if (result != 0) {
shared_data_->SetLastError(result);
return -1;
}
return 0;
}
int ViEFileImpl::StopPlayFile(const int file_id) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s(file_id: %d)", __FUNCTION__, file_id);
{
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
shared_data_->SetLastError(kViEFileNotPlaying);
return -1;
}
}
// Destroy the capture device.
return shared_data_->input_manager()->DestroyFilePlayer(file_id);
}
int ViEFileImpl::RegisterObserver(int file_id, ViEFileObserver& observer) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s(file_id: %d)", __FUNCTION__, file_id);
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
shared_data_->SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->IsObserverRegistered()) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), file_id),
"%s: Observer already registered", __FUNCTION__);
shared_data_->SetLastError(kViEFileObserverAlreadyRegistered);
return -1;
}
if (vie_file_player->RegisterObserver(observer) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), file_id),
"%s: Failed to register observer", __FUNCTION__, file_id);
shared_data_->SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::DeregisterObserver(int file_id, ViEFileObserver& observer) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s(file_id: %d)", __FUNCTION__, file_id);
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
shared_data_->SetLastError(kViEFileNotPlaying);
return -1;
}
if (!vie_file_player->IsObserverRegistered()) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), file_id),
"%s: No Observer registered", __FUNCTION__);
shared_data_->SetLastError(kViEFileObserverNotRegistered);
return -1;
}
if (vie_file_player->DeRegisterObserver() != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), file_id),
"%s: Failed to deregister observer", __FUNCTION__, file_id);
shared_data_->SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::SendFileOnChannel(const int file_id, const int video_channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s(file_id: %d)", __FUNCTION__, file_id);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEInputManagerScoped is(*(shared_data_->input_manager()));
if (is.FrameProvider(vie_encoder) != NULL) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Channel %d already connected to a capture device or "
"file.", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileInputAlreadyConnected);
return -1;
}
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
shared_data_->SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->RegisterFrameCallback(video_channel, vie_encoder)
!= 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s: Failed to register frame callback.", __FUNCTION__,
file_id);
shared_data_->SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::StopSendFileOnChannel(const int video_channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViEFrameProviderBase* frame_provider = is.FrameProvider(vie_encoder);
if (!frame_provider ||
frame_provider->Id() < kViEFileIdBase ||
frame_provider->Id() > kViEFileIdMax) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No file connected to Channel %d", __FUNCTION__,
video_channel);
shared_data_->SetLastError(kViEFileNotConnected);
return -1;
}
if (frame_provider->DeregisterFrameCallback(vie_encoder) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Failed to deregister file from channel %d",
__FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileUnknownError);
}
return 0;
}
int ViEFileImpl::StartPlayFileAsMicrophone(const int file_id,
const int audio_channel,
bool mix_microphone,
float volume_scaling) {
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
shared_data_->SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->SendAudioOnChannel(audio_channel, mix_microphone,
volume_scaling) != 0) {
shared_data_->SetLastError(kViEFileVoEFailure);
return -1;
}
return 0;
}
int ViEFileImpl::StopPlayFileAsMicrophone(const int file_id,
const int audio_channel) {
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
shared_data_->SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->StopSendAudioOnChannel(audio_channel) != 0) {
shared_data_->SetLastError(kViEFileVoEFailure);
return -1;
}
return 0;
}
int ViEFileImpl::StartPlayAudioLocally(const int file_id,
const int audio_channel,
float volume_scaling) {
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
shared_data_->SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->PlayAudioLocally(audio_channel, volume_scaling) != 0) {
shared_data_->SetLastError(kViEFileVoEFailure);
return -1;
}
return 0;
}
int ViEFileImpl::StopPlayAudioLocally(const int file_id,
const int audio_channel) {
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
shared_data_->SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->StopPlayAudioLocally(audio_channel) != 0) {
shared_data_->SetLastError(kViEFileVoEFailure);
return -1;
}
return 0;
}
int ViEFileImpl::StartRecordOutgoingVideo(const int video_channel,
const char* file_nameUTF8,
AudioSource audio_source,
const CodecInst& audio_codec,
const VideoCodec& video_codec,
const FileFormats file_format) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& file_recorder = vie_encoder->GetOutgoingFileRecorder();
if (file_recorder.RecordingStarted()) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Already recording outgoing video on channel %d",
__FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileAlreadyRecording);
return -1;
}
WebRtc_Word32 ve_channel_id = -1;
VoiceEngine* ve_ptr = NULL;
if (audio_source != NO_AUDIO) {
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
// Channel should exists since we have a ViEEncoder above.
assert(false);
return -1;
}
ve_channel_id = vie_channel->VoiceChannel();
ve_ptr = shared_data_->channel_manager()->GetVoiceEngine();
if (!ve_ptr) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Can't access voice engine. Have SetVoiceEngine "
"been called?", __FUNCTION__);
shared_data_->SetLastError(kViEFileVoENotSet);
return -1;
}
}
if (file_recorder.StartRecording(file_nameUTF8, video_codec, audio_source,
ve_channel_id, audio_codec, ve_ptr,
file_format) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Failed to start recording. Check arguments.",
__FUNCTION__);
shared_data_->SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::StopRecordOutgoingVideo(const int video_channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& file_recorder = vie_encoder->GetOutgoingFileRecorder();
if (!file_recorder.RecordingStarted()) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Channel %d is not recording.", __FUNCTION__,
video_channel);
shared_data_->SetLastError(kViEFileNotRecording);
return -1;
}
if (file_recorder.StopRecording() != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Failed to stop recording of channel %d.", __FUNCTION__,
video_channel);
shared_data_->SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::StopRecordIncomingVideo(const int video_channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& file_recorder = vie_channel->GetIncomingFileRecorder();
if (!file_recorder.RecordingStarted()) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Channel %d is not recording.", __FUNCTION__,
video_channel);
shared_data_->SetLastError(kViEFileNotRecording);
vie_channel->ReleaseIncomingFileRecorder();
return -1;
}
if (file_recorder.StopRecording() != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Failed to stop recording of channel %d.",
__FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileUnknownError);
vie_channel->ReleaseIncomingFileRecorder();
return -1;
}
// Let the channel know we are no longer recording.
vie_channel->ReleaseIncomingFileRecorder();
return 0;
}
int ViEFileImpl::StartRecordIncomingVideo(const int video_channel,
const char* file_nameUTF8,
AudioSource audio_source,
const CodecInst& audio_codec,
const VideoCodec& video_codec,
const FileFormats file_format) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__,
video_channel);
shared_data_->SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& file_recorder = vie_channel->GetIncomingFileRecorder();
if (file_recorder.RecordingStarted()) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Already recording outgoing video on channel %d",
__FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileAlreadyRecording);
return -1;
}
WebRtc_Word32 ve_channel_id = -1;
VoiceEngine* ve_ptr = NULL;
if (audio_source != NO_AUDIO) {
ve_channel_id = vie_channel->VoiceChannel();
ve_ptr = shared_data_->channel_manager()->GetVoiceEngine();
if (!ve_ptr) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Can't access voice engine. Have SetVoiceEngine "
"been called?", __FUNCTION__);
shared_data_->SetLastError(kViEFileVoENotSet);
return -1;
}
}
if (file_recorder.StartRecording(file_nameUTF8, video_codec, audio_source,
ve_channel_id, audio_codec, ve_ptr,
file_format) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Failed to start recording. Check arguments.",
__FUNCTION__);
shared_data_->SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::GetFileInformation(const char* file_name,
VideoCodec& video_codec,
CodecInst& audio_codec,
const FileFormats file_format) {
return ViEFilePlayer::GetFileInformation(
shared_data_->instance_id(),
static_cast<const WebRtc_Word8*>(file_name),
video_codec, audio_codec, file_format);
}
int ViEFileImpl::GetRenderSnapshot(const int video_channel,
const char* file_nameUTF8) {
// Gain access to the renderer for the specified channel and get it's
// current frame.
ViERenderManagerScoped rs(*(shared_data_->render_manager()));
ViERenderer* renderer = rs.Renderer(video_channel);
if (!renderer) {
return -1;
}
VideoFrame video_frame;
if (renderer->GetLastRenderedFrame(video_channel, video_frame) == -1) {
return -1;
}
// JPEGEncoder writes the jpeg file for you (no control over it) and does
// not return you the buffer. Thus, we are not going to be writing to the
// disk here.
JpegEncoder jpeg_encoder;
RawImage input_image;
if (jpeg_encoder.SetFileName(file_nameUTF8) == -1) {
WEBRTC_TRACE(kTraceError, kTraceVideo, shared_data_->instance_id(),
"\tCould not open output file '%s' for writing!",
file_nameUTF8);
return -1;
}
input_image._width = video_frame.Width();
input_image._height = video_frame.Height();
video_frame.Swap(input_image._buffer, input_image._length,
input_image._size);
if (jpeg_encoder.Encode(input_image) == -1) {
WEBRTC_TRACE(kTraceError, kTraceVideo, shared_data_->instance_id(),
"\tCould not encode i420 -> jpeg file '%s' for writing!",
file_nameUTF8);
if (input_image._buffer) {
delete [] input_image._buffer;
input_image._buffer = NULL;
}
return -1;
}
delete [] input_image._buffer;
input_image._buffer = NULL;
return 0;
}
int ViEFileImpl::GetRenderSnapshot(const int video_channel,
ViEPicture& picture) {
// Gain access to the renderer for the specified channel and get it's
// current frame.
ViERenderManagerScoped rs(*(shared_data_->render_manager()));
ViERenderer* renderer = rs.Renderer(video_channel);
if (!renderer) {
return -1;
}
VideoFrame video_frame;
if (renderer->GetLastRenderedFrame(video_channel, video_frame) == -1) {
return -1;
}
// Copy from VideoFrame class to ViEPicture struct.
int buffer_length =
static_cast<int>(video_frame.Width() * video_frame.Height() * 1.5);
picture.data = static_cast<WebRtc_UWord8*>(malloc(
buffer_length * sizeof(WebRtc_UWord8)));
memcpy(picture.data, video_frame.Buffer(), buffer_length);
picture.size = buffer_length;
picture.width = video_frame.Width();
picture.height = video_frame.Height();
picture.type = kVideoI420;
return 0;
}
int ViEFileImpl::GetCaptureDeviceSnapshot(const int capture_id,
const char* file_nameUTF8) {
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViECapturer* capturer = is.Capture(capture_id);
if (!capturer) {
return -1;
}
VideoFrame video_frame;
if (GetNextCapturedFrame(capture_id, video_frame) == -1) {
WEBRTC_TRACE(kTraceError, kTraceVideo, shared_data_->instance_id(),
"Could not gain acces to capture device %d video frame "
"%s:%d", capture_id, __FUNCTION__);
return -1;
}
// 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 jpeg_encoder;
RawImage input_image;
input_image._width = video_frame.Width();
input_image._height = video_frame.Height();
video_frame.Swap(input_image._buffer, input_image._length,
input_image._size);
if (jpeg_encoder.SetFileName(file_nameUTF8) == -1) {
WEBRTC_TRACE(kTraceError, kTraceVideo, shared_data_->instance_id(),
"\tCould not open output file '%s' for writing!",
file_nameUTF8);
if (input_image._buffer) {
delete [] input_image._buffer;
}
return -1;
}
if (jpeg_encoder.Encode(input_image) == -1) {
WEBRTC_TRACE(kTraceError, kTraceVideo, shared_data_->instance_id(),
"\tCould not encode i420 -> jpeg file '%s' for "
"writing!", file_nameUTF8);
if (input_image._buffer) {
delete [] input_image._buffer;
}
return -1;
}
delete [] input_image._buffer;
input_image._buffer = NULL;
return 0;
}
int ViEFileImpl::GetCaptureDeviceSnapshot(const int capture_id,
ViEPicture& picture) {
VideoFrame video_frame;
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViECapturer* capturer = is.Capture(capture_id);
if (!capturer) {
return -1;
}
if (GetNextCapturedFrame(capture_id, video_frame) == -1) {
WEBRTC_TRACE(kTraceError, kTraceVideo, shared_data_->instance_id(),
"Could not gain acces to capture device %d video frame "
"%s:%d", capture_id, __FUNCTION__);
return -1;
}
// Copy from VideoFrame class to ViEPicture struct.
int buffer_length =
static_cast<int>(video_frame.Width() * video_frame.Height() * 1.5);
picture.data = static_cast<WebRtc_UWord8*>(malloc(
buffer_length * sizeof(WebRtc_UWord8)));
memcpy(picture.data, video_frame.Buffer(), buffer_length);
picture.size = buffer_length;
picture.width = video_frame.Width();
picture.height = video_frame.Height();
picture.type = kVideoI420;
return 0;
}
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;
}
int ViEFileImpl::SetCaptureDeviceImage(const int capture_id,
const char* file_nameUTF8) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_->instance_id(),
"%s(capture_id: %d)", __FUNCTION__, capture_id);
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViECapturer* capturer = is.Capture(capture_id);
if (!capturer) {
shared_data_->SetLastError(kViEFileInvalidCaptureId);
return -1;
}
VideoFrame capture_image;
if (ViEFileImage::ConvertJPEGToVideoFrame(
ViEId(shared_data_->instance_id(), capture_id), file_nameUTF8,
capture_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), capture_id),
"%s(capture_id: %d) Failed to open file.", __FUNCTION__,
capture_id);
shared_data_->SetLastError(kViEFileInvalidFile);
return -1;
}
if (capturer->SetCaptureDeviceImage(capture_image)) {
shared_data_->SetLastError(kViEFileSetCaptureImageError);
return -1;
}
return 0;
}
int ViEFileImpl::SetCaptureDeviceImage(const int capture_id,
const ViEPicture& picture) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_->instance_id(),
"%s(capture_id: %d)", __FUNCTION__, capture_id);
if (picture.type != kVideoI420) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), capture_id),
"%s(capture_id: %d) Not a valid picture type.",
__FUNCTION__, capture_id);
shared_data_->SetLastError(kViEFileInvalidArgument);
return -1;
}
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViECapturer* capturer = is.Capture(capture_id);
if (!capturer) {
shared_data_->SetLastError(kViEFileSetCaptureImageError);
return -1;
}
VideoFrame capture_image;
if (ViEFileImage::ConvertPictureToVideoFrame(
ViEId(shared_data_->instance_id(), capture_id), picture, capture_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), capture_id),
"%s(capture_id: %d) Failed to use picture.", __FUNCTION__,
capture_id);
shared_data_->SetLastError(kViEFileInvalidFile);
return -1;
}
if (capturer->SetCaptureDeviceImage(capture_image)) {
shared_data_->SetLastError(kViEFileInvalidCapture);
return -1;
}
return 0;
}
int ViEFileImpl::SetRenderStartImage(const int video_channel,
const char* file_nameUTF8) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
ViERenderManagerScoped rs(*(shared_data_->render_manager()));
ViERenderer* renderer = rs.Renderer(video_channel);
if (!renderer) {
shared_data_->SetLastError(kViEFileInvalidRenderId);
return -1;
}
VideoFrame start_image;
if (ViEFileImage::ConvertJPEGToVideoFrame(
ViEId(shared_data_->instance_id(), video_channel), file_nameUTF8, start_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d) Failed to open file.", __FUNCTION__,
video_channel);
shared_data_->SetLastError(kViEFileInvalidFile);
return -1;
}
if (renderer->SetRenderStartImage(start_image) != 0) {
shared_data_->SetLastError(kViEFileSetStartImageError);
return -1;
}
return 0;
}
int ViEFileImpl::SetRenderStartImage(const int video_channel,
const ViEPicture& picture) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
if (picture.type != kVideoI420) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d) Not a valid picture type.",
__FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileInvalidArgument);
return -1;
}
ViERenderManagerScoped rs(*(shared_data_->render_manager()));
ViERenderer* renderer = rs.Renderer(video_channel);
if (!renderer) {
shared_data_->SetLastError(kViEFileInvalidRenderId);
return -1;
}
VideoFrame start_image;
if (ViEFileImage::ConvertPictureToVideoFrame(
ViEId(shared_data_->instance_id(), video_channel), picture, start_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d) Failed to use picture.",
__FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileInvalidCapture);
return -1;
}
if (renderer->SetRenderStartImage(start_image) != 0) {
shared_data_->SetLastError(kViEFileSetStartImageError);
return -1;
}
return 0;
}
int ViEFileImpl::SetRenderTimeoutImage(const int video_channel,
const char* file_nameUTF8,
const unsigned int timeout_ms) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
ViERenderManagerScoped rs(*(shared_data_->render_manager()));
ViERenderer* renderer = rs.Renderer(video_channel);
if (!renderer) {
shared_data_->SetLastError(kViEFileInvalidRenderId);
return -1;
}
VideoFrame timeout_image;
if (ViEFileImage::ConvertJPEGToVideoFrame(
ViEId(shared_data_->instance_id(), video_channel), file_nameUTF8,
timeout_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d) Failed to open file.", __FUNCTION__,
video_channel);
shared_data_->SetLastError(kViEFileInvalidFile);
return -1;
}
WebRtc_Word32 timeout_time = timeout_ms;
if (timeout_ms < kViEMinRenderTimeoutTimeMs) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d) Invalid timeout_ms, using %d.",
__FUNCTION__, video_channel, kViEMinRenderTimeoutTimeMs);
timeout_time = kViEMinRenderTimeoutTimeMs;
}
if (timeout_ms > kViEMaxRenderTimeoutTimeMs) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d) Invalid timeout_ms, using %d.",
__FUNCTION__, video_channel, kViEMaxRenderTimeoutTimeMs);
timeout_time = kViEMaxRenderTimeoutTimeMs;
}
if (renderer->SetTimeoutImage(timeout_image, timeout_time) != 0) {
shared_data_->SetLastError(kViEFileSetRenderTimeoutError);
return -1;
}
return 0;
}
int ViEFileImpl::SetRenderTimeoutImage(const int video_channel,
const ViEPicture& picture,
const unsigned int timeout_ms) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
if (picture.type != kVideoI420) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d) Not a valid picture type.",
__FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileInvalidArgument);
return -1;
}
ViERenderManagerScoped rs(*(shared_data_->render_manager()));
ViERenderer* renderer = rs.Renderer(video_channel);
if (!renderer) {
shared_data_->SetLastError(kViEFileSetRenderTimeoutError);
return -1;
}
VideoFrame timeout_image;
if (ViEFileImage::ConvertPictureToVideoFrame(
ViEId(shared_data_->instance_id(), video_channel), picture,
timeout_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d) Failed to use picture.",
__FUNCTION__, video_channel);
shared_data_->SetLastError(kViEFileInvalidCapture);
return -1;
}
WebRtc_Word32 timeout_time = timeout_ms;
if (timeout_ms < kViEMinRenderTimeoutTimeMs) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d) Invalid timeout_ms, using %d.",
__FUNCTION__, video_channel, kViEMinRenderTimeoutTimeMs);
timeout_time = kViEMinRenderTimeoutTimeMs;
}
if (timeout_ms > kViEMaxRenderTimeoutTimeMs) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d) Invalid timeout_ms, using %d.",
__FUNCTION__, video_channel, kViEMaxRenderTimeoutTimeMs);
timeout_time = kViEMaxRenderTimeoutTimeMs;
}
if (renderer->SetTimeoutImage(timeout_image, timeout_time) != 0) {
shared_data_->SetLastError(kViEFileSetRenderTimeoutError);
return -1;
}
return 0;
}
WebRtc_Word32 ViEFileImpl::GetNextCapturedFrame(WebRtc_Word32 capture_id,
VideoFrame& video_frame) {
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViECapturer* capturer = is.Capture(capture_id);
if (!capturer) {
return -1;
}
ViECaptureSnapshot* snap_shot = new ViECaptureSnapshot();
capturer->RegisterFrameCallback(-1, snap_shot);
bool snapshot_taken = snap_shot->GetSnapshot(
video_frame, kViECaptureMaxSnapshotWaitTimeMs);
// Check once again if it has been destroyed.
capturer->DeregisterFrameCallback(snap_shot);
delete snap_shot;
snap_shot = NULL;
if (snapshot_taken) {
return 0;
}
return -1;
}
ViECaptureSnapshot::ViECaptureSnapshot()
: crit_(CriticalSectionWrapper::CreateCriticalSection()),
condition_varaible_(ConditionVariableWrapper::CreateConditionVariable()),
video_frame_(NULL) {
}
ViECaptureSnapshot::~ViECaptureSnapshot() {
if (video_frame_) {
delete video_frame_;
video_frame_ = NULL;
}
}
bool ViECaptureSnapshot::GetSnapshot(VideoFrame& video_frame,
unsigned int max_wait_time) {
crit_->Enter();
video_frame_ = new VideoFrame();
if (condition_varaible_->SleepCS(*(crit_.get()), max_wait_time)) {
// Snapshot taken.
video_frame.SwapFrame(*video_frame_);
delete video_frame_;
video_frame_ = NULL;
crit_->Leave();
return true;
}
crit_->Leave();
return false;
}
void ViECaptureSnapshot::DeliverFrame(int id, VideoFrame& video_frame,
int num_csrcs,
const WebRtc_UWord32 CSRC[kRtpCsrcSize]) {
CriticalSectionScoped cs(crit_.get());
if (!video_frame_) {
return;
}
video_frame_->SwapFrame(video_frame);
condition_varaible_->WakeAll();
return;
}
#endif
} // namespace webrtc