1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-12-11 08:39:49 +01:00
libtgvoip/controller/media/Video.cpp
2020-01-28 12:34:24 +01:00

169 lines
5.3 KiB
C++

#include "../PrivateDefines.cpp"
using namespace tgvoip;
using namespace std;
#pragma mark - Video
void VoIPController::SetVideoSource(video::VideoSource *source)
{
shared_ptr<Stream> stm = GetStreamByType(STREAM_TYPE_VIDEO, true);
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); });
}
if (!stm->packetSender)
stm->packetSender = std::make_unique<video::VideoPacketSender>(this, source, stm);
else
dynamic_cast<video::VideoPacketSender *>(stm->packetSender.get())->SetSource(source);
}
else
{
if (stm->enabled)
{
stm->enabled = false;
messageThread.Post([this, stm] { SendStreamFlags(*stm); });
}
if (stm->packetSender)
{
dynamic_cast<video::VideoPacketSender *>(stm->packetSender.get())->SetSource(NULL);
}
}
}
void VoIPController::SetVideoRenderer(video::VideoRenderer *renderer)
{
videoRenderer = renderer;
}
void VoIPController::SetVideoCodecSpecificData(const std::vector<Buffer> &data)
{
outgoingStreams[1]->codecSpecificData.clear();
for (const Buffer &csd : data)
{
outgoingStreams[1]->codecSpecificData.push_back(Buffer::CopyOf(csd));
}
LOGI("Set outgoing video stream CSD");
}
void VoIPController::SendVideoFrame(const Buffer &frame, uint32_t flags, uint32_t rotation)
{
//LOGI("Send video frame %u flags %u", (unsigned int)frame.Length(), flags);
shared_ptr<Stream> stm = GetStreamByType(STREAM_TYPE_VIDEO, true);
if (stm)
{
}
}
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)
{
shared_ptr<Stream> stm = GetStreamByType(STREAM_TYPE_VIDEO, false);
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();
shared_ptr<Stream> vstm = make_shared<Stream>();
vstm->id = 2;
vstm->type = STREAM_TYPE_VIDEO;
if (find(myEncoders.begin(), myEncoders.end(), CODEC_HEVC) != myEncoders.end() && find(peerVideoDecoders.begin(), peerVideoDecoders.end(), CODEC_HEVC) != peerVideoDecoders.end())
{
vstm->codec = CODEC_HEVC;
}
else if (find(myEncoders.begin(), myEncoders.end(), CODEC_AVC) != myEncoders.end() && find(peerVideoDecoders.begin(), peerVideoDecoders.end(), CODEC_AVC) != peerVideoDecoders.end())
{
vstm->codec = CODEC_AVC;
}
else if (find(myEncoders.begin(), myEncoders.end(), CODEC_VP8) != myEncoders.end() && find(peerVideoDecoders.begin(), peerVideoDecoders.end(), CODEC_VP8) != peerVideoDecoders.end())
{
vstm->codec = CODEC_VP8;
}
else
{
LOGW("Can't setup outgoing video stream: no codecs in common");
return;
}
vstm->enabled = false;
outgoingStreams.push_back(vstm);
}