添加win测试程序

This commit is contained in:
xiongziliang 2017-12-13 14:18:10 +08:00
parent 34176f0e2b
commit f347bec3cb
100 changed files with 10477 additions and 0 deletions

BIN
bin_lib/windows/ZLMediaKit.dll Executable file

Binary file not shown.

View File

@ -0,0 +1,37 @@
/*
* AACEncoder.h
*
* Created on: 2016811
* Author: xzl
*/
#ifndef CODEC_AACENCODER_H_
#define CODEC_AACENCODER_H_
namespace ZL {
namespace Codec {
class AACEncoder {
public:
AACEncoder(void);
virtual ~AACEncoder(void);
bool init(int iSampleRate, int iAudioChannel, int iAudioSampleBit);
int inputData(char *pcData, int iLen, unsigned char **ppucOutBuffer);
private:
unsigned char *m_pucPcmBuf = nullptr;
unsigned int m_uiPcmLen = 0;
unsigned char *m_pucAacBuf = nullptr;
void *m_hEncoder = nullptr;
unsigned long m_ulInputSamples = 0;
unsigned long m_ulMaxInputBytes = 0;
unsigned long m_ulMaxOutputBytes = 0;
};
} /* namespace Codec */
} /* namespace ZL */
#endif /* CODEC_AACENCODER_H_ */

View File

@ -0,0 +1,46 @@
/*
* H264Encoder.h
*
* Created on: 2016811
* Author: xzl
*/
#ifndef CODEC_H264ENCODER_H_
#define CODEC_H264ENCODER_H_
#include <cstdint>
#ifdef __cplusplus
extern "C" {
#endif //__cplusplus
#include <x264.h>
#ifdef __cplusplus
}
#endif //__cplusplus
namespace ZL {
namespace Codec {
class H264Encoder {
public:
typedef struct {
int iType;
int iLength;
uint8_t *pucData;
} H264Frame;
H264Encoder(void);
virtual ~H264Encoder(void);
bool init(int iWidth, int iHeight, int iFps);
int inputData(char *apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame **ppFrame);
private:
x264_t* m_pX264Handle = nullptr;
x264_picture_t* m_pPicIn = nullptr;
x264_picture_t* m_pPicOut = nullptr;
H264Frame m_aFrames[10];
};
} /* namespace Codec */
} /* namespace ZL */
#endif /* CODEC_H264ENCODER_H_ */

View File

@ -0,0 +1,25 @@
/*
* MediaSender.h
*
* Created on: 201691
* Author: xzl
*/
#ifndef SRC_MEDIASENDER_H_
#define SRC_MEDIASENDER_H_
#include "Thread/ThreadPool.h"
using namespace ZL::Thread;
class MediaSender {
public:
static ThreadPool & sendThread() {
static ThreadPool pool(1);
return pool;
}
private:
MediaSender();
virtual ~MediaSender();
};
#endif /* SRC_MEDIASENDER_H_ */

View File

@ -0,0 +1,164 @@
//
// appConfig.h
// ZLMedia
//
// Created by lyl on 16/10/22.
// Copyright © 2016年 jizan. All rights reserved.
//
#ifndef appConfig_h
#define appConfig_h
#include "Util/mini.h"
using namespace ZL::Util;
namespace Config {
void loaIniConfig();
////////////TCP最大连接数///////////
#ifdef __x86_64__
#define MAX_TCP_SESSION 100000
#else
#define MAX_TCP_SESSION 128
#endif
////////////其他宏定义///////////
#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b) )
#endif //MAX
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b) )
#endif //MIN
#ifndef CLEAR_ARR
#define CLEAR_ARR(arr) for(auto &item : arr){ item = 0;}
#endif //CLEAR_ARR
////////////广播名称///////////
namespace Broadcast {
extern const char kBroadcastRtspSessionPlay[];
#define BroadcastRtspSessionPlayArgs const char *app,const char *stream
extern const char kBroadcastRtspSrcRegisted[];
#define BroadcastRtspSrcRegistedArgs const char *app,const char *stream
extern const char kBroadcastRtmpSrcRegisted[];
#define BroadcastRtmpSrcRegistedArgs const char *app,const char *stream
extern const char kBroadcastRecordMP4[];
#define BroadcastRecordMP4Args const Mp4Info &info
extern const char kBroadcastHttpRequest[];
#define BroadcastHttpRequestArgs const Parser &parser,HttpSession::HttpResponseInvoker &invoker
} //namespace Broadcast
//代理失败最大重试次数
namespace Proxy {
extern const char kReplayCount[];
}//namespace Proxy
////////////HTTP配置///////////
namespace Http {
extern const char kPort[];
extern const char kSSLPort[];
//http 文件发送缓存大小
extern const char kSendBufSize[];
//http 最大请求字节数
extern const char kMaxReqSize[];
//http keep-alive秒数
extern const char kKeepAliveSecond[];
//http keep-alive最大请求数
extern const char kMaxReqCount[];
//http 字符编码
extern const char kCharSet[];
//http 服务器名称
extern const char kServerName[];
//http 服务器根目录
extern const char kRootPath[];
//http 404错误提示内容
extern const char kNotFound[];
//HTTP访问url前缀
extern const char kHttpPrefix[];
}//namespace Http
////////////SHELL配置///////////
namespace Shell {
extern const char kServerName[];
extern const char kMaxReqSize[];
extern const char kPort[];
} //namespace Shell
////////////RTSP服务器配置///////////
namespace Rtsp {
#define RTSP_VERSION 1.30
#define RTSP_BUILDTIME __DATE__" CST"
extern const char kServerName[];
extern const char kPort[];
} //namespace Rtsp
////////////RTMP服务器配置///////////
namespace Rtmp {
extern const char kPort[];
} //namespace RTMP
////////////RTP配置///////////
namespace Rtp {
//RTP打包最大MTU,公网情况下更小
extern const char kVideoMtuSize[];
//RTP打包最大MTU,公网情况下更小
extern const char kAudioMtuSize[];
//udp方式接受RTP包的最大缓存
extern const char kUdpBufSize[];
//RTP排序缓存最大个数
extern const char kMaxRtpCount[];
//如果RTP序列正确次数累计达到该数字就启动清空排序缓存
extern const char kClearCount[];
//最大RTP时间为13个小时每13小时回环一次
extern const char kCycleMS[];
} //namespace Rtsp
////////////组播配置///////////
namespace MultiCast {
//组播分配起始地址
extern const char kAddrMin[];
//组播分配截止地址
extern const char kAddrMax[];
//组播TTL
extern const char kUdpTTL[];
} //namespace MultiCast
////////////录像配置///////////
namespace Record {
//查看录像的应用名称
extern const char kAppName[];
//每次流化MP4文件的时长,单位毫秒
extern const char kSampleMS[];
//MP4文件录制大小,不能太大,否则MP4Close函数执行事件太长
extern const char kFileSecond[];
//Rtsp访问url前缀
extern const char kRtspPrefix[];
//录制文件路径
extern const char kFilePath[];
} //namespace Record
////////////HLS相关配置///////////
namespace Hls {
//HLS切片时长,单位秒
extern const char kSegmentDuration[];
//HLS切片个数
extern const char kSegmentNum[];
//HLS文件写缓存大小
extern const char kFileBufSize[];
//录制文件路径
extern const char kFilePath[];
} //namespace Hls
} // namespace Config
#endif /* appConfig_h */

View File

@ -0,0 +1,107 @@
/*
* Device.h
*
* Created on: 2016810
* Author: xzl
*/
#ifndef DEVICE_DEVICE_H_
#define DEVICE_DEVICE_H_
#include <memory>
#include <string>
#include <functional>
#include "Util/util.h"
#include "RTP/RtpMakerAAC.h"
#include "RTP/RtpMakerH264.h"
#include "Rtsp/RtspToRtmpMediaSource.h"
using namespace std;
using namespace ZL::Rtsp;
using namespace ZL::Util;
#ifdef ENABLE_FAAC
#include "Codec/AACEncoder.h"
using namespace ZL::Codec;
#endif //ENABLE_FAAC
#ifdef ENABLE_X264
#include "Codec/H264Encoder.h"
using namespace ZL::Codec;
#endif //ENABLE_X264
namespace ZL {
namespace DEV {
class VideoInfo {
public:
int iWidth;
int iHeight;
float iFrameRate;
};
class AudioInfo {
public:
int iChannel;
int iSampleBit;
int iSampleRate;
};
class DevChannel {
public:
typedef std::shared_ptr<DevChannel> Ptr;
DevChannel(const char *strApp, const char *strId,float fDuration = 0,bool bLiveStream = true);
virtual ~DevChannel();
void initVideo(const VideoInfo &info);
void initAudio(const AudioInfo &info);
void inputYUV(char *apcYuv[3], int aiYuvLen[3], uint32_t uiStamp);
void inputPCM(char *pcData, int iDataLen, uint32_t uiStamp);
void inputH264(char *pcData, int iDataLen, uint32_t uiStamp);
void inputAAC(char *pcData, int iDataLen, uint32_t uiStamp);
#ifdef ENABLE_RTSP2RTMP
int readerCount() {
return m_mediaSrc ? m_mediaSrc->readerCount() : 0;
}
void updateTimeStamp(uint32_t uiStamp){
m_mediaSrc->updateTimeStamp(uiStamp);
}
#endif //ENABLE_RTSP2RTMP
void setOnSeek(const function<bool(uint32_t)> &onSeek){
m_mediaSrc->setOnSeek(onSeek);
}
void setOnStamp(const function<uint32_t()> &cb) {
m_mediaSrc->setOnStamp(cb);
}
private:
inline void makeSDP_264(unsigned char *pucData, int iDataLen);
inline void makeSDP_AAC(unsigned char *pucData, int iDataLen);
inline void makeSDP(const string& strSdp);
#ifdef ENABLE_X264
std::shared_ptr<H264Encoder> m_pH264Enc;
#endif //ENABLE_X264
#ifdef ENABLE_FAAC
std::shared_ptr<AACEncoder> m_pAacEnc;
#endif //ENABLE_FAAC
RtpMaker_AAC::Ptr m_pRtpMaker_aac;
RtpMaker_H264::Ptr m_pRtpMaker_h264;
RtspToRtmpMediaSource::Ptr m_mediaSrc;
string m_strSDP;
bool m_bSdp_gotH264 = false;
bool m_bSdp_gotAAC = false;
unsigned char m_aucSPS[256];
unsigned int m_uiSPSLen = 0;
unsigned char m_aucPPS[256];
unsigned int m_uiPPSLen = 0;
std::shared_ptr<VideoInfo> m_video;
std::shared_ptr<AudioInfo> m_audio;
};
} /* namespace DEV */
} /* namespace ZL */
#endif /* DEVICE_DEVICE_H_ */

View File

@ -0,0 +1,51 @@
/*
* PlyerProxy.h
*
* Created on: 2016126
* Author: xzl
*/
#ifndef SRC_DEVICE_PLAYERPROXY_H_
#define SRC_DEVICE_PLAYERPROXY_H_
#include <memory>
#include "Device.h"
#include "Player/MediaPlayer.h"
#include "Util/TimeTicker.h"
using namespace std;
using namespace ZL::Player;
namespace ZL {
namespace DEV {
class PlayerProxy :public MediaPlayer, public std::enable_shared_from_this<PlayerProxy>{
public:
typedef std::shared_ptr<PlayerProxy> Ptr;
//设置代理时间0为永久其他为代理秒数
//设置方法proxy[PlayerProxy::kAliveSecond] = 100;
static const char kAliveSecond[];
PlayerProxy(const char *strApp, const char *strSrc);
virtual ~PlayerProxy();
void play(const char* strUrl) override;
void setOnExpired(const function<void()> &cb){
onExpired = cb;
}
private :
DevChannel::Ptr m_pChn;
Ticker m_aliveTicker;
uint32_t m_aliveSecond = 0;
function<void()> onExpired;
string m_strApp;
string m_strSrc;
void initMedia();
void rePlay(const string &strUrl,uint64_t iFailedCnt);
void checkExpired();
void expired();
};
} /* namespace Player */
} /* namespace ZL */
#endif /* SRC_DEVICE_PLAYERPROXY_H_ */

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com)
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
#ifndef AVUTIL_BASE64_H
#define AVUTIL_BASE64_H
#include <stdint.h>
/**
* Decode a base64-encoded string.
*
* @param out buffer for decoded data
* @param in null-terminated input string
* @param out_size size in bytes of the out buffer, must be at
* least 3/4 of the length of in
* @return number of bytes written, or a negative value in case of
* invalid input
*/
int av_base64_decode(uint8_t *out, const char *in, int out_size);
/**
* Encode data to base64 and null-terminate.
*
* @param out buffer for encoded data
* @param out_size size in bytes of the output buffer, must be at
* least AV_BASE64_SIZE(in_size)
* @param in_size size in bytes of the 'in' buffer
* @return 'out' or NULL in case of error
*/
char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size);
/**
* Calculate the output size needed to base64-encode x bytes.
*/
#define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1)
#endif /* AVUTIL_BASE64_H */

View File

@ -0,0 +1,58 @@
//
// H264Parser.h
// MediaPlayer
//
// Created by xzl on 2017/1/16.
// Copyright © 2017年 jizan. All rights reserved.
//
#ifndef H264Parser_h
#define H264Parser_h
#include <stdio.h>
#include <string>
#include "h264_poc.h"
#include "h264_parser.h"
using namespace std;
#ifndef INT32_MAX
#define INT32_MAX 0x7FFFFFFF
#endif//INT32_MAX
class H264Parser{
public:
H264Parser();
virtual ~H264Parser();
void inputH264(const string &h264,uint32_t dts);
int32_t getPOC() const{
return m_iNowPOC;
}
int getSliceType() const{
return m_shdr.slice_type;
}
int getNaluType() const{
return m_nalu.nal_unit_type;
}
uint32_t getPts() const{
return m_iNowPTS;
}
private:
media::H264Parser m_parser;
media::H264POC m_poc;
media::H264NALU m_nalu;
media::H264SliceHeader m_shdr;
int32_t m_iNowPOC = INT32_MAX;
int32_t m_iLastPOC = INT32_MAX;
uint32_t m_iNowPTS = INT32_MAX;
uint32_t m_iLastPTS = INT32_MAX;
int32_t m_iMsPerPOC = 30;
void computePts(uint32_t dts);
};
#endif /* H264Parser_hpp */

View File

@ -0,0 +1,192 @@
/***************************************************************************************
***************************************************************************************/
#ifndef _JZAN_SPS_PPS_H_
#define _JZAN_SPS_PPS_H_
#if defined (__cplusplus)
extern "C" {
#endif
#define QP_MAX_NUM (51 + 6*6) // The maximum supported qp
/**
* Chromaticity coordinates of the source primaries.
*/
enum T_AVColorPrimaries {
AVCOL_PRI_RESERVED0 = 0,
AVCOL_PRI_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B
AVCOL_PRI_UNSPECIFIED = 2,
AVCOL_PRI_RESERVED = 3,
AVCOL_PRI_BT470M = 4, ///< also FCC Title 47 Code of Federal Regulations 73.682 (a)(20)
AVCOL_PRI_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM
AVCOL_PRI_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC
AVCOL_PRI_SMPTE240M = 7, ///< functionally identical to above
AVCOL_PRI_FILM = 8, ///< colour filters using Illuminant C
AVCOL_PRI_BT2020 = 9, ///< ITU-R BT2020
AVCOL_PRI_NB, ///< Not part of ABI
};
/**
* Color Transfer Characteristic.
*/
enum T_AVColorTransferCharacteristic {
AVCOL_TRC_RESERVED0 = 0,
AVCOL_TRC_BT709 = 1, ///< also ITU-R BT1361
AVCOL_TRC_UNSPECIFIED = 2,
AVCOL_TRC_RESERVED = 3,
AVCOL_TRC_GAMMA22 = 4, ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM
AVCOL_TRC_GAMMA28 = 5, ///< also ITU-R BT470BG
AVCOL_TRC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC
AVCOL_TRC_SMPTE240M = 7,
AVCOL_TRC_LINEAR = 8, ///< "Linear transfer characteristics"
AVCOL_TRC_LOG = 9, ///< "Logarithmic transfer characteristic (100:1 range)"
AVCOL_TRC_LOG_SQRT = 10, ///< "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)"
AVCOL_TRC_IEC61966_2_4 = 11, ///< IEC 61966-2-4
AVCOL_TRC_BT1361_ECG = 12, ///< ITU-R BT1361 Extended Colour Gamut
AVCOL_TRC_IEC61966_2_1 = 13, ///< IEC 61966-2-1 (sRGB or sYCC)
AVCOL_TRC_BT2020_10 = 14, ///< ITU-R BT2020 for 10 bit system
AVCOL_TRC_BT2020_12 = 15, ///< ITU-R BT2020 for 12 bit system
AVCOL_TRC_NB, ///< Not part of ABI
};
/**
* YUV tColorspace type.
*/
enum T_AVColorSpace {
AVCOL_SPC_RGB = 0, ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB)
AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B
AVCOL_SPC_UNSPECIFIED = 2,
AVCOL_SPC_RESERVED = 3,
AVCOL_SPC_FCC = 4, ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20)
AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601
AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above
AVCOL_SPC_SMPTE240M = 7,
AVCOL_SPC_YCOCG = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16
AVCOL_SPC_BT2020_NCL = 9, ///< ITU-R BT2020 non-constant luminance system
AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system
AVCOL_SPC_NB, ///< Not part of ABI
};
/**
* rational number numerator/denominator
*/
typedef struct T_AVRational{
int num; ///< numerator
int den; ///< denominator
} T_AVRational;
/***
* Sequence parameter set
* ¿É²Î¿¼H264±ê×¼µÚ7½ÚºÍ¸½Â¼D E
*/
#define Extended_SAR 255
/**
* Sequence parameter set
*/
typedef struct T_SPS {
unsigned int uiSpsId;
int iProfileIdc;
int iLevelIdc;
int iChromaFormatIdc;
int iTransformBypass; ///< qpprime_y_zero_transform_bypass_flag
int iLog2MaxFrameNum; ///< log2_max_frame_num_minus4 + 4
int iPocType; ///< pic_order_cnt_type
int iLog2MaxPocLsb; ///< log2_max_pic_order_cnt_lsb_minus4
int iDeltaPicOrderAlwaysZeroFlag;
int iOffsetForNonRefPic;
int iOffsetForTopToBottomField;
int iPocCycleLength; ///< num_ref_frames_in_pic_order_cnt_cycle
int iRefFrameCount; ///< num_ref_frames
int iGapsInFrameNumAllowedFlag;
int iMbWidth; ///< pic_width_in_mbs_minus1 + 1
int iMbHeight; ///< pic_height_in_map_units_minus1 + 1
int iFrameMbsOnlyFlag;
int iMbAff; ///< mb_adaptive_frame_field_flag
int iDirect8x8InferenceFlag;
int iCrop; ///< frame_cropping_flag
/* those 4 are already in luma samples */
unsigned int uiCropLeft; ///< frame_cropping_rect_left_offset
unsigned int uiCropRight; ///< frame_cropping_rect_right_offset
unsigned int uiCropTop; ///< frame_cropping_rect_top_offset
unsigned int uiCropBottom; ///< frame_cropping_rect_bottom_offset
int iVuiParametersPresentFlag;
T_AVRational tSar;
int iVideoSignalTypePresentFlag;
int iFullRange;
int iColourDescriptionPresentFlag;
enum T_AVColorPrimaries tColorPrimaries;
enum T_AVColorTransferCharacteristic tColorTrc;
enum T_AVColorSpace tColorspace;
int iTimingInfoPresentFlag;
uint32_t u32NumUnitsInTick;
uint32_t u32TimeScale;
int iFixedFrameRateFlag;
short asOffsetForRefFrame[256]; // FIXME dyn aloc?
int iBitstreamRestrictionFlag;
int iNumReorderFrames;
int iScalingMatrixPresent;
uint8_t aau8ScalingMatrix4[6][16];
uint8_t aau8ScalingMatrix8[6][64];
int iNalHrdParametersPresentFlag;
int iVclHrdParametersPresentFlag;
int iPicStructPresentFlag;
int iTimeOffsetLength;
int iCpbCnt; ///< See H.264 E.1.2
int iInitialCpbRemovalDelayLength; ///< initial_cpb_removal_delay_length_minus1 + 1
int iCpbRemovalDelayLength; ///< cpb_removal_delay_length_minus1 + 1
int iDpbOutputDelayLength; ///< dpb_output_delay_length_minus1 + 1
int iBitDepthLuma; ///< bit_depth_luma_minus8 + 8
int iBitDepthChroma; ///< bit_depth_chroma_minus8 + 8
int iResidualColorTransformFlag; ///< residual_colour_transform_flag
int iConstraintSetFlags; ///< constraint_set[0-3]_flag
int iNew; ///< flag to keep track if the decoder context needs re-init due to changed SPS
} T_SPS;
/**
* Picture parameter set
*/
typedef struct T_PPS {
unsigned int uiSpsId;
int iCabac; ///< entropy_coding_mode_flag
int iPicOrderPresent; ///< pic_order_present_flag
int iSliceGroupCount; ///< num_slice_groups_minus1 + 1
int iMbSliceGroupMapType;
unsigned int auiRefCount[2]; ///< num_ref_idx_l0/1_active_minus1 + 1
int iWeightedPred; ///< weighted_pred_flag
int iWeightedBipredIdc;
int iInitQp; ///< pic_init_qp_minus26 + 26
int iInitQs; ///< pic_init_qs_minus26 + 26
int aiChromaQpIndexOffset[2];
int iDeblockingFilterParametersPresent; ///< deblocking_filter_parameters_present_flag
int iConstrainedIntraPred; ///< constrained_intra_pred_flag
int iRedundantPicCntPresent; ///< redundant_pic_cnt_present_flag
int iTransform8x8Mode; ///< transform_8x8_mode_flag
uint8_t aau8ScalingMatrix4[6][16];
uint8_t aau8ScalingMatrix8[6][64];
uint8_t u8ChromaQpTable[2][QP_MAX_NUM+1]; ///< pre-scaled (with aiChromaQpIndexOffset) version of qp_table
int iChromaQpDiff;
} T_PPS;
typedef struct T_GetBitContext{
uint8_t *pu8Buf; /*Ö¸ÏòSPS start*/
int iBufSize; /*SPS ³¤¶È*/
int iBitPos; /*bitÒѶÁȡλÖÃ*/
int iTotalBit; /*bit×ܳ¤¶È*/
int iCurBitPos; /*µ±Ç°¶ÁȡλÖÃ*/
}T_GetBitContext;
int h264DecSeqParameterSet(void *pvBuf, T_SPS *ptSps);
void h264GetWidthHeight(T_SPS *ptSps, int *piWidth, int *piHeight);
void h264GeFramerate(T_SPS *ptSps, float *pfFramerate);
#if defined (__cplusplus)
}
#endif
#endif

View File

@ -0,0 +1,81 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This file contains an implementation of an H264 Annex-B video stream parser.
#ifndef MEDIA_FILTERS_H264_BIT_READER_H_
#define MEDIA_FILTERS_H264_BIT_READER_H_
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include "macros.h"
using namespace std;
namespace media {
// A class to provide bit-granularity reading of H.264 streams.
// This is not a generic bit reader class, as it takes into account
// H.264 stream-specific constraints, such as skipping emulation-prevention
// bytes and stop bits. See spec for more details.
class MEDIA_EXPORT H264BitReader {
public:
H264BitReader();
~H264BitReader();
// Initialize the reader to start reading at |data|, |size| being size
// of |data| in bytes.
// Return false on insufficient size of stream..
// TODO(posciak,fischman): consider replacing Initialize() with
// heap-allocating and creating bit readers on demand instead.
bool Initialize(const uint8_t* data, off_t size);
// Read |num_bits| next bits from stream and return in |*out|, first bit
// from the stream starting at |num_bits| position in |*out|.
// |num_bits| may be 1-32, inclusive.
// Return false if the given number of bits cannot be read (not enough
// bits in the stream), true otherwise.
bool ReadBits(int num_bits, int* out);
// Return the number of bits left in the stream.
off_t NumBitsLeft();
// See the definition of more_rbsp_data() in spec.
bool HasMoreRBSPData();
// Return the number of emulation prevention bytes already read.
size_t NumEmulationPreventionBytesRead();
private:
// Advance to the next byte, loading it into curr_byte_.
// Return false on end of stream.
bool UpdateCurrByte();
// Pointer to the next unread (not in curr_byte_) byte in the stream.
const uint8_t* data_;
// Bytes left in the stream (without the curr_byte_).
off_t bytes_left_;
// Contents of the current byte; first unread bit starting at position
// 8 - num_remaining_bits_in_curr_byte_ from MSB.
int curr_byte_;
// Number of bits remaining in curr_byte_
int num_remaining_bits_in_curr_byte_;
// Used in emulation prevention three byte detection (see spec).
// Initially set to 0xffff to accept all initial two-byte sequences.
int prev_two_bytes_;
// Number of emulation preventation bytes (0x000003) we met.
size_t emulation_prevention_bytes_;
DISALLOW_COPY_AND_ASSIGN(H264BitReader);
};
} // namespace media
#endif // MEDIA_FILTERS_H264_BIT_READER_H_

View File

@ -0,0 +1,491 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This file contains an implementation of an H264 Annex-B video stream parser.
#ifndef MEDIA_FILTERS_H264_PARSER_H_
#define MEDIA_FILTERS_H264_PARSER_H_
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include <map>
#include <vector>
#include "macros.h"
#include "h264_bit_reader.h"
#include "ranges.h"
using namespace std;
namespace media {
struct SubsampleEntry {
uint32_t clear_bytes;
uint32_t cypher_bytes;
};
// For explanations of each struct and its members, see H.264 specification
// at http://www.itu.int/rec/T-REC-H.264.
struct MEDIA_EXPORT H264NALU {
H264NALU();
enum Type {
kUnspecified = 0,
kNonIDRSlice = 1,
kSliceDataA = 2,
kSliceDataB = 3,
kSliceDataC = 4,
kIDRSlice = 5,
kSEIMessage = 6,
kSPS = 7,
kPPS = 8,
kAUD = 9,
kEOSeq = 10,
kEOStream = 11,
kFiller = 12,
kSPSExt = 13,
kReserved14 = 14,
kReserved15 = 15,
kReserved16 = 16,
kReserved17 = 17,
kReserved18 = 18,
kCodedSliceAux = 19,
kCodedSliceExtension = 20,
};
// After (without) start code; we don't own the underlying memory
// and a shallow copy should be made when copying this struct.
const uint8_t* data;
off_t size; // From after start code to start code of next NALU (or EOS).
int nal_ref_idc;
int nal_unit_type;
};
enum {
kH264ScalingList4x4Length = 16,
kH264ScalingList8x8Length = 64,
};
struct MEDIA_EXPORT H264SPS {
H264SPS();
enum H264ProfileIDC {
kProfileIDCBaseline = 66,
kProfileIDCConstrainedBaseline = kProfileIDCBaseline,
kProfileIDCMain = 77,
kProfileIDScalableBaseline = 83,
kProfileIDScalableHigh = 86,
kProfileIDCHigh = 100,
kProfileIDHigh10 = 110,
kProfileIDSMultiviewHigh = 118,
kProfileIDHigh422 = 122,
kProfileIDStereoHigh = 128,
kProfileIDHigh444Predictive = 244,
};
enum AspectRatioIdc {
kExtendedSar = 255,
};
enum {
// Constants for HRD parameters (spec ch. E.2.2).
kBitRateScaleConstantTerm = 6, // Equation E-37.
kCPBSizeScaleConstantTerm = 4, // Equation E-38.
kDefaultInitialCPBRemovalDelayLength = 24,
kDefaultDPBOutputDelayLength = 24,
kDefaultTimeOffsetLength = 24,
};
int profile_idc;
bool constraint_set0_flag;
bool constraint_set1_flag;
bool constraint_set2_flag;
bool constraint_set3_flag;
bool constraint_set4_flag;
bool constraint_set5_flag;
int level_idc;
int seq_parameter_set_id;
int chroma_format_idc;
bool separate_colour_plane_flag;
int bit_depth_luma_minus8;
int bit_depth_chroma_minus8;
bool qpprime_y_zero_transform_bypass_flag;
bool seq_scaling_matrix_present_flag;
int scaling_list4x4[6][kH264ScalingList4x4Length];
int scaling_list8x8[6][kH264ScalingList8x8Length];
int log2_max_frame_num_minus4;
int pic_order_cnt_type;
int log2_max_pic_order_cnt_lsb_minus4;
bool delta_pic_order_always_zero_flag;
int offset_for_non_ref_pic;
int offset_for_top_to_bottom_field;
int num_ref_frames_in_pic_order_cnt_cycle;
int expected_delta_per_pic_order_cnt_cycle; // calculated
int offset_for_ref_frame[255];
int max_num_ref_frames;
bool gaps_in_frame_num_value_allowed_flag;
int pic_width_in_mbs_minus1;
int pic_height_in_map_units_minus1;
bool frame_mbs_only_flag;
bool mb_adaptive_frame_field_flag;
bool direct_8x8_inference_flag;
bool frame_cropping_flag;
int frame_crop_left_offset;
int frame_crop_right_offset;
int frame_crop_top_offset;
int frame_crop_bottom_offset;
bool vui_parameters_present_flag;
int sar_width; // Set to 0 when not specified.
int sar_height; // Set to 0 when not specified.
bool bitstream_restriction_flag;
int max_num_reorder_frames;
int max_dec_frame_buffering;
bool timing_info_present_flag;
int num_units_in_tick;
int time_scale;
bool fixed_frame_rate_flag;
// TODO(posciak): actually parse these instead of ParseAndIgnoreHRDParameters.
bool nal_hrd_parameters_present_flag;
int cpb_cnt_minus1;
int bit_rate_scale;
int cpb_size_scale;
int bit_rate_value_minus1[32];
int cpb_size_value_minus1[32];
bool cbr_flag[32];
int initial_cpb_removal_delay_length_minus_1;
int cpb_removal_delay_length_minus1;
int dpb_output_delay_length_minus1;
int time_offset_length;
bool low_delay_hrd_flag;
int chroma_array_type;
};
struct MEDIA_EXPORT H264PPS {
H264PPS();
int pic_parameter_set_id;
int seq_parameter_set_id;
bool entropy_coding_mode_flag;
bool bottom_field_pic_order_in_frame_present_flag;
int num_slice_groups_minus1;
// TODO(posciak): Slice groups not implemented, could be added at some point.
int num_ref_idx_l0_default_active_minus1;
int num_ref_idx_l1_default_active_minus1;
bool weighted_pred_flag;
int weighted_bipred_idc;
int pic_init_qp_minus26;
int pic_init_qs_minus26;
int chroma_qp_index_offset;
bool deblocking_filter_control_present_flag;
bool constrained_intra_pred_flag;
bool redundant_pic_cnt_present_flag;
bool transform_8x8_mode_flag;
bool pic_scaling_matrix_present_flag;
int scaling_list4x4[6][kH264ScalingList4x4Length];
int scaling_list8x8[6][kH264ScalingList8x8Length];
int second_chroma_qp_index_offset;
};
struct MEDIA_EXPORT H264ModificationOfPicNum {
int modification_of_pic_nums_idc;
union {
int abs_diff_pic_num_minus1;
int long_term_pic_num;
};
};
struct MEDIA_EXPORT H264WeightingFactors {
bool luma_weight_flag;
bool chroma_weight_flag;
int luma_weight[32];
int luma_offset[32];
int chroma_weight[32][2];
int chroma_offset[32][2];
};
struct MEDIA_EXPORT H264DecRefPicMarking {
int memory_mgmnt_control_operation;
int difference_of_pic_nums_minus1;
int long_term_pic_num;
int long_term_frame_idx;
int max_long_term_frame_idx_plus1;
};
struct MEDIA_EXPORT H264SliceHeader {
H264SliceHeader();
enum {
kRefListSize = 32,
kRefListModSize = kRefListSize
};
enum Type {
kPSlice = 0,
kBSlice = 1,
kISlice = 2,
kSPSlice = 3,
kSISlice = 4,
};
bool IsPSlice() const;
bool IsBSlice() const;
bool IsISlice() const;
bool IsSPSlice() const;
bool IsSISlice() const;
bool idr_pic_flag; // from NAL header
int nal_ref_idc; // from NAL header
const uint8_t* nalu_data; // from NAL header
off_t nalu_size; // from NAL header
off_t header_bit_size; // calculated
int first_mb_in_slice;
int slice_type;
int pic_parameter_set_id;
int colour_plane_id; // TODO(posciak): use this! http://crbug.com/139878
int frame_num;
bool field_pic_flag;
bool bottom_field_flag;
int idr_pic_id;
int pic_order_cnt_lsb;
int delta_pic_order_cnt_bottom;
int delta_pic_order_cnt0;
int delta_pic_order_cnt1;
int redundant_pic_cnt;
bool direct_spatial_mv_pred_flag;
bool num_ref_idx_active_override_flag;
int num_ref_idx_l0_active_minus1;
int num_ref_idx_l1_active_minus1;
bool ref_pic_list_modification_flag_l0;
bool ref_pic_list_modification_flag_l1;
H264ModificationOfPicNum ref_list_l0_modifications[kRefListModSize];
H264ModificationOfPicNum ref_list_l1_modifications[kRefListModSize];
int luma_log2_weight_denom;
int chroma_log2_weight_denom;
bool luma_weight_l0_flag;
bool chroma_weight_l0_flag;
H264WeightingFactors pred_weight_table_l0;
bool luma_weight_l1_flag;
bool chroma_weight_l1_flag;
H264WeightingFactors pred_weight_table_l1;
bool no_output_of_prior_pics_flag;
bool long_term_reference_flag;
bool adaptive_ref_pic_marking_mode_flag;
H264DecRefPicMarking ref_pic_marking[kRefListSize];
int cabac_init_idc;
int slice_qp_delta;
bool sp_for_switch_flag;
int slice_qs_delta;
int disable_deblocking_filter_idc;
int slice_alpha_c0_offset_div2;
int slice_beta_offset_div2;
// Calculated.
// Size in bits of dec_ref_pic_marking() syntax element.
size_t dec_ref_pic_marking_bit_size;
size_t pic_order_cnt_bit_size;
};
struct H264SEIRecoveryPoint {
int recovery_frame_cnt;
bool exact_match_flag;
bool broken_link_flag;
int changing_slice_group_idc;
};
struct MEDIA_EXPORT H264SEIMessage {
H264SEIMessage();
enum Type {
kSEIRecoveryPoint = 6,
};
int type;
int payload_size;
union {
// Placeholder; in future more supported types will contribute to more
// union members here.
H264SEIRecoveryPoint recovery_point;
};
};
// Class to parse an Annex-B H.264 stream,
// as specified in chapters 7 and Annex B of the H.264 spec.
class MEDIA_EXPORT H264Parser {
public:
enum Result {
kOk,
kInvalidStream, // error in stream
kUnsupportedStream, // stream not supported by the parser
kEOStream, // end of stream
};
// Find offset from start of data to next NALU start code
// and size of found start code (3 or 4 bytes).
// If no start code is found, offset is pointing to the first unprocessed byte
// (i.e. the first byte that was not considered as a possible start of a start
// code) and |*start_code_size| is set to 0.
// Preconditions:
// - |data_size| >= 0
// Postconditions:
// - |*offset| is between 0 and |data_size| included.
// It is strictly less than |data_size| if |data_size| > 0.
// - |*start_code_size| is either 0, 3 or 4.
static bool FindStartCode(const uint8_t* data,
off_t data_size,
off_t* offset,
off_t* start_code_size);
// Wrapper for FindStartCode() that skips over start codes that
// may appear inside of |encrypted_ranges_|.
// Returns true if a start code was found. Otherwise returns false.
static bool FindStartCodeInClearRanges(const uint8_t* data,
off_t data_size,
const Ranges<const uint8_t*>& ranges,
off_t* offset,
off_t* start_code_size);
H264Parser();
~H264Parser();
void Reset();
// Set current stream pointer to |stream| of |stream_size| in bytes,
// |stream| owned by caller.
// |subsamples| contains information about what parts of |stream| are
// encrypted.
void SetStream(const uint8_t* stream, off_t stream_size);
void SetEncryptedStream(const uint8_t* stream,
off_t stream_size,
const std::vector<SubsampleEntry>& subsamples);
// Read the stream to find the next NALU, identify it and return
// that information in |*nalu|. This advances the stream to the beginning
// of this NALU, but not past it, so subsequent calls to NALU-specific
// parsing functions (ParseSPS, etc.) will parse this NALU.
// If the caller wishes to skip the current NALU, it can call this function
// again, instead of any NALU-type specific parse functions below.
Result AdvanceToNextNALU(H264NALU* nalu);
// NALU-specific parsing functions.
// These should be called after AdvanceToNextNALU().
// SPSes and PPSes are owned by the parser class and the memory for their
// structures is managed here, not by the caller, as they are reused
// across NALUs.
//
// Parse an SPS/PPS NALU and save their data in the parser, returning id
// of the parsed structure in |*pps_id|/|*sps_id|.
// To get a pointer to a given SPS/PPS structure, use GetSPS()/GetPPS(),
// passing the returned |*sps_id|/|*pps_id| as parameter.
// TODO(posciak,fischman): consider replacing returning Result from Parse*()
// methods with a scoped_ptr and adding an AtEOS() function to check for EOS
// if Parse*() return NULL.
Result ParseSPS(int* sps_id);
Result ParsePPS(int* pps_id);
// Return a pointer to SPS/PPS with given |sps_id|/|pps_id| or NULL if not
// present.
const H264SPS* GetSPS(int sps_id) const;
const H264PPS* GetPPS(int pps_id) const;
// Slice headers and SEI messages are not used across NALUs by the parser
// and can be discarded after current NALU, so the parser does not store
// them, nor does it manage their memory.
// The caller has to provide and manage it instead.
// Parse a slice header, returning it in |*shdr|. |*nalu| must be set to
// the NALU returned from AdvanceToNextNALU() and corresponding to |*shdr|.
Result ParseSliceHeader(const H264NALU& nalu, H264SliceHeader* shdr);
// Parse a SEI message, returning it in |*sei_msg|, provided and managed
// by the caller.
Result ParseSEI(H264SEIMessage* sei_msg);
private:
// Move the stream pointer to the beginning of the next NALU,
// i.e. pointing at the next start code.
// Return true if a NALU has been found.
// If a NALU is found:
// - its size in bytes is returned in |*nalu_size| and includes
// the start code as well as the trailing zero bits.
// - the size in bytes of the start code is returned in |*start_code_size|.
bool LocateNALU(off_t* nalu_size, off_t* start_code_size);
// Exp-Golomb code parsing as specified in chapter 9.1 of the spec.
// Read one unsigned exp-Golomb code from the stream and return in |*val|.
Result ReadUE(int* val);
// Read one signed exp-Golomb code from the stream and return in |*val|.
Result ReadSE(int* val);
// Parse scaling lists (see spec).
Result ParseScalingList(int size, int* scaling_list, bool* use_default);
Result ParseSPSScalingLists(H264SPS* sps);
Result ParsePPSScalingLists(const H264SPS& sps, H264PPS* pps);
// Parse optional VUI parameters in SPS (see spec).
Result ParseVUIParameters(H264SPS* sps);
// Set |hrd_parameters_present| to true only if they are present.
Result ParseAndIgnoreHRDParameters(bool* hrd_parameters_present);
// Parse reference picture lists' modifications (see spec).
Result ParseRefPicListModifications(H264SliceHeader* shdr);
Result ParseRefPicListModification(int num_ref_idx_active_minus1,
H264ModificationOfPicNum* ref_list_mods);
// Parse prediction weight table (see spec).
Result ParsePredWeightTable(const H264SPS& sps, H264SliceHeader* shdr);
// Parse weighting factors (see spec).
Result ParseWeightingFactors(int num_ref_idx_active_minus1,
int chroma_array_type,
int luma_log2_weight_denom,
int chroma_log2_weight_denom,
H264WeightingFactors* w_facts);
// Parse decoded reference picture marking information (see spec).
Result ParseDecRefPicMarking(H264SliceHeader* shdr);
// Pointer to the current NALU in the stream.
const uint8_t* stream_;
// Bytes left in the stream after the current NALU.
off_t bytes_left_;
H264BitReader br_;
// PPSes and SPSes stored for future reference.
typedef std::map<int, H264SPS*> SPSById;
typedef std::map<int, H264PPS*> PPSById;
SPSById active_SPSes_;
PPSById active_PPSes_;
// Ranges of encrypted bytes in the buffer passed to
// SetEncryptedStream().
Ranges<const uint8_t*> encrypted_ranges_;
DISALLOW_COPY_AND_ASSIGN(H264Parser);
};
} // namespace media
#endif // MEDIA_FILTERS_H264_PARSER_H_

