2020-01-25 18:36:49 +01:00
|
|
|
#include "../PrivateDefines.cpp"
|
2020-01-25 18:11:15 +01:00
|
|
|
|
|
|
|
using namespace tgvoip;
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
#pragma mark - Video
|
|
|
|
|
|
|
|
void VoIPController::SetVideoSource(video::VideoSource *source)
|
|
|
|
{
|
2020-03-25 12:37:40 +01:00
|
|
|
std::shared_ptr<OutgoingVideoStream> stm = GetStreamByTypeShared<OutgoingVideoStream>();
|
2020-01-25 18:11:15 +01:00
|
|
|
if (!stm)
|
|
|
|
{
|
|
|
|
LOGE("Can't set video source when there is no outgoing video stream");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (source)
|
|
|
|
{
|
|
|
|
if (!stm->enabled)
|
|
|
|
{
|
|
|
|
stm->enabled = true;
|
|
|
|
messageThread.Post([this, stm] { SendStreamFlags(*stm); });
|
|
|
|
}
|
|
|
|
|
2020-01-27 19:53:32 +01:00
|
|
|
if (!stm->packetSender)
|
2020-03-25 12:37:40 +01:00
|
|
|
stm->packetSender = std::make_unique<video::VideoPacketSender>(this, stm, source);
|
2020-01-25 18:11:15 +01:00
|
|
|
else
|
2020-01-27 19:53:32 +01:00
|
|
|
dynamic_cast<video::VideoPacketSender *>(stm->packetSender.get())->SetSource(source);
|
2020-01-25 18:11:15 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (stm->enabled)
|
|
|
|
{
|
|
|
|
stm->enabled = false;
|
|
|
|
messageThread.Post([this, stm] { SendStreamFlags(*stm); });
|
|
|
|
}
|
2020-01-27 19:53:32 +01:00
|
|
|
if (stm->packetSender)
|
2020-01-25 18:11:15 +01:00
|
|
|
{
|
2020-01-27 19:53:32 +01:00
|
|
|
dynamic_cast<video::VideoPacketSender *>(stm->packetSender.get())->SetSource(NULL);
|
2020-01-25 18:11:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VoIPController::SetVideoRenderer(video::VideoRenderer *renderer)
|
|
|
|
{
|
|
|
|
videoRenderer = renderer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VoIPController::SetVideoCodecSpecificData(const std::vector<Buffer> &data)
|
|
|
|
{
|
2020-03-25 12:37:40 +01:00
|
|
|
auto *stm = GetStreamByType<OutgoingVideoStream>();
|
2020-03-22 20:09:44 +01:00
|
|
|
stm->codecSpecificData.clear();
|
2020-01-25 18:11:15 +01:00
|
|
|
for (const Buffer &csd : data)
|
|
|
|
{
|
2020-03-22 20:09:44 +01:00
|
|
|
stm->codecSpecificData.push_back(Buffer::CopyOf(csd));
|
2020-01-25 18:11:15 +01:00
|
|
|
}
|
|
|
|
LOGI("Set outgoing video stream CSD");
|
|
|
|
}
|
|
|
|
|
|
|
|
void VoIPController::ProcessIncomingVideoFrame(Buffer frame, uint32_t pts, bool keyframe, uint16_t rotation)
|
|
|
|
{
|
|
|
|
//LOGI("Incoming video frame size %u pts %u", (unsigned int)frame.Length(), pts);
|
|
|
|
if (frame.Length() == 0)
|
|
|
|
{
|
|
|
|
LOGE("EMPTY FRAME");
|
|
|
|
}
|
|
|
|
if (videoRenderer)
|
|
|
|
{
|
2020-03-25 12:37:40 +01:00
|
|
|
auto *stm = GetStreamByType<IncomingVideoStream>();
|
2020-01-25 18:11:15 +01:00
|
|
|
size_t offset = 0;
|
|
|
|
if (keyframe)
|
|
|
|
{
|
|
|
|
BufferInputStream in(frame);
|
|
|
|
uint16_t width = in.ReadUInt16();
|
|
|
|
uint16_t height = in.ReadUInt16();
|
|
|
|
uint8_t sizeAndFlag = in.ReadByte();
|
|
|
|
int size = sizeAndFlag & 0x0F;
|
|
|
|
bool reset = (sizeAndFlag & 0x80) == 0x80;
|
|
|
|
if (reset || !stm->csdIsValid || stm->width != width || stm->height != height)
|
|
|
|
{
|
|
|
|
stm->width = width;
|
|
|
|
stm->height = height;
|
|
|
|
stm->codecSpecificData.clear();
|
|
|
|
for (int i = 0; i < size; i++)
|
|
|
|
{
|
|
|
|
size_t len = in.ReadByte();
|
|
|
|
Buffer b(len);
|
|
|
|
in.ReadBytes(b);
|
|
|
|
stm->codecSpecificData.push_back(move(b));
|
|
|
|
}
|
|
|
|
stm->csdIsValid = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (int i = 0; i < size; i++)
|
|
|
|
{
|
|
|
|
size_t len = in.ReadByte();
|
|
|
|
in.Seek(in.GetOffset() + len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
offset = in.GetOffset();
|
|
|
|
}
|
|
|
|
if (!stm->csdIsValid && stm->width && stm->height)
|
|
|
|
{
|
|
|
|
videoRenderer->Reset(stm->codec, stm->width, stm->height, stm->codecSpecificData);
|
|
|
|
stm->csdIsValid = true;
|
|
|
|
}
|
|
|
|
if (lastReceivedVideoFrameNumber == UINT32_MAX || lastReceivedVideoFrameNumber == pts - 1 || keyframe)
|
|
|
|
{
|
|
|
|
lastReceivedVideoFrameNumber = pts;
|
|
|
|
//LOGV("3 before decode %u", (unsigned int)frame.Length());
|
|
|
|
if (stm->rotation != rotation)
|
|
|
|
{
|
|
|
|
stm->rotation = rotation;
|
|
|
|
videoRenderer->SetRotation(rotation);
|
|
|
|
}
|
|
|
|
if (offset == 0)
|
|
|
|
{
|
|
|
|
videoRenderer->DecodeAndDisplay(move(frame), pts);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
videoRenderer->DecodeAndDisplay(Buffer::CopyOf(frame, offset, frame.Length() - offset), pts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOGW("Skipping non-keyframe after packet loss...");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VoIPController::SetupOutgoingVideoStream()
|
|
|
|
{
|
|
|
|
vector<uint32_t> myEncoders = video::VideoSource::GetAvailableEncoders();
|
2020-03-24 15:07:56 +01:00
|
|
|
auto vstm = make_shared<OutgoingVideoStream>();
|
2020-01-25 18:11:15 +01:00
|
|
|
|
2020-03-21 15:08:03 +01:00
|
|
|
if (find(myEncoders.begin(), myEncoders.end(), Codec::Hevc) != myEncoders.end() && find(peerVideoDecoders.begin(), peerVideoDecoders.end(), Codec::Hevc) != peerVideoDecoders.end())
|
2020-01-25 18:11:15 +01:00
|
|
|
{
|
2020-03-21 15:08:03 +01:00
|
|
|
vstm->codec = Codec::Hevc;
|
2020-01-25 18:11:15 +01:00
|
|
|
}
|
2020-03-21 15:08:03 +01:00
|
|
|
else if (find(myEncoders.begin(), myEncoders.end(), Codec::Avc) != myEncoders.end() && find(peerVideoDecoders.begin(), peerVideoDecoders.end(), Codec::Avc) != peerVideoDecoders.end())
|
2020-01-25 18:11:15 +01:00
|
|
|
{
|
2020-03-21 15:08:03 +01:00
|
|
|
vstm->codec = Codec::Avc;
|
2020-01-25 18:11:15 +01:00
|
|
|
}
|
2020-03-21 15:08:03 +01:00
|
|
|
else if (find(myEncoders.begin(), myEncoders.end(), Codec::Vp8) != myEncoders.end() && find(peerVideoDecoders.begin(), peerVideoDecoders.end(), Codec::Vp8) != peerVideoDecoders.end())
|
2020-01-25 18:11:15 +01:00
|
|
|
{
|
2020-03-21 15:08:03 +01:00
|
|
|
vstm->codec = Codec::Vp8;
|
2020-01-25 18:11:15 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOGW("Can't setup outgoing video stream: no codecs in common");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vstm->enabled = false;
|
2020-03-24 15:07:56 +01:00
|
|
|
outgoingStreams.push_back(dynamic_pointer_cast<OutgoingStream<>>(vstm));
|
2020-01-25 18:11:15 +01:00
|
|
|
}
|