From f6172eaa5f78d2af04e8e99fdf26b2b0ad4994d6 Mon Sep 17 00:00:00 2001 From: zhangmeng <775834166@qq.com> Date: 星期四, 01 八月 2019 15:51:19 +0800 Subject: [PATCH] bug fix record file thread quit dup pkt --- csrc/wrapper.cpp | 24 + csrc/wrapper.hpp | 1 csrc/ffmpeg/format/FormatOut.cpp | 8 csrc/buz/sole.hpp | 902 +++++++++++++++++++++++++++++++++++++++++++++++++++++ csrc/buz/recorder.cpp | 62 ++- 5 files changed, 971 insertions(+), 26 deletions(-) diff --git a/csrc/buz/recorder.cpp b/csrc/buz/recorder.cpp index d80cea9..2cb3b12 100644 --- a/csrc/buz/recorder.cpp +++ b/csrc/buz/recorder.cpp @@ -1,4 +1,5 @@ #include "recorder.hpp" +#include "sole.hpp" #include <thread> #include <unistd.h> @@ -30,11 +31,22 @@ ,file_frame_index_(-1) ,file_path_("") ,func_rec_info_(nullptr) - {} + { + // logIt("RECODER ID: %s", id_.c_str()); + } Recorder::~Recorder(){ - stop_recorder_.store(true); - cv_.notify_one(); + if (out_ && !stop_recorder_.load()){ + stop_recorder_.store(true); + cv_.notify_one(); + while(stop_recorder_.load()){ + logIt("REC WAIT TO QUIT ID %s", id_.c_str()); + sleep(1); + } + }else if (stop_recorder_.load()){ + logIt("REC NORMAL QUIT"); + } + } int Recorder::init_writer(){ @@ -54,10 +66,11 @@ void Recorder::start_writer(){ if (cur_frame == 0) { - srandom(time(NULL)); - file_path_ = dir_ + "/" + std::to_string(random()) + ".mp4"; + + sole::uuid u4 = sole::uuid4(); + file_path_ = dir_ + "/" + u4.base62() + ".mp4"; out_->JustWriter(in_->getStream(), file_path_.c_str()); - logIt("start record %s", file_path_.c_str()); + logIt("START RECORD %s", file_path_.c_str()); } } @@ -69,21 +82,27 @@ } // writer error, reinit writer int64_t cur = cur_frame++; - if(!out_->writeFrame(pkt.data->getAVPacket(), cur)){ + AVPacket &op = pkt.data->getAVPacket(); + AVPacket np(op); + av_copy_packet(&np, &op); + if(!out_->writeFrame(np, cur)){ + av_packet_unref(&np); end_writer(); return -1; } + av_packet_unref(&np); if(pkt.id == id_frame_){ - file_frame_index_ = cur_frame; + file_frame_index_ = cur_frame-1; } + // logIt("WRITE FRAME ID: %d, RECORD ID: %d", pkt.id, id_frame_); return 0; } void Recorder::end_writer(){ if(cur_frame == -1) return; out_->endWriter(); - logIt("INDEX %d, FILE %s, CURFrame %d, ENDFrame %d\n", - file_frame_index_, file_path_.c_str(), cur_frame, end_frame); + logIt("INDEX %d, REAL-FRAME-ID %d, FILE %s, CURFrame %d, ENDFrame %d\n", + file_frame_index_, id_frame_, file_path_.c_str(), cur_frame, end_frame); //reinit cur_frame clear list pkt { @@ -92,11 +111,10 @@ end_frame = minduration; list_pkt_.clear(); } + //callback to frame index and path if(func_rec_info_){ func_rec_info_(id_,file_frame_index_, file_path_); - }else{ - // logIt("recorder has no func_rec_info"); } } @@ -134,21 +152,24 @@ for(auto &i : pkts){ if (cur_frame < end_frame){ - const int ret = write_correctly(i); - if(ret != 0){ - if(ret == -1) reinit_writer = true; + if(write_correctly(i) != 0){ + stop_recorder_.store(true); break; } }else{ end_writer(); + stop_recorder_.store(true); break; } } + } + if (out_){ delete out_; out_ = NULL; } + // stop_recorder_.store(false); } int Recorder::Run(const char* output, const int mind, const int maxd){ @@ -167,7 +188,7 @@ end_frame = minduration; } - logIt("min %d max %d endcount %d", minduration, maxduration, end_frame); + logIt("minduration %d maxduration %d curduration %d", minduration, maxduration, end_frame); std::thread([&]{ run_thread(); @@ -179,9 +200,15 @@ int Recorder::FireRecorder(const int64_t &id){ if(cur_frame == -1){ id_frame_ = id; + logIt("FIRST FIRE RECORD ID: %lld", id); { std::lock_guard<std::mutex> locker(mutex_pkt_); cur_frame = 0; + if (list_pkt_.size() > end_frame){ + end_frame = list_pkt_.size() + minduration/2; + if (end_frame > maxduration) + end_frame = maxduration; + } } }else if(end_frame - cur_frame > minduration/2 && end_frame < maxduration){ end_frame = end_frame + minduration / 2; @@ -189,7 +216,7 @@ end_frame = maxduration; } } - logIt("FIRE REC FRAME ID: %lld", id); + // logIt("FIRE REC FRAME ID: %lld", id); return 0; } @@ -219,7 +246,6 @@ cv_.notify_one(); } - logIt("CACHE PACKET FRAME ID %lld", pkt.id); return 0; } diff --git a/csrc/buz/sole.hpp b/csrc/buz/sole.hpp new file mode 100644 index 0000000..2c5c1ac --- /dev/null +++ b/csrc/buz/sole.hpp @@ -0,0 +1,902 @@ +/* Sole is a lightweight C++11 library to generate universally unique identificators. + * Sole provides interface for UUID versions 0, 1 and 4. + + * https://github.com/r-lyeh/sole + * Copyright (c) 2013,2014,2015 r-lyeh. zlib/libpng licensed. + + * Based on code by Dmitri Bouianov, Philip O'Toole, Poco C++ libraries and anonymous + * code found on the net. Thanks guys! + + * Theory: (see Hoylen's answer at [1]) + * - UUID version 1 (48-bit MAC address + 60-bit clock with a resolution of 100ns) + * Clock wraps in 3603 A.D. + * Up to 10000000 UUIDs per second. + * MAC address revealed. + * + * - UUID Version 4 (122-bits of randomness) + * See [2] or other analysis that describe how very unlikely a duplicate is. + * + * - Use v1 if you need to sort or classify UUIDs per machine. + * Use v1 if you are worried about leaving it up to probabilities (e.g. your are the + * type of person worried about the earth getting destroyed by a large asteroid in your + * lifetime). Just use a v1 and it is guaranteed to be unique till 3603 AD. + * + * - Use v4 if you are worried about security issues and determinism. That is because + * v1 UUIDs reveal the MAC address of the machine it was generated on and they can be + * predictable. Use v4 if you need more than 10 million uuids per second, or if your + * application wants to live past 3603 A.D. + + * Additionally a custom UUID v0 is provided: + * - 16-bit PID + 48-bit MAC address + 60-bit clock with a resolution of 100ns since Unix epoch + * - Format is EPOCH_LOW-EPOCH_MID-VERSION(0)|EPOCH_HI-PID-MAC + * - Clock wraps in 3991 A.D. + * - Up to 10000000 UUIDs per second. + * - MAC address and PID revealed. + + * References: + * - [1] http://stackoverflow.com/questions/1155008/how-unique-is-uuid + * - [2] http://en.wikipedia.org/wiki/UUID#Random%5FUUID%5Fprobability%5Fof%5Fduplicates + * - http://en.wikipedia.org/wiki/Universally_unique_identifier + * - http://en.cppreference.com/w/cpp/numeric/random/random_device + * - http://www.itu.int/ITU-T/asn1/uuid.html f81d4fae-7dec-11d0-a765-00a0c91e6bf6 + + * - rlyeh ~~ listening to Hedon Cries / Until The Sun Goes up + */ + +////////////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include <stdint.h> +#include <stdio.h> // for size_t; should be stddef.h instead; however, clang+archlinux fails when compiling it (@Travis-Ci) +#include <sys/types.h> // for uint32_t; should be stdint.h instead; however, GCC 5 on OSX fails when compiling it (See issue #11) +#include <functional> +#include <string> + +// public API + +#define SOLE_VERSION "1.0.1" /* (2017/05/16): Improve UUID4 and base62 performance; fix warnings +#define SOLE_VERSION "1.0.0" // (2016/02/03): Initial semver adherence; Switch to header-only; Remove warnings */ + +namespace sole +{ + // 128-bit basic UUID type that allows comparison and sorting. + // Use .str() for printing and .pretty() for pretty printing. + // Also, ostream friendly. + struct uuid + { + uint64_t ab; + uint64_t cd; + + bool operator==( const uuid &other ) const; + bool operator!=( const uuid &other ) const; + bool operator <( const uuid &other ) const; + + std::string pretty() const; + std::string base62() const; + std::string str() const; + + template<typename ostream> + inline friend ostream &operator<<( ostream &os, const uuid &self ) { + return os << self.str(), os; + } + }; + + // Generators + uuid uuid0(); // UUID v0, pro: unique; cons: MAC revealed, pid revealed, predictable. + uuid uuid1(); // UUID v1, pro: unique; cons: MAC revealed, predictable. + uuid uuid4(); // UUID v4, pros: anonymous, fast; con: uuids "can clash" + + // Rebuilders + uuid rebuild( uint64_t ab, uint64_t cd ); + uuid rebuild( const std::string &uustr ); +} + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4127) +#endif + +namespace std { + template<> + struct hash< sole::uuid > { + public: + // hash functor: hash uuid to size_t value by pseudorandomizing transform + size_t operator()( const sole::uuid &uuid ) const { + if( sizeof(size_t) > 4 ) { + return size_t( uuid.ab ^ uuid.cd ); + } else { + uint64_t hash64 = uuid.ab ^ uuid.cd; + return size_t( uint32_t( hash64 >> 32 ) ^ uint32_t( hash64 ) ); + } + } + }; +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// implementation + +#include <memory.h> +#include <stdint.h> +#include <stdio.h> +#include <time.h> + +#include <cstring> +#include <ctime> + +#include <iomanip> +#include <random> +#include <sstream> +#include <string> +#include <vector> + +#if defined(_WIN32) +# include <winsock2.h> +# include <process.h> +# include <iphlpapi.h> +# ifdef _MSC_VER +# pragma comment(lib,"iphlpapi.lib") +# endif +# define $windows $yes +#elif defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__OpenBSD__) || defined(__MINT__) || defined(__bsdi__) +# include <ifaddrs.h> +# include <net/if_dl.h> +# include <sys/socket.h> +# include <sys/time.h> +# include <sys/types.h> +# include <unistd.h> +# define $bsd $yes +#elif (defined(__APPLE__) && defined(__MACH__)) +# include <ifaddrs.h> +# include <net/if_dl.h> +# include <sys/socket.h> +# include <sys/time.h> +# include <sys/types.h> +# include <unistd.h> +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" +# define $osx $yes +#elif defined(__linux__) +# include <arpa/inet.h> +# include <net/if.h> +# include <netinet/in.h> +# include <sys/ioctl.h> +# include <sys/socket.h> +# include <sys/time.h> +# include <unistd.h> +# define $linux $yes +#else //elif defined(__unix__) +# if defined(__VMS) +# include <ioctl.h> +# include <inet.h> +# else +# include <sys/ioctl.h> +# include <arpa/inet.h> +# endif +# if defined(sun) || defined(__sun) +# include <sys/sockio.h> +# endif +# include <net/if.h> +# include <net/if_arp.h> +# include <netdb.h> +# include <netinet/in.h> +# include <sys/socket.h> +# include <sys/time.h> +# include <sys/types.h> +# include <unistd.h> +# if defined(__VMS) + namespace { enum { MAXHOSTNAMELEN = 64 }; } +# endif +# define $unix $yes +#endif + +#ifdef _MSC_VER +# define $msvc $yes +#endif + +#if defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 < 50100) + namespace std + { + static inline std::string put_time( const std::tm* tmb, const char* fmt ) { + std::string s( 128, '\0' ); + while( !strftime( &s[0], s.size(), fmt, tmb ) ) + s.resize( s.size() + 128 ); + return s; + } + } +#endif + +//////////////////////////////////////////////////////////////////////////////////// + +#ifdef $windows +#define $welse $no +#else +#define $windows $no +#define $welse $yes +#endif + +#ifdef $bsd +#define $belse $no +#else +#define $bsd $no +#define $belse $yes +#endif + +#ifdef $linux +#define $lelse $no +#else +#define $linux $no +#define $lelse $yes +#endif + +#ifdef $unix +#define $uelse $no +#else +#define $unix $no +#define $uelse $yes +#endif + +#ifdef $osx +#define $oelse $no +#else +#define $osx $no +#define $oelse $yes +#endif + +#ifdef $msvc +#define $melse $no +#else +#define $msvc $no +#define $melse $yes +#endif + +#define $yes(...) __VA_ARGS__ +#define $no(...) + +inline bool sole::uuid::operator==( const sole::uuid &other ) const { + return ab == other.ab && cd == other.cd; +} +inline bool sole::uuid::operator!=( const sole::uuid &other ) const { + return !operator==(other); +} +inline bool sole::uuid::operator<( const sole::uuid &other ) const { + if( ab < other.ab ) return true; + if( ab > other.ab ) return false; + if( cd < other.cd ) return true; + return false; +} + +namespace sole { + + inline std::string printftime( uint64_t timestamp_secs = 0, const std::string &locale = std::string() ) { + std::string timef; + try { + // Taken from parameter + //std::string locale; // = "es-ES", "Chinese_China.936", "en_US.UTF8", etc... + std::time_t t = timestamp_secs; + std::tm tm; + $msvc( + localtime_s( &tm, &t ); + ) + $melse( + $windows(tm = *localtime( &t ); ) + $welse( localtime_r(&t, &tm); ) + ) + + std::stringstream ss; + $melse( + std::locale lc( locale.c_str() ); + ss.imbue( lc ); + ) + ss << std::put_time( &tm, "\"%c\"" ); + + timef = ss.str(); + } + catch(...) { + timef = "\"\""; + } + return timef; + } + + inline std::string uuid::pretty() const { + std::stringstream ss; + + uint64_t a = (ab >> 32); + uint64_t b = (ab & 0xFFFFFFFF); + uint64_t c = (cd >> 32); + uint64_t d = (cd & 0xFFFFFFFF); + + int version = (b & 0xF000) >> 12; + uint64_t timestamp = ((b & 0x0FFF) << 48 ) | (( b >> 16 ) << 32) | a; // in 100ns units + + ss << "version=" << (version) << ','; + + if( version == 1 ) + timestamp = timestamp - 0x01b21dd213814000ULL; // decrement Gregorian calendar + + ss << std::hex << std::nouppercase << std::setfill('0'); + version <= 1 && ss << "timestamp=" << printftime(timestamp/10000000) << ','; + version <= 1 && ss << "mac=" << std::setw(4) << (c & 0xFFFF) << std::setw(8) << d << ','; + version == 4 && ss << "randbits=" << std::setw(8) << (ab & 0xFFFFFFFFFFFF0FFFULL) << std::setw(8) << (cd & 0x3FFFFFFFFFFFFFFFULL) << ','; + + ss << std::dec; + version == 0 && ss << "pid=" << std::setw(4) << (c >> 16 ) << ','; + version == 1 && ss << "clock_seq=" << std::setw(4) << ((c >> 16) & 0x3FFF) << ','; + + return ss.str(); + } + + inline std::string uuid::str() const { + std::stringstream ss; + ss << std::hex << std::nouppercase << std::setfill('0'); + + uint32_t a = (ab >> 32); + uint32_t b = (ab & 0xFFFFFFFF); + uint32_t c = (cd >> 32); + uint32_t d = (cd & 0xFFFFFFFF); + + ss << std::setw(8) << (a) << '-'; + ss << std::setw(4) << (b >> 16) << '-'; + ss << std::setw(4) << (b & 0xFFFF) << '-'; + ss << std::setw(4) << (c >> 16 ) << '-'; + ss << std::setw(4) << (c & 0xFFFF); + ss << std::setw(8) << d; + + return ss.str(); + } + + inline std::string uuid::base62() const { + int base62len = 10 + 26 + 26; + const char base62[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + char res[24], *end = &res[24]; *(--end) = '\0'; + uint64_t rem, AB = ab, CD = cd; + do { + rem = CD % base62len; + *--end = base62[int(rem)]; + CD /= base62len; + } while (CD > 0); + *--end = '-'; + do { + rem = AB % base62len; + *--end = base62[int(rem)]; + AB /= base62len; + } while (AB > 0); + return end; + } + + ////////////////////////////////////////////////////////////////////////////////////// + // multiplatform clock_gettime() + + $windows( + struct timespec { + uint64_t tv_sec; + uint64_t tv_nsec; + }; + struct timezone { + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ + }; + inline int gettimeofday( struct timeval *tv, struct timezone *tz ) { + FILETIME ft; + uint64_t tmpres = 0; + + if( NULL != tv ) { + GetSystemTimeAsFileTime(&ft); + + // The GetSystemTimeAsFileTime returns the number of 100 nanosecond + // intervals since Jan 1, 1601 in a structure. Copy the high bits to + // the 64 bit tmpres, shift it left by 32 then or in the low 32 bits. + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + // Convert to microseconds by dividing by 10 + tmpres /= 10; + + // The Unix epoch starts on Jan 1 1970. Need to subtract the difference + // in seconds from Jan 1 1601. + tmpres -= 11644473600000000ULL; + + // Finally change microseconds to seconds and place in the seconds value. + // The modulus picks up the microseconds. + tv->tv_sec = static_cast<long>(tmpres / 1000000UL); + tv->tv_usec = (tmpres % 1000000UL); + } + + if( NULL != tz ) { + static bool once = true; + if( once ) { + once = false; + _tzset(); + } + + long timezoneSecs = 0; + int daylight = 0; + + $msvc( + _get_timezone(&timezoneSecs); + _get_daylight(&daylight); + ) + $melse( + timezoneSecs = _timezone; + daylight = _daylight; + ) + + tz->tz_minuteswest = timezoneSecs / 60; + tz->tz_dsttime = daylight; + } + + return 0; + } + ) + $lelse( $belse( // if not linux, if not bsd... valid for apple/win32 + inline int clock_gettime( int /*clk_id*/, struct timespec* t ) { + struct timeval now; + int rv = gettimeofday(&now, NULL); + if( rv ) return rv; + t->tv_sec = now.tv_sec; + t->tv_nsec = now.tv_usec * 1000; + return 0; + } + )) + + ////////////////////////////////////////////////////////////////////////////////////// + // Timestamp and MAC interfaces + + // Returns number of 100ns intervals + inline uint64_t get_time( uint64_t offset ) { + struct timespec tp; + clock_gettime(0 /*CLOCK_REALTIME*/, &tp); + + // Convert to 100-nanosecond intervals + uint64_t uuid_time; + uuid_time = tp.tv_sec * 10000000; + uuid_time = uuid_time + (tp.tv_nsec / 100); + uuid_time = uuid_time + offset; + + // If the clock looks like it went backwards, or is the same, increment it. + static uint64_t last_uuid_time = 0; + if( last_uuid_time > uuid_time ) + last_uuid_time = uuid_time; + else + last_uuid_time = ++uuid_time; + + return uuid_time; + } + + // Looks for first MAC address of any network device, any size. + inline bool get_any_mac( std::vector<unsigned char> &_node ) { + $windows({ + PIP_ADAPTER_INFO pAdapterInfo; + PIP_ADAPTER_INFO pAdapter = 0; + ULONG len = sizeof(IP_ADAPTER_INFO); + pAdapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(new char[len]); + + // Make an initial call to GetAdaptersInfo to get + // the necessary size into len + DWORD rc = GetAdaptersInfo(pAdapterInfo, &len); + if (rc == ERROR_BUFFER_OVERFLOW) + { + delete [] reinterpret_cast<char*>(pAdapterInfo); + pAdapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(new char[len]); + } + else if (rc != ERROR_SUCCESS) + { + return $no("cannot get network adapter list") false; + } + + bool found = false, gotten = false; + if (GetAdaptersInfo(pAdapterInfo, &len) == NO_ERROR) + { + gotten = true; + + pAdapter = pAdapterInfo; + while (pAdapter && !found) + { + if (pAdapter->Type == MIB_IF_TYPE_ETHERNET && pAdapter->AddressLength > 0 ) + { + _node.resize( pAdapter->AddressLength ); + std::memcpy(_node.data(), pAdapter->Address, _node.size() ); + found = true; + } + pAdapter = pAdapter->Next; + } + } + + delete [] reinterpret_cast<char*>(pAdapterInfo); + + if( !gotten ) + return $no("cannot get network adapter list") false; + + if (!found) + return $no("no Ethernet adapter found") false; + + return true; + }) + + $bsd({ + struct ifaddrs* ifaphead; + int rc = getifaddrs(&ifaphead); + if (rc) return $no("cannot get network adapter list") false; + + bool foundAdapter = false; + for (struct ifaddrs* ifap = ifaphead; ifap; ifap = ifap->ifa_next) + { + if (ifap->ifa_addr && ifap->ifa_addr->sa_family == AF_LINK) + { + struct sockaddr_dl* sdl = reinterpret_cast<struct sockaddr_dl*>(ifap->ifa_addr); + caddr_t ap = (caddr_t) (sdl->sdl_data + sdl->sdl_nlen); + int alen = sdl->sdl_alen; + if (ap && alen > 0) + { + _node.resize( alen ); + std::memcpy(_node.data(), ap, _node.size() ); + foundAdapter = true; + break; + } + } + } + freeifaddrs(ifaphead); + if (!foundAdapter) return $no("cannot determine MAC address (no suitable network adapter found)") false; + return true; + }) + + $osx({ + struct ifaddrs* ifaphead; + int rc = getifaddrs(&ifaphead); + if (rc) return $no("cannot get network adapter list") false; + + bool foundAdapter = false; + for (struct ifaddrs* ifap = ifaphead; ifap; ifap = ifap->ifa_next) + { + if (ifap->ifa_addr && ifap->ifa_addr->sa_family == AF_LINK) + { + struct sockaddr_dl* sdl = reinterpret_cast<struct sockaddr_dl*>(ifap->ifa_addr); + caddr_t ap = (caddr_t) (sdl->sdl_data + sdl->sdl_nlen); + int alen = sdl->sdl_alen; + if (ap && alen > 0) + { + _node.resize( alen ); + std::memcpy(_node.data(), ap, _node.size() ); + foundAdapter = true; + break; + } + } + } + freeifaddrs(ifaphead); + if (!foundAdapter) return $no("cannot determine MAC address (no suitable network adapter found)") false; + return true; + }) + + $linux({ + struct ifreq ifr; + + int s = socket(PF_INET, SOCK_DGRAM, 0); + if (s == -1) return $no("cannot open socket") false; + + std::strcpy(ifr.ifr_name, "eth0"); + int rc = ioctl(s, SIOCGIFHWADDR, &ifr); + close(s); + if (rc < 0) return $no("cannot get MAC address") false; + struct sockaddr* sa = reinterpret_cast<struct sockaddr*>(&ifr.ifr_addr); + _node.resize( sizeof(sa->sa_data) ); + std::memcpy(_node.data(), sa->sa_data, _node.size() ); + return true; + }) + + $unix({ + char name[MAXHOSTNAMELEN]; + if (gethostname(name, sizeof(name))) + return $no("cannot get host name") false; + + struct hostent* pHost = gethostbyname(name); + if (!pHost) return $no("cannot get host IP address") false; + + int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s == -1) return $no("cannot open socket") false; + + struct arpreq ar; + std::memset(&ar, 0, sizeof(ar)); + struct sockaddr_in* pAddr = reinterpret_cast<struct sockaddr_in*>(&ar.arp_pa); + pAddr->sin_family = AF_INET; + std::memcpy(&pAddr->sin_addr, *pHost->h_addr_list, sizeof(struct in_addr)); + int rc = ioctl(s, SIOCGARP, &ar); + close(s); + if (rc < 0) return $no("cannot get MAC address") false; + _node.resize( sizeof(ar.arp_ha.sa_data) ); + std::memcpy(_node.data(), ar.arp_ha.sa_data, _node.size()); + return true; + }) + } + + // Looks for first MAC address of any network device, size truncated to 48bits. + inline uint64_t get_any_mac48() { + std::vector<unsigned char> node; + if( get_any_mac(node) ) { + std::stringstream ss; + ss << std::hex << std::setfill('0'); + node.resize(6); + for( unsigned i = 0; i < 6; ++i ) + ss << std::setw(2) << int(node[i]); + uint64_t t; + if( ss >> t ) + return t; + } + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////// + // UUID implementations + + inline uuid uuid4() { + static std::random_device rd; + static std::uniform_int_distribution<uint64_t> dist(0, (uint64_t)(~0)); + + uuid my; + + my.ab = dist(rd); + my.cd = dist(rd); + + my.ab = (my.ab & 0xFFFFFFFFFFFF0FFFULL) | 0x0000000000004000ULL; + my.cd = (my.cd & 0x3FFFFFFFFFFFFFFFULL) | 0x8000000000000000ULL; + + return my; + } + + inline uuid uuid1() { + // Number of 100-ns intervals since 00:00:00.00 15 October 1582; [ref] uuid.py + uint64_t ns100_intervals = get_time( 0x01b21dd213814000ULL ); + uint16_t clock_seq = (uint16_t)( ns100_intervals & 0x3fff ); // 14-bits max + uint64_t mac = get_any_mac48(); // 48-bits max + + uint32_t time_low = ns100_intervals & 0xffffffff; + uint16_t time_mid = (ns100_intervals >> 32) & 0xffff; + uint16_t time_hi_version = (ns100_intervals >> 48) & 0xfff; + uint8_t clock_seq_low = clock_seq & 0xff; + uint8_t clock_seq_hi_variant = (clock_seq >> 8) & 0x3f; + + uuid u; + uint64_t &upper_ = u.ab; + uint64_t &lower_ = u.cd; + + // Build the high 32 bytes + upper_ = (uint64_t) time_low << 32; + upper_ |= (uint64_t) time_mid << 16; + upper_ |= (uint64_t) time_hi_version; + + // Build the low 32 bytes, using the clock sequence number + lower_ = (uint64_t) ((clock_seq_hi_variant << 8) | clock_seq_low) << 48; + lower_ |= mac; + + // Set the variant to RFC 4122. + lower_ &= ~((uint64_t)0xc000 << 48); + lower_ |= (uint64_t)0x8000 << 48; + + // Set the version number. + enum { version = 1 }; + upper_ &= ~0xf000; + upper_ |= version << 12; + + return u; + } + + inline uuid uuid0() { + // Number of 100-ns intervals since Unix epoch time + uint64_t ns100_intervals = get_time( 0 ); + uint64_t pid = $windows( _getpid() ) $welse( getpid() ); + uint16_t pid16 = (uint16_t)( pid & 0xffff ); // 16-bits max + uint64_t mac = get_any_mac48(); // 48-bits max + + uint32_t time_low = ns100_intervals & 0xffffffff; + uint16_t time_mid = (ns100_intervals >> 32) & 0xffff; + uint16_t time_hi_version = (ns100_intervals >> 48) & 0xfff; + uint8_t pid_low = pid16 & 0xff; + uint8_t pid_hi = (pid16 >> 8) & 0xff; + + uuid u; + uint64_t &upper_ = u.ab; + uint64_t &lower_ = u.cd; + + // Build the high 32 bytes. + upper_ = (uint64_t) time_low << 32; + upper_ |= (uint64_t) time_mid << 16; + upper_ |= (uint64_t) time_hi_version; + + // Build the low 32 bytes, using the mac and pid number. + lower_ = (uint64_t) ((pid_hi << 8) | pid_low) << 48; + lower_ |= mac; + + // Set the version number. + enum { version = 0 }; + upper_ &= ~0xf000; + upper_ |= version << 12; + + return u; + } + + inline uuid rebuild( uint64_t ab, uint64_t cd ) { + uuid u; + u.ab = ab; u.cd = cd; + return u; + } + + inline uuid rebuild( const std::string &uustr ) { + char sep; + uint64_t a,b,c,d,e; + uuid u = { 0, 0 }; + auto idx = uustr.find_first_of("-"); + if( idx != std::string::npos ) { + // single separator, base62 notation + if( uustr.find_first_of("-",idx+1) == std::string::npos ) { + auto rebase62 = [&]( const char *input, size_t limit ) -> uint64_t { + int base62len = 10 + 26 + 26; + auto strpos = []( char ch ) -> size_t { + if( ch >= 'a' ) return ch - 'a' + 10 + 26; + if( ch >= 'A' ) return ch - 'A' + 10; + return ch - '0'; + }; + uint64_t res = strpos( input[0] ); + for( size_t i = 1; i < limit; ++i ) + res = base62len * res + strpos( input[i] ); + return res; + }; + u.ab = rebase62( &uustr[0], idx ); + u.cd = rebase62( &uustr[idx+1], uustr.size() - (idx+1) ); + } + // else classic hex notation + else { + std::stringstream ss( uustr ); + if( ss >> std::hex >> a >> sep >> b >> sep >> c >> sep >> d >> sep >> e ) { + if( ss.eof() ) { + u.ab = (a << 32) | (b << 16) | c; + u.cd = (d << 48) | e; + } + } + } + } + return u; + } + +} // ::sole + +#undef $bsd +#undef $belse +#undef $linux +#undef $lelse +#undef $osx +#undef $oelse +#undef $unix +#undef $uelse +#undef $windows +#undef $welse +#undef $yes +#undef $no + +// Pop disabled warnings +#if (defined(__APPLE__) && defined(__MACH__)) +#pragma clang diagnostic pop +#endif + +#ifdef SOLE_BUILD_DEMO +// g++ users: `g++ demo.cc -std=c++11 -lrt -o sample` +// visual studio: `cl.exe demo.cc sole.cpp` + +#include <iostream> + +int main() { + sole::uuid u0 = sole::uuid0(), u1 = sole::uuid1(), u4 = sole::uuid4(); + + std::cout << "uuid v0 string : " << u0 << std::endl; + std::cout << "uuid v0 base62 : " << u0.base62() << std::endl; + std::cout << "uuid v0 pretty : " << u0.pretty() << std::endl << std::endl; + + std::cout << "uuid v1 string : " << u1 << std::endl; + std::cout << "uuid v1 base62 : " << u1.base62() << std::endl; + std::cout << "uuid v1 pretty : " << u1.pretty() << std::endl << std::endl; + + std::cout << "uuid v4 string : " << u4 << std::endl; + std::cout << "uuid v4 base62 : " << u4.base62() << std::endl; + std::cout << "uuid v4 pretty : " << u4.pretty() << std::endl << std::endl; + + u1 = sole::rebuild("F81D4FAE-7DEC-11D0-A765-00A0C91E6BF6"); + u4 = sole::rebuild("GITheR4tLlg-BagIW20DGja"); + + std::cout << "uuid v1 rebuilt : " << u1 << " -> " << u1.pretty() << std::endl; + std::cout << "uuid v4 rebuilt : " << u4 << " -> " << u4.pretty() << std::endl; +} + +#endif + +#ifdef SOLE_BUILD_TESTS +// g++ users: `g++ sole.cxx -std=c++11 -lrt -o tests` +// visual studio: `cl.exe sole.cxx` + +#include <cassert> +#include <set> +#include <ratio> +#include <chrono> +#include <iostream> + +using namespace sole; + +namespace run +{ + auto epoch = [](){ + return std::chrono::system_clock::to_time_t( std::chrono::system_clock::now() ); + }; + + template<typename FN> + void benchmark( const FN &fn, const std::string &name ) { + std::cout << "Benchmarking " << name << "... " << std::flush; + + auto then = epoch(); + + while( epoch() == then ); + then = epoch(); + + unsigned c = 0; + while( epoch() == then ) c = ( fn(), ++c ); + + std::cout << (c) << " uuids/sec" << std::endl; + } + + template<typename FN> + void tests( const FN &fn ) { + unsigned numtests = ~0; + std::cout << "Testing for " << numtests << " collisions... " << std::endl; + + auto then = epoch(); + + std::set<uuid> all; + for( unsigned i = 0; i < numtests; ++i ) { + auto now = epoch(); + if( now != then ) { + then = now; + double pct6digs = ( int( ( double(i) / (unsigned)(~0) ) * 1e4 ) / double(1e4) ); + std::cout << '\r' << i << " uuids generated, no collision (" << pct6digs << "%)" << std::flush; + } + sole::uuid my_uuid = fn(); + assert( all.find(my_uuid) == all.end() && "error: UUIDs just collided! is std::random_device a real random generator?" ); + all.insert( my_uuid ); + } + } + + template<typename FN> + void verify( const FN &fn ) { + std::cout << "Verifying serialization of 1 million UUIDs... " << std::flush; + + for( unsigned i = 0; i < 1000000; ++i ) { + sole::uuid uuid = fn(); + sole::uuid rebuilt1 = sole::rebuild( uuid.str() ); + sole::uuid rebuilt2 = sole::rebuild( uuid.base62() ); + assert( rebuilt1 == uuid && "error: rebuild() or .str() failed" ); + assert( rebuilt2 == uuid && "error: rebuild() or .base62() failed" ); + } + + std::cout << "ok" << std::endl; + } +} + +int main() { + assert( sizeof(sole::uuid ) * 8 == 128 ); + assert( sizeof(sole::uuid0().ab) * 8 == 64 ); + assert( sizeof(sole::uuid0().cd) * 8 == 64 ); + + run::benchmark(uuid0, "v0"); + run::benchmark(uuid1, "v1"); + run::benchmark(uuid4, "v4"); + + run::verify(uuid4); // use fastest implementation + +// run::tests(uuid0); // not applicable +// run::tests(uuid1); // not applicable + run::tests(uuid4); +} + +#endif diff --git a/csrc/ffmpeg/format/FormatOut.cpp b/csrc/ffmpeg/format/FormatOut.cpp index d319969..bc77524 100644 --- a/csrc/ffmpeg/format/FormatOut.cpp +++ b/csrc/ffmpeg/format/FormatOut.cpp @@ -339,7 +339,6 @@ char option_key[]="movflags"; char option_value[]="frag_keyframe+empty_moov"; av_dict_set(&avdic,option_key,option_value,0); - flag = writeHeader(&avdic); av_dict_free(&avdic); @@ -397,12 +396,17 @@ AVRational time_base_q = { 1, AV_TIME_BASE }; //Duration between 2 frames (us) - int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / fps_); //鍐呴儴鏃堕棿鎴� + // int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / fps_); //鍐呴儴鏃堕棿鎴� + int64_t calc_duration = (int64_t)(AV_TIME_BASE / fps_); //鍐呴儴鏃堕棿鎴� //Parameters pkt.pts = av_rescale_q(time_stamp*calc_duration, time_base_q, time_base); pkt.dts = pkt.pts; pkt.duration = av_rescale_q(calc_duration, time_base_q, time_base); //(double)(calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base)); + // if (pkt.duration < 0 || time_base.den != 90000){ + // logIt("CALCULATE DURATION : %lld, fame count : %lld, TIMEBASE: %d", calc_duration,time_stamp, time_base.den); + // } + } bool FormatOut::writeFrame(AVPacket &pkt, const int64_t &frame_cnt, diff --git a/csrc/wrapper.cpp b/csrc/wrapper.cpp index e26c1f4..1ebda9d 100644 --- a/csrc/wrapper.cpp +++ b/csrc/wrapper.cpp @@ -56,6 +56,12 @@ delete bridge_; bridge_ = NULL; } + map_rec_.clear(); + list_rec_pkt_.clear(); + + for(auto &i : list_pic_){ + free(i.data); + } } void Wrapper::ScalePicture(const int w, const int h, const int flags){ @@ -199,7 +205,7 @@ avpacket p = {k.data, k.id}; i.second.rec->CachePacket(p); } - logIt("start rec %d frames", list_rec_pkt_.size()); + logIt("START REC %d FRAMES", list_rec_pkt_.size()); } }else if (i.second.rec){ i.second.rec->CachePacket(pkt); @@ -240,13 +246,13 @@ } //////////////recorder - std::shared_ptr<Recorder> Wrapper::init_recorder(FormatIn *in, std::string id,std::string dir, const int mind, const int maxd){ + std::shared_ptr<Recorder> Wrapper::init_recorder(FormatIn *in, std::string id, std::string dir, const int mind, const int maxd){ if(!in){ logIt("Init wrapper first"); return nullptr; } - auto rec = std::make_shared<Recorder>(in, id); + auto rec = std::make_shared<Recorder>(in, id.c_str()); rec->SetCallback([&](std::string &id, int &index, std::string &path){ cache_rec_info(id, index, path); @@ -267,6 +273,7 @@ void Wrapper::BuildRecorder(const char* id, const char *output, const int mindur, const int maxdur){ std::string rid(id); std::string dir(output); + auto fn = [=](FormatIn *in){ return init_recorder(in, rid, dir, mindur, maxdur); }; @@ -286,7 +293,6 @@ iter->second.rec->FireRecorder(id); } } - logIt("FIRE REC %s, FRAME ID: %d", sid, id); } void Wrapper::cache_rec_info(std::string &id, int &index, std::string &path){ @@ -300,10 +306,11 @@ struct record_file_info info; info.file_frame_index = index; info.file_path = path; + info.rec_id = id; list_rec_.emplace_back(info); list_rec_map_[path] = id; - logIt("list rec files count : %d", list_rec_.size()); - map_rec_.erase(id); + logIt("LIST REC FILES COUNT : %d", list_rec_.size()); + } void Wrapper::GetInfoRecorder(int &index, std::string &path){ @@ -317,6 +324,9 @@ index = info.file_frame_index; path = info.file_path; list_rec_.pop_front(); + + if (map_rec_.find(info.rec_id) != map_rec_.end()) + map_rec_.erase(info.rec_id); // logIt("go get info index: %d, file: %s\n", index, path.c_str()); } @@ -327,6 +337,8 @@ ret = iter->second; list_rec_map_.erase(iter); } + + return ret; } ////////decoder diff --git a/csrc/wrapper.hpp b/csrc/wrapper.hpp index a7d4f92..b11c9ca 100644 --- a/csrc/wrapper.hpp +++ b/csrc/wrapper.hpp @@ -102,6 +102,7 @@ struct record_file_info{ int file_frame_index; std::string file_path; + std::string rec_id; }; std::list<struct record_file_info> list_rec_; std::unordered_map<std::string, std::string> list_rec_map_; -- Gitblit v1.8.0