View File

@ -0,0 +1,45 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_VIDEO_H264_POC_H_
#define MEDIA_VIDEO_H264_POC_H_
#include <stdint.h>
#include "macros.h"
using namespace std;
namespace media {
struct H264SPS;
struct H264SliceHeader;
class MEDIA_EXPORT H264POC {
public:
H264POC();
~H264POC();
// Compute the picture order count for a slice, storing the result into
// |*pic_order_cnt|.
bool ComputePicOrderCnt(
const H264SPS* sps,
const H264SliceHeader& slice_hdr,
int32_t* pic_order_cnt);
// Reset computation state. It's best (although not strictly required) to call
// this after a seek.
void Reset();
private:
int32_t ref_pic_order_cnt_msb_;
int32_t ref_pic_order_cnt_lsb_;
int32_t prev_frame_num_;
int32_t prev_frame_num_offset_;
DISALLOW_COPY_AND_ASSIGN(H264POC);
};
} // namespace media
#endif // MEDIA_VIDEO_H264_POC_H_

View File

@ -0,0 +1,100 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains macros and macro-like constructs (e.g., templates) that
// are commonly used throughout Chromium source. (It may also contain things
// that are closely related to things that are commonly used that belong in this
// file.)
#ifndef BASE_MACROS_H_
#define BASE_MACROS_H_
#include <stddef.h> // For size_t.
// Put this in the declarations for a class to be uncopyable.
#define DISALLOW_COPY(TypeName) \
TypeName(const TypeName&) = delete
// Put this in the declarations for a class to be unassignable.
#define DISALLOW_ASSIGN(TypeName) \
void operator=(const TypeName&) = delete
// A macro to disallow the copy constructor and operator= functions.
// This should be used in the private: declarations for a class.
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
//
// This should be used in the private: declarations for a class
// that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods.
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName() = delete; \
DISALLOW_COPY_AND_ASSIGN(TypeName)
// The arraysize(arr) macro returns the # of elements in an array arr. The
// expression is a compile-time constant, and therefore can be used in defining
// new arrays, for example. If you use arraysize on a pointer by mistake, you
// will get a compile-time error. For the technical details, refer to
// http://blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx.
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
// Used to explicitly mark the return value of a function as unused. If you are
// really sure you don't want to do anything with the return value of a function
// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
//
// std::unique_ptr<MyType> my_var = ...;
// if (TakeOwnership(my_var.get()) == SUCCESS)
// ignore_result(my_var.release());
//
template<typename T>
inline void ignore_result(const T&) {
}
// The following enum should be used only as a constructor argument to indicate
// that the variable has static storage class, and that the constructor should
// do nothing to its state. It indicates to the reader that it is legal to
// declare a static instance of the class, provided the constructor is given
// the base::LINKER_INITIALIZED argument. Normally, it is unsafe to declare a
// static variable that has a constructor or a destructor because invocation
// order is undefined. However, IF the type can be initialized by filling with
// zeroes (which the loader does for static variables), AND the destructor also
// does nothing to the storage, AND there are no virtual methods, then a
// constructor declared as
// explicit MyClass(base::LinkerInitialized x) {}
// and invoked as
// static MyClass my_variable_name(base::LINKER_INITIALIZED);
namespace base {
enum LinkerInitialized { LINKER_INITIALIZED };
// Use these to declare and define a static local variable (static T;) so that
// it is leaked so that its destructors are not called at exit. If you need
// thread-safe initialization, use base/lazy_instance.h instead.
#define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \
static type& name = *new type arguments
} // base
#define MEDIA_EXPORT
#include <assert.h>
#include "Util/logger.h"
using namespace ZL::Util;
#define DCHECK(x) if(!(x)) { ErrorL << "DCHECK " << #x <<endl; }
#define DCHECK_GT(x,y) if(!((x) > (y))) { ErrorL << "DCHECK_GT:" << #x << #y << endl; }
#define DCHECK_GE(x,y) if(!((x) >= (y))) { ErrorL << "DCHECK_GE:" << #x << #y << endl; }
#define DCHECK_LT(x,y) if(!((x) < (y))) { ErrorL << "DCHECK_LT:" << #x << #y << endl; }
#define NOTREACHED() ErrorL << "NOTREACHED" << endl;
#endif // BASE_MACROS_H_

View File

@ -0,0 +1,154 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_BASE_RANGES_H_
#define MEDIA_BASE_RANGES_H_
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <ostream>
#include <vector>
using namespace std;
namespace media {
// Ranges allows holding an ordered list of ranges of [start,end) intervals.
// The canonical example use-case is holding the list of ranges of buffered
// bytes or times in a <video> tag.
template <typename T> // Endpoint type; typically a base::TimeDelta or an int64_t.
class Ranges {
public:
// Allow copy & assign.
// Add (start,end) to this object, coallescing overlaps as appropriate.
// Returns the number of stored ranges, post coallescing.
size_t Add(T start, T end);
// Return the number of disjoint ranges.
size_t size() const;
// Return the "i"'th range's start & end (0-based).
T start(size_t i) const;
T end(size_t i) const;
// Clear all ranges.
void clear();
// Computes the intersection between this range and |other|.
Ranges<T> IntersectionWith(const Ranges<T>& other) const;
private:
// Wrapper around DCHECK_LT allowing comparisons of operator<<'able T's.
void DCheckLT(const T& lhs, const T& rhs) const;
// Disjoint, in increasing order of start.
std::vector<std::pair<T, T> > ranges_;
};
//////////////////////////////////////////////////////////////////////
// EVERYTHING BELOW HERE IS IMPLEMENTATION DETAIL!!
//////////////////////////////////////////////////////////////////////
template<class T>
size_t Ranges<T>::Add(T start, T end) {
if (start == end) // Nothing to be done with empty ranges.
return ranges_.size();
//DCheckLT(start, end);
size_t i;
// Walk along the array of ranges until |start| is no longer larger than the
// current interval's end.
for (i = 0; i < ranges_.size() && ranges_[i].second < start; ++i) {
// Empty body
}
// Now we know |start| belongs in the i'th slot.
// If i is the end of the range, append new range and done.
if (i == ranges_.size()) {
ranges_.push_back(std::make_pair(start, end));
return ranges_.size();
}
// If |end| is less than i->first, then [start,end) is a new (non-overlapping)
// i'th entry pushing everyone else back, and done.
if (end < ranges_[i].first) {
ranges_.insert(ranges_.begin() + i, std::make_pair(start, end));
return ranges_.size();
}
// Easy cases done. Getting here means there is overlap between [start,end)
// and the existing ranges.
// Now: start <= i->second && i->first <= end
if (start < ranges_[i].first)
ranges_[i].first = start;
if (ranges_[i].second < end)
ranges_[i].second = end;
// Now: [start,end) is contained in the i'th range, and we'd be done, except
// for the fact that the newly-extended i'th range might now overlap
// subsequent ranges. Merge until discontinuities appear. Note that there's
// no need to test/merge previous ranges, since needing that would mean the
// original loop went too far.
while ((i + 1) < ranges_.size() &&
ranges_[i + 1].first <= ranges_[i].second) {
ranges_[i].second = max(ranges_[i].second, ranges_[i + 1].second);
ranges_.erase(ranges_.begin() + i + 1);
}
return ranges_.size();
}
template<class T>
size_t Ranges<T>::size() const {
return ranges_.size();
}
template<class T>
T Ranges<T>::start(size_t i) const {
return ranges_[i].first;
}
template<class T>
T Ranges<T>::end(size_t i) const {
return ranges_[i].second;
}
template<class T>
void Ranges<T>::clear() {
ranges_.clear();
}
template<class T>
Ranges<T> Ranges<T>::IntersectionWith(const Ranges<T>& other) const {
Ranges<T> result;
size_t i = 0;
size_t j = 0;
while (i < size() && j < other.size()) {
T max_start = max(start(i), other.start(j));
T min_end = min(end(i), other.end(j));
// Add an intersection range to the result if the ranges overlap.
if (max_start < min_end)
result.Add(max_start, min_end);
if (end(i) < other.end(j))
++i;
else
++j;
}
return result;
}
} // namespace media
#endif // MEDIA_BASE_RANGES_H_

View File

@ -0,0 +1,130 @@
//
// HttpClient.h
// ZLMediaKit
//
// Created by xzl on 2017/5/4.
//
#ifndef Http_HttpClient_h
#define Http_HttpClient_h
#include <string.h>
#include <functional>
#include <memory>
#include "Rtsp/Rtsp.h"
#include "Util/util.h"
#include "Network/TcpClient.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Network;
namespace ZL {
namespace Http {
class HttpArgs : public StrCaseMap
{
public:
HttpArgs(){}
virtual ~HttpArgs(){}
string make() const {
string ret;
for(auto &pr : *this){
ret.append(pr.first);
ret.append("=");
ret.append(pr.second);
ret.append("&");
}
if(ret.size()){
ret.pop_back();
}
return ret;
}
};
class HttpClient : public TcpClient
{
public:
typedef StrCaseMap HttpHeader;
typedef std::shared_ptr<HttpClient> Ptr;
HttpClient();
virtual ~HttpClient();
virtual void sendRequest(const string &url);
void clear(){
_header.clear();
_body.clear();
_method.clear();
_path.clear();
_recvedResponse.clear();
_parser.Clear();
}
void setMethod(const string &method){
_method = method;
}
void setHeader(const HttpHeader &header){
_header = header;
}
void addHeader(const string &key,const string &val){
_header.emplace(key,val);
}
void setBody(const string &body){
_body = body;
}
const string &responseStatus(){
return _parser.Url();
}
const HttpHeader &responseHeader(){
return _parser.getValues();
}
protected:
bool _isHttps;
virtual void onResponseHeader(const string &status,const HttpHeader &headers){
DebugL << status;
};
virtual void onResponseBody(const char *buf,size_t size,size_t recvedSize,size_t totalSize){
DebugL << size << " " << recvedSize << " " << totalSize;
};
virtual void onResponseCompleted(){
DebugL;
}
virtual void onRecvBytes(const char *data,int size);
virtual void onDisconnect(const SockException &ex){}
private:
virtual void onConnect(const SockException &ex) override;
virtual void onRecv(const Socket::Buffer::Ptr &pBuf) override;
virtual void onErr(const SockException &ex) override;
//send
HttpHeader _header;
string _body;
string _method;
string _path;
//recv
string _recvedResponse;
size_t _recvedBodySize;
size_t _totalBodySize;
Parser _parser;
string _lastHost;
};
} /* namespace Http */
} /* namespace ZL */
#endif /* Http_HttpClient_h */

View File

@ -0,0 +1,47 @@
/*
* HttpClientImp.h
*
* Created on: 201754
* Author: xzl
*/
#ifndef SRC_HTTP_HTTPCLIENTIMP_H_
#define SRC_HTTP_HTTPCLIENTIMP_H_
#include "HttpClient.h"
#ifdef ENABLE_OPENSSL
#include "Util/SSLBox.h"
using namespace ZL::Util;
#endif //ENABLE_OPENSSL
namespace ZL {
namespace Http {
class HttpClientImp: public HttpClient {
public:
typedef std::shared_ptr<HttpClientImp> Ptr;
HttpClientImp();
virtual ~HttpClientImp();
virtual void sendRequest(const string &url) override;
#if defined(__GNUC__) && (__GNUC__ < 5)
void public_onRecvBytes(const char *data,int len){
HttpClient::onRecvBytes(data,len);
}
void public_send(const char *data, uint32_t len){
HttpClient::send(data,len);
}
#endif //defined(__GNUC__) && (__GNUC__ < 5)
private:
#ifdef ENABLE_OPENSSL
virtual void onRecvBytes(const char *data,int size) override;
virtual int send(const string &str) override;
virtual int send(const char *str, int len) override;
std::shared_ptr<SSL_Box> _sslBox;
#endif //ENABLE_OPENSSL
};
} /* namespace Http */
} /* namespace ZL */
#endif /* SRC_HTTP_HTTPCLIENTIMP_H_ */

View File

@ -0,0 +1,47 @@
/*
* HttpDownloader.h
*
* Created on: 201755
* Author: xzl
*/
#ifndef SRC_HTTP_HTTPDOWNLOADER_H_
#define SRC_HTTP_HTTPDOWNLOADER_H_
#include "HttpClientImp.h"
namespace ZL {
namespace Http {
class HttpDownloader: public HttpClientImp {
public:
typedef std::shared_ptr<HttpDownloader> Ptr;
typedef std::function<void(ErrCode code,const char *errMsg,const char *filePath)> onDownloadResult;
HttpDownloader();
virtual ~HttpDownloader();
//开始下载文件,默认断点续传方式下载
void startDownload(const string &url,const string &filePath = "",bool bAppend = false);
void startDownload(const string &url,const onDownloadResult &cb){
setOnResult(cb);
startDownload(url);
}
void setOnResult(const onDownloadResult &cb){
_onResult = cb;
}
private:
void onResponseHeader(const string &status,const HttpHeader &headers) override;
void onResponseBody(const char *buf,size_t size,size_t recvedSize,size_t totalSize) override;
void onResponseCompleted() override;
void onDisconnect(const SockException &ex) override;
void closeFile();
FILE *_saveFile = nullptr;
string _filePath;
onDownloadResult _onResult;
bool _bDownloadSuccess = false;
};
} /* namespace Http */
} /* namespace ZL */
#endif /* SRC_HTTP_HTTPDOWNLOADER_H_ */

View File

@ -0,0 +1,40 @@
//
// HttpRequester_h
// ZLMediaKit
//
// Created by xzl on 2017/5/5.
//
#ifndef Htt_HttpRequester_h
#define Htt_HttpRequester_h
#include "HttpClientImp.h"
namespace ZL{
namespace Http{
class HttpRequester : public HttpClientImp
{
public:
typedef std::shared_ptr<HttpRequester> Ptr;
typedef std::function<void(const SockException &ex,const string &status,const HttpHeader &header,const string &strRecvBody)> HttpRequesterResult;
HttpRequester();
virtual ~HttpRequester();
void startRequester(const string &url,const HttpRequesterResult &onResult);
private:
void onResponseHeader(const string &status,const HttpHeader &headers) override;
void onResponseBody(const char *buf,size_t size,size_t recvedSize,size_t totalSize) override;
void onResponseCompleted() override;
void onDisconnect(const SockException &ex) override;
string _strRecvBody;
HttpRequesterResult _onResult;
};
}//namespace Http
}//namespace ZL
#endif /* Htt_HttpRequester_h */

View File

@ -0,0 +1,68 @@
/*
* HttpSession.h
*
* Created on: 2016922
* Author: xzl
*/
#ifndef SRC_HTTP_HTTPSESSION_H_
#define SRC_HTTP_HTTPSESSION_H_
#include <functional>
#include "Common/config.h"
#include "Rtsp/Rtsp.h"
#include "Network/TcpLimitedSession.h"
using namespace std;
using namespace ZL::Network;
namespace ZL {
namespace Http {
class HttpSession: public TcpLimitedSession<MAX_TCP_SESSION> {
public:
typedef StrCaseMap KeyValue;
typedef std::function<void(const string &codeOut,
const KeyValue &headerOut,
const string &contentOut)> HttpResponseInvoker;
HttpSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock);
virtual ~HttpSession();
virtual void onRecv(const Socket::Buffer::Ptr &) override;
virtual void onError(const SockException &err) override;
virtual void onManager() override;
protected:
void onRecv(const char *data,int size);
private:
typedef enum
{
Http_success = 0,
Http_failed = 1,
Http_moreData = 2,
} HttpCode;
typedef HttpSession::HttpCode (HttpSession::*HttpCMDHandle)();
static unordered_map<string, HttpCMDHandle> g_mapCmdIndex;
Parser m_parser;
string m_strPath;
string m_strRcvBuf;
Ticker m_ticker;
uint32_t m_iReqCnt = 0;
inline HttpCode parserHttpReq(const string &);
inline HttpCode Handle_Req_GET();
inline HttpCode Handle_Req_POST();
inline bool makeMeun(const string &strFullPath, string &strRet);
inline void sendNotFound(bool bClose);
inline void sendResponse(const char *pcStatus,const KeyValue &header,const string &strContent);
inline static KeyValue makeHttpHeader(bool bClose=false,int64_t iContentSize=-1,const char *pcContentType="text/html");
void responseDelay(bool bClose,string &codeOut,KeyValue &headerOut, string &contentOut);
};
} /* namespace Http */
} /* namespace ZL */
#endif /* SRC_HTTP_HTTPSESSION_H_ */

View File

@ -0,0 +1,71 @@
/*
* HttpsSession.h
*
* Created on: 2017419
* Author: xzl
*/
#ifndef SRC_HTTP_HTTPSSESSION_H_
#define SRC_HTTP_HTTPSSESSION_H_
#include "HttpSession.h"
#include "Util/SSLBox.h"
#include "Util/TimeTicker.h"
using namespace ZL::Util;
namespace ZL {
namespace Http {
class HttpsSession: public HttpSession {
public:
HttpsSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock):
HttpSession(pTh,pSock){
m_sslBox.setOnEncData([&](const char *data, uint32_t len){
#if defined(__GNUC__) && (__GNUC__ < 5)
public_send(data,len);
#else//defined(__GNUC__) && (__GNUC__ < 5)
HttpSession::send(data,len);
#endif//defined(__GNUC__) && (__GNUC__ < 5)
});
m_sslBox.setOnDecData([&](const char *data, uint32_t len){
#if defined(__GNUC__) && (__GNUC__ < 5)
public_onRecv(data,len);
#else//defined(__GNUC__) && (__GNUC__ < 5)
HttpSession::onRecv(data,len);
#endif//defined(__GNUC__) && (__GNUC__ < 5)
});
}
virtual ~HttpsSession(){
//m_sslBox.shutdown();
}
void onRecv(const Socket::Buffer::Ptr &pBuf) override{
TimeTicker();
m_sslBox.onRecv(pBuf->data(), pBuf->size());
}
#if defined(__GNUC__) && (__GNUC__ < 5)
int public_send(const char *data, uint32_t len){
return HttpSession::send(data,len);
}
void public_onRecv(const char *data, uint32_t len){
HttpSession::onRecv(data,len);
}
#endif//defined(__GNUC__) && (__GNUC__ < 5)
private:
virtual int send(const string &buf) override{
TimeTicker();
m_sslBox.onSend(buf.data(), buf.size());
return buf.size();
}
virtual int send(const char *buf, int size) override{
TimeTicker();
m_sslBox.onSend(buf, size);
return size;
}
SSL_Box m_sslBox;
};
} /* namespace Http */
} /* namespace ZL */
#endif /* SRC_HTTP_HTTPSSESSION_H_ */

View File

@ -0,0 +1,33 @@
/*
* strCoding.h
*
* Created on: 2016922
* Author: xzl
*/
#ifndef SRC_HTTP_STRCODING_H_
#define SRC_HTTP_STRCODING_H_
#include <iostream>
#include <string>
using namespace std;
namespace ZL {
namespace Http {
class strCoding {
public:
static string UrlUTF8Encode(const char * str); //urlutf8 编码
static string UrlUTF8Decode(const string &str); //urlutf8解码
private:
strCoding(void);
virtual ~strCoding(void);
static inline char CharToInt(char ch);
static inline char StrToBin(const char *str);
};
} /* namespace Http */
} /* namespace ZL */
#endif /* SRC_HTTP_STRCODING_H_ */

View File

@ -0,0 +1,63 @@
/*
* HLSMaker.h
*
* Created on: 2013-6-24
* Author: root
*/
#ifndef HLSMAKER_H_
#define HLSMAKER_H_
#include "TSMaker.h"
#include "Common/config.h"
#include "Util/TimeTicker.h"
#include "Util/File.h"
#include "Util/util.h"
#include "Util/logger.h"
using namespace ZL::Util;
namespace ZL {
namespace MediaFile {
class HLSMaker {
public:
HLSMaker(const string &strM3u8File,
const string &strHttpUrl,
uint32_t ui32BufSize = 64 * 1024,
uint32_t ui32Duration = 5,
uint32_t ui32Num = 3);
virtual ~HLSMaker();
//时间戳参考频率90000
void inputH264( void *pData,
uint32_t ui32Length,
uint32_t ui32TimeStamp,
int iType);
//时间戳参考频率90000
void inputAAC( void *pData,
uint32_t ui32Length,
uint32_t ui32TimeStamp);
private:
TSMaker m_ts;
string m_strM3u8File;
string m_strHttpUrl;
string m_strFileName;
string m_strOutputPrefix;
string m_strTmpFileName;
uint32_t m_ui32SegmentDuration;
uint32_t m_ui32NumSegments;
uint64_t m_ui64TsCnt;
uint32_t m_ui32BufSize;
Ticker m_Timer;
int write_index_file(int iFirstSegment, unsigned int uiLastSegment, int iEnd);
void removets();
};
} /* namespace MediaFile */
} /* namespace ZL */
#endif /* HLSMAKER_H_ */

View File

@ -0,0 +1,85 @@
/*
* MediaReader.h
*
* Created on: 20161214
* Author: xzl
*/
#ifndef SRC_MEDIAFILE_MEDIAREADER_H_
#define SRC_MEDIAFILE_MEDIAREADER_H_
#include "Device/Device.h"
#include "Rtsp/RtspMediaSource.h"
#include "Rtmp/RtmpMediaSource.h"
#ifdef ENABLE_MP4V2
#include <mp4v2/mp4v2.h>
#endif //ENABLE_MP4V2
using namespace ZL::DEV;
using namespace ZL::Rtsp;
using namespace ZL::Rtmp;
namespace ZL {
namespace MediaFile {
class MediaReader : public std::enable_shared_from_this<MediaReader>{
public:
typedef std::shared_ptr<MediaReader> Ptr;
MediaReader(const string &strApp, const string &strId);
virtual ~MediaReader();
static RtspMediaSource::Ptr onMakeRtsp(const string &strApp, const string &strId);
static RtmpMediaSource::Ptr onMakeRtmp(const string &strApp, const string &strId);
private:
#ifdef ENABLE_MP4V2
MP4FileHandle m_hMP4File = MP4_INVALID_FILE_HANDLE;
MP4TrackId m_video_trId = MP4_INVALID_TRACK_ID;
uint32_t m_video_ms = 0;
uint32_t m_video_num_samples = 0;
uint32_t m_video_sample_max_size = 0;
uint32_t m_video_width = 0;
uint32_t m_video_height = 0;
uint32_t m_video_framerate = 0;
string m_strPps;
string m_strSps;
bool m_bSyncSample = false;
MP4TrackId m_audio_trId = MP4_INVALID_TRACK_ID;
uint32_t m_audio_ms = 0;
uint32_t m_audio_num_samples = 0;
uint32_t m_audio_sample_max_size = 0;
uint32_t m_audio_sample_rate = 0;
uint32_t m_audio_num_channels = 0;
string m_strAacCfg;
AdtsFrame m_adts;
int m_iDuration = 0;
DevChannel::Ptr m_pChn;
MP4SampleId m_video_current = 0;
MP4SampleId m_audio_current = 0;
std::shared_ptr<uint8_t> m_pcVideoSample;
int m_iSeekTime = 0 ;
Ticker m_ticker;
Ticker m_alive;
recursive_mutex m_mtx;
void seek(int iSeekTime,bool bReStart = true);
inline void setSeekTime(int iSeekTime);
inline uint32_t getVideoCurrentTime();
void startReadMP4();
inline MP4SampleId getVideoSampleId(int iTimeInc = 0);
inline MP4SampleId getAudioSampleId(int iTimeInc = 0);
bool readSample(int iTimeInc = 0);
inline bool readVideoSample(int iTimeInc = 0);
inline bool readAudioSample(int iTimeInc = 0);
inline void writeH264(uint8_t *pucData,int iLen,uint32_t uiStamp);
inline void writeAAC(uint8_t *pucData,int iLen,uint32_t uiStamp);
#endif //ENABLE_MP4V2
};
} /* namespace MediaFile */
} /* namespace ZL */
#endif /* SRC_MEDIAFILE_MEDIAREADER_H_ */

View File

@ -0,0 +1,58 @@
/*
* MediaRecorder.h
*
* Created on: 2016128
* Author: xzl
*/
#ifndef SRC_MEDIAFILE_MEDIARECORDER_H_
#define SRC_MEDIAFILE_MEDIARECORDER_H_
#include <memory>
#include "Player/PlayerBase.h"
#ifdef ENABLE_MP4V2
#include "Mp4Maker.h"
#endif //ENABLE_MP4V2
#ifdef ENABLE_HLS
#include "HLSMaker.h"
#endif //ENABLE_HLS
using namespace std;
using namespace ZL::Player;
namespace ZL {
namespace MediaFile {
class MediaRecorder {
public:
typedef std::shared_ptr<MediaRecorder> Ptr;
MediaRecorder(const string &strApp,const string &strId,const std::shared_ptr<PlayerBase> &pPlayer);
virtual ~MediaRecorder();
void inputH264( void *pData,
uint32_t ui32Length,
uint32_t ui32TimeStamp,
int iType);
void inputAAC( void *pData,
uint32_t ui32Length,
uint32_t ui32TimeStamp);
private:
#ifdef ENABLE_HLS
std::shared_ptr<HLSMaker> m_hlsMaker;
#endif //ENABLE_HLS
#ifdef ENABLE_MP4V2
std::shared_ptr<Mp4Maker> m_mp4Maker;
#endif //ENABLE_MP4V2
};
} /* namespace MediaFile */
} /* namespace ZL */
#endif /* SRC_MEDIAFILE_MEDIARECORDER_H_ */

View File

@ -0,0 +1,82 @@
/*
* Mp4Maker.h
*
* Created on: 2013-9-18
* Author: root
*/
#ifndef MP4MAKER_H_
#define MP4MAKER_H_
#ifdef ENABLE_MP4V2
#include <mutex>
#include <memory>
#include <mp4v2/mp4v2.h>
#include "Player/PlayerBase.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Util/TimeTicker.h"
#include "Util/TimeTicker.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Player;
namespace ZL {
namespace MediaFile {
class Mp4Info
{
public:
time_t ui64StartedTime; //GMT标准时间单位秒
time_t ui64TimeLen;//录像长度,单位秒
off_t ui64FileSize;//文件大小单位BYTE
string strFilePath;//文件路径
string strFileName;//文件名称
string strFolder;//文件夹路径
string strUrl;//播放路径
string strAppName;//应用名称
string strStreamId;//流ID
};
class Mp4Maker {
public:
typedef std::shared_ptr<Mp4Maker> Ptr;
Mp4Maker(const string &strPath,const string &strApp,const string &strStreamId, const PlayerBase::Ptr &pPlayer);
virtual ~Mp4Maker();
//时间戳参考频率1000
void inputH264(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp, int iType);
//时间戳参考频率1000
void inputAAC(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp);
private:
MP4FileHandle m_hMp4 = MP4_INVALID_FILE_HANDLE;
MP4TrackId m_hVideo = MP4_INVALID_TRACK_ID;
MP4TrackId m_hAudio = MP4_INVALID_TRACK_ID;
PlayerBase::Ptr m_pPlayer;
string m_strPath;
string m_strFile;
string m_strFileTmp;
Ticker m_ticker;
SmoothTicker m_mediaTicker[2];
void createFile();
void closeFile();
void _inputH264(void *pData, uint32_t ui32Length, uint32_t ui64Duration, int iType);
void _inputAAC(void *pData, uint32_t ui32Length, uint32_t ui64Duration);
string m_strLastVideo;
string m_strLastAudio;
uint32_t m_ui32LastVideoTime = 0;
uint32_t m_ui32LastAudioTime = 0;
int m_iLastVideoType = 0;
Mp4Info m_info;
};
} /* namespace MediaFile */
} /* namespace ZL */
#endif ///ENABLE_MP4V2
#endif /* MP4MAKER_H_ */

View File

