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