VTrain/tools/rtsp_server/xop/H265Source.cpp

146 lines
3.8 KiB
C++

// PHZ
// 2018-6-7
#if defined(WIN32) || defined(_WIN32)
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#endif
#include "H265Source.h"
#include <cstdio>
#include <chrono>
#if defined(__linux) || defined(__linux__)
#include <sys/time.h>
#endif
using namespace xop;
using namespace std;
H265Source::H265Source(uint32_t framerate)
: framerate_(framerate)
{
payload_ = 96;
media_type_ = H265;
clock_rate_ = 90000;
}
H265Source* H265Source::CreateNew(uint32_t framerate)
{
return new H265Source(framerate);
}
H265Source::~H265Source()
{
}
string H265Source::GetMediaDescription(uint16_t port)
{
char buf[100] = {0};
sprintf(buf, "m=video %hu RTP/AVP 96", port);
return string(buf);
}
string H265Source::GetAttribute()
{
return string("a=rtpmap:96 H265/90000");
}
bool H265Source::HandleFrame(MediaChannelId channelId, AVFrame frame)
{
uint8_t *frame_buf = frame.buffer.get();
uint32_t frame_size = frame.size;
if (frame.timestamp == 0) {
frame.timestamp = GetTimestamp();
}
if (frame_size <= MAX_RTP_PAYLOAD_SIZE) {
RtpPacket rtp_pkt;
rtp_pkt.type = frame.type;
rtp_pkt.timestamp = frame.timestamp;
rtp_pkt.size = frame_size + RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE;
rtp_pkt.last = 1;
memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE, frame_buf, frame_size);
if (send_frame_callback_) {
if (!send_frame_callback_(channelId, rtp_pkt)) {
return false;
}
}
}
else {
char FU[3] = {0};
char nalUnitType = (frame_buf[0] & 0x7E) >> 1;
FU[0] = (frame_buf[0] & 0x81) | (49<<1);
FU[1] = frame_buf[1];
FU[2] = (0x80 | nalUnitType);
frame_buf += 2;
frame_size -= 2;
while (frame_size + 3 > MAX_RTP_PAYLOAD_SIZE) {
RtpPacket rtp_pkt;
rtp_pkt.type = frame.type;
rtp_pkt.timestamp = frame.timestamp;
rtp_pkt.size = RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + MAX_RTP_PAYLOAD_SIZE;
rtp_pkt.last = 0;
rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 0] = FU[0];
rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 1] = FU[1];
rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 2] = FU[2];
memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE+3, frame_buf, MAX_RTP_PAYLOAD_SIZE-3);
if (send_frame_callback_) {
if (!send_frame_callback_(channelId, rtp_pkt)) {
return false;
}
}
frame_buf += (MAX_RTP_PAYLOAD_SIZE - 3);
frame_size -= (MAX_RTP_PAYLOAD_SIZE - 3);
FU[2] &= ~0x80;
}
{
RtpPacket rtp_pkt;
rtp_pkt.type = frame.type;
rtp_pkt.timestamp = frame.timestamp;
rtp_pkt.size = RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 3 + frame_size;
rtp_pkt.last = 1;
FU[2] |= 0x40;
rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 0] = FU[0];
rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 1] = FU[1];
rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 2] = FU[2];
memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE+3, frame_buf, frame_size);
if (send_frame_callback_) {
if (!send_frame_callback_(channelId, rtp_pkt)) {
return false;
}
}
}
}
return true;
}
uint32_t H265Source::GetTimestamp()
{
/* #if defined(__linux) || defined(__linux__)
struct timeval tv = {0};
gettimeofday(&tv, NULL);
uint32_t ts = ((tv.tv_sec*1000)+((tv.tv_usec+500)/1000))*90; // 90: _clockRate/1000;
return ts;
#else */
//auto time_point = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
//auto time_point = chrono::time_point_cast<chrono::milliseconds>(chrono::steady_clock::now());
auto time_point = chrono::time_point_cast<chrono::microseconds>(chrono::steady_clock::now());
return (uint32_t)((time_point.time_since_epoch().count() + 500) / 1000 * 90);
//#endif
}