@ -0,0 +1,249 @@
/*
* TSMaker.h
*
* Created on: 2013-6-21
* Author: root
*/
#ifndef TSMAKER_H_
#define TSMAKER_H_
#include "crc32.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <iostream>
#include "Util/File.h"
using namespace std;
using namespace ZL::Util;
#define TS_PACKET_SIZE 188
#define TS_PACKET_HEADER 4
#define TS_SYNC_BYTE 0x47
#define TS_PAT_PID 0x00
#define TS_PMT_PID 0xFFF
#define TS_H264_PID 0x100
#define TS_AAC_PID 0x101
#define TS_H264_STREAM_ID 0xE0
#define TS_AAC_STREAM_ID 0xC0
#define PMT_STREAM_TYPE_VIDEO 0x1B
#define PMT_STREAM_TYPE_AUDIO 0x0F
//#define ES_BUF_SIZE 256*1024
//ts 包头
typedef struct Tag_PacketHeader {
unsigned char sync_byte :8; //同步字节, 固定为0x47,表示后面的是一个TS分组
unsigned char tras_error :1; //传输误码指示符
unsigned char play_init :1; //有效荷载单元起始指示符
unsigned char tras_prio :1; //传输优先, 1表示高优先级,传输机制可能用到,解码用不着
unsigned int PID :13; //PID
unsigned char tras_scramb :2; //传输加扰控制
unsigned char ada_field_C :2; //自适应控制 01仅含有效负载10仅含调整字段11含有调整字段和有效负载先调整字段然后有效负载。为00解码器不进行处理
unsigned char conti_cter :4; //连续计数器 一个4bit的计数器范围0-15
} TsPacketHeader;
//连续性计数器,也就是说 有多少个 pat包几个pmt包 几个MP3 包,几个 h264包0x00 - 0x0f 然后折回到0x00
typedef struct Tag_Continuity_Counter {
unsigned char continuity_counter_pat;
unsigned char continuity_counter_pmt;
unsigned char continuity_counter_video;
unsigned char continuity_counter_audio;
} Continuity_Counter;
//自适应段标志
typedef struct Tag_Ts_Adaptation_field {
unsigned char discontinuty_indicator :1; //1表明当前传送流分组的不连续状态为真
unsigned char random_access_indicator :1; //表明下一个有相同PID的PES分组应该含有PTS字段和一个原始流访问点
unsigned char elementary_stream_priority_indicator :1; //优先级
unsigned char PCR_flag :1; //包含pcr字段
unsigned char OPCR_flag :1; //包含opcr字段
unsigned char splicing_point_flag :1; //拼接点标志
unsigned char transport_private_data_flag :1; //私用字节
unsigned char adaptation_field_extension_flag :1; //调整字段有扩展
unsigned char adaptation_field_length; //自适应段长度
unsigned long long pcr; //自适应段中用到的的pcr
unsigned long long opcr; //自适应段中用到的的opcr
unsigned char splice_countdown;
unsigned char private_data_len;
unsigned char private_data[256];
} Ts_Adaptation_field;
//PAT结构体节目相关表
typedef struct Tag_TsPat {
unsigned char table_id :8; //固定为0x00 标志是该表是PAT
unsigned char section_syntax_indicator :1; //段语法标志位固定为1
unsigned char zero :1; //0
unsigned char reserved_1 :2; //保留位
unsigned int section_length :12; //表示这个字节后面有用的字节数包括CRC32
unsigned int transport_stream_id :16; //该传输流的ID区别于一个网络中其它多路复用的流
unsigned char reserved_2 :2; //保留位
unsigned char version_number :5; //范围0-31表示PAT的版本号
unsigned char current_next_indicator :1; //发送的PAT是当前有效还是下一个PAT有效
unsigned char section_number :8; //分段的号码。PAT可能分为多段传输第一段为00以后每个分段加1最多可能有256个分段
unsigned char last_section_number :8; //最后一个分段的号码
unsigned int program_number :16; //节目号
unsigned char reserved_3 :3; //保留位
//unsigned int network_PID :13 ; //网络信息表NIT的PID,节目号为0时对应的PID为network_PID,本例中不含有 networke_pid
unsigned int program_map_PID :13; //节目映射表的PID节目号大于0时对应的PID每个节目对应一个
unsigned long long CRC_32 :32; //CRC32校验码
} TsPat;
//PMT结构体节目映射表
typedef struct Tag_TsPmt {
unsigned char table_id :8; //固定为0x02, 表示PMT表
unsigned char section_syntax_indicator :1; //固定为0x01
unsigned char zero :1; //0x00
unsigned char reserved_1 :2; //0x03
unsigned int section_length :12; //首先两位bit置为00它指示段的byte数由段长度域开始包含CRC。
unsigned int program_number :16; // 指出该节目对应于可应用的Program map PID
unsigned char reserved_2 :2; //0x03
unsigned char version_number :5; //指出TS流中Program map section的版本号
unsigned char current_next_indicator :1; //当该位置1时当前传送的Program map section可用当该位置0时指示当前传送的Program map section不可用下一个TS流的Program map section有效。
unsigned char section_number :8; //固定为0x00
unsigned char last_section_number :8; //固定为0x00
unsigned char reserved_3 :3; //0x07
unsigned int PCR_PID :13; //指明TS包的PID值该TS包含有PCR域该PCR值对应于由节目号指定的对应节目。如果对于私有数据流的节目定义与PCR无关这个域的值将为0x1FFF。
unsigned char reserved_4 :4; //预留为0x0F
unsigned int program_info_length :12; //前两位bit为00。该域指出跟随其后对节目信息的描述的byte数。
unsigned char stream_type_video :8; //指示特定PID的节目元素包的类型。该处PID由elementary PID指定
unsigned char reserved_5_video :3; //0x07
unsigned int elementary_PID_video :13; //该域指示TS包的PID值。这些TS包含有相关的节目元素
unsigned char reserved_6_video :4; //0x0F
unsigned int ES_info_length_video :12; //前两位bit为00。该域指示跟随其后的描述相关节目元素的byte数
unsigned char stream_type_audio :8; //指示特定PID的节目元素包的类型。该处PID由elementary PID指定
unsigned char reserved_5_audio :3; //0x07
unsigned int elementary_PID_audio :13; //该域指示TS包的PID值。这些TS包含有相关的节目元素
unsigned char reserved_6_audio :4; //0x0F
unsigned int ES_info_length_audio :12; //前两位bit为00。该域指示跟随其后的描述相关节目元素的byte数
unsigned long long CRC_32 :32; //CRC32校验码
} TsPmt;
//PTS_DTS结构体本程序设置都有 “11”
typedef struct Tag_TsPtsDts {
unsigned char reserved_1 :4;
unsigned char pts_32_30 :3; //显示时间戳
unsigned char marker_bit1 :1;
unsigned int pts_29_15 :15;
unsigned char marker_bit2 :1;
unsigned int pts_14_0 :15;
unsigned char marker_bit3 :1;
unsigned char reserved_2 :4;
unsigned char dts_32_30 :3; //解码时间戳
unsigned char marker_bit4 :1;
unsigned int dts_29_15 :15;
unsigned char marker_bit5 :1;
unsigned int dts_14_0 :15;
unsigned char marker_bit6 :1;
} TsPtsDts;
//PES包结构体包括PES包头和ES数据 ,头 19 个字节
typedef struct Tag_TsPes {
unsigned int packet_start_code_prefix :24; //起始0x000001
unsigned char stream_id :8; //基本流的类型和编号
unsigned int PES_packet_length :16; //包长度,就是帧数据的长度可能为0,要自己算,做多16位如果超出则需要自己算
unsigned char marker_bit :2; //必须是:'10'
unsigned char PES_scrambling_control :2; //pes包有效载荷的加扰方式
unsigned char PES_priority :1; //有效负载的优先级
unsigned char data_alignment_indicator :1; //如果设置为1表明PES包的头后面紧跟着视频或音频syncword开始的代码。
unsigned char copyright :1; //1:靠版权保护0不靠
unsigned char original_or_copy :1; //1;有效负载是原始的0有效负载时拷贝的
unsigned char PTS_DTS_flags :2; //'10'PTS字段存在11PTD和DTS都存在00都没有01禁用。
unsigned char ESCR_flag :1; //1:escr基准字段 和 escr扩展字段均存在0无任何escr字段存在
unsigned char ES_rate_flag :1; //1:es_rate字段存在0 :不存在
unsigned char DSM_trick_mode_flag :1; //1;8比特特接方式字段存在0 :不存在
unsigned char additional_copy_info_flag :1; //1:additional_copy_info存在0: 不存在
unsigned char PES_CRC_flag :1; //1:crc字段存在0不存在
unsigned char PES_extension_flag :1; //1扩展字段存在0不存在
unsigned char PES_header_data_length :8; //后面数据的长度,
//TsPtsDts tsptsdts; //ptsdts结构体对象10个字节
char *ES;
unsigned long ESlen;
} TsPes;
/*//H264一帧数据的结构体
typedef struct Tag_NALU_t {
unsigned char forbidden_bit; //! Should always be FALSE
unsigned char nal_reference_idc; //! NALU_PRIORITY_xxxx
unsigned char nal_unit_type; //! NALU_TYPE_xxxx
unsigned int startcodeprefix_len; //! 前缀字节数
unsigned int len; //! 包含nal 头的nal 长度从第一个00000001到下一个000000001的长度
unsigned int max_size; //! 做多一个nal 的长度
unsigned char * buf; //! 包含nal 头的nal 数据
unsigned int lost_packets; //! 预留
} NALU_t;*/
//nal类型
typedef enum {
NALU_TYPE_SLICE = 1,
NALU_TYPE_DPA = 2,
NALU_TYPE_DPB = 3,
NALU_TYPE_DPC = 4,
NALU_TYPE_IDR = 5,
NALU_TYPE_SEI = 6,
NALU_TYPE_SPS = 7,
NALU_TYPE_PPS = 8,
NALU_TYPE_AUD = 9,
NALU_TYPE_EOSEQ = 10,
NALU_TYPE_EOSTREAM = 11,
NALU_TYPE_FILL = 12,
#if (MVC_EXTENSION_ENABLE)
NALU_TYPE_PREFIX = 14,
NALU_TYPE_SUB_SPS = 15,
NALU_TYPE_SLC_EXT = 20,
NALU_TYPE_VDRD = 24 // View and Dependency Representation Delimiter NAL Unit
#endif
} NaluType;
/*//MP3头结构体
typedef struct Tag_Mp3_Header {
unsigned int sync :11; //同步信息
unsigned char version :2; //版本
unsigned char layer :2; //层
unsigned char error_protection :1; //CRC校验
unsigned char bitrate_index :4; //位率
unsigned char sampling_frequency :2; //采样频率
unsigned char padding :1; //帧长调节
unsigned char private_t :1; //保留字
unsigned char mode :2; //声道模式
unsigned char mode_extension :2; //扩展模式
unsigned char copyright :1; //版权
unsigned char original :1; //原版标志
unsigned char emphasis :2; //强调模式
} Mp3_Header;*/
class TSMaker {
public:
TSMaker();
virtual ~TSMaker();
bool init(const string &strFilename, uint32_t ui32BufSize);
int inputH264(const char *pcData, uint32_t ui32Len, uint64_t ui64Time);
int inputAAC(const char *pcData, uint32_t ui32Len, uint64_t ui64Time);
void clear();
private:
string m_strFilename;
FILE *m_pOutVideoTs;
Continuity_Counter m_continuityCounter;
TsPes *m_pVideo_pes;
TsPes *m_pAudio_pes;
unsigned int m_uiWritePacketNum;
char *m_pcFileBuf;
void flush();
void CreateTsHeader(TsPacketHeader * pTsHeader, unsigned int uiPID, unsigned char ucPlayInit, unsigned char ucAdaFieldC);
void TsHeader2buffer(TsPacketHeader * pTsHeader, unsigned char *pucBuffer);
void CreatePAT();
void CreatePMT();
void WriteAdaptive_flags_Head(Ts_Adaptation_field * pAdaptationField, uint64_t ui64VideoPts);
void WriteAdaptive_flags_Tail(Ts_Adaptation_field * pAdaptationField); //填写自适应段标志帧尾的
void PES2TS(TsPes * pPes, unsigned int uiPID, Ts_Adaptation_field * pAdaptationField, uint64_t ui64Pts);
void CreateAdaptive_Ts(Ts_Adaptation_field * pAdaptationField, unsigned char * pcTs, unsigned int uiAdaptiveLength);
};
#endif /* TSMAKER_H_ */

View File

@ -0,0 +1,16 @@
/*
* crc32.h
*
* Created on: 2013-6-21
* Author: root
*/
#ifndef CRC32_H_
#define CRC32_H_
unsigned int calc_crc32 (unsigned char *data, unsigned int datalen);
unsigned int Zwg_ntohl(unsigned int s);
#endif /* CRC32_H_ */

View File

@ -0,0 +1,42 @@
/*
* MediaPlayer.h
*
* Created on: 2016125
* Author: xzl
*/
#ifndef SRC_PLAYER_MEDIAPLAYER_H_
#define SRC_PLAYER_MEDIAPLAYER_H_
#include <memory>
#include <string>
#include "Player.h"
#include "PlayerBase.h"
#include "Rtsp/RtspPlayer.h"
#include "Rtmp/RtmpPlayer.h"
using namespace std;
using namespace ZL::Rtsp;
using namespace ZL::Rtmp;
namespace ZL {
namespace Player {
class MediaPlayer : public PlayerImp<PlayerBase,PlayerBase> {
public:
typedef std::shared_ptr<MediaPlayer> Ptr;
MediaPlayer();
virtual ~MediaPlayer();
void play(const char* strUrl) override;
void pause(bool bPause) override;
void teardown() override;
private:
string m_strPrefix;
};
} /* namespace Player */
} /* namespace ZL */
#endif /* SRC_PLAYER_MEDIAPLAYER_H_ */

View File

@ -0,0 +1,53 @@
/*
* Player.h
*
* Created on: 2016122
* Author: xzl
*/
#ifndef SRC_PLAYER_PLAYER_H_
#define SRC_PLAYER_PLAYER_H_
#include <string>
using namespace std;
typedef struct {
uint16_t sequence;
uint32_t timeStamp;
unsigned char type;
string data;
} H264Frame;
//ADTS 头中相对有用的信息 采样率、声道数、帧长度
typedef struct {
unsigned int syncword; //12 bslbf 同步字The bit string 1111 1111 1111说明一个ADTS帧的开始
unsigned int id; //1 bslbf MPEG 标示符, 设置为1
unsigned int layer; //2 uimsbf Indicates which layer is used. Set to 00
unsigned int protection_absent; //1 bslbf 表示是否误码校验
unsigned int profile; //2 uimsbf 表示使用哪个级别的AAC如01 Low Complexity(LC)--- AACLC
unsigned int sf_index; //4 uimsbf 表示使用的采样率下标
unsigned int private_bit; //1 bslbf
unsigned int channel_configuration; //3 uimsbf 表示声道数
unsigned int original; //1 bslbf
unsigned int home; //1 bslbf
//下面的为改变的参数即每一帧都不同
unsigned int copyright_identification_bit; //1 bslbf
unsigned int copyright_identification_start; //1 bslbf
unsigned int aac_frame_length; // 13 bslbf 一个ADTS帧的长度包括ADTS头和raw data block
unsigned int adts_buffer_fullness; //11 bslbf 0x7FF 说明是码率可变的码流
//no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧.
//所以说number_of_raw_data_blocks_in_frame == 0
//表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
unsigned int no_raw_data_blocks_in_frame; //2 uimsfb
unsigned char data[2 * 1024 + 7];
uint16_t sequence;
uint32_t timeStamp;
} AdtsFrame;
void makeAdtsHeader(const string &strAudioCfg,AdtsFrame &adts);
void writeAdtsHeader(const AdtsFrame &adts, uint8_t *pcAdts) ;
string makeAdtsConfig(const uint8_t *pcAdts);
void getAACInfo(const AdtsFrame &adts,int &iSampleRate,int &iChannel);
bool getAVCInfo(const string &strSps,int &iVideoWidth, int &iVideoHeight, float &iVideoFps);
#endif /* SRC_PLAYER_PLAYER_H_ */

View File

@ -0,0 +1,221 @@
/*
* PlayerBase.h
*
* Created on: 2016121
* Author: xzl
*/
#ifndef SRC_PLAYER_PLAYERBASE_H_
#define SRC_PLAYER_PLAYERBASE_H_
#include <map>
#include <memory>
#include <string>
#include <functional>
#include "Player.h"
#include "Network/Socket.h"
#include "Util/mini.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Network;
namespace ZL {
namespace Player {
class PlayerBase : public mINI{
public:
typedef std::shared_ptr<PlayerBase> Ptr;
typedef enum {
RTP_TCP = 0,
RTP_UDP = 1,
RTP_MULTICAST = 2,
} eRtpType;
static Ptr createPlayer(const char* strUrl);
PlayerBase(){};
virtual ~PlayerBase(){};
virtual void play(const char* strUrl) {};
virtual void pause(bool bPause) {};
virtual void teardown() {};
virtual void setOnShutdown( const function<void(const SockException &)> &cb) {};
virtual void setOnPlayResult( const function<void(const SockException &ex)> &cb) {};
virtual void setOnVideoCB( const function<void(const H264Frame &frame)> &cb) {};
virtual void setOnAudioCB( const function<void(const AdtsFrame &frame)> &cb) {};
virtual int getVideoHeight() const { return 0; };
virtual int getVideoWidth() const { return 0; };
virtual float getVideoFps() const { return 0; };
virtual int getAudioSampleRate() const { return 0; };
virtual int getAudioSampleBit() const { return 0; };
virtual int getAudioChannel() const { return 0; };
virtual float getRtpLossRate(int iTrackId) const {return 0; };
virtual const string& getPps() const { static string null;return null; };
virtual const string& getSps() const { static string null;return null; };
virtual const string& getAudioCfg() const { static string null;return null; };
virtual bool containAudio() const { return false; };
virtual bool containVideo() const { return false; };
virtual bool isInited() const { return true; };
virtual float getDuration() const { return 0;};
virtual float getProgresss() const { return 0;};
virtual void seekTo(float fProgress) {};
protected:
virtual void onShutdown(const SockException &ex) {};
virtual void onPlayResult(const SockException &ex) {};
};
template<typename Parent,typename Parser>
class PlayerImp : public Parent
{
public:
typedef std::shared_ptr<PlayerImp> Ptr;
PlayerImp(){};
virtual ~PlayerImp(){};
void setOnShutdown(const function<void(const SockException &)> &cb) override {
if (m_parser) {
m_parser->setOnShutdown(cb);
}
m_shutdownCB = cb;
}
void setOnPlayResult(const function<void(const SockException &ex)> &cb) override {
if (m_parser) {
m_parser->setOnPlayResult(cb);
}
m_playResultCB = cb;
}
void setOnVideoCB(const function<void(const H264Frame &frame)> &cb) override{
if (m_parser) {
m_parser->setOnVideoCB(cb);
}
m_onGetVideoCB = cb;
}
void setOnAudioCB(const function<void(const AdtsFrame &frame)> &cb) override{
if (m_parser) {
m_parser->setOnAudioCB(cb);
}
m_onGetAudioCB = cb;
}
int getVideoHeight() const override{
if (m_parser) {
return m_parser->getVideoHeight();
}
return PlayerBase::getVideoHeight();
}
int getVideoWidth() const override{
if (m_parser) {
return m_parser->getVideoWidth();
}
return PlayerBase::getVideoWidth();
}
float getVideoFps() const override{
if (m_parser) {
return m_parser->getVideoFps();
}
return PlayerBase::getVideoFps();
}
int getAudioSampleRate() const override{
if (m_parser) {
return m_parser->getAudioSampleRate();
}
return PlayerBase::getAudioSampleRate();
}
int getAudioSampleBit() const override{
if (m_parser) {
return m_parser->getAudioSampleBit();
}
return PlayerBase::getAudioSampleBit();
}
int getAudioChannel() const override{
if (m_parser) {
return m_parser->getAudioChannel();
}
return PlayerBase::getAudioChannel();
}
const string& getPps() const override{
if (m_parser) {
return m_parser->getPps();
}
return PlayerBase::getPps();
}
const string& getSps() const override{
if (m_parser) {
return m_parser->getSps();
}
return PlayerBase::getSps();
}
const string& getAudioCfg() const override{
if (m_parser) {
return m_parser->getAudioCfg();
}
return PlayerBase::getAudioCfg();
}
bool containAudio() const override{
if (m_parser) {
return m_parser->containAudio();
}
return PlayerBase::containAudio();
}
bool containVideo() const override{
if (m_parser) {
return m_parser->containVideo();
}
return PlayerBase::containVideo();
}
bool isInited() const override{
if (m_parser) {
return m_parser->isInited();
}
return PlayerBase::isInited();
}
float getDuration() const override {
if (m_parser) {
return m_parser->getDuration();
}
return PlayerBase::getDuration();
}
float getProgresss() const override{
if (m_parser) {
return m_parser->getProgresss();
}
return PlayerBase::getProgresss();
};
void seekTo(float fProgress) override{
if (m_parser) {
return m_parser->seekTo(fProgress);
}
return PlayerBase::seekTo(fProgress);
};
protected:
void onShutdown(const SockException &ex) override {
if (m_shutdownCB) {
m_shutdownCB(ex);
}
}
void onPlayResult(const SockException &ex) override {
if (m_playResultCB) {
m_playResultCB(ex);
m_playResultCB = nullptr;
}
}
function<void(const SockException &ex)> m_shutdownCB;
function<void(const SockException &ex)> m_playResultCB;
std::shared_ptr<Parser> m_parser;
function<void(const H264Frame &frame)> m_onGetVideoCB;
function<void(const AdtsFrame &frame)> m_onGetAudioCB;
};
} /* namespace Player */
} /* namespace ZL */
#endif /* SRC_PLAYER_PLAYERBASE_H_ */

View File

@ -0,0 +1,85 @@
/*
* RtpMaker.h
*
* Created on: 2016812
* Author: xzl
*/
#ifndef RTP_RTPMAKER_H_
#define RTP_RTPMAKER_H_
#include "Rtsp/RtspMediaSource.h"
#include "Util/logger.h"
#include "Util/RingBuffer.h"
#include "Util/TimeTicker.h"
#include "Util/ResourcePool.h"
#include "Thread/ThreadPool.h"
using namespace ZL::Util;
using namespace ZL::Thread;
namespace ZL {
namespace Rtsp {
class RtpMaker {
public:
typedef function<void(const RtpPacket::Ptr &pPkt, bool bKeyPos)> onGetRTP;
RtpMaker(const onGetRTP &cb, uint32_t ui32Ssrc, int iMtuSize,int iSampleRate,
uint8_t ui8PlayloadType, uint8_t ui8Interleaved) {
callBack = cb;
m_ui32Ssrc = ui32Ssrc;
m_ui32SampleRate = iSampleRate;
m_iMtuSize = iMtuSize;
m_ui8PlayloadType = ui8PlayloadType;
m_ui8Interleaved = ui8Interleaved;
}
virtual ~RtpMaker() {
}
virtual void makeRtp(const char *pcData, int iDataLen, uint32_t uiStamp)=0;
int getInterleaved() const {
return m_ui8Interleaved;
}
int getPlayloadType() const {
return m_ui8PlayloadType;
}
int getSampleRate() const {
return m_ui32SampleRate;
}
uint32_t getSsrc() const {
return m_ui32Ssrc;
}
uint16_t getSeqence() const {
return m_ui16Sequence;
}
uint32_t getTimestamp() const {
return m_ui32TimeStamp;
}
protected:
uint32_t m_ui32Ssrc;
uint32_t m_ui32SampleRate;
int m_iMtuSize;
uint8_t m_ui8PlayloadType;
uint8_t m_ui8Interleaved;
uint16_t m_ui16Sequence = 0;
uint32_t m_ui32TimeStamp = 0;
virtual void onMakeRtp(const RtpPacket::Ptr &pkt, bool bKeyPos = true) {
callBack(pkt, bKeyPos);
}
inline RtpPacket::Ptr obtainPkt() {
return m_pktPool.obtain();
}
private:
RtspMediaSource::PoolType m_pktPool;
onGetRTP callBack;
};
} /* namespace RTP */
} /* namespace ZL */
#endif /* RTP_RTPMAKER_H_ */

View File

@ -0,0 +1,43 @@
/*
* RtpMakerAAC.h
*
* Created on: 2016812
* Author: xzl
*/
#ifndef RTP_RTPMAKERAAC_H_
#define RTP_RTPMAKERAAC_H_
#include <memory>
#include "RtpMaker.h"
#include "Rtsp/RtspMediaSource.h"
#include "Util/logger.h"
#include "Util/RingBuffer.h"
#include "Util/ResourcePool.h"
using namespace std;
using namespace ZL::Util;
namespace ZL {
namespace Rtsp {
class RtpMaker_AAC: public RtpMaker {
public:
typedef std::shared_ptr<RtpMaker_AAC> Ptr;
RtpMaker_AAC(const onGetRTP &cb,
uint32_t ui32Ssrc, int iMtuSize , int iSampleRate, uint8_t ui8PlayloadType = 97,
uint8_t ui8Interleaved = 2) :
RtpMaker(cb, ui32Ssrc, iMtuSize,iSampleRate, ui8PlayloadType, ui8Interleaved) {
}
virtual ~RtpMaker_AAC() {
}
void makeRtp(const char *pcData, int iDataLen, uint32_t uiStamp) override;
private:
inline void makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp);
unsigned char m_aucSectionBuf[1600];
};
} /* namespace RTP */
} /* namespace ZL */
#endif /* RTP_RTPMAKERAAC_H_ */

View File

@ -0,0 +1,43 @@
/*
* RtpMakerH264.h
*
* Created on: 2016812
* Author: xzl
*/
#ifndef RTP_RTPMAKERH264_H_
#define RTP_RTPMAKERH264_H_
#include <memory>
#include "RtpMaker.h"
#include "Rtsp/RtspMediaSource.h"
#include "Util/logger.h"
#include "Util/RingBuffer.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Rtsp;
namespace ZL {
namespace Rtsp {
class RtpMaker_H264: public RtpMaker {
public:
typedef std::shared_ptr<RtpMaker_H264> Ptr;
RtpMaker_H264(const onGetRTP &cb, uint32_t ui32Ssrc,int iMtuSize = 1400,int iSampleRate = 90000,
uint8_t ui8PlayloadType = 96, uint8_t ui8Interleaved = 0) :
RtpMaker(cb, ui32Ssrc, iMtuSize,iSampleRate, ui8PlayloadType, ui8Interleaved) {
}
virtual ~RtpMaker_H264() {
}
void makeRtp(const char *pcData, int iDataLen, uint32_t uiStamp) override;
private:
inline void makeH264Rtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp);
unsigned char aucSectionBuf[1600];
};
} /* namespace RTP */
} /* namespace ZL */
#endif /* RTP_RTPMAKERH264_H_ */

View File

@ -0,0 +1,236 @@
#ifndef __rtmp_h
#define __rtmp_h
#include <memory>
#include <string>
#include "Util/util.h"
#include "Util/logger.h"
#include "Network/sockutil.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Network;
#define PORT 1935
#define DEFAULT_CHUNK_LEN 128
#if !defined(_WIN32)
#define PACKED __attribute__((packed))
#else
#define PACKED
#endif //!defined(_WIN32)
#define HANDSHAKE_PLAINTEXT 0x03
#define RANDOM_LEN (1536 - 8)
#define MSG_SET_CHUNK 1 /*Set Chunk Size (1)*/
#define MSG_ABORT 2 /*Abort Message (2)*/
#define MSG_ACK 3 /*Acknowledgement (3)*/
#define MSG_USER_CONTROL 4 /*User Control Messages (4)*/
#define MSG_WIN_SIZE 5 /*Window Acknowledgement Size (5)*/
#define MSG_SET_PEER_BW 6 /*Set Peer Bandwidth (6)*/
#define MSG_AUDIO 8 /*Audio Message (8)*/
#define MSG_VIDEO 9 /*Video Message (9)*/
#define MSG_DATA 18 /*Data Message (18, 15) AMF0*/
#define MSG_DATA3 15 /*Data Message (18, 15) AMF3*/
#define MSG_CMD 20 /*Command Message AMF0 */
#define MSG_CMD3 17 /*Command Message AMF3 */
#define MSG_OBJECT3 16 /*Shared Object Message (19, 16) AMF3*/
#define MSG_OBJECT 19 /*Shared Object Message (19, 16) AMF0*/
#define MSG_AGGREGATE 22 /*Aggregate Message (22)*/
#define CONTROL_STREAM_BEGIN 0
#define CONTROL_STREAM_EOF 1
#define CONTROL_STREAM_DRY 2
#define CONTROL_SETBUFFER 3
#define CONTROL_STREAM_ISRECORDED 4
#define CONTROL_PING_REQUEST 6
#define CONTROL_PING_RESPONSE 7
#define STREAM_CONTROL 0
#define STREAM_MEDIA 1
#define CHUNK_SERVER_REQUEST 2 /*服务器像客户端发出请求时的chunkID*/
#define CHUNK_CLIENT_REQUEST_BEFORE 3 /*客户端在createStream前,向服务器发出请求的chunkID*/
#define CHUNK_CLIENT_REQUEST_AFTER 4 /*客户端在createStream后,向服务器发出请求的chunkID*/
#define CHUNK_AUDIO 6 /*音频chunkID*/
#define CHUNK_VIDEO 7 /*视频chunkID*/
#define FLV_KEY_FRAME 1
#define FLV_INTER_FRAME 2
#if defined(_WIN32)
#pragma pack(push, 1)
#endif // defined(_WIN32)
class RtmpHandshake {
public:
RtmpHandshake(uint32_t _time, uint8_t *_random = nullptr) {
_time = htonl(_time);
memcpy(timeStamp, &_time, 4);
if (!_random) {
random_generate((char *) random, sizeof(random));
} else {
memcpy(random, _random, sizeof(random));
}
}
uint8_t timeStamp[4];
uint8_t zero[4] = {0};
uint8_t random[RANDOM_LEN];
void random_generate(char* bytes, int size) {
static char cdata[] = { 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x72,
0x74, 0x6d, 0x70, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2d, 0x77, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x2d, 0x77, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x40, 0x31, 0x32, 0x36, 0x2e, 0x63, 0x6f, 0x6d };
for (int i = 0; i < size; i++) {
bytes[i] = cdata[rand() % (sizeof(cdata) - 1)];
}
}
}PACKED;
class RtmpHeader {
public:
uint8_t flags;
uint8_t timeStamp[3];
uint8_t bodySize[3];
uint8_t typeId;
uint8_t streamId[4]; /* Note, this is little-endian while others are BE */
}PACKED;
#if defined(_WIN32)
#pragma pack(pop)
#endif // defined(_WIN32)
class RtmpPacket {
public:
typedef std::shared_ptr<RtmpPacket> Ptr;
uint8_t typeId;
uint32_t bodySize = 0;
uint32_t timeStamp = 0;
bool hasAbsStamp = false;
bool hasExtStamp = false;
uint32_t deltaStamp = 0;
uint32_t streamId;
uint32_t chunkId;
std::string strBuf;
bool isVideoKeyFrame() const {
return typeId == MSG_VIDEO && (uint8_t) strBuf[0] >> 4 == FLV_KEY_FRAME
&& (uint8_t) strBuf[1] == 1;
}
bool isCfgFrame() const {
return (typeId == MSG_VIDEO || typeId == MSG_AUDIO)
&& (uint8_t) strBuf[1] == 0;
}
int getMediaType() const {
switch (typeId) {
case MSG_VIDEO: {
return (uint8_t) strBuf[0] & 0x0F;
}
break;
case MSG_AUDIO: {
return (uint8_t) strBuf[0] >> 4;
}
break;
default:
break;
}
return 0;
}
int getAudioSampleRate() const {
if (typeId != MSG_AUDIO) {
return 0;
}
int flvSampleRate = ((uint8_t) strBuf[0] & 0x0C) >> 2;
const static int sampleRate[] = { 5512, 11025, 22050, 44100 };
return sampleRate[flvSampleRate];
}
int getAudioSampleBit() const {
if (typeId != MSG_AUDIO) {
return 0;
}
int flvSampleBit = ((uint8_t) strBuf[0] & 0x02) >> 1;
const static int sampleBit[] = { 8, 16 };
return sampleBit[flvSampleBit];
}
int getAudioChannel() const {
if (typeId != MSG_AUDIO) {
return 0;
}
int flvStereoOrMono = (uint8_t) strBuf[0] & 0x01;
const static int channel[] = { 1, 2 };
return channel[flvStereoOrMono];
}
string getH264SPS() const {
string ret;
if (getMediaType() != 7) {
return ret;
}
if (!isCfgFrame()) {
return ret;
}
if (strBuf.size() < 13) {
WarnL << "bad H264 cfg!";
return ret;
}
uint16_t sps_size ;
memcpy(&sps_size,strBuf.data() + 11,2);
sps_size = ntohs(sps_size);
if ((int) strBuf.size() < 13 + sps_size) {
WarnL << "bad H264 cfg!";
return ret;
}
ret.assign(strBuf.data() + 13, sps_size);
return ret;
}
string getH264PPS() const {
string ret;
if (getMediaType() != 7) {
return ret;
}
if (!isCfgFrame()) {
return ret;
}
if (strBuf.size() < 13) {
WarnL << "bad H264 cfg!";
return ret;
}
uint16_t sps_size ;
memcpy(&sps_size,strBuf.data() + 11,2);
sps_size = ntohs(sps_size);
if ((int) strBuf.size() < 13 + sps_size + 1 + 2) {
WarnL << "bad H264 cfg!";
return ret;
}
uint16_t pps_size ;
memcpy(&pps_size,strBuf.data() + 13 + sps_size + 1,2);
pps_size = ntohs(pps_size);
if ((int) strBuf.size() < 13 + sps_size + 1 + 2 + pps_size) {
WarnL << "bad H264 cfg!";
return ret;
}
ret.assign(strBuf.data() + 13 + sps_size + 1 + 2, pps_size);
return ret;
}
string getAacCfg() const {
string ret;
if (getMediaType() != 10) {
return ret;
}
if (!isCfgFrame()) {
return ret;
}
if (strBuf.size() < 4) {
WarnL << "bad aac cfg!";
return ret;
}
ret = strBuf.substr(2, 2);
return ret;
}
};
#endif

View File

@ -0,0 +1,161 @@
/*
* RtmpMediaSource.h
*
* Created on: 201691
* Author: xzl
*/
#ifndef SRC_RTMP_RTMPMEDIASOURCE_H_
#define SRC_RTMP_RTMPMEDIASOURCE_H_
#include <mutex>
#include <memory>
#include <string>
#include <functional>
#include <unordered_map>
#include "amf.h"
#include "Rtmp.h"
#include "Common/config.h"
#include "Common/MediaSender.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Util/RingBuffer.h"
#include "Util/TimeTicker.h"
#include "Util/ResourcePool.h"
#include "Util/NoticeCenter.h"
#include "Thread/ThreadPool.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Thread;
namespace ZL {
namespace Rtmp {
class RtmpMediaSource: public enable_shared_from_this<RtmpMediaSource> {
public:
typedef std::shared_ptr<RtmpMediaSource> Ptr;
typedef RingBuffer<RtmpPacket> RingType;
RtmpMediaSource(const string &strApp, const string &strId) :
m_strApp(strApp),
m_strId(strId),
m_pRing(new RingBuffer<RtmpPacket>()),
m_thPool( MediaSender::sendThread()) {
}
virtual ~RtmpMediaSource() {
unregist();
}
const RingType::Ptr &getRing() const {
//获取媒体源的rtp环形缓冲
return m_pRing;
}
virtual void regist() {
//注册该源注册后rtmp服务器才能找到该源
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
if (!g_mapMediaSrc[m_strApp].erase(m_strId)) {
InfoL << "Rtmp src:" << m_strApp << " " << m_strId;
}
g_mapMediaSrc[m_strApp].emplace(m_strId, shared_from_this());
NoticeCenter::Instance().emitEvent(Config::Broadcast::kBroadcastRtmpSrcRegisted,m_strApp.data(),m_strId.data());
}
virtual void unregist() {
//反注册该源
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
auto it = g_mapMediaSrc.find(m_strApp);
if (it == g_mapMediaSrc.end()) {
return;
}
if (it->second.erase(m_strId)) {
if (it->second.size() == 0) {
g_mapMediaSrc.erase(it);
}
InfoL << "Rtmp src:" << m_strApp << " " << m_strId;
}
}
static set<string> getMediaSet() {
set<string> ret;
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
for (auto &pr0 : g_mapMediaSrc) {
for (auto &pr1 : pr0.second) {
if (pr1.second.lock()) {
ret.emplace(pr0.first + "/" + pr1.first);
}
}
}
return ret;
}
static Ptr find(const string &strApp, const string &strId, bool bMake = true) ;
const string& getApp() const {
//获取该源的id
return m_strApp;
}
const string& getId() const {
//获取该源的id
return m_strId;
}
const AMFValue &getMetaData() const {
return m_metadata;
}
template<typename FUN>
void getConfigFrame(const FUN &f) {
lock_guard<recursive_mutex> lock(m_mtxMap);
for (auto &pr : m_mapCfgFrame) {
f(pr.second);
}
}
bool ready() const {
lock_guard<recursive_mutex> lock(m_mtxMap);
return (m_mapCfgFrame.size() != 0);
}
virtual void onGetMetaData(const AMFValue &_metadata) {
m_metadata = _metadata;
}
virtual void onGetMedia(const RtmpPacket &_pkt) {
RtmpPacket & pkt = const_cast<RtmpPacket &>(_pkt);
if (pkt.isCfgFrame()) {
lock_guard<recursive_mutex> lock(m_mtxMap);
m_mapCfgFrame.emplace(pkt.typeId, pkt);
}
auto _ring = m_pRing;
m_thPool.async([_ring,pkt]() {
_ring->write(pkt,pkt.isVideoKeyFrame());
});
}
bool seekTo(uint32_t ui32Stamp) {
if (!m_onSeek) {
return false;
}
return m_onSeek(ui32Stamp);
}
virtual void setOnSeek(const function<bool(uint32_t)> &cb) {
m_onSeek = cb;
}
uint32_t getStamp() {
if (!m_onStamp) {
return 0;
}
return m_onStamp();
}
virtual void setOnStamp(const function<uint32_t()> &cb) {
m_onStamp = cb;
}
protected:
function<bool(uint32_t)> m_onSeek;
function<uint32_t()> m_onStamp;
private:
AMFValue m_metadata;
unordered_map<int, RtmpPacket> m_mapCfgFrame;
mutable recursive_mutex m_mtxMap;
string m_strApp; //媒体app
string m_strId; //媒体id
RingBuffer<RtmpPacket>::Ptr m_pRing; //rtp环形缓冲
ThreadPool &m_thPool;
static unordered_map<string, unordered_map<string,weak_ptr<RtmpMediaSource> > > g_mapMediaSrc; //静态的媒体源表
static recursive_mutex g_mtxMediaSrc; ///访问静态的媒体源表的互斥锁
};
} /* namespace Rtmp */
} /* namespace ZL */
#endif /* SRC_RTMP_RTMPMEDIASOURCE_H_ */

View File

@ -0,0 +1,132 @@
/*
* RtmpParser.h
*
* Created on: 2016122
* Author: xzl
*/
#ifndef SRC_RTMP_RTMPPARSER_H_
#define SRC_RTMP_RTMPPARSER_H_
#include <functional>
#include <unordered_map>
#include "amf.h"
#include "Rtmp.h"
#include "Player/Player.h"
#include "Util/TimeTicker.h"
#include "Player/PlayerBase.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Player;
namespace ZL {
namespace Rtmp {
class RtmpParser : public PlayerBase{
public:
typedef std::shared_ptr<RtmpParser> Ptr;
RtmpParser(const AMFValue &val);
virtual ~RtmpParser();
bool inputRtmp(const RtmpPacket &pkt);
void setOnVideoCB(const function<void(const H264Frame &frame)> &cb) override{
lock_guard<recursive_mutex> lck(m_mtxCB);
onVideo = cb;
}
void setOnAudioCB(const function<void(const AdtsFrame &frame)> &cb) override{
lock_guard<recursive_mutex> lck(m_mtxCB);
onAudio = cb;
}
int getVideoHeight() const override{
return m_iVideoHeight;
}
int getVideoWidth() const override{
return m_iVideoWidth;
}
float getVideoFps() const override{
return m_fVideoFps;
}
int getAudioSampleRate() const override{
return m_iSampleRate;
}
int getAudioSampleBit() const override{
return m_iSampleBit;
}
int getAudioChannel() const override{
return m_iChannel;
}
const string& getPps() const override{
return m_strPPS;
}
const string& getSps() const override{
return m_strSPS;
}
const string& getAudioCfg() const override{
return m_strAudioCfg;
}
bool containAudio() const override{
return m_bHaveAudio;
}
bool containVideo () const override{
return m_bHaveVideo;
}
bool isInited() const override{
if (m_bHaveAudio && !m_strAudioCfg.size()) {
return false;
}
if (m_bHaveVideo && !m_strSPS.size()) {
return false;
}
return true;
}
float getDuration() const override{
return m_fDuration;
}
private:
inline void onCheckMedia(const AMFValue &obj);
//返回值true 代表是i帧第一个rtp包
inline bool inputVideo(const RtmpPacket &pkt);
inline bool inputAudio(const RtmpPacket &pkt);
inline void _onGetH264(const char *pcData, int iLen, uint32_t ui32TimeStamp);
inline void onGetH264(const char *pcData, int iLen, uint32_t ui32TimeStamp);
inline void onGetAAC(const char *pcData, int iLen, uint32_t ui32TimeStamp);
//video
H264Frame m_h264frame;
//aduio
AdtsFrame m_adts;
int m_iSampleRate = 44100;
int m_iSampleBit = 16;
int m_iChannel = 1;
string m_strSPS;
string m_strPPS;
string m_strAudioCfg;
int m_iVideoWidth = 0;
int m_iVideoHeight = 0;
float m_fVideoFps = 0;
bool m_bHaveAudio = false;
bool m_bHaveVideo = false;
float m_fDuration = 0;
function<void(const H264Frame &frame)> onVideo;
function<void(const AdtsFrame &frame)> onAudio;
recursive_mutex m_mtxCB;
};
} /* namespace Rtmp */
} /* namespace ZL */
#endif /* SRC_RTMP_RTMPPARSER_H_ */

