139 lines
3.7 KiB
C++
139 lines
3.7 KiB
C++
// PHZ
|
|
// 2018-5-16
|
|
|
|
#if defined(WIN32) || defined(_WIN32)
|
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#endif
|
|
#endif
|
|
|
|
#include "H264Source.h"
|
|
#include <cstdio>
|
|
#include <chrono>
|
|
#if defined(__linux) || defined(__linux__)
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
using namespace xop;
|
|
using namespace std;
|
|
|
|
H264Source::H264Source(uint32_t framerate)
|
|
: framerate_(framerate)
|
|
{
|
|
payload_ = 96;
|
|
media_type_ = H264;
|
|
clock_rate_ = 90000;
|
|
}
|
|
|
|
H264Source* H264Source::CreateNew(uint32_t framerate)
|
|
{
|
|
return new H264Source(framerate);
|
|
}
|
|
|
|
H264Source::~H264Source()
|
|
{
|
|
|
|
}
|
|
|
|
string H264Source::GetMediaDescription(uint16_t port)
|
|
{
|
|
char buf[100] = {0};
|
|
sprintf(buf, "m=video %hu RTP/AVP 96", port); // \r\nb=AS:2000
|
|
return string(buf);
|
|
}
|
|
|
|
string H264Source::GetAttribute()
|
|
{
|
|
return string("a=rtpmap:96 H264/90000");
|
|
}
|
|
|
|
bool H264Source::HandleFrame(MediaChannelId channel_id, 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_(channel_id, rtp_pkt)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
char FU_A[2] = {0};
|
|
|
|
FU_A[0] = (frame_buf[0] & 0xE0) | 28;
|
|
FU_A[1] = 0x80 | (frame_buf[0] & 0x1f);
|
|
|
|
frame_buf += 1;
|
|
frame_size -= 1;
|
|
|
|
while (frame_size + 2 > 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_A[0];
|
|
rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 1] = FU_A[1];
|
|
memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE+2, frame_buf, MAX_RTP_PAYLOAD_SIZE-2);
|
|
|
|
if (send_frame_callback_) {
|
|
if (!send_frame_callback_(channel_id, rtp_pkt))
|
|
return false;
|
|
}
|
|
|
|
frame_buf += MAX_RTP_PAYLOAD_SIZE - 2;
|
|
frame_size -= MAX_RTP_PAYLOAD_SIZE - 2;
|
|
|
|
FU_A[1] &= ~0x80;
|
|
}
|
|
|
|
{
|
|
RtpPacket rtp_pkt;
|
|
rtp_pkt.type = frame.type;
|
|
rtp_pkt.timestamp = frame.timestamp;
|
|
rtp_pkt.size = 4 + RTP_HEADER_SIZE + 2 + frame_size;
|
|
rtp_pkt.last = 1;
|
|
|
|
FU_A[1] |= 0x40;
|
|
rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 0] = FU_A[0];
|
|
rtp_pkt.data.get()[RTP_TCP_HEAD_SIZE + RTP_HEADER_SIZE + 1] = FU_A[1];
|
|
memcpy(rtp_pkt.data.get()+RTP_TCP_HEAD_SIZE+RTP_HEADER_SIZE+2, frame_buf, frame_size);
|
|
|
|
if (send_frame_callback_) {
|
|
if (!send_frame_callback_(channel_id, rtp_pkt)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
uint32_t H264Source::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::microseconds>(chrono::steady_clock::now());
|
|
return (uint32_t)((time_point.time_since_epoch().count() + 500) / 1000 * 90 );
|
|
//#endif
|
|
}
|
|
|