blob: 5667c88ad03888afd2d80d472902fcba4d1f5768 [file] [log] [blame]
/*
* 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.
*/
#include "engine_configurations.h"
#include "video_engine/vie_file_impl.h"
#ifdef WEBRTC_VIDEO_ENGINE_FILE_API
#include "common_video/jpeg/main/interface/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, instance_id_,
"ViEFile::Release()");
// Decrease ref count.
(*this)--;
WebRtc_Word32 ref_count = GetCount();
if (ref_count < 0) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo, instance_id_,
"ViEFile release too many times");
SetLastError(kViEAPIDoesNotExist);
return -1;
}
WEBRTC_TRACE(kTraceInfo, kTraceVideo, instance_id_,
"ViEFile reference count: %d", ref_count);
return ref_count;
}
ViEFileImpl::ViEFileImpl() {
WEBRTC_TRACE(kTraceMemory, kTraceVideo, instance_id_,
"ViEFileImpl::ViEFileImpl() Ctor");
}
ViEFileImpl::~ViEFileImpl() {
WEBRTC_TRACE(kTraceMemory, kTraceVideo, 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(instance_id_), "%s",
__FUNCTION__);
if (!Initialized()) {
SetLastError(kViENotInitialized);
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_),
"%s - ViE instance %d not initialized", __FUNCTION__,
instance_id_);
return -1;
}
VoiceEngine* voice = channel_manager_.GetVoiceEngine();
const WebRtc_Word32 result = input_manager_.CreateFilePlayer(file_nameUTF8,
loop,
file_format,
voice, file_id);
if (result != 0) {
SetLastError(result);
return -1;
}
return 0;
}
int ViEFileImpl::StopPlayFile(const int file_id) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_),
"%s(file_id: %d)", __FUNCTION__, file_id);
{
ViEInputManagerScoped is(input_manager_);
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
SetLastError(kViEFileNotPlaying);
return -1;
}
}
// Destroy the capture device.
return input_manager_.DestroyFilePlayer(file_id);
}
int ViEFileImpl::RegisterObserver(int file_id, ViEFileObserver& observer) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_),
"%s(file_id: %d)", __FUNCTION__, file_id);
ViEInputManagerScoped is(input_manager_);
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->IsObserverRegistered()) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, file_id),
"%s: Observer already registered", __FUNCTION__);
SetLastError(kViEFileObserverAlreadyRegistered);
return -1;
}
if (vie_file_player->RegisterObserver(observer) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, file_id),
"%s: Failed to register observer", __FUNCTION__, file_id);
SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::DeregisterObserver(int file_id, ViEFileObserver& observer) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_),
"%s(file_id: %d)", __FUNCTION__, file_id);
ViEInputManagerScoped is(input_manager_);
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (!vie_file_player->IsObserverRegistered()) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(instance_id_, file_id), "%s: No Observer registered",
__FUNCTION__);
SetLastError(kViEFileObserverNotRegistered);
return -1;
}
if (vie_file_player->DeRegisterObserver() != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, file_id),
"%s: Failed to deregister observer", __FUNCTION__, file_id);
SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::SendFileOnChannel(const int file_id, const int video_channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_),
"%s(file_id: %d)", __FUNCTION__, file_id);
ViEChannelManagerScoped cs(channel_manager_);
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEInputManagerScoped is(input_manager_);
if (is.FrameProvider(vie_encoder) != NULL) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Channel %d already connected to a capture device or "
"file.", __FUNCTION__, video_channel);
SetLastError(kViEFileInputAlreadyConnected);
return -1;
}
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->RegisterFrameCallback(video_channel, vie_encoder)
!= 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_),
"%s: Failed to register frame callback.", __FUNCTION__,
file_id);
SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::StopSendFileOnChannel(const int video_channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(channel_manager_);
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEInputManagerScoped is(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(instance_id_, video_channel),
"%s: No file connected to Channel %d", __FUNCTION__,
video_channel);
SetLastError(kViEFileNotConnected);
return -1;
}
if (frame_provider->DeregisterFrameCallback(vie_encoder) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Failed to deregister file from channel %d",
__FUNCTION__, video_channel);
SetLastError(kViEFileUnknownError);
}
return 0;
}
int ViEFileImpl::StartPlayFileAsMicrophone(const int file_id,
const int audio_channel,
bool mix_microphone,
float volume_scaling) {
ViEInputManagerScoped is(input_manager_);
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->SendAudioOnChannel(audio_channel, mix_microphone,
volume_scaling) != 0) {
SetLastError(kViEFileVoEFailure);
return -1;
}
return 0;
}
int ViEFileImpl::StopPlayFileAsMicrophone(const int file_id,
const int audio_channel) {
ViEInputManagerScoped is(input_manager_);
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->StopSendAudioOnChannel(audio_channel) != 0) {
SetLastError(kViEFileVoEFailure);
return -1;
}
return 0;
}
int ViEFileImpl::StartPlayAudioLocally(const int file_id,
const int audio_channel,
float volume_scaling) {
ViEInputManagerScoped is(input_manager_);
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->PlayAudioLocally(audio_channel, volume_scaling) != 0) {
SetLastError(kViEFileVoEFailure);
return -1;
}
return 0;
}
int ViEFileImpl::StopPlayAudioLocally(const int file_id,
const int audio_channel) {
ViEInputManagerScoped is(input_manager_);
ViEFilePlayer* vie_file_player = is.FilePlayer(file_id);
if (!vie_file_player) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_),
"%s: File with id %d is not playing.", __FUNCTION__,
file_id);
SetLastError(kViEFileNotPlaying);
return -1;
}
if (vie_file_player->StopPlayAudioLocally(audio_channel) != 0) {
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(instance_id_, video_channel),
"%s video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(channel_manager_);
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& file_recorder = vie_encoder->GetOutgoingFileRecorder();
if (file_recorder.RecordingStarted()) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Already recording outgoing video on channel %d",
__FUNCTION__, video_channel);
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);
// Channel should exists since we have a ViEEncoder.
assert(vie_channel);
ve_channel_id = vie_channel->VoiceChannel();
ve_ptr = channel_manager_.GetVoiceEngine();
if (!ve_ptr) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Can't access voice engine. Have SetVoiceEngine "
"been called?", __FUNCTION__);
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(instance_id_, video_channel),
"%s: Failed to start recording. Check arguments.",
__FUNCTION__);
SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::StopRecordOutgoingVideo(const int video_channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(instance_id_, video_channel), "%s video_channel: %d)",
__FUNCTION__, video_channel);
ViEChannelManagerScoped cs(channel_manager_);
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& file_recorder = vie_encoder->GetOutgoingFileRecorder();
if (!file_recorder.RecordingStarted()) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Channel %d is not recording.", __FUNCTION__,
video_channel);
SetLastError(kViEFileNotRecording);
return -1;
}
if (file_recorder.StopRecording() != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Failed to stop recording of channel %d.", __FUNCTION__,
video_channel);
SetLastError(kViEFileUnknownError);
return -1;
}
return 0;
}
int ViEFileImpl::StopRecordIncomingVideo(const int video_channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_, video_channel),
"%s video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(channel_manager_);
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& file_recorder = vie_channel->GetIncomingFileRecorder();
if (!file_recorder.RecordingStarted()) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Channel %d is not recording.", __FUNCTION__,
video_channel);
SetLastError(kViEFileNotRecording);
vie_channel->ReleaseIncomingFileRecorder();
return -1;
}
if (file_recorder.StopRecording() != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Failed to stop recording of channel %d.",
__FUNCTION__, video_channel);
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(instance_id_, video_channel),
"%s video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(channel_manager_);
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__,
video_channel);
SetLastError(kViEFileInvalidChannelId);
return -1;
}
ViEFileRecorder& file_recorder = vie_channel->GetIncomingFileRecorder();
if (file_recorder.RecordingStarted()) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Already recording outgoing video on channel %d",
__FUNCTION__, video_channel);
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 = channel_manager_.GetVoiceEngine();
if (!ve_ptr) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s: Can't access voice engine. Have SetVoiceEngine "
"been called?", __FUNCTION__);
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(instance_id_, video_channel),
"%s: Failed to start recording. Check arguments.",
__FUNCTION__);
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(
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(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, 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, 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(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(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, 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, 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, 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(input_manager_);
ViECapturer* capturer = is.Capture(capture_id);
if (!capturer) {
return -1;
}
if (GetNextCapturedFrame(capture_id, video_frame) == -1) {
WEBRTC_TRACE(kTraceError, kTraceVideo, 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, instance_id_,
"%s(capture_id: %d)", __FUNCTION__, capture_id);
ViEInputManagerScoped is(input_manager_);
ViECapturer* capturer = is.Capture(capture_id);
if (!capturer) {
SetLastError(kViEFileInvalidCaptureId);
return -1;
}
VideoFrame capture_image;
if (ViEFileImage::ConvertJPEGToVideoFrame(
ViEId(instance_id_, capture_id), file_nameUTF8, capture_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(instance_id_, capture_id),
"%s(capture_id: %d) Failed to open file.", __FUNCTION__,
capture_id);
SetLastError(kViEFileInvalidFile);
return -1;
}
if (capturer->SetCaptureDeviceImage(capture_image)) {
SetLastError(kViEFileSetCaptureImageError);
return -1;
}
return 0;
}
int ViEFileImpl::SetCaptureDeviceImage(const int capture_id,
const ViEPicture& picture) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, instance_id_,
"%s(capture_id: %d)", __FUNCTION__, capture_id);
if (picture.type != kVideoI420) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, capture_id),
"%s(capture_id: %d) Not a valid picture type.",
__FUNCTION__, capture_id);
SetLastError(kViEFileInvalidArgument);
return -1;
}
ViEInputManagerScoped is(input_manager_);
ViECapturer* capturer = is.Capture(capture_id);
if (!capturer) {
SetLastError(kViEFileSetCaptureImageError);
return -1;
}
VideoFrame capture_image;
if (ViEFileImage::ConvertPictureToVideoFrame(
ViEId(instance_id_, capture_id), picture, capture_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, capture_id),
"%s(capture_id: %d) Failed to use picture.", __FUNCTION__,
capture_id);
SetLastError(kViEFileInvalidFile);
return -1;
}
if (capturer->SetCaptureDeviceImage(capture_image)) {
SetLastError(kViEFileInvalidCapture);
return -1;
}
return 0;
}
int ViEFileImpl::SetRenderStartImage(const int video_channel,
const char* file_nameUTF8) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_, video_channel),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
ViERenderManagerScoped rs(render_manager_);
ViERenderer* renderer = rs.Renderer(video_channel);
if (!renderer) {
SetLastError(kViEFileInvalidRenderId);
return -1;
}
VideoFrame start_image;
if (ViEFileImage::ConvertJPEGToVideoFrame(
ViEId(instance_id_, video_channel), file_nameUTF8, start_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s(video_channel: %d) Failed to open file.", __FUNCTION__,
video_channel);
SetLastError(kViEFileInvalidFile);
return -1;
}
if (renderer->SetRenderStartImage(start_image) != 0) {
SetLastError(kViEFileSetStartImageError);
return -1;
}
return 0;
}
int ViEFileImpl::SetRenderStartImage(const int video_channel,
const ViEPicture& picture) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(instance_id_, video_channel), "%s(video_channel: %d)",
__FUNCTION__, video_channel);
if (picture.type != kVideoI420) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s(video_channel: %d) Not a valid picture type.",
__FUNCTION__, video_channel);
SetLastError(kViEFileInvalidArgument);
return -1;
}
ViERenderManagerScoped rs(render_manager_);
ViERenderer* renderer = rs.Renderer(video_channel);
if (!renderer) {
SetLastError(kViEFileInvalidRenderId);
return -1;
}
VideoFrame start_image;
if (ViEFileImage::ConvertPictureToVideoFrame(
ViEId(instance_id_, video_channel), picture, start_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s(video_channel: %d) Failed to use picture.",
__FUNCTION__, video_channel);
SetLastError(kViEFileInvalidCapture);
return -1;
}
if (renderer->SetRenderStartImage(start_image) != 0) {
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(instance_id_, video_channel),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
ViERenderManagerScoped rs(render_manager_);
ViERenderer* renderer = rs.Renderer(video_channel);
if (!renderer) {
SetLastError(kViEFileInvalidRenderId);
return -1;
}
VideoFrame timeout_image;
if (ViEFileImage::ConvertJPEGToVideoFrame(
ViEId(instance_id_, video_channel), file_nameUTF8, timeout_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s(video_channel: %d) Failed to open file.", __FUNCTION__,
video_channel);
SetLastError(kViEFileInvalidFile);
return -1;
}
WebRtc_Word32 timeout_time = timeout_ms;
if (timeout_ms < kViEMinRenderTimeoutTimeMs) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(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(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) {
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(instance_id_, video_channel),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
if (picture.type != kVideoI420) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s(video_channel: %d) Not a valid picture type.",
__FUNCTION__, video_channel);
SetLastError(kViEFileInvalidArgument);
return -1;
}
ViERenderManagerScoped rs(render_manager_);
ViERenderer* renderer = rs.Renderer(video_channel);
if (!renderer) {
SetLastError(kViEFileSetRenderTimeoutError);
return -1;
}
VideoFrame timeout_image;
if (ViEFileImage::ConvertPictureToVideoFrame(
ViEId(instance_id_, video_channel), picture, timeout_image) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel),
"%s(video_channel: %d) Failed to use picture.",
__FUNCTION__, video_channel);
SetLastError(kViEFileInvalidCapture);
return -1;
}
WebRtc_Word32 timeout_time = timeout_ms;
if (timeout_ms < kViEMinRenderTimeoutTimeMs) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(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(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) {
SetLastError(kViEFileSetRenderTimeoutError);
return -1;
}
return 0;
}
WebRtc_Word32 ViEFileImpl::GetNextCapturedFrame(WebRtc_Word32 capture_id,
VideoFrame& video_frame) {
ViEInputManagerScoped is(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