View File

@ -0,0 +1,143 @@
/*
* RtmpPlayer2.h
*
* Created on: 20161129
* Author: xzl
*/
#ifndef SRC_RTMP_RtmpPlayer2_H_
#define SRC_RTMP_RtmpPlayer2_H_
#include <memory>
#include <string>
#include <functional>
#include "amf.h"
#include "Rtmp.h"
#include "RtmpProtocol.h"
#include "Player/PlayerBase.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Util/TimeTicker.h"
#include "Network/Socket.h"
#include "Network/TcpClient.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Player;
using namespace ZL::Network;
namespace ZL {
namespace Rtmp {
class RtmpPlayer:public PlayerBase, public TcpClient, public RtmpProtocol{
public:
typedef std::shared_ptr<RtmpPlayer> Ptr;
RtmpPlayer();
virtual ~RtmpPlayer();
void play(const char* strUrl) override;
void pause(bool bPause) override;
void teardown() override;
protected:
virtual bool onCheckMeta(AMFValue &val) =0;
virtual void onMediaData(RtmpPacket &chunkData) =0;
float getProgressTime() const;
void seekToTime(float fTime);
private:
void _onShutdown(const SockException &ex) {
WarnL << ex.getErrCode() << " " << ex.what();
m_pPlayTimer.reset();
m_pMediaTimer.reset();
m_pBeatTimer.reset();
onShutdown(ex);
}
void _onMediaData(RtmpPacket &chunkData) {
m_mediaTicker.resetTime();
onMediaData(chunkData);
}
void _onPlayResult(const SockException &ex) {
WarnL << ex.getErrCode() << " " << ex.what();
m_pPlayTimer.reset();
m_pMediaTimer.reset();
if (!ex) {
m_mediaTicker.resetTime();
weak_ptr<RtmpPlayer> weakSelf = dynamic_pointer_cast<RtmpPlayer>(shared_from_this());
m_pMediaTimer.reset( new Timer(5, [weakSelf]() {
auto strongSelf=weakSelf.lock();
if(!strongSelf) {
return false;
}
if(strongSelf->m_mediaTicker.elapsedTime()>10000) {
//recv media timeout!
strongSelf->_onShutdown(SockException(Err_timeout,"recv rtmp timeout"));
strongSelf->teardown();
return false;
}
return true;
}));
}
onPlayResult(ex);
}
//for Tcpclient
void onRecv(const Socket::Buffer::Ptr &pBuf) override;
void onConnect(const SockException &err) override;
void onErr(const SockException &ex) override;
//fro RtmpProtocol
void onRtmpChunk(RtmpPacket &chunkData) override;
void onStreamDry(uint32_t ui32StreamId) override;
void onSendRawData(const char *pcRawData, int iSize) override {
send(pcRawData, iSize);
}
template<typename FUN>
inline void addOnResultCB(const FUN &fun) {
lock_guard<recursive_mutex> lck(m_mtxOnResultCB);
m_mapOnResultCB.emplace(m_iReqID, fun);
}
template<typename FUN>
inline void addOnStatusCB(const FUN &fun) {
lock_guard<recursive_mutex> lck(m_mtxOnStatusCB);
m_dqOnStatusCB.emplace_back(fun);
}
void onCmd_result(AMFDecoder &dec);
void onCmd_onStatus(AMFDecoder &dec);
void onCmd_onMetaData(AMFDecoder &dec);
inline void send_connect();
inline void send_createStream();
inline void send_play();
inline void send_pause(bool bPause);
string m_strApp;
string m_strStream;
string m_strTcUrl;
bool m_bPaused = false;
unordered_map<int, function<void(AMFDecoder &dec)> > m_mapOnResultCB;
recursive_mutex m_mtxOnResultCB;
deque<function<void(AMFValue &dec)> > m_dqOnStatusCB;
recursive_mutex m_mtxOnStatusCB;
typedef void (RtmpPlayer::*rtmpCMDHandle)(AMFDecoder &dec);
static unordered_map<string, rtmpCMDHandle> g_mapCmd;
//超时功能实现
Ticker m_mediaTicker;
std::shared_ptr<Timer> m_pMediaTimer;
std::shared_ptr<Timer> m_pPlayTimer;
//心跳定时器
std::shared_ptr<Timer> m_pBeatTimer;
//播放进度控制
float m_fSeekTo = 0;
double m_adFistStamp[2] = { 0, 0 };
double m_adNowStamp[2] = { 0, 0 };
Ticker m_aNowStampTicker[2];
};
} /* namespace Rtmp */
} /* namespace ZL */
#endif /* SRC_RTMP_RtmpPlayer2_H_ */

View File

@ -0,0 +1,62 @@
/*
* RtmpPlayerImp.h
*
* Created on: 2016121
* Author: xzl
*/
#ifndef SRC_RTMP_RTMPPLAYERIMP_H_
#define SRC_RTMP_RTMPPLAYERIMP_H_
#include <memory>
#include <functional>
#include "Common/config.h"
#include "RtmpPlayer.h"
#include "RtmpParser.h"
#include "Poller/Timer.h"
#include "Util/TimeTicker.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Player;
namespace ZL {
namespace Rtmp {
class RtmpPlayerImp: public PlayerImp<RtmpPlayer,RtmpParser> {
public:
typedef std::shared_ptr<RtmpPlayerImp> Ptr;
RtmpPlayerImp();
virtual ~RtmpPlayerImp();
float getProgresss() const override{
if(getDuration() > 0){
return getProgressTime() / getDuration();
}
return PlayerBase::getProgresss();
};
void seekTo(float fProgress) override{
fProgress = MAX(float(0),MIN(fProgress,float(1.0)));
seekToTime(fProgress * getDuration());
};
private:
//派生类回调函数
bool onCheckMeta(AMFValue &val) override {
try {
m_parser.reset(new RtmpParser(val));
m_parser->setOnVideoCB(m_onGetVideoCB);
m_parser->setOnAudioCB(m_onGetAudioCB);
return true;
} catch (std::exception &ex) {
WarnL << ex.what();
return false;
}
}
void onMediaData(RtmpPacket &chunkData) override {
m_parser->inputRtmp(chunkData);
}
};
} /* namespace Rtmp */
} /* namespace ZL */
#endif /* SRC_RTMP_RTMPPLAYERIMP_H_ */

View File

@ -0,0 +1,103 @@
/*
* RtmpProtocol.h
*
* Created on: 201727
* Author: xzl
*/
#ifndef SRC_RTMP_RTMPPROTOCOL_H_
#define SRC_RTMP_RTMPPROTOCOL_H_
#include <memory>
#include <string>
#include <functional>
#include "amf.h"
#include "Rtmp.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Util/TimeTicker.h"
#include "Network/Socket.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Network;
namespace ZL {
namespace Rtmp {
class RtmpProtocol {
public:
RtmpProtocol();
virtual ~RtmpProtocol();
//作为客户端发送c0c1等待s0s1s2并且回调
void startClientSession(const function<void()> &cb);
void onParseRtmp(const char *pcRawData,int iSize);
void reset();
protected:
virtual void onSendRawData(const char *pcRawData,int iSize) = 0;
virtual void onRtmpChunk(RtmpPacket &chunkData) = 0;
virtual void onStreamBegin(uint32_t ui32StreamId){
m_ui32StreamId = ui32StreamId;
}
virtual void onStreamEof(uint32_t ui32StreamId){};
virtual void onStreamDry(uint32_t ui32StreamId){};
protected:
void sendAcknowledgement(uint32_t ui32Size);
void sendAcknowledgementSize(uint32_t ui32Size);
void sendPeerBandwidth(uint32_t ui32Size);
void sendChunkSize(uint32_t ui32Size);
void sendPingRequest(uint32_t ui32TimeStamp = ::time(NULL));
void sendPingResponse(uint32_t ui32TimeStamp = ::time(NULL));
void sendSetBufferLength(uint32_t ui32StreamId, uint32_t ui32Length);
void sendUserControl(uint16_t ui16EventType, uint32_t ui32EventData);
void sendUserControl(uint16_t ui16EventType, const string &strEventData);
void sendInvoke(const string &strCmd, const AMFValue &val);
void sendRequest(int iCmd, const string &str);
void sendResponse(int iType, const string &str);
void sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, const std::string &strBuf, uint32_t ui32TimeStamp, int iChunkID);
protected:
int m_iReqID = 0;
uint32_t m_ui32StreamId = STREAM_CONTROL;
int m_iNowStreamID = 0;
int m_iNowChunkID = 0;
bool m_bDataStarted = false;
private:
void handle_S0S1S2(const function<void()> &cb);
void handle_C0C1();
void handle_C1_simple();
#ifdef ENABLE_OPENSSL
void handle_C1_complex();
string get_C1_digest(const uint8_t *ptr,char **digestPos);
string get_C1_key(const uint8_t *ptr);
void check_C1_Digest(const string &digest,const string &data);
void send_complex_S0S1S2(int schemeType,const string &digest);
#endif //ENABLE_OPENSSL
void handle_C2();
void handle_rtmp();
void handle_rtmpChunk(RtmpPacket &chunkData);
////////////ChunkSize////////////
size_t m_iChunkLenIn = DEFAULT_CHUNK_LEN;
size_t m_iChunkLenOut = DEFAULT_CHUNK_LEN;
////////////Acknowledgement////////////
uint32_t m_ui32ByteSent = 0;
uint32_t m_ui32LastSent = 0;
uint32_t m_ui32WinSize = 0;
///////////PeerBandwidth///////////
uint32_t m_ui32Bandwidth = 2500000;
uint8_t m_ui8LimitType = 2;
////////////Chunk////////////
unordered_map<int, RtmpPacket> m_mapChunkData;
//////////Rtmp parser//////////
string m_strRcvBuf;
function<void()> m_nextHandle;
};
} /* namespace Rtmp */
} /* namespace ZL */
#endif /* SRC_RTMP_RTMPPROTOCOL_H_ */

View File

@ -0,0 +1,108 @@
/*
* RtmpPusher.h
*
* Created on: 2017213
* Author: xzl
*/
#ifndef SRC_RTMP_RTMPPUSHER_H_
#define SRC_RTMP_RTMPPUSHER_H_
#include "RtmpProtocol.h"
#include "RtmpMediaSource.h"
#include "Network/TcpClient.h"
namespace ZL {
namespace Rtmp {
class RtmpPusher: public RtmpProtocol , public TcpClient{
public:
typedef std::shared_ptr<RtmpPusher> Ptr;
typedef std::function<void(const SockException &ex)> Event;
RtmpPusher(const char *strApp,const char *strStream);
virtual ~RtmpPusher();
void publish(const char* strUrl);
void teardown();
void setOnPublished(Event onPublished) {
m_onPublished = onPublished;
}
void setOnShutdown(Event onShutdown) {
m_onShutdown = onShutdown;
}
protected:
//for Tcpclient
void onRecv(const Socket::Buffer::Ptr &pBuf) override;
void onConnect(const SockException &err) override;
void onErr(const SockException &ex) override;
//fro RtmpProtocol
void onRtmpChunk(RtmpPacket &chunkData) override;
void onSendRawData(const char *pcRawData, int iSize) override {
send(pcRawData, iSize);
}
private:
void onShutdown(const SockException &ex) {
m_pPublishTimer.reset();
if(m_onShutdown){
m_onShutdown(ex);
}
}
void onPublishResult(const SockException &ex) {
m_pPublishTimer.reset();
if(m_onPublished){
m_onPublished(ex);
}
}
template<typename FUN>
inline void addOnResultCB(const FUN &fun) {
lock_guard<recursive_mutex> lck(m_mtxOnResultCB);
m_mapOnResultCB.emplace(m_iReqID, fun);
}
template<typename FUN>
inline void addOnStatusCB(const FUN &fun) {
lock_guard<recursive_mutex> lck(m_mtxOnStatusCB);
m_dqOnStatusCB.emplace_back(fun);
}
void onCmd_result(AMFDecoder &dec);
void onCmd_onStatus(AMFDecoder &dec);
void onCmd_onMetaData(AMFDecoder &dec);
inline void send_connect();
inline void send_createStream();
inline void send_publish();
inline void send_metaData();
string m_strApp;
string m_strStream;
string m_strTcUrl;
unordered_map<int, function<void(AMFDecoder &dec)> > m_mapOnResultCB;
recursive_mutex m_mtxOnResultCB;
deque<function<void(AMFValue &dec)> > m_dqOnStatusCB;
recursive_mutex m_mtxOnStatusCB;
typedef void (RtmpPusher::*rtmpCMDHandle)(AMFDecoder &dec);
static unordered_map<string, rtmpCMDHandle> g_mapCmd;
//超时功能实现
std::shared_ptr<Timer> m_pPublishTimer;
//源
std::weak_ptr<RtmpMediaSource> m_pMediaSrc;
RtmpMediaSource::RingType::RingReader::Ptr m_pRtmpReader;
//事件监听
Event m_onShutdown;
Event m_onPublished;
};
} /* namespace Rtmp */
} /* namespace ZL */
#endif /* SRC_RTMP_RTMPPUSHER_H_ */

View File

@ -0,0 +1,81 @@
/*
* RtmpSession.h
*
* Created on: 2017210
* Author: xzl
*/
#ifndef SRC_RTMP_RTMPSESSION_H_
#define SRC_RTMP_RTMPSESSION_H_
#include <unordered_map>
#include "amf.h"
#include "Rtmp.h"
#include "utils.h"
#include "Common/config.h"
#include "RtmpProtocol.h"
#include "RtmpToRtspMediaSource.h"
#include "Util/util.h"
#include "Util/TimeTicker.h"
#include "Network/TcpLimitedSession.h"
using namespace ZL::Util;
using namespace ZL::Network;
namespace ZL {
namespace Rtmp {
class RtmpSession: public TcpLimitedSession<MAX_TCP_SESSION> ,public RtmpProtocol{
public:
typedef std::shared_ptr<RtmpSession> Ptr;
RtmpSession(const std::shared_ptr<ThreadPool> &_th, const Socket::Ptr &_sock);
virtual ~RtmpSession();
void onRecv(const Socket::Buffer::Ptr &pBuf) override;
void onError(const SockException &err) override;
void onManager() override;
private:
std::string m_strApp;
std::string m_strId;
double m_dNowReqID = 0;
Ticker m_ticker;//数据接收时间
typedef void (RtmpSession::*rtmpCMDHandle)(AMFDecoder &dec);
static unordered_map<string, rtmpCMDHandle> g_mapCmd;
RingBuffer<RtmpPacket>::RingReader::Ptr m_pRingReader;
std::shared_ptr<RtmpMediaSource> m_pPublisherSrc;
bool m_bPublisherSrcRegisted = false;
std::weak_ptr<RtmpMediaSource> m_pPlayerSrc;
uint32_t m_aui32FirstStamp[2] = {0};
void onProcessCmd(AMFDecoder &dec);
void onCmd_connect(AMFDecoder &dec);
void onCmd_createStream(AMFDecoder &dec);
void onCmd_publish(AMFDecoder &dec);
void onCmd_deleteStream(AMFDecoder &dec);
void onCmd_play(AMFDecoder &dec);
void onCmd_play2(AMFDecoder &dec);
void doPlay();
void onCmd_seek(AMFDecoder &dec);
void onCmd_pause(AMFDecoder &dec);
void setMetaData(AMFDecoder &dec);
void onSendMedia(const RtmpPacket &pkt);
void onSendRawData(const char *pcRawData,int iSize) override{
send(pcRawData, iSize);
}
void onRtmpChunk(RtmpPacket &chunkData) override;
template<typename first, typename second>
inline void sendReply(const char *str, const first &reply, const second &status) {
AMFEncoder invoke;
invoke << str << m_dNowReqID << reply << status;
sendResponse(MSG_CMD, invoke.data());
}
};
} /* namespace Rtmp */
} /* namespace ZL */
#endif /* SRC_RTMP_RTMPSESSION_H_ */

View File

@ -0,0 +1,96 @@
/*
* RtmpToRtspMediaSource.h
*
* Created on: 20161020
* Author: xzl
*/
#ifndef SRC_RTMP_RTMPTORTSPMEDIASOURCE_H_
#define SRC_RTMP_RTMPTORTSPMEDIASOURCE_H_
#include <mutex>
#include <string>
#include <memory>
#include <functional>
#include <unordered_map>
#include "amf.h"
#include "Rtmp.h"
#include "RtmpParser.h"
#include "RtmpMediaSource.h"
#include "RTP/RtpMakerH264.h"
#include "RTP/RtpMakerAAC.h"
#include "Rtsp/RtpParser.h"
#include "Rtsp/RtspMediaSource.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "MediaFile/MediaRecorder.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Rtsp;
using namespace ZL::MediaFile;
namespace ZL {
namespace Rtmp {
#ifdef ENABLE_RTMP2RTSP
class RtmpToRtspMediaSource: public RtmpMediaSource {
public:
typedef std::shared_ptr<RtmpToRtspMediaSource> Ptr;
RtmpToRtspMediaSource(const string &_app, const string &_id);
virtual ~RtmpToRtspMediaSource();
virtual void regist() override;
virtual void unregist() override;
virtual void onGetMetaData(const AMFValue &_metadata) override {
try {
m_pParser.reset(new RtmpParser(_metadata));
m_pRecorder.reset(new MediaRecorder(getApp(),getId(),m_pParser));
m_pParser->setOnAudioCB(std::bind(&RtmpToRtspMediaSource::onGetAdts, this, placeholders::_1));
m_pParser->setOnVideoCB(std::bind(&RtmpToRtspMediaSource::onGetH264, this, placeholders::_1));
} catch (exception &ex) {
WarnL << ex.what();
}
RtmpMediaSource::onGetMetaData(_metadata);
}
virtual void onGetMedia(const RtmpPacket &pkt) override {
if (m_pParser) {
if (!m_pRtspSrc && m_pParser->isInited()) {
makeSDP();
}
m_pParser->inputRtmp(pkt);
}
RtmpMediaSource::onGetMedia(pkt);
}
void setOnSeek(const function<bool(uint32_t)> &cb) override {
RtmpMediaSource::setOnSeek(cb);
if (m_pRtspSrc) {
m_pRtspSrc->setOnSeek(cb);
}
}
void setOnStamp(const function<uint32_t()> &cb) override{
RtmpMediaSource::setOnStamp(cb);
if (m_pRtspSrc) {
m_pRtspSrc->setOnStamp(cb);
}
}
private:
RtmpParser::Ptr m_pParser;
RtspMediaSource::Ptr m_pRtspSrc;
RtpMaker_AAC::Ptr m_pRtpMaker_aac;
RtpMaker_H264::Ptr m_pRtpMaker_h264;
MediaRecorder::Ptr m_pRecorder;
void onGetH264(const H264Frame &frame);
void onGetAdts(const AdtsFrame &frame);
void makeSDP();
};
#else
typedef RtmpMediaSource RtmpToRtspMediaSource;
#endif //ENABLE_RTMP2RTSP
} /* namespace Rtmp */
} /* namespace ZL */
#endif /* SRC_RTMP_RTMPTORTSPMEDIASOURCE_H_ */

View File

@ -0,0 +1,224 @@
#ifndef __amf_h
#define __amf_h
#include <assert.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <map>
enum AMFType {
AMF_NUMBER,
AMF_INTEGER,
AMF_BOOLEAN,
AMF_STRING,
AMF_OBJECT,
AMF_NULL,
AMF_UNDEFINED,
AMF_ECMA_ARRAY,
AMF_STRICT_ARRAY,
};
class AMFValue;
class AMFValue {
public:
AMFValue(AMFType type = AMF_NULL);
AMFValue(const char *s);
AMFValue(const std::string &s);
AMFValue(double n);
AMFValue(int i);
AMFValue(bool b);
AMFValue(const AMFValue &from);
AMFValue(AMFValue &&from);
AMFValue &operator =(const AMFValue &from);
AMFValue &operator =(AMFValue &&from);
~AMFValue();
void clear() {
switch (m_type) {
case AMF_STRING:
m_value.string->clear();
break;
case AMF_OBJECT:
case AMF_ECMA_ARRAY:
m_value.object->clear();
break;
default:
break;
}
}
AMFType type() const {
return m_type;
}
const std::string &as_string() const {
if(m_type != AMF_STRING){
throw std::runtime_error("AMF not a string");
}
return *m_value.string;
}
double as_number() const {
switch (m_type) {
case AMF_NUMBER:
return m_value.number;
case AMF_INTEGER:
return m_value.integer;
case AMF_BOOLEAN:
return m_value.boolean;
break;
default:
throw std::runtime_error("AMF not a number");
break;
}
}
int as_integer() const {
switch (m_type) {
case AMF_NUMBER:
return m_value.number;
case AMF_INTEGER:
return m_value.integer;
case AMF_BOOLEAN:
return m_value.boolean;
break;
default:
throw std::runtime_error("AMF not a integer");
break;
}
}
bool as_boolean() const {
switch (m_type) {
case AMF_NUMBER:
return m_value.number;
case AMF_INTEGER:
return m_value.integer;
case AMF_BOOLEAN:
return m_value.boolean;
break;
default:
throw std::runtime_error("AMF not a boolean");
break;
}
}
const AMFValue &operator[](const char *str) const {
if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) {
throw std::runtime_error("AMF not a object");
}
auto i = m_value.object->find(str);
if (i == m_value.object->end()) {
static AMFValue val(AMF_NULL);
return val;
}
return i->second;
}
template<typename FUN>
void object_for_each(const FUN &fun) const {
if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) {
throw std::runtime_error("AMF not a object");
}
for (auto & pr : *(m_value.object)) {
fun(pr.first, pr.second);
}
}
operator bool() const{
return m_type != AMF_NULL;
}
void set(const std::string &s, const AMFValue &val) {
if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) {
throw std::runtime_error("AMF not a object");
}
m_value.object->emplace(s, val);
}
void add(const AMFValue &val) {
if (m_type != AMF_STRICT_ARRAY) {
throw std::runtime_error("AMF not a array");
}
assert(m_type == AMF_STRICT_ARRAY);
m_value.array->push_back(val);
}
private:
typedef std::map<std::string, AMFValue> mapType;
typedef std::vector<AMFValue> arrayType;
AMFType m_type;
union {
std::string *string;
double number;
int integer;
bool boolean;
mapType *object;
arrayType *array;
} m_value;
friend class AMFEncoder;
const mapType &getMap() const {
if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) {
throw std::runtime_error("AMF not a object");
}
return *m_value.object;
}
const arrayType &getArr() const {
if (m_type != AMF_STRICT_ARRAY) {
throw std::runtime_error("AMF not a array");
}
return *m_value.array;
}
inline void destroy();
inline void init();
};
class AMFDecoder {
public:
AMFDecoder(const std::string &_buf, size_t _pos, int _version = 0) :
buf(_buf), pos(_pos), version(_version) {
}
int getVersion() const {
return version;
}
template<typename TP>
TP load();
private:
const std::string &buf;
size_t pos;
int version;
std::string load_key();
AMFValue load_object();
AMFValue load_ecma();
AMFValue load_arr();
uint8_t front();
uint8_t pop_front();
};
class AMFEncoder {
public:
AMFEncoder & operator <<(const char *s);
AMFEncoder & operator <<(const std::string &s);
AMFEncoder & operator <<(std::nullptr_t);
AMFEncoder & operator <<(const int n);
AMFEncoder & operator <<(const double n);
AMFEncoder & operator <<(const bool b);
AMFEncoder & operator <<(const AMFValue &value);
const std::string data() const {
return buf;
}
void clear() {
buf.clear();
}
private:
void write_key(const std::string &s);
AMFEncoder &write_undefined();
std::string buf;
};
#endif

View File

@ -0,0 +1,17 @@
#ifndef __utils_h
#define __utils_h
#include <stdio.h>
#include <stdint.h>
uint32_t load_be32(const void *p);
uint16_t load_be16(const void *p);
uint32_t load_be24(const void *p);
uint32_t load_le32(const void *p);
void set_be24(void *p, uint32_t val);
void set_le32(void *p, uint32_t val);
void set_be32(void *p, uint32_t val);
#endif

View File

@ -0,0 +1,81 @@
/*
* RtpBroadCaster.h
*
* Created on: 20161223
* Author: xzl
*/
#ifndef SRC_RTSP_RTPBROADCASTER_H_
#define SRC_RTSP_RTPBROADCASTER_H_
#include <mutex>
#include <memory>
#include <unordered_set>
#include <unordered_map>
#include "Common/config.h"
#include "RtspMediaSource.h"
#include "Util/mini.h"
#include "Network/Socket.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Network;
namespace ZL {
namespace Rtsp {
class MultiCastAddressMaker
{
public:
static MultiCastAddressMaker &Instance(){
static MultiCastAddressMaker instance;
return instance;
}
static bool isMultiCastAddress(uint32_t iAddr){
static uint32_t addrMin = mINI::Instance()[Config::MultiCast::kAddrMin].as<uint32_t>();
static uint32_t addrMax = mINI::Instance()[Config::MultiCast::kAddrMax].as<uint32_t>();
return iAddr >= addrMin && iAddr <= addrMax;
}
static string toString(uint32_t iAddr){
iAddr = htonl(iAddr);
return ::inet_ntoa((struct in_addr &)(iAddr));
}
virtual ~MultiCastAddressMaker(){}
std::shared_ptr<uint32_t> obtain(uint32_t iTry = 10);
private:
MultiCastAddressMaker(){};
void release(uint32_t iAddr);
uint32_t m_iAddr = mINI::Instance()[Config::MultiCast::kAddrMin].as<uint32_t>();
recursive_mutex m_mtx;
unordered_set<uint32_t> m_setBadAddr;
};
class RtpBroadCaster {
public:
typedef std::shared_ptr<RtpBroadCaster> Ptr;
typedef function<void()> onDetach;
virtual ~RtpBroadCaster();
static Ptr get(const string &strLocalIp,const string &strApp,const string &strStream);
void setDetachCB(void *listener,const onDetach &cb);
uint16_t getPort(int iTrackId);
string getIP();
private:
static recursive_mutex g_mtx;
static unordered_map<string , weak_ptr<RtpBroadCaster> > g_mapBroadCaster;
static Ptr make(const string &strLocalIp,const string &strApp,const string &strStream);
std::shared_ptr<uint32_t> m_multiAddr;
recursive_mutex m_mtx;
unordered_map<void * , onDetach > m_mapDetach;
RtspMediaSource::RingType::RingReader::Ptr m_pReader;
Socket::Ptr m_apUdpSock[2];
struct sockaddr_in m_aPeerUdpAddr[2];
RtpBroadCaster(const string &strLocalIp,const string &strApp,const string &strStream);
};
} /* namespace Rtsp */
} /* namespace ZL */
#endif /* SRC_RTSP_RTPBROADCASTER_H_ */

View File

@ -0,0 +1,132 @@
/*
* RtpPraser.h
*
* Created on: 201695
* Author: xzl
*/
#ifndef SRC_RTP_RTPPARSER_H_
#define SRC_RTP_RTPPARSER_H_
#include <unordered_map>
#include "Rtsp/Rtsp.h"
#include "Player/Player.h"
#include "Player/PlayerBase.h"
#include "Util/TimeTicker.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Player;
namespace ZL {
namespace Rtsp {
class RtpParser : public PlayerBase{
public:
typedef std::shared_ptr<RtpParser> Ptr;
RtpParser(const string &sdp);
virtual ~RtpParser();
//返回值true 代表是i帧第一个rtp包
bool inputRtp(const RtpPacket &rtp);
void setOnVideoCB(const function<void(const H264Frame &frame)> &cb) override{
lock_guard<recursive_mutex> lck(m_mtxCB);
onVideo = cb;
}
void setOnAudioCB(const function<void(const AdtsFrame &frame)> &cb) override{
lock_guard<recursive_mutex> lck(m_mtxCB);
onAudio = cb;
}
int getVideoHeight() const override{
return m_iVideoHeight;
}
int getVideoWidth() const override{
return m_iVideoWidth;
}
float getVideoFps() const override{
return m_fVideoFps;
}
int getAudioSampleRate() const override{
return m_iSampleRate;
}
int getAudioSampleBit() const override{
return m_iSampleBit;
}
int getAudioChannel() const override{
return m_iChannel;
}
const string& getPps() const override{
return m_strPPS;
}
const string& getSps() const override{
return m_strSPS;
}
const string& getAudioCfg() const override{
return m_strAudioCfg;
}
bool containAudio() const override{
return m_bHaveAudio;
}
bool containVideo() const override{
return m_bHaveVideo;
}
bool isInited() const override{
if (m_bHaveAudio && !m_strAudioCfg.size()) {
return false;
}
if (m_bHaveVideo && !m_strSPS.size()) {
return false;
}
return true;
}
float getDuration() const override {
return m_fDuration;
}
private:
std::unordered_map<uint8_t, RtspTrack> m_mapTracks;
inline void onGetAudioTrack(const RtspTrack &audio);
inline void onGetVideoTrack(const RtspTrack &video);
//返回值true 代表是i帧第一个rtp包
inline bool inputVideo(const RtpPacket &rtp, const RtspTrack &track);
inline bool inputAudio(const RtpPacket &rtp, const RtspTrack &track);
inline void _onGetH264(H264Frame &frame);
inline void onGetH264(H264Frame &frame);
inline void onGetAdts(AdtsFrame &frame);
//video
H264Frame m_h264frame;
//aduio
AdtsFrame m_adts;
int m_iSampleRate = 44100;
int m_iSampleBit = 16;
int m_iChannel = 1;
string m_strSPS;
string m_strPPS;
string m_strAudioCfg;
int m_iVideoWidth = 0;
int m_iVideoHeight = 0;
float m_fVideoFps = 0;
bool m_bHaveAudio = false;
bool m_bHaveVideo= false;
float m_fDuration = 0;
function<void(const H264Frame &frame)> onVideo;
function<void(const AdtsFrame &frame)> onAudio;
recursive_mutex m_mtxCB;
};
} /* namespace Rtsp */
} /* namespace ZL */
#endif /* SRC_RTP_RTPPARSER_H_ */

View File

@ -0,0 +1,169 @@
#ifndef RTSP_RTSP_H_
#define RTSP_RTSP_H_
#include <string.h>
#include <string>
#include <memory>
#include <unordered_map>
#include "Common/config.h"
#include "Util/util.h"
using namespace std;
using namespace ZL::Util;
typedef enum {
TrackVideo = 0, TrackAudio
} TrackType;
class RtspTrack{
public:
uint8_t PT;
uint8_t trackId;
uint8_t interleaved;
TrackType type = (TrackType) -1;
string trackSdp;
string trackStyle;
bool inited;
uint32_t ssrc = 0;
uint16_t seq;
uint32_t timeStamp;
};
class RtpPacket {
public:
typedef std::shared_ptr<RtpPacket> Ptr;
uint8_t interleaved;
uint8_t PT;
bool mark;
uint32_t length;
uint32_t timeStamp;
uint16_t sequence;
uint32_t ssrc;
uint8_t payload[1560];
TrackType type;
};
class RtcpCounter {
public:
uint32_t pktCnt = 0;
uint32_t octCount = 0;
uint32_t timeStamp = 0;
};
string FindField(const char* buf, const char* start, const char *end,int bufSize = 0 );
int parserSDP(const string& sdp, RtspTrack Track[2]);
struct StrCaseCompare
{
bool operator()(const string& __x, const string& __y) const
{return strcasecmp(__x.data(), __y.data()) < 0 ;}
};
typedef map<string,string,StrCaseCompare> StrCaseMap;
class Parser {
public:
Parser() {
}
virtual ~Parser() {
}
void Parse(const char *buf) {
//解析
const char *start = buf;
string line;
string field;
string value;
Clear();
while (true) {
line = FindField(start, NULL, "\r\n");
if (line.size() == 0) {
break;
}
if (start == buf) {
m_strMethod = FindField(line.c_str(), NULL, " ");
m_strUrl = FindField(line.c_str(), " ", " ");
m_strTail = FindField(line.c_str(), (m_strUrl + " ").c_str(), NULL);
} else {
field = FindField(line.c_str(), NULL, ": ");
value = FindField(line.c_str(), ": ", NULL);
if (field.size() != 0) {
m_mapValues[field] = value;
}
}
start = start + line.size() + 2;
if (strncmp(start, "\r\n", 2) == 0) { //协议解析完毕
m_strContent = FindField(start, "\r\n", NULL);
break;
}
}
}
const string& Method() const {
//rtsp方法
return m_strMethod;
}
const string& Url() const {
//rtsp url
return m_strUrl;
}
const string& Tail() const {
//RTSP/1.0
return m_strTail;
}
const string& operator[](const char *name) const {
//rtsp field
auto it = m_mapValues.find(name);
if (it == m_mapValues.end()) {
return m_strNull;
}
return it->second;
}
const string& Content() const {
return m_strContent;
}
void Clear() {
m_strMethod.clear();
m_strUrl.clear();
m_strTail.clear();
m_strContent.clear();
m_mapValues.clear();
}
void setUrl(const string& url) {
this->m_strUrl = url;
}
void setContent(const string& content) {
this->m_strContent = content;
}
const StrCaseMap& getValues() const {
return m_mapValues;
}
private:
string m_strMethod;
string m_strUrl;
string m_strTail;
string m_strContent;
string m_strNull;
StrCaseMap m_mapValues;
};
typedef struct {
unsigned forbidden_zero_bit :1;
unsigned nal_ref_idc :2;
unsigned type :5;
} NALU;
typedef struct {
unsigned S :1;
unsigned E :1;
unsigned R :1;
unsigned type :5;
} FU;
bool MakeNalu(char in, NALU &nal) ;
bool MakeFU(char in, FU &fu) ;
#endif //RTSP_RTSP_H_

View File

