Merge branch 'development' into LTS_development
# Conflicts: # lib/h264.h
This commit is contained in:
commit
416254304a
7 changed files with 108 additions and 12 deletions
|
@ -37,12 +37,30 @@ static const char * DBG_LVL_LIST[] = {"NONE", "FAIL", "ERROR", "WARN", "INFO", "
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <execinfo.h>
|
||||||
|
static inline void show_stackframe() {
|
||||||
|
void *trace[16];
|
||||||
|
char **messages = 0;
|
||||||
|
int i, trace_size = 0;
|
||||||
|
trace_size = backtrace(trace, 16);
|
||||||
|
messages = backtrace_symbols(trace, trace_size);
|
||||||
|
for (i=1; i<trace_size; ++i){
|
||||||
|
size_t p = 0;
|
||||||
|
while(messages[i][p] != '(' && messages[i][p] != ' ' && messages[i][p] != 0){
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
DEBUG_MSG(0, "Backtrace[%d]: %s", i, messages[i]+p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define DEBUG_MSG(lvl, msg, ...) // Debugging disabled.
|
#define DEBUG_MSG(lvl, msg, ...) // Debugging disabled.
|
||||||
|
static inline void show_stackframe(){}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define BACKTRACE show_stackframe();
|
||||||
#define FAIL_MSG(msg, ...) DEBUG_MSG(DLVL_FAIL, msg, ##__VA_ARGS__)
|
#define FAIL_MSG(msg, ...) DEBUG_MSG(DLVL_FAIL, msg, ##__VA_ARGS__)
|
||||||
#define ERROR_MSG(msg, ...) DEBUG_MSG(DLVL_ERROR, msg, ##__VA_ARGS__)
|
#define ERROR_MSG(msg, ...) DEBUG_MSG(DLVL_ERROR, msg, ##__VA_ARGS__)
|
||||||
#define WARN_MSG(msg, ...) DEBUG_MSG(DLVL_WARN, msg, ##__VA_ARGS__)
|
#define WARN_MSG(msg, ...) DEBUG_MSG(DLVL_WARN, msg, ##__VA_ARGS__)
|
||||||
|
|
30
lib/h264.cpp
30
lib/h264.cpp
|
@ -10,6 +10,36 @@
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
namespace h264 {
|
namespace h264 {
|
||||||
|
|
||||||
|
///Helper function to determine if a H264 NAL unit is a keyframe or not
|
||||||
|
bool isKeyframe(const char * data, uint32_t len){
|
||||||
|
uint8_t nalType = (data[0] & 0x1F);
|
||||||
|
if (nalType == 0x05){return true;}
|
||||||
|
if (nalType != 0x01){return false;}
|
||||||
|
Utils::bitstream bs;
|
||||||
|
for (size_t i = 1; i < 10 && i < len; ++i) {
|
||||||
|
if (i + 2 < len && (memcmp(data + i, "\000\000\003", 3) == 0)) { //Emulation prevention bytes
|
||||||
|
bs.append(data + i, 2);
|
||||||
|
i += 2;
|
||||||
|
} else {
|
||||||
|
bs.append(data + i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bs.getExpGolomb();//Discard first_mb_in_slice
|
||||||
|
uint64_t sliceType = bs.getUExpGolomb();
|
||||||
|
//Slice types:
|
||||||
|
// 0: P - Predictive slice (at most 1 reference)
|
||||||
|
// 1: B - Bi-predictive slice (at most 2 references)
|
||||||
|
// 2: I - Intra slice (no external references)
|
||||||
|
// 3: SP - Switching predictive slice (at most 1 reference)
|
||||||
|
// 4: SI - Switching intra slice (no external references)
|
||||||
|
// 5-9: 0-4, but all in picture of same type
|
||||||
|
if (sliceType == 2 || sliceType == 4 || sliceType == 7 || sliceType == 9){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::deque<nalu::nalData> analysePackets(const char * data, unsigned long len){
|
std::deque<nalu::nalData> analysePackets(const char * data, unsigned long len){
|
||||||
std::deque<nalu::nalData> res;
|
std::deque<nalu::nalData> res;
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,8 @@ namespace h264 {
|
||||||
size_t dataLen;
|
size_t dataLen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool isKeyframe(const char * data, uint32_t len);
|
||||||
|
|
||||||
class nalUnit {
|
class nalUnit {
|
||||||
public:
|
public:
|
||||||
nalUnit(const char * data, size_t len) : payload(data, len) {}
|
nalUnit(const char * data, size_t len) : payload(data, len) {}
|
||||||
|
|
|
@ -65,6 +65,10 @@ std::string uint2string(unsigned int i){
|
||||||
return st.str();
|
return st.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Socket::Buffer::Buffer(){
|
||||||
|
splitter = "\n";
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the amount of elements in the internal std::deque of std::string objects.
|
/// Returns the amount of elements in the internal std::deque of std::string objects.
|
||||||
/// The back is popped as long as it is empty, first - this way this function is
|
/// The back is popped as long as it is empty, first - this way this function is
|
||||||
/// guaranteed to return 0 if the buffer is empty.
|
/// guaranteed to return 0 if the buffer is empty.
|
||||||
|
@ -83,26 +87,58 @@ unsigned int Socket::Buffer::bytes(unsigned int max){
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns how many bytes to read until the next splitter, or 0 if none found.
|
||||||
|
unsigned int Socket::Buffer::bytesToSplit(){
|
||||||
|
unsigned int i = 0;
|
||||||
|
for (std::deque<std::string>::reverse_iterator it = data.rbegin(); it != data.rend(); ++it){
|
||||||
|
i += (*it).size();
|
||||||
|
if ((*it).size() >= splitter.size() && (*it).substr((*it).size()-splitter.size()) == splitter){
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// Appends this string to the internal std::deque of std::string objects.
|
/// Appends this string to the internal std::deque of std::string objects.
|
||||||
/// It is automatically split every BUFFER_BLOCKSIZE bytes.
|
/// It is automatically split every BUFFER_BLOCKSIZE bytes and when the splitter string is encountered.
|
||||||
void Socket::Buffer::append(const std::string &newdata){
|
void Socket::Buffer::append(const std::string &newdata){
|
||||||
append(newdata.c_str(), newdata.size());
|
append(newdata.data(), newdata.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
///Helper function that does a short-circuiting string compare
|
||||||
|
inline bool string_compare(const char *a, const char *b, const size_t len){
|
||||||
|
for (size_t i = 0; i < len; ++i){
|
||||||
|
if (a[i] != b[i]){return false;}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends this data block to the internal std::deque of std::string objects.
|
/// Appends this data block to the internal std::deque of std::string objects.
|
||||||
/// It is automatically split every BUFFER_BLOCKSIZE bytes.
|
/// It is automatically split every BUFFER_BLOCKSIZE bytes and when the splitter string is encountered.
|
||||||
void Socket::Buffer::append(const char *newdata, const unsigned int newdatasize){
|
void Socket::Buffer::append(const char *newdata, const unsigned int newdatasize){
|
||||||
unsigned int i = 0, j = 0;
|
uint32_t i = 0;
|
||||||
while (i < newdatasize){
|
while (i < newdatasize){
|
||||||
j = i;
|
uint32_t j = 0;
|
||||||
while (j < newdatasize && j - i <= BUFFER_BLOCKSIZE){
|
if (!splitter.size()){
|
||||||
j++;
|
if (newdatasize - i > BUFFER_BLOCKSIZE){
|
||||||
if (newdata[j - 1] == '\n'){break;}
|
j = BUFFER_BLOCKSIZE;
|
||||||
}
|
}else{
|
||||||
if (i != j){
|
j = newdatasize - i;
|
||||||
data.push_front(std::string(newdata + i, (size_t)(j - i)));
|
}
|
||||||
i = j;
|
|
||||||
}else{
|
}else{
|
||||||
|
while (j+i < newdatasize && j < BUFFER_BLOCKSIZE){
|
||||||
|
j++;
|
||||||
|
if (j >= splitter.size()){
|
||||||
|
if (string_compare(newdata+i+j-splitter.size(), splitter.data(), splitter.size())){break;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j){
|
||||||
|
data.push_front("");
|
||||||
|
data.front().assign(newdata + i, (size_t)j);
|
||||||
|
i += j;
|
||||||
|
}else{
|
||||||
|
FAIL_MSG("Appended an empty string to buffer: aborting!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,11 @@ namespace Socket{
|
||||||
std::deque<std::string> data;
|
std::deque<std::string> data;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::string splitter;///<String to automatically split on if encountered. \n by default
|
||||||
|
Buffer();
|
||||||
unsigned int size();
|
unsigned int size();
|
||||||
unsigned int bytes(unsigned int max);
|
unsigned int bytes(unsigned int max);
|
||||||
|
unsigned int bytesToSplit();
|
||||||
void append(const std::string &newdata);
|
void append(const std::string &newdata);
|
||||||
void append(const char *newdata, const unsigned int newdatasize);
|
void append(const char *newdata, const unsigned int newdatasize);
|
||||||
void prepend(const std::string &newdata);
|
void prepend(const std::string &newdata);
|
||||||
|
|
|
@ -81,6 +81,12 @@ long long int Util::bootSecs() {
|
||||||
return t.tv_sec;
|
return t.tv_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t Util::bootMS() {
|
||||||
|
struct timespec t;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||||
|
return ((uint64_t)t.tv_sec) * 1000 + t.tv_nsec / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the current time in microseconds.
|
/// Gets the current time in microseconds.
|
||||||
long long unsigned int Util::getMicros() {
|
long long unsigned int Util::getMicros() {
|
||||||
struct timespec t;
|
struct timespec t;
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace Util {
|
||||||
void sleep(int ms); ///< Sleeps for roughly the indicated amount of milliseconds.
|
void sleep(int ms); ///< Sleeps for roughly the indicated amount of milliseconds.
|
||||||
long long int getMS(); ///< Gets the current time in milliseconds.
|
long long int getMS(); ///< Gets the current time in milliseconds.
|
||||||
long long int bootSecs(); ///< Gets the current system uptime in seconds.
|
long long int bootSecs(); ///< Gets the current system uptime in seconds.
|
||||||
|
uint64_t bootMS(); ///< Gets the current system uptime in milliseconds.
|
||||||
long long unsigned int getMicros();///<Gets the current time in microseconds.
|
long long unsigned int getMicros();///<Gets the current time in microseconds.
|
||||||
long long unsigned int getMicros(long long unsigned int previous);///<Gets the time difference in microseconds.
|
long long unsigned int getMicros(long long unsigned int previous);///<Gets the time difference in microseconds.
|
||||||
long long int getNTP();
|
long long int getNTP();
|
||||||
|
|
Loading…
Add table
Reference in a new issue