1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-12-02 17:51:06 +01:00
libtgvoip/controller/media/Video.cpp

159 lines
5.1 KiB
C++
Raw Normal View History

2020-03-25 15:49:13 +01:00
#include "../../VoIPController.h"
2020-01-25 18:11:15 +01:00
using namespace tgvoip;
2020-03-25 15:49:13 +01:00
2020-01-25 18:11:15 +01:00
#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-25 15:49:13 +01:00
auto vstm = std::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
}