From a6dd7933e0bd8ae1fd083639758f7fee9fc7a151 Mon Sep 17 00:00:00 2001 From: chenshijun <csj_sky@126.com> Date: 星期二, 10 九月 2019 16:34:10 +0800 Subject: [PATCH] Merge branch 'master' of ssh://192.168.1.14:29418/valib/goffmpeg --- csrc/wrapper.cpp | 170 ++++++- csrc/wrapper.hpp | 30 + csrc/ffmpeg/format/FormatOut.cpp | 9 goffmpeg.go | 12 cffmpeg.h | 2 csrc/buz/sole.hpp | 902 ++++++++++++++++++++++++++++++++++++++++++ libcffmpeg.c | 4 csrc/buz/recorder.hpp | 6 csrc/cffmpeg.cpp | 4 libcffmpeg.h | 4 csrc/buz/recorder.cpp | 85 +++ 11 files changed, 1,164 insertions(+), 64 deletions(-) diff --git a/cffmpeg.h b/cffmpeg.h index ef4ed72..b411d0a 100644 --- a/cffmpeg.h +++ b/cffmpeg.h @@ -23,7 +23,7 @@ char* c_ffmpeg_get_rec_id(const cffmpeg h, const char* p, int *length); void c_ffmpeg_build_decoder(const cffmpeg h); -void* c_ffmpeg_get_pic_decoder(const cffmpeg h, int *wid, int *hei); +void* c_ffmpeg_get_pic_decoder(const cffmpeg h, int *wid, int *hei, int64_t *id); void* c_ffmpeg_get_avpacket(const cffmpeg h, int *size, int *key); //////test diff --git a/csrc/buz/recorder.cpp b/csrc/buz/recorder.cpp index f83a596..2da437c 100644 --- a/csrc/buz/recorder.cpp +++ b/csrc/buz/recorder.cpp @@ -1,7 +1,9 @@ #include "recorder.hpp" +#include "sole.hpp" #include <thread> #include <unistd.h> +#include <chrono> extern "C"{ #include <libavcodec/avcodec.h> @@ -30,11 +32,31 @@ ,file_frame_index_(-1) ,file_path_("") ,func_rec_info_(nullptr) - {} + ,thrd_(nullptr) + ,error_occured_(false) + { + // logIt("RECODER ID: %s", id_.c_str()); + } Recorder::~Recorder(){ - stop_recorder_.store(true); - cv_.notify_one(); + + try + { + if (thrd_){ + { + std::unique_lock<std::mutex> locker(mutex_pkt_); + stop_recorder_.store(true); + cv_.notify_one(); + } + thrd_->join(); + logIt("REC THREAD JOINED, QUIT!!!"); + } + } + catch(const std::exception& e) + { + logIt("RECODER DESTRUCTOR EXCEPTION: ", e.what()); + } + } int Recorder::init_writer(){ @@ -54,10 +76,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,19 +92,28 @@ } // 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, 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 { std::lock_guard<std::mutex> locker(mutex_pkt_); @@ -89,12 +121,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_); - // logIt("recoder index %d, file name %s\n", file_frame_index_, file_path_.c_str()); - }else{ - // logIt("recorder has no func_rec_info"); } } @@ -113,9 +143,15 @@ std::list<avpacket> pkts; { std::unique_lock<std::mutex> locker(mutex_pkt_); - cv_.wait(locker,[&]{ + auto status = cv_.wait_for(locker, std::chrono::seconds(10), [&]{ return !list_pkt_.empty() || stop_recorder_.load(); }); + + if (!status){ + end_writer(); + error_occured_ = true; + break; + } if(stop_recorder_.load()){ end_writer(); break; @@ -132,21 +168,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){ @@ -165,11 +204,12 @@ 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([&]{ + thrd_.reset(new std::thread([&]{ run_thread(); - }).detach(); + })); + //.detach(); return 0; } @@ -177,9 +217,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; @@ -187,6 +233,7 @@ end_frame = maxduration; } } + // logIt("FIRE REC FRAME ID: %lld", id); return 0; } @@ -235,4 +282,4 @@ } } } -} \ No newline at end of file +} diff --git a/csrc/buz/recorder.hpp b/csrc/buz/recorder.hpp index 483404e..ba9cea4 100644 --- a/csrc/buz/recorder.hpp +++ b/csrc/buz/recorder.hpp @@ -40,6 +40,8 @@ void SetCallback(FUNC_REC_INFO cb){ func_rec_info_ = cb; } + + const bool ErrorOcurred(){return error_occured_;} private: void run_thread(); @@ -64,6 +66,8 @@ std::mutex mutex_pkt_; std::condition_variable cv_; + std::unique_ptr<std::thread> thrd_; + std::string dir_; std::string id_; @@ -71,6 +75,8 @@ int file_frame_index_; std::string file_path_; FUNC_REC_INFO func_rec_info_; + + bool error_occured_; }; } } 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/cffmpeg.cpp b/csrc/cffmpeg.cpp index cdbd2f0..3383b31 100644 --- a/csrc/cffmpeg.cpp +++ b/csrc/cffmpeg.cpp @@ -90,10 +90,10 @@ s->BuildDecoder(); } -void* c_ffmpeg_get_pic_decoder(const cffmpeg h, int *wid, int *hei){ +void* c_ffmpeg_get_pic_decoder(const cffmpeg h, int *wid, int *hei, int64_t *id){ Wrapper *s = (Wrapper*)h; unsigned char *data = NULL; - s->GetPicDecoder(&data, wid, hei); + s->GetPicDecoder(&data, wid, hei, id); return data; } diff --git a/csrc/ffmpeg/format/FormatOut.cpp b/csrc/ffmpeg/format/FormatOut.cpp index d319969..804c8ed 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); @@ -365,6 +364,7 @@ bool FormatOut::endWriter(){ auto flag = writeTrailer(); + closeResource(); record_ = false; return flag; @@ -397,12 +397,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 4e3d8b8..513055e 100644 --- a/csrc/wrapper.cpp +++ b/csrc/wrapper.cpp @@ -39,6 +39,8 @@ ,gb_(0) ,cpu_(0) ,use_decoder_(false) + ,minduration(250) + ,maxduration(750) { makeTheWorld(); } @@ -46,14 +48,29 @@ Wrapper::~Wrapper() { - if(thread_){ - stop_stream_.store(true); - thread_->join(); + try + { + if(thread_){ + stop_stream_.store(true); + thread_->join(); + } + if(bridge_){ + delete bridge_; bridge_ = NULL; + } + + map_rec_.clear(); + list_rec_pkt_.clear(); + + for(auto &i : list_pic_){ + free(i.data); + } } - if(bridge_){ - delete bridge_; bridge_ = NULL; + catch(const std::exception& e) + { + logIt("WRAPPER EXCEPTION: ", e.what()); } - + + } void Wrapper::ScalePicture(const int w, const int h, const int flags){ @@ -132,7 +149,10 @@ auto data(std::make_shared<CodedData>()); if(!in->readPacket(data)){ logIt("read packet error"); - pkt.id = -1; data = nullptr; id = 0; + data.reset(); + data = nullptr; + pkt.id = -1; + id = 0; }else{ pkt.id = id++; } @@ -143,6 +163,13 @@ run_worker(in.get(), pkt); if(!data){ + { + std::lock_guard<std::mutex> l(mutex_rec_); + map_rec_.clear(); + } + std::lock_guard<std::mutex> locker(mtx_rec_pkt_); + list_rec_pkt_.clear(); + break; } //test @@ -180,27 +207,72 @@ auto ret = in->decode(frame, pkt.data); if(ret == 1){ //鍚愬嚭鏁版嵁 - cache_pic(frame); + cache_pic(frame, pkt.id); } } + cache_rec_pkt(pkt); + { + std::lock_guard<std::mutex> l(mutex_rec_); - for(auto &i : map_rec_){ - if (!i.second.rec){ - i.second.rec = i.second.fn_init(in); + for(auto &i : map_rec_){ + if (!i.second.rec){ + i.second.rec = std::move(init_recorder(in, i.second.rid, i.second.dir, i.second.min, i.second.max)); + if (i.second.rec){ + std::lock_guard<std::mutex> locker(mtx_rec_pkt_); + for(auto &k : list_rec_pkt_){ + avpacket p = {k.data, k.id}; + i.second.rec->CachePacket(p); + } + logIt("START REC %d FRAMES", list_rec_pkt_.size()); + } + }else if (i.second.rec){ + i.second.rec->CachePacket(pkt); + } } - if (i.second.rec){ - i.second.rec->CachePacket(pkt); + + } + } + + int Wrapper::cache_rec_pkt(const avpacket &pkt){ + + std::lock_guard<std::mutex> locker(mtx_rec_pkt_); + //wait I + if (list_rec_pkt_.empty()) { + AVPacket &avpkt = pkt.data->getAVPacket(); + if (!(avpkt.flags & AV_PKT_FLAG_KEY)){ + return -1; + } + } + maybe_dump_rec_pkt(); + recpkt k = {pkt.data, pkt.id}; + list_rec_pkt_.push_back(k); + + return 0; + } + void Wrapper::maybe_dump_rec_pkt(){ + //瓒呰繃min/2,涓㈠純gop + while (list_rec_pkt_.size() > minduration) { + list_rec_pkt_.pop_front(); + while(!list_rec_pkt_.empty()){ + auto &cache = list_rec_pkt_.front(); + AVPacket &avpkt = cache.data->getAVPacket(); + if (!(avpkt.flags & AV_PKT_FLAG_KEY)){ + list_rec_pkt_.pop_front(); + }else{ + break; + } } } } + //////////////recorder - std::shared_ptr<Recorder> Wrapper::init_recorder(FormatIn *in, std::string id,std::string dir, const int mind, const int maxd){ + std::unique_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); + std::unique_ptr<Recorder> rec(new Recorder(in, id.c_str())); rec->SetCallback([&](std::string &id, int &index, std::string &path){ cache_rec_info(id, index, path); @@ -221,22 +293,51 @@ 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); - }; - std::shared_ptr<Recorder> rec(nullptr); - FnRec r = FnRec{fn, rec}; - map_rec_[rid] = r; + std::lock_guard<std::mutex> l(mutex_rec_); + + // auto fn = [=](FormatIn *in){ + // return init_recorder(in, rid, dir, mindur, maxdur); + // }; + // FnRec r = FnRec{fn, nullptr}; + if (map_rec_.find(rid) != map_rec_.end()){ + map_rec_.erase(rid); + } + // for (auto iter = map_rec_.begin(); iter != map_rec_.end();){ + // if (iter->second.rec && iter->second.rec->ErrorOcurred()){ + // iter == map_rec_.erase(iter); + // }else{ + // iter++; + // } + // } + FnRec fr; + fr.rid = rid; + fr.dir = dir; + fr.min = mindur; + fr.max = maxdur; + map_rec_[rid] = std::move(fr); + + minduration = mindur * 25; + maxduration = maxdur * 25; } int Wrapper::FireRecorder(const char* sid,const int64_t &id){ + std::lock_guard<std::mutex> l(mutex_rec_); + auto iter = map_rec_.find(sid); if (iter != map_rec_.end()){ if(iter->second.rec){ iter->second.rec->FireRecorder(id); } } + + // for (auto iter = map_rec_.begin(); iter != map_rec_.end();){ + // if (iter->second.rec && iter->second.rec->ErrorOcurred()){ + // iter == map_rec_.erase(iter); + // }else{ + // iter++; + // } + // } } void Wrapper::cache_rec_info(std::string &id, int &index, std::string &path){ @@ -250,10 +351,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){ @@ -267,16 +369,32 @@ 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); + + for (auto iter = map_rec_.begin(); iter != map_rec_.end();){ + if (iter->second.rec && iter->second.rec->ErrorOcurred()){ + iter == map_rec_.erase(iter); + }else{ + iter++; + } + } + // logIt("go get info index: %d, file: %s\n", index, path.c_str()); } std::string Wrapper::GetRecorderID(const std::string &path){ + std::lock_guard<std::mutex> l(mutex_rec_); + std::string ret(""); auto iter = list_rec_map_.find(path); if (iter != list_rec_map_.end()){ ret = iter->second; list_rec_map_.erase(iter); } + + return ret; } ////////decoder @@ -284,7 +402,7 @@ use_decoder_ = true; } - void Wrapper::cache_pic(std::shared_ptr<ffwrapper::FrameData> &frame){ + void Wrapper::cache_pic(std::shared_ptr<ffwrapper::FrameData> &frame, int64_t &id){ pic_bgr24 pic; if(bridge_){ @@ -295,6 +413,7 @@ unsigned char *data = (unsigned char*)malloc(pic.w * pic.h * 3); bridge_->copyPicture(data, frm); pic.data = data; + pic.id = id; } { @@ -311,7 +430,7 @@ } - void Wrapper::GetPicDecoder(unsigned char **data, int *w, int *h){ + void Wrapper::GetPicDecoder(unsigned char **data, int *w, int *h, int64_t *id){ std::lock_guard<std::mutex> l(mutex_pic_); if(list_pic_.empty()){ *data = NULL; @@ -321,6 +440,7 @@ } auto p = list_pic_.front(); *data = p.data; *w = p.w; *h = p.h; + *id = p.id; list_pic_.pop_front(); } diff --git a/csrc/wrapper.hpp b/csrc/wrapper.hpp index 943936f..66f2aca 100644 --- a/csrc/wrapper.hpp +++ b/csrc/wrapper.hpp @@ -35,6 +35,8 @@ unsigned char *data; int w; int h; + + int64_t id; }pic_bgr24; namespace buz{ @@ -42,11 +44,14 @@ struct avpacket; } - typedef std::function<std::shared_ptr<buz::Recorder>(ffwrapper::FormatIn*)> FN_REC; + // typedef std::function<std::shared_ptr<buz::Recorder>(ffwrapper::FormatIn*)> FN_REC; typedef struct _fn_rec{ - FN_REC fn_init; - std::shared_ptr<buz::Recorder> rec; + std::string rid; + std::string dir; + int min; + int max; + std::unique_ptr<buz::Recorder> rec; }FnRec; class Wrapper{ @@ -58,10 +63,10 @@ std::unique_ptr<ffwrapper::FormatIn> init_reader(const char* input); // ffwrapper::FormatIn* init_reader_gb28181(const char* input); void run_worker(ffwrapper::FormatIn *in, buz::avpacket &pkt); - std::shared_ptr<buz::Recorder> init_recorder(ffwrapper::FormatIn *in, std::string id,std::string dir, const int mind, const int maxd); + std::unique_ptr<buz::Recorder> init_recorder(ffwrapper::FormatIn *in, std::string id,std::string dir, const int mind, const int maxd); void cache_rec_info(std::string &id, int &index, std::string &path); - void cache_pic(std::shared_ptr<ffwrapper::FrameData> &frame); + void cache_pic(std::shared_ptr<ffwrapper::FrameData> &frame, int64_t &id); void cacheAVPacket(const AVPacket &pkt); public: @@ -80,7 +85,7 @@ void UseCPU(); public: //decoder void BuildDecoder(); - void GetPicDecoder(unsigned char **data, int *w, int *h); + void GetPicDecoder(unsigned char **data, int *w, int *h, int64_t *id); void GetPacket(unsigned char **pktData, int *size, int *key); //active api @@ -100,6 +105,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_; @@ -114,6 +120,18 @@ int scale_w_, scale_h_, scale_f_; int gb_, cpu_; + + typedef struct recpkt{ + std::shared_ptr<ffwrapper::CodedData> data; + int64_t id; + }recpkt; + std::list<recpkt> list_rec_pkt_; + std::mutex mtx_rec_pkt_; + int cache_rec_pkt(const buz::avpacket &pkt); + void maybe_dump_rec_pkt(); + int maxduration; + int minduration; + //////////////////test frame to bgr24 public: uint8_t *decodeJPEG(const char *file, int *w, int *h); diff --git a/goffmpeg.go b/goffmpeg.go index 8569084..d79d0ba 100644 --- a/goffmpeg.go +++ b/goffmpeg.go @@ -160,6 +160,7 @@ return int(i), path } +// GetRecID get rec id func (h *GoFFMPEG) GetRecID(p string) string { pt := C.CString(p) defer C.free(unsafe.Pointer(pt)) @@ -179,20 +180,21 @@ } // GetPicDecoder get pic from decoder -func (h *GoFFMPEG) GetPicDecoder() ([]byte, int, int) { +func (h *GoFFMPEG) GetPicDecoder() ([]byte, int, int, int64) { var width C.int var height C.int + var fid C.long - p := C.wrap_fn_decoder_pic(h.ffmpeg, &width, &height) + p := C.wrap_fn_decoder_pic(h.ffmpeg, &width, &height, &fid) if width == 0 && height == 0 { - return nil, 0, 0 + return nil, 0, 0, 0 } defer C.free(unsafe.Pointer(p)) d := C.GoBytes(p, width*height*3) wid := int(width) hei := int(height) - - return d, wid, hei + gfid := int64(fid) + return d, wid, hei, gfid } //GetAVPacket get AVPacket diff --git a/libcffmpeg.c b/libcffmpeg.c index a380de4..6cb7e5a 100644 --- a/libcffmpeg.c +++ b/libcffmpeg.c @@ -109,8 +109,8 @@ fn_decoder(h); } -void* wrap_fn_decoder_pic(const cffmpeg h, int* wid, int* hei){ - return fn_decoder_pic(h, wid, hei); +void* wrap_fn_decoder_pic(const cffmpeg h, int* wid, int* hei, int64_t *id){ + return fn_decoder_pic(h, wid, hei, id); } void* wrap_fn_get_avpacket(const cffmpeg h, int* size, int* key){ diff --git a/libcffmpeg.h b/libcffmpeg.h index 7c31723..cbcf14c 100644 --- a/libcffmpeg.h +++ b/libcffmpeg.h @@ -21,7 +21,7 @@ typedef char*(*lib_cffmpeg_info_recorder)(const cffmpeg, int*, int*); typedef char*(*lib_cffmpeg_rec_id)(const cffmpeg, const char*, int*); typedef void (*lib_cffmpeg_decoder)(const cffmpeg); -typedef void*(*lib_cffmpeg_pic)(const cffmpeg, int*, int*); +typedef void*(*lib_cffmpeg_pic)(const cffmpeg, int*, int*, int64_t*); typedef void*(*lib_cffmpeg_avpacket)(const cffmpeg, int*, int*); typedef void*(*lib_cffmpeg_decode_jpeg)(const cffmpeg, const char*, int*, int*); @@ -55,7 +55,7 @@ char* wrap_fn_info_recorder(const cffmpeg, int* index, int* length); char* wrap_fn_rec_id(const cffmpeg h, const char* path, int*length); void wrap_fn_decoder(const cffmpeg h); -void* wrap_fn_decoder_pic(const cffmpeg h, int* wid, int* hei); +void* wrap_fn_decoder_pic(const cffmpeg h, int* wid, int* hei, int64_t *id); void* wrap_fn_get_avpacket(const cffmpeg h, int* size, int* key); void* wrap_fn_decode_jpeg(const cffmpeg h, const char* file, int* wid, int* hei); -- Gitblit v1.8.0