@ -0,0 +1,163 @@
/*
* RtspMediaSource.h
*
* Created on: 2016810
* Author: xzl
*/
#ifndef SRC_RTSP_RTSPMEDIASOURCE_H_
#define SRC_RTSP_RTSPMEDIASOURCE_H_
#include <mutex>
#include <string>
#include <memory>
#include <functional>
#include <unordered_map>
#include "Rtsp.h"
#include "Common/config.h"
#include "Common/MediaSender.h"
#include "Util/logger.h"
#include "Util/RingBuffer.h"
#include "Util/TimeTicker.h"
#include "Util/ResourcePool.h"
#include "Util/NoticeCenter.h"
#include "Thread/ThreadPool.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Thread;
namespace ZL {
namespace Rtsp {
class RtspMediaSource: public enable_shared_from_this<RtspMediaSource> {
public:
typedef ResourcePool<RtpPacket, 64> PoolType;
typedef std::shared_ptr<RtspMediaSource> Ptr;
typedef RingBuffer<RtpPacket::Ptr> RingType;
RtspMediaSource(const string &strApp, const string &strId) :
m_strApp(strApp),
m_strId(strId),
m_pRing(new RingBuffer<RtpPacket::Ptr>()),
m_thPool(MediaSender::sendThread()) {
}
virtual ~RtspMediaSource() {
unregist();
}
const RingType::Ptr &getRing() const {
//获取媒体源的rtp环形缓冲
return m_pRing;
}
const string& getSdp() const {
//获取该源的媒体描述信息
return m_strSdp;
}
virtual void regist() {
//注册该源注册后rtsp服务器才能找到该源
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
if (!g_mapMediaSrc[m_strApp].erase(m_strId)) {
InfoL << "Rtsp src:" << m_strApp << " " << m_strId;
}
g_mapMediaSrc[m_strApp].emplace(m_strId, shared_from_this());
NoticeCenter::Instance().emitEvent(Config::Broadcast::kBroadcastRtspSrcRegisted,m_strApp.data(),m_strId.data());
}
virtual void unregist() {
//反注册该源
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
auto it = g_mapMediaSrc.find(m_strApp);
if (it == g_mapMediaSrc.end()) {
return;
}
if (it->second.erase(m_strId)) {
if(it->second.size() == 0){
g_mapMediaSrc.erase(it);
}
InfoL << "Rtsp src:" << m_strApp << " " << m_strId;
}
}
static set<string> getMediaSet() {
set<string> ret;
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
for (auto &pr0 : g_mapMediaSrc) {
for (auto &pr1 : pr0.second) {
if(pr1.second.lock()){
ret.emplace(pr0.first + "/" + pr1.first);
}
}
}
return ret;
}
static Ptr find(const string &_app, const string &_id,bool bMake = true) ;
const string& getApp() const {
//获取该源的id
return m_strApp;
}
const string& getId() const {
return m_strId;
}
virtual uint32_t getSsrc(int trackId) {
return m_mapTracks[trackId].ssrc;
}
virtual uint16_t getSeqence(int trackId) {
return m_mapTracks[trackId].seq;
}
virtual uint32_t getTimestamp(int trackId) {
return m_mapTracks[trackId].timeStamp;
}
virtual void onGetSDP(const string& sdp) {
//派生类设置该媒体源媒体描述信息
this->m_strSdp = sdp;
}
virtual void onGetRTP(const RtpPacket::Ptr &rtppt, bool keyPos) {
auto &trackRef = m_mapTracks[rtppt->interleaved / 2];
trackRef.seq = rtppt->sequence;
trackRef.timeStamp = rtppt->timeStamp;
trackRef.ssrc = rtppt->ssrc;
trackRef.type = rtppt->type;
auto _outRing = m_pRing;
m_thPool.async([_outRing,rtppt,keyPos]() {
_outRing->write(rtppt,keyPos);
});
}
bool seekTo(uint32_t ui32Stamp) {
if (!m_onSeek) {
return false;
}
return m_onSeek(ui32Stamp);
}
virtual void setOnSeek(const function<bool(uint32_t)> &cb){
m_onSeek = cb;
}
uint32_t getStamp() {
if (!m_onStamp) {
return 0;
}
return m_onStamp();
}
virtual void setOnStamp(const function<uint32_t()> &cb) {
m_onStamp = cb;
}
protected:
function<bool(uint32_t)> m_onSeek;
function<uint32_t()> m_onStamp;
unordered_map<int, RtspTrack> m_mapTracks;
private:
string m_strSdp; //媒体描述信息
string m_strApp; //媒体app
string m_strId; //媒体id
RingType::Ptr m_pRing; //rtp环形缓冲
ThreadPool &m_thPool;
static unordered_map<string, unordered_map<string, weak_ptr<RtspMediaSource> > > g_mapMediaSrc; //静态的媒体源表
static recursive_mutex g_mtxMediaSrc; ///访问静态的媒体源表的互斥锁
};
} /* namespace Rtsp */
} /* namespace ZL */
#endif /* SRC_RTSP_RTSPMEDIASOURCE_H_ */

View File

@ -0,0 +1,165 @@
/*
* RtspPlayer.h
*
* Created on: 2016817
* Author: xzl
*/
#ifndef SRC_RTSPPLAYER_RTSPPLAYER_H_TXT_
#define SRC_RTSPPLAYER_RTSPPLAYER_H_TXT_
#include <string>
#include <memory>
#include "Rtsp.h"
#include "RtspSession.h"
#include "RtspMediaSource.h"
#include "Player/PlayerBase.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Util/TimeTicker.h"
#include "Poller/Timer.h"
#include "Network/Socket.h"
#include "Network/TcpClient.h"
using namespace std;
using namespace ZL::Rtsp;
using namespace ZL::Player;
using namespace ZL::Util;
using namespace ZL::Poller;
using namespace ZL::Network;
namespace ZL {
namespace Rtsp {
//实现了rtsp播放器协议部分的功能
class RtspPlayer: public PlayerBase,public TcpClient {
public:
typedef std::shared_ptr<RtspPlayer> Ptr;
//设置rtp传输类型可选项有0(tcp默认)、1(udp)、2(组播)
//设置方法:player[RtspPlayer::kRtpType] = 0/1/2;
static const char kRtpType[];
RtspPlayer();
virtual ~RtspPlayer(void);
void play(const char* strUrl) override;
void pause(bool bPause) override;
void teardown() override;
float getRtpLossRate(int iTrackId) const override;
protected:
//派生类回调函数
virtual bool onCheckSDP(const string &strSdp, const RtspTrack *pTrack, int iTrackCnt) = 0;
virtual void onRecvRTP(const RtpPacket::Ptr &pRtppt, const RtspTrack &track) = 0;
float getProgressTime() const;
void seekToTime(float fTime);
private:
void _onShutdown(const SockException &ex) {
WarnL << ex.getErrCode() << " " << ex.what();
m_pPlayTimer.reset();
m_pRtpTimer.reset();
m_pBeatTimer.reset();
onShutdown(ex);
}
void _onRecvRTP(const RtpPacket::Ptr &pRtppt, const RtspTrack &track) {
m_rtpTicker.resetTime();
onRecvRTP(pRtppt,track);
}
void _onPlayResult(const SockException &ex) {
WarnL << ex.getErrCode() << " " << ex.what();
m_pPlayTimer.reset();
m_pRtpTimer.reset();
if (!ex) {
m_rtpTicker.resetTime();
weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
m_pRtpTimer.reset( new Timer(5, [weakSelf]() {
auto strongSelf=weakSelf.lock();
if(!strongSelf) {
return false;
}
if(strongSelf->m_rtpTicker.elapsedTime()>10000) {
//recv rtp timeout!
strongSelf->_onShutdown(SockException(Err_timeout,"recv rtp timeout"));
strongSelf->teardown();
return false;
}
return true;
}));
}
onPlayResult(ex);
}
void play(const char* strUrl, const char *strUser, const char *strPwd, eRtpType eType);
void onConnect(const SockException &err) override;
void onRecv(const Socket::Buffer::Ptr &pBuf) override;
void onErr(const SockException &ex) override;
void HandleResSETUP(const Parser &parser, unsigned int uiTrackIndex);
void HandleResDESCRIBE(const Parser &parser);
void HandleResPAUSE(const Parser &parser, bool bPause);
//发数据给服务器
inline int write(const char *strMsg, ...);
inline int onProcess(const char* strBuf);
//生成rtp包结构体
inline void splitRtp(unsigned char *pucData, unsigned int uiLen);
//发送SETUP命令
inline void sendSetup(unsigned int uiTrackIndex);
inline void sendPause(bool bPause,float fTime);
//处理一个rtp包
inline bool HandleOneRtp(int iTrackidx, unsigned char *ucData, unsigned int uiLen);
bool sendOptions();
inline void _onRecvRTP(const RtpPacket::Ptr &pRtppt, int iTrackidx);
inline int getTrackIndex(int iTrackId) const{
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
if (m_aTrackInfo[i].trackId == iTrackId) {
return i;
}
}
return -1;
}
string m_strUrl;
unsigned int m_uiTrackCnt = 0;
RtspTrack m_aTrackInfo[2];
function<void(const Parser&)> m_onHandshake;
RtspMediaSource::PoolType m_pktPool;
uint8_t *m_pucRtpBuf = nullptr;
unsigned int m_uiRtpBufLen = 0;
Socket::Ptr m_apUdpSock[2];
//rtsp info
string m_strSession;
unsigned int m_uiCseq = 1;
uint32_t m_aui32SsrcErrorCnt[2] = { 0, 0 };
string m_strAuthorization;
string m_strContentBase;
eRtpType m_eType = RTP_TCP;
/* RTP包排序所用参数 */
uint16_t m_aui16LastSeq[2] = { 0 , 0 };
uint64_t m_aui64SeqOkCnt[2] = { 0 , 0};
bool m_abSortStarted[2] = { 0 , 0};
map<uint32_t , RtpPacket::Ptr> m_amapRtpSort[2];
/* 丢包率统计需要用到的参数 */
uint16_t m_aui16FirstSeq[2] = { 0 , 0};
uint16_t m_aui16NowSeq[2] = { 0 , 0 };
uint64_t m_aui64RtpRecv[2] = { 0 , 0};
//超时功能实现
Ticker m_rtpTicker;
std::shared_ptr<Timer> m_pPlayTimer;
std::shared_ptr<Timer> m_pRtpTimer;
//心跳定时器
std::shared_ptr<Timer> m_pBeatTimer;
//播放进度控制
float m_fSeekTo = 0;
double m_adFistStamp[2] = {0,0};
double m_adNowStamp[2] = {0,0};
Ticker m_aNowStampTicker[2];
};
} /* namespace Rtsp */
} /* namespace ZL */
#endif /* SRC_RTSPPLAYER_RTSPPLAYER_H_TXT_ */

View File

@ -0,0 +1,65 @@
/*
* RtspParserTester.h
*
* Created on: 201695
* Author: xzl
*/
#ifndef SRC_RTP_RTPPARSERTESTER_H_
#define SRC_RTP_RTPPARSERTESTER_H_
#include <memory>
#include <algorithm>
#include <functional>
#include "Common/config.h"
#include "RtpParser.h"
#include "RtspPlayer.h"
#include "Poller/Timer.h"
#include "Util/TimeTicker.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Player;
namespace ZL {
namespace Rtsp {
class RtspPlayerImp: public PlayerImp<RtspPlayer,RtpParser> {
public:
typedef std::shared_ptr<RtspPlayerImp> Ptr;
RtspPlayerImp();
virtual ~RtspPlayerImp();
float getProgresss() const override{
if(getDuration() > 0){
return getProgressTime() / getDuration();
}
return PlayerBase::getProgresss();
};
void seekTo(float fProgress) override{
fProgress = MAX(float(0),MIN(fProgress,float(1.0)));
seekToTime(fProgress * getDuration());
};
private:
//派生类回调函数
bool onCheckSDP(const string &sdp, const RtspTrack *track, int trackCnt) override {
try {
m_parser.reset(new RtpParser(sdp));
m_parser->setOnVideoCB(m_onGetVideoCB);
m_parser->setOnAudioCB(m_onGetAudioCB);
return true;
} catch (std::exception &ex) {
WarnL << ex.what();
return false;
}
}
void onRecvRTP(const RtpPacket::Ptr &rtppt, const RtspTrack &track) override {
m_parser->inputRtp(*rtppt);
}
};
} /* namespace Rtsp */
} /* namespace ZL */
#endif /* SRC_RTP_RTPPARSERTESTER_H_ */

View File

@ -0,0 +1,141 @@
/*
* RtspSession.h
*
* Created on: 2016812
* Author: xzl
*/
#ifndef SESSION_RTSPSESSION_H_
#define SESSION_RTSPSESSION_H_
#include <set>
#include <vector>
#include <unordered_map>
#include "Common/config.h"
#include "Rtsp.h"
#include "RtpBroadCaster.h"
#include "RtspMediaSource.h"
#include "Player/PlayerBase.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Network/TcpLimitedSession.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Rtsp;
using namespace ZL::Player;
using namespace ZL::Network;
namespace ZL {
namespace Rtsp {
class RtspSession;
class RtspSession: public TcpLimitedSession<MAX_TCP_SESSION> {
public:
typedef std::shared_ptr<RtspSession> Ptr;
RtspSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock);
virtual ~RtspSession();
void onRecv(const Socket::Buffer::Ptr &pBuf) override;
void onError(const SockException &err) override;
void onManager() override;
private:
typedef bool (RtspSession::*rtspCMDHandle)();
int send(const string &strBuf) override {
return m_pSender->send(strBuf);
}
int send(const char *pcBuf, int iSize) override {
return m_pSender->send(pcBuf, iSize);
}
void shutdown() override;
bool handleReq_Options(); //处理options方法
bool handleReq_Describe(); //处理describe方法
bool handleReq_Setup(); //处理setup方法
bool handleReq_Play(); //处理play方法
bool handleReq_Pause(); //处理pause方法
bool handleReq_Teardown(); //处理teardown方法
bool handleReq_Get(); //处理Get方法
bool handleReq_Post(); //处理Post方法
bool handleReq_SET_PARAMETER(); //处理SET_PARAMETER方法
void inline send_StreamNotFound(); //rtsp资源未找到
void inline send_UnsupportedTransport(); //不支持的传输模式
void inline send_SessionNotFound(); //会话id错误
void inline send_NotAcceptable(); //rtsp同时播放数限制
inline bool findStream(); //根据rtsp url查找 MediaSource实例
inline void initSender(const std::shared_ptr<RtspSession> &pSession); //处理rtsp over httpquicktime使用的
inline void sendRtpPacket(const RtpPacket &pkt);
inline string printSSRC(uint32_t ui32Ssrc) {
char tmp[9] = { 0 };
ui32Ssrc = htonl(ui32Ssrc);
uint8_t *pSsrc = (uint8_t *) &ui32Ssrc;
for (int i = 0; i < 4; i++) {
sprintf(tmp + 2 * i, "%02X", pSsrc[i]);
}
return tmp;
}
inline int getTrackIndexByTrackId(int iTrackId) {
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
if (iTrackId == m_aTrackInfo[i].trackId) {
return i;
}
}
return -1;
}
inline void onRcvPeerUdpData(int iTrackIdx, const Socket::Buffer::Ptr &pBuf, const struct sockaddr &addr);
inline void tryGetPeerUdpPort();
char *m_pcBuf = nullptr;
Ticker m_ticker;
Parser m_parser; //rtsp解析类
string m_strUrl;
string m_strSdp;
string m_strSession;
bool m_bFirstPlay = true;
string m_strApp;
string m_strStream;
std::weak_ptr<RtspMediaSource> m_pMediaSrc;
static unordered_map<string, rtspCMDHandle> g_mapCmd;
//RTP缓冲
weak_ptr<RingBuffer<RtpPacket::Ptr> > m_pWeakRing;
RingBuffer<RtpPacket::Ptr>::RingReader::Ptr m_pRtpReader;
PlayerBase::eRtpType m_rtpType = PlayerBase::RTP_UDP;
bool m_bSetUped = false;
int m_iCseq = 0;
unsigned int m_uiTrackCnt = 0; //媒体track个数
RtspTrack m_aTrackInfo[2]; //媒体track信息,trackid idx 为数组下标
#ifdef RTSP_SEND_RTCP
RtcpCounter m_aRtcpCnt[2]; //rtcp统计,trackid idx 为数组下标
Ticker m_aRtcpTicker[2]; //rtcp发送时间,trackid idx 为数组下标
inline void sendRTCP();
#endif
//RTP over UDP
bool m_abGotPeerUdp[2] = { false, false }; //获取客户端udp端口计数
weak_ptr<Socket> m_apUdpSock[2]; //发送RTP的UDP端口,trackid idx 为数组下标
std::shared_ptr<struct sockaddr> m_apPeerUdpAddr[2]; //播放器接收RTP的地址,trackid idx 为数组下标
bool m_bListenPeerUdpPort = false;
RtpBroadCaster::Ptr m_pBrdcaster;
//RTSP over HTTP
function<void(void)> m_onDestory;
bool m_bBase64need = false; //是否需要base64解码
Socket::Ptr m_pSender; //回复rtsp时走的tcp通道供quicktime用
//quicktime 请求rtsp会产生两次tcp连接
//一次发送 get 一次发送post需要通过sessioncookie关联起来
string m_strSessionCookie;
static recursive_mutex g_mtxGetter; //对quicktime上锁保护
static recursive_mutex g_mtxPostter; //对quicktime上锁保护
static unordered_map<string, weak_ptr<RtspSession> > g_mapGetter;
static unordered_map<void *, std::shared_ptr<RtspSession> > g_mapPostter;
static string g_serverName;
};
} /* namespace Session */
} /* namespace ZL */
#endif /* SESSION_RTSPSESSION_H_ */

View File

@ -0,0 +1,102 @@
/*
* RtspToRtmpMediaSource.h
*
* Created on: 201697
* Author: xzl
*/
#ifndef SRC_RTSP_RTSPTORTMPMEDIASOURCE_H_
#define SRC_RTSP_RTSPTORTMPMEDIASOURCE_H_
#include "RtpParser.h"
#include "RtspMediaSource.h"
#include "Rtmp/amf.h"
#include "Rtmp/RtmpMediaSource.h"
#include "MediaFile/MediaRecorder.h"
using namespace ZL::Rtmp;
using namespace ZL::MediaFile;
namespace ZL {
namespace Rtsp {
#ifdef ENABLE_RTSP2RTMP
class RtspToRtmpMediaSource: public RtspMediaSource {
public:
typedef std::shared_ptr<RtspToRtmpMediaSource> Ptr;
RtspToRtmpMediaSource(const string &_app,const string &_id,bool bEnableFile = true);
virtual ~RtspToRtmpMediaSource();
virtual void onGetSDP(const string& strSdp) override{
try {
m_pParser.reset(new RtpParser(strSdp));
if(m_bEnableFile){
m_pRecorder.reset(new MediaRecorder(getApp(),getId(),m_pParser));
}
m_pParser->setOnAudioCB( std::bind(&RtspToRtmpMediaSource::onGetAdts, this, placeholders::_1));
m_pParser->setOnVideoCB( std::bind(&RtspToRtmpMediaSource::onGetH264, this, placeholders::_1));
makeMetaData();
} catch (exception &ex) {
WarnL << ex.what();
}
RtspMediaSource::onGetSDP(strSdp);
}
virtual void onGetRTP(const RtpPacket::Ptr &pRtppkt, bool bKeyPos) override{
if (m_pParser) {
bKeyPos = m_pParser->inputRtp(*pRtppkt);
}
RtspMediaSource::onGetRTP(pRtppkt, bKeyPos);
}
virtual void regist() override ;
virtual void unregist() override;
int readerCount(){
return getRing()->readerCount() + (m_pRtmpSrc ? m_pRtmpSrc->getRing()->readerCount() : 0);
}
void setOnSeek(const function<bool(uint32_t)> &cb) override{
RtspMediaSource::setOnSeek(cb);
if(m_pRtmpSrc){
m_pRtmpSrc->setOnSeek(cb);
}
}
void setOnStamp(const function<uint32_t()> &cb) override{
RtspMediaSource::setOnStamp(cb);
if (m_pRtmpSrc) {
m_pRtmpSrc->setOnStamp(cb);
}
}
void updateTimeStamp(uint32_t uiStamp) {
for (auto &pr : m_mapTracks) {
switch (pr.second.type) {
case TrackAudio: {
pr.second.timeStamp = uiStamp * (m_pParser->getAudioSampleRate() / 1000.0);
}
break;
case TrackVideo: {
pr.second.timeStamp = uiStamp * 90;
}
break;
default:
break;
}
}
}
private:
RtpParser::Ptr m_pParser;
RtmpMediaSource::Ptr m_pRtmpSrc;
RtmpPacket m_rtmpPkt;
uint8_t m_ui8AudioFlags = 0;
MediaRecorder::Ptr m_pRecorder;
bool m_bEnableFile = true;
void onGetH264(const H264Frame &frame);
void onGetAdts(const AdtsFrame &frame);
void makeVideoConfigPkt();
void makeAudioConfigPkt();
void makeMetaData();
};
#else
typedef RtspMediaSource RtspToRtmpMediaSource;
#endif //ENABLE_RTSP2RTMP
} /* namespace Rtsp */
} /* namespace ZL */
#endif /* SRC_RTSP_RTSPTORTMPMEDIASOURCE_H_ */

View File

@ -0,0 +1,54 @@
/*
* UDPServer.h
*
* Created on: 2016812
* Author: xzl
*/
#ifndef RTSP_UDPSERVER_H_
#define RTSP_UDPSERVER_H_
#include <mutex>
#include <stdint.h>
#include <unordered_map>
#include <unordered_set>
#include "Util/util.h"
#include "Util/logger.h"
#include "Network/Socket.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Network;
namespace ZL {
namespace Rtsp {
class UDPServer {
public:
typedef function< bool(int, const Socket::Buffer::Ptr &, struct sockaddr *)> onRecvData;
UDPServer();
virtual ~UDPServer();
static UDPServer &Instance() {
static UDPServer *instance(new UDPServer());
return *instance;
}
static void Destory() {
delete &UDPServer::Instance();
}
Socket::Ptr getSock(const char *strLocalIp, int iTrackIndex);
void listenPeer(const char *strPeerIp, void *pSelf, const onRecvData &cb);
void stopListenPeer(const char *strPeerIp, void *pSelf);
private:
void onRcvData(int iTrackId, const Socket::Buffer::Ptr &pBuf,struct sockaddr *pPeerAddr);
void onErr(const string &strKey,const SockException &err);
unordered_map<string, Socket::Ptr> m_mapUpdSock;
mutex m_mtxUpdSock;
unordered_map<string, unordered_map<void *, onRecvData> > m_mapDataHandler;
mutex m_mtxDataHandler;
};
} /* namespace Rtsp */
} /* namespace ZL */
#endif /* RTSP_UDPSERVER_H_ */

View File

@ -0,0 +1,253 @@
/*
* CMD.h
*
* Created on: 2016926
* Author: xzl
*/
#ifndef SRC_SHELL_CMD_H_
#define SRC_SHELL_CMD_H_
#if defined(_WIN32)
#include "win32/getopt.h"
#else
#include <getopt.h>
#endif //defined(_WIN32)
#include <string>
#include <vector>
#include <iostream>
#include <functional>
#include <unordered_map>
#include "Util/util.h"
#include "Util/logger.h"
using namespace std;
using namespace ZL::Util;
namespace ZL {
namespace Shell {
class OutStream {
public:
virtual ~OutStream() {
}
virtual void response(const string &str) =0;
virtual string &operator[](const string &) =0;
virtual int erase(const string &) =0;
};
class Option {
public:
typedef function<bool(OutStream *stream, const char *arg)> OptionHandler;
enum ArgType {
ArgNone = no_argument,
ArgRequired = required_argument,
ArgOptional = optional_argument
};
Option() {
}
Option(char _shortOpt, const char *_longOpt, enum ArgType _argType,
const char *_des, const OptionHandler &_cb) {
shortOpt = _shortOpt;
longOpt = _longOpt;
argType = _argType;
des = _des;
cb = _cb;
}
virtual ~Option() {
}
bool operator()(OutStream *stream, const char *arg){
return cb ? cb(stream,arg): true;
}
private:
friend class OptionParser;
char shortOpt;
string longOpt;
enum ArgType argType;
string des;
OptionHandler cb;
};
class OptionParser {
public:
typedef function< void(OutStream *stream, const unordered_multimap<char, string> &)> OptionCompleted;
OptionParser(const OptionCompleted &_cb) {
onCompleted = _cb;
helper = Option('h', "help", Option::ArgNone, "print this message", [this](OutStream *stream,const char *arg)->bool {
_StrPrinter printer;
for (auto &pr : options) {
printer<<"\t-"<<pr.first<<"\t--"<<pr.second.longOpt<<"\t"<<pr.second.des<<"\r\n";
}
auto sendStr=printer<<endl;
stream->response(sendStr);
return false;
});
}
virtual ~OptionParser() {
}
OptionParser &operator <<(const Option &option) {
options.emplace(option.shortOpt, option);
return *this;
}
void operator <<(ostream&(*f)(ostream&)) {
str_shortOpt.clear();
vec_longOpt.clear();
(*this) << helper;
struct option tmp;
for (auto &pr : options) {
//long opt
tmp.name = (char *)pr.second.longOpt.data();
tmp.has_arg = pr.second.argType;
tmp.flag = NULL;
tmp.val = pr.first;
vec_longOpt.emplace_back(tmp);
//short opt
str_shortOpt.push_back(pr.first);
switch (pr.second.argType) {
case Option::ArgRequired:
str_shortOpt.append(":");
break;
case Option::ArgOptional:
str_shortOpt.append("::");
break;
default:
break;
}
}
tmp.flag=0;
tmp.name=0;
tmp.has_arg=0;
tmp.val=0;
vec_longOpt.emplace_back(tmp);
}
bool operator ()(OutStream *stream, int argc, char *argv[]) {
lock_guard<mutex> lck(mtx_opt);
unordered_multimap<char, string> allArg;
int opt;
optind = 0;
while ((opt = getopt_long(argc, argv, &str_shortOpt[0], &vec_longOpt[0],NULL)) != -1) {
auto it = options.find(opt);
if (it == options.end()) {
string sendStr = StrPrinter << "\tUnrecognized option. Enter \"-h\" to get help.\r\n" << endl;
stream->response(sendStr);
return true;
}
allArg.emplace(it->first, optarg ? optarg : "");
if (!it->second(stream, optarg)) {
return true;
}
optarg = NULL;
}
if(!allArg.size() && options.size()){
helper(stream,"");
return true;
}
if (onCompleted) {
onCompleted(stream, allArg);
}
return true;
}
private:
unordered_map<char, Option> options;
OptionCompleted onCompleted;
vector<struct option> vec_longOpt;
string str_shortOpt;
Option helper;
static mutex mtx_opt;
};
class CMD {
public:
CMD();
virtual ~CMD();
virtual const char *description() const {
return "description";
}
bool operator ()(OutStream *stream, int argc, char *argv[]) const {
return (*parser)(stream, argc, argv);
}
protected:
mutable std::shared_ptr<OptionParser> parser;
};
template<typename C>
class CMDInstance {
public:
static CMD &Instance() {
static C instance;
return (CMD &) instance;
}
};
class CMD_help: public CMD {
public:
CMD_help();
virtual ~CMD_help() {
}
const char *description() const override {
return "打印帮助信息.";
}
};
class CMD_rtsp: public CMD {
public:
CMD_rtsp();
virtual ~CMD_rtsp() {
}
const char *description() const override {
return "查看rtsp服务器相关信息.";
}
};
class CMD_rtmp: public CMD {
public:
CMD_rtmp();
virtual ~CMD_rtmp() {
}
const char *description() const override {
return "查看rtmp服务器相关信息.";
}
};
} /* namespace Shell */
} /* namespace ZL */
#endif /* SRC_SHELL_CMD_H_ */

View File

@ -0,0 +1,64 @@
/*
* ShellSession.h
*
* Created on: 2016926
* Author: xzl
*/
#ifndef SRC_SHELL_SHELLSESSION_H_
#define SRC_SHELL_SHELLSESSION_H_
#include <functional>
#include "CMD.h"
#include "Common/config.h"
#include "Util/TimeTicker.h"
#include "Network/TcpLimitedSession.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Network;
namespace ZL {
namespace Shell {
class ShellSession: public TcpLimitedSession<MAX_TCP_SESSION>, public OutStream {
public:
ShellSession(const std::shared_ptr<ThreadPool> &_th, const Socket::Ptr &_sock);
virtual ~ShellSession();
void onRecv(const Socket::Buffer::Ptr &) override;
void onError(const SockException &err) override;
void onManager() override;
static void addUser(const string &userName,const string &userPwd){
g_mapUser[userName] = userPwd;
}
private:
friend class CMD_help;
inline bool onProcessLine(const string &);
inline void requestLogin();
inline void requestPasswd();
inline void sendHead();
inline bool authUser(const string &user, const string &pwd);
void response(const string &str) override{
send(str);
}
string &operator[](const string &key) override{
return m_mapConfig[key];
}
int erase(const string &key) override{
return m_mapConfig.erase(key);
}
function<bool(const string &)> m_requestCB;
string m_strRecvBuf;
Ticker m_beatTicker;
string m_strUserName;
unordered_map<string,string> m_mapConfig;
static unordered_map<string, string> g_mapUser;
static map<string, CMD&> g_mapCmd;
static string g_serverName;
};
} /* namespace Shell */
} /* namespace ZL */
#endif /* SRC_SHELL_SHELLSESSION_H_ */

View File

@ -0,0 +1,128 @@
/* Declarations for getopt.
Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if __STDC__
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
//#if __STDC__ || defined(PROTO)
//#if defined(__GNU_LIBRARY__)
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
//#endif /* not __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
/* extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only); */
//#else /* not __STDC__ */
//extern int getopt ();
//extern int getopt_long ();
//extern int getopt_long_only ();
//extern int _getopt_internal ();
//#endif /* not __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* _GETOPT_H */

View File

@ -0,0 +1,329 @@
/* tailor.h -- target dependent definitions
* Copyright (C) 1992-1993 Jean-loup Gailly.
* This is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, see the file COPYING.
*/
/* The target dependent definitions should be defined here only.
* The target dependent functions should be defined in tailor.c.
*/
/* $Id: tailor.h,v 0.18 1993/06/14 19:32:20 jloup Exp $ */
#if defined(__MSDOS__) && !defined(MSDOS)
# define MSDOS
#endif
#if defined(__OS2__) && !defined(OS2)
# define OS2
#endif
#if defined(OS2) && defined(MSDOS) /* MS C under OS/2 */
# undef MSDOS
#endif
#ifdef MSDOS
# ifdef __GNUC__
/* DJGPP version 1.09+ on MS-DOS.
* The DJGPP 1.09 stat() function must be upgraded before gzip will
* fully work.
* No need for DIRENT, since <unistd.h> defines POSIX_SOURCE which
* implies DIRENT.
*/
# define near
# else
# define MAXSEG_64K
# ifdef __TURBOC__
# define NO_OFF_T
# ifdef __BORLANDC__
# define DIRENT
# else
# define NO_UTIME
# endif
# else /* MSC */
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# endif
# endif
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 128
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define NO_CHOWN
# define PROTO
# define STDC_HEADERS
# define NO_SIZE_CHECK
# define casemap(c) tolow(c) /* Force file names to lower case */
# include <io.h>
# define OS_CODE 0x00
# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
# if !defined(NO_ASM) && !defined(ASMV)
# define ASMV
# endif
#else
# define near
#endif
#ifdef OS2
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 260
# ifdef OS2FAT
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define casemap(c) tolow(c)
# endif
# define NO_CHOWN
# define PROTO
# define STDC_HEADERS
# include <io.h>
# define OS_CODE 0x06
# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
# ifdef _MSC_VER
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# define MAXSEG_64K
# undef near
# define near _near
# endif
# ifdef __EMX__
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# define DIRENT
# define EXPAND(argc,argv) \
{_response(&argc, &argv); _wildcard(&argc, &argv);}
# endif
# ifdef __BORLANDC__
# define DIRENT
# endif
# ifdef __ZTC__
# define NO_DIR
# define NO_UTIME_H
# include <dos.h>
# define EXPAND(argc,argv) \
{response_expand(&argc, &argv);}
# endif
#endif
#ifdef WIN32 /* Windows NT */
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 260
# define NO_CHOWN
# define PROTO
# define STDC_HEADERS
# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
# include <io.h>
# include <malloc.h>
# ifdef NTFAT
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define casemap(c) tolow(c) /* Force file names to lower case */
# endif
# define OS_CODE 0x0b
#endif
#ifdef MSDOS
# ifdef __TURBOC__
# include <alloc.h>
# define DYN_ALLOC
/* Turbo C 2.0 does not accept static allocations of large arrays */
void * fcalloc (unsigned items, unsigned size);
void fcfree (void *ptr);
# else /* MSC */
# include <malloc.h>
# define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize))
# define fcfree(ptr) hfree(ptr)
# endif
#else
# ifdef MAXSEG_64K
# define fcalloc(items,size) calloc((items),(size))
# else
# define fcalloc(items,size) malloc((size_t)(items)*(size_t)(size))
# endif
# define fcfree(ptr) free(ptr)
#endif
#if defined(VAXC) || defined(VMS)
# define PATH_SEP ']'
# define PATH_SEP2 ':'
# define SUFFIX_SEP ';'
# define NO_MULTIPLE_DOTS
# define Z_SUFFIX "-gz"
# define RECORD_IO 1
# define casemap(c) tolow(c)
# define OS_CODE 0x02
# define OPTIONS_VAR "GZIP_OPT"
# define STDC_HEADERS
# define NO_UTIME
# define EXPAND(argc,argv) vms_expand_args(&argc,&argv);
# include <file.h>
# define unlink delete
# ifdef VAXC
# define NO_FCNTL_H
# include <unixio.h>
# endif
#endif
#ifdef AMIGA
# define PATH_SEP2 ':'
# define STDC_HEADERS
# define OS_CODE 0x01
# define ASMV
# ifdef __GNUC__
# define DIRENT
# define HAVE_UNISTD_H
# else /* SASC */
# define NO_STDIN_FSTAT
# define SYSDIR
# define NO_SYMLINK
# define NO_CHOWN
# define NO_FCNTL_H
# include <fcntl.h> /* for read() and write() */
# define direct dirent
extern void _expand_args(int *argc, char ***argv);
# define EXPAND(argc,argv) _expand_args(&argc,&argv);
# undef O_BINARY /* disable useless --ascii option */
# endif
#endif
#if defined(ATARI) || defined(atarist)
# ifndef STDC_HEADERS
# define STDC_HEADERS
# define HAVE_UNISTD_H
# define DIRENT
# endif
# define ASMV
# define OS_CODE 0x05
# ifdef TOSFS
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 128
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define NO_CHOWN
# define casemap(c) tolow(c) /* Force file names to lower case */
# define NO_SYMLINK
# endif
#endif
#ifdef MACOS
# define PATH_SEP ':'
# define DYN_ALLOC
# define PROTO
# define NO_STDIN_FSTAT
# define NO_CHOWN
# define NO_UTIME
# define chmod(file, mode) (0)
# define OPEN(name, flags, mode) open(name, flags)
# define OS_CODE 0x07
# ifdef MPW
# define isatty(fd) ((fd) <= 2)
# endif
#endif
#ifdef __50SERIES /* Prime/PRIMOS */
# define PATH_SEP '>'
# define STDC_HEADERS
# define NO_MEMORY_H
# define NO_UTIME_H
# define NO_UTIME
# define NO_CHOWN
# define NO_STDIN_FSTAT
# define NO_SIZE_CHECK
# define NO_SYMLINK
# define RECORD_IO 1
# define casemap(c) tolow(c) /* Force file names to lower case */
# define put_char(c) put_byte((c) & 0x7F)
# define get_char(c) ascii2pascii(get_byte())
# define OS_CODE 0x0F /* temporary, subject to change */
# ifdef SIGTERM
# undef SIGTERM /* We don't want a signal handler for SIGTERM */
# endif
#endif
#if defined(pyr) && !defined(NOMEMCPY) /* Pyramid */
# define NOMEMCPY /* problem with overlapping copies */
#endif
#ifdef TOPS20
# define OS_CODE 0x0a
#endif
#ifndef unix
# define NO_ST_INO /* don't rely on inode numbers */
#endif
/* Common defaults */
#ifndef OS_CODE
# define OS_CODE 0x03 /* assume Unix */
#endif
#ifndef PATH_SEP
# define PATH_SEP '/'
#endif
#ifndef casemap
# define casemap(c) (c)
#endif
#ifndef OPTIONS_VAR
# define OPTIONS_VAR "GZIP"
#endif
#ifndef Z_SUFFIX
# define Z_SUFFIX ".gz"
#endif
#ifdef MAX_EXT_CHARS
# define MAX_SUFFIX MAX_EXT_CHARS
#else
# define MAX_SUFFIX 30
#endif
#ifndef MAKE_LEGAL_NAME
# ifdef NO_MULTIPLE_DOTS
# define MAKE_LEGAL_NAME(name) make_simple_name(name)
# else
# define MAKE_LEGAL_NAME(name)
# endif
#endif
#ifndef MIN_PART
# define MIN_PART 3
/* keep at least MIN_PART chars between dots in a file name. */
#endif
#ifndef EXPAND
# define EXPAND(argc,argv)
#endif
#ifndef RECORD_IO
# define RECORD_IO 0
#endif
#ifndef SET_BINARY_MODE
# define SET_BINARY_MODE(fd)
#endif
#ifndef OPEN
# define OPEN(name, flags, mode) open(name, flags, mode)
#endif
#ifndef get_char
# define get_char() get_byte()
#endif
#ifndef put_char
# define put_char(c) put_byte(c)
#endif

Binary file not shown.

BIN
bin_lib/windows/ZLToolKit.dll Executable file

Binary file not shown.

View File

@ -0,0 +1,246 @@
//
// Socket.h
// xzl
//
// Created by xzl on 16/4/13.
//
#ifndef Socket_h
#define Socket_h
#include <memory>
#include <string>
#include <deque>
#include <mutex>
#include <atomic>
#include <functional>
#include "Util/util.h"
#include "Util/TimeTicker.h"
#include "Poller/Timer.h"
#include "Network/sockutil.h"
#include "Thread/spin_mutex.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Poller;
using namespace ZL::Thread;
namespace ZL {
namespace Network {
#if defined(MSG_NOSIGNAL)
#define FLAG_NOSIGNAL MSG_NOSIGNAL
#else
#define FLAG_NOSIGNAL 0
#endif //MSG_NOSIGNAL
#if defined(MSG_MORE)
#define FLAG_MORE MSG_MORE
#else
#define FLAG_MORE 0
#endif //MSG_MORE
#if defined(MSG_DONTWAIT)
#define FLAG_DONTWAIT MSG_DONTWAIT
#else
#define FLAG_DONTWAIT 0
#endif //MSG_DONTWAIT
#define TCP_DEFAULE_FLAGS (FLAG_NOSIGNAL | FLAG_DONTWAIT)
#define UDP_DEFAULE_FLAGS (FLAG_NOSIGNAL | FLAG_DONTWAIT)
#define MAX_SEND_PKT (256)
#if defined(__APPLE__)
#import "TargetConditionals.h"
#if TARGET_IPHONE_SIMULATOR
#define OS_IPHONE
#elif TARGET_OS_IPHONE
#define OS_IPHONE
#endif
#endif //__APPLE__
typedef enum {
Err_success = 0, //成功
Err_eof, //eof
Err_timeout, //超时
Err_refused,
Err_dns,
Err_other,
} ErrCode;
class SockException: public std::exception {
public:
SockException(ErrCode _errCode = Err_success, const string &_errMsg = "") {
errMsg = _errMsg;
errCode = _errCode;
}
void reset(ErrCode _errCode, const string &_errMsg) {
errMsg = _errMsg;
errCode = _errCode;
}
virtual const char* what() const noexcept {
return errMsg.c_str();
}
ErrCode getErrCode() const {
return errCode;
}
operator bool() const{
return errCode != Err_success;
}
private:
string errMsg;
ErrCode errCode;
};
class SockFD
{
public:
typedef std::shared_ptr<SockFD> Ptr;
SockFD(int sock){
_sock = sock;
}
virtual ~SockFD(){
::shutdown(_sock, SHUT_RDWR);
#if defined (OS_IPHONE)
unsetSocketOfIOS(_sock);
#endif //OS_IPHONE
int fd = _sock;
EventPoller::Instance().delEvent(fd,[fd](bool){
close(fd);
});
}
void setConnected(){
#if defined (OS_IPHONE)
setSocketOfIOS(_sock);
#endif //OS_IPHONE
}
int rawFd() const{
return _sock;
}
private:
int _sock;
#if defined (OS_IPHONE)
void *readStream=NULL;
void *writeStream=NULL;
bool setSocketOfIOS(int socket);
void unsetSocketOfIOS(int socket);
#endif //OS_IPHONE
};
class Socket: public std::enable_shared_from_this<Socket> {
public:
class Buffer {
public:
typedef std::shared_ptr<Buffer> Ptr;
Buffer(uint32_t size) {
_size = size;
_data = new char[size];
}
virtual ~Buffer() {
delete[] _data;
}
const char *data() const {
return _data;
}
uint32_t size() const {
return _size;
}
private:
friend class Socket;
char *_data;
uint32_t _size;
};
typedef std::shared_ptr<Socket> Ptr;
typedef function<void(const Buffer::Ptr &buf, struct sockaddr *addr)> onReadCB;
typedef function<void(const SockException &err)> onErrCB;
typedef function<void(Socket::Ptr &sock)> onAcceptCB;
typedef function<bool()> onFlush;
Socket();
virtual ~Socket();
int rawFD() const{
SockFD::Ptr sock;
{
lock_guard<spin_mutex> lck(_mtx_sockFd);
sock = _sockFd;
}
if(!sock){
return -1;
}
return sock->rawFd();
}
void connect(const string &url, uint16_t port, onErrCB &&connectCB, int timeoutSec = 5);
bool listen(const uint16_t port, const char *localIp = "0.0.0.0", int backLog = 1024);
bool bindUdpSock(const uint16_t port, const char *localIp = "0.0.0.0");
void setOnRead(const onReadCB &cb);
void setOnErr(const onErrCB &cb);
void setOnAccept(const onAcceptCB &cb);
void setOnFlush(const onFlush &cb);
int send(const char *buf, int size = 0,int flags = TCP_DEFAULE_FLAGS);
int send(const string &buf,int flags = TCP_DEFAULE_FLAGS);
int sendTo(const char *buf, int size, struct sockaddr *peerAddr,int flags = UDP_DEFAULE_FLAGS);
int sendTo(const string &buf, struct sockaddr *peerAddr,int flags = UDP_DEFAULE_FLAGS);
bool emitErr(const SockException &err);
void enableRecv(bool enabled);
string get_local_ip();
uint16_t get_local_port();
string get_peer_ip();
uint16_t get_peer_port();
void setSendPktSize(uint32_t iPktSize){
_iMaxSendPktSize = iPktSize;
}
private:
mutable spin_mutex _mtx_sockFd;
SockFD::Ptr _sockFd;
//send buffer
recursive_mutex _mtx_sendBuf;
deque<string> _sendPktBuf;
deque<struct sockaddr> _udpSendPeer;
/////////////////////
std::shared_ptr<Timer> _conTimer;
struct sockaddr _peerAddr;
spin_mutex _mtx_read;
spin_mutex _mtx_err;
spin_mutex _mtx_accept;
spin_mutex _mtx_flush;
onReadCB _readCB;
onErrCB _errCB;
onAcceptCB _acceptCB;
onFlush _flushCB;
Ticker _flushTicker;
int _lastSendFlags = TCP_DEFAULE_FLAGS;
uint32_t _iMaxSendPktSize = MAX_SEND_PKT;
atomic_bool _enableRecv;
void closeSock();
bool setPeerSock(int fd, struct sockaddr *addr);
bool attachEvent(const SockFD::Ptr &pSock,bool isUdp = false);
int onAccept(const SockFD::Ptr &pSock,int event);
int onRead(const SockFD::Ptr &pSock,bool mayEof=true);
void onError(const SockFD::Ptr &pSock);
int realSend(const string &buf, struct sockaddr *peerAddr,int flags);
int onWrite(const SockFD::Ptr &pSock, bool bMainThread,int flags,bool isUdp);
void onConnected(const SockFD::Ptr &pSock, const onErrCB &connectCB);
void onFlushed(const SockFD::Ptr &pSock);
void startWriteEvent(const SockFD::Ptr &pSock);
void stopWriteEvent(const SockFD::Ptr &pSock);
bool sendTimeout(bool isUdp);
SockFD::Ptr makeSock(int sock){
return std::make_shared<SockFD>(sock);
}
static SockException getSockErr(const SockFD::Ptr &pSock,bool tryErrno=true);
};
} // namespace Network
} // namespace ZL
#endif /* Socket_h */

View File

@ -0,0 +1,106 @@
/*
* TcpClient.h
*
* Created on: 2017213
* Author: xzl
*/
#ifndef SRC_NETWORK_TCPCLIENT_H_
#define SRC_NETWORK_TCPCLIENT_H_
#include <memory>
#include <functional>
#include "Socket.h"
#include "Util/TimeTicker.h"
#include "Thread/WorkThreadPool.h"
#include "Thread/spin_mutex.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Thread;
namespace ZL {
namespace Network {
class TcpClient : public std::enable_shared_from_this<TcpClient> {
public:
typedef std::shared_ptr<TcpClient> Ptr;
TcpClient();
virtual ~TcpClient();
protected:
void startConnect(const string &strUrl, uint16_t iPort, int iTimeOutSec = 3);
void shutdown();
virtual int send(const string &str);
virtual int send(const char *str, int len);
bool alive() {
lock_guard<spin_mutex> lck(m_mutex);
return m_pSock.operator bool();
}
string get_local_ip() {
decltype(m_pSock) sockTmp;
{
lock_guard<spin_mutex> lck(m_mutex);
sockTmp = m_pSock;
}
if(!sockTmp){
return "";
}
return sockTmp->get_local_ip();
}
uint16_t get_local_port() {
decltype(m_pSock) sockTmp;
{
lock_guard<spin_mutex> lck(m_mutex);
sockTmp = m_pSock;
}
if(!sockTmp){
return 0;
}
return sockTmp->get_local_port();
}
string get_peer_ip() {
decltype(m_pSock) sockTmp;
{
lock_guard<spin_mutex> lck(m_mutex);
sockTmp = m_pSock;
}
if(!sockTmp){
return "";
}
return sockTmp->get_peer_ip();
}
uint16_t get_peer_port() {
decltype(m_pSock) sockTmp;
{
lock_guard<spin_mutex> lck(m_mutex);
sockTmp = m_pSock;
}
if(!sockTmp){
return 0;
}
return sockTmp->get_peer_port();
}
uint64_t elapsedTime();
//链接成功后客户端将绑定一个后台线程并且onConnect/onRecv/onSend/onErr事件将在该后台线程触发
virtual void onConnect(const SockException &ex) {}
virtual void onRecv(const Socket::Buffer::Ptr &pBuf) {}
virtual void onSend() {}
virtual void onErr(const SockException &ex) {}
Socket::Ptr m_pSock;
private:
Ticker m_ticker;
spin_mutex m_mutex;
void onSockConnect(const SockException &ex);
void onSockRecv(const Socket::Buffer::Ptr &pBuf);
void onSockSend();
void onSockErr(const SockException &ex);
};
} /* namespace Network */
} /* namespace ZL */
#endif /* SRC_NETWORK_TCPCLIENT_H_ */

View File

@ -0,0 +1,64 @@
/*
* Session.h
*
* Created on: 20151027
* Author: root
*/
#ifndef SERVER_LIMITEDSESSION_H_
#define SERVER_LIMITEDSESSION_H_
#include <memory>
#include "Util/logger.h"
#include "TcpSession.h"
using namespace std;
using namespace ZL::Util;
namespace ZL {
namespace Network {
template<int MaxCount>
class TcpLimitedSession: public TcpSession {
public:
TcpLimitedSession(const std::shared_ptr<ThreadPool> &_th, const Socket::Ptr &_sock) :
TcpSession(_th,_sock) {
lock_guard<recursive_mutex> lck(stackMutex());
static uint64_t maxSeq(0);
sessionSeq = maxSeq++;
auto &stack = getStack();
stack.emplace(this);
if(stack.size() > MaxCount){
auto it = stack.begin();
(*it)->safeShutdown();
stack.erase(it);
WarnL << "超过TCP个数限制:" << MaxCount;
}
}
virtual ~TcpLimitedSession() {
lock_guard<recursive_mutex> lck(stackMutex());
getStack().erase(this);
}
private:
uint64_t sessionSeq; //会话栈顺序
struct Comparer {
bool operator()(TcpLimitedSession *x, TcpLimitedSession *y) const {
return x->sessionSeq < y->sessionSeq;
}
};
static recursive_mutex &stackMutex(){
static recursive_mutex mtx;
return mtx;
}
//RTSP会话栈,先创建的在前面
static set<TcpLimitedSession *, Comparer> &getStack(){
static set<TcpLimitedSession *, Comparer> stack;
return stack;
}
};
} /* namespace Session */
} /* namespace ZL */
#endif /* SERVER_LIMITEDSESSION_H_ */

View File

@ -0,0 +1,134 @@
/*
* TcpServer.h
*
* Created on: 201689
* Author: xzl
*/
#ifndef TCPSERVER_TCPSERVER_H_
#define TCPSERVER_TCPSERVER_H_
#include <memory>
#include <exception>
#include <functional>
#include "Socket.h"
#include "Util/util.h"
#include "Util/uv_errno.h"
#include "Util/logger.h"
#include "Poller/Timer.h"
#include "Thread/semaphore.h"
#include "Thread/WorkThreadPool.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Poller;
using namespace ZL::Thread;
namespace ZL {
namespace Network {
template<typename Session>
class TcpServer {
public:
typedef std::shared_ptr<TcpServer> Ptr;
TcpServer() {
socket.reset(new Socket());
sessionMap.reset(new typename decltype(sessionMap)::element_type);
}
~TcpServer() {
TraceL << "start clean...";
timer.reset();
socket.reset();
typename decltype(sessionMap)::element_type copyMap;
sessionMap->swap(copyMap);
for (auto it = copyMap.begin(); it != copyMap.end(); ++it) {
auto session = it->second;
it->second->async_first( [session]() {
session->onError(SockException(Err_other,"Tcp server shutdown!"));
});
}
TraceL << "clean completed!";
}
void start(uint16_t port, const std::string& host = "0.0.0.0", uint32_t backlog = 1024) {
bool success = socket->listen(port, host.c_str(), backlog);
if (!success) {
string err = (StrPrinter << "listen on " << host << ":" << port << "] failed:" << get_uv_errmsg(true)).operator <<(endl);
throw std::runtime_error(err);
}
socket->setOnAccept( bind(&TcpServer::onAcceptConnection, this, placeholders::_1));
timer.reset(new Timer(2, [this]()->bool {
this->onManagerSession();
return true;
}));
InfoL << "TCP Server listening on " << host << ":" << port;
}
private:
Socket::Ptr socket;
std::shared_ptr<Timer> timer;
std::shared_ptr<std::unordered_map<Socket *, std::shared_ptr<Session> > > sessionMap;
void onAcceptConnection(const Socket::Ptr & sock) {
// 接收到客户端连接请求
auto session(std::make_shared<Session>(WorkThreadPool::Instance().getWorkThread(), sock));
auto sockPtr(sock.get());
auto sessionMapTmp(sessionMap);
weak_ptr<Session> weakSession(session);
sessionMapTmp->emplace(sockPtr, session);
// 会话接收数据事件
sock->setOnRead([weakSession](const Socket::Buffer::Ptr &buf, struct sockaddr *addr){
//获取会话强应用
auto strongSession=weakSession.lock();
if(!strongSession) {
//会话对象已释放
return;
}
//在会话线程中执行onRecv操作
strongSession->async([weakSession,buf]() {
auto strongSession=weakSession.lock();
if(!strongSession) {
return;
}
strongSession->onRecv(buf);
});
});
//会话接收到错误事件
sock->setOnErr([weakSession,sockPtr,sessionMapTmp](const SockException &err){
//获取会话强应用
auto strongSession=weakSession.lock();
//移除掉会话
sessionMapTmp->erase(sockPtr);
if(!strongSession) {
//会话对象已释放
return;
}
//在会话线程中执行onError操作
strongSession->async_first([strongSession,err]() {
strongSession->onError(err);
});
});
}
void onManagerSession() {
//DebugL<<EventPoller::Instance().isMainThread();
for (auto &pr : *sessionMap) {
weak_ptr<Session> weakSession = pr.second;
pr.second->async([weakSession]() {
auto strongSession=weakSession.lock();
if(!strongSession) {
return;
}
strongSession->onManager();
});
}
}
};
} /* namespace Network */
} /* namespace ZL */
#endif /* TCPSERVER_TCPSERVER_H_ */

View File

@ -0,0 +1,91 @@
/*
* Session.h
*
* Created on: 20151027
* Author: root
*/
#ifndef SERVER_SESSION_H_
#define SERVER_SESSION_H_
#include <memory>
#include "Socket.h"
#include "Util/logger.h"
#include "Thread/ThreadPool.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Thread;
namespace ZL {
namespace Network {
class TcpSession: public std::enable_shared_from_this<TcpSession> {
public:
TcpSession(const std::shared_ptr<ThreadPool> &_th, const Socket::Ptr &_sock) :
sock(_sock), th(_th) {
localIp = sock->get_local_ip();
peerIp = sock->get_peer_ip();
localPort = sock->get_local_port();
peerPort = sock->get_peer_port();
}
virtual ~TcpSession() {
}
virtual void onRecv(const Socket::Buffer::Ptr &) =0;
virtual void onError(const SockException &err) =0;
virtual void onManager() =0;
template <typename T>
void async(T &&task) {
th->async(std::forward<T>(task));
}
template <typename T>
void async_first(T &&task) {
th->async_first(std::forward<T>(task));
}
protected:
const string& getLocalIp() const {
return localIp;
}
const string& getPeerIp() const {
return peerIp;
}
uint16_t getLocalPort() const {
return localPort;
}
uint16_t getPeerPort() const {
return peerPort;
}
virtual void shutdown() {
sock->emitErr(SockException(Err_other, "self shutdown"));
}
void safeShutdown(){
std::weak_ptr<TcpSession> weakSelf = shared_from_this();
async_first([weakSelf](){
auto strongSelf = weakSelf.lock();
if(strongSelf){
strongSelf->shutdown();
}
});
}
virtual int send(const string &buf) {
return sock->send(buf);
}
virtual int send(const char *buf, int size) {
return sock->send(buf, size);
}
Socket::Ptr sock;
private:
std::shared_ptr<ThreadPool> th;
string localIp;
string peerIp;
uint16_t localPort;
uint16_t peerPort;
};
} /* namespace Session */
} /* namespace ZL */
#endif /* SERVER_SESSION_H_ */

View File

@ -0,0 +1,86 @@
#ifndef SOCKUTIL_H
#define SOCKUTIL_H
#if defined(_WIN32)
#include <WinSock2.h>
#include <Iphlpapi.h>
#pragma comment (lib,"WS2_32")
#pragma comment(lib,"Iphlpapi.lib")
#else
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif // defined(_WIN32)
#include <string>
#include <string.h>
#include <stdint.h>
using namespace std;
#if defined(_WIN32)
#ifndef socklen_t
#define socklen_t int
#endif //!socklen_t
#ifndef SHUT_RDWR
#define SHUT_RDWR 2
#endif //!SHUT_RDWR
int ioctl(int fd, long cmd, u_long *ptr);
int close(int fd);
#endif // defined(_WIN32)
namespace ZL {
namespace Network {
class SockUtil {
public:
static int connect(const char *host, uint16_t port, bool bAsync = true);
static int listen(const uint16_t port, const char *localIp = "0.0.0.0",
int backLog = 1024);
static int bindUdpSock(const uint16_t port,
const char *localIp = "0.0.0.0");
static int setNoDelay(int sockFd, bool on = true);
static int setNoSigpipe(int sock);
static int setNoBlocked(int sock, bool noblock = true);
static int setRecvBuf(int sock, int size = 256 * 1024);
static int setSendBuf(int sock, int size = 256 * 1024);
static int setReuseable(int sockFd, bool on = true);
static int setBroadcast(int sockFd, bool on = true);
static int setKeepAlive(int sockFd, bool on = true);
//组播相关
static int setMultiTTL(int sockFd, uint8_t ttl = 64);
static int setMultiIF(int sockFd, const char *strLocalIp);
static int setMultiLOOP(int sockFd, bool bAccept = false);
static int joinMultiAddr(int sockFd, const char *strAddr, const char* strLocalIp = "0.0.0.0");
static int leaveMultiAddr(int sockFd, const char *strAddr, const char* strLocalIp = "0.0.0.0");
static int joinMultiAddrFilter(int sockFd, const char* strAddr, const char* strSrcIp, const char* strLocalIp = "0.0.0.0");
static int leaveMultiAddrFilter(int sockFd, const char* strAddr, const char* strSrcIp, const char* strLocalIp = "0.0.0.0");
static int getSockError(int sockFd);
static int setCloseWait(int sockFd, int second = 0);
static string get_local_ip(int fd);
static string get_local_ip();
static uint16_t get_local_port(int fd);
static string get_peer_ip(int fd);
static uint16_t get_peer_port(int fd);
static string get_ifr_name(const char *localIp);
static string get_ifr_mask(const char *ifrName);
static string get_ifr_brdaddr(const char *ifrName);
static bool in_same_lan(const char *myIp, const char *dsrIp);
};
} // namespace Network
} // namespace ZL
#endif // !SOCKUTIL_H

View File

@ -0,0 +1,123 @@
//
// EventPoller.h
// xzl
//
// Created by xzl on 16/4/12.
//
#ifndef EventPoller_h
#define EventPoller_h
#include <mutex>
#include <thread>
#include <string>
#include <functional>
#include <unordered_map>
#include "PipeWrap.h"
#include "Util/logger.h"
#include "Util/util.h"
using namespace std;
using namespace ZL::Util;
#if defined(__linux__)
#define HAS_EPOLL
#endif //__linux__
namespace ZL {
namespace Poller {
typedef enum {
Event_Read = 1 << 0, //读事件
Event_Write = 1 << 1, //写事件
Event_Error = 1 << 2, //错误事件
Event_LT = 1 << 3,//水平触发
} Poll_Event;
typedef enum {
Sig_Exit = 0, //关闭监听
Sig_Async, //异步
} Sigal_Type;
typedef function<void(int event)> PollEventCB;
typedef function<void(bool success)> PollDelCB;
typedef function<void(void)> PollAsyncCB;
typedef PollAsyncCB PollSyncCB;
#ifndef HAS_EPOLL
typedef struct {
Poll_Event event;
PollEventCB callBack;
int attach;
void operator()(int _event) const{
callBack(_event);
}
void operator()() const{
callBack(attach);
}
} Poll_Record;
#endif //HAS_EPOLL
class EventPoller {
public:
EventPoller(bool enableSelfRun = false);
virtual ~EventPoller();
static EventPoller &Instance(bool enableSelfRun = false) {
static EventPoller *instance(new EventPoller(enableSelfRun));
return *instance;
}
static void Destory() {
delete &EventPoller::Instance();
}
int addEvent(int fd, int event, PollEventCB &&eventCb);
int delEvent(int fd, PollDelCB &&delCb = nullptr);
int modifyEvent(int fd, int event);
void async(PollAsyncCB &&asyncCb);
void sync(PollSyncCB &&syncCb);
void runLoop();
void shutdown();
bool isMainThread();
private:
void initPoll();
inline int sigalPipe(uint64_t type, uint64_t i64_size = 0, uint64_t *buf = NULL);
inline bool handlePipeEvent();
inline Sigal_Type _handlePipeEvent(uint64_t type, uint64_t i64_size, uint64_t *buf);
PipeWrap _pipe;
bool _exitLoop = false;
thread *loopThread = nullptr;
thread::id mainThreadId;
mutex mtx_event_map;
#if defined(HAS_EPOLL)
int epoll_fd = -1;
unordered_map<int, PollEventCB> event_map;
#else
unordered_map<int, Poll_Record> event_map;
#endif //HAS_EPOLL
string pipeBuffer;
};
#define ASYNC_TRACE(...) {\
/*TraceL;*/\
EventPoller::Instance().async(__VA_ARGS__);\
}
#define SYNC_TRACE(...) {\
/*TraceL;*/\
EventPoller::Instance().sync(__VA_ARGS__);\
}
} // namespace Poller
} // namespace ZL
#endif /* EventPoller_h */

View File

@ -0,0 +1,36 @@
//
// Pipe.h
// xzl
//
// Created by xzl on 16/4/13.
//
#ifndef Pipe_h
#define Pipe_h
#include <stdio.h>
#include <functional>
#include "PipeWrap.h"
#include "EventPoller.h"
using namespace std;
namespace ZL {
namespace Poller {
class Pipe
{
public:
Pipe(function<void(int size,const char *buf)> &&onRead=nullptr);
virtual ~Pipe();
void send(const char *send,int size=0);
private:
std::shared_ptr<PipeWrap> _pipe;
};
} // namespace Poller
} // namespace ZL
#endif /* Pipe_h */

View File

@ -0,0 +1,32 @@
#ifndef PipeWarp_h
#define PipeWarp_h
namespace ZL {
namespace Poller {
class PipeWrap {
public:
PipeWrap();
~PipeWrap();
int write(const void *buf, int n);
int read(void *buf, int n);
int readFD() const {
return _pipe_fd[0];
}
int writeFD() const {
return _pipe_fd[1];
}
private:
int _pipe_fd[2] = { -1,-1 };
void clearFD();
#if defined(_WIN32)
int _listenerFd = -1;
#endif // defined(_WIN32)
};
} /* namespace Poller */
} /* namespace ZL */
#endif // !PipeWarp_h

View File

@ -0,0 +1,34 @@
/*
* WinSelect.h
*
* Created on: 201732
* Author: Jzan
*/
#ifndef SRC_POLLER_SELECTWRAP_H_
#define SRC_POLLER_SELECTWRAP_H_
namespace ZL {
namespace Poller {
class FdSet
{
public:
FdSet();
virtual ~FdSet();
void fdZero();
void fdSet(int fd);
void fdClr(int fd);
bool isSet(int fd);
void *ptr;
private:
};
} /* namespace Poller */
} /* namespace ZL */
using namespace ZL::Poller;
int zl_select(int cnt,FdSet *read,FdSet *write,FdSet *err,struct timeval *tv);
#endif /* SRC_POLLER_SELECTWRAP_H_ */

View File

@ -0,0 +1,32 @@
//
// Timer.h
// xzl
//
// Created by xzl on 16/4/13.
//
#ifndef Timer_h
#define Timer_h
#include <stdio.h>
#include <functional>
#include "EventPoller.h"
#include "Thread/AsyncTaskThread.h"
using namespace std;
using namespace ZL::Thread;
namespace ZL {
namespace Poller {
class Timer {
public:
Timer(float second,const function<bool()> &cb);
virtual ~Timer();
private:
std::shared_ptr<bool> canceled;
};
} // namespace Poller
} // namespace ZL
#endif /* Timer_h */

View File

@ -0,0 +1,77 @@
//
// AsyncTaskThread.h
// xzl
//
// Created by xzl on 15/6/8.
//
#ifndef AsyncTaskThread_h
#define AsyncTaskThread_h
#include <stdio.h>
#include <deque>
#include <mutex>
#include <atomic>
#include <thread>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <condition_variable>
#include "Util/util.h"
using namespace std;
using namespace ZL::Util;
#define TASK_INTERVAL 50
namespace ZL {
namespace Thread {
typedef struct {
uint64_t type;
uint64_t timeLine;
uint64_t tickTime;
function<bool()> task;
} TaskInfo;
class AsyncTaskThread {
public:
//the timer default 30s
AsyncTaskThread(uint64_t millisecond_sleep);
~AsyncTaskThread();
void DoTaskDelay(uint64_t type, uint64_t millisecond, const function<bool()> &func);
void CancelTask(uint64_t type);
static AsyncTaskThread &Instance(uint32_t millisecond_sleep = TASK_INTERVAL) {
static AsyncTaskThread *instance(new AsyncTaskThread(millisecond_sleep));
return *instance;
}
static void Destory(){
delete &AsyncTaskThread::Instance();
}
private:
recursive_mutex _mtx;
unordered_multimap<uint64_t, std::shared_ptr<TaskInfo> > taskMap;
unordered_set<uint64_t> needCancel;
inline uint64_t getNowTime();
thread *taskThread;
void DoTask();
atomic_bool threadExit;
condition_variable_any cond;
uint64_t millisecond_sleep;
};
class AsyncTaskHelper
{
public:
AsyncTaskHelper(uint64_t millisecond,const function<bool()> &task){
AsyncTaskThread::Instance().DoTaskDelay(reinterpret_cast<uint64_t>(this),millisecond,task);
}
virtual ~AsyncTaskHelper(){
AsyncTaskThread::Instance().CancelTask(reinterpret_cast<uint64_t>(this));
}
};
} /* namespace Thread */
} /* namespace ZL */
#endif /* defined(AsyncTaskThread_h) */

View File

@ -0,0 +1,72 @@
/*
* TaskQueue.h
*
* Created on: 2013-10-11
* Author: root
*/
#ifndef TASKQUEUE_H_
#define TASKQUEUE_H_
#include <deque>
#include <atomic>
#include <mutex>
#include <functional>
#include "spin_mutex.h"
#include "semaphore.h"
using namespace std;
namespace ZL {
namespace Thread {
//实现了一个基于函数对象的任务列队,该列队是线程安全的,任务列队任务数由信号量控制
class TaskQueue {
public:
TaskQueue() {
}
//打入任务至列队
template <typename T>
void push_task(T &&task_func) {
{
lock_guard<spin_mutex> lock(my_mutex);
my_queue.emplace_back(std::forward<T>(task_func));
}
sem.post();
}
template <typename T>
void push_task_first(T &&task_func) {
{
lock_guard<spin_mutex> lock(my_mutex);
my_queue.emplace_front(std::forward<T>(task_func));
}
sem.post();
}
//清空任务列队
void push_exit(unsigned int n) {
sem.post(n);
}
//从列队获取一个任务,由执行线程执行
bool get_task(function<void(void)> &tsk) {
sem.wait();
lock_guard<spin_mutex> lock(my_mutex);
if (my_queue.size() == 0) {
return false;
}
tsk = my_queue.front();
my_queue.pop_front();
return true;
}
uint64_t size() const{
lock_guard<spin_mutex> lock(my_mutex);
return my_queue.size();
}
private:
deque<function<void(void)>> my_queue;
mutable spin_mutex my_mutex;
semaphore sem;
};
} /* namespace Thread */
} /* namespace ZL */
#endif /* TASKQUEUE_H_ */

View File

@ -0,0 +1,173 @@
/*
* ThreadPool.h
*
* Created on: 2013-10-11
* Author: root
*/
#ifndef THREADPOOL_H_
#define THREADPOOL_H_
#include <assert.h>
#include <vector>
#include "threadgroup.h"
#include "TaskQueue.h"
#include "Util/util.h"
#include "Util/logger.h"
using namespace ZL::Util;
namespace ZL {
namespace Thread {
class ThreadPool {
public:
enum Priority {
PRIORITY_LOWEST = 0,
PRIORITY_LOW,
PRIORITY_NORMAL,
PRIORITY_HIGH,
PRIORITY_HIGHEST
};
//num:线程池线程个数
ThreadPool(int num, Priority _priority = PRIORITY_NORMAL) :
thread_num(num), avaible(true), priority(_priority) {
start();
}
~ThreadPool() {
wait();
}
//把任务打入线程池并异步执行
template <typename T>
bool async(T &&task) {
if (!avaible) {
return false;
}
if (my_thread_group.is_this_thread_in()) {
task();
} else {
my_queue.push_task(std::forward<T>(task));
}
return true;
}
template <typename T>
bool async_first(T &&task) {
if (!avaible) {
return false;
}
if (my_thread_group.is_this_thread_in()) {
task();
} else {
my_queue.push_task_first(std::forward<T>(task));
}
return true;
}
template <typename T>
bool sync(T &&task){
semaphore sem;
bool flag = async([&](){
task();
sem.post();
});
if(flag){
sem.wait();
}
return flag;
}
template <typename T>
bool sync_first(T &&task) {
semaphore sem;
bool flag = async_first([&]() {
task();
sem.post();
});
if (flag) {
sem.wait();
}
return flag;
}
//同步等待线程池执行完所有任务并退出
void wait() {
exit();
my_thread_group.join_all();
}
uint64_t size() const{
return my_queue.size();
}
static ThreadPool &Instance() {
//单例模式
static ThreadPool instance(thread::hardware_concurrency());
return instance;
}
static bool setPriority(Priority _priority = PRIORITY_NORMAL,
thread::native_handle_type threadId = 0) {
// set priority
#if defined(_WIN32)
static int Priorities[] = { THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST };
if (_priority != PRIORITY_NORMAL && SetThreadPriority(GetCurrentThread(), Priorities[_priority]) == 0) {
return false;
}
return true;
#else
static int Min = sched_get_priority_min(SCHED_OTHER);
if (Min == -1) {
return false;
}
static int Max = sched_get_priority_max(SCHED_OTHER);
if (Max == -1) {
return false;
}
static int Priorities[] = { Min, Min + (Max - Min) / 4, Min
+ (Max - Min) / 2, Min + (Max - Min) / 4, Max };
if (threadId == 0) {
threadId = pthread_self();
}
struct sched_param params;
params.sched_priority = Priorities[_priority];
return pthread_setschedparam(threadId, SCHED_OTHER, &params) == 0;
#endif
}
private:
TaskQueue my_queue;
thread_group my_thread_group;
int thread_num;
volatile bool avaible;
Priority priority;
//发送空任务至任务列队,通知线程主动退出
void exit() {
avaible = false;
my_queue.push_exit(thread_num);
}
void start() {
if (thread_num <= 0)
return;
for (int i = 0; i < thread_num; ++i) {
my_thread_group.create_thread(bind(&ThreadPool::run, this));
}
}
void run() {
ThreadPool::setPriority(priority);
function<void(void)> task;
while (true) {
if (my_queue.get_task(task)) {
try {
task();
} catch (std::exception &ex) {
FatalL << ex.what();
}
task = nullptr;
} else {
//空任务,退出线程
break;
}
}
}
}
;
} /* namespace Thread */
} /* namespace ZL */
#endif /* THREADPOOL_H_ */

View File

@ -0,0 +1,46 @@
/*
* WorkThreadPool.h
*
* Created on: 20151030
* Author: root
*/
#ifndef UTIL_WORKTHREADPOOL_H_
#define UTIL_WORKTHREADPOOL_H_
#include <map>
#include <thread>
#include <memory>
#include <atomic>
#include <iostream>
#include <unordered_map>
#include "ThreadPool.h"
using namespace std;
namespace ZL {
namespace Thread {
class WorkThreadPool {
public:
WorkThreadPool(int threadnum = thread::hardware_concurrency());
virtual ~WorkThreadPool();
std::shared_ptr<ThreadPool> &getWorkThread();
static WorkThreadPool &Instance() {
static WorkThreadPool *intance(new WorkThreadPool());
return *intance;
}
static void Destory(){
delete &(WorkThreadPool::Instance());
}
private:
int threadnum;
atomic<int> threadPos;
vector <std::shared_ptr<ThreadPool> > threads;
void wait();
};
} /* namespace Thread */
} /* namespace ZL */
#endif /* UTIL_WORKTHREADPOOL_H_ */

View File

@ -0,0 +1,71 @@
/*
* rwmutex.h
*
* Created on: 2016127
* Author:
*/
#ifndef UTIL_RWMUTEX_H_
#define UTIL_RWMUTEX_H_
#include <mutex>
#include <atomic>
using namespace std;
namespace ZL {
namespace Thread {
class rw_mutex {
public:
rw_mutex() :
reader_cnt(0) {
}
void lock(bool write_mode = true) {
if (write_mode) {
//write thread
mtx_write.lock();
} else {
// read thread
lock_guard<mutex> lck(mtx_reader);
if (reader_cnt++ == 0) {
mtx_write.lock();
}
}
}
void unlock(bool write_mode = true) {
if (write_mode) {
//write thread
mtx_write.unlock();
} else {
// read thread
lock_guard<mutex> lck(mtx_reader);
if (--reader_cnt == 0) {
mtx_write.unlock();
}
}
}
virtual ~rw_mutex() {
}
private:
mutex mtx_write;
mutex mtx_reader;
int reader_cnt;
};
class lock_guard_rw {
public:
lock_guard_rw(rw_mutex &_mtx, bool _write_mode = true) :
mtx(_mtx), write_mode(_write_mode) {
mtx.lock(write_mode);
}
virtual ~lock_guard_rw() {
mtx.unlock(write_mode);
}
private:
rw_mutex &mtx;
bool write_mode;
};
} /* namespace Thread */
} /* namespace ZL */
#endif /* UTIL_RWMUTEX_H_ */

View File

@ -0,0 +1,78 @@
/*
* semaphore.h
*
* Created on: 2015814
* Author: root
*/
#ifndef SEMAPHORE_H_
#define SEMAPHORE_H_
/*
* 32
* 线
#if defined(__linux__)
#include <semaphore.h>
#define HAVE_SEM
#endif //HAVE_SEM
*/
#include <mutex>
#include <atomic>
#include <condition_variable>
using namespace std;
namespace ZL {
namespace Thread {
class semaphore {
public:
explicit semaphore(unsigned int initial = 0) {
#if defined(HAVE_SEM)
sem_init(&sem, 0, initial);
#else
count_ = 0;
#endif
}
~semaphore() {
#if defined(HAVE_SEM)
sem_destroy(&sem);
#endif
}
void post(unsigned int n = 1) {
#if defined(HAVE_SEM)
while (n--) {
sem_post(&sem);
}
#else
unique_lock<mutex> lock(mutex_);
count_ += n;
while (n--) {
condition_.notify_one();
}
#endif
}
void wait() {
#if defined(HAVE_SEM)
sem_wait(&sem);
#else
unique_lock<mutex> lock(mutex_);
while (count_ == 0) {
condition_.wait(lock);
}
--count_;
#endif
}
private:
#if defined(HAVE_SEM)
sem_t sem;
#else
atomic_uint count_;
mutex mutex_;
condition_variable_any condition_;
#endif
};
} /* namespace Thread */
} /* namespace ZL */
#endif /* SEMAPHORE_H_ */

View File

@ -0,0 +1,41 @@
/*
* spinmutex.h
*
* Created on: 2017331
* Author: xzl
*/
#ifndef SRC_THREAD_SPIN_MUTEX_H_
#define SRC_THREAD_SPIN_MUTEX_H_
#include <atomic>
#include <mutex>
using namespace std;
namespace ZL {
namespace Thread {
#ifndef __ARM_ARCH
class spin_mutex {
std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:
spin_mutex() = default;
spin_mutex(const spin_mutex&) = delete;
spin_mutex& operator= (const spin_mutex&) = delete;
void lock() {
while(flag.test_and_set(std::memory_order_acquire)) ;
}
void unlock() {
flag.clear(std::memory_order_release);
}
};
#else
typedef mutex spin_mutex;
#endif //__ARM_ARCH
} /* namespace Thread */
} /* namespace ZL */
#endif /* SRC_THREAD_SPIN_MUTEX_H_ */

View File

@ -0,0 +1,93 @@
/*
* threadgroup.h
*
* Created on: 2014-6-23
* Author: root
*/
#ifndef THREADGROUP_H_
#define THREADGROUP_H_
#include <set>
#include <mutex>
#include <thread>
#include <vector>
#include <unordered_map>
using namespace std;
namespace ZL {
namespace Thread {
class thread_group {
private:
thread_group(thread_group const&);
thread_group& operator=(thread_group const&);
public:
thread_group() {
}
~thread_group() {
for (auto &th : threads) {
delete th.second;
}
}
bool is_this_thread_in() {
auto it = threads.find(this_thread::get_id());
return it != threads.end();
}
bool is_thread_in(thread* thrd) {
if (thrd) {
auto it = threads.find(thrd->get_id());
return it != threads.end();
} else {
return false;
}
}
template<typename F>
thread* create_thread(F threadfunc) {
thread *new_thread=new thread(threadfunc);
threads[new_thread->get_id()] = new_thread;
return new_thread;
}
void add_thread(thread* thrd) {
if (thrd) {
if (is_thread_in(thrd)) {
throw runtime_error(
"thread_group: trying to add a duplicated thread");
}
threads[thrd->get_id()] = thrd;
}
}
void remove_thread(thread* thrd) {
auto it = threads.find(thrd->get_id());
if (it != threads.end()) {
threads.erase(it);
}
}
void join_all() {
if (is_this_thread_in()) {
throw runtime_error("thread_group: trying joining itself");
return;
}
for (auto &it : threads) {
if (it.second->joinable()) {
it.second->join(); //等待线程主动退出
}
}
}
size_t size() {
return threads.size();
}
private:
unordered_map<thread::id, thread*> threads;
};
} /* namespace Thread */
} /* namespace ZL */
#endif /* THREADGROUP_H_ */

View File

@ -0,0 +1,75 @@
/*
* File.h
*
* Created on: 2016922
* Author: xzl
*/
#ifndef SRC_UTIL_FILE_H_
#define SRC_UTIL_FILE_H_
#if defined(_WIN32)
#include <WinSock2.h>
#pragma comment (lib,"WS2_32")
#endif // WIN32
#include <stdio.h>
#if defined(_WIN32)
#ifndef PATH_MAX
#define PATH_MAX 256
#endif // !PATH_MAX
struct dirent{
long d_ino; /* inode number*/
off_t d_off; /* offset to this dirent*/
unsigned short d_reclen; /* length of this d_name*/
unsigned char d_type; /* the type of d_name*/
char d_name[1]; /* file name (null-terminated)*/
};
typedef struct _dirdesc {
int dd_fd; /** file descriptor associated with directory */
long dd_loc; /** offset in current buffer */
long dd_size; /** amount of data returned by getdirentries */
char *dd_buf; /** data buffer */
int dd_len; /** size of data buffer */
long dd_seek; /** magic cookie returned by getdirentries */
HANDLE handle;
struct dirent *index;
} DIR;
# define __dirfd(dp) ((dp)->dd_fd)
int mkdir(const char *path, int mode);
DIR *opendir(const char *);
int closedir(DIR *);
struct dirent *readdir(DIR *);
#endif // defined(_WIN32)
namespace ZL {
namespace Util {
class File {
public:
// 可读普通文件
static bool isrfile(const char *path) ;
//新建文件,目录文件夹自动生成
static bool createfile_path(const char *file, unsigned int mod);
static FILE *createfile_file(const char *file,const char *mode);
//判断是否为目录
static bool is_dir(const char *path) ;
//判断是否为常规文件
static bool is_file(const char *path) ;
//判断是否是特殊目录(. or ..
static bool is_special_dir(const char *path);
//删除目录或文件
static void delete_file(const char *path) ;
static bool rm_empty_dir(const char *path);
private:
File();
virtual ~File();
};
} /* namespace Util */
} /* namespace ZL */
#endif /* SRC_UTIL_FILE_H_ */

View File

@ -0,0 +1,74 @@
/*
* MD5.h
*
* Created on: 2016823
* Author: xzl
*/
#ifndef SRC_UTIL_MD5_H_
#define SRC_UTIL_MD5_H_
#include <string>
#include <iostream>
using namespace std;
namespace ZL {
namespace Util {
// a small class for calculating MD5 hashes of strings or byte arrays
// it is not meant to be fast or secure
//
// usage: 1) feed it blocks of uchars with update()
// 2) finalize()
// 3) get hexdigest() string
// or
// MD5(std::string).hexdigest()
//
// assumes that char is 8 bit and int is 32 bit
class MD5
{
public:
typedef unsigned int size_type; // must be 32bit
MD5();
MD5(const std::string& text);
void update(const unsigned char *buf, size_type length);
void update(const char *buf, size_type length);
MD5& finalize();
std::string hexdigest() const;
friend std::ostream& operator<<(std::ostream&, MD5 md5);
private:
void init();
typedef uint8_t uint1; // 8bit
typedef uint32_t uint4; // 32bit
enum {blocksize = 64}; // VC6 won't eat a const static int here
void transform(const uint1 block[blocksize]);
static void decode(uint4 output[], const uint1 input[], size_type len);
static void encode(uint1 output[], const uint4 input[], size_type len);
bool finalized;
uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk
uint4 count[2]; // 64bit counter for number of bits (lo, hi)
uint4 state[4]; // digest so far
uint1 digest[16]; // the result
// low level logic operations
static inline uint4 F(uint4 x, uint4 y, uint4 z);
static inline uint4 G(uint4 x, uint4 y, uint4 z);
static inline uint4 H(uint4 x, uint4 y, uint4 z);
static inline uint4 I(uint4 x, uint4 y, uint4 z);
static inline uint4 rotate_left(uint4 x, int n);
static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
};
} /* namespace Util */
} /* namespace ZL */
#endif /* SRC_UTIL_MD5_H_ */

View File

@ -0,0 +1,104 @@
/*
* NoticeCenter.h
*
* Created on: 2017217
* Author: xzl
*/
#ifndef SRC_UTIL_NOTICECENTER_H_
#define SRC_UTIL_NOTICECENTER_H_
#include <mutex>
#include <memory>
#include <string>
#include <exception>
#include <functional>
#include <unordered_map>
#include "function_traits.h"
using namespace std;
namespace ZL {
namespace Util {
class NoticeCenter {
public:
class InterruptException : public std::runtime_error
{
public:
InterruptException():std::runtime_error("InterruptException"){}
virtual ~InterruptException(){}
};
virtual ~NoticeCenter(){}
static NoticeCenter &Instance(){
static NoticeCenter instance;
return instance;
}
template<typename ...ArgsType>
bool emitEvent(const char *strEvent,ArgsType &&...args){
lock_guard<recursive_mutex> lck(_mtxListener);
auto it0 = _mapListener.find(strEvent);
if (it0 == _mapListener.end()) {
return false;
}
for(auto &pr : it0->second){
typedef function<void(ArgsType &&...)> funType;
funType *obj = (funType *)(pr.second.get());
try{
(*obj)(std::forward<ArgsType>(args)...);
}catch(InterruptException &ex){
break;
}
}
return it0->second.size();
}
template<typename FUN>
void addListener(void *tag, const char *strEvent, const FUN &fun) {
typedef typename function_traits<FUN>::stl_function_type funType;
std::shared_ptr<void> pListener(new funType(fun), [](void *ptr) {
funType *obj = (funType *)ptr;
delete obj;
});
lock_guard<recursive_mutex> lck(_mtxListener);
_mapListener[strEvent][tag] = pListener;
}
void delListener(void *tag,const char *strEvent){
lock_guard<recursive_mutex> lck(_mtxListener);
auto it = _mapListener.find(strEvent);
if(it == _mapListener.end()){
return;
}
it->second.erase(tag);
if(it->second.empty()){
_mapListener.erase(it);
}
}
void delListener(void *tag){
lock_guard<recursive_mutex> lck(_mtxListener);
for(auto it = _mapListener.begin();it != _mapListener.end();){
it->second.erase(tag);
if(it->second.empty()){
it = _mapListener.erase(it);
continue;
}
++it;
}
}
private:
NoticeCenter(){}
recursive_mutex _mtxListener;
unordered_map<string,unordered_map<void *,std::shared_ptr<void> > > _mapListener;
};
} /* namespace Util */
} /* namespace ZL */
#endif /* SRC_UTIL_NOTICECENTER_H_ */

View File

@ -0,0 +1,133 @@
/*
* ResourcePool.h
*
* Created on: 20151029
* Author: root
*/
#ifndef UTIL_RECYCLEPOOL_H_
#define UTIL_RECYCLEPOOL_H_
#include <mutex>
#include <deque>
#include <memory>
#include <atomic>
#include <functional>
#include <unordered_set>
namespace ZL {
namespace Util {
using namespace std;
template<typename C, int poolSize = 10>
class ResourcePool {
public:
typedef std::shared_ptr<C> ValuePtr;
ResourcePool() {
pool.reset(new _ResourcePool());
}
#if (!defined(__GNUC__)) || (__GNUC__ >= 5)
template<typename ...ArgTypes>
ResourcePool(ArgTypes &&...args) {
pool.reset(new _ResourcePool(std::forward<ArgTypes>(args)...));
}
#endif //(!defined(__GNUC__)) || (__GNUC__ >= 5)
void reSize(int size) {
pool->setSize(size);
}
ValuePtr obtain() {
return pool->obtain();
}
void quit(const ValuePtr &ptr) {
pool->quit(ptr);
}
private:
class _ResourcePool: public enable_shared_from_this<_ResourcePool> {
public:
typedef std::shared_ptr<C> ValuePtr;
_ResourcePool() {
poolsize = poolSize;
allotter = []()->C* {
return new C();
};
}
#if (!defined(__GNUC__)) || (__GNUC__ >= 5)
template<typename ...ArgTypes>
_ResourcePool(ArgTypes &&...args) {
poolsize = poolSize;
allotter = [args...]()->C* {
return new C(args...);
};
}
#endif //(!defined(__GNUC__)) || (__GNUC__ >= 5)
virtual ~_ResourcePool(){
std::lock_guard<mutex> lck(_mutex);
for(auto &ptr : objs){
delete ptr;
}
}
void setSize(int size) {
poolsize = size;
}
ValuePtr obtain() {
std::lock_guard<mutex> lck(_mutex);
C *ptr = nullptr;
if (objs.size() == 0) {
ptr = allotter();
} else {
ptr = objs.front();
objs.pop_front();
}
return ValuePtr(ptr, Deleter(this->shared_from_this()));
}
void quit(const ValuePtr &ptr) {
std::lock_guard<mutex> lck(_mutex);
quitSet.emplace(ptr.get());
}
private:
class Deleter {
public:
Deleter(const std::shared_ptr<_ResourcePool> &pool) {
weakPool = pool;
}
void operator()(C *ptr) {
auto strongPool = weakPool.lock();
if (strongPool) {
strongPool->recycle(ptr);
} else {
delete ptr;
}
}
private:
weak_ptr<_ResourcePool> weakPool;
};
private:
void recycle(C *obj) {
std::lock_guard<mutex> lck(_mutex);
auto it = quitSet.find(obj);
if (it != quitSet.end()) {
delete obj;
quitSet.erase(it);
return;
}
if ((int)objs.size() >= poolsize) {
delete obj;
return;
}
objs.push_back(obj);
}
deque<C*> objs;
unordered_set<C*> quitSet;
function<C*(void)> allotter;
mutex _mutex;
int poolsize;
};
std::shared_ptr<_ResourcePool> pool;
};
} /* namespace util */
} /* namespace im */
#endif /* UTIL_RECYCLEPOOL_H_ */

View File

@ -0,0 +1,244 @@
/*
* RingBuffer.h
*
* Created on: 2016810
* Author: xzl
*/
#ifndef UTIL_RINGBUFFER_H_
#define UTIL_RINGBUFFER_H_
#include <atomic>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <condition_variable>
using namespace std;
namespace ZL {
namespace Util {
//实现了一个一写多读得环形缓冲的模板类
template<typename T> class RingBuffer: public enable_shared_from_this<
RingBuffer<T> > {
public:
typedef std::shared_ptr<RingBuffer> Ptr;
class RingReader {
public:
friend class RingBuffer;
typedef std::shared_ptr<RingReader> Ptr;
RingReader(const std::shared_ptr<RingBuffer> &_buffer,bool _useBuffer) {
buffer = _buffer;
curpos = _buffer->ringKeyPos;
useBuffer = _useBuffer;
}
virtual ~RingReader() {
auto strongBuffer = buffer.lock();
if (strongBuffer) {
strongBuffer->release(this);
}
}
//重新定位读取器至最新的数据位置
void reset(bool keypos = true) {
auto strongBuffer = buffer.lock();
if (strongBuffer) {
if(keypos){
curpos = strongBuffer->ringKeyPos; //定位读取器
}else{
curpos = strongBuffer->ringPos; //定位读取器
}
}
}
void setReadCB(const function<void(const T &)> &cb) {
lock_guard<recursive_mutex> lck(mtxCB);
readCB = cb;
reset();
}
void setDetachCB(const function<void()> &cb) {
lock_guard<recursive_mutex> lck(mtxCB);
if (!cb) {
detachCB = []() {};
} else {
detachCB = cb;
}
}
const T* read(){
auto strongBuffer=buffer.lock();
if(!strongBuffer){
return nullptr;
}
return read(strongBuffer.get());
}
private:
void onRead(const T &data) {
lock_guard<recursive_mutex> lck(mtxCB);
if(!readCB){
return;
}
if(!useBuffer){
readCB(data);
}else{
const T *pkt = nullptr;
while((pkt = read())){
readCB(*pkt);
}
}
}
void onDetach() const {
lock_guard<recursive_mutex> lck(mtxCB);
detachCB();
}
//读环形缓冲
const T *read(RingBuffer *ring) {
if (curpos == ring->ringPos) {
return nullptr;
}
const T *data = &(ring->dataRing[curpos]); //返回包
curpos = ring->next(curpos); //更新位置
return data;
}
function<void(const T &)> readCB ;
function<void(void)> detachCB = []() {};
weak_ptr<RingBuffer> buffer;
mutable recursive_mutex mtxCB;
int curpos;
bool useBuffer;
};
friend class RingReader;
RingBuffer(int size = 0) {
if(size <= 0){
size = 32;
canReSize = true;
}
ringSize = size;
dataRing = new T[ringSize];
ringPos = 0;
ringKeyPos = 0;
}
virtual ~RingBuffer() {
decltype(readerMap) mapCopy;
{
lock_guard<recursive_mutex> lck(mtx_reader);
mapCopy.swap(readerMap);
}
for (auto &pr : mapCopy) {
auto reader = pr.second.lock();
if(reader){
reader->onDetach();
}
}
delete[] dataRing;
}
#if defined(ENABLE_RING_USEBUF)
std::shared_ptr<RingReader> attach(bool useBuffer = true) {
#else //ENABLE_RING_USEBUF
std::shared_ptr<RingReader> attach(bool useBuffer = false) {
#endif //ENABLE_RING_USEBUF
std::shared_ptr<RingReader> ptr(new RingReader(this->shared_from_this(),useBuffer));
std::weak_ptr<RingReader> weakPtr = ptr;
lock_guard<recursive_mutex> lck(mtx_reader);
readerMap.emplace(ptr.get(),weakPtr);
return ptr;
}
//写环形缓冲,非线程安全的
void write(const T &in,bool isKey = true) {
computeBestSize(isKey);
dataRing[ringPos] = in;
if (isKey) {
ringKeyPos = ringPos; //设置读取器可以定位的点
}
ringPos = next(ringPos);
decltype(readerMap) mapCopy;
{
lock_guard<recursive_mutex> lck(mtx_reader);
mapCopy = readerMap;
}
for (auto &pr : mapCopy) {
auto reader = pr.second.lock();
if(reader){
reader->onRead(in);
}
}
}
int readerCount(){
lock_guard<recursive_mutex> lck(mtx_reader);
return readerMap.size();
}
private:
T *dataRing;
int ringPos;
int ringKeyPos;
int ringSize;
//计算最佳环形缓存大小的参数
int besetSize = 0;
int totalCnt = 0;
int lastKeyCnt = 0;
bool canReSize = false;
recursive_mutex mtx_reader;
unordered_map<void *,std::weak_ptr<RingReader> > readerMap;
inline int next(int pos) {
//读取器下一位置
if (pos > ringSize - 2) {
return 0;
} else {
return pos + 1;
}
}
void release(RingReader *reader) {
lock_guard<recursive_mutex> lck(mtx_reader);
readerMap.erase(reader);
}
void computeBestSize(bool isKey){
if(!canReSize || besetSize){
return;
}
totalCnt++;
if(!isKey){
return;
}
//关键帧
if(lastKeyCnt){
//计算两个I帧之间的包个数
besetSize = totalCnt - lastKeyCnt;
reSize();
return;
}
lastKeyCnt = totalCnt;
}
void reSize(){
ringSize = besetSize;
delete [] dataRing;
dataRing = new T[ringSize];
ringPos = 0;
ringKeyPos = 0;
decltype(readerMap) mapCopy;
{
lock_guard<recursive_mutex> lck(mtx_reader);
mapCopy = readerMap;
}
for (auto &pr : mapCopy) {
auto reader = pr.second.lock();
if(reader){
reader->reset(true);
}
}
}
};
} /* namespace Util */
} /* namespace ZL */
#endif /* UTIL_RINGBUFFER_H_ */

View File

@ -0,0 +1,112 @@
/*
* SSLServer.h
*
* Created on: 2016111
* Author: root
*/
#ifndef CRYPTO_SSLBOX_H_
#define CRYPTO_SSLBOX_H_
#include <fcntl.h>
#include <openssl/bio.h>
#include <openssl/ossl_typ.h>
#include <mutex>
#include <string>
#include <atomic>
#include <functional>
#include "logger.h"
#if defined(_WIN32)
#if defined(_WIN64)
//64bit
#if defined(_DEBUG)
#pragma comment (lib,"libssl64MDd")
#pragma comment (lib,"libcrypto64MDd")
#else
#pragma comment (lib,"libssl64MD")
#pragma comment (lib,"libcrypto64MD")
#endif // defined(_DEBUG)
#else
//32 bit
#if defined(_DEBUG)
#pragma comment (lib,"libssl32MDd")
#pragma comment (lib,"libcrypto32MDd")
#else
#pragma comment (lib,"libssl32MD")
#pragma comment (lib,"libcrypto32MD")
#endif // defined(_DEBUG)
#endif //defined(_WIN64)
#endif // defined(_WIN32)
using namespace std;
namespace ZL {
namespace Util {
class SSL_Initor {
public:
friend class SSL_Box;
static SSL_Initor &Instance() {
static SSL_Initor obj;
return obj;
}
void loadServerPem(const char *keyAndCA_pem, const char *import_pwd = "");
void loadClientPem(const char *keyAndCA_pem, const char *import_pwd = "");
private:
static mutex *_mutexes;
SSL_CTX *ssl_server;
SSL_CTX *ssl_client;
SSL_Initor();
~SSL_Initor();
void setCtx(SSL_CTX *ctx);
void loadPem(SSL_CTX *ctx, const char *keyAndCA_pem,const char *import_pwd);
inline std::string getLastError();
}
;
class SSL_Box {
public:
SSL_Box(bool isServer = true, bool enable = true);
virtual ~SSL_Box();
//收到密文后,调用此函数解密
void onRecv(const char *data, uint32_t data_len);
//需要加密明文调用此函数
void onSend(const char *data, uint32_t data_len);
//设置解密后获取明文的回调
template<typename F>
void setOnDecData(F &&fun) {
onDec = fun;
}
//设置加密后获取密文的回调
template<typename F>
void setOnEncData(F &&fun) {
onEnc = fun;
}
void shutdown();
private:
bool isServer;
bool enable;
bool sendHandshake;
SSL *ssl;
BIO *read_bio, *write_bio;
function<void(const char *data, uint32_t len)> onDec;
function<void(const char *data, uint32_t len)> onEnc;
std::string _bufferOut;
void flush();
void flushWriteBio(char *buf, int bufsize);
void flushReadBio(char *buf, int bufsize);
};
} /* namespace Util */
} /* namespace ZL */
#endif /* CRYPTO_SSLBOX_H_ */

View File

@ -0,0 +1,145 @@
/*
* SqlConnection.h
*
* Created on: 20151029
* Author: root
*/
#ifndef SQL_SQLCONNECTION_H_
#define SQL_SQLCONNECTION_H_
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <stdexcept>
#include "Util/logger.h"
#if defined(_WIN32)
#include <mysql.h>
#pragma comment (lib,"libmysql")
#else
#include <mysql/mysql.h>
#endif // defined(_WIN32)
using namespace std;
namespace ZL {
namespace Util {
class SqlConnection {
public:
SqlConnection(const string &url, unsigned short port, const string &dbname,
const string &user, const string &password,const string &character = "utf8mb4");
virtual ~SqlConnection();
template<typename ...Args>
int64_t query(int64_t &rowId, const char *fmt, Args && ...arg) {
check();
string tmp = queryString(fmt, std::forward<Args>(arg)...);
if (mysql_query(&sql, tmp.c_str())) {
WarnL << mysql_error(&sql) << ":" << tmp << endl;
return -1;
}
rowId=mysql_insert_id(&sql);
return mysql_affected_rows(&sql);
}
int64_t query(int64_t &rowId,const char *str) {
check();
if (mysql_query(&sql, str)) {
WarnL << mysql_error(&sql) << ":" << str << endl;
return -1;
}
rowId=mysql_insert_id(&sql);
return mysql_affected_rows(&sql);
}
template<typename ...Args>
int64_t query(int64_t &rowId,vector<vector<string>> &ret, const char *fmt,
Args && ...arg) {
check();
string tmp = queryString(fmt, std::forward<Args>(arg)...);
if (mysql_query(&sql, tmp.c_str())) {
WarnL << mysql_error(&sql) << ":" << tmp << endl;
return -1;
}
ret.clear();
MYSQL_RES *res = mysql_store_result(&sql);
if (!res) {
rowId=mysql_insert_id(&sql);
return mysql_affected_rows(&sql);
}
MYSQL_ROW row;
unsigned int column = mysql_num_fields(res);
while ((row = mysql_fetch_row(res)) != NULL) {
ret.emplace_back();
auto &back = ret.back();
for (unsigned int i = 0; i < column; i++) {
back.emplace_back(row[i] ? row[i] : "");
}
}
mysql_free_result(res);
rowId=mysql_insert_id(&sql);
return mysql_affected_rows(&sql);
}
int64_t query(int64_t &rowId,vector<vector<string>> &ret, const char *str) {
check();
if (mysql_query(&sql, str)) {
WarnL << mysql_error(&sql) << ":" << str << endl;
return -1;
}
ret.clear();
MYSQL_RES *res = mysql_store_result(&sql);
if (!res) {
rowId=mysql_insert_id(&sql);
return mysql_affected_rows(&sql);
}
MYSQL_ROW row;
unsigned int column = mysql_num_fields(res);
while ((row = mysql_fetch_row(res)) != NULL) {
ret.emplace_back();
auto &back = ret.back();
for (unsigned int i = 0; i < column; i++) {
back.emplace_back(row[i] ? row[i] : "" );
}
}
mysql_free_result(res);
rowId=mysql_insert_id(&sql);
return mysql_affected_rows(&sql);
}
template<typename ...Args>
static string queryString(const char *fmt, Args && ...arg) {
char *ptr_out = NULL;
asprintf(&ptr_out, fmt, arg...);
string ret(ptr_out);
if (ptr_out) {
free(ptr_out);
}
return ret;
}
static string queryString(const char *fmt) {
return fmt;
}
string &escape(string &str) {
char *out = new char[str.length() * 2 + 1];
mysql_real_escape_string(&sql, out, str.c_str(), str.size());
str.assign(out);
delete [] out;
return str;
}
private:
MYSQL sql;
inline void check() {
if (mysql_ping(&sql) != 0) {
throw runtime_error("MYSQL连接异常!");
}
}
};
} /* namespace util */
} /* namespace ZL */
#endif /* SQL_SQLCONNECTION_H_ */

View File

@ -0,0 +1,230 @@
/*
* SqlPool.h
*
* Created on: 20151029
* Author: root
*/
#ifndef SQL_SQLPOOL_H_
#define SQL_SQLPOOL_H_
#include <deque>
#include <mutex>
#include <memory>
#include <sstream>
#include <functional>
#include "logger.h"
#include "SqlConnection.h"
#include "Thread/ThreadPool.h"
#include "Util/ResourcePool.h"
#include "Thread/AsyncTaskThread.h"
using namespace std;
using namespace ZL::Thread;
namespace ZL {
namespace Util {
template<int poolSize = 10>
class _SqlPool {
public:
typedef ResourcePool<SqlConnection, poolSize> PoolType;
typedef vector<vector<string> > SqlRetType;
static _SqlPool &Instance() {
static _SqlPool *pool(new _SqlPool());
return *pool;
}
static void Destory(){
delete &Instance();
}
void reSize(int size) {
if (size < 0) {
return;
}
poolsize = size;
pool->reSize(size);
threadPool.reset(new ThreadPool(poolsize));
}
template<typename ...Args>
void Init(Args && ...arg) {
pool.reset(new PoolType(std::forward<Args>(arg)...));
pool->obtain();
}
template<typename ...Args>
int64_t query(const char *fmt, Args && ...arg) {
string sql = SqlConnection::queryString(fmt, std::forward<Args>(arg)...);
doQuery(sql);
return 0;
}
int64_t query(const string &sql) {
doQuery(sql);
return 0;
}
template<typename ...Args>
int64_t query(int64_t &rowID,vector<vector<string>> &ret, const char *fmt,
Args && ...arg) {
return _query(rowID,ret, fmt, std::forward<Args>(arg)...);
}
int64_t query(int64_t &rowID,vector<vector<string>> &ret, const string &sql) {
return _query(rowID,ret, sql.c_str());
}
static const string &escape(const string &str) {
try {
//捕获创建对象异常
_SqlPool::Instance().pool->obtain()->escape(
const_cast<string &>(str));
} catch (exception &e) {
WarnL << e.what() << endl;
}
return str;
}
private:
_SqlPool() :
threadPool(new ThreadPool(poolSize)), asyncTaskThread(10 * 1000) {
poolsize = poolSize;
asyncTaskThread.DoTaskDelay(reinterpret_cast<uint64_t>(this), 30 * 1000,
[this]() {
flushError();
return true;
});
}
inline void doQuery(const string &str,int tryCnt = 3) {
auto lam = [this,str,tryCnt]() {
int64_t rowID;
auto cnt = tryCnt - 1;
if(_query(rowID,str.c_str())==-2 && cnt > 0) {
lock_guard<mutex> lk(error_query_mutex);
sqlQuery query(str,cnt);
error_query.push_back(query);
}
};
threadPool->async(lam);
}
template<typename ...Args>
inline int64_t _query(int64_t &rowID,Args &&...arg) {
typename PoolType::ValuePtr mysql;
try {
//捕获执行异常
mysql = pool->obtain();
return mysql->query(rowID,std::forward<Args>(arg)...);
} catch (exception &e) {
pool->quit(mysql);
WarnL << e.what() << endl;
return -2;
}
}
void flushError() {
decltype(error_query) query_copy;
error_query_mutex.lock();
query_copy.swap(error_query);
error_query_mutex.unlock();
if (query_copy.size() == 0) {
return;
}
for (auto &query : query_copy) {
doQuery(query.sql_str,query.tryCnt);
}
}
virtual ~_SqlPool() {
asyncTaskThread.CancelTask(reinterpret_cast<uint64_t>(this));
flushError();
threadPool.reset();
pool.reset();
InfoL;
}
std::shared_ptr<ThreadPool> threadPool;
mutex error_query_mutex;
class sqlQuery
{
public:
sqlQuery(const string &sql,int cnt):sql_str(sql),tryCnt(cnt){}
string sql_str;
int tryCnt = 0;
} ;
deque<sqlQuery> error_query;
std::shared_ptr<PoolType> pool;
AsyncTaskThread asyncTaskThread;
unsigned int poolsize;
}
;
typedef _SqlPool<1> SqlPool;
class SqlStream {
public:
SqlStream(const char *_sql) :
sql(_sql) {
startPos = 0;
}
~SqlStream() {
}
template<typename T>
SqlStream& operator <<(const T& data) {
auto pos = sql.find_first_of('?', startPos);
if (pos == string::npos) {
return *this;
}
str_tmp.str("");
str_tmp << data;
string str = str_tmp.str();
startPos = pos + str.size();
sql.replace(pos, 1, str);
return *this;
}
const string& operator <<(std::ostream&(*f)(std::ostream&)) const {
return sql;
}
private:
stringstream str_tmp;
string sql;
string::size_type startPos;
};
class SqlWriter {
public:
SqlWriter(const char *_sql,bool _throwAble = true) :
sqlstream(_sql),throwAble(_throwAble) {
}
~SqlWriter() {
}
template<typename T>
SqlWriter& operator <<(const T& data) {
sqlstream << data;
return *this;
}
void operator <<(std::ostream&(*f)(std::ostream&)) {
SqlPool::Instance().query(sqlstream << endl);
}
int64_t operator <<(vector<vector<string>> &ret) {
affectedRows = SqlPool::Instance().query(rowId,ret, sqlstream << endl);
if(affectedRows < 0 && throwAble){
throw std::runtime_error("operate database failed");
}
return affectedRows;
}
int64_t getRowID() const {
return rowId;
}
int64_t getAffectedRows() const {
return affectedRows;
}
private:
SqlStream sqlstream;
int64_t rowId = 0;
int64_t affectedRows = -1;
bool throwAble = true;
};
} /* namespace mysql */
} /* namespace im */
#endif /* SQL_SQLPOOL_H_ */

View File

@ -0,0 +1,116 @@
/*
* TimeTicker.h
*
* Created on: 20151230
* Author: root
*/
#ifndef UTIL_TIMETICKER_H_
#define UTIL_TIMETICKER_H_
#include "logger.h"
#include "Util/util.h"
namespace ZL {
namespace Util {
class Ticker {
public:
Ticker(int64_t _minMs = 0, const char *_where = "",
LogInfoMaker && _stream = LogInfoMaker(LWarn, __FILE__, "", __LINE__),bool printLog=false) :
stream(_stream) {
if(!printLog){
stream.clear();
}
begin = getNowTime();
created = begin;
minMs = _minMs;
where = _where;
}
virtual ~Ticker() {
int64_t tm = getNowTime() - begin;
if (tm > minMs) {
stream << where << " take time:" << tm << endl;
} else {
stream.clear();
}
}
uint64_t elapsedTime() {
stream.clear();
return getNowTime() - begin;
}
uint64_t createdTime() {
stream.clear();
return getNowTime() - created;
}
void resetTime() {
stream.clear();
begin = getNowTime();
}
private:
inline static uint64_t getNowTime() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
uint64_t begin;
uint64_t created;
LogInfoMaker stream;
const char *where;
int64_t minMs;
};
class SmoothTicker {
public:
SmoothTicker(uint64_t _resetMs = 10000) {
resetMs = _resetMs;
ticker.resetTime();
}
virtual ~SmoothTicker() {
}
uint64_t elapsedTime() {
auto nowTime = ticker.elapsedTime();
if (firstTime == 0) {
firstTime = nowTime;
lastTime = nowTime;
pktCount = 0;
return nowTime;
}
uint64_t elapseTime = (nowTime - firstTime);
uint64_t retTime = lastTime + elapseTime / ++pktCount;
lastTime = retTime;
if (elapseTime > 10000) {
firstTime = 0;
}
return retTime;
}
void resetTime(){
firstTime = 0;
pktCount = 0;
lastTime = 0;
ticker.resetTime();
}
private:
uint64_t firstTime = 0;
uint64_t pktCount = 0;
uint64_t lastTime = 0;
uint64_t resetMs;
Ticker ticker;
};
#if defined(_DEBUG)
#define TimeTicker() Ticker(5,"",WarnL,true)
#define TimeTicker1(tm) Ticker(tm,"",WarnL,true)
#define TimeTicker2(tm,where) Ticker(tm,where,WarnL,true)
#define TimeTicker3(tm,where,log) Ticker(tm,where,log,true)
#else
#define TimeTicker()
#define TimeTicker1(tm)
#define TimeTicker2(tm,where)
#define TimeTicker3(tm,where,log)
#endif
} /* namespace Util */
} /* namespace ZL */
#endif /* UTIL_TIMETICKER_H_ */

View File

@ -0,0 +1,64 @@
/*
* functiontraits.h
*
* Created on: 2017315
* Author: xzl
*/
#ifndef SRC_UTIL_FUNCTION_TRAITS_H_
#define SRC_UTIL_FUNCTION_TRAITS_H_
#include <tuple>
using namespace std;
namespace ZL {
namespace Util {
template<typename T>
struct function_traits;
//普通函数
template<typename Ret, typename... Args>
struct function_traits<Ret(Args...)>
{
public:
enum { arity = sizeof...(Args) };
typedef Ret function_type(Args...);
typedef Ret return_type;
using stl_function_type = std::function<function_type>;
typedef Ret(*pointer)(Args...);
template<size_t I>
struct args
{
static_assert(I < arity, "index is out of range, index must less than sizeof Args");
using type = typename std::tuple_element<I, std::tuple<Args...> >::type;
};
};
//函数指针
template<typename Ret, typename... Args>
struct function_traits<Ret(*)(Args...)> : function_traits<Ret(Args...)>{};
//std::function
template <typename Ret, typename... Args>
struct function_traits<std::function<Ret(Args...)>> : function_traits<Ret(Args...)>{};
//member function
#define FUNCTION_TRAITS(...) \
template <typename ReturnType, typename ClassType, typename... Args>\
struct function_traits<ReturnType(ClassType::*)(Args...) __VA_ARGS__> : function_traits<ReturnType(Args...)>{}; \
FUNCTION_TRAITS()
FUNCTION_TRAITS(const)
FUNCTION_TRAITS(volatile)
FUNCTION_TRAITS(const volatile)
//函数对象
template<typename Callable>
struct function_traits : function_traits<decltype(&Callable::operator())>{};
} /* namespace Util */
} /* namespace ZL */
#endif /* SRC_UTIL_FUNCTION_TRAITS_H_ */

View File

@ -0,0 +1,400 @@
/*
* logger.h
*
* Created on: 201683
* Author: xzl
*/
#ifndef UTIL_LOGGER_H_
#define UTIL_LOGGER_H_
#include <iostream>
#include <fstream>
#include <sstream>
#include <deque>
#include <map>
#include <ctime>
#include <string.h>
#include <cstdlib>
#include <thread>
#include <memory>
#include <mutex>
#include <time.h>
#include <condition_variable>
#include "Util/util.h"
#include "Thread/semaphore.h"
using namespace std;
using namespace ZL::Thread;
namespace ZL {
namespace Util {
enum LogLevel {
LTrace = 0, LDebug, LInfo, LWarn, LError, LFatal,
};
static const char *LogLevelStr[] = { "trace", "debug", "info", "warn", "error",
"fatal" };
#define CLEAR_COLOR "\033[0m"
#define UNDERLINE "\033[4m"
static const char *COLOR[6][2] = { { "\033[44;37m", "\033[34m" }, {
"\033[42;37m", "\033[32m" }, { "\033[46;37m", "\033[36m" }, {
"\033[43;37m", "\033[33m" }, { "\033[45;37m", "\033[35m" }, {
"\033[41;37m", "\033[31m" } };
class Logger;
class LogWriter;
class LogChannel;
class LogInfo;
class LogInfoMaker;
typedef std::shared_ptr<LogInfo> LogInfo_ptr;
class LogChannel {
public:
LogChannel(const string& name, LogLevel level = LDebug,
const char* timeFormat = "%Y-%m-%d %H:%M:%S") :
_name(name), _level(level), _timeFormat(timeFormat) {
}
virtual ~LogChannel() {
}
virtual void write(const LogInfo_ptr & stream)=0;
const string &name() const {
return _name;
}
LogLevel level() const {
return _level;
}
const string &timeFormat() const {
return _timeFormat;
}
void setLevel(LogLevel level) {
_level = level;
}
void setDateFormat(const char* format) {
_timeFormat = format;
}
protected:
string _name;
LogLevel _level;
string _timeFormat;
};
class LogWriter {
public:
LogWriter() {
}
virtual ~LogWriter() {
}
virtual void write(const LogInfo_ptr &stream) =0;
};
class Logger {
public:
friend class LogWriter;
friend class AsyncLogWriter;
static Logger& Instance() {
static Logger *logger(new Logger());
return *logger;
}
static void Destory() {
delete &Logger::Instance();
}
void add(const std::shared_ptr<LogChannel> &&channel) {
channels[channel->name()] = channel;
}
void del(const string& name) {
auto it = channels.find(name);
if (it != channels.end()) {
channels.erase(it);
}
}
std::shared_ptr<LogChannel> get(const string& name){
auto it = channels.find(name);
if(it == channels.end()){
return nullptr;
}
return it->second;
}
void setWriter(const std::shared_ptr<LogWriter> &&_writer) {
if (_writer) {
this->writer = _writer;
}
}
void write(const LogInfo_ptr &stream) {
if (writer) {
writer->write(stream);
return;
}
for (auto &chn : channels) {
chn.second->write(stream);
}
}
void setLevel(LogLevel level) {
for (auto &chn : channels) {
chn.second->setLevel(level);
}
}
protected:
Logger() {
}
~Logger() {
}
// Non-copyable and non-movable
Logger(const Logger&); // = delete;
Logger(Logger&&); // = delete;
Logger& operator=(const Logger&); // = delete;
Logger& operator=(Logger&&); // = delete;
map<string, std::shared_ptr<LogChannel> > channels;
std::shared_ptr<LogWriter> writer;
};
class LogInfo {
public:
friend class LogInfoMaker;
void format(ostream& ost, const char *timeFormat = "%Y-%m-%d %H:%M:%S",
bool enableColor = true) {
static string appName = exeName();
ost << appName << " "<< file << " " << line << "\r\n ";
if (enableColor) {
ost << COLOR[level][1];
}
if (timeFormat) {
ost << print(toLocal(ts), timeFormat);
}
ost << " [" << LogLevelStr[level] << "] ";
ost << function << " ";
ost << message.str();
if (enableColor) {
ost << CLEAR_COLOR;
}
ost.flush();
}
LogLevel getLevel() const {
return level;
}
private:
LogInfo(LogLevel _level, const char* _file, const char* _function,
int _line) :
level(_level), line(_line), file(_file), function(_function), ts(
::time(NULL)) {
}
std::string print(const std::tm& dt, const char* fmt) {
/*
#if defined(__WIN32__)
// BOGUS hack done for VS2012: C++11 non-conformant since it SHOULD take a "const struct tm* "
// ref. C++11 standard: ISO/IEC 14882:2011, <20> 27.7.1,
std::ostringstream oss;
oss << std::put_time(const_cast<std::tm*>(&dt), fmt);
return oss.str();
#else // LINUX
*/
const size_t size = 1024;
char buffer[size];
auto success = std::strftime(buffer, size, fmt, &dt);
if (0 == success)
return string(fmt);
return buffer;
//#endif
}
std::tm toLocal(const std::time_t& time) {
std::tm tm_snapshot;
#if defined(_WIN32)
localtime_s(&tm_snapshot, &time); // thread-safe?
#else
localtime_r(&time, &tm_snapshot); // POSIX
#endif //WIN32
return tm_snapshot;
}
LogLevel level;
int line;
string file;
string function;
time_t ts;
ostringstream message;
};
class LogInfoMaker {
public:
LogInfoMaker(LogLevel level, const char* file, const char* function,
int line) :
logInfo(new LogInfo(level, file, function, line)) {
}
LogInfoMaker(LogInfoMaker &&that) {
this->logInfo = that.logInfo;
that.logInfo.reset();
}
LogInfoMaker(const LogInfoMaker &that) {
this->logInfo = that.logInfo;
(const_cast<LogInfoMaker &>(that)).logInfo.reset();
}
~LogInfoMaker() {
*this << endl;
}
template<typename T>
LogInfoMaker& operator <<(const T& data) {
if (!logInfo) {
return *this;
}
logInfo->message << data;
return *this;
}
LogInfoMaker& operator <<(const char *data) {
if (!logInfo) {
return *this;
}
if(data){
logInfo->message << data;
}
return *this;
}
LogInfoMaker& operator <<(ostream&(*f)(ostream&)) {
if (!logInfo) {
return *this;
}
logInfo->message << f;
Logger::Instance().write(logInfo);
logInfo.reset();
return *this;
}
void clear() {
logInfo.reset();
}
private:
LogInfo_ptr logInfo;
};
class AsyncLogWriter: public LogWriter {
public:
AsyncLogWriter() :
exit_flag(false) {
_thread.reset(new thread([this]() {this->run();}));
}
virtual ~AsyncLogWriter() {
exit_flag = true;
sem.post();
_thread->join();
while (_pending.size()) {
auto &next = _pending.front();
realWrite(next);
_pending.pop_front();
}
}
virtual void write(const LogInfo_ptr &stream) {
{
lock_guard<mutex> lock(_mutex);
_pending.push_back(stream);
}
sem.post();
}
protected:
void run() {
while (!exit_flag) {
sem.wait();
{
lock_guard<mutex> lock(_mutex);
if (_pending.size()) {
auto &next = _pending.front();
realWrite(next);
_pending.pop_front();
}
}
}
}
inline void realWrite(const LogInfo_ptr &stream) {
for (auto &chn : Logger::Instance().channels) {
chn.second->write(stream);
}
}
bool exit_flag;
std::shared_ptr<thread> _thread;
deque<LogInfo_ptr> _pending;
semaphore sem;
mutex _mutex;
};
class ConsoleChannel: public LogChannel {
public:
ConsoleChannel(const string& name, LogLevel level = LDebug,
const char* timeFormat = "%Y-%m-%d %H:%M:%S") :
LogChannel(name, level, timeFormat) {
}
virtual ~ConsoleChannel() {
}
void write(const LogInfo_ptr &logInfo) {
if (level() > logInfo->getLevel()) {
return;
}
logInfo->format(std::cout, timeFormat().c_str(), true);
}
};
class FileChannel: public LogChannel {
public:
FileChannel(const string& name, const string& path, LogLevel level = LDebug,
const char* timeFormat = "%Y-%m-%d %H:%M:%S") :
LogChannel(name, level, timeFormat), _path(path) {
}
virtual ~FileChannel() {
close();
}
virtual void write(const std::shared_ptr<LogInfo> &stream) {
if (level() > stream->getLevel()) {
return;
}
if (!_fstream.is_open()) {
open();
}
stream->format(_fstream, timeFormat().c_str(), false);
}
void setPath(const string& path) {
_path = path;
open();
}
const string &path() const {
return _path;
}
protected:
virtual void open() {
// Ensure a path was set
if (_path.empty()) {
throw runtime_error("Log file path must be set.");
}
// Open the file stream
_fstream.close();
_fstream.open(_path.c_str(), ios::out | ios::app);
// Throw on failure
if (!_fstream.is_open()) {
throw runtime_error("Failed to open log file: " + _path);
}
}
virtual void close() {
_fstream.close();
}
ofstream _fstream;
string _path;
};
#define TraceL LogInfoMaker(LTrace, __FILE__,__FUNCTION__, __LINE__)
#define DebugL LogInfoMaker(LDebug, __FILE__,__FUNCTION__, __LINE__)
#define InfoL LogInfoMaker(LInfo, __FILE__,__FUNCTION__, __LINE__)
#define WarnL LogInfoMaker(LWarn,__FILE__, __FUNCTION__, __LINE__)
#define ErrorL LogInfoMaker(LError,__FILE__, __FUNCTION__, __LINE__)
#define FatalL LogInfoMaker(LFatal,__FILE__, __FUNCTION__, __LINE__)
} /* namespace util */
} /* namespace ZL */
#endif /* UTIL_LOGGER_H_ */

View File

@ -0,0 +1,149 @@
#ifndef UTIL_MINI_H
#define UTIL_MINI_H
#include <map>
#include <string>
#include <vector>
#include <fstream>
#include <cstring>
#include <cassert>
#include <iostream>
#include <exception>
#include "Util/util.h"
using namespace std;
namespace ZL {
namespace Util {
template<typename key, typename variant>
class mINI_basic: public map<key, variant> {
// Public API : existing map<> interface plus following methods
public:
void parse(const string &text) {
// reset, split lines and parse
static auto trim = []( string line ) {
while( line.size() && ( line.back()=='\t' || line.back()==' ' ) ) line.pop_back();
while( line.size() && ( line.front()=='\t' || line.front()==' ' ) ) line.erase(0,1);
return line;
};
vector<string> lines = tokenize(text, "\r\n");
string symbol, tag;
for (auto &line : lines){
// trim blanks
line = trim(line);
// split line into tokens and parse tokens
if(line.empty() || line.front() == ';' || line.front() == '#'){
continue;
}
if (line.size() >= 3 && line.front() == '[' && line.back() == ']') {
tag = trim(line.substr(1, line.size() - 2));
} else {
auto at = line.find_first_of('=');
symbol = trim(tag + "." + line.substr(0, at));
(*this)[symbol] = (at == string::npos ? string() : trim(line.substr(at + 1)));
}
}
}
void parseFile(const string &fileName = exePath() + ".ini") {
ifstream in(fileName, ios::in | ios::binary | ios::ate);
if (!in.good()) {
stringstream ss;
ss << "invalid ini file:" << fileName;
throw invalid_argument(ss.str());
}
long size = in.tellg();
in.seekg(0, ios::beg);
string buf;
buf.resize(size);
in.read((char *) buf.data(), size);
parse(buf);
}
string dump(const string &header = "; auto-generated by mINI class {",
const string &footer = "; } ---") const {
string output(header + (header.empty() ? "" : "\r\n")), tag;
for (auto &pr : *this) {
vector<string> kv = tokenize(pr.first, ".");
if (tag != kv[0]) {
output += "\r\n[" + (tag = kv[0]) + "]\r\n";
}
output += kv[1] + "=" + pr.second + "\r\n";
}
return output + "\r\n" + footer + (footer.empty() ? "" : "\r\n");
}
void dumpFile(const string &fileName = exePath() + ".ini") {
ofstream out(fileName, ios::out | ios::binary | ios::trunc);
auto dmp = dump();
out.write(dmp.data(),dmp.size());
}
static mINI_basic &Instance(){
static mINI_basic instance;
return instance;
}
private:
vector<string> tokenize(const string &self, const string &chars) const {
vector<string> tokens(1);
string map(256, '\0');
for (const unsigned char &ch : chars) {
map[ch] = '\1';
}
for (const unsigned char &ch : self) {
if (!map.at(ch)) {
tokens.back().push_back(char(ch));
} else if (tokens.back().size()) {
tokens.push_back(string());
}
}
while (tokens.size() && tokens.back().empty()) {
tokens.pop_back();
}
return tokens;
}
};
// handy variant class as key/values
struct variant: public string {
template<typename T>
variant(const T &t) :
string(to_string(t)) {
}
template<size_t N>
variant(const char (&s)[N]) :
string(s, N) {
}
variant(const char *cstr) :
string(cstr) {
}
variant(const string &other = string()) :
string(other) {
}
template<typename T>
operator T() const {
T t;
stringstream ss;
return ss << *this && ss >> t ? t : T();
}
template<typename T> bool operator ==(const T &t) const {
return 0 == this->compare(variant(t));
}
bool operator ==(const char *t) const {
return this->compare(t) == 0;
}
template<typename T>
T as() const {
return (T) (*this);
}
};
using mINI = mINI_basic<string, variant>;
} // namespace Util
} // namespace ZL
#endif //UTIL_MINI_H

View File

@ -0,0 +1,44 @@
/*
* onceToken.h
*
* Created on: 2016810
* Author: xzl
*/
#ifndef UTIL_ONCETOKEN_H_
#define UTIL_ONCETOKEN_H_
#include "functional"
using namespace std;
namespace ZL {
namespace Util {
class onceToken {
public:
typedef function<void(void)> task;
onceToken(const task &onConstructed, const task &_onDestructed) {
if (onConstructed) {
onConstructed();
}
onDestructed = _onDestructed;
}
virtual ~onceToken() {
if (onDestructed) {
onDestructed();
}
}
private:
onceToken();
onceToken(const onceToken &);
onceToken(onceToken &&);
onceToken &operator =(const onceToken &);
onceToken &operator =(onceToken &&);
task onDestructed;
};
} /* namespace Util */
} /* namespace ZL */
#endif /* UTIL_ONCETOKEN_H_ */

View File

@ -0,0 +1,79 @@
/*
* util.h
*
* Created on: 201684
* Author: xzl
*/
#ifndef UTIL_UTIL_H_
#define UTIL_UTIL_H_
#if defined(_WIN32)
#include <WinSock2.h>
#pragma comment (lib,"WS2_32")
#else
#include <unistd.h>
#include <sys/time.h>
#endif // defined(_WIN32)
#include <stdio.h>
#include <string.h>
#include <string>
#include <sstream>
using namespace std;
namespace ZL {
namespace Util {
class _StrPrinter {
public:
_StrPrinter() {
}
template<typename T>
_StrPrinter& operator <<(const T& data) {
ss << data;
return *this;
}
string operator <<(std::ostream&(*f)(std::ostream&)) const {
return ss.str();
}
private:
stringstream ss;
};
#define StrPrinter _StrPrinter()
string makeRandStr(int sz, bool printable = true);
string hexdump(const void *buf, size_t len);
string exePath();
string exeDir();
string exeName();
void setExePath(const string &path);
#ifndef bzero
#define bzero(ptr,size) memset((ptr),0,(size));
#endif //bzero
#if defined(ANDROID)
template <typename T>
std::string to_string(T value){
std::ostringstream os ;
os << std::forward<T>(value);
return os.str() ;
}
#endif//ANDROID
#if defined(_WIN32)
int gettimeofday(struct timeval *tp, void *tzp);
int strcasecmp(const char *strA,const char *strB);
void usleep(int micro_seconds);
void sleep(int second);
#endif //WIN32
} // namespace Util
} // namespace ZL
#endif /* UTIL_UTIL_H_ */

View File

@ -0,0 +1,522 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_ERRNO_H_
#define UV_ERRNO_H_
#include <errno.h>
#define UV__EOF (-4095)
#define UV__UNKNOWN (-4094)
#define UV__EAI_ADDRFAMILY (-3000)
#define UV__EAI_AGAIN (-3001)
#define UV__EAI_BADFLAGS (-3002)
#define UV__EAI_CANCELED (-3003)
#define UV__EAI_FAIL (-3004)
#define UV__EAI_FAMILY (-3005)
#define UV__EAI_MEMORY (-3006)
#define UV__EAI_NODATA (-3007)
#define UV__EAI_NONAME (-3008)
#define UV__EAI_OVERFLOW (-3009)
#define UV__EAI_SERVICE (-3010)
#define UV__EAI_SOCKTYPE (-3011)
#define UV__EAI_BADHINTS (-3013)
#define UV__EAI_PROTOCOL (-3014)
/* Only map to the system errno on non-Windows platforms. It's apparently
* a fairly common practice for Windows programmers to redefine errno codes.
*/
#if defined(E2BIG) && !defined(_WIN32)
# define UV__E2BIG (-E2BIG)
#else
# define UV__E2BIG (-4093)
#endif
#if defined(EACCES) && !defined(_WIN32)
# define UV__EACCES (-EACCES)
#else
# define UV__EACCES (-4092)
#endif
#if defined(EADDRINUSE) && !defined(_WIN32)
# define UV__EADDRINUSE (-EADDRINUSE)
#else
# define UV__EADDRINUSE (-4091)
#endif
#if defined(EADDRNOTAVAIL) && !defined(_WIN32)
# define UV__EADDRNOTAVAIL (-EADDRNOTAVAIL)
#else
# define UV__EADDRNOTAVAIL (-4090)
#endif
#if defined(EAFNOSUPPORT) && !defined(_WIN32)
# define UV__EAFNOSUPPORT (-EAFNOSUPPORT)
#else
# define UV__EAFNOSUPPORT (-4089)
#endif
#if defined(EAGAIN) && !defined(_WIN32)
# define UV__EAGAIN (-EAGAIN)
#else
# define UV__EAGAIN (-4088)
#endif
#if defined(EALREADY) && !defined(_WIN32)
# define UV__EALREADY (-EALREADY)
#else
# define UV__EALREADY (-4084)
#endif
#if defined(EBADF) && !defined(_WIN32)
# define UV__EBADF (-EBADF)
#else
# define UV__EBADF (-4083)
#endif
#if defined(EBUSY) && !defined(_WIN32)
# define UV__EBUSY (-EBUSY)
#else
# define UV__EBUSY (-4082)
#endif
#if defined(ECANCELED) && !defined(_WIN32)
# define UV__ECANCELED (-ECANCELED)
#else
# define UV__ECANCELED (-4081)
#endif
#if defined(ECHARSET) && !defined(_WIN32)
# define UV__ECHARSET (-ECHARSET)
#else
# define UV__ECHARSET (-4080)
#endif
#if defined(ECONNABORTED) && !defined(_WIN32)
# define UV__ECONNABORTED (-ECONNABORTED)
#else
# define UV__ECONNABORTED (-4079)
#endif
#if defined(ECONNREFUSED) && !defined(_WIN32)
# define UV__ECONNREFUSED (-ECONNREFUSED)
#else
# define UV__ECONNREFUSED (-4078)
#endif
#if defined(ECONNRESET) && !defined(_WIN32)
# define UV__ECONNRESET (-ECONNRESET)
#else
# define UV__ECONNRESET (-4077)
#endif
#if defined(EDESTADDRREQ) && !defined(_WIN32)
# define UV__EDESTADDRREQ (-EDESTADDRREQ)
#else
# define UV__EDESTADDRREQ (-4076)
#endif
#if defined(EEXIST) && !defined(_WIN32)
# define UV__EEXIST (-EEXIST)
#else
# define UV__EEXIST (-4075)
#endif
#if defined(EFAULT) && !defined(_WIN32)
# define UV__EFAULT (-EFAULT)
#else
# define UV__EFAULT (-4074)
#endif
#if defined(EHOSTUNREACH) && !defined(_WIN32)
# define UV__EHOSTUNREACH (-EHOSTUNREACH)
#else
# define UV__EHOSTUNREACH (-4073)
#endif
#if defined(EINTR) && !defined(_WIN32)
# define UV__EINTR (-EINTR)
#else
# define UV__EINTR (-4072)
#endif
#if defined(EINVAL) && !defined(_WIN32)
# define UV__EINVAL (-EINVAL)
#else
# define UV__EINVAL (-4071)
#endif
#if defined(EIO) && !defined(_WIN32)
# define UV__EIO (-EIO)
#else
# define UV__EIO (-4070)
#endif
#if defined(EISCONN) && !defined(_WIN32)
# define UV__EISCONN (-EISCONN)
#else
# define UV__EISCONN (-4069)
#endif
#if defined(EISDIR) && !defined(_WIN32)
# define UV__EISDIR (-EISDIR)
#else
# define UV__EISDIR (-4068)
#endif
#if defined(ELOOP) && !defined(_WIN32)
# define UV__ELOOP (-ELOOP)
#else
# define UV__ELOOP (-4067)
#endif
#if defined(EMFILE) && !defined(_WIN32)
# define UV__EMFILE (-EMFILE)
#else
# define UV__EMFILE (-4066)
#endif
#if defined(EMSGSIZE) && !defined(_WIN32)
# define UV__EMSGSIZE (-EMSGSIZE)
#else
# define UV__EMSGSIZE (-4065)
#endif
#if defined(ENAMETOOLONG) && !defined(_WIN32)
# define UV__ENAMETOOLONG (-ENAMETOOLONG)
#else
# define UV__ENAMETOOLONG (-4064)
#endif
#if defined(ENETDOWN) && !defined(_WIN32)
# define UV__ENETDOWN (-ENETDOWN)
#else
# define UV__ENETDOWN (-4063)
#endif
#if defined(ENETUNREACH) && !defined(_WIN32)
# define UV__ENETUNREACH (-ENETUNREACH)
#else
# define UV__ENETUNREACH (-4062)
#endif
#if defined(ENFILE) && !defined(_WIN32)
# define UV__ENFILE (-ENFILE)
#else
# define UV__ENFILE (-4061)
#endif
#if defined(ENOBUFS) && !defined(_WIN32)
# define UV__ENOBUFS (-ENOBUFS)
#else
# define UV__ENOBUFS (-4060)
#endif
#if defined(ENODEV) && !defined(_WIN32)
# define UV__ENODEV (-ENODEV)
#else
# define UV__ENODEV (-4059)
#endif
#if defined(ENOENT) && !defined(_WIN32)
# define UV__ENOENT (-ENOENT)
#else
# define UV__ENOENT (-4058)
#endif
#if defined(ENOMEM) && !defined(_WIN32)
# define UV__ENOMEM (-ENOMEM)
#else
# define UV__ENOMEM (-4057)
#endif
#if defined(ENONET) && !defined(_WIN32)
# define UV__ENONET (-ENONET)
#else
# define UV__ENONET (-4056)
#endif
#if defined(ENOSPC) && !defined(_WIN32)
# define UV__ENOSPC (-ENOSPC)
#else
# define UV__ENOSPC (-4055)
#endif
#if defined(ENOSYS) && !defined(_WIN32)
# define UV__ENOSYS (-ENOSYS)
#else
# define UV__ENOSYS (-4054)
#endif
#if defined(ENOTCONN) && !defined(_WIN32)
# define UV__ENOTCONN (-ENOTCONN)
#else
# define UV__ENOTCONN (-4053)
#endif
#if defined(ENOTDIR) && !defined(_WIN32)
# define UV__ENOTDIR (-ENOTDIR)
#else
# define UV__ENOTDIR (-4052)
#endif
#if defined(ENOTEMPTY) && !defined(_WIN32)
# define UV__ENOTEMPTY (-ENOTEMPTY)
#else
# define UV__ENOTEMPTY (-4051)
#endif
#if defined(ENOTSOCK) && !defined(_WIN32)
# define UV__ENOTSOCK (-ENOTSOCK)
#else
# define UV__ENOTSOCK (-4050)
#endif
#if defined(ENOTSUP) && !defined(_WIN32)
# define UV__ENOTSUP (-ENOTSUP)
#else
# define UV__ENOTSUP (-4049)
#endif
#if defined(EPERM) && !defined(_WIN32)
# define UV__EPERM (-EPERM)
#else
# define UV__EPERM (-4048)
#endif
#if defined(EPIPE) && !defined(_WIN32)
# define UV__EPIPE (-EPIPE)
#else
# define UV__EPIPE (-4047)
#endif
#if defined(EPROTO) && !defined(_WIN32)
# define UV__EPROTO (-EPROTO)
#else
# define UV__EPROTO (-4046)
#endif
#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
# define UV__EPROTONOSUPPORT (-EPROTONOSUPPORT)
#else
# define UV__EPROTONOSUPPORT (-4045)
#endif
#if defined(EPROTOTYPE) && !defined(_WIN32)
# define UV__EPROTOTYPE (-EPROTOTYPE)
#else
# define UV__EPROTOTYPE (-4044)
#endif
#if defined(EROFS) && !defined(_WIN32)
# define UV__EROFS (-EROFS)
#else
# define UV__EROFS (-4043)
#endif
#if defined(ESHUTDOWN) && !defined(_WIN32)
# define UV__ESHUTDOWN (-ESHUTDOWN)
#else
# define UV__ESHUTDOWN (-4042)
#endif
#if defined(ESPIPE) && !defined(_WIN32)
# define UV__ESPIPE (-ESPIPE)
#else
# define UV__ESPIPE (-4041)
#endif
#if defined(ESRCH) && !defined(_WIN32)
# define UV__ESRCH (-ESRCH)
#else
# define UV__ESRCH (-4040)
#endif
#if defined(ETIMEDOUT) && !defined(_WIN32)
# define UV__ETIMEDOUT (-ETIMEDOUT)
#else
# define UV__ETIMEDOUT (-4039)
#endif
#if defined(ETXTBSY) && !defined(_WIN32)
# define UV__ETXTBSY (-ETXTBSY)
#else
# define UV__ETXTBSY (-4038)
#endif
#if defined(EXDEV) && !defined(_WIN32)
# define UV__EXDEV (-EXDEV)
#else
# define UV__EXDEV (-4037)
#endif
#if defined(EFBIG) && !defined(_WIN32)
# define UV__EFBIG (-EFBIG)
#else
# define UV__EFBIG (-4036)
#endif
#if defined(ENOPROTOOPT) && !defined(_WIN32)
# define UV__ENOPROTOOPT (-ENOPROTOOPT)
#else
# define UV__ENOPROTOOPT (-4035)
#endif
#if defined(ERANGE) && !defined(_WIN32)
# define UV__ERANGE (-ERANGE)
#else
# define UV__ERANGE (-4034)
#endif
#if defined(ENXIO) && !defined(_WIN32)
# define UV__ENXIO (-ENXIO)
#else
# define UV__ENXIO (-4033)
#endif
#if defined(EMLINK) && !defined(_WIN32)
# define UV__EMLINK (-EMLINK)
#else
# define UV__EMLINK (-4032)
#endif
/* EHOSTDOWN is not visible on BSD-like systems when _POSIX_C_SOURCE is
* defined. Fortunately, its value is always 64 so it's possible albeit
* icky to hard-code it.
*/
#if defined(EHOSTDOWN) && !defined(_WIN32)
# define UV__EHOSTDOWN (-EHOSTDOWN)
#elif defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__)
# define UV__EHOSTDOWN (-64)
#else
# define UV__EHOSTDOWN (-4031)
#endif
#if defined(EREMOTEIO) && !defined(_WIN32)
# define UV__EREMOTEIO (-EREMOTEIO)
#else
# define UV__EREMOTEIO (-4030)
#endif
#define UV_ERRNO_MAP(XX) \
XX(E2BIG, "argument list too long") \
XX(EACCES, "permission denied") \
XX(EADDRINUSE, "address already in use") \
XX(EADDRNOTAVAIL, "address not available") \
XX(EAFNOSUPPORT, "address family not supported") \
XX(EAGAIN, "resource temporarily unavailable") \
XX(EAI_ADDRFAMILY, "address family not supported") \
XX(EAI_AGAIN, "temporary failure") \
XX(EAI_BADFLAGS, "bad ai_flags value") \
XX(EAI_BADHINTS, "invalid value for hints") \
XX(EAI_CANCELED, "request canceled") \
XX(EAI_FAIL, "permanent failure") \
XX(EAI_FAMILY, "ai_family not supported") \
XX(EAI_MEMORY, "out of memory") \
XX(EAI_NODATA, "no address") \
XX(EAI_NONAME, "unknown node or service") \
XX(EAI_OVERFLOW, "argument buffer overflow") \
XX(EAI_PROTOCOL, "resolved protocol is unknown") \
XX(EAI_SERVICE, "service not available for socket type") \
XX(EAI_SOCKTYPE, "socket type not supported") \
XX(EALREADY, "connection already in progress") \
XX(EBADF, "bad file descriptor") \
XX(EBUSY, "resource busy or locked") \
XX(ECANCELED, "operation canceled") \
XX(ECHARSET, "invalid Unicode character") \
XX(ECONNABORTED, "software caused connection abort") \
XX(ECONNREFUSED, "connection refused") \
XX(ECONNRESET, "connection reset by peer") \
XX(EDESTADDRREQ, "destination address required") \
XX(EEXIST, "file already exists") \
XX(EFAULT, "bad address in system call argument") \
XX(EFBIG, "file too large") \
XX(EHOSTUNREACH, "host is unreachable") \
XX(EINTR, "interrupted system call") \
XX(EINVAL, "invalid argument") \
XX(EIO, "i/o error") \
XX(EISCONN, "socket is already connected") \
XX(EISDIR, "illegal operation on a directory") \
XX(ELOOP, "too many symbolic links encountered") \
XX(EMFILE, "too many open files") \
XX(EMSGSIZE, "message too long") \
XX(ENAMETOOLONG, "name too long") \
XX(ENETDOWN, "network is down") \
XX(ENETUNREACH, "network is unreachable") \
XX(ENFILE, "file table overflow") \
XX(ENOBUFS, "no buffer space available") \
XX(ENODEV, "no such device") \
XX(ENOENT, "no such file or directory") \
XX(ENOMEM, "not enough memory") \
XX(ENONET, "machine is not on the network") \
XX(ENOPROTOOPT, "protocol not available") \
XX(ENOSPC, "no space left on device") \
XX(ENOSYS, "function not implemented") \
XX(ENOTCONN, "socket is not connected") \
XX(ENOTDIR, "not a directory") \
XX(ENOTEMPTY, "directory not empty") \
XX(ENOTSOCK, "socket operation on non-socket") \
XX(ENOTSUP, "operation not supported on socket") \
XX(EPERM, "operation not permitted") \
XX(EPIPE, "broken pipe") \
XX(EPROTO, "protocol error") \
XX(EPROTONOSUPPORT, "protocol not supported") \
XX(EPROTOTYPE, "protocol wrong type for socket") \
XX(ERANGE, "result too large") \
XX(EROFS, "read-only file system") \
XX(ESHUTDOWN, "cannot send after transport endpoint shutdown") \
XX(ESPIPE, "invalid seek") \
XX(ESRCH, "no such process") \
XX(ETIMEDOUT, "connection timed out") \
XX(ETXTBSY, "text file is busy") \
XX(EXDEV, "cross-device link not permitted") \
XX(UNKNOWN, "unknown error") \
XX(EOF, "end of file") \
XX(ENXIO, "no such device or address") \
XX(EMLINK, "too many links") \
XX(EHOSTDOWN, "host is down") \
XX(EREMOTEIO, "remote I/O error") \
typedef enum {
#define XX(code, _) UV_ ## code = UV__ ## code,
UV_ERRNO_MAP(XX)
#undef XX
UV_ERRNO_MAX = UV__EOF - 1
} uv_errno_t;
const char* uv_err_name(int err);
const char* uv_strerror(int err);
int uv_translate_posix_error(int err);
int get_uv_error(bool netErr = false);
const char* get_uv_errmsg(bool netErr = false);
#endif /* UV_ERRNO_H_ */

Binary file not shown.

BIN
bin_lib/windows/libcrypto-1_1.dll Executable file

Binary file not shown.

BIN
bin_lib/windows/libmysql.dll Executable file

Binary file not shown.

BIN
bin_lib/windows/libssl-1_1.dll Executable file

Binary file not shown.

View File

@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDe56xOopefsL3K+kfpDohkBnjZaTCLVdS+p6BUeRbeFO9xOaGy
5hPnVLHI1nlpRZaKfxm1MY9fDBh1kSbjhSqim9HUBoSvEE32yMM+0GIoNKKDWmhd
ePDXuSNO6d9nabg+5gmrR2fyYtSigTH6liqGSjhblAozlaXVZVYZOs/ePwIDAQAB
AoGAYcjkMALn3SgduoOdNEIp1yd3sHiS0S0wDQtgLG6Kd5ZbjCIqK17/cEYZT++2
h1X9ungTgQdiy+F0gW7RzpHGp4lso2a8PgEUIt4HICLZqBOWv6kId43kysBZQS/5
5g0ZGJGU5BFTdHzN5chaPE32MRGPpukNngRuRruRvoQaOuECQQD0EoC6EHwLehFI
KoLnDtzXpR1f4eRRbxJ6U/05Kr4+nz+MB7A2ilGEf+E7iCvoRGYkuieEuKYS9+NQ
Bv67i/aZAkEA6cxan6Q5BsSCoIKGbqATxW40j7m0Ii3VFb4w9vgaI0mHdRl9x59x
LKsIamcJZI7szmJdOi3tBKB9Xc3PxfD6lwJBAIYOU53eyAMVvMBCeTunsizPh97O
F7WSqDeAQilQDMYgearT3jlWp4d7JZ6pIFSmnOO3S1VehfkNJlEiRm+EZKECQCEb
+IV9GzpTH/CdK26FKueduMHV2aWxeeivW33OGt1+bzltF7vqX3uk6Pcwikr8VprP
oUY49MTf+YEMQW1VuBcCQA3UvxGx7YbD3RihysBmTLHyF2DOR3pBQdL1jH5fFI9k
mMo0M2cvHytsIYZ69oULJkQ0TyNBslm/TLaHAK6fHbo=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIICWDCCAcGgAwIBAgIJANTNO5CfgnKmMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTYwMTExMDgyNTIxWhcNMTkwMTEwMDgyNTIxWjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQDe56xOopefsL3K+kfpDohkBnjZaTCLVdS+p6BUeRbeFO9xOaGy5hPnVLHI1nlp
RZaKfxm1MY9fDBh1kSbjhSqim9HUBoSvEE32yMM+0GIoNKKDWmhdePDXuSNO6d9n
abg+5gmrR2fyYtSigTH6liqGSjhblAozlaXVZVYZOs/ePwIDAQABo1AwTjAdBgNV
HQ4EFgQUKOfhSgRHIkKMX7cwlVIBR493EXQwHwYDVR0jBBgwFoAUKOfhSgRHIkKM
X7cwlVIBR493EXQwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQCxs7Ge
0mjdtHhFd7qerYVYS0uvVzRdYsYnK+rY6Y5wtXEWDNG2EOLA5/puaj93mvesKXTl
plTjFUnhmyXwwvXuKx+PdK87FXl4sTIyvf4/1eN2QIpy6WU4lAE11ONNF8djNc4W
FCu9etyoYfy6NE4C/ntJpB0xCNrX1cvrmukb6g==
-----END CERTIFICATE-----

View File

@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDe56xOopefsL3K+kfpDohkBnjZaTCLVdS+p6BUeRbeFO9xOaGy
5hPnVLHI1nlpRZaKfxm1MY9fDBh1kSbjhSqim9HUBoSvEE32yMM+0GIoNKKDWmhd
ePDXuSNO6d9nabg+5gmrR2fyYtSigTH6liqGSjhblAozlaXVZVYZOs/ePwIDAQAB
AoGAYcjkMALn3SgduoOdNEIp1yd3sHiS0S0wDQtgLG6Kd5ZbjCIqK17/cEYZT++2
h1X9ungTgQdiy+F0gW7RzpHGp4lso2a8PgEUIt4HICLZqBOWv6kId43kysBZQS/5
5g0ZGJGU5BFTdHzN5chaPE32MRGPpukNngRuRruRvoQaOuECQQD0EoC6EHwLehFI
KoLnDtzXpR1f4eRRbxJ6U/05Kr4+nz+MB7A2ilGEf+E7iCvoRGYkuieEuKYS9+NQ
Bv67i/aZAkEA6cxan6Q5BsSCoIKGbqATxW40j7m0Ii3VFb4w9vgaI0mHdRl9x59x
LKsIamcJZI7szmJdOi3tBKB9Xc3PxfD6lwJBAIYOU53eyAMVvMBCeTunsizPh97O
F7WSqDeAQilQDMYgearT3jlWp4d7JZ6pIFSmnOO3S1VehfkNJlEiRm+EZKECQCEb
+IV9GzpTH/CdK26FKueduMHV2aWxeeivW33OGt1+bzltF7vqX3uk6Pcwikr8VprP
oUY49MTf+YEMQW1VuBcCQA3UvxGx7YbD3RihysBmTLHyF2DOR3pBQdL1jH5fFI9k
mMo0M2cvHytsIYZ69oULJkQ0TyNBslm/TLaHAK6fHbo=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIICWDCCAcGgAwIBAgIJANTNO5CfgnKmMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTYwMTExMDgyNTIxWhcNMTkwMTEwMDgyNTIxWjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQDe56xOopefsL3K+kfpDohkBnjZaTCLVdS+p6BUeRbeFO9xOaGy5hPnVLHI1nlp
RZaKfxm1MY9fDBh1kSbjhSqim9HUBoSvEE32yMM+0GIoNKKDWmhdePDXuSNO6d9n
abg+5gmrR2fyYtSigTH6liqGSjhblAozlaXVZVYZOs/ePwIDAQABo1AwTjAdBgNV
HQ4EFgQUKOfhSgRHIkKMX7cwlVIBR493EXQwHwYDVR0jBBgwFoAUKOfhSgRHIkKM
X7cwlVIBR493EXQwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQCxs7Ge
0mjdtHhFd7qerYVYS0uvVzRdYsYnK+rY6Y5wtXEWDNG2EOLA5/puaj93mvesKXTl
plTjFUnhmyXwwvXuKx+PdK87FXl4sTIyvf4/1eN2QIpy6WU4lAE11ONNF8djNc4W
FCu9etyoYfy6NE4C/ntJpB0xCNrX1cvrmukb6g==
-----END CERTIFICATE-----