├── HIK_EHome ├── doc │ └── Hikvision_EHOME_SDK使用手册.chm ├── eh_cn │ ├── HCEHomeAlarm.h │ ├── HCEHomeCMS.h │ ├── HCEHomePublic.h │ └── HCEHomeStream.h └── eh_lib │ ├── libHCEHomeCMS.so │ ├── libHCEHomeStream.so │ ├── libSystemTransform.so │ ├── libhpr.so │ └── libiconv2.so ├── LICENSE ├── README.md ├── config.h ├── conv ├── parser_h264.c ├── parser_h264.h ├── parser_ps.c ├── parser_ps.h ├── sps_dec.c └── sps_dec.h ├── ipc ├── cms_vtdu.c ├── cms_vtdu.h ├── ipcs.c └── ipcs.h ├── librtmp ├── COPYING ├── Makefile ├── amf.c ├── amf.h ├── bytes.h ├── dh.h ├── dhgroups.h ├── handshake.h ├── hashswf.c ├── http.h ├── librtmp.3 ├── librtmp.3.html ├── librtmp.pc.in ├── parseurl.c ├── rtmp.c ├── rtmp.h ├── rtmp_log.c ├── rtmp_log.h └── rtmp_sys.h ├── main.c ├── makefile ├── record ├── log.c └── log.h └── request ├── req_srv.c └── req_srv.h /HIK_EHome/doc/Hikvision_EHOME_SDK使用手册.chm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlesPu/HIKPusher/26c6815dccc57bd60b93bffcda15dbfe7229d0e2/HIK_EHome/doc/Hikvision_EHOME_SDK使用手册.chm -------------------------------------------------------------------------------- /HIK_EHome/eh_cn/HCEHomeAlarm.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlesPu/HIKPusher/26c6815dccc57bd60b93bffcda15dbfe7229d0e2/HIK_EHome/eh_cn/HCEHomeAlarm.h -------------------------------------------------------------------------------- /HIK_EHome/eh_cn/HCEHomeCMS.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlesPu/HIKPusher/26c6815dccc57bd60b93bffcda15dbfe7229d0e2/HIK_EHome/eh_cn/HCEHomeCMS.h -------------------------------------------------------------------------------- /HIK_EHome/eh_cn/HCEHomePublic.h: -------------------------------------------------------------------------------- 1 | #ifndef _HC_EHOME_PUBLIC_H_ 2 | #define _HC_EHOME_PUBLIC_H_ 3 | 4 | //多SDK公共定义 5 | #ifndef _HC_NET_SDK_H_ 6 | 7 | /*******************平台相关的数据类型定义 begin**********************/ 8 | 9 | #if (defined(_WIN32)) //windows 10 | #define NET_DVR_API extern "C"__declspec(dllimport) 11 | typedef unsigned __int64 UINT64; 12 | #elif defined(__linux__) || defined(__APPLE__) //linux 13 | typedef unsigned int DWORD; 14 | typedef unsigned short WORD; 15 | typedef unsigned short USHORT; 16 | typedef short SHORT; 17 | typedef int LONG; 18 | typedef unsigned char BYTE; 19 | #define BOOL int 20 | // #define bool int 21 | typedef unsigned int UINT; 22 | typedef void* LPVOID; 23 | typedef void* HANDLE; 24 | typedef unsigned int* LPDWORD; 25 | typedef unsigned long long UINT64; 26 | 27 | #ifndef TRUE 28 | #define TRUE 1 29 | #endif 30 | #ifndef FALSE 31 | #define FALSE 0 32 | #endif 33 | #ifndef NULL 34 | #define NULL 0 35 | #endif 36 | 37 | #define __stdcall 38 | #define CALLBACK 39 | 40 | #ifdef __cplusplus 41 | #define NET_DVR_API extern "C" 42 | #else 43 | #define NET_DVR_API 44 | #endif 45 | 46 | #endif //linux 47 | 48 | /*******************平台相关的数据类型定义 end**********************/ 49 | 50 | /*******************全局错误码 begin**********************/ 51 | #define NET_DVR_NOERROR 0 //没有错误 52 | #define NET_DVR_PASSWORD_ERROR 1 //用户名密码错误 53 | #define NET_DVR_NOENOUGHPRI 2 //权限不足 54 | #define NET_DVR_NOINIT 3 //没有初始化 55 | #define NET_DVR_CHANNEL_ERROR 4 //通道号错误 56 | #define NET_DVR_OVER_MAXLINK 5 //连接到DVR的客户端个数超过最大 57 | #define NET_DVR_VERSIONNOMATCH 6 //版本不匹配 58 | #define NET_DVR_NETWORK_FAIL_CONNECT 7 //连接服务器失败 59 | #define NET_DVR_NETWORK_SEND_ERROR 8 //向服务器发送失败 60 | #define NET_DVR_NETWORK_RECV_ERROR 9 //从服务器接收数据失败 61 | #define NET_DVR_NETWORK_RECV_TIMEOUT 10 //从服务器接收数据超时 62 | #define NET_DVR_NETWORK_ERRORDATA 11 //传送的数据有误 63 | #define NET_DVR_ORDER_ERROR 12 //调用次序错误 64 | #define NET_DVR_OPERNOPERMIT 13 //无此权限 65 | #define NET_DVR_COMMANDTIMEOUT 14 //DVR命令执行超时c 66 | 67 | #define NET_DVR_PARAMETER_ERROR 17 //参数错误 68 | 69 | #define NET_DVR_NOSUPPORT 23 //服务器不支持 70 | 71 | #define NET_DVR_DVROPRATEFAILED 29 //DVR操作失败 72 | 73 | #define NET_DVR_DIR_ERROR 40 //路径错误 74 | #define NET_DVR_ALLOC_RESOURCE_ERROR 41 //资源分配错误 75 | #define NET_DVR_AUDIO_MODE_ERROR 42 //声卡模式错误 76 | #define NET_DVR_NOENOUGH_BUF 43 //缓冲区太小 77 | #define NET_DVR_CREATESOCKET_ERROR 44 //创建SOCKET出错 78 | #define NET_DVR_SETSOCKET_ERROR 45 //设置SOCKET出错 79 | #define NET_DVR_MAX_NUM 46 //个数达到最大 80 | #define NET_DVR_USERNOTEXIST 47 //用户不存在 81 | 82 | #define NET_DVR_GETLOCALIPANDMACFAIL 53 //获得本地的IP地址或物理地址失败 83 | 84 | #define NET_DVR_VOICEMONOPOLIZE 69 //声卡被独占 85 | 86 | #define NET_DVR_CREATEDIR_ERROR 71 //建立日志文件目录失败 87 | #define NET_DVR_BINDSOCKET_ERROR 72 //绑定套接字失败 88 | #define NET_DVR_SOCKETCLOSE_ERROR 73 //socket连接中断,此错误通常是由于连接中断或目的地不可达 89 | #define NET_DVR_USERID_ISUSING 74 //注销时用户ID正在进行某操作 90 | #define NET_DVR_SOCKETLISTEN_ERROR 75 //监听失败 91 | 92 | #define NET_DVR_CONVERT_SDK_ERROR 85 //加载转码库失败 93 | 94 | #define NET_DVR_FUNCTION_NOT_SUPPORT_OS 98 //此功能不支持该操作系统 95 | 96 | #define NET_DVR_USE_LOG_SWITCH_FILE 103 //正在使用日志开关文件 97 | 98 | #define NET_DVR_PACKET_TYPE_NOT_SUPPORT 105 //码流封装格式错误 99 | 100 | 101 | 102 | //语音对讲库错误码 103 | #define NET_AUDIOINTERCOM_OK 600 //无错误 104 | #define NET_AUDIOINTECOM_ERR_NOTSUPORT 601 //不支持 105 | #define NET_AUDIOINTECOM_ERR_ALLOC_MEMERY 602 //内存申请错误 106 | #define NET_AUDIOINTECOM_ERR_PARAMETER 603 //参数错误 107 | #define NET_AUDIOINTECOM_ERR_CALL_ORDER 604 //调用次序错误 108 | #define NET_AUDIOINTECOM_ERR_FIND_DEVICE 605 //未发现设备 109 | #define NET_AUDIOINTECOM_ERR_OPEN_DEVICE 606 //不能打开设备诶 110 | #define NET_AUDIOINTECOM_ERR_NO_CONTEXT 607 //设备上下文出错 111 | #define NET_AUDIOINTECOM_ERR_NO_WAVFILE 608 //WAV文件出错 112 | #define NET_AUDIOINTECOM_ERR_INVALID_TYPE 609 //无效的WAV参数类型 113 | #define NET_AUDIOINTECOM_ERR_ENCODE_FAIL 610 //编码失败 114 | #define NET_AUDIOINTECOM_ERR_DECODE_FAIL 611 //解码失败 115 | #define NET_AUDIOINTECOM_ERR_NO_PLAYBACK 612 //播放失败 116 | #define NET_AUDIOINTECOM_ERR_DENOISE_FAIL 613 //降噪失败 117 | #define NET_AUDIOINTECOM_ERR_UNKOWN 619 //未知错误 118 | 119 | /*******************全局错误码 begin**********************/ 120 | #define MAX_PASSWD_LEN 32 121 | #define NAME_LEN 32 //用户名长度 122 | 123 | #endif //_HC_NET_SDK_H_ 124 | #define MAX_DEVICE_ID_LEN 256 //设备ID长度 125 | #define NET_EHOME_SERIAL_LEN 12 126 | 127 | 128 | typedef struct tagNET_EHOME_IPADDRESS 129 | { 130 | char szIP[128]; 131 | WORD wPort; //端口 132 | char byRes[2]; 133 | }NET_EHOME_IPADDRESS, *LPNET_EHOME_IPADDRESS; 134 | 135 | typedef struct tagNET_EHOME_ZONE 136 | { 137 | DWORD dwX; //X轴坐标 138 | DWORD dwY; //Y轴坐标 139 | DWORD dwWidth; //宽度 140 | DWORD dwHeight; //高度 141 | }NET_EHOME_ZONE, *LPNET_EHOME_ZONE; 142 | 143 | //本地配置 144 | typedef enum tagNET_EHOME_LOCAL_CFG_TYPE 145 | { 146 | UNDEFINE = -1, //暂时没有具体的定义 147 | ACTIVE_ACCESS_SECURITY = 0, //设备主动接入的安全性 148 | AMS_ADDRESS = 1, //报警服务器本地回环地址 149 | SEND_PARAM = 2, //发送参数配置 150 | }NET_EHOME_LOCAL_CFG_TYPE, *LPNET_EHOME_LOCAL_CFG_TYPE; 151 | 152 | typedef struct tagNET_EHOME_LOCAL_ACCESS_SECURITY 153 | { 154 | DWORD dwSize; 155 | BYTE byAccessSecurity; //0-兼容模式(允许任意版本的协议接入),1-普通模式(只支持4.0以下版本,不支持协议安全的版本接入) 2-安全模式(只允许4.0以上版本,支持协议安全的版本接入) 156 | BYTE byRes[127]; 157 | }NET_EHOME_LOCAL_ACCESS_SECURITY,*LPNET_EHOME_LOCAL_ACCESS_SECURITY; 158 | 159 | typedef struct tagNET_EHOME_AMS_ADDRESS 160 | { 161 | DWORD dwSize; 162 | BYTE byEnable; //0-关闭CMS接收报警功能,1-开启CMS接收报警功能 163 | BYTE byRes1[3]; 164 | NET_EHOME_IPADDRESS struAddress; //AMS本地回环地址 165 | BYTE byRes2[32]; 166 | }NET_EHOME_AMS_ADDRESS, *LPNET_EHOME_AMS_ADDRESS; 167 | 168 | typedef struct tagNET_EHOME_SEND_PARAM 169 | { 170 | DWORD dwSize; 171 | DWORD dwRecvTimeOut; //接收超时时间,单位毫秒 172 | BYTE bySendTimes; //报文发送次数,为了应对网络环境较差的情况下,丢包的情况,默认一次,最大3次 173 | BYTE byRes2[127]; 174 | }NET_EHOME_SEND_PARAM, *LPNET_EHOME_SEND_PARAM; 175 | 176 | 177 | #endif //_HC_EHOME_PUBLIC_H_ -------------------------------------------------------------------------------- /HIK_EHome/eh_cn/HCEHomeStream.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlesPu/HIKPusher/26c6815dccc57bd60b93bffcda15dbfe7229d0e2/HIK_EHome/eh_cn/HCEHomeStream.h -------------------------------------------------------------------------------- /HIK_EHome/eh_lib/libHCEHomeCMS.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlesPu/HIKPusher/26c6815dccc57bd60b93bffcda15dbfe7229d0e2/HIK_EHome/eh_lib/libHCEHomeCMS.so -------------------------------------------------------------------------------- /HIK_EHome/eh_lib/libHCEHomeStream.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlesPu/HIKPusher/26c6815dccc57bd60b93bffcda15dbfe7229d0e2/HIK_EHome/eh_lib/libHCEHomeStream.so -------------------------------------------------------------------------------- /HIK_EHome/eh_lib/libSystemTransform.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlesPu/HIKPusher/26c6815dccc57bd60b93bffcda15dbfe7229d0e2/HIK_EHome/eh_lib/libSystemTransform.so -------------------------------------------------------------------------------- /HIK_EHome/eh_lib/libhpr.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlesPu/HIKPusher/26c6815dccc57bd60b93bffcda15dbfe7229d0e2/HIK_EHome/eh_lib/libhpr.so -------------------------------------------------------------------------------- /HIK_EHome/eh_lib/libiconv2.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlesPu/HIKPusher/26c6815dccc57bd60b93bffcda15dbfe7229d0e2/HIK_EHome/eh_lib/libiconv2.so -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HIKPusher 2 | > * 这是一个基于海康威视EHome SDK(v4.0)的实时推流工具,它能够对支持EHome SDK(v4.0)平台的IPC设备或者NVR设备的原始RTP流(海康私有RTP协议)进行协议转化,变为RTMP协议流,并推送到RTMP流媒体服务器,而后使用基于Flash插件的播放器进行网页端实时播放,从而最终实现Web端实时视频监控。 3 | > * 参考了CSDN上[@雷霄骅](https://blog.csdn.net/leixiaohua1020)的部分博客,在此向雷神致敬! 4 | > * 这也是我硕士课题的一部分,目前已经测试通过投入正式运行的环境是: 5 | > * **IPC型号:** DS-2CD2T25FD-I3W/R 6 | > * **云服务器规格:** 阿里云ECS(Ubuntu 16.04 LTS 64位) 7 | > * **Web端播放器:** JW Player 8 | > * **RTMP流媒体服务器:** nginx-rtmp-module 9 | > * **Web服务器:** Nginx 10 | > * 部分型号的NVR已经通过测试,能否稳定运行还需要进一步测试。 11 | > * 部署和预览请求协议注意点已经在下面[deploy tips](https://github.com/CharlesPu/HIKPusher#deploy-tips)和[REQ_SRV protocol](https://github.com/CharlesPu/HIKPusher#req_srv-protocol)列出。 12 | > * 附上本人硕士毕业拙文作为参考 13 | > * [基于实时推流工具的风机叶片测试过程视频监控[J]](http://kns.cnki.net/KCMS/detail/detail.aspx?dbcode=CJFQ&dbname=CJFDPREP&filename=GXJX201811029&uid=WEEvREcwSlJHSldRa1FhdXNXaEd1ZDNHQUsvSU1NNWp6d1JCWGJZOEZWdz0=$9A4hF_YAuvQ5obgVAqNKPCYcEjKensW4IQMovwHtwkF4VYPoHbKxJw!!&v=MjM4MjJYQmRyRzRIOW5Ocm85SGJZUjhlWDFMdXhZUzdEaDFUM3FUcldNMUZyQ1VSTE9mWnVkbkZ5em1WcnJOSWo=) 14 | > * 风机叶片测试远程监控系统[D] 15 | > * 由于本人水平有限,也希望大家指出我的不足,多提提意见,一起来完善这个项目,实现大家想要的功能。>_< 16 | 17 | --- 18 | A push kit of RTMP based on HikVision's EHome SDK(v4.0) that can accept the registration of HIK's IPCs and push streaming to RTMP server. 19 | Once there is a preview request, this kit can collect the streaming and transform the private RTP into RTMP, and then push it to any RTMP server, such as Red5 or nginx-rtmp module. Hence the real time monitoring. 20 | 21 | --- 22 | ## software framework 23 | ____________________________________ 24 | requests | |========>>>>=======+ 25 | from web ============>| REQ_SRV ============> CMS | preview request | 26 | socket | | | 27 | |------------------------------------| IPCs 28 | streaming server | | | 29 | (nginx-rtmp, ...) <============| librtmp <== conversion <== VTDU |========<<<<=======+ 30 | RTMP |------------------------------------| RTP stream 31 | stream | record, ... | 32 | |____________________________________| 33 | ## deploy tips 34 | It very strange that the link tool--ldd still can't find the **libhpr.so** dynamic library even if I use **-L(hik_ehomelib_path)** and **-l(hik_ehomelib_name)** in makefile. 35 | So you need to add **hik_ehomelib_path** into **/etc/profile** to make the executable program can be created successfully. 36 | > export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:(your_path)/HIKPusher/HIK_EHome/eh_lib/ 37 | 38 | ## REQ_SRV protocol 39 | The request from web in the form of socket is now following the format: 40 | > "start:IPCS00000x0x" 41 | 42 | so you need to set the EHome account of HikVision IPC with the format of **"IPCS00000x0x"**, and the first 'x' refers to location, the second one refers to number in this location in order to distinguish every IPC. 43 | 44 | The settings above is mine, and you can also set your own protocol, which must change the function **IPCS_GetInt_Devid()** in **ipc/ipcs.c** so as to parse out correct IPC dev_id(EHome account). 45 | 46 | --- 47 | ## VERSIONS 48 | 49 | ##### date: 2018-07-15 50 | ##### version: v1.0 51 | ##### description: 52 | * Finish the decoding of private RTP to H264 streaming. 53 | * Finish the encoding of H264 streaming to RTMP. 54 | * Combine the dec-enc and HIK's EHome SDK. 55 | * Add a server that used to listen and accept the preview requests. Use heart beat packet to collect the requests. 56 | * Add "ipcs.c", use the global array variable "IPCs[]" to storage every ipc's infos: login_id, dev_id, push rtmp handle, etc. 57 | 58 | --- 59 | ##### date: 2018-07-16 60 | ##### version: v1.0.2 61 | ##### description: 62 | * Add the signal handler function of signal "ctrl + c", hence the release of all memory resources such as req_srv buf and ipc's push buf when use "ctrl + c" to exit the main function. As a result, some variables has changed to global ones due to the reference in signal handler function. 63 | 64 | --- 65 | ##### date: 2018-07-17 66 | ##### version: v1.0.4 67 | ##### description: 68 | * Change every ipc's rtmp url, the end of url is dev_id. 69 | * Change the rtmp ip macro to two: "0.0.0.0" and public net ip. 70 | * Fix the bug when free ipc's push resources. 71 | * Change the project name(from "eh_rtmp_demo" to "HIKPusher"). 72 | 73 | --- 74 | ##### date: 2018-07-21 75 | ##### version: v1.2 76 | ##### description: 77 | * **Add each ipc's info: metadata, send flag, tick, etc. when send h264, so as to distinguish different ipcs.** And modify each ipc's push_free function. 78 | * Because of the loop contains between h264-rtmp.h and ipcs.h, move the definition of RTMPMetadata to ipcs.h. 79 | 80 | --- 81 | ##### date: 2018-08-18 82 | ##### version: v1.4 83 | ##### description: 84 | * Change the directions of the project. 85 | * Add the record module(./record) of the project, hence the log files which can record the problems when running. 86 | 87 | --- 88 | ##### date: 2018-09-13 89 | ##### version: v1.4.2 90 | ##### description: 91 | * Change the macro name of ipc's states. 92 | * Fix some bugs about the judgements of ipc's states. 93 | 94 | --- 95 | ##### date: 2018-09-14 96 | ##### version: v1.4.4 97 | ##### description: 98 | * Change the file name of ps/h264 parser and some function name in 'conv' to look more clear. 99 | * Change the **struct _ipc**, remove 'm_pFileBuf' because its duplication with 'full_h264pack'. 100 | 101 | --- 102 | ##### date: 2018-09-16 103 | ##### version: v1.4.6 104 | ##### description: 105 | * Change some functions in parser_h264.c, especially **H264_SendToRtmp**, to make it more simple. 106 | * Change the return value of functions in parser_ps.c. 107 | * Simplify many functions and data structures in the whole project. 108 | 109 | --- 110 | ##### date: 2018-09-20 111 | ##### version: v1.4.8 112 | ##### description: 113 | * Change log.c, divide logs into different types--INFO, WARN, ERROR, DEBUG. 114 | * Change the format of record: [INFO/WARN/ERROR/DEBUG time]\([error_num]\) \\ content 115 | * Fix some mutex bugs when save log files. 116 | 117 | --- 118 | ##### date: 2019-01-18 119 | ##### version: v2.0.0 120 | ##### description: 121 | * Due to the truncation of PS packs during transmission, use two parse buffer: **pespack_buf** and **h264pack_buf** in struct \_ipc to storage a complete pes pack or h264 pack for the following parse. 122 | * Clarify the parse process into two parser: **PS_Parser** and **H264_Parser**, and make them a chain. 123 | * May be used in different kinds of HIK devices... -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H__ 2 | #define __CONFIG_H__ 3 | 4 | /*DEBUG*/ 5 | // #define PRINT_H264_NALU_RD 6 | #define PRINT_RTMP_SEND_SIZE 7 | // #define PRINT_REQ_RECV_RAW 8 | // #define PRINT_REQ_LINK 9 | 10 | /**RTMP**/ 11 | #define RTMP_URL "rtmp://localhost:1935/blade_test/" 12 | #define RTMP_CONNECTION_TIMEOUT 5 //s 13 | #define RTMP_SEND_INTVL 20 //ms 14 | 15 | /*H264*/ 16 | #define PESPACK_BUF_MAX_SIZE 262144 17 | #define H264PACK_BUF_MAX_SIZE 262144 18 | /*******************************************************/ 19 | /*NET_ESTREAM*/ 20 | #define NET_ESTREAM_IP "0.0.0.0" 21 | #define NET_ESTREAM_PUBLIC_IP "x.x.x.x" 22 | #define NET_ESTREAM_PORT 8003 23 | /*NET_ECMS*/ 24 | #define NET_ECMS_PORT 7660 25 | 26 | //0- TCP方式,1- UDP方式 27 | #define LINK_MODE_TCP 0 28 | #define LINK_MODE_UDP 1 29 | //码流类型:0- 主码流,1- 子码流, 2- 第三码流 30 | #define STREAM_TYPE_MAIN 0 31 | #define STREAM_TYPE_SUB 1 32 | #define STREAM_TYPE_THIRD 2 33 | //通道号 34 | #define CHANNEL_ID 1 35 | 36 | /*request listen server*/ 37 | #define REQ_SRV_PORT 9001 38 | #define REQ_SRV_CLIE_MAX_NUM 10 39 | #define REQ_SRV_BUF_LEN 1024 40 | 41 | /*IPCS*/ 42 | #define IPCS_MAX_NUM 4096 43 | #define IPCS_EPOLL_WAIT_TIME 5000 //ms 44 | #define IPCS_HEARTBEAT_INVL 4000000 //us // 4s cause the delay of the internet 45 | //states 46 | #define IPCS_PUSHING_STREAM 1 47 | #define IPCS_NOT_PUSHING_STREAM 0 48 | #define IPCS_ONLINE 1 49 | #define IPCS_OFFLINE 0 50 | 51 | /*log*/ 52 | // #define LOG_SAVE 53 | #define LOG_CONTENT_MAX_SIZE 256 54 | #define LOG_OUT_PATH "./logs/" 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /conv/parser_h264.c: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-06-24 4 | @@Mail : pu17rui@sina.com 5 | @@Description: 6 | *******************************/ 7 | #include 8 | #include 9 | #include 10 | #include "config.h" 11 | #include "parser_h264.h" 12 | #include "rtmp_log.h" 13 | #include "rtmp_sys.h" 14 | #include "amf.h" 15 | #include "sps_dec.h" 16 | #include "log.h" 17 | 18 | /****************************** 19 | ** 第二链:H264解析器 20 | ** 传入为PES包荷载的完整数据 21 | ** 处理时,利用链缓冲区h264pack_buf来拼接残余项,因为可识别程度 22 | 不如第一链(只能通过下一个NALU的头来截断,而不是NALU长度) 23 | ** 链缓冲区h264pack_buf用来缓冲残缺的n个NALU,始终会留下一个NALU(可能残缺) 24 | ******************************/ 25 | int H264_Parser(struct _ipc *ipc, const char *pes_payload, int pes_payload_len) 26 | { 27 | int len_tmp = ipc->h264pack_buf_len + pes_payload_len; 28 | if ( len_tmp > H264PACK_BUF_MAX_SIZE) 29 | { 30 | LOG_WARN("H264 buf overflow!"); 31 | return 1; 32 | } 33 | char *buf_tmp = ipc->h264pack_buf; 34 | //这里复制到链缓冲区处理是因为残余项到来时,不像第一链可以根据变量判断,故和之前的拼接起来再集中处理最方便 35 | memcpy(buf_tmp + ipc->h264pack_buf_len, pes_payload, pes_payload_len); 36 | int head = 0, posi = 0; 37 | for (; posi < len_tmp - 3; ++posi) 38 | { 39 | if (buf_tmp[posi] == 0x00 40 | && buf_tmp[posi + 1] == 0x00 41 | && (buf_tmp[posi + 2] == 0x01 42 | || (buf_tmp[posi + 2] == 0x00 43 | && buf_tmp[posi + 3] == 0x01)))//界定符 44 | { 45 | NalUnit nalUnit; 46 | int tmp = H264_ParserNALU(&nalUnit, buf_tmp + head, posi - head); 47 | if (!tmp)//得到一个nalu就发送 48 | H264_SendToRtmp(ipc, &nalUnit); 49 | //解析失败说明posi之前没有nalu或者是错误的nalu,则直接丢弃 50 | head = posi;//head指向下一个nalu的开始 51 | }else 52 | { 53 | 54 | } 55 | } 56 | //把剩余的复制到buf中去 57 | int len_left = len_tmp - head; 58 | memmove(buf_tmp, buf_tmp + head, len_left); 59 | memset(buf_tmp + len_left, 0, H264PACK_BUF_MAX_SIZE - len_left); 60 | ipc->h264pack_buf_len = len_left;//更新buf缓冲大小 61 | 62 | return 0; 63 | } 64 | 65 | int H264_ParserNALU(NalUnit* nalu, char *nalu_buf, int nalus_buf_len) 66 | { 67 | int nalustart = 0;//nal的开始标识符是几个00 68 | if (nalus_buf_len < 4) return 1; 69 | nalu->data = NULL; 70 | #ifdef PRINT_H264_NALU_RD 71 | printf("read_first_nalu: "); 72 | for (int i = 0; i < 10; ++i) 73 | printf("0x%02x ", nalu_buf[i]); 74 | printf("\n"); 75 | #endif 76 | //search for nal header 00 00 01 or 00 00 00 01 77 | if ( nalu_buf[0] == 0x00 78 | && nalu_buf[1] == 0x00) 79 | { 80 | if (nalu_buf[2] == 0x01) 81 | nalustart = 3; 82 | else 83 | if ( nalu_buf[2] == 0x00 84 | && nalu_buf[3] == 0x01) 85 | nalustart = 4; 86 | else 87 | return 2; 88 | }else 89 | return 3; 90 | 91 | nalu->type = nalu_buf[nalustart] & 0x1f; 92 | nalu->data = nalu_buf + nalustart; 93 | nalu->size = nalus_buf_len - nalustart; 94 | 95 | return 0; 96 | } 97 | 98 | int H264_SendToRtmp(struct _ipc* ipc, const NalUnit* nalu) 99 | { 100 | switch(nalu->type) 101 | { 102 | case NALU_TYPE_SPS: 103 | { 104 | ipc->metaData.nSpsLen = nalu->size; 105 | if (ipc->metaData.Sps == NULL) 106 | ipc->metaData.Sps = (unsigned char*)malloc(nalu->size); 107 | memcpy(ipc->metaData.Sps, nalu->data, nalu->size); 108 | break; 109 | } 110 | case NALU_TYPE_PPS: 111 | { 112 | ipc->metaData.nPpsLen = nalu->size; 113 | if (ipc->metaData.Pps == NULL) 114 | ipc->metaData.Pps = (unsigned char*)malloc(nalu->size); 115 | memcpy(ipc->metaData.Pps, nalu->data, nalu->size); 116 | // 解码SPS PPS,获取视频图像宽、高信息 117 | int width = 0, height = 0, fps = 0; 118 | H264_DecodeSPS(ipc->metaData.Sps, ipc->metaData.nSpsLen, &width, &height, &fps); 119 | //ipc->metaData.nWidth = width; 120 | //ipc->metaData.nHeight = height; 121 | if(fps) 122 | ipc->metaData.nFrameRate = fps; 123 | else 124 | ipc->metaData.nFrameRate = 25; 125 | ipc->tick_gap = 1000 / ipc->metaData.nFrameRate; 126 | break; 127 | } 128 | default: 129 | { 130 | int bKeyframe = (nalu->type == NALU_TYPE_IDR) ? TRUE : FALSE; // key frame 131 | H264_SendH264Packet(nalu->data, nalu->size, bKeyframe, ipc->tick, ipc); 132 | #ifdef PRINT_RTMP_SEND_SIZE 133 | LOG_INFO("%s NALU size:%8d\n", ipc->dev_id, nalu->size); 134 | #endif 135 | ipc->tick += ipc->tick_gap; 136 | msleep(RTMP_SEND_INTVL); 137 | break; 138 | } 139 | } 140 | 141 | return 0; 142 | } 143 | 144 | /************************************************* 145 | @Description: 发送H264数据帧 146 | @Input: data 存储数据帧内容 size 数据帧的大小 bIsKeyFrame 记录该帧是否为关键帧 nTimeStamp 当前帧的时间戳 147 | @Output: 148 | @Return: 0 - success, others - fail 149 | @Others: 150 | *************************************************/ 151 | int H264_SendH264Packet(char *data, unsigned int size, int bIsKeyFrame, unsigned int nTimeStamp, struct _ipc* ipc) 152 | { 153 | if(data == NULL && size < 11){ 154 | return -1; 155 | } 156 | char *body = (char*)malloc(size + 9); 157 | memset(body, 0, size + 9); 158 | int i = 0; 159 | if(bIsKeyFrame){ 160 | body[i++] = 0x17;// 1:Iframe 7:AVC 161 | body[i++] = 0x01;// AVC NALU_TYPE_AUDU 162 | body[i++] = 0x00; 163 | body[i++] = 0x00; 164 | body[i++] = 0x00; 165 | // NALU size 166 | body[i++] = size>>24 & 0xff; 167 | body[i++] = size>>16 & 0xff; 168 | body[i++] = size>>8 & 0xff; 169 | body[i++] = size & 0xff; 170 | // NALU data 171 | memcpy(&(body[i]), data, size); 172 | H264_SendVideoSpsPps(ipc->rtmp, ipc->metaData.Pps, ipc->metaData.nPpsLen, ipc->metaData.Sps, ipc->metaData.nSpsLen, nTimeStamp); 173 | msleep(RTMP_SEND_INTVL); 174 | }else{ 175 | body[i++] = 0x27;// 2:Pframe 7:AVC 176 | body[i++] = 0x01;// AVC NALU 177 | body[i++] = 0x00; 178 | body[i++] = 0x00; 179 | body[i++] = 0x00; 180 | // NALU size 181 | body[i++] = size>>24 & 0xff; 182 | body[i++] = size>>16 & 0xff; 183 | body[i++] = size>>8 & 0xff; 184 | body[i++] = size & 0xff; 185 | // NALU data 186 | memcpy(&(body[i]), data, size); 187 | } 188 | 189 | int bRet = H264_SendPacket(ipc->rtmp, RTMP_PACKET_TYPE_VIDEO, body, i + size, nTimeStamp); 190 | if (body != NULL) 191 | { 192 | free(body); 193 | body = NULL; 194 | } 195 | 196 | return bRet; 197 | } 198 | /************************************************* 199 | @Description: 发送视频的sps和pps信息 200 | @Input: pps 存储视频的pps信息 pps_len 视频的pps信息长度 sps 存储视频的pps信息 sps_len 视频的sps信息长度 201 | @Output: 202 | @Return: 0 - fail 203 | @Others: 204 | *************************************************/ 205 | int H264_SendVideoSpsPps(RTMP *rtmp, unsigned char *pps, int pps_len, unsigned char * sps, int sps_len, unsigned int nTimestamp) 206 | { 207 | RTMPPacket * packet = NULL;//rtmp包结构 208 | unsigned char * body = NULL; 209 | 210 | packet = (RTMPPacket *)malloc(sizeof(RTMPPacket)); 211 | RTMPPacket_Alloc(packet, 32766); 212 | RTMPPacket_Reset(packet); 213 | 214 | body = (unsigned char *)packet->m_body; 215 | int i = 0; 216 | body[i++] = 0x17; 217 | body[i++] = 0x00; 218 | 219 | body[i++] = 0x00; 220 | body[i++] = 0x00; 221 | body[i++] = 0x00; 222 | 223 | /*AVCDecoderConfigurationRecord*/ 224 | body[i++] = 0x01; 225 | body[i++] = sps[1]; 226 | body[i++] = sps[2]; 227 | body[i++] = sps[3]; 228 | body[i++] = 0xff; 229 | 230 | /*sps*/ 231 | body[i++] = 0xe1; 232 | body[i++] = (sps_len >> 8) & 0xff; 233 | body[i++] = sps_len & 0xff; 234 | memcpy(&(body[i]), sps, sps_len); 235 | i += sps_len; 236 | 237 | /*pps*/ 238 | body[i++] = 0x01; 239 | body[i++] = (pps_len >> 8) & 0xff; 240 | body[i++] = (pps_len) & 0xff; 241 | memcpy(&(body[i]), pps, pps_len); 242 | i += pps_len; 243 | 244 | packet->m_packetType = RTMP_PACKET_TYPE_VIDEO; 245 | packet->m_nBodySize = i; 246 | packet->m_nChannel = 0x04; 247 | packet->m_nTimeStamp = nTimestamp; 248 | packet->m_hasAbsTimestamp = 0; 249 | packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM; 250 | packet->m_nInfoField2 = rtmp->m_stream_id; 251 | /*调用发送接口*/ 252 | int nRet = RTMP_SendPacket(rtmp, packet, TRUE); 253 | if (!nRet) 254 | { 255 | LOG_ERROR(ERR_RTMP_SEND, "RTMP Send Error\n"); 256 | // RTMP_Log(RTMP_LOGERROR,"Send Error\n"); 257 | } 258 | if (packet != NULL) 259 | { 260 | RTMPPacket_Free(packet); 261 | free(packet); 262 | packet = NULL; 263 | } 264 | 265 | return nRet; 266 | } 267 | /************************************************* 268 | @Description: 发送RTMP数据包 269 | @Input: nPacketType 数据类型 data 存储数据内容 size 数据大小 nTimestamp 当前包的时间戳 270 | @Output: 271 | @Return: 成功则返回 1 , 失败则返回一个小于0的数 272 | @Others: 273 | *************************************************/ 274 | int H264_SendPacket(RTMP *rtmp, unsigned int nPacketType,char *data,unsigned int size,unsigned int nTimestamp) 275 | { 276 | RTMPPacket* packet; 277 | /*分配包内存和初始化,len为包体长度*/ 278 | packet = (RTMPPacket *)malloc(sizeof(RTMPPacket)); 279 | RTMPPacket_Alloc(packet, size); //actully alloc "body" 280 | RTMPPacket_Reset(packet); 281 | /*包体内存*/ 282 | memcpy(packet->m_body, data, size); 283 | packet->m_nBodySize = size; 284 | packet->m_hasAbsTimestamp = 0; 285 | packet->m_packetType = nPacketType; /*此处为类型有两种一种是音频,一种是视频*/ 286 | packet->m_nInfoField2 = rtmp->m_stream_id; 287 | packet->m_nChannel = 0x04; 288 | packet->m_headerType = RTMP_PACKET_SIZE_LARGE; 289 | packet->m_nTimeStamp = nTimestamp; 290 | if (RTMP_PACKET_TYPE_AUDIO == nPacketType && size !=4) 291 | { 292 | packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM; 293 | } 294 | /*发送*/ 295 | int nRet =0; 296 | if (RTMP_IsConnected(rtmp)) 297 | { 298 | nRet = RTMP_SendPacket(rtmp, packet, TRUE); /*TRUE为放进发送队列,FALSE是不放进发送队列,直接发送*/ 299 | } 300 | /*释放内存, carefull that RTMPPacket_Free-free body, free-free packet mem*/ 301 | if (packet != NULL) 302 | { 303 | RTMPPacket_Free(packet); 304 | free(packet); 305 | packet = NULL; 306 | } 307 | 308 | return nRet; 309 | } 310 | -------------------------------------------------------------------------------- /conv/parser_h264.h: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-06-05 4 | @@Mail : pu17rui@sina.com 5 | @@Description: 6 | *******************************/ 7 | #ifndef __PARSER_H264_H__ 8 | #define __PARSER_H264_H__ 9 | 10 | #include "rtmp_sys.h" 11 | #include "ipcs.h" 12 | 13 | #define NALU_TYPE_SLICE 0x01 14 | #define NALU_TYPE_DPA 0x02 15 | #define NALU_TYPE_DPB 0x03 16 | #define NALU_TYPE_DPC 0x04 17 | #define NALU_TYPE_IDR 0x05 18 | #define NALU_TYPE_SEI 0x06 19 | #define NALU_TYPE_SPS 0x07 20 | #define NALU_TYPE_PPS 0x08 21 | #define NALU_TYPE_AUD 0x09 22 | #define NALU_TYPE_EOSEQ 0x0a 23 | #define NALU_TYPE_EOSTREAM 0x0b 24 | #define NALU_TYPE_FILL 0x0c 25 | 26 | typedef struct 27 | { 28 | int type; 29 | int size; 30 | char *data; 31 | }NalUnit; 32 | 33 | int H264_Parser(struct _ipc *i, const char *pack, int len); 34 | int H264_ParserNALU(NalUnit* nalu, char *buf, int length); 35 | int H264_SendToRtmp(struct _ipc* , const NalUnit* nalu); 36 | 37 | int H264_SendH264Packet(char *data, unsigned int size, int bIsKeyFrame, unsigned int nTimeStamp, struct _ipc*); 38 | int H264_SendVideoSpsPps(RTMP *rtmp, unsigned char *pps, int pps_len, unsigned char * sps, int sps_len, unsigned int nTimeStamp); 39 | int H264_SendPacket(RTMP *rtmp, unsigned int nPacketType,char *data,unsigned int size,unsigned int nTimestamp); 40 | 41 | #endif -------------------------------------------------------------------------------- /conv/parser_ps.c: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-12-27 4 | @@Mail : pu17rui@sina.com 5 | @@Description: 6 | *******************************/ 7 | #include 8 | #include 9 | #include 10 | #include "parser_ps.h" 11 | #include "parser_h264.h" 12 | #include "config.h" 13 | 14 | /****************************** 15 | ** 第一链:PS解析器 16 | ** 传入为RTP原始数据流 17 | ** 处理后传出为一个完整的PES包荷载数据,这个荷载数据实际为n(n>1)个NALU,可能是断的, 18 | 但是第一链只保证PES荷载数据的完整性,而不保证内容含义的完整性,所以需要第二链 19 | 自行保证n个NALU的截断和拼接 20 | ** 链缓冲区pespack_buf用来缓冲残缺的PES荷载数据,直到得到完整的一个为止 21 | ******************************/ 22 | int PS_Parser(struct _ipc *ipc, char *rtp_pack, int length) 23 | { 24 | /***************************************残余项解析任务 开始***************************************/ 25 | //残余项长度由PES包头中长度字段得知 26 | //由于其它历史遗留信息的存在,接下来的判断过程只需根据pespack_left_len成员判断即可 27 | if (ipc->pespack_left_len) //如有残余长度存在,则直接尝试拼接剩下的 28 | { 29 | int real_cp_len = ipc->pespack_left_len > length ? length : ipc->pespack_left_len;//取小值 30 | memcpy(ipc->pespack_buf + ipc->pespack_buf_len, rtp_pack, real_cp_len); 31 | ipc->pespack_left_len -= real_cp_len; 32 | ipc->pespack_buf_len += real_cp_len; 33 | length -= real_cp_len; 34 | rtp_pack += real_cp_len; 35 | 36 | if (!(ipc->pespack_left_len))//若拼接后发现已经得到了一个完整的PES荷载数据,则直接送入下一链 37 | { 38 | H264_Parser(ipc, ipc->pespack_buf, ipc->pespack_buf_len); 39 | memset(ipc->pespack_buf, 0, PESPACK_BUF_MAX_SIZE); 40 | ipc->pespack_buf_len = 0; 41 | }//若还是没得到完整的,说明还是有残余项,后面还是要进入此代码 42 | } 43 | /************************************残余项解析任务 结束******************************************/ 44 | 45 | //处理完上一次的残余项之后正式开始后续PES解析 46 | int left_len = length; 47 | char *next_posi = rtp_pack; 48 | char *PayloadData = NULL; 49 | int PayloadDataLen = 0; 50 | while(left_len >= 4) // >= sizeof(PS_EACH_PACKET_START) 51 | { 52 | if(next_posi 53 | && next_posi[0] == '\x00' 54 | && next_posi[1] == '\x00' 55 | && next_posi[2] == '\x01') 56 | { 57 | switch (next_posi[3]) 58 | { 59 | case '\xBA': 60 | if(PS_ParserHeadPacket(&next_posi, &left_len)) 61 | return 1; 62 | break; 63 | case '\xBC': 64 | if(PS_ParserMapPacket(&next_posi, &left_len, &PayloadData, &PayloadDataLen)) 65 | return 2; 66 | break; 67 | case '\xE0': 68 | if(!PS_ParserPESPacket(&next_posi, &left_len, &PayloadData, &PayloadDataLen)) 69 | { 70 | if (left_len < 0)//如果断了,则存储已有数据,后续需要交由 残余项解析任务 完成 71 | { 72 | ipc->pespack_left_len = -left_len; 73 | int real_cp_len = PayloadDataLen - (-left_len); 74 | memcpy(ipc->pespack_buf + ipc->pespack_buf_len, PayloadData, real_cp_len); 75 | ipc->pespack_buf_len += real_cp_len; 76 | }else//最完美的情况下是没断,则直接得到一个完整的PES荷载数据,直接送入下一链 77 | { 78 | H264_Parser(ipc, PayloadData, PayloadDataLen); 79 | ipc->pespack_left_len = 0; 80 | memset(ipc->pespack_buf, 0, PESPACK_BUF_MAX_SIZE); 81 | ipc->pespack_buf_len = 0; 82 | } 83 | } 84 | else //payload之前就断了,那么直接放弃此包 85 | return 3; 86 | break; 87 | default: 88 | next_posi++;//往后走 89 | left_len--; 90 | break; 91 | } 92 | } 93 | else //如果啥都不是 94 | { 95 | next_posi++;//往后走 96 | left_len--; 97 | } 98 | } 99 | 100 | return 0; 101 | } 102 | 103 | /************************************************* 104 | @Description: 处理PS流的包头 105 | @Input: Pack-流起始位置和处理完之后指向的包的位置 length-流目前长度和处理完之后包剩下的长度 106 | @Output: 107 | @Return: 0 - success, else - fail 108 | @Others: 109 | *************************************************/ 110 | int PS_ParserHeadPacket(char** Pack, int *length) 111 | { 112 | #ifdef PS_PRINT_HEAD_PACK_HEADER 113 | printf("[%s]now :%02x %02x %02x %02x\n", __FUNCTION__, 114 | (unsigned char)(*Pack)[0], (unsigned char)(*Pack)[1], (unsigned char)(*Pack)[2], (unsigned char)(*Pack)[3]); 115 | #endif 116 | //通过 00 00 01 ba头的第14个字节的最后3位来确定头部填充了多少字节 117 | PS_HEAD_PACKET_HEADER *PS_head_pack = (PS_HEAD_PACKET_HEADER *) (*Pack); 118 | unsigned char pack_stuffing_length = PS_head_pack->stuffing_len & '\x07'; 119 | 120 | *length = (*length) - sizeof(PS_HEAD_PACKET_HEADER) - pack_stuffing_length;//减去头和填充的字节 121 | *Pack = (*Pack) + sizeof(PS_HEAD_PACKET_HEADER) + pack_stuffing_length; 122 | 123 | #ifdef PS_PRINT_HEAD_PACK_HEADER 124 | printf("[%s]leftlen:%d\n", __FUNCTION__, *length); 125 | if(*length > 0) 126 | printf("[%s]next:%02x %02x %02x %02x\n", __FUNCTION__, 127 | (unsigned char)(*Pack)[0], (unsigned char)(*Pack)[1], (unsigned char)(*Pack)[2], (unsigned char)(*Pack)[3]); 128 | #endif 129 | return 0; 130 | } 131 | 132 | /************************************************* 133 | @Description: 处理PS流的映射流包头 134 | @Input: Pack-流起始位置和处理完之后指向的包的位置 length-流目前长度和处理完之后包剩下的长度 135 | @Output: 136 | @Return: 0 - success, else - fail 137 | @Others: 138 | *************************************************/ 139 | int PS_ParserMapPacket(char** Pack, int* length, char **PayloadData, int *PayloadDataLen) 140 | { 141 | #ifdef PS_PRINT_MAP_PACK_HEADER 142 | printf("[%s]now :%02x %02x %02x %02x\n", __FUNCTION__, 143 | (unsigned char)(*Pack)[0], (unsigned char)(*Pack)[1], (unsigned char)(*Pack)[2], (unsigned char)(*Pack)[3]); 144 | #endif 145 | PS_MAP_PACKET_HEADER* PSM_pack = (PS_MAP_PACKET_HEADER*) (*Pack); 146 | 147 | //no payload 148 | *PayloadData = 0; 149 | *PayloadDataLen = 0; 150 | 151 | if((unsigned int)(*length) < sizeof(PS_MAP_PACKET_HEADER)) return 1; 152 | 153 | PS_2BYTES_LENGTH data_length; 154 | data_length.byte[0] = PSM_pack->pack_len.byte[1]; 155 | data_length.byte[1] = PSM_pack->pack_len.byte[0]; 156 | 157 | *length = (*length) - data_length.length - sizeof(PS_MAP_PACKET_HEADER); 158 | *Pack = (*Pack) + data_length.length + sizeof(PS_MAP_PACKET_HEADER); 159 | #ifdef PS_PRINT_MAP_PACK_HEADER 160 | printf("[%s]leftlen:%d\n", __FUNCTION__, *length); 161 | if(*length > 0) 162 | printf("[%s]next:%02x %02x %02x %02x\n", __FUNCTION__, 163 | (unsigned char)(*Pack)[0], (unsigned char)(*Pack)[1], (unsigned char)(*Pack)[2], (unsigned char)(*Pack)[3]); 164 | #endif 165 | return 0; 166 | } 167 | 168 | /************************************************* 169 | @Description: 处理PES包头 170 | @Input: Pack-流起始位置和处理完之后指向的包的位置 length-流目前长度和处理完之后包剩下的长度 171 | PayloadData-h264裸流的指向位置 PayloadDataLen-h264裸流的长度 172 | @Output: 173 | @Return: 0 - success, else - fail 174 | @Others: 所有传入传出参数都为指针,并不会分配新的内存空间!内存空间存在于函数之外 175 | *************************************************/ 176 | int PS_ParserPESPacket(char** Pack, int *length, char **PayloadData, int *PayloadDataLen) 177 | { 178 | #ifdef PS_PRINT_PES_PACK_HEADER 179 | printf("[%s]now :%02x %02x %02x %02x\n", __FUNCTION__, 180 | (unsigned char)(*Pack)[0], (unsigned char)(*Pack)[1], (unsigned char)(*Pack)[2], (unsigned char)(*Pack)[3]); 181 | #endif 182 | PES_PACKET_HEADER* PES_pack = (PES_PACKET_HEADER*) (*Pack); 183 | //初始化清空!! 184 | *PayloadData = NULL; 185 | *PayloadDataLen = 0; 186 | 187 | if(((*length) > 0 ? (*length) : -(*length)) < sizeof(PES_PACKET_HEADER) - 1) return 1; //包头9个字节断了 188 | 189 | PS_2BYTES_LENGTH data_length; 190 | data_length.byte[0] = PES_pack->pack_len.byte[1]; 191 | data_length.byte[1] = PES_pack->pack_len.byte[0]; 192 | 193 | *PayloadDataLen = data_length.length - 2 - 1 - PES_pack->stuffing_len; 194 | int header_len = 9 + PES_pack->stuffing_len; 195 | if(*PayloadDataLen > 0) //只需指向位置,内存空间已经在外面分配了!! 196 | *PayloadData = (*Pack) + header_len; 197 | if (((*length) > 0 ? (*length) : -(*length)) < header_len) return 2; //附加长度断了 198 | 199 | *length = (*length) - (header_len + *PayloadDataLen); 200 | *Pack = (*Pack) + (header_len + *PayloadDataLen); 201 | 202 | #ifdef PS_PRINT_PES_PACK_HEADER 203 | printf("[%s]payloadlen:%d, leftlen:%d\n", __FUNCTION__, *PayloadDataLen, *length); 204 | if(*length > 0) 205 | printf("[%s]next:%02x %02x %02x %02x\n", __FUNCTION__, 206 | (unsigned char)(*Pack)[0], (unsigned char)(*Pack)[1], (unsigned char)(*Pack)[2], (unsigned char)(*Pack)[3]); 207 | #endif 208 | return 0; 209 | } -------------------------------------------------------------------------------- /conv/parser_ps.h: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-06-05 4 | @@Mail : pu17rui@sina.com 5 | @@Description: 6 | *******************************/ 7 | #ifndef __PARSER_PS_H__ 8 | #define __PARSER_PS_H__ 9 | #include "ipcs.h" 10 | 11 | typedef union //后面要注意大端存放 12 | { 13 | unsigned short int length; 14 | unsigned char byte[2]; 15 | }PS_2BYTES_LENGTH; 16 | //每个PS包的起始码 17 | typedef struct 18 | { 19 | unsigned char start_code[3]; // start_code :00 00 01 20 | unsigned char stream_id[1]; // 流标识 :ba/bb/bc/e0 21 | }PS_EACH_PACKET_START; 22 | //PS包头的起始码 23 | typedef struct 24 | { 25 | PS_EACH_PACKET_START pack_start;// 4个字节的包头起始码 26 | unsigned char buf[9]; //包头不重要的9个字节 27 | unsigned char stuffing_len; //扩展字节长度 28 | }PS_HEAD_PACKET_HEADER; 29 | //映射流包头 30 | typedef struct 31 | { 32 | PS_EACH_PACKET_START pack_start; 33 | PS_2BYTES_LENGTH pack_len; //we must do exchange 34 | }PS_MAP_PACKET_HEADER; 35 | //PES包头,注意长度是uint两字节对齐!!因为PS_2BYTES_LENGTH中uint的存在!!!所以stuffing_len占2字节! 36 | typedef struct 37 | { 38 | PS_EACH_PACKET_START pack_start; 39 | PS_2BYTES_LENGTH pack_len;//we must do exchange 40 | unsigned char pack_info[2]; // 8c xx 41 | unsigned char stuffing_len; //包头中扩展的长度,实际占2字节 42 | }PES_PACKET_HEADER; 43 | 44 | int PS_ParserHeadPacket(char** Pack, int *length); 45 | int PS_ParserMapPacket(char** Pack, int *length, char **PayloadData, int *PayloadDataLen); 46 | int PS_ParserPESPacket(char** Pack, int *length, char **PayloadData, int *PayloadDataLen); 47 | int PS_Parser(struct _ipc *i, char *pack, int len); 48 | 49 | #endif -------------------------------------------------------------------------------- /conv/sps_dec.c: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-06-17 4 | @@Mail : pu17rui@sina.com 5 | @@Description: 6 | *******************************/ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "sps_dec.h" 13 | 14 | SPS_UINT Ue(SPS_BYTE *pBuff, SPS_UINT nLen, SPS_UINT* nStartBit) 15 | { 16 | //计算0bit的个数 17 | SPS_UINT nZeroNum = 0; 18 | while ((*nStartBit) < nLen * 8) 19 | { 20 | if (pBuff[(*nStartBit) / 8] & (0x80 >> ((*nStartBit) % 8))) //&:按位与,%取余 21 | { 22 | break; 23 | } 24 | nZeroNum++; 25 | (*nStartBit)++; 26 | } 27 | (*nStartBit)++; 28 | 29 | 30 | //计算结果 31 | SPS_DWORD dwRet = 0; 32 | for (SPS_UINT i = 0; i> ((*nStartBit) % 8))) 36 | { 37 | dwRet += 1; 38 | } 39 | (*nStartBit)++; 40 | } 41 | return (1 << nZeroNum) - 1 + dwRet; 42 | } 43 | 44 | int Se(SPS_BYTE *pBuff, SPS_UINT nLen, SPS_UINT* nStartBit) 45 | { 46 | int UeVal = Ue(pBuff, nLen, nStartBit); 47 | double k = UeVal; 48 | int nValue = ceil(k / 2);//ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00 49 | if (UeVal % 2 == 0) 50 | nValue = -nValue; 51 | return nValue; 52 | } 53 | 54 | SPS_DWORD u(SPS_UINT BitCount, SPS_BYTE * buf, SPS_UINT* nStartBit) 55 | { 56 | SPS_DWORD dwRet = 0; 57 | for (SPS_UINT i = 0; i> ((*nStartBit) % 8))) 61 | { 62 | dwRet += 1; 63 | } 64 | (*nStartBit)++; 65 | } 66 | return dwRet; 67 | } 68 | 69 | /** 70 | * H264的NAL起始码防竞争机制 71 | * 72 | * @param buf SPS数据内容 73 | * 74 | * @无返回值 75 | */ 76 | void de_emulation_prevention(SPS_BYTE* buf, unsigned int buf_size) 77 | { 78 | unsigned int i = 0, j = 0; 79 | SPS_BYTE* tmp_ptr = NULL; 80 | unsigned int tmp_buf_size = 0; 81 | int val = 0; 82 | 83 | tmp_ptr = buf; 84 | tmp_buf_size = buf_size;//printf("%d\n", tmp_buf_size); 85 | for(i = 0; i < (tmp_buf_size - 2); i++) 86 | { 87 | //check for 0x000003 88 | 89 | val = (tmp_ptr[i] ^ 0x00) + (tmp_ptr[i + 1] ^ 0x00) + (tmp_ptr[i + 2] ^ 0x03); 90 | if(val == 0) 91 | { 92 | //kick out 0x03 93 | for(j = i + 2; j < tmp_buf_size - 1; j++) 94 | tmp_ptr[j] = tmp_ptr[j + 1]; 95 | 96 | //and so we should devrease bufsize 97 | buf_size--; 98 | } 99 | } 100 | 101 | return; 102 | } 103 | 104 | /** 105 | * 解码SPS,获取视频图像宽、高信息 106 | * 107 | * @param buf SPS数据内容 108 | * @param nLen SPS数据的长度 109 | * @param width 图像宽度 110 | * @param height 图像高度 111 | 112 | * @成功则返回0 , 失败则返回not 0 113 | */ 114 | int H264_DecodeSPS(SPS_BYTE * buf,unsigned int nLen,int* width, int* height, int* fps) 115 | { 116 | SPS_UINT StartBit=0; 117 | *fps = 0; 118 | de_emulation_prevention(buf, nLen); 119 | 120 | // int forbidden_zero_bit = 121 | u(1, buf, &StartBit); 122 | // int nal_ref_idc = 123 | u(2, buf, &StartBit); 124 | int nal_unit_type = u(5, buf, &StartBit); 125 | if(nal_unit_type == 7) 126 | { 127 | int profile_idc = u(8, buf, &StartBit); 128 | // int constraint_set0_flag = 129 | u(1, buf, &StartBit);//(buf[1] & 0x80)>>7; 130 | // int constraint_set1_flag = 131 | u(1, buf, &StartBit);//(buf[1] & 0x40)>>6; 132 | // int constraint_set2_flag = 133 | u(1, buf, &StartBit);//(buf[1] & 0x20)>>5; 134 | // int constraint_set3_flag = 135 | u(1, buf, &StartBit);//(buf[1] & 0x10)>>4; 136 | // int reserved_zero_4bits = 137 | u(4, buf, &StartBit); 138 | // int level_idc = 139 | u(8, buf, &StartBit); 140 | 141 | // int seq_parameter_set_id = 142 | Ue(buf, nLen, &StartBit); 143 | 144 | if( profile_idc == 100 || profile_idc == 110 || 145 | profile_idc == 122 || profile_idc == 144 ) 146 | { 147 | int chroma_format_idc = Ue(buf, nLen, &StartBit); 148 | if( chroma_format_idc == 3 ) 149 | { 150 | // int residual_colour_transform_flag = 151 | u(1, buf, &StartBit); 152 | } 153 | // int bit_depth_luma_minus8 = 154 | Ue(buf, nLen, &StartBit); 155 | // int bit_depth_chroma_minus8 = 156 | Ue(buf, nLen, &StartBit); 157 | // int qpprime_y_zero_transform_bypass_flag = 158 | u(1, buf, &StartBit); 159 | int seq_scaling_matrix_present_flag = u(1, buf, &StartBit); 160 | 161 | // int seq_scaling_list_present_flag[8] = {0}; 162 | if( seq_scaling_matrix_present_flag ) 163 | { 164 | for( int i = 0; i < 8; i++ ) 165 | { 166 | // seq_scaling_list_present_flag[i] = 167 | u(1, buf, &StartBit); 168 | } 169 | } 170 | } 171 | // int log2_max_frame_num_minus4= 172 | Ue(buf,nLen, &StartBit); 173 | int pic_order_cnt_type=Ue(buf,nLen, &StartBit); 174 | if( pic_order_cnt_type == 0 ) 175 | { 176 | // int log2_max_pic_order_cnt_lsb_minus4= 177 | Ue(buf,nLen, &StartBit); 178 | } 179 | else if( pic_order_cnt_type == 1 ) 180 | { 181 | // int delta_pic_order_always_zero_flag= 182 | u(1,buf, &StartBit); 183 | // int offset_for_non_ref_pic= 184 | Se(buf,nLen, &StartBit); 185 | // int offset_for_top_to_bottom_field= 186 | Se(buf,nLen, &StartBit); 187 | int num_ref_frames_in_pic_order_cnt_cycle=Ue(buf,nLen, &StartBit); 188 | 189 | int *offset_for_ref_frame = (int*)malloc(num_ref_frames_in_pic_order_cnt_cycle); 190 | for( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ ) 191 | offset_for_ref_frame[i] = Se(buf,nLen, &StartBit); 192 | free(offset_for_ref_frame); 193 | } 194 | // int num_ref_frames= 195 | Ue(buf,nLen, &StartBit); 196 | // int gaps_in_frame_num_value_allowed_flag= 197 | u(1,buf, &StartBit); 198 | int pic_width_in_mbs_minus1=Ue(buf,nLen, &StartBit); 199 | int pic_height_in_map_units_minus1=Ue(buf,nLen, &StartBit); 200 | 201 | *width=(pic_width_in_mbs_minus1+1)*16; 202 | *height=(pic_height_in_map_units_minus1+1)*16; 203 | 204 | int frame_mbs_only_flag=u(1,buf, &StartBit); 205 | if(!frame_mbs_only_flag) 206 | { 207 | // int mb_adaptive_frame_field_flag= 208 | u(1,buf, &StartBit); 209 | } 210 | 211 | // int direct_8x8_inference_flag= 212 | u(1,buf, &StartBit); 213 | int frame_cropping_flag=u(1,buf, &StartBit); 214 | if(frame_cropping_flag) 215 | { 216 | // int frame_crop_left_offset= 217 | Ue(buf,nLen, &StartBit); 218 | // int frame_crop_right_offset= 219 | Ue(buf,nLen, &StartBit); 220 | // int frame_crop_top_offset= 221 | Ue(buf,nLen, &StartBit); 222 | // int frame_crop_bottom_offset= 223 | Ue(buf,nLen, &StartBit); 224 | } 225 | int vui_parameter_present_flag=u(1,buf, &StartBit); 226 | if(vui_parameter_present_flag) 227 | { 228 | int aspect_ratio_info_present_flag=u(1,buf, &StartBit); 229 | if(aspect_ratio_info_present_flag) 230 | { 231 | int aspect_ratio_idc=u(8,buf, &StartBit); 232 | if(aspect_ratio_idc==255) 233 | { 234 | // int sar_width= 235 | u(16,buf, &StartBit); 236 | // int sar_height= 237 | u(16,buf, &StartBit); 238 | } 239 | } 240 | int overscan_info_present_flag=u(1,buf, &StartBit); 241 | if(overscan_info_present_flag) 242 | { 243 | // int overscan_appropriate_flagu= 244 | u(1,buf, &StartBit); 245 | } 246 | int video_signal_type_present_flag=u(1,buf, &StartBit); 247 | if(video_signal_type_present_flag) 248 | { 249 | // int video_format= 250 | u(3,buf, &StartBit); 251 | // int video_full_range_flag= 252 | u(1,buf, &StartBit); 253 | int colour_description_present_flag=u(1,buf, &StartBit); 254 | if(colour_description_present_flag) 255 | { 256 | // int colour_primaries= 257 | u(8,buf, &StartBit); 258 | // int transfer_characteristics= 259 | u(8,buf, &StartBit); 260 | // int matrix_coefficients= 261 | u(8,buf, &StartBit); 262 | } 263 | } 264 | int chroma_loc_info_present_flag=u(1,buf, &StartBit); 265 | if(chroma_loc_info_present_flag) 266 | { 267 | // int chroma_sample_loc_type_top_field= 268 | Ue(buf,nLen, &StartBit); 269 | // int chroma_sample_loc_type_bottom_field= 270 | Ue(buf,nLen, &StartBit); 271 | } 272 | int timing_info_present_flag=u(1,buf, &StartBit); 273 | if(timing_info_present_flag) 274 | { 275 | int num_units_in_tick=u(32,buf, &StartBit); 276 | int time_scale=u(32,buf, &StartBit); 277 | *fps = time_scale/(2*num_units_in_tick); 278 | } 279 | } 280 | return 0; 281 | } 282 | else 283 | return 1; 284 | } -------------------------------------------------------------------------------- /conv/sps_dec.h: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-06-17 4 | @@Mail : pu17rui@sina.com 5 | @@Description: 6 | *******************************/ 7 | #ifndef __SPS_DEC_H__ 8 | #define __SPS_DEC_H__ 9 | 10 | typedef unsigned int SPS_UINT; 11 | typedef unsigned char SPS_BYTE; 12 | typedef unsigned long SPS_DWORD; 13 | 14 | SPS_UINT Ue(SPS_BYTE *pBuff, SPS_UINT nLen, SPS_UINT* nStartBit); 15 | int Se(SPS_BYTE *pBuff, SPS_UINT nLen, SPS_UINT* nStartBit); 16 | SPS_DWORD u(SPS_UINT BitCount, SPS_BYTE* buf, SPS_UINT* nStartBit); 17 | void de_emulation_prevention(SPS_BYTE* buf, unsigned int buf_size); 18 | int H264_DecodeSPS(SPS_BYTE* buf, unsigned int nLen, int* width, int* height, int* fps); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /ipc/cms_vtdu.c: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-06-25 4 | @@Mail : pu17rui@sina.com 5 | @@Description: 6 | HIKPusher 7 | *******************************/ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "config.h" 14 | #include "cms_vtdu.h" 15 | #include "ipcs.h" 16 | #include "parser_ps.h" 17 | #include "log.h" 18 | 19 | extern struct _ipc IPCs[IPCS_MAX_NUM]; 20 | //注册回调函数, CALLBACK is not defined as any value! (HCEHomePublic.h) 21 | BOOL CALLBACK RegisterCallBack(LONG lUserID, DWORD dwDataType, void *pOutBuffer, DWORD dwOutLen, void *pInBuffer, DWORD dwInLen, void *pUser) 22 | { 23 | NET_EHOME_DEV_REG_INFO *pDevInfo = (NET_EHOME_DEV_REG_INFO *)pOutBuffer; 24 | if (ENUM_DEV_ON == dwDataType) 25 | { 26 | if (pDevInfo != NULL) 27 | { 28 | unsigned short int_dev_id = IPCS_GetInt_Devid(pDevInfo->byDeviceID, strlen((char*)(pDevInfo->byDeviceID))); 29 | IPCs[int_dev_id].login_id = lUserID; 30 | IPCs[int_dev_id].online_state = IPCS_ONLINE; 31 | LOG_INFO("On-line, lUserID: %ld, Device ID: %s\n", IPCs[int_dev_id].login_id, pDevInfo->byDeviceID); 32 | } 33 | //输入参数 34 | NET_EHOME_SERVER_INFO *pServerInfo = (NET_EHOME_SERVER_INFO *)pInBuffer; 35 | pServerInfo->dwTimeOutCount = 6; //心跳超时次数 36 | pServerInfo->dwKeepAliveSec = 5; //心跳间隔 37 | } 38 | else if (ENUM_DEV_OFF == dwDataType) 39 | { 40 | LOG_INFO("Off-line, lUserID: %d", lUserID); 41 | for (int i = 0; i < IPCS_MAX_NUM; ++i) 42 | { 43 | if (IPCs[i].login_id == lUserID) 44 | { 45 | //如果之前在推流了,注意释放所有资源! 46 | if (IPCs[i].push_state == IPCS_PUSHING_STREAM) 47 | { 48 | if(!NET_ECMS_StopGetRealStream(IPCs[i].login_id, IPCs[i].preview_session_id)) 49 | LOG_ERROR(ERR_CMS_STREAM_STOP, "NET_ECMS_StopGetRealStream failed, error code: %d\n", NET_ECMS_GetLastError()); 50 | if(IPCs[i].stream_handle >= 0) 51 | if (!NET_ESTREAM_StopPreview(IPCs[i].stream_handle)) 52 | LOG_ERROR(ERR_VTDU_STOP, "NET_ESTREAM_StopPreview failed, error code: %d\n", NET_ECMS_GetLastError()); 53 | IPCS_PushFree(&(IPCs[i])); 54 | } 55 | IPCs[i].online_state = IPCS_OFFLINE; 56 | IPCs[i].push_state = IPCS_NOT_PUSHING_STREAM; 57 | IPCs[i].login_id = -1; 58 | IPCs[i].stream_handle = -1; 59 | IPCs[i].preview_session_id = -1; 60 | printf(", Device ID: %s\n", IPCs[i].dev_id); 61 | break; 62 | } 63 | } 64 | NET_ECMS_ForceLogout(lUserID); 65 | } 66 | else 67 | { 68 | } 69 | 70 | return TRUE; 71 | } 72 | 73 | ////////////////////////////////////////////////////////////////////// 74 | //实时流数据处理 75 | // static FILE *Videofile = NULL; 76 | BOOL InputStreamData(long int_dev_id, BYTE byDataType, char* pBuffer, int iDataLen) 77 | { 78 | 79 | PS_Parser(&(IPCs[int_dev_id]), pBuffer, iDataLen); 80 | // if(Videofile == NULL) 81 | // { 82 | // Videofile = fopen("test.rtp","wb"); 83 | // printf("Save data to file: test.rtp!\n"); 84 | // } 85 | 86 | // if(Videofile!= NULL) 87 | // { 88 | // printf("len:%d buf:\n", iDataLen); 89 | // for (int i = 0; i < iDataLen; ++i) 90 | // printf("0x%02x ", (unsigned char)pBuffer[i]); 91 | // printf("\n"); 92 | // fwrite(pBuffer,iDataLen,1,Videofile); //回调实时流直接写文件,保存录像 93 | // } 94 | 95 | return TRUE; 96 | } 97 | 98 | ////////////////////////////////////////////////////////////////////// 99 | //实时流数据回调函数 100 | void CALLBACK fnPREVIEW_DATA_CB(LONG lPreviewHandle, NET_EHOME_PREVIEW_CB_MSG *pPreviewCBMsg, void *pUserData) 101 | { 102 | if (NULL == pPreviewCBMsg) 103 | { 104 | return ; 105 | } 106 | long int_dev_id = -1; 107 | for (int i = 0; i < IPCS_MAX_NUM; ++i) 108 | { 109 | if (IPCs[i].stream_handle == lPreviewHandle) 110 | { 111 | int_dev_id = i; 112 | // printf("int_dev_id%d, Device ID: %s\n", i, IPCs[i].dev_id); 113 | break; 114 | } 115 | } 116 | InputStreamData(int_dev_id, pPreviewCBMsg->byDataType, (char*)pPreviewCBMsg->pRecvdata, pPreviewCBMsg->dwDataLen); 117 | } 118 | 119 | ////////////////////////////////////////////////////////////////////// 120 | //VTDU预览请求回应回调函数 121 | BOOL CALLBACK fnPREVIEW_NEWLINK_CB(LONG lPreviewHandle, NET_EHOME_NEWLINK_CB_MSG *pNewLinkCBMsg, void *pUserData) 122 | { 123 | LOG_INFO("Callback of preview listening, Device ID: %s, Channel: %d\n", pNewLinkCBMsg->szDeviceID, pNewLinkCBMsg->dwChannelNo); 124 | unsigned short int_dev_id = IPCS_GetInt_Devid(pNewLinkCBMsg->szDeviceID, strlen((char*)(pNewLinkCBMsg->szDeviceID))); 125 | IPCs[int_dev_id].stream_handle = lPreviewHandle;//printf("hand%ld\n", IPCs[int_dev_id].stream_handle); 126 | //预览数据回调参数 127 | NET_EHOME_PREVIEW_DATA_CB_PARAM struDataCB = {0}; 128 | struDataCB.fnPreviewDataCB = fnPREVIEW_DATA_CB; 129 | //struDataCB.byStreamFormat = 0;//封装格式:0- PS 130 | 131 | if (!NET_ESTREAM_SetPreviewDataCB(IPCs[int_dev_id].stream_handle, &struDataCB)) 132 | { 133 | LOG_ERROR(ERR_VTDU_SETCB, "NET_ESTREAM_SetPreviewDataCB failed, error code: %d\n", NET_ESTREAM_GetLastError()); 134 | return FALSE; 135 | } 136 | LOG_INFO("NET_ESTREAM_SetPreviewDataCB!\n"); 137 | 138 | return TRUE; 139 | } 140 | -------------------------------------------------------------------------------- /ipc/cms_vtdu.h: -------------------------------------------------------------------------------- 1 | #ifndef __CMS_H__ 2 | #define __CMS_H__ 3 | 4 | #include "HCEHomeCMS.h" 5 | #include "HCEHomeStream.h" 6 | 7 | BOOL CALLBACK RegisterCallBack(LONG lUserID, DWORD dwDataType, void *pOutBuffer, DWORD dwOutLen, void *pInBuffer, DWORD dwInLen, void *pUser); 8 | BOOL InputStreamData(BYTE byDataType, char* pBuffer, int iDataLen); 9 | void CALLBACK fnPREVIEW_DATA_CB(LONG lPreviewHandle, NET_EHOME_PREVIEW_CB_MSG *pPreviewCBMsg, void *pUserData); 10 | BOOL CALLBACK fnPREVIEW_NEWLINK_CB(LONG lPreviewHandle, NET_EHOME_NEWLINK_CB_MSG *pNewLinkCBMsg, void *pUserData); 11 | 12 | 13 | 14 | #endif -------------------------------------------------------------------------------- /ipc/ipcs.c: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-07-04 4 | @@Mail : pu17rui@sina.com 5 | @@Description: 6 | *******************************/ 7 | #include 8 | #include 9 | #include 10 | #include "config.h" 11 | #include "ipcs.h" 12 | #include "rtmp_log.h" 13 | #include "log.h" 14 | 15 | struct _ipc IPCs[IPCS_MAX_NUM]; 16 | /************************************************* 17 | @Description: init of the ipc struct 18 | @Input: 19 | @Output: 20 | @Return: 0 - success 21 | @Others: 22 | *************************************************/ 23 | int IPCS_Init(void) 24 | { 25 | for (int i = 0; i < IPCS_MAX_NUM; ++i) 26 | { 27 | IPCs[i].login_id = -1; 28 | IPCs[i].stream_handle = -1; 29 | IPCs[i].preview_session_id = -1; 30 | 31 | short co_id = i / 16 % 16; 32 | short sta_id = i % 16; 33 | sprintf(IPCs[i].dev_id, "IPCS00000%x0%x", co_id, sta_id); 34 | // printf("dev_id:%s \n", IPCs[i].dev_id); 35 | 36 | memset(&(IPCs[i].last_req_time), 0, sizeof(IPCs[i].last_req_time)); 37 | IPCs[i].push_state = IPCS_NOT_PUSHING_STREAM; 38 | IPCs[i].online_state = IPCS_OFFLINE; 39 | 40 | IPCs[i].rtmp = NULL; 41 | IPCs[i].pespack_buf = NULL; 42 | IPCs[i].pespack_buf_len = 0; 43 | IPCs[i].h264pack_buf = NULL; 44 | IPCs[i].h264pack_buf_len = 0; 45 | 46 | memset(&(IPCs[i].metaData), 0, sizeof(IPCs[i].metaData)); 47 | IPCs[i].tick = 0; 48 | IPCs[i].tick_gap = 0; 49 | } 50 | 51 | return 0; 52 | } 53 | /************************************************* 54 | @Description: init of one ipc 55 | @Input: 56 | @Output: 57 | @Return: 0 - success 58 | @Others: 59 | *************************************************/ 60 | int IPCS_PushInit(struct _ipc *ipc) 61 | { 62 | RTMP *rtmp = NULL; 63 | rtmp = RTMP_Alloc(); 64 | RTMP_Init(rtmp); 65 | //set connection timeout,default 30s 66 | rtmp->Link.timeout = RTMP_CONNECTION_TIMEOUT; 67 | char url_tmp[50] = {0}; 68 | int posi = sprintf(url_tmp, "%s", RTMP_URL); 69 | sprintf(url_tmp + posi, "%s", ipc->dev_id);//printf("%s\n", url_tmp); 70 | if(!RTMP_SetupURL(rtmp, (char*)url_tmp)) 71 | { 72 | // RTMP_Log(RTMP_LOGERROR, "SetupURL Err\n"); 73 | LOG_ERROR(ERR_RTMP_SET_URL, "RTMP SetupURL Err\n"); 74 | RTMP_Free(rtmp); 75 | return 1; 76 | } 77 | //if unable,the AMF command would be 'play' instead of 'publish' 78 | RTMP_EnableWrite(rtmp); 79 | 80 | if (!RTMP_Connect(rtmp, NULL)){ 81 | // RTMP_Log(RTMP_LOGERROR, "Connect Err\n"); 82 | LOG_ERROR(ERR_RTMP_CONNECT, "RTMP Connect Err\n"); 83 | RTMP_Free(rtmp); 84 | return 2; 85 | } 86 | 87 | if (!RTMP_ConnectStream(rtmp, 0)){ 88 | LOG_ERROR(ERR_RTMP_CONNECT_STREAM, "RTMP ConnectStream Err\n"); 89 | // RTMP_Log(RTMP_LOGERROR, "ConnectStream Err\n"); 90 | RTMP_Close(rtmp); 91 | RTMP_Free(rtmp); 92 | return 3; 93 | } 94 | /*this statement must be after the init of rtmp!!*/ 95 | ipc->rtmp = rtmp; 96 | 97 | ipc->pespack_buf = (char*)malloc(PESPACK_BUF_MAX_SIZE); 98 | for (int i = 0; i < PESPACK_BUF_MAX_SIZE; ++i) 99 | ipc->pespack_buf[i] = 0; 100 | ipc->pespack_buf_len = 0; 101 | ipc->pespack_left_len = 0; 102 | ipc->h264pack_buf = (char*)malloc(H264PACK_BUF_MAX_SIZE); 103 | for (int i = 0; i < H264PACK_BUF_MAX_SIZE; ++i) 104 | ipc->h264pack_buf[i] = 0; 105 | ipc->h264pack_buf_len = 0; 106 | 107 | //in case... 108 | if (ipc->metaData.Sps != NULL) 109 | { 110 | free(ipc->metaData.Sps); 111 | ipc->metaData.Sps = NULL; 112 | } 113 | if (ipc->metaData.Pps != NULL) 114 | { 115 | free(ipc->metaData.Pps); 116 | ipc->metaData.Pps = NULL; 117 | } 118 | memset(&(ipc->metaData), 0, sizeof(ipc->metaData)); 119 | ipc->tick = 0; 120 | ipc->tick_gap = 0; 121 | 122 | return 0; 123 | } 124 | /************************************************* 125 | @Description: init of the ipc struct 126 | @Input: 127 | @Output: 128 | @Return: 0 - success 129 | @Others: 130 | *************************************************/ 131 | int IPCS_PushFree(struct _ipc *ipc) 132 | { 133 | if (ipc->rtmp != NULL) 134 | { 135 | RTMP_Close(ipc->rtmp); 136 | RTMP_Free(ipc->rtmp); 137 | ipc->rtmp = NULL; 138 | } 139 | ipc->pespack_buf_len = 0; 140 | ipc->pespack_left_len = 0; 141 | if (ipc->pespack_buf != NULL) 142 | { 143 | free(ipc->pespack_buf); 144 | ipc->pespack_buf = NULL; 145 | } 146 | ipc->h264pack_buf_len = 0; 147 | if (ipc->h264pack_buf != NULL) 148 | { 149 | free(ipc->h264pack_buf); 150 | ipc->h264pack_buf = NULL; 151 | } 152 | //must free first! 153 | if (ipc->metaData.Sps != NULL) 154 | { 155 | free(ipc->metaData.Sps); 156 | ipc->metaData.Sps = NULL; 157 | } 158 | if (ipc->metaData.Pps != NULL) 159 | { 160 | free(ipc->metaData.Pps); 161 | ipc->metaData.Pps = NULL; 162 | } 163 | memset(&(ipc->metaData), 0, sizeof(ipc->metaData)); 164 | ipc->tick = 0; 165 | ipc->tick_gap = 0; 166 | 167 | return 0; 168 | } 169 | /************************************************* 170 | @Description: Get Devid(int) 171 | @Input: req_serv's recv buf except "start"; buf's length 172 | @Output: 173 | @Return: 174 | @Others: reg_pack : I P C S 00 00 0X 0X 175 | *************************************************/ 176 | unsigned short IPCS_GetInt_Devid(unsigned char *msgs, int len) 177 | { 178 | // char str_user_id[2] = {0};//must be 2 cause the '\0' 179 | // char str_loc_id[2] = {0}; 180 | // char str_sta_id[2] = {0}; 181 | 182 | // if (len < 12) 183 | // return -1; 184 | // memcpy(str_user_id, msgs + 7, 1); 185 | // memcpy(str_loc_id, msgs + 9, 1); 186 | // memcpy(str_sta_id, msgs + 11, 1); 187 | // // printf("usr:%s, loc:%s, sta:%s\n", str_user_id, str_loc_id, str_sta_id); 188 | 189 | // short user_id = strtol(str_user_id, NULL, 16); 190 | // short loc_id = strtol(str_loc_id, NULL, 16); 191 | // short sta_id = strtol(str_sta_id, NULL, 16); 192 | // // printf("usr:0x%02x, loc:0x%02x, sta:0x%02x\n", user_id, loc_id, sta_id); 193 | 194 | // unsigned short int_dev_id = (user_id << 8) + (loc_id << 4) + sta_id; 195 | // // printf("int_dev_id:%d\n", int_dev_id); 196 | 197 | char str_co_id[2] = {0};//must be 2 cause the '\0' 198 | char str_sta_id[2] = {0}; 199 | 200 | if (len < 12) 201 | return -1; 202 | memcpy(str_co_id, msgs + 9, 1); 203 | memcpy(str_sta_id, msgs + 11, 1); 204 | // printf("usr:%s, sta:%s\n", str_co_id, str_sta_id); 205 | 206 | short co_id = strtol(str_co_id, NULL, 16); 207 | short sta_id = strtol(str_sta_id, NULL, 16); 208 | // printf("usr:0x%02x, sta:0x%02x\n", co_id, sta_id); 209 | 210 | unsigned short int_dev_id = (co_id << 4) + sta_id; 211 | // printf("int_dev_id:%d\n", int_dev_id); 212 | 213 | return int_dev_id; 214 | } -------------------------------------------------------------------------------- /ipc/ipcs.h: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-07-04 4 | @@Mail : pu17rui@sina.com 5 | @@Description: 6 | *******************************/ 7 | #ifndef __IPC_H__ 8 | #define __IPC_H__ 9 | 10 | #include 11 | #include "rtmp_sys.h" 12 | /*** _RTMPMetadata 内部结构体。该结构体主要用于存储和传递元数据信息*/ 13 | typedef struct _RTMPMetadata 14 | { 15 | // video, must be h264 type 16 | unsigned int nWidth; 17 | unsigned int nHeight; 18 | unsigned int nFrameRate; //帧率 19 | unsigned int nSpsLen; 20 | unsigned char *Sps; 21 | unsigned int nPpsLen; 22 | unsigned char *Pps; 23 | } RTMPMetadata; 24 | 25 | struct _ipc 26 | { 27 | /*交互状态相关*/ 28 | long login_id; //系统分配的登录ID 29 | long stream_handle; //实时流句柄 30 | long preview_session_id; //系统分配的预览会话ID struPreviewOut.lSessionID 31 | char dev_id[13]; //字符串形式的设备ID 32 | struct timeval last_req_time; //上一次预览请求时间 33 | char push_state; //是否在推流 34 | char online_state; //是否在线 35 | /*解析RTP流相关*/ 36 | char *pespack_buf; //PES解析器缓冲区,为一个PES包荷载数据 37 | int pespack_buf_len; //当前PES解析器缓冲区中一个PES包荷载数据长度,可能不完整 38 | int pespack_left_len; //下一次需要继续解析的残余长度 39 | char *h264pack_buf; //H264解析器缓冲区,实际为n个NALU 40 | int h264pack_buf_len; //当前H264解析器缓冲区中n个NALU长度,可能不完整 41 | /*封装RTMP流相关*/ 42 | RTMP *rtmp; 43 | RTMPMetadata metaData; //元数据 44 | unsigned int tick; 45 | unsigned int tick_gap; 46 | }; 47 | 48 | int IPCS_Init(void); 49 | int IPCS_PushInit(struct _ipc *); 50 | int IPCS_PushFree(struct _ipc *); 51 | unsigned short IPCS_GetInt_Devid(unsigned char *msgs, int len); 52 | 53 | 54 | 55 | #endif -------------------------------------------------------------------------------- /librtmp/COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | 504 | 505 | -------------------------------------------------------------------------------- /librtmp/Makefile: -------------------------------------------------------------------------------- 1 | VERSION=v2.4 2 | 3 | prefix=/usr/local 4 | 5 | incdir=$(prefix)/include/librtmp 6 | bindir=$(prefix)/bin 7 | libdir=$(prefix)/lib 8 | mandir=$(prefix)/man 9 | BINDIR=$(DESTDIR)$(bindir) 10 | INCDIR=$(DESTDIR)$(incdir) 11 | LIBDIR=$(DESTDIR)$(libdir) 12 | MANDIR=$(DESTDIR)$(mandir) 13 | 14 | CC=$(CROSS_COMPILE)gcc 15 | LD=$(CROSS_COMPILE)ld 16 | AR=$(CROSS_COMPILE)ar 17 | 18 | SYS=posix 19 | CRYPTO=OPENSSL 20 | #CRYPTO=GNUTLS 21 | DEF_POLARSSL=-DUSE_POLARSSL 22 | DEF_OPENSSL=-DUSE_OPENSSL 23 | DEF_GNUTLS=-DUSE_GNUTLS 24 | DEF_=-DNO_CRYPTO 25 | REQ_GNUTLS=gnutls,hogweed,nettle 26 | REQ_OPENSSL=libssl,libcrypto 27 | PUB_GNUTLS=-lgmp 28 | LIBZ=-lz 29 | LIBS_posix= 30 | LIBS_darwin= 31 | LIBS_mingw=-lws2_32 -lwinmm -lgdi32 32 | LIB_GNUTLS=-lgnutls -lhogweed -lnettle -lgmp $(LIBZ) 33 | LIB_OPENSSL=-lssl -lcrypto $(LIBZ) 34 | LIB_POLARSSL=-lpolarssl $(LIBZ) 35 | PRIVATE_LIBS=$(LIBS_$(SYS)) 36 | CRYPTO_LIB=$(LIB_$(CRYPTO)) $(PRIVATE_LIBS) 37 | CRYPTO_REQ=$(REQ_$(CRYPTO)) 38 | CRYPTO_DEF=$(DEF_$(CRYPTO)) 39 | PUBLIC_LIBS=$(PUB_$(CRYPTO)) 40 | 41 | SO_VERSION=1 42 | SOX_posix=so 43 | SOX_darwin=dylib 44 | SOX_mingw=dll 45 | SOX=$(SOX_$(SYS)) 46 | SO_posix=.$(SOX).$(SO_VERSION) 47 | SO_darwin=.$(SO_VERSION).$(SOX) 48 | SO_mingw=-$(SO_VERSION).$(SOX) 49 | SO_EXT=$(SO_$(SYS)) 50 | 51 | SODIR_posix=$(LIBDIR) 52 | SODIR_darwin=$(LIBDIR) 53 | SODIR_mingw=$(BINDIR) 54 | SODIR=$(SODIR_$(SYS)) 55 | 56 | SO_LDFLAGS_posix=-shared -Wl,-soname,$@ 57 | SO_LDFLAGS_darwin=-dynamiclib -twolevel_namespace -undefined dynamic_lookup \ 58 | -fno-common -headerpad_max_install_names -install_name $(libdir)/$@ 59 | SO_LDFLAGS_mingw=-shared -Wl,--out-implib,librtmp.dll.a 60 | SO_LDFLAGS=$(SO_LDFLAGS_$(SYS)) 61 | 62 | INSTALL_IMPLIB_posix= 63 | INSTALL_IMPLIB_darwin= 64 | INSTALL_IMPLIB_mingw=cp librtmp.dll.a $(LIBDIR) 65 | INSTALL_IMPLIB=$(INSTALL_IMPLIB_$(SYS)) 66 | 67 | SHARED=yes 68 | SODEF_yes=-fPIC 69 | SOLIB_yes=librtmp$(SO_EXT) 70 | SOINST_yes=install_so 71 | SO_DEF=$(SODEF_$(SHARED)) 72 | SO_LIB=$(SOLIB_$(SHARED)) 73 | SO_INST=$(SOINST_$(SHARED)) 74 | 75 | DEF=-DRTMPDUMP_VERSION=\"$(VERSION)\" $(CRYPTO_DEF) $(XDEF) 76 | OPT=-O2 77 | CFLAGS=-Wall $(XCFLAGS) $(INC) $(DEF) $(OPT) $(SO_DEF) 78 | LDFLAGS=$(XLDFLAGS) 79 | 80 | 81 | OBJS=rtmp.o rtmp_log.o amf.o hashswf.o parseurl.o 82 | 83 | all: librtmp.a $(SO_LIB) 84 | 85 | clean: 86 | rm -f *.o *.a *.$(SOX) *$(SO_EXT) librtmp.pc 87 | 88 | librtmp.a: $(OBJS) 89 | $(AR) rs $@ $? 90 | 91 | librtmp$(SO_EXT): $(OBJS) 92 | $(CC) $(SO_LDFLAGS) $(LDFLAGS) -o $@ $^ $> $(CRYPTO_LIB) 93 | ln -sf $@ librtmp.$(SOX) 94 | 95 | rtmp_log.o: rtmp_log.c rtmp_log.h Makefile 96 | rtmp.o: rtmp.c rtmp.h rtmp_sys.h handshake.h dh.h rtmp_log.h amf.h Makefile 97 | amf.o: amf.c amf.h bytes.h rtmp_log.h Makefile 98 | hashswf.o: hashswf.c http.h rtmp.h rtmp_sys.h Makefile 99 | parseurl.o: parseurl.c rtmp.h rtmp_sys.h rtmp_log.h Makefile 100 | 101 | librtmp.pc: librtmp.pc.in Makefile 102 | sed -e "s;@prefix@;$(prefix);" -e "s;@libdir@;$(libdir);" \ 103 | -e "s;@VERSION@;$(VERSION);" \ 104 | -e "s;@CRYPTO_REQ@;$(CRYPTO_REQ);" \ 105 | -e "s;@PUBLIC_LIBS@;$(PUBLIC_LIBS);" \ 106 | -e "s;@PRIVATE_LIBS@;$(PRIVATE_LIBS);" librtmp.pc.in > $@ 107 | 108 | install: install_base $(SO_INST) 109 | 110 | install_base: librtmp.a librtmp.pc 111 | -mkdir -p $(INCDIR) $(LIBDIR)/pkgconfig $(MANDIR)/man3 $(SODIR) 112 | cp amf.h http.h rtmp_log.h rtmp.h $(INCDIR) 113 | cp librtmp.a $(LIBDIR) 114 | cp librtmp.pc $(LIBDIR)/pkgconfig 115 | cp librtmp.3 $(MANDIR)/man3 116 | 117 | install_so: librtmp$(SO_EXT) 118 | cp librtmp$(SO_EXT) $(SODIR) 119 | $(INSTALL_IMPLIB) 120 | cd $(SODIR); ln -sf librtmp$(SO_EXT) librtmp.$(SOX) 121 | 122 | -------------------------------------------------------------------------------- /librtmp/amf.h: -------------------------------------------------------------------------------- 1 | #ifndef __AMF_H__ 2 | #define __AMF_H__ 3 | /* 4 | * Copyright (C) 2005-2008 Team XBMC 5 | * http://www.xbmc.org 6 | * Copyright (C) 2008-2009 Andrej Stepanchuk 7 | * Copyright (C) 2009-2010 Howard Chu 8 | * 9 | * This file is part of librtmp. 10 | * 11 | * librtmp is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU Lesser General Public License as 13 | * published by the Free Software Foundation; either version 2.1, 14 | * or (at your option) any later version. 15 | * 16 | * librtmp is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public License 22 | * along with librtmp see the file COPYING. If not, write to 23 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301, USA. 25 | * http://www.gnu.org/copyleft/lgpl.html 26 | */ 27 | 28 | #include 29 | 30 | #ifndef TRUE 31 | #define TRUE 1 32 | #define FALSE 0 33 | #endif 34 | 35 | #ifdef __cplusplus 36 | extern "C" 37 | { 38 | #endif 39 | 40 | typedef enum 41 | { AMF_NUMBER = 0, AMF_BOOLEAN, AMF_STRING, AMF_OBJECT, 42 | AMF_MOVIECLIP, /* reserved, not used */ 43 | AMF_NULL, AMF_UNDEFINED, AMF_REFERENCE, AMF_ECMA_ARRAY, AMF_OBJECT_END, 44 | AMF_STRICT_ARRAY, AMF_DATE, AMF_LONG_STRING, AMF_UNSUPPORTED, 45 | AMF_RECORDSET, /* reserved, not used */ 46 | AMF_XML_DOC, AMF_TYPED_OBJECT, 47 | AMF_AVMPLUS, /* switch to AMF3 */ 48 | AMF_INVALID = 0xff 49 | } AMFDataType; 50 | 51 | typedef enum 52 | { AMF3_UNDEFINED = 0, AMF3_NULL, AMF3_FALSE, AMF3_TRUE, 53 | AMF3_INTEGER, AMF3_DOUBLE, AMF3_STRING, AMF3_XML_DOC, AMF3_DATE, 54 | AMF3_ARRAY, AMF3_OBJECT, AMF3_XML, AMF3_BYTE_ARRAY 55 | } AMF3DataType; 56 | 57 | typedef struct AVal 58 | { 59 | char *av_val; 60 | int av_len; 61 | } AVal; 62 | #define AVC(str) {str,sizeof(str)-1} 63 | #define AVMATCH(a1,a2) ((a1)->av_len == (a2)->av_len && !memcmp((a1)->av_val,(a2)->av_val,(a1)->av_len)) 64 | 65 | struct AMFObjectProperty; 66 | 67 | typedef struct AMFObject 68 | { 69 | int o_num; 70 | struct AMFObjectProperty *o_props; 71 | } AMFObject; 72 | 73 | typedef struct AMFObjectProperty 74 | { 75 | AVal p_name; 76 | AMFDataType p_type; 77 | union 78 | { 79 | double p_number; 80 | AVal p_aval; 81 | AMFObject p_object; 82 | } p_vu; 83 | int16_t p_UTCoffset; 84 | } AMFObjectProperty; 85 | 86 | char *AMF_EncodeString(char *output, char *outend, const AVal * str); 87 | char *AMF_EncodeNumber(char *output, char *outend, double dVal); 88 | char *AMF_EncodeInt16(char *output, char *outend, short nVal); 89 | char *AMF_EncodeInt24(char *output, char *outend, int nVal); 90 | char *AMF_EncodeInt32(char *output, char *outend, int nVal); 91 | char *AMF_EncodeBoolean(char *output, char *outend, int bVal); 92 | 93 | /* Shortcuts for AMFProp_Encode */ 94 | char *AMF_EncodeNamedString(char *output, char *outend, const AVal * name, const AVal * value); 95 | char *AMF_EncodeNamedNumber(char *output, char *outend, const AVal * name, double dVal); 96 | char *AMF_EncodeNamedBoolean(char *output, char *outend, const AVal * name, int bVal); 97 | 98 | unsigned short AMF_DecodeInt16(const char *data); 99 | unsigned int AMF_DecodeInt24(const char *data); 100 | unsigned int AMF_DecodeInt32(const char *data); 101 | void AMF_DecodeString(const char *data, AVal * str); 102 | void AMF_DecodeLongString(const char *data, AVal * str); 103 | int AMF_DecodeBoolean(const char *data); 104 | double AMF_DecodeNumber(const char *data); 105 | 106 | char *AMF_Encode(AMFObject * obj, char *pBuffer, char *pBufEnd); 107 | char *AMF_EncodeEcmaArray(AMFObject *obj, char *pBuffer, char *pBufEnd); 108 | char *AMF_EncodeArray(AMFObject *obj, char *pBuffer, char *pBufEnd); 109 | 110 | int AMF_Decode(AMFObject * obj, const char *pBuffer, int nSize, 111 | int bDecodeName); 112 | int AMF_DecodeArray(AMFObject * obj, const char *pBuffer, int nSize, 113 | int nArrayLen, int bDecodeName); 114 | int AMF3_Decode(AMFObject * obj, const char *pBuffer, int nSize, 115 | int bDecodeName); 116 | void AMF_Dump(AMFObject * obj); 117 | void AMF_Reset(AMFObject * obj); 118 | 119 | void AMF_AddProp(AMFObject * obj, const AMFObjectProperty * prop); 120 | int AMF_CountProp(AMFObject * obj); 121 | AMFObjectProperty *AMF_GetProp(AMFObject * obj, const AVal * name, 122 | int nIndex); 123 | 124 | AMFDataType AMFProp_GetType(AMFObjectProperty * prop); 125 | void AMFProp_SetNumber(AMFObjectProperty * prop, double dval); 126 | void AMFProp_SetBoolean(AMFObjectProperty * prop, int bflag); 127 | void AMFProp_SetString(AMFObjectProperty * prop, AVal * str); 128 | void AMFProp_SetObject(AMFObjectProperty * prop, AMFObject * obj); 129 | 130 | void AMFProp_GetName(AMFObjectProperty * prop, AVal * name); 131 | void AMFProp_SetName(AMFObjectProperty * prop, AVal * name); 132 | double AMFProp_GetNumber(AMFObjectProperty * prop); 133 | int AMFProp_GetBoolean(AMFObjectProperty * prop); 134 | void AMFProp_GetString(AMFObjectProperty * prop, AVal * str); 135 | void AMFProp_GetObject(AMFObjectProperty * prop, AMFObject * obj); 136 | 137 | int AMFProp_IsValid(AMFObjectProperty * prop); 138 | 139 | char *AMFProp_Encode(AMFObjectProperty * prop, char *pBuffer, char *pBufEnd); 140 | int AMF3Prop_Decode(AMFObjectProperty * prop, const char *pBuffer, 141 | int nSize, int bDecodeName); 142 | int AMFProp_Decode(AMFObjectProperty * prop, const char *pBuffer, 143 | int nSize, int bDecodeName); 144 | 145 | void AMFProp_Dump(AMFObjectProperty * prop); 146 | void AMFProp_Reset(AMFObjectProperty * prop); 147 | 148 | typedef struct AMF3ClassDef 149 | { 150 | AVal cd_name; 151 | char cd_externalizable; 152 | char cd_dynamic; 153 | int cd_num; 154 | AVal *cd_props; 155 | } AMF3ClassDef; 156 | 157 | void AMF3CD_AddProp(AMF3ClassDef * cd, AVal * prop); 158 | AVal *AMF3CD_GetProp(AMF3ClassDef * cd, int idx); 159 | 160 | #ifdef __cplusplus 161 | } 162 | #endif 163 | 164 | #endif /* __AMF_H__ */ 165 | -------------------------------------------------------------------------------- /librtmp/bytes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2008 Team XBMC 3 | * http://www.xbmc.org 4 | * Copyright (C) 2008-2009 Andrej Stepanchuk 5 | * Copyright (C) 2009-2010 Howard Chu 6 | * 7 | * This file is part of librtmp. 8 | * 9 | * librtmp is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License as 11 | * published by the Free Software Foundation; either version 2.1, 12 | * or (at your option) any later version. 13 | * 14 | * librtmp is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public License 20 | * along with librtmp see the file COPYING. If not, write to 21 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 | * Boston, MA 02110-1301, USA. 23 | * http://www.gnu.org/copyleft/lgpl.html 24 | */ 25 | 26 | #ifndef __BYTES_H__ 27 | #define __BYTES_H__ 28 | 29 | #include 30 | 31 | #ifdef _WIN32 32 | /* Windows is little endian only */ 33 | #define __LITTLE_ENDIAN 1234 34 | #define __BIG_ENDIAN 4321 35 | #define __BYTE_ORDER __LITTLE_ENDIAN 36 | #define __FLOAT_WORD_ORDER __BYTE_ORDER 37 | 38 | typedef unsigned char uint8_t; 39 | 40 | #else /* !_WIN32 */ 41 | 42 | #include 43 | 44 | #if defined(BYTE_ORDER) && !defined(__BYTE_ORDER) 45 | #define __BYTE_ORDER BYTE_ORDER 46 | #endif 47 | 48 | #if defined(BIG_ENDIAN) && !defined(__BIG_ENDIAN) 49 | #define __BIG_ENDIAN BIG_ENDIAN 50 | #endif 51 | 52 | #if defined(LITTLE_ENDIAN) && !defined(__LITTLE_ENDIAN) 53 | #define __LITTLE_ENDIAN LITTLE_ENDIAN 54 | #endif 55 | 56 | #endif /* !_WIN32 */ 57 | 58 | /* define default endianness */ 59 | #ifndef __LITTLE_ENDIAN 60 | #define __LITTLE_ENDIAN 1234 61 | #endif 62 | 63 | #ifndef __BIG_ENDIAN 64 | #define __BIG_ENDIAN 4321 65 | #endif 66 | 67 | #ifndef __BYTE_ORDER 68 | #warning "Byte order not defined on your system, assuming little endian!" 69 | #define __BYTE_ORDER __LITTLE_ENDIAN 70 | #endif 71 | 72 | /* ok, we assume to have the same float word order and byte order if float word order is not defined */ 73 | #ifndef __FLOAT_WORD_ORDER 74 | #warning "Float word order not defined, assuming the same as byte order!" 75 | #define __FLOAT_WORD_ORDER __BYTE_ORDER 76 | #endif 77 | 78 | #if !defined(__BYTE_ORDER) || !defined(__FLOAT_WORD_ORDER) 79 | #error "Undefined byte or float word order!" 80 | #endif 81 | 82 | #if __FLOAT_WORD_ORDER != __BIG_ENDIAN && __FLOAT_WORD_ORDER != __LITTLE_ENDIAN 83 | #error "Unknown/unsupported float word order!" 84 | #endif 85 | 86 | #if __BYTE_ORDER != __BIG_ENDIAN && __BYTE_ORDER != __LITTLE_ENDIAN 87 | #error "Unknown/unsupported byte order!" 88 | #endif 89 | 90 | #endif 91 | 92 | -------------------------------------------------------------------------------- /librtmp/dh.h: -------------------------------------------------------------------------------- 1 | /* RTMPDump - Diffie-Hellmann Key Exchange 2 | * Copyright (C) 2009 Andrej Stepanchuk 3 | * Copyright (C) 2009-2010 Howard Chu 4 | * 5 | * This file is part of librtmp. 6 | * 7 | * librtmp is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1, 10 | * or (at your option) any later version. 11 | * 12 | * librtmp is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with librtmp see the file COPYING. If not, write to 19 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | * http://www.gnu.org/copyleft/lgpl.html 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef USE_POLARSSL 31 | #include 32 | typedef mpi * MP_t; 33 | #define MP_new(m) m = malloc(sizeof(mpi)); mpi_init(m) 34 | #define MP_set_w(mpi, w) mpi_lset(mpi, w) 35 | #define MP_cmp(u, v) mpi_cmp_mpi(u, v) 36 | #define MP_set(u, v) mpi_copy(u, v) 37 | #define MP_sub_w(mpi, w) mpi_sub_int(mpi, mpi, w) 38 | #define MP_cmp_1(mpi) mpi_cmp_int(mpi, 1) 39 | #define MP_modexp(r, y, q, p) mpi_exp_mod(r, y, q, p, NULL) 40 | #define MP_free(mpi) mpi_free(mpi); free(mpi) 41 | #define MP_gethex(u, hex, res) MP_new(u); res = mpi_read_string(u, 16, hex) == 0 42 | #define MP_bytes(u) mpi_size(u) 43 | #define MP_setbin(u,buf,len) mpi_write_binary(u,buf,len) 44 | #define MP_getbin(u,buf,len) MP_new(u); mpi_read_binary(u,buf,len) 45 | 46 | typedef struct MDH { 47 | MP_t p; 48 | MP_t g; 49 | MP_t pub_key; 50 | MP_t priv_key; 51 | long length; 52 | dhm_context ctx; 53 | } MDH; 54 | 55 | #define MDH_new() calloc(1,sizeof(MDH)) 56 | #define MDH_free(vp) {MDH *_dh = vp; dhm_free(&_dh->ctx); MP_free(_dh->p); MP_free(_dh->g); MP_free(_dh->pub_key); MP_free(_dh->priv_key); free(_dh);} 57 | 58 | static int MDH_generate_key(MDH *dh) 59 | { 60 | unsigned char out[2]; 61 | MP_set(&dh->ctx.P, dh->p); 62 | MP_set(&dh->ctx.G, dh->g); 63 | dh->ctx.len = 128; 64 | dhm_make_public(&dh->ctx, 1024, out, 1, havege_random, &RTMP_TLS_ctx->hs); 65 | MP_new(dh->pub_key); 66 | MP_new(dh->priv_key); 67 | MP_set(dh->pub_key, &dh->ctx.GX); 68 | MP_set(dh->priv_key, &dh->ctx.X); 69 | return 1; 70 | } 71 | 72 | static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh) 73 | { 74 | MP_set(&dh->ctx.GY, pub); 75 | dhm_calc_secret(&dh->ctx, secret, &len); 76 | return 0; 77 | } 78 | 79 | #elif defined(USE_GNUTLS) 80 | #include 81 | #include 82 | #include 83 | typedef mpz_ptr MP_t; 84 | #define MP_new(m) m = malloc(sizeof(*m)); mpz_init2(m, 1) 85 | #define MP_set_w(mpi, w) mpz_set_ui(mpi, w) 86 | #define MP_cmp(u, v) mpz_cmp(u, v) 87 | #define MP_set(u, v) mpz_set(u, v) 88 | #define MP_sub_w(mpi, w) mpz_sub_ui(mpi, mpi, w) 89 | #define MP_cmp_1(mpi) mpz_cmp_ui(mpi, 1) 90 | #define MP_modexp(r, y, q, p) mpz_powm(r, y, q, p) 91 | #define MP_free(mpi) mpz_clear(mpi); free(mpi) 92 | #define MP_gethex(u, hex, res) u = malloc(sizeof(*u)); mpz_init2(u, 1); res = (mpz_set_str(u, hex, 16) == 0) 93 | #define MP_bytes(u) (mpz_sizeinbase(u, 2) + 7) / 8 94 | #define MP_setbin(u,buf,len) nettle_mpz_get_str_256(len,buf,u) 95 | #define MP_getbin(u,buf,len) u = malloc(sizeof(*u)); mpz_init2(u, 1); nettle_mpz_set_str_256_u(u,len,buf) 96 | 97 | typedef struct MDH { 98 | MP_t p; 99 | MP_t g; 100 | MP_t pub_key; 101 | MP_t priv_key; 102 | long length; 103 | } MDH; 104 | 105 | #define MDH_new() calloc(1,sizeof(MDH)) 106 | #define MDH_free(dh) do {MP_free(((MDH*)(dh))->p); MP_free(((MDH*)(dh))->g); MP_free(((MDH*)(dh))->pub_key); MP_free(((MDH*)(dh))->priv_key); free(dh);} while(0) 107 | 108 | static int MDH_generate_key(MDH *dh) 109 | { 110 | int num_bytes; 111 | uint32_t seed; 112 | gmp_randstate_t rs; 113 | 114 | num_bytes = (mpz_sizeinbase(dh->p, 2) + 7) / 8 - 1; 115 | if (num_bytes <= 0 || num_bytes > 18000) 116 | return 0; 117 | 118 | dh->priv_key = calloc(1, sizeof(*dh->priv_key)); 119 | if (!dh->priv_key) 120 | return 0; 121 | mpz_init2(dh->priv_key, 1); 122 | gnutls_rnd(GNUTLS_RND_RANDOM, &seed, sizeof(seed)); 123 | gmp_randinit_mt(rs); 124 | gmp_randseed_ui(rs, seed); 125 | mpz_urandomb(dh->priv_key, rs, num_bytes); 126 | gmp_randclear(rs); 127 | 128 | dh->pub_key = calloc(1, sizeof(*dh->pub_key)); 129 | if (!dh->pub_key) 130 | return 0; 131 | mpz_init2(dh->pub_key, 1); 132 | if (!dh->pub_key) { 133 | mpz_clear(dh->priv_key); 134 | free(dh->priv_key); 135 | return 0; 136 | } 137 | 138 | mpz_powm(dh->pub_key, dh->g, dh->priv_key, dh->p); 139 | 140 | return 1; 141 | } 142 | 143 | static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh) 144 | { 145 | mpz_ptr k; 146 | int num_bytes; 147 | 148 | num_bytes = (mpz_sizeinbase(dh->p, 2) + 7) / 8; 149 | if (num_bytes <= 0 || num_bytes > 18000) 150 | return -1; 151 | 152 | k = calloc(1, sizeof(*k)); 153 | if (!k) 154 | return -1; 155 | mpz_init2(k, 1); 156 | 157 | mpz_powm(k, pub, dh->priv_key, dh->p); 158 | nettle_mpz_get_str_256(len, secret, k); 159 | mpz_clear(k); 160 | free(k); 161 | 162 | /* return the length of the shared secret key like DH_compute_key */ 163 | return len; 164 | } 165 | 166 | #else /* USE_OPENSSL */ 167 | #include 168 | #include 169 | 170 | typedef BIGNUM * MP_t; 171 | #define MP_new(m) m = BN_new() 172 | #define MP_set_w(mpi, w) BN_set_word(mpi, w) 173 | #define MP_cmp(u, v) BN_cmp(u, v) 174 | #define MP_set(u, v) BN_copy(u, v) 175 | #define MP_sub_w(mpi, w) BN_sub_word(mpi, w) 176 | #define MP_cmp_1(mpi) BN_cmp(mpi, BN_value_one()) 177 | #define MP_modexp(r, y, q, p) do {BN_CTX *ctx = BN_CTX_new(); BN_mod_exp(r, y, q, p, ctx); BN_CTX_free(ctx);} while(0) 178 | #define MP_free(mpi) BN_free(mpi) 179 | #define MP_gethex(u, hex, res) res = BN_hex2bn(&u, hex) 180 | #define MP_bytes(u) BN_num_bytes(u) 181 | #define MP_setbin(u,buf,len) BN_bn2bin(u,buf) 182 | #define MP_getbin(u,buf,len) u = BN_bin2bn(buf,len,0) 183 | 184 | #define MDH DH 185 | #define MDH_new() DH_new() 186 | #define MDH_free(dh) DH_free(dh) 187 | #define MDH_generate_key(dh) DH_generate_key(dh) 188 | #define MDH_compute_key(secret, seclen, pub, dh) DH_compute_key(secret, pub, dh) 189 | 190 | #endif 191 | 192 | #include "rtmp_log.h" 193 | #include "dhgroups.h" 194 | 195 | /* RFC 2631, Section 2.1.5, http://www.ietf.org/rfc/rfc2631.txt */ 196 | static int 197 | isValidPublicKey(MP_t y, MP_t p, MP_t q) 198 | { 199 | int ret = TRUE; 200 | MP_t bn; 201 | assert(y); 202 | 203 | MP_new(bn); 204 | assert(bn); 205 | 206 | /* y must lie in [2,p-1] */ 207 | MP_set_w(bn, 1); 208 | if (MP_cmp(y, bn) < 0) 209 | { 210 | RTMP_Log(RTMP_LOGERROR, "DH public key must be at least 2"); 211 | ret = FALSE; 212 | goto failed; 213 | } 214 | 215 | /* bn = p-2 */ 216 | MP_set(bn, p); 217 | MP_sub_w(bn, 1); 218 | if (MP_cmp(y, bn) > 0) 219 | { 220 | RTMP_Log(RTMP_LOGERROR, "DH public key must be at most p-2"); 221 | ret = FALSE; 222 | goto failed; 223 | } 224 | 225 | /* Verify with Sophie-Germain prime 226 | * 227 | * This is a nice test to make sure the public key position is calculated 228 | * correctly. This test will fail in about 50% of the cases if applied to 229 | * random data. 230 | */ 231 | if (q) 232 | { 233 | /* y must fulfill y^q mod p = 1 */ 234 | MP_modexp(bn, y, q, p); 235 | 236 | if (MP_cmp_1(bn) != 0) 237 | { 238 | RTMP_Log(RTMP_LOGWARNING, "DH public key does not fulfill y^q mod p = 1"); 239 | } 240 | } 241 | 242 | failed: 243 | MP_free(bn); 244 | return ret; 245 | } 246 | 247 | static MDH * 248 | DHInit(int nKeyBits) 249 | { 250 | size_t res; 251 | MDH *dh = MDH_new(); 252 | 253 | if (!dh) 254 | goto failed; 255 | 256 | MP_new(dh->g); 257 | 258 | if (!dh->g) 259 | goto failed; 260 | 261 | MP_gethex(dh->p, P1024, res); /* prime P1024, see dhgroups.h */ 262 | if (!res) 263 | { 264 | goto failed; 265 | } 266 | 267 | MP_set_w(dh->g, 2); /* base 2 */ 268 | 269 | dh->length = nKeyBits; 270 | return dh; 271 | 272 | failed: 273 | if (dh) 274 | MDH_free(dh); 275 | 276 | return 0; 277 | } 278 | 279 | static int 280 | DHGenerateKey(MDH *dh) 281 | { 282 | size_t res = 0; 283 | if (!dh) 284 | return 0; 285 | 286 | while (!res) 287 | { 288 | MP_t q1 = NULL; 289 | 290 | if (!MDH_generate_key(dh)) 291 | return 0; 292 | 293 | MP_gethex(q1, Q1024, res); 294 | assert(res); 295 | 296 | res = isValidPublicKey(dh->pub_key, dh->p, q1); 297 | if (!res) 298 | { 299 | MP_free(dh->pub_key); 300 | MP_free(dh->priv_key); 301 | dh->pub_key = dh->priv_key = 0; 302 | } 303 | 304 | MP_free(q1); 305 | } 306 | return 1; 307 | } 308 | 309 | /* fill pubkey with the public key in BIG ENDIAN order 310 | * 00 00 00 00 00 x1 x2 x3 ..... 311 | */ 312 | 313 | static int 314 | DHGetPublicKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen) 315 | { 316 | int len; 317 | if (!dh || !dh->pub_key) 318 | return 0; 319 | 320 | len = MP_bytes(dh->pub_key); 321 | if (len <= 0 || len > (int) nPubkeyLen) 322 | return 0; 323 | 324 | memset(pubkey, 0, nPubkeyLen); 325 | MP_setbin(dh->pub_key, pubkey + (nPubkeyLen - len), len); 326 | return 1; 327 | } 328 | 329 | #if 0 /* unused */ 330 | static int 331 | DHGetPrivateKey(MDH *dh, uint8_t *privkey, size_t nPrivkeyLen) 332 | { 333 | if (!dh || !dh->priv_key) 334 | return 0; 335 | 336 | int len = MP_bytes(dh->priv_key); 337 | if (len <= 0 || len > (int) nPrivkeyLen) 338 | return 0; 339 | 340 | memset(privkey, 0, nPrivkeyLen); 341 | MP_setbin(dh->priv_key, privkey + (nPrivkeyLen - len), len); 342 | return 1; 343 | } 344 | #endif 345 | 346 | /* computes the shared secret key from the private MDH value and the 347 | * other party's public key (pubkey) 348 | */ 349 | static int 350 | DHComputeSharedSecretKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen, 351 | uint8_t *secret) 352 | { 353 | MP_t q1 = NULL, pubkeyBn = NULL; 354 | size_t len; 355 | int res; 356 | 357 | if (!dh || !secret || nPubkeyLen >= INT_MAX) 358 | return -1; 359 | 360 | MP_getbin(pubkeyBn, pubkey, nPubkeyLen); 361 | if (!pubkeyBn) 362 | return -1; 363 | 364 | MP_gethex(q1, Q1024, len); 365 | assert(len); 366 | 367 | if (isValidPublicKey(pubkeyBn, dh->p, q1)) 368 | res = MDH_compute_key(secret, nPubkeyLen, pubkeyBn, dh); 369 | else 370 | res = -1; 371 | 372 | MP_free(q1); 373 | MP_free(pubkeyBn); 374 | 375 | return res; 376 | } 377 | -------------------------------------------------------------------------------- /librtmp/dhgroups.h: -------------------------------------------------------------------------------- 1 | /* librtmp - Diffie-Hellmann Key Exchange 2 | * Copyright (C) 2009 Andrej Stepanchuk 3 | * 4 | * This file is part of librtmp. 5 | * 6 | * librtmp is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1, 9 | * or (at your option) any later version. 10 | * 11 | * librtmp is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with librtmp see the file COPYING. If not, write to 18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 | * Boston, MA 02110-1301, USA. 20 | * http://www.gnu.org/copyleft/lgpl.html 21 | */ 22 | 23 | /* from RFC 3526, see http://www.ietf.org/rfc/rfc3526.txt */ 24 | 25 | /* 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } */ 26 | #define P768 \ 27 | "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ 28 | "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ 29 | "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ 30 | "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF" 31 | 32 | /* 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } */ 33 | #define P1024 \ 34 | "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ 35 | "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ 36 | "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ 37 | "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ 38 | "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \ 39 | "FFFFFFFFFFFFFFFF" 40 | 41 | /* Group morder largest prime factor: */ 42 | #define Q1024 \ 43 | "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" \ 44 | "948127044533E63A0105DF531D89CD9128A5043CC71A026E" \ 45 | "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" \ 46 | "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" \ 47 | "F71C35FDAD44CFD2D74F9208BE258FF324943328F67329C0" \ 48 | "FFFFFFFFFFFFFFFF" 49 | 50 | /* 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } */ 51 | #define P1536 \ 52 | "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ 53 | "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ 54 | "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ 55 | "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ 56 | "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ 57 | "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ 58 | "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ 59 | "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF" 60 | 61 | /* 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } */ 62 | #define P2048 \ 63 | "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ 64 | "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ 65 | "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ 66 | "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ 67 | "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ 68 | "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ 69 | "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ 70 | "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ 71 | "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ 72 | "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ 73 | "15728E5A8AACAA68FFFFFFFFFFFFFFFF" 74 | 75 | /* 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } */ 76 | #define P3072 \ 77 | "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ 78 | "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ 79 | "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ 80 | "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ 81 | "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ 82 | "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ 83 | "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ 84 | "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ 85 | "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ 86 | "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ 87 | "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ 88 | "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ 89 | "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ 90 | "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ 91 | "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ 92 | "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF" 93 | 94 | /* 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } */ 95 | #define P4096 \ 96 | "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ 97 | "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ 98 | "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ 99 | "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ 100 | "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ 101 | "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ 102 | "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ 103 | "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ 104 | "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ 105 | "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ 106 | "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ 107 | "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ 108 | "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ 109 | "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ 110 | "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ 111 | "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \ 112 | "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \ 113 | "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \ 114 | "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \ 115 | "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \ 116 | "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" \ 117 | "FFFFFFFFFFFFFFFF" 118 | 119 | /* 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } */ 120 | #define P6144 \ 121 | "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ 122 | "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ 123 | "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ 124 | "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ 125 | "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ 126 | "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ 127 | "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ 128 | "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ 129 | "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ 130 | "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ 131 | "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ 132 | "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ 133 | "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ 134 | "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ 135 | "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ 136 | "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \ 137 | "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \ 138 | "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \ 139 | "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \ 140 | "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \ 141 | "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" \ 142 | "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" \ 143 | "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" \ 144 | "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" \ 145 | "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" \ 146 | "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" \ 147 | "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" \ 148 | "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" \ 149 | "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" \ 150 | "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" \ 151 | "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" \ 152 | "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF" 153 | 154 | /* 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } */ 155 | #define P8192 \ 156 | "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ 157 | "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ 158 | "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ 159 | "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ 160 | "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ 161 | "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ 162 | "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ 163 | "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ 164 | "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ 165 | "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ 166 | "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ 167 | "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ 168 | "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ 169 | "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ 170 | "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ 171 | "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \ 172 | "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \ 173 | "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \ 174 | "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \ 175 | "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \ 176 | "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" \ 177 | "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" \ 178 | "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" \ 179 | "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" \ 180 | "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" \ 181 | "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" \ 182 | "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" \ 183 | "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" \ 184 | "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" \ 185 | "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" \ 186 | "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" \ 187 | "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" \ 188 | "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" \ 189 | "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" \ 190 | "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" \ 191 | "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" \ 192 | "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" \ 193 | "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" \ 194 | "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" \ 195 | "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" \ 196 | "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" \ 197 | "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" \ 198 | "60C980DD98EDD3DFFFFFFFFFFFFFFFFF" 199 | 200 | -------------------------------------------------------------------------------- /librtmp/hashswf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009-2010 Howard Chu 3 | * 4 | * This file is part of librtmp. 5 | * 6 | * librtmp is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1, 9 | * or (at your option) any later version. 10 | * 11 | * librtmp is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with librtmp see the file COPYING. If not, write to 18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 | * Boston, MA 02110-1301, USA. 20 | * http://www.gnu.org/copyleft/lgpl.html 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "rtmp_sys.h" 30 | #include "rtmp_log.h" 31 | #include "http.h" 32 | 33 | #ifdef CRYPTO 34 | #ifdef USE_POLARSSL 35 | #include 36 | #ifndef SHA256_DIGEST_LENGTH 37 | #define SHA256_DIGEST_LENGTH 32 38 | #endif 39 | #define HMAC_CTX sha2_context 40 | #define HMAC_setup(ctx, key, len) sha2_hmac_starts(&ctx, (unsigned char *)key, len, 0) 41 | #define HMAC_crunch(ctx, buf, len) sha2_hmac_update(&ctx, buf, len) 42 | #define HMAC_finish(ctx, dig, dlen) dlen = SHA256_DIGEST_LENGTH; sha2_hmac_finish(&ctx, dig) 43 | #define HMAC_close(ctx) 44 | #elif defined(USE_GNUTLS) 45 | #include 46 | #ifndef SHA256_DIGEST_LENGTH 47 | #define SHA256_DIGEST_LENGTH 32 48 | #endif 49 | #undef HMAC_CTX 50 | #define HMAC_CTX struct hmac_sha256_ctx 51 | #define HMAC_setup(ctx, key, len) hmac_sha256_set_key(&ctx, len, key) 52 | #define HMAC_crunch(ctx, buf, len) hmac_sha256_update(&ctx, len, buf) 53 | #define HMAC_finish(ctx, dig, dlen) dlen = SHA256_DIGEST_LENGTH; hmac_sha256_digest(&ctx, SHA256_DIGEST_LENGTH, dig) 54 | #define HMAC_close(ctx) 55 | #else /* USE_OPENSSL */ 56 | #include 57 | #include 58 | #include 59 | #include 60 | #define HMAC_setup(ctx, key, len) HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, (unsigned char *)key, len, EVP_sha256(), 0) 61 | #define HMAC_crunch(ctx, buf, len) HMAC_Update(&ctx, (unsigned char *)buf, len) 62 | #define HMAC_finish(ctx, dig, dlen) HMAC_Final(&ctx, (unsigned char *)dig, &dlen); 63 | #define HMAC_close(ctx) HMAC_CTX_cleanup(&ctx) 64 | #endif 65 | 66 | extern void RTMP_TLS_Init(); 67 | extern TLS_CTX RTMP_TLS_ctx; 68 | 69 | #include 70 | 71 | #endif /* CRYPTO */ 72 | 73 | #define AGENT "Mozilla/5.0" 74 | 75 | HTTPResult 76 | HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) 77 | { 78 | char *host, *path; 79 | char *p1, *p2; 80 | char hbuf[256]; 81 | int port = 80; 82 | #ifdef CRYPTO 83 | int ssl = 0; 84 | #endif 85 | int hlen, flen = 0; 86 | int rc, i; 87 | int len_known; 88 | HTTPResult ret = HTTPRES_OK; 89 | struct sockaddr_in sa; 90 | RTMPSockBuf sb = {0}; 91 | 92 | http->status = -1; 93 | 94 | memset(&sa, 0, sizeof(struct sockaddr_in)); 95 | sa.sin_family = AF_INET; 96 | 97 | /* we only handle http here */ 98 | if (strncasecmp(url, "http", 4)) 99 | return HTTPRES_BAD_REQUEST; 100 | 101 | if (url[4] == 's') 102 | { 103 | #ifdef CRYPTO 104 | ssl = 1; 105 | port = 443; 106 | if (!RTMP_TLS_ctx) 107 | RTMP_TLS_Init(); 108 | #else 109 | return HTTPRES_BAD_REQUEST; 110 | #endif 111 | } 112 | 113 | p1 = strchr(url + 4, ':'); 114 | if (!p1 || strncmp(p1, "://", 3)) 115 | return HTTPRES_BAD_REQUEST; 116 | 117 | host = p1 + 3; 118 | path = strchr(host, '/'); 119 | hlen = path - host; 120 | strncpy(hbuf, host, hlen); 121 | hbuf[hlen] = '\0'; 122 | host = hbuf; 123 | p1 = strrchr(host, ':'); 124 | if (p1) 125 | { 126 | *p1++ = '\0'; 127 | port = atoi(p1); 128 | } 129 | 130 | sa.sin_addr.s_addr = inet_addr(host); 131 | if (sa.sin_addr.s_addr == INADDR_NONE) 132 | { 133 | struct hostent *hp = gethostbyname(host); 134 | if (!hp || !hp->h_addr) 135 | return HTTPRES_LOST_CONNECTION; 136 | sa.sin_addr = *(struct in_addr *)hp->h_addr; 137 | } 138 | sa.sin_port = htons(port); 139 | sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 140 | if (sb.sb_socket == -1) 141 | return HTTPRES_LOST_CONNECTION; 142 | i = 143 | sprintf(sb.sb_buf, 144 | "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\nReferer: %.*s\r\n", 145 | path, AGENT, host, (int)(path - url + 1), url); 146 | if (http->date[0]) 147 | i += sprintf(sb.sb_buf + i, "If-Modified-Since: %s\r\n", http->date); 148 | i += sprintf(sb.sb_buf + i, "\r\n"); 149 | 150 | if (connect 151 | (sb.sb_socket, (struct sockaddr *)&sa, sizeof(struct sockaddr)) < 0) 152 | { 153 | ret = HTTPRES_LOST_CONNECTION; 154 | goto leave; 155 | } 156 | #ifdef CRYPTO 157 | if (ssl) 158 | { 159 | #ifdef NO_SSL 160 | RTMP_Log(RTMP_LOGERROR, "%s, No SSL/TLS support", __FUNCTION__); 161 | ret = HTTPRES_BAD_REQUEST; 162 | goto leave; 163 | #else 164 | TLS_client(RTMP_TLS_ctx, sb.sb_ssl); 165 | TLS_setfd(sb.sb_ssl, sb.sb_socket); 166 | if (TLS_connect(sb.sb_ssl) < 0) 167 | { 168 | RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__); 169 | ret = HTTPRES_LOST_CONNECTION; 170 | goto leave; 171 | } 172 | #endif 173 | } 174 | #endif 175 | RTMPSockBuf_Send(&sb, sb.sb_buf, i); 176 | 177 | /* set timeout */ 178 | #define HTTP_TIMEOUT 5 179 | { 180 | SET_RCVTIMEO(tv, HTTP_TIMEOUT); 181 | if (setsockopt 182 | (sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv))) 183 | { 184 | RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!", 185 | __FUNCTION__, HTTP_TIMEOUT); 186 | } 187 | } 188 | 189 | sb.sb_size = 0; 190 | sb.sb_timedout = FALSE; 191 | if (RTMPSockBuf_Fill(&sb) < 1) 192 | { 193 | ret = HTTPRES_LOST_CONNECTION; 194 | goto leave; 195 | } 196 | if (strncmp(sb.sb_buf, "HTTP/1", 6)) 197 | { 198 | ret = HTTPRES_BAD_REQUEST; 199 | goto leave; 200 | } 201 | 202 | p1 = strchr(sb.sb_buf, ' '); 203 | rc = atoi(p1 + 1); 204 | http->status = rc; 205 | 206 | if (rc >= 300) 207 | { 208 | if (rc == 304) 209 | { 210 | ret = HTTPRES_OK_NOT_MODIFIED; 211 | goto leave; 212 | } 213 | else if (rc == 404) 214 | ret = HTTPRES_NOT_FOUND; 215 | else if (rc >= 500) 216 | ret = HTTPRES_SERVER_ERROR; 217 | else if (rc >= 400) 218 | ret = HTTPRES_BAD_REQUEST; 219 | else 220 | ret = HTTPRES_REDIRECTED; 221 | } 222 | 223 | p1 = memchr(sb.sb_buf, '\n', sb.sb_size); 224 | if (!p1) 225 | { 226 | ret = HTTPRES_BAD_REQUEST; 227 | goto leave; 228 | } 229 | sb.sb_start = p1 + 1; 230 | sb.sb_size -= sb.sb_start - sb.sb_buf; 231 | 232 | while ((p2 = memchr(sb.sb_start, '\r', sb.sb_size))) 233 | { 234 | if (*sb.sb_start == '\r') 235 | { 236 | sb.sb_start += 2; 237 | sb.sb_size -= 2; 238 | break; 239 | } 240 | else 241 | if (!strncasecmp 242 | (sb.sb_start, "Content-Length: ", sizeof("Content-Length: ") - 1)) 243 | { 244 | flen = atoi(sb.sb_start + sizeof("Content-Length: ") - 1); 245 | } 246 | else 247 | if (!strncasecmp 248 | (sb.sb_start, "Last-Modified: ", sizeof("Last-Modified: ") - 1)) 249 | { 250 | *p2 = '\0'; 251 | strcpy(http->date, sb.sb_start + sizeof("Last-Modified: ") - 1); 252 | } 253 | p2 += 2; 254 | sb.sb_size -= p2 - sb.sb_start; 255 | sb.sb_start = p2; 256 | if (sb.sb_size < 1) 257 | { 258 | if (RTMPSockBuf_Fill(&sb) < 1) 259 | { 260 | ret = HTTPRES_LOST_CONNECTION; 261 | goto leave; 262 | } 263 | } 264 | } 265 | 266 | len_known = flen > 0; 267 | while ((!len_known || flen > 0) && 268 | (sb.sb_size > 0 || RTMPSockBuf_Fill(&sb) > 0)) 269 | { 270 | cb(sb.sb_start, 1, sb.sb_size, http->data); 271 | if (len_known) 272 | flen -= sb.sb_size; 273 | http->size += sb.sb_size; 274 | sb.sb_size = 0; 275 | } 276 | 277 | if (flen > 0) 278 | ret = HTTPRES_LOST_CONNECTION; 279 | 280 | leave: 281 | RTMPSockBuf_Close(&sb); 282 | return ret; 283 | } 284 | 285 | #ifdef CRYPTO 286 | 287 | #define CHUNK 16384 288 | 289 | struct info 290 | { 291 | z_stream *zs; 292 | HMAC_CTX ctx; 293 | int first; 294 | int zlib; 295 | int size; 296 | }; 297 | 298 | static size_t 299 | swfcrunch(void *ptr, size_t size, size_t nmemb, void *stream) 300 | { 301 | struct info *i = stream; 302 | char *p = ptr; 303 | size_t len = size * nmemb; 304 | 305 | if (i->first) 306 | { 307 | i->first = 0; 308 | /* compressed? */ 309 | if (!strncmp(p, "CWS", 3)) 310 | { 311 | *p = 'F'; 312 | i->zlib = 1; 313 | } 314 | HMAC_crunch(i->ctx, (unsigned char *)p, 8); 315 | p += 8; 316 | len -= 8; 317 | i->size = 8; 318 | } 319 | 320 | if (i->zlib) 321 | { 322 | unsigned char out[CHUNK]; 323 | i->zs->next_in = (unsigned char *)p; 324 | i->zs->avail_in = len; 325 | do 326 | { 327 | i->zs->avail_out = CHUNK; 328 | i->zs->next_out = out; 329 | inflate(i->zs, Z_NO_FLUSH); 330 | len = CHUNK - i->zs->avail_out; 331 | i->size += len; 332 | HMAC_crunch(i->ctx, out, len); 333 | } 334 | while (i->zs->avail_out == 0); 335 | } 336 | else 337 | { 338 | i->size += len; 339 | HMAC_crunch(i->ctx, (unsigned char *)p, len); 340 | } 341 | return size * nmemb; 342 | } 343 | 344 | static int tzoff; 345 | static int tzchecked; 346 | 347 | #define JAN02_1980 318340800 348 | 349 | static const char *monthtab[12] = { "Jan", "Feb", "Mar", 350 | "Apr", "May", "Jun", 351 | "Jul", "Aug", "Sep", 352 | "Oct", "Nov", "Dec" 353 | }; 354 | static const char *days[] = 355 | { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; 356 | 357 | /* Parse an HTTP datestamp into Unix time */ 358 | static time_t 359 | make_unix_time(char *s) 360 | { 361 | struct tm time; 362 | int i, ysub = 1900, fmt = 0; 363 | char *month; 364 | char *n; 365 | time_t res; 366 | 367 | if (s[3] != ' ') 368 | { 369 | fmt = 1; 370 | if (s[3] != ',') 371 | ysub = 0; 372 | } 373 | for (n = s; *n; ++n) 374 | if (*n == '-' || *n == ':') 375 | *n = ' '; 376 | 377 | time.tm_mon = 0; 378 | n = strchr(s, ' '); 379 | if (fmt) 380 | { 381 | /* Day, DD-MMM-YYYY HH:MM:SS GMT */ 382 | time.tm_mday = strtol(n + 1, &n, 0); 383 | month = n + 1; 384 | n = strchr(month, ' '); 385 | time.tm_year = strtol(n + 1, &n, 0); 386 | time.tm_hour = strtol(n + 1, &n, 0); 387 | time.tm_min = strtol(n + 1, &n, 0); 388 | time.tm_sec = strtol(n + 1, NULL, 0); 389 | } 390 | else 391 | { 392 | /* Unix ctime() format. Does not conform to HTTP spec. */ 393 | /* Day MMM DD HH:MM:SS YYYY */ 394 | month = n + 1; 395 | n = strchr(month, ' '); 396 | while (isspace(*n)) 397 | n++; 398 | time.tm_mday = strtol(n, &n, 0); 399 | time.tm_hour = strtol(n + 1, &n, 0); 400 | time.tm_min = strtol(n + 1, &n, 0); 401 | time.tm_sec = strtol(n + 1, &n, 0); 402 | time.tm_year = strtol(n + 1, NULL, 0); 403 | } 404 | if (time.tm_year > 100) 405 | time.tm_year -= ysub; 406 | 407 | for (i = 0; i < 12; i++) 408 | if (!strncasecmp(month, monthtab[i], 3)) 409 | { 410 | time.tm_mon = i; 411 | break; 412 | } 413 | time.tm_isdst = 0; /* daylight saving is never in effect in GMT */ 414 | 415 | /* this is normally the value of extern int timezone, but some 416 | * braindead C libraries don't provide it. 417 | */ 418 | if (!tzchecked) 419 | { 420 | struct tm *tc; 421 | time_t then = JAN02_1980; 422 | tc = localtime(&then); 423 | tzoff = (12 - tc->tm_hour) * 3600 + tc->tm_min * 60 + tc->tm_sec; 424 | tzchecked = 1; 425 | } 426 | res = mktime(&time); 427 | /* Unfortunately, mktime() assumes the input is in local time, 428 | * not GMT, so we have to correct it here. 429 | */ 430 | if (res != -1) 431 | res += tzoff; 432 | return res; 433 | } 434 | 435 | /* Convert a Unix time to a network time string 436 | * Weekday, DD-MMM-YYYY HH:MM:SS GMT 437 | */ 438 | static void 439 | strtime(time_t * t, char *s) 440 | { 441 | struct tm *tm; 442 | 443 | tm = gmtime((time_t *) t); 444 | sprintf(s, "%s, %02d %s %d %02d:%02d:%02d GMT", 445 | days[tm->tm_wday], tm->tm_mday, monthtab[tm->tm_mon], 446 | tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec); 447 | } 448 | 449 | #define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf)) 450 | 451 | int 452 | RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, 453 | int age) 454 | { 455 | FILE *f = NULL; 456 | char *path, date[64], cctim[64]; 457 | long pos = 0; 458 | time_t ctim = -1, cnow; 459 | int i, got = 0, ret = 0; 460 | unsigned int hlen; 461 | struct info in = { 0 }; 462 | struct HTTP_ctx http = { 0 }; 463 | HTTPResult httpres; 464 | z_stream zs = { 0 }; 465 | AVal home, hpre; 466 | 467 | date[0] = '\0'; 468 | #ifdef _WIN32 469 | #ifdef XBMC4XBOX 470 | hpre.av_val = "Q:"; 471 | hpre.av_len = 2; 472 | home.av_val = "\\UserData"; 473 | #else 474 | hpre.av_val = getenv("HOMEDRIVE"); 475 | hpre.av_len = strlen(hpre.av_val); 476 | home.av_val = getenv("HOMEPATH"); 477 | #endif 478 | #define DIRSEP "\\" 479 | 480 | #else /* !_WIN32 */ 481 | hpre.av_val = ""; 482 | hpre.av_len = 0; 483 | home.av_val = getenv("HOME"); 484 | #define DIRSEP "/" 485 | #endif 486 | if (!home.av_val) 487 | home.av_val = "."; 488 | home.av_len = strlen(home.av_val); 489 | 490 | /* SWF hash info is cached in a fixed-format file. 491 | * url: 492 | * ctim: HTTP datestamp of when we last checked it. 493 | * date: HTTP datestamp of the SWF's last modification. 494 | * size: SWF size in hex 495 | * hash: SWF hash in hex 496 | * 497 | * These fields must be present in this order. All fields 498 | * besides URL are fixed size. 499 | */ 500 | path = malloc(hpre.av_len + home.av_len + sizeof(DIRSEP ".swfinfo")); 501 | sprintf(path, "%s%s" DIRSEP ".swfinfo", hpre.av_val, home.av_val); 502 | 503 | f = fopen(path, "r+"); 504 | while (f) 505 | { 506 | char buf[4096], *file, *p; 507 | 508 | file = strchr(url, '/'); 509 | if (!file) 510 | break; 511 | file += 2; 512 | file = strchr(file, '/'); 513 | if (!file) 514 | break; 515 | file++; 516 | hlen = file - url; 517 | p = strrchr(file, '/'); 518 | if (p) 519 | file = p; 520 | else 521 | file--; 522 | 523 | while (fgets(buf, sizeof(buf), f)) 524 | { 525 | char *r1; 526 | 527 | got = 0; 528 | 529 | if (strncmp(buf, "url: ", 5)) 530 | continue; 531 | if (strncmp(buf + 5, url, hlen)) 532 | continue; 533 | r1 = strrchr(buf, '/'); 534 | i = strlen(r1); 535 | r1[--i] = '\0'; 536 | if (strncmp(r1, file, i)) 537 | continue; 538 | pos = ftell(f); 539 | while (got < 4 && fgets(buf, sizeof(buf), f)) 540 | { 541 | if (!strncmp(buf, "size: ", 6)) 542 | { 543 | *size = strtol(buf + 6, NULL, 16); 544 | got++; 545 | } 546 | else if (!strncmp(buf, "hash: ", 6)) 547 | { 548 | unsigned char *ptr = hash, *in = (unsigned char *)buf + 6; 549 | int l = strlen((char *)in) - 1; 550 | for (i = 0; i < l; i += 2) 551 | *ptr++ = (HEX2BIN(in[i]) << 4) | HEX2BIN(in[i + 1]); 552 | got++; 553 | } 554 | else if (!strncmp(buf, "date: ", 6)) 555 | { 556 | buf[strlen(buf) - 1] = '\0'; 557 | strncpy(date, buf + 6, sizeof(date)); 558 | got++; 559 | } 560 | else if (!strncmp(buf, "ctim: ", 6)) 561 | { 562 | buf[strlen(buf) - 1] = '\0'; 563 | ctim = make_unix_time(buf + 6); 564 | got++; 565 | } 566 | else if (!strncmp(buf, "url: ", 5)) 567 | break; 568 | } 569 | break; 570 | } 571 | break; 572 | } 573 | 574 | cnow = time(NULL); 575 | /* If we got a cache time, see if it's young enough to use directly */ 576 | if (age && ctim > 0) 577 | { 578 | ctim = cnow - ctim; 579 | ctim /= 3600 * 24; /* seconds to days */ 580 | if (ctim < age) /* ok, it's new enough */ 581 | goto out; 582 | } 583 | 584 | in.first = 1; 585 | HMAC_setup(in.ctx, "Genuine Adobe Flash Player 001", 30); 586 | inflateInit(&zs); 587 | in.zs = &zs; 588 | 589 | http.date = date; 590 | http.data = ∈ 591 | 592 | httpres = HTTP_get(&http, url, swfcrunch); 593 | 594 | inflateEnd(&zs); 595 | 596 | if (httpres != HTTPRES_OK && httpres != HTTPRES_OK_NOT_MODIFIED) 597 | { 598 | ret = -1; 599 | if (httpres == HTTPRES_LOST_CONNECTION) 600 | RTMP_Log(RTMP_LOGERROR, "%s: connection lost while downloading swfurl %s", 601 | __FUNCTION__, url); 602 | else if (httpres == HTTPRES_NOT_FOUND) 603 | RTMP_Log(RTMP_LOGERROR, "%s: swfurl %s not found", __FUNCTION__, url); 604 | else 605 | RTMP_Log(RTMP_LOGERROR, "%s: couldn't contact swfurl %s (HTTP error %d)", 606 | __FUNCTION__, url, http.status); 607 | } 608 | else 609 | { 610 | if (got && pos) 611 | fseek(f, pos, SEEK_SET); 612 | else 613 | { 614 | char *q; 615 | if (!f) 616 | f = fopen(path, "w"); 617 | if (!f) 618 | { 619 | int err = errno; 620 | RTMP_Log(RTMP_LOGERROR, 621 | "%s: couldn't open %s for writing, errno %d (%s)", 622 | __FUNCTION__, path, err, strerror(err)); 623 | ret = -1; 624 | goto out; 625 | } 626 | fseek(f, 0, SEEK_END); 627 | q = strchr(url, '?'); 628 | if (q) 629 | i = q - url; 630 | else 631 | i = strlen(url); 632 | 633 | fprintf(f, "url: %.*s\n", i, url); 634 | } 635 | strtime(&cnow, cctim); 636 | fprintf(f, "ctim: %s\n", cctim); 637 | 638 | if (!in.first) 639 | { 640 | HMAC_finish(in.ctx, hash, hlen); 641 | *size = in.size; 642 | 643 | fprintf(f, "date: %s\n", date); 644 | fprintf(f, "size: %08x\n", in.size); 645 | fprintf(f, "hash: "); 646 | for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 647 | fprintf(f, "%02x", hash[i]); 648 | fprintf(f, "\n"); 649 | } 650 | } 651 | HMAC_close(in.ctx); 652 | out: 653 | free(path); 654 | if (f) 655 | fclose(f); 656 | return ret; 657 | } 658 | #else 659 | int 660 | RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, 661 | int age) 662 | { 663 | return -1; 664 | } 665 | #endif 666 | -------------------------------------------------------------------------------- /librtmp/http.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTMP_HTTP_H__ 2 | #define __RTMP_HTTP_H__ 3 | /* 4 | * Copyright (C) 2010 Howard Chu 5 | * Copyright (C) 2010 Antti Ajanki 6 | * 7 | * This file is part of librtmp. 8 | * 9 | * librtmp is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License as 11 | * published by the Free Software Foundation; either version 2.1, 12 | * or (at your option) any later version. 13 | * 14 | * librtmp is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public License 20 | * along with librtmp see the file COPYING. If not, write to 21 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 | * Boston, MA 02110-1301, USA. 23 | * http://www.gnu.org/copyleft/lgpl.html 24 | */ 25 | 26 | typedef enum { 27 | HTTPRES_OK, /* result OK */ 28 | HTTPRES_OK_NOT_MODIFIED, /* not modified since last request */ 29 | HTTPRES_NOT_FOUND, /* not found */ 30 | HTTPRES_BAD_REQUEST, /* client error */ 31 | HTTPRES_SERVER_ERROR, /* server reported an error */ 32 | HTTPRES_REDIRECTED, /* resource has been moved */ 33 | HTTPRES_LOST_CONNECTION /* connection lost while waiting for data */ 34 | } HTTPResult; 35 | 36 | struct HTTP_ctx { 37 | char *date; 38 | int size; 39 | int status; 40 | void *data; 41 | }; 42 | 43 | typedef size_t (HTTP_read_callback)(void *ptr, size_t size, size_t nmemb, void *stream); 44 | 45 | HTTPResult HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /librtmp/librtmp.3: -------------------------------------------------------------------------------- 1 | .TH LIBRTMP 3 "2011-07-20" "RTMPDump v2.4" 2 | .\" Copyright 2011 Howard Chu. 3 | .\" Copying permitted according to the GNU General Public License V2. 4 | .SH NAME 5 | librtmp \- RTMPDump Real-Time Messaging Protocol API 6 | .SH LIBRARY 7 | RTMPDump RTMP (librtmp, -lrtmp) 8 | .SH SYNOPSIS 9 | .B #include 10 | .SH DESCRIPTION 11 | The Real-Time Messaging Protocol (RTMP) is used for streaming 12 | multimedia content across a TCP/IP network. This API provides most client 13 | functions and a few server functions needed to support RTMP, RTMP tunneled 14 | in HTTP (RTMPT), encrypted RTMP (RTMPE), RTMP over SSL/TLS (RTMPS) and 15 | tunneled variants of these encrypted types (RTMPTE, RTMPTS). The basic 16 | RTMP specification has been published by Adobe but this API was 17 | reverse-engineered without use of the Adobe specification. As such, it may 18 | deviate from any published specifications but it usually duplicates the 19 | actual behavior of the original Adobe clients. 20 | 21 | The RTMPDump software package includes a basic client utility program 22 | in 23 | .BR rtmpdump (1), 24 | some sample servers, and a library used to provide programmatic access 25 | to the RTMP protocol. This man page gives an overview of the RTMP 26 | library routines. These routines are found in the -lrtmp library. Many 27 | other routines are also available, but they are not documented yet. 28 | 29 | The basic interaction is as follows. A session handle is created using 30 | .BR RTMP_Alloc () 31 | and initialized using 32 | .BR RTMP_Init (). 33 | All session parameters are provided using 34 | .BR RTMP_SetupURL (). 35 | The network connection is established using 36 | .BR RTMP_Connect (), 37 | and then the RTMP session is established using 38 | .BR RTMP_ConnectStream (). 39 | The stream is read using 40 | .BR RTMP_Read (). 41 | A client can publish a stream by calling 42 | .BR RTMP_EnableWrite () 43 | before the 44 | .BR RTMP_Connect () 45 | call, and then using 46 | .BR RTMP_Write () 47 | after the session is established. 48 | While a stream is playing it may be paused and unpaused using 49 | .BR RTMP_Pause (). 50 | The stream playback position can be moved using 51 | .BR RTMP_Seek (). 52 | When 53 | .BR RTMP_Read () 54 | returns 0 bytes, the stream is complete and may be closed using 55 | .BR RTMP_Close (). 56 | The session handle is freed using 57 | .BR RTMP_Free (). 58 | 59 | All data is transferred using FLV format. The basic session requires 60 | an RTMP URL. The RTMP URL format is of the form 61 | .nf 62 | rtmp[t][e|s]://hostname[:port][/app[/playpath]] 63 | .fi 64 | 65 | Plain rtmp, as well as tunneled and encrypted sessions are supported. 66 | 67 | Additional options may be specified by appending space-separated 68 | key=value pairs to the URL. Special characters in values may need 69 | to be escaped to prevent misinterpretation by the option parser. 70 | The escape encoding uses a backslash followed by two hexadecimal digits 71 | representing the ASCII value of the character. E.g., spaces must 72 | be escaped as \fB\\20\fP and backslashes must be escaped as \fB\\5c\fP. 73 | .SH OPTIONS 74 | .SS "Network Parameters" 75 | These options define how to connect to the media server. 76 | .TP 77 | .BI socks= host:port 78 | Use the specified SOCKS4 proxy. 79 | .SS "Connection Parameters" 80 | These options define the content of the RTMP Connect request packet. 81 | If correct values are not provided, the media server will reject the 82 | connection attempt. 83 | .TP 84 | .BI app= name 85 | Name of application to connect to on the RTMP server. Overrides 86 | the app in the RTMP URL. Sometimes the librtmp URL parser cannot 87 | determine the app name automatically, so it must be given explicitly 88 | using this option. 89 | .TP 90 | .BI tcUrl= url 91 | URL of the target stream. Defaults to rtmp[t][e|s]://host[:port]/app. 92 | .TP 93 | .BI pageUrl= url 94 | URL of the web page in which the media was embedded. By default no 95 | value will be sent. 96 | .TP 97 | .BI swfUrl= url 98 | URL of the SWF player for the media. By default no value will be sent. 99 | .TP 100 | .BI flashVer= version 101 | Version of the Flash plugin used to run the SWF player. The 102 | default is "LNX 10,0,32,18". 103 | .TP 104 | .BI conn= type:data 105 | Append arbitrary AMF data to the Connect message. The type 106 | must be B for Boolean, N for number, S for string, O for object, or Z 107 | for null. For Booleans the data must be either 0 or 1 for FALSE or TRUE, 108 | respectively. Likewise for Objects the data must be 0 or 1 to end or 109 | begin an object, respectively. Data items in subobjects may be named, by 110 | prefixing the type with 'N' and specifying the name before the value, e.g. 111 | NB:myFlag:1. This option may be used multiple times to construct arbitrary 112 | AMF sequences. E.g. 113 | .nf 114 | conn=B:1 conn=S:authMe conn=O:1 conn=NN:code:1.23 conn=NS:flag:ok conn=O:0 115 | .fi 116 | .SS "Session Parameters" 117 | These options take effect after the Connect request has succeeded. 118 | .TP 119 | .BI playpath= path 120 | Overrides the playpath parsed from the RTMP URL. Sometimes the 121 | rtmpdump URL parser cannot determine the correct playpath 122 | automatically, so it must be given explicitly using this option. 123 | .TP 124 | .BI playlist= 0|1 125 | If the value is 1 or TRUE, issue a set_playlist command before sending the 126 | play command. The playlist will just contain the current playpath. If the 127 | value is 0 or FALSE, the set_playlist command will not be sent. The 128 | default is FALSE. 129 | .TP 130 | .BI live= 0|1 131 | Specify that the media is a live stream. No resuming or seeking in 132 | live streams is possible. 133 | .TP 134 | .BI subscribe= path 135 | Name of live stream to subscribe to. Defaults to 136 | .IR playpath . 137 | .TP 138 | .BI start= num 139 | Start at 140 | .I num 141 | seconds into the stream. Not valid for live streams. 142 | .TP 143 | .BI stop= num 144 | Stop at 145 | .I num 146 | seconds into the stream. 147 | .TP 148 | .BI buffer= num 149 | Set buffer time to 150 | .I num 151 | milliseconds. The default is 30000. 152 | .TP 153 | .BI timeout= num 154 | Timeout the session after 155 | .I num 156 | seconds without receiving any data from the server. The default is 120. 157 | .SS "Security Parameters" 158 | These options handle additional authentication requests from the server. 159 | .TP 160 | .BI token= key 161 | Key for SecureToken response, used if the server requires SecureToken 162 | authentication. 163 | .TP 164 | .BI jtv= JSON 165 | JSON token used by legacy Justin.tv servers. Invokes NetStream.Authenticate.UsherToken 166 | .TP 167 | .BI swfVfy= 0|1 168 | If the value is 1 or TRUE, the SWF player is retrieved from the 169 | specified 170 | .I swfUrl 171 | for performing SWF Verification. The SWF hash and size (used in the 172 | verification step) are computed automatically. Also the SWF information is 173 | cached in a 174 | .I .swfinfo 175 | file in the user's home directory, so that it doesn't need to be retrieved 176 | and recalculated every time. The .swfinfo file records 177 | the SWF URL, the time it was fetched, the modification timestamp of the SWF 178 | file, its size, and its hash. By default, the cached info will be used 179 | for 30 days before re-checking. 180 | .TP 181 | .BI swfAge= days 182 | Specify how many days to use the cached SWF info before re-checking. Use 183 | 0 to always check the SWF URL. Note that if the check shows that the 184 | SWF file has the same modification timestamp as before, it will not be 185 | retrieved again. 186 | .SH EXAMPLES 187 | An example character string suitable for use with 188 | .BR RTMP_SetupURL (): 189 | .nf 190 | "rtmp://flashserver:1935/ondemand/thefile swfUrl=http://flashserver/player.swf swfVfy=1" 191 | .fi 192 | .SH ENVIRONMENT 193 | .TP 194 | .B HOME 195 | The value of 196 | .RB $ HOME 197 | is used as the location for the 198 | .I .swfinfo 199 | file. 200 | .SH FILES 201 | .TP 202 | .I $HOME/.swfinfo 203 | Cache of SWF Verification information 204 | .SH "SEE ALSO" 205 | .BR rtmpdump (1), 206 | .BR rtmpgw (8) 207 | .SH AUTHORS 208 | Andrej Stepanchuk, Howard Chu, The Flvstreamer Team 209 | .br 210 | 211 | -------------------------------------------------------------------------------- /librtmp/librtmp.3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | LIBRTMP(3): 4 | 5 | 6 | 8 | 9 | 11 |
LIBRTMP(3)LIBRTMP(3) 7 |
RTMPDump v2.42011-07-20LIBRTMP(3) 10 |


    12 | 14 |
15 | 16 |

NAME

    17 | librtmp − RTMPDump Real-Time Messaging Protocol API 18 |
19 | 20 |

LIBRARY

    21 | RTMPDump RTMP (librtmp, -lrtmp) 22 |
23 | 24 |

SYNOPSIS

    25 | #include <librtmp/rtmp.h> 26 |
27 | 28 |

DESCRIPTION

    29 | The Real-Time Messaging Protocol (RTMP) is used for streaming 30 | multimedia content across a TCP/IP network. This API provides most client 31 | functions and a few server functions needed to support RTMP, RTMP tunneled 32 | in HTTP (RTMPT), encrypted RTMP (RTMPE), RTMP over SSL/TLS (RTMPS) and 33 | tunneled variants of these encrypted types (RTMPTE, RTMPTS). The basic 34 | RTMP specification has been published by Adobe but this API was 35 | reverse-engineered without use of the Adobe specification. As such, it may 36 | deviate from any published specifications but it usually duplicates the 37 | actual behavior of the original Adobe clients. 38 |

    39 | The RTMPDump software package includes a basic client utility program 40 | in 41 | rtmpdump(1), 42 | some sample servers, and a library used to provide programmatic access 43 | to the RTMP protocol. This man page gives an overview of the RTMP 44 | library routines. These routines are found in the -lrtmp library. Many 45 | other routines are also available, but they are not documented yet. 46 |

    47 | The basic interaction is as follows. A session handle is created using 48 | RTMP_Alloc() 49 | and initialized using 50 | RTMP_Init(). 51 | All session parameters are provided using 52 | RTMP_SetupURL(). 53 | The network connection is established using 54 | RTMP_Connect(), 55 | and then the RTMP session is established using 56 | RTMP_ConnectStream(). 57 | The stream is read using 58 | RTMP_Read(). 59 | A client can publish a stream by calling 60 | RTMP_EnableWrite() 61 | before the 62 | RTMP_Connect() 63 | call, and then using 64 | RTMP_Write() 65 | after the session is established. 66 | While a stream is playing it may be paused and unpaused using 67 | RTMP_Pause(). 68 | The stream playback position can be moved using 69 | RTMP_Seek(). 70 | When 71 | RTMP_Read() 72 | returns 0 bytes, the stream is complete and may be closed using 73 | RTMP_Close(). 74 | The session handle is freed using 75 | RTMP_Free(). 76 |

    77 | All data is transferred using FLV format. The basic session requires 78 | an RTMP URL. The RTMP URL format is of the form 79 |

     80 |   rtmp[t][e|s]://hostname[:port][/app[/playpath]]
     81 | 
    82 |

    83 | Plain rtmp, as well as tunneled and encrypted sessions are supported. 84 |

    85 | Additional options may be specified by appending space-separated 86 | key=value pairs to the URL. Special characters in values may need 87 | to be escaped to prevent misinterpretation by the option parser. 88 | The escape encoding uses a backslash followed by two hexadecimal digits 89 | representing the ASCII value of the character. E.g., spaces must 90 | be escaped as \20 and backslashes must be escaped as \5c. 91 |

92 | 93 |

OPTIONS

    94 |
95 | 96 |

Network Parameters

    97 | These options define how to connect to the media server. 98 |

    99 |

    100 | socks=host:port 101 |
    102 | Use the specified SOCKS4 proxy. 103 |
    104 |
105 | 106 |

Connection Parameters

    107 | These options define the content of the RTMP Connect request packet. 108 | If correct values are not provided, the media server will reject the 109 | connection attempt. 110 |

    111 |

    112 | app=name 113 |
    114 | Name of application to connect to on the RTMP server. Overrides 115 | the app in the RTMP URL. Sometimes the librtmp URL parser cannot 116 | determine the app name automatically, so it must be given explicitly 117 | using this option. 118 |
    119 |

    120 |

    121 | tcUrl=url 122 |
    123 | URL of the target stream. Defaults to rtmp[t][e|s]://host[:port]/app. 124 |
    125 |

    126 |

    127 | pageUrl=url 128 |
    129 | URL of the web page in which the media was embedded. By default no 130 | value will be sent. 131 |
    132 |

    133 |

    134 | swfUrl=url 135 |
    136 | URL of the SWF player for the media. By default no value will be sent. 137 |
    138 |

    139 |

    140 | flashVer=version 141 |
    142 | Version of the Flash plugin used to run the SWF player. The 143 | default is "LNX 10,0,32,18". 144 |
    145 |

    146 |

    147 | conn=type:data 148 |
    149 | Append arbitrary AMF data to the Connect message. The type 150 | must be B for Boolean, N for number, S for string, O for object, or Z 151 | for null. For Booleans the data must be either 0 or 1 for FALSE or TRUE, 152 | respectively. Likewise for Objects the data must be 0 or 1 to end or 153 | begin an object, respectively. Data items in subobjects may be named, by 154 | prefixing the type with 'N' and specifying the name before the value, e.g. 155 | NB:myFlag:1. This option may be used multiple times to construct arbitrary 156 | AMF sequences. E.g. 157 |
    158 |   conn=B:1 conn=S:authMe conn=O:1 conn=NN:code:1.23 conn=NS:flag:ok conn=O:0
    159 | 
    160 |
    161 |
162 | 163 |

Session Parameters

    164 | These options take effect after the Connect request has succeeded. 165 |

    166 |

    167 | playpath=path 168 |
    169 | Overrides the playpath parsed from the RTMP URL. Sometimes the 170 | rtmpdump URL parser cannot determine the correct playpath 171 | automatically, so it must be given explicitly using this option. 172 |
    173 |

    174 |

    175 | playlist=0|1 176 |
    177 | If the value is 1 or TRUE, issue a set_playlist command before sending the 178 | play command. The playlist will just contain the current playpath. If the 179 | value is 0 or FALSE, the set_playlist command will not be sent. The 180 | default is FALSE. 181 |
    182 |

    183 |

    184 | live=0|1 185 |
    186 | Specify that the media is a live stream. No resuming or seeking in 187 | live streams is possible. 188 |
    189 |

    190 |

    191 | subscribe=path 192 |
    193 | Name of live stream to subscribe to. Defaults to 194 | playpath. 195 |
    196 |

    197 |

    198 | start=num 199 |
    200 | Start at 201 | num 202 | seconds into the stream. Not valid for live streams. 203 |
    204 |

    205 |

    206 | stop=num 207 |
    208 | Stop at 209 | num 210 | seconds into the stream. 211 |
    212 |

    213 |

    214 | buffer=num 215 |
    216 | Set buffer time to 217 | num 218 | milliseconds. The default is 30000. 219 |
    220 |

    221 |

    222 | timeout=num 223 |
    224 | Timeout the session after 225 | num 226 | seconds without receiving any data from the server. The default is 120. 227 |
    228 |
229 | 230 |

Security Parameters

    231 | These options handle additional authentication requests from the server. 232 |

    233 |

    234 | token=key 235 |
    236 | Key for SecureToken response, used if the server requires SecureToken 237 | authentication. 238 |
    239 |

    240 |

    241 | jtv=JSON 242 |
    243 | JSON token used by legacy Justin.tv servers. Invokes NetStream.Authenticate.UsherToken 244 |
    245 |

    246 |

    247 | swfVfy=0|1 248 |
    249 | If the value is 1 or TRUE, the SWF player is retrieved from the 250 | specified 251 | swfUrl 252 | for performing SWF Verification. The SWF hash and size (used in the 253 | verification step) are computed automatically. Also the SWF information is 254 | cached in a 255 | .swfinfo 256 | file in the user's home directory, so that it doesn't need to be retrieved 257 | and recalculated every time. The .swfinfo file records 258 | the SWF URL, the time it was fetched, the modification timestamp of the SWF 259 | file, its size, and its hash. By default, the cached info will be used 260 | for 30 days before re-checking. 261 |
    262 |

    263 |

    264 | swfAge=days 265 |
    266 | Specify how many days to use the cached SWF info before re-checking. Use 267 | 0 to always check the SWF URL. Note that if the check shows that the 268 | SWF file has the same modification timestamp as before, it will not be 269 | retrieved again. 270 |
    271 |
272 | 273 |

EXAMPLES

    274 | An example character string suitable for use with 275 | RTMP_SetupURL(): 276 |
    277 |   "rtmp://flashserver:1935/ondemand/thefile swfUrl=http://flashserver/player.swf swfVfy=1"
    278 | 
    279 |
280 | 281 |

ENVIRONMENT

    282 |

    283 |

    284 | HOME 285 |
    286 | The value of 287 | $HOME 288 | is used as the location for the 289 | .swfinfo 290 | file. 291 |
    292 |
293 | 294 |

FILES

    295 |

    296 |

    297 | $HOME/.swfinfo 298 |
    299 | Cache of SWF Verification information 300 |
    301 |
302 | 303 |

SEE ALSO

307 | 308 |

AUTHORS

313 | -------------------------------------------------------------------------------- /librtmp/librtmp.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=${prefix} 3 | libdir=@libdir@ 4 | incdir=${prefix}/include 5 | 6 | Name: librtmp 7 | Description: RTMP implementation 8 | Version: @VERSION@ 9 | Requires: @CRYPTO_REQ@ 10 | URL: http://rtmpdump.mplayerhq.hu 11 | Libs: -L${libdir} -lrtmp -lz @PUBLIC_LIBS@ 12 | Libs.private: @PRIVATE_LIBS@ 13 | Cflags: -I${incdir} 14 | -------------------------------------------------------------------------------- /librtmp/parseurl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Andrej Stepanchuk 3 | * Copyright (C) 2009-2010 Howard Chu 4 | * 5 | * This file is part of librtmp. 6 | * 7 | * librtmp is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1, 10 | * or (at your option) any later version. 11 | * 12 | * librtmp is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with librtmp see the file COPYING. If not, write to 19 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | * http://www.gnu.org/copyleft/lgpl.html 22 | */ 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include "rtmp_sys.h" 31 | #include "rtmp_log.h" 32 | 33 | int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, 34 | AVal *playpath, AVal *app) 35 | { 36 | char *p, *end, *col, *ques, *slash; 37 | 38 | RTMP_Log(RTMP_LOGDEBUG, "Parsing..."); 39 | 40 | *protocol = RTMP_PROTOCOL_RTMP; 41 | *port = 0; 42 | playpath->av_len = 0; 43 | playpath->av_val = NULL; 44 | app->av_len = 0; 45 | app->av_val = NULL; 46 | 47 | /* Old School Parsing */ 48 | 49 | /* look for usual :// pattern */ 50 | p = strstr(url, "://"); 51 | if(!p) { 52 | RTMP_Log(RTMP_LOGERROR, "RTMP URL: No :// in url!"); 53 | return FALSE; 54 | } 55 | { 56 | int len = (int)(p-url); 57 | 58 | if(len == 4 && strncasecmp(url, "rtmp", 4)==0) 59 | *protocol = RTMP_PROTOCOL_RTMP; 60 | else if(len == 5 && strncasecmp(url, "rtmpt", 5)==0) 61 | *protocol = RTMP_PROTOCOL_RTMPT; 62 | else if(len == 5 && strncasecmp(url, "rtmps", 5)==0) 63 | *protocol = RTMP_PROTOCOL_RTMPS; 64 | else if(len == 5 && strncasecmp(url, "rtmpe", 5)==0) 65 | *protocol = RTMP_PROTOCOL_RTMPE; 66 | else if(len == 5 && strncasecmp(url, "rtmfp", 5)==0) 67 | *protocol = RTMP_PROTOCOL_RTMFP; 68 | else if(len == 6 && strncasecmp(url, "rtmpte", 6)==0) 69 | *protocol = RTMP_PROTOCOL_RTMPTE; 70 | else if(len == 6 && strncasecmp(url, "rtmpts", 6)==0) 71 | *protocol = RTMP_PROTOCOL_RTMPTS; 72 | else { 73 | RTMP_Log(RTMP_LOGWARNING, "Unknown protocol!\n"); 74 | goto parsehost; 75 | } 76 | } 77 | 78 | RTMP_Log(RTMP_LOGDEBUG, "Parsed protocol: %d", *protocol); 79 | 80 | parsehost: 81 | /* let's get the hostname */ 82 | p+=3; 83 | 84 | /* check for sudden death */ 85 | if(*p==0) { 86 | RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!"); 87 | return FALSE; 88 | } 89 | 90 | end = p + strlen(p); 91 | col = strchr(p, ':'); 92 | ques = strchr(p, '?'); 93 | slash = strchr(p, '/'); 94 | 95 | { 96 | int hostlen; 97 | if(slash) 98 | hostlen = slash - p; 99 | else 100 | hostlen = end - p; 101 | if(col && col -p < hostlen) 102 | hostlen = col - p; 103 | 104 | if(hostlen < 256) { 105 | host->av_val = p; 106 | host->av_len = hostlen; 107 | RTMP_Log(RTMP_LOGDEBUG, "Parsed host : %.*s", hostlen, host->av_val); 108 | } else { 109 | RTMP_Log(RTMP_LOGWARNING, "Hostname exceeds 255 characters!"); 110 | } 111 | 112 | p+=hostlen; 113 | } 114 | 115 | /* get the port number if available */ 116 | if(*p == ':') { 117 | unsigned int p2; 118 | p++; 119 | p2 = atoi(p); 120 | if(p2 > 65535) { 121 | RTMP_Log(RTMP_LOGWARNING, "Invalid port number!"); 122 | } else { 123 | *port = p2; 124 | } 125 | } 126 | 127 | if(!slash) { 128 | RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!"); 129 | return TRUE; 130 | } 131 | p = slash+1; 132 | 133 | { 134 | /* parse application 135 | * 136 | * rtmp://host[:port]/app[/appinstance][/...] 137 | * application = app[/appinstance] 138 | */ 139 | 140 | char *slash2, *slash3 = NULL, *slash4 = NULL; 141 | int applen, appnamelen; 142 | 143 | slash2 = strchr(p, '/'); 144 | if(slash2) 145 | slash3 = strchr(slash2+1, '/'); 146 | if(slash3) 147 | slash4 = strchr(slash3+1, '/'); 148 | 149 | applen = end-p; /* ondemand, pass all parameters as app */ 150 | appnamelen = applen; /* ondemand length */ 151 | 152 | if(ques && strstr(p, "slist=")) { /* whatever it is, the '?' and slist= means we need to use everything as app and parse plapath from slist= */ 153 | appnamelen = ques-p; 154 | } 155 | else if(strncmp(p, "ondemand/", 9)==0) { 156 | /* app = ondemand/foobar, only pass app=ondemand */ 157 | applen = 8; 158 | appnamelen = 8; 159 | } 160 | else { /* app!=ondemand, so app is app[/appinstance] */ 161 | if(slash4) 162 | appnamelen = slash4-p; 163 | else if(slash3) 164 | appnamelen = slash3-p; 165 | else if(slash2) 166 | appnamelen = slash2-p; 167 | 168 | applen = appnamelen; 169 | } 170 | 171 | app->av_val = p; 172 | app->av_len = applen; 173 | RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p); 174 | 175 | p += appnamelen; 176 | } 177 | 178 | if (*p == '/') 179 | p++; 180 | 181 | if (end-p) { 182 | AVal av = {p, end-p}; 183 | RTMP_ParsePlaypath(&av, playpath); 184 | } 185 | 186 | return TRUE; 187 | } 188 | 189 | /* 190 | * Extracts playpath from RTMP URL. playpath is the file part of the 191 | * URL, i.e. the part that comes after rtmp://host:port/app/ 192 | * 193 | * Returns the stream name in a format understood by FMS. The name is 194 | * the playpath part of the URL with formatting depending on the stream 195 | * type: 196 | * 197 | * mp4 streams: prepend "mp4:", remove extension 198 | * mp3 streams: prepend "mp3:", remove extension 199 | * flv streams: remove extension 200 | */ 201 | void RTMP_ParsePlaypath(AVal *in, AVal *out) { 202 | int addMP4 = 0; 203 | int addMP3 = 0; 204 | int subExt = 0; 205 | const char *playpath = in->av_val; 206 | const char *temp, *q, *ext = NULL; 207 | const char *ppstart = playpath; 208 | char *streamname, *destptr, *p; 209 | 210 | int pplen = in->av_len; 211 | 212 | out->av_val = NULL; 213 | out->av_len = 0; 214 | 215 | if ((*ppstart == '?') && 216 | (temp=strstr(ppstart, "slist=")) != 0) { 217 | ppstart = temp+6; 218 | pplen = strlen(ppstart); 219 | 220 | temp = strchr(ppstart, '&'); 221 | if (temp) { 222 | pplen = temp-ppstart; 223 | } 224 | } 225 | 226 | q = strchr(ppstart, '?'); 227 | if (pplen >= 4) { 228 | if (q) 229 | ext = q-4; 230 | else 231 | ext = &ppstart[pplen-4]; 232 | if ((strncmp(ext, ".f4v", 4) == 0) || 233 | (strncmp(ext, ".mp4", 4) == 0)) { 234 | addMP4 = 1; 235 | subExt = 1; 236 | /* Only remove .flv from rtmp URL, not slist params */ 237 | } else if ((ppstart == playpath) && 238 | (strncmp(ext, ".flv", 4) == 0)) { 239 | subExt = 1; 240 | } else if (strncmp(ext, ".mp3", 4) == 0) { 241 | addMP3 = 1; 242 | subExt = 1; 243 | } 244 | } 245 | 246 | streamname = (char *)malloc((pplen+4+1)*sizeof(char)); 247 | if (!streamname) 248 | return; 249 | 250 | destptr = streamname; 251 | if (addMP4) { 252 | if (strncmp(ppstart, "mp4:", 4)) { 253 | strcpy(destptr, "mp4:"); 254 | destptr += 4; 255 | } else { 256 | subExt = 0; 257 | } 258 | } else if (addMP3) { 259 | if (strncmp(ppstart, "mp3:", 4)) { 260 | strcpy(destptr, "mp3:"); 261 | destptr += 4; 262 | } else { 263 | subExt = 0; 264 | } 265 | } 266 | 267 | for (p=(char *)ppstart; pplen >0;) { 268 | /* skip extension */ 269 | if (subExt && p == ext) { 270 | p += 4; 271 | pplen -= 4; 272 | continue; 273 | } 274 | if (*p == '%') { 275 | unsigned int c; 276 | sscanf(p+1, "%02x", &c); 277 | *destptr++ = c; 278 | pplen -= 3; 279 | p += 3; 280 | } else { 281 | *destptr++ = *p++; 282 | pplen--; 283 | } 284 | } 285 | *destptr = '\0'; 286 | 287 | out->av_val = streamname; 288 | out->av_len = destptr - streamname; 289 | } 290 | -------------------------------------------------------------------------------- /librtmp/rtmp.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTMP_H__ 2 | #define __RTMP_H__ 3 | /* 4 | * Copyright (C) 2005-2008 Team XBMC 5 | * http://www.xbmc.org 6 | * Copyright (C) 2008-2009 Andrej Stepanchuk 7 | * Copyright (C) 2009-2010 Howard Chu 8 | * 9 | * This file is part of librtmp. 10 | * 11 | * librtmp is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU Lesser General Public License as 13 | * published by the Free Software Foundation; either version 2.1, 14 | * or (at your option) any later version. 15 | * 16 | * librtmp is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public License 22 | * along with librtmp see the file COPYING. If not, write to 23 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301, USA. 25 | * http://www.gnu.org/copyleft/lgpl.html 26 | */ 27 | 28 | #if !defined(NO_CRYPTO) && !defined(CRYPTO) 29 | #define CRYPTO 30 | #endif 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include "amf.h" 37 | 38 | #ifdef __cplusplus 39 | extern "C" 40 | { 41 | #endif 42 | 43 | #define RTMP_LIB_VERSION 0x020300 /* 2.3 */ 44 | 45 | #define RTMP_FEATURE_HTTP 0x01 46 | #define RTMP_FEATURE_ENC 0x02 47 | #define RTMP_FEATURE_SSL 0x04 48 | #define RTMP_FEATURE_MFP 0x08 /* not yet supported */ 49 | #define RTMP_FEATURE_WRITE 0x10 /* publish, not play */ 50 | #define RTMP_FEATURE_HTTP2 0x20 /* server-side rtmpt */ 51 | 52 | #define RTMP_PROTOCOL_UNDEFINED -1 53 | #define RTMP_PROTOCOL_RTMP 0 54 | #define RTMP_PROTOCOL_RTMPE RTMP_FEATURE_ENC 55 | #define RTMP_PROTOCOL_RTMPT RTMP_FEATURE_HTTP 56 | #define RTMP_PROTOCOL_RTMPS RTMP_FEATURE_SSL 57 | #define RTMP_PROTOCOL_RTMPTE (RTMP_FEATURE_HTTP|RTMP_FEATURE_ENC) 58 | #define RTMP_PROTOCOL_RTMPTS (RTMP_FEATURE_HTTP|RTMP_FEATURE_SSL) 59 | #define RTMP_PROTOCOL_RTMFP RTMP_FEATURE_MFP 60 | 61 | #define RTMP_DEFAULT_CHUNKSIZE 128 62 | 63 | /* needs to fit largest number of bytes recv() may return */ 64 | #define RTMP_BUFFER_CACHE_SIZE (16*1024) 65 | 66 | #define RTMP_CHANNELS 65600 67 | 68 | extern const char RTMPProtocolStringsLower[][7]; 69 | extern const AVal RTMP_DefaultFlashVer; 70 | extern int RTMP_ctrlC; 71 | 72 | uint32_t RTMP_GetTime(void); 73 | 74 | /* RTMP_PACKET_TYPE_... 0x00 */ 75 | #define RTMP_PACKET_TYPE_CHUNK_SIZE 0x01 76 | /* RTMP_PACKET_TYPE_... 0x02 */ 77 | #define RTMP_PACKET_TYPE_BYTES_READ_REPORT 0x03 78 | #define RTMP_PACKET_TYPE_CONTROL 0x04 79 | #define RTMP_PACKET_TYPE_SERVER_BW 0x05 80 | #define RTMP_PACKET_TYPE_CLIENT_BW 0x06 81 | /* RTMP_PACKET_TYPE_... 0x07 */ 82 | #define RTMP_PACKET_TYPE_AUDIO 0x08 83 | #define RTMP_PACKET_TYPE_VIDEO 0x09 84 | /* RTMP_PACKET_TYPE_... 0x0A */ 85 | /* RTMP_PACKET_TYPE_... 0x0B */ 86 | /* RTMP_PACKET_TYPE_... 0x0C */ 87 | /* RTMP_PACKET_TYPE_... 0x0D */ 88 | /* RTMP_PACKET_TYPE_... 0x0E */ 89 | #define RTMP_PACKET_TYPE_FLEX_STREAM_SEND 0x0F 90 | #define RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT 0x10 91 | #define RTMP_PACKET_TYPE_FLEX_MESSAGE 0x11 92 | #define RTMP_PACKET_TYPE_INFO 0x12 93 | #define RTMP_PACKET_TYPE_SHARED_OBJECT 0x13 94 | #define RTMP_PACKET_TYPE_INVOKE 0x14 95 | /* RTMP_PACKET_TYPE_... 0x15 */ 96 | #define RTMP_PACKET_TYPE_FLASH_VIDEO 0x16 97 | 98 | #define RTMP_MAX_HEADER_SIZE 18 99 | 100 | #define RTMP_PACKET_SIZE_LARGE 0 101 | #define RTMP_PACKET_SIZE_MEDIUM 1 102 | #define RTMP_PACKET_SIZE_SMALL 2 103 | #define RTMP_PACKET_SIZE_MINIMUM 3 104 | 105 | typedef struct RTMPChunk 106 | { 107 | int c_headerSize; 108 | int c_chunkSize; 109 | char *c_chunk; 110 | char c_header[RTMP_MAX_HEADER_SIZE]; 111 | } RTMPChunk; 112 | 113 | typedef struct RTMPPacket 114 | { 115 | uint8_t m_headerType; 116 | uint8_t m_packetType; 117 | uint8_t m_hasAbsTimestamp; /* timestamp absolute or relative? */ 118 | int m_nChannel; 119 | uint32_t m_nTimeStamp; /* timestamp */ 120 | int32_t m_nInfoField2; /* last 4 bytes in a long header */ 121 | uint32_t m_nBodySize; 122 | uint32_t m_nBytesRead; 123 | RTMPChunk *m_chunk; 124 | char *m_body; 125 | } RTMPPacket; 126 | 127 | typedef struct RTMPSockBuf 128 | { 129 | int sb_socket; 130 | int sb_size; /* number of unprocessed bytes in buffer */ 131 | char *sb_start; /* pointer into sb_pBuffer of next byte to process */ 132 | char sb_buf[RTMP_BUFFER_CACHE_SIZE]; /* data read from socket */ 133 | int sb_timedout; 134 | void *sb_ssl; 135 | } RTMPSockBuf; 136 | 137 | void RTMPPacket_Reset(RTMPPacket *p); 138 | void RTMPPacket_Dump(RTMPPacket *p); 139 | int RTMPPacket_Alloc(RTMPPacket *p, uint32_t nSize); 140 | void RTMPPacket_Free(RTMPPacket *p); 141 | 142 | #define RTMPPacket_IsReady(a) ((a)->m_nBytesRead == (a)->m_nBodySize) 143 | 144 | typedef struct RTMP_LNK 145 | { 146 | AVal hostname; 147 | AVal sockshost; 148 | 149 | AVal playpath0; /* parsed from URL */ 150 | AVal playpath; /* passed in explicitly */ 151 | AVal tcUrl; 152 | AVal swfUrl; 153 | AVal pageUrl; 154 | AVal app; 155 | AVal auth; 156 | AVal flashVer; 157 | AVal subscribepath; 158 | AVal usherToken; 159 | AVal token; 160 | AVal pubUser; 161 | AVal pubPasswd; 162 | AMFObject extras; 163 | int edepth; 164 | 165 | int seekTime; 166 | int stopTime; 167 | 168 | #define RTMP_LF_AUTH 0x0001 /* using auth param */ 169 | #define RTMP_LF_LIVE 0x0002 /* stream is live */ 170 | #define RTMP_LF_SWFV 0x0004 /* do SWF verification */ 171 | #define RTMP_LF_PLST 0x0008 /* send playlist before play */ 172 | #define RTMP_LF_BUFX 0x0010 /* toggle stream on BufferEmpty msg */ 173 | #define RTMP_LF_FTCU 0x0020 /* free tcUrl on close */ 174 | #define RTMP_LF_FAPU 0x0040 /* free app on close */ 175 | int lFlags; 176 | 177 | int swfAge; 178 | 179 | int protocol; 180 | int timeout; /* connection timeout in seconds */ 181 | 182 | int pFlags; /* unused, but kept to avoid breaking ABI */ 183 | 184 | unsigned short socksport; 185 | unsigned short port; 186 | 187 | #ifdef CRYPTO 188 | #define RTMP_SWF_HASHLEN 32 189 | void *dh; /* for encryption */ 190 | void *rc4keyIn; 191 | void *rc4keyOut; 192 | 193 | uint32_t SWFSize; 194 | uint8_t SWFHash[RTMP_SWF_HASHLEN]; 195 | char SWFVerificationResponse[RTMP_SWF_HASHLEN+10]; 196 | #endif 197 | } RTMP_LNK; 198 | 199 | /* state for read() wrapper */ 200 | typedef struct RTMP_READ 201 | { 202 | char *buf; 203 | char *bufpos; 204 | unsigned int buflen; 205 | uint32_t timestamp; 206 | uint8_t dataType; 207 | uint8_t flags; 208 | #define RTMP_READ_HEADER 0x01 209 | #define RTMP_READ_RESUME 0x02 210 | #define RTMP_READ_NO_IGNORE 0x04 211 | #define RTMP_READ_GOTKF 0x08 212 | #define RTMP_READ_GOTFLVK 0x10 213 | #define RTMP_READ_SEEKING 0x20 214 | int8_t status; 215 | #define RTMP_READ_COMPLETE -3 216 | #define RTMP_READ_ERROR -2 217 | #define RTMP_READ_EOF -1 218 | #define RTMP_READ_IGNORE 0 219 | 220 | /* if bResume == TRUE */ 221 | uint8_t initialFrameType; 222 | uint32_t nResumeTS; 223 | char *metaHeader; 224 | char *initialFrame; 225 | uint32_t nMetaHeaderSize; 226 | uint32_t nInitialFrameSize; 227 | uint32_t nIgnoredFrameCounter; 228 | uint32_t nIgnoredFlvFrameCounter; 229 | } RTMP_READ; 230 | 231 | typedef struct RTMP_METHOD 232 | { 233 | AVal name; 234 | int num; 235 | } RTMP_METHOD; 236 | 237 | typedef struct RTMP 238 | { 239 | int m_inChunkSize; 240 | int m_outChunkSize; 241 | int m_nBWCheckCounter; 242 | int m_nBytesIn; 243 | int m_nBytesInSent; 244 | int m_nBufferMS; 245 | int m_stream_id; /* returned in _result from createStream */ 246 | int m_mediaChannel; 247 | uint32_t m_mediaStamp; 248 | uint32_t m_pauseStamp; 249 | int m_pausing; 250 | int m_nServerBW; 251 | int m_nClientBW; 252 | uint8_t m_nClientBW2; 253 | uint8_t m_bPlaying; 254 | uint8_t m_bSendEncoding; 255 | uint8_t m_bSendCounter; 256 | 257 | int m_numInvokes; 258 | int m_numCalls; 259 | RTMP_METHOD *m_methodCalls; /* remote method calls queue */ 260 | 261 | int m_channelsAllocatedIn; 262 | int m_channelsAllocatedOut; 263 | RTMPPacket **m_vecChannelsIn; 264 | RTMPPacket **m_vecChannelsOut; 265 | int *m_channelTimestamp; /* abs timestamp of last packet */ 266 | 267 | double m_fAudioCodecs; /* audioCodecs for the connect packet */ 268 | double m_fVideoCodecs; /* videoCodecs for the connect packet */ 269 | double m_fEncoding; /* AMF0 or AMF3 */ 270 | 271 | double m_fDuration; /* duration of stream in seconds */ 272 | 273 | int m_msgCounter; /* RTMPT stuff */ 274 | int m_polling; 275 | int m_resplen; 276 | int m_unackd; 277 | AVal m_clientID; 278 | 279 | RTMP_READ m_read; 280 | RTMPPacket m_write; 281 | RTMPSockBuf m_sb; 282 | RTMP_LNK Link; 283 | } RTMP; 284 | 285 | int RTMP_ParseURL(const char *url, int *protocol, AVal *host, 286 | unsigned int *port, AVal *playpath, AVal *app); 287 | 288 | void RTMP_ParsePlaypath(AVal *in, AVal *out); 289 | void RTMP_SetBufferMS(RTMP *r, int size); 290 | void RTMP_UpdateBufferMS(RTMP *r); 291 | 292 | int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg); 293 | int RTMP_SetupURL(RTMP *r, char *url); 294 | void RTMP_SetupStream(RTMP *r, int protocol, 295 | AVal *hostname, 296 | unsigned int port, 297 | AVal *sockshost, 298 | AVal *playpath, 299 | AVal *tcUrl, 300 | AVal *swfUrl, 301 | AVal *pageUrl, 302 | AVal *app, 303 | AVal *auth, 304 | AVal *swfSHA256Hash, 305 | uint32_t swfSize, 306 | AVal *flashVer, 307 | AVal *subscribepath, 308 | AVal *usherToken, 309 | int dStart, 310 | int dStop, int bLiveStream, long int timeout); 311 | 312 | int RTMP_Connect(RTMP *r, RTMPPacket *cp); 313 | struct sockaddr; 314 | int RTMP_Connect0(RTMP *r, struct sockaddr *svc); 315 | int RTMP_Connect1(RTMP *r, RTMPPacket *cp); 316 | int RTMP_Serve(RTMP *r); 317 | int RTMP_TLS_Accept(RTMP *r, void *ctx); 318 | 319 | int RTMP_ReadPacket(RTMP *r, RTMPPacket *packet); 320 | int RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue); 321 | int RTMP_SendChunk(RTMP *r, RTMPChunk *chunk); 322 | int RTMP_IsConnected(RTMP *r); 323 | int RTMP_Socket(RTMP *r); 324 | int RTMP_IsTimedout(RTMP *r); 325 | double RTMP_GetDuration(RTMP *r); 326 | int RTMP_ToggleStream(RTMP *r); 327 | 328 | int RTMP_ConnectStream(RTMP *r, int seekTime); 329 | int RTMP_ReconnectStream(RTMP *r, int seekTime); 330 | void RTMP_DeleteStream(RTMP *r); 331 | int RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet); 332 | int RTMP_ClientPacket(RTMP *r, RTMPPacket *packet); 333 | 334 | void RTMP_Init(RTMP *r); 335 | void RTMP_Close(RTMP *r); 336 | RTMP *RTMP_Alloc(void); 337 | void RTMP_Free(RTMP *r); 338 | void RTMP_EnableWrite(RTMP *r); 339 | 340 | void *RTMP_TLS_AllocServerContext(const char* cert, const char* key); 341 | void RTMP_TLS_FreeServerContext(void *ctx); 342 | 343 | int RTMP_LibVersion(void); 344 | void RTMP_UserInterrupt(void); /* user typed Ctrl-C */ 345 | 346 | int RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, 347 | unsigned int nTime); 348 | 349 | /* caller probably doesn't know current timestamp, should 350 | * just use RTMP_Pause instead 351 | */ 352 | int RTMP_SendPause(RTMP *r, int DoPause, int dTime); 353 | int RTMP_Pause(RTMP *r, int DoPause); 354 | 355 | int RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name, 356 | AMFObjectProperty * p); 357 | 358 | int RTMPSockBuf_Fill(RTMPSockBuf *sb); 359 | int RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len); 360 | int RTMPSockBuf_Close(RTMPSockBuf *sb); 361 | 362 | int RTMP_SendCreateStream(RTMP *r); 363 | int RTMP_SendSeek(RTMP *r, int dTime); 364 | int RTMP_SendServerBW(RTMP *r); 365 | int RTMP_SendClientBW(RTMP *r); 366 | void RTMP_DropRequest(RTMP *r, int i, int freeit); 367 | int RTMP_Read(RTMP *r, char *buf, int size); 368 | int RTMP_Write(RTMP *r, const char *buf, int size); 369 | 370 | /* hashswf.c */ 371 | int RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, 372 | int age); 373 | 374 | #ifdef __cplusplus 375 | }; 376 | #endif 377 | 378 | #endif 379 | -------------------------------------------------------------------------------- /librtmp/rtmp_log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2009 Andrej Stepanchuk 3 | * Copyright (C) 2009-2010 Howard Chu 4 | * 5 | * This file is part of librtmp. 6 | * 7 | * librtmp is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1, 10 | * or (at your option) any later version. 11 | * 12 | * librtmp is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with librtmp see the file COPYING. If not, write to 19 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | * http://www.gnu.org/copyleft/lgpl.html 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "rtmp_sys.h" 31 | #include "rtmp_log.h" 32 | 33 | #define MAX_PRINT_LEN 2048 34 | 35 | RTMP_LogLevel RTMP_debuglevel = RTMP_LOGERROR; 36 | 37 | static int neednl; 38 | 39 | static FILE *fmsg; 40 | 41 | static RTMP_LogCallback rtmp_log_default, *cb = rtmp_log_default; 42 | 43 | static const char *levels[] = { 44 | "CRIT", "ERROR", "WARNING", "INFO", 45 | "DEBUG", "DEBUG2" 46 | }; 47 | 48 | static void rtmp_log_default(int level, const char *format, va_list vl) 49 | { 50 | char str[MAX_PRINT_LEN]=""; 51 | 52 | vsnprintf(str, MAX_PRINT_LEN-1, format, vl); 53 | 54 | /* Filter out 'no-name' */ 55 | if ( RTMP_debuglevel RTMP_debuglevel ) 97 | return; 98 | 99 | va_start(args, format); 100 | cb(level, format, args); 101 | va_end(args); 102 | } 103 | 104 | static const char hexdig[] = "0123456789abcdef"; 105 | 106 | void RTMP_LogHex(int level, const uint8_t *data, unsigned long len) 107 | { 108 | unsigned long i; 109 | char line[50], *ptr; 110 | 111 | if ( level > RTMP_debuglevel ) 112 | return; 113 | 114 | ptr = line; 115 | 116 | for(i=0; i> 4)]; 118 | *ptr++ = hexdig[0x0f & data[i]]; 119 | if ((i & 0x0f) == 0x0f) { 120 | *ptr = '\0'; 121 | ptr = line; 122 | RTMP_Log(level, "%s", line); 123 | } else { 124 | *ptr++ = ' '; 125 | } 126 | } 127 | if (i & 0x0f) { 128 | *ptr = '\0'; 129 | RTMP_Log(level, "%s", line); 130 | } 131 | } 132 | 133 | void RTMP_LogHexString(int level, const uint8_t *data, unsigned long len) 134 | { 135 | #define BP_OFFSET 9 136 | #define BP_GRAPH 60 137 | #define BP_LEN 80 138 | char line[BP_LEN]; 139 | unsigned long i; 140 | 141 | if ( !data || level > RTMP_debuglevel ) 142 | return; 143 | 144 | /* in case len is zero */ 145 | line[0] = '\0'; 146 | 147 | for ( i = 0 ; i < len ; i++ ) { 148 | int n = i % 16; 149 | unsigned off; 150 | 151 | if( !n ) { 152 | if( i ) RTMP_Log( level, "%s", line ); 153 | memset( line, ' ', sizeof(line)-2 ); 154 | line[sizeof(line)-2] = '\0'; 155 | 156 | off = i % 0x0ffffU; 157 | 158 | line[2] = hexdig[0x0f & (off >> 12)]; 159 | line[3] = hexdig[0x0f & (off >> 8)]; 160 | line[4] = hexdig[0x0f & (off >> 4)]; 161 | line[5] = hexdig[0x0f & off]; 162 | line[6] = ':'; 163 | } 164 | 165 | off = BP_OFFSET + n*3 + ((n >= 8)?1:0); 166 | line[off] = hexdig[0x0f & ( data[i] >> 4 )]; 167 | line[off+1] = hexdig[0x0f & data[i]]; 168 | 169 | off = BP_GRAPH + n + ((n >= 8)?1:0); 170 | 171 | if ( isprint( data[i] )) { 172 | line[BP_GRAPH + n] = data[i]; 173 | } else { 174 | line[BP_GRAPH + n] = '.'; 175 | } 176 | } 177 | 178 | RTMP_Log( level, "%s", line ); 179 | } 180 | 181 | /* These should only be used by apps, never by the library itself */ 182 | void RTMP_LogPrintf(const char *format, ...) 183 | { 184 | char str[MAX_PRINT_LEN]=""; 185 | int len; 186 | va_list args; 187 | va_start(args, format); 188 | len = vsnprintf(str, MAX_PRINT_LEN-1, format, args); 189 | va_end(args); 190 | 191 | if ( RTMP_debuglevel==RTMP_LOGCRIT ) 192 | return; 193 | 194 | if ( !fmsg ) fmsg = stderr; 195 | 196 | if (neednl) { 197 | putc('\n', fmsg); 198 | neednl = 0; 199 | } 200 | 201 | if (len > MAX_PRINT_LEN-1) 202 | len = MAX_PRINT_LEN-1; 203 | fprintf(fmsg, "%s", str); 204 | if (str[len-1] == '\n') 205 | fflush(fmsg); 206 | } 207 | 208 | void RTMP_LogStatus(const char *format, ...) 209 | { 210 | char str[MAX_PRINT_LEN]=""; 211 | va_list args; 212 | va_start(args, format); 213 | vsnprintf(str, MAX_PRINT_LEN-1, format, args); 214 | va_end(args); 215 | 216 | if ( RTMP_debuglevel==RTMP_LOGCRIT ) 217 | return; 218 | 219 | if ( !fmsg ) fmsg = stderr; 220 | 221 | fprintf(fmsg, "%s", str); 222 | fflush(fmsg); 223 | neednl = 1; 224 | } 225 | -------------------------------------------------------------------------------- /librtmp/rtmp_log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2009 Andrej Stepanchuk 3 | * Copyright (C) 2009-2010 Howard Chu 4 | * 5 | * This file is part of librtmp. 6 | * 7 | * librtmp is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1, 10 | * or (at your option) any later version. 11 | * 12 | * librtmp is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with librtmp see the file COPYING. If not, write to 19 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | * http://www.gnu.org/copyleft/lgpl.html 22 | */ 23 | 24 | #ifndef __RTMP_LOG_H__ 25 | #define __RTMP_LOG_H__ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | /* Enable this to get full debugging output */ 35 | /* #define _DEBUG */ 36 | 37 | #ifdef _DEBUG 38 | #undef NODEBUG 39 | #endif 40 | 41 | typedef enum 42 | { RTMP_LOGCRIT=0, RTMP_LOGERROR, RTMP_LOGWARNING, RTMP_LOGINFO, 43 | RTMP_LOGDEBUG, RTMP_LOGDEBUG2, RTMP_LOGALL 44 | } RTMP_LogLevel; 45 | 46 | extern RTMP_LogLevel RTMP_debuglevel; 47 | 48 | typedef void (RTMP_LogCallback)(int level, const char *fmt, va_list); 49 | void RTMP_LogSetCallback(RTMP_LogCallback *cb); 50 | void RTMP_LogSetOutput(FILE *file); 51 | #ifdef __GNUC__ 52 | void RTMP_LogPrintf(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2))); 53 | void RTMP_LogStatus(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2))); 54 | void RTMP_Log(int level, const char *format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); 55 | #else 56 | void RTMP_LogPrintf(const char *format, ...); 57 | void RTMP_LogStatus(const char *format, ...); 58 | void RTMP_Log(int level, const char *format, ...); 59 | #endif 60 | void RTMP_LogHex(int level, const uint8_t *data, unsigned long len); 61 | void RTMP_LogHexString(int level, const uint8_t *data, unsigned long len); 62 | void RTMP_LogSetLevel(RTMP_LogLevel lvl); 63 | RTMP_LogLevel RTMP_LogGetLevel(void); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /librtmp/rtmp_sys.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTMP_SYS_H__ 2 | #define __RTMP_SYS_H__ 3 | /* 4 | * Copyright (C) 2010 Howard Chu 5 | * 6 | * This file is part of librtmp. 7 | * 8 | * librtmp is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation; either version 2.1, 11 | * or (at your option) any later version. 12 | * 13 | * librtmp is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with librtmp see the file COPYING. If not, write to 20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 | * Boston, MA 02110-1301, USA. 22 | * http://www.gnu.org/copyleft/lgpl.html 23 | */ 24 | 25 | #ifdef _WIN32 26 | 27 | #include 28 | #include 29 | 30 | #ifdef _MSC_VER /* MSVC */ 31 | #define snprintf _snprintf 32 | #define strcasecmp stricmp 33 | #define strncasecmp strnicmp 34 | #define vsnprintf _vsnprintf 35 | #endif 36 | 37 | #define GetSockError() WSAGetLastError() 38 | #define SetSockError(e) WSASetLastError(e) 39 | #define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e) 40 | #define EWOULDBLOCK WSAETIMEDOUT /* we don't use nonblocking, but we do use timeouts */ 41 | #define sleep(n) Sleep(n*1000) 42 | #define msleep(n) Sleep(n) 43 | #define SET_RCVTIMEO(tv,s) int tv = s*1000 44 | #else /* !_WIN32 */ 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #define GetSockError() errno 54 | #define SetSockError(e) errno = e 55 | #undef closesocket 56 | #define closesocket(s) close(s) 57 | #define msleep(n) usleep(n*1000) 58 | #define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0} 59 | #endif 60 | 61 | #include "rtmp.h" 62 | 63 | #ifdef USE_POLARSSL 64 | #include 65 | #include 66 | #include 67 | #include 68 | #if POLARSSL_VERSION_NUMBER < 0x01010000 69 | #define havege_random havege_rand 70 | #endif 71 | #if POLARSSL_VERSION_NUMBER >= 0x01020000 72 | #define SSL_SET_SESSION(S,resume,timeout,ctx) ssl_set_session(S,ctx) 73 | #else 74 | #define SSL_SET_SESSION(S,resume,timeout,ctx) ssl_set_session(S,resume,timeout,ctx) 75 | #endif 76 | typedef struct tls_ctx { 77 | havege_state hs; 78 | ssl_session ssn; 79 | } tls_ctx; 80 | typedef struct tls_server_ctx { 81 | havege_state *hs; 82 | x509_cert cert; 83 | rsa_context key; 84 | ssl_session ssn; 85 | const char *dhm_P, *dhm_G; 86 | } tls_server_ctx; 87 | 88 | #define TLS_CTX tls_ctx * 89 | #define TLS_client(ctx,s) s = malloc(sizeof(ssl_context)); ssl_init(s);\ 90 | ssl_set_endpoint(s, SSL_IS_CLIENT); ssl_set_authmode(s, SSL_VERIFY_NONE);\ 91 | ssl_set_rng(s, havege_random, &ctx->hs);\ 92 | ssl_set_ciphersuites(s, ssl_default_ciphersuites);\ 93 | SSL_SET_SESSION(s, 1, 600, &ctx->ssn) 94 | #define TLS_server(ctx,s) s = malloc(sizeof(ssl_context)); ssl_init(s);\ 95 | ssl_set_endpoint(s, SSL_IS_SERVER); ssl_set_authmode(s, SSL_VERIFY_NONE);\ 96 | ssl_set_rng(s, havege_random, ((tls_server_ctx*)ctx)->hs);\ 97 | ssl_set_ciphersuites(s, ssl_default_ciphersuites);\ 98 | SSL_SET_SESSION(s, 1, 600, &((tls_server_ctx*)ctx)->ssn);\ 99 | ssl_set_own_cert(s, &((tls_server_ctx*)ctx)->cert, &((tls_server_ctx*)ctx)->key);\ 100 | ssl_set_dh_param(s, ((tls_server_ctx*)ctx)->dhm_P, ((tls_server_ctx*)ctx)->dhm_G) 101 | #define TLS_setfd(s,fd) ssl_set_bio(s, net_recv, &fd, net_send, &fd) 102 | #define TLS_connect(s) ssl_handshake(s) 103 | #define TLS_accept(s) ssl_handshake(s) 104 | #define TLS_read(s,b,l) ssl_read(s,(unsigned char *)b,l) 105 | #define TLS_write(s,b,l) ssl_write(s,(unsigned char *)b,l) 106 | #define TLS_shutdown(s) ssl_close_notify(s) 107 | #define TLS_close(s) ssl_free(s); free(s) 108 | 109 | #elif defined(USE_GNUTLS) 110 | #include 111 | typedef struct tls_ctx { 112 | gnutls_certificate_credentials_t cred; 113 | gnutls_priority_t prios; 114 | } tls_ctx; 115 | #define TLS_CTX tls_ctx * 116 | #define TLS_client(ctx,s) gnutls_init((gnutls_session_t *)(&s), GNUTLS_CLIENT); gnutls_priority_set(s, ctx->prios); gnutls_credentials_set(s, GNUTLS_CRD_CERTIFICATE, ctx->cred) 117 | #define TLS_server(ctx,s) gnutls_init((gnutls_session_t *)(&s), GNUTLS_SERVER); gnutls_priority_set_direct(s, "NORMAL", NULL); gnutls_credentials_set(s, GNUTLS_CRD_CERTIFICATE, ctx) 118 | #define TLS_setfd(s,fd) gnutls_transport_set_ptr(s, (gnutls_transport_ptr_t)(long)fd) 119 | #define TLS_connect(s) gnutls_handshake(s) 120 | #define TLS_accept(s) gnutls_handshake(s) 121 | #define TLS_read(s,b,l) gnutls_record_recv(s,b,l) 122 | #define TLS_write(s,b,l) gnutls_record_send(s,b,l) 123 | #define TLS_shutdown(s) gnutls_bye(s, GNUTLS_SHUT_RDWR) 124 | #define TLS_close(s) gnutls_deinit(s) 125 | 126 | #else /* USE_OPENSSL */ 127 | #define TLS_CTX SSL_CTX * 128 | #define TLS_client(ctx,s) s = SSL_new(ctx) 129 | #define TLS_server(ctx,s) s = SSL_new(ctx) 130 | #define TLS_setfd(s,fd) SSL_set_fd(s,fd) 131 | #define TLS_connect(s) SSL_connect(s) 132 | #define TLS_accept(s) SSL_accept(s) 133 | #define TLS_read(s,b,l) SSL_read(s,b,l) 134 | #define TLS_write(s,b,l) SSL_write(s,b,l) 135 | #define TLS_shutdown(s) SSL_shutdown(s) 136 | #define TLS_close(s) SSL_free(s) 137 | 138 | #endif 139 | #endif 140 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-06-04 4 | @@Mail : pu17rui@sina.com 5 | @@Description: 6 | wish that I can transfer RTP to RTMP successfully!! 7 | *******************************/ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "config.h" 15 | #include "cms_vtdu.h" 16 | #include "req_srv.h" 17 | #include "ipcs.h" 18 | #include "log.h" 19 | 20 | /*global variables*/ 21 | LONG gpreview_listen_handle = 0; 22 | LONG glisten_handle = 0; 23 | struct _srv req_srv; 24 | extern struct _ipc IPCs[IPCS_MAX_NUM]; 25 | 26 | unsigned long GetTimeInterval(struct timeval* start, struct timeval* end); 27 | void FreeAll(int sig_num); 28 | int main() 29 | { 30 | LOG_Init(); 31 | signal(SIGINT, FreeAll);//ctrl + c signal handler 32 | IPCS_Init(); 33 | REQ_ServerInit(&req_srv); 34 | LOG_INFO("REQ_Listen_Server start listen! port:%d\n", REQ_SRV_PORT); 35 | //流媒体服务器(VTDU)监听取流 36 | //取流库初始化 37 | NET_ESTREAM_Init(); 38 | //预览监听参数 39 | NET_EHOME_LISTEN_PREVIEW_CFG struListen = {0}; 40 | memcpy(struListen.struIPAdress.szIP,NET_ESTREAM_IP, sizeof(NET_ESTREAM_IP)); 41 | struListen.struIPAdress.wPort = NET_ESTREAM_PORT; //流媒体服务器监听端口 42 | struListen.fnNewLinkCB = fnPREVIEW_NEWLINK_CB; //预览连接请求回调函数 43 | struListen.pUser = NULL; 44 | struListen.byLinkMode = LINK_MODE_TCP; //0- TCP方式,1- UDP方式 45 | //启动预览监听 46 | gpreview_listen_handle = NET_ESTREAM_StartListenPreview(&struListen); 47 | if(gpreview_listen_handle < -1) 48 | { 49 | LOG_ERROR(ERR_VTDU_START, "NET_ESTREAM_StartListenPreview failed, error code: %d\n", NET_ESTREAM_GetLastError()); 50 | NET_ESTREAM_Fini(); 51 | return 1; 52 | } 53 | LOG_INFO( "NET_ESTREAM_StartListenPreview! port:%d\n", NET_ESTREAM_PORT); 54 | //////////////////////////////////////////////////////////////////////// 55 | //CMS注册和预览请求 56 | //CMS注册模块初始化 57 | NET_ECMS_Init(); 58 | //注册监听参数 59 | NET_EHOME_CMS_LISTEN_PARAM struCMSListenPara = {0}; 60 | memcpy(struCMSListenPara.struAddress.szIP, NET_ESTREAM_IP, sizeof(NET_ESTREAM_IP)); 61 | struCMSListenPara.struAddress.wPort = NET_ECMS_PORT; 62 | struCMSListenPara.fnCB = RegisterCallBack; 63 | //启动监听,接收设备注册信息 64 | glisten_handle = NET_ECMS_StartListen(&struCMSListenPara); 65 | if(glisten_handle < -1) 66 | { 67 | LOG_ERROR(ERR_CMS_START, "NET_ECMS_StartListen failed, error code: %d\n", NET_ECMS_GetLastError()); 68 | NET_ECMS_Fini(); 69 | return 2; 70 | } 71 | LOG_INFO("NET_ECMS_StartListen! port:%d\n", NET_ECMS_PORT); 72 | 73 | while(1) 74 | { 75 | /*epoll为server阻塞监听事件, evts为struct epoll_event类型数组, REQ_SRV_CLIE_MAX_NUM为数组容量, -1表永久阻塞*/ 76 | int fd_num = epoll_wait(req_srv.ep_fd, req_srv.evts, REQ_SRV_CLIE_MAX_NUM, IPCS_EPOLL_WAIT_TIME); 77 | if (fd_num < 0) 78 | { 79 | LOG_ERROR(ERR_EPOLL_WAIT, "epoll_wait fail"); 80 | perror("epoll_wait fail\n"); 81 | sleep(1); 82 | continue; 83 | }else 84 | if (fd_num == 0) 85 | { 86 | LOG_DEBUG("There is no preview request now!\n"); 87 | // continue; 88 | } 89 | struct timeval time_now; 90 | gettimeofday(&time_now, NULL); 91 | for (int i = 0; i < fd_num; i++) 92 | { 93 | if( !(req_srv.evts[i].events & EPOLLIN )) //如果读到的不是有数据过来了 94 | continue; 95 | if (req_srv.evts[i].data.fd == req_srv.listen_fd) //如果读到的是新的连接,就建立连接先 96 | REQ_ServerAccept(&req_srv); 97 | else 98 | if( (req_srv.evts[i].events & EPOLLIN) ) //如果读到的是有数据过来了!else不能省略!! 99 | { 100 | int sock_tmp = req_srv.evts[i].data.fd; 101 | int bytes_num = REQ_ServerRecv(sock_tmp, &req_srv); 102 | if (bytes_num <= 0) 103 | {//先从红黑树上删除此节点 104 | int res = epoll_ctl(req_srv.ep_fd, EPOLL_CTL_DEL, sock_tmp, NULL); 105 | if (res == -1) 106 | { 107 | LOG_ERROR(ERR_EPOLL_CTL_DEL, "epoll_ctl_delete fail!"); 108 | perror("epoll_ctl_delete fail!\r\n"); 109 | } 110 | close(sock_tmp);//一定要释放掉此socket!!!! 111 | #ifdef PRINT_REQ_LINK 112 | LOG_INFO("%s:%d, clie_fd:%d closed connection\r\n" 113 | , inet_ntoa(req_srv.clie_addr.sin_addr), ntohs(req_srv.clie_addr.sin_port), sock_tmp); 114 | #endif 115 | }else 116 | { 117 | //reg_pack : I P C S 00 00 0X 0X 118 | //receive_pack : s t a r t : I P C S 00 00 0X 0X 119 | unsigned short int_dev_id = IPCS_GetInt_Devid(req_srv.rxbuf + 6, bytes_num - 6); 120 | memcpy(&(IPCs[int_dev_id].last_req_time), &time_now, sizeof(struct timeval)); 121 | if (IPCs[int_dev_id].push_state == IPCS_NOT_PUSHING_STREAM// must be not pushing! 122 | && IPCs[int_dev_id].online_state == IPCS_ONLINE)//must be on line! 123 | { 124 | /***********************start pushing!!!************************/ 125 | // if (IPCs[int_dev_id].online_state == IPCS_OFFLINE 126 | // || IPCs[int_dev_id].push_state == IPCS_PUSHING_STREAM) 127 | // continue; 128 | LOG_INFO("Starting device_id:%s, login_id:%ld .......\n" 129 | , IPCs[int_dev_id].dev_id, IPCs[int_dev_id].login_id); 130 | if (IPCS_PushInit(&(IPCs[int_dev_id]))) 131 | { 132 | LOG_ERROR(ERR_IPC_PUSH_INIT, "RTMP_init failed! dev_id:%s, login_id:%ld\n" 133 | , IPCs[int_dev_id].dev_id, IPCs[int_dev_id].login_id); 134 | IPCS_PushFree(&(IPCs[int_dev_id])); 135 | continue; 136 | } 137 | //预览请求输入参数 138 | NET_EHOME_PREVIEWINFO_IN_V11 struPreviewIn = {0}; 139 | struPreviewIn.iChannel = CHANNEL_ID; //通道号 140 | struPreviewIn.dwLinkMode = LINK_MODE_TCP; //0- TCP方式,1- UDP方式 141 | struPreviewIn.dwStreamType = STREAM_TYPE_SUB; //码流类型:0- 主码流,1- 子码流, 2- 第三码流 142 | memcpy(struPreviewIn.struStreamSever.szIP, NET_ESTREAM_PUBLIC_IP, sizeof(NET_ESTREAM_PUBLIC_IP));//流媒体服务器IP地址 143 | struPreviewIn.struStreamSever.wPort = NET_ESTREAM_PORT; //流媒体服务器端口,需要跟服务器启动监听端口一致 144 | //预览请求输出参数 145 | NET_EHOME_PREVIEWINFO_OUT struPreviewOut = {0}; 146 | //预览请求 147 | if(!NET_ECMS_StartGetRealStreamV11(IPCs[int_dev_id].login_id, &struPreviewIn, &struPreviewOut)) 148 | { 149 | LOG_ERROR(ERR_CMS_STREAM_START, "NET_ECMS_StartGetRealStreamV11 failed, error code: %d\n", NET_ECMS_GetLastError()); 150 | IPCS_PushFree(&(IPCs[int_dev_id])); 151 | continue; 152 | } 153 | IPCs[int_dev_id].preview_session_id = struPreviewOut.lSessionID; 154 | // LOG_Print(ERR_NONE, "NET_ECMS_StartGetRealStreamV11!\n"); 155 | //预览请求推流输入参数 156 | NET_EHOME_PUSHSTREAM_IN struPushStreamIn = {0}; 157 | struPushStreamIn.dwSize = sizeof(struPushStreamIn); 158 | struPushStreamIn.lSessionID = IPCs[int_dev_id].preview_session_id; //SessionID,预览请求会话ID 159 | //预览请求推流输出参数 160 | NET_EHOME_PUSHSTREAM_OUT struPushStreamOut = {0}; 161 | 162 | //向设备发送命令请求开始发送实时码流,EHOME协议版本大于等于4.0的设备支持 163 | if(!NET_ECMS_StartPushRealStream(IPCs[int_dev_id].login_id, &struPushStreamIn, &struPushStreamOut)) 164 | { 165 | LOG_ERROR(ERR_CMS_STREAM_PUSH, "NET_ECMS_StartPushRealStream failed, error code: %d\n", NET_ECMS_GetLastError()); 166 | IPCS_PushFree(&(IPCs[int_dev_id])); 167 | continue; 168 | } 169 | LOG_INFO("NET_ECMS_StartPushRealStream! dev_id:%s, login_id:%ld\n" 170 | , IPCs[int_dev_id].dev_id, IPCs[int_dev_id].login_id); 171 | /*remember change the push_state*/ 172 | IPCs[int_dev_id].push_state = IPCS_PUSHING_STREAM; 173 | } 174 | } 175 | } 176 | } 177 | /*check every ipc's time interval*/ 178 | unsigned long interval = 0; 179 | for (int i = 0; i < IPCS_MAX_NUM; ++i) 180 | { 181 | if (IPCs[i].push_state == IPCS_PUSHING_STREAM//this ipc has started pushing stream! 182 | && IPCs[i].online_state == IPCS_ONLINE) //must be on line! 183 | { 184 | interval = GetTimeInterval(&(IPCs[i].last_req_time), &time_now); // us 185 | if ( interval > IPCS_HEARTBEAT_INVL ) //user has left the web page(none heartbeat packs) 186 | { 187 | // if (IPCs[i].online_state == IPCS_OFFLINE 188 | // || IPCs[i].push_state == IPCS_NOT_PUSHING_STREAM)//and must be pushing! 189 | // continue; 190 | /**************************stop preview************************/ 191 | // LOG_Print(ERR_NONE, "[%d]the interval:%ld \n", i, interval); 192 | LOG_INFO("Stoping device_id:%s, login_id:%ld .......\n", IPCs[i].dev_id, IPCs[i].login_id); 193 | //释放CMS预览请求资源 194 | if(!NET_ECMS_StopGetRealStream(IPCs[i].login_id, IPCs[i].preview_session_id)) 195 | { 196 | LOG_ERROR(ERR_CMS_STREAM_STOP, "NET_ECMS_StopGetRealStream failed, error code: %d\n", NET_ECMS_GetLastError()); 197 | } 198 | //VTDU停止预览 199 | if(IPCs[i].stream_handle >= 0) 200 | { 201 | if (!NET_ESTREAM_StopPreview(IPCs[i].stream_handle)) 202 | { 203 | LOG_ERROR(ERR_VTDU_STOP, "NET_ESTREAM_StopPreview failed, error code: %d\n", NET_ECMS_GetLastError()); 204 | } 205 | } 206 | IPCS_PushFree(&(IPCs[i])); 207 | LOG_INFO("NET_ECMS_StopPushRealStream! dev_id:%s, login_id:%ld\n", IPCs[i].dev_id, IPCs[i].login_id); 208 | /*remember change the push_state*/ 209 | IPCs[i].push_state = IPCS_NOT_PUSHING_STREAM; 210 | } 211 | } 212 | } 213 | usleep(1); 214 | } 215 | //////////////////////////////////////////////////////////////////////// 216 | //退出 217 | FreeAll(0); 218 | 219 | return 0; 220 | } 221 | unsigned long GetTimeInterval(struct timeval* start, struct timeval* end) 222 | { 223 | unsigned long diff = 1000000 * (end->tv_sec - start->tv_sec) + end->tv_usec - start->tv_usec; 224 | 225 | return diff; 226 | } 227 | void FreeAll(int sig_num) 228 | { 229 | // LOG_Print(ERR_NONE, "sig_num:%d\n", sig_num); 230 | //CMS停止监听 231 | if(!NET_ECMS_StopListen(glisten_handle)) 232 | LOG_ERROR(ERR_CMS_STOP, "NET_ECMS_StopListen failed, error code: %d\n", NET_ECMS_GetLastError()); 233 | //CMS库反初始化,释放资源 234 | NET_ECMS_Fini(); 235 | //VTDU停止预览监听 236 | if(gpreview_listen_handle >= 0) 237 | if (!NET_ESTREAM_StopListenPreview(gpreview_listen_handle)) 238 | LOG_ERROR(ERR_VTDU_STOP, "NET_ESTREAM_StopListenPreview failed, error code: %d\n", NET_ECMS_GetLastError()); 239 | //取流库反初始化,释放资源 240 | NET_ESTREAM_Fini(); 241 | REQ_FreeServer(&req_srv); 242 | for (int i = 0; i < IPCS_MAX_NUM; ++i) 243 | if (IPCs[i].push_state == IPCS_PUSHING_STREAM) 244 | IPCS_PushFree(&(IPCs[i])); 245 | LOG_INFO("Exit!\n"); 246 | LOG_Free(); 247 | exit(0); 248 | } -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | EXEC = r 2 | DIR_CURR=./ 3 | DIR_OBJ=./OBJ/ 4 | 5 | C_SRCS =$(wildcard ${DIR_CURR}*.c) 6 | C_SRCS +=$(wildcard ./conv/*.c) $(wildcard ./ipc/*.c) $(wildcard ./request/*.c) 7 | C_SRCS +=$(wildcard ./record/*.c) 8 | 9 | C_OBJS = ${patsubst %.c,${DIR_OBJ}%.o, ${notdir ${C_SRCS}}} 10 | C_SRCS_DIR = ${dir $(C_SRCS)} 11 | 12 | # delete the repeatition 13 | uniq = $(eval seen :=)$(foreach i,$1,$(if $(filter $i,${seen}),,$(eval seen += $i)))${seen} 14 | rwildcard = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) 15 | ALL_DIRS = $(dir $(foreach src_path,$(DIR_CURR), $(call rwildcard,$(src_path),*/) ) ) 16 | ALL_DIRS := $(call uniq, $(ALL_DIRS)) 17 | INC_DIR := $(ALL_DIRS) 18 | # libraries 19 | RTMP_LIB_DIR = ./librtmp/ 20 | EH_LIB_DIR = ./HIK_EHome/eh_lib/ 21 | LIBS_RTMP = rtmp 22 | LIBS_EHOME = HCEHomeCMS HCEHomeStream SystemTransform hpr iconv2 23 | 24 | LIB_DIR := $(RTMP_LIB_DIR) $(EH_LIB_DIR) 25 | LIBS := $(LIBS_RTMP) $(LIBS_EHOME) 26 | 27 | CC = g++ 28 | CFLAGS = -O2 -Wall -g 29 | INCFLAGS = $(foreach i, $(INC_DIR),-I$(i)) 30 | LDFLAGS += $(foreach i, $(LIB_DIR),-L$(i)) 31 | LDFLAGS += $(foreach i, $(LIBS),-l$(i)) 32 | DY_LDFLAGS =-Wl,-rpath=$(EH_LIB_DIR) 33 | 34 | all:clean $(EXEC) 35 | 36 | $(EXEC):$(C_OBJS) 37 | cd ./librtmp && make 38 | $(CC) -o $@ $(C_OBJS) $(LDFLAGS) 39 | @echo "Make Done~" 40 | 41 | VPATH = $(C_SRCS_DIR) 42 | ${DIR_OBJ}%.o:${DIR_CURR}%.c 43 | @if [ ! -d $(DIR_OBJ) ]; then mkdir -p $(DIR_OBJ); fi; 44 | @$(CC) -c $< -o $@ $(CFLAGS) $(INCFLAGS) 45 | 46 | .PHONY:clean 47 | clean: 48 | @rm -rf ${DIR_OBJ} 49 | @rm -rf ${EXEC} 50 | @echo "Clean Done~" 51 | -------------------------------------------------------------------------------- /record/log.c: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-08-15 4 | @@Mail : pu17rui@sina.com 5 | @@Description: logs print 6 | *******************************/ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include //close、read、write函数需要 15 | #include 16 | #include 17 | #include "log.h" 18 | #include "config.h" 19 | 20 | static pthread_mutex_t gLOG_out_file_mutex; 21 | static FILE* gLOG_out_fd = NULL; 22 | 23 | int LOG_Init(void) 24 | { 25 | pthread_mutex_init(&gLOG_out_file_mutex, NULL); 26 | 27 | if (access(LOG_OUT_PATH, F_OK) == -1) 28 | { 29 | mkdir(LOG_OUT_PATH, S_IRWXU | S_IRWXG | S_IRWXO); 30 | } 31 | 32 | return 0; 33 | } 34 | int LOG_Save(char* data, int len) 35 | { 36 | char file_name[256] = {0}; 37 | 38 | time_t now; 39 | struct tm *timenow; 40 | time(&now); 41 | timenow = localtime(&now); 42 | // printf("Local time is %s", asctime(timenow)); 43 | pthread_mutex_lock(&gLOG_out_file_mutex); 44 | /* the file name */ 45 | sprintf(file_name, "%slog_%d%02d%02d", LOG_OUT_PATH, 46 | timenow->tm_year + 1900, timenow->tm_mon + 1, timenow->tm_mday); 47 | // printf("%s\n", file_name); 48 | if (access(file_name, F_OK) == -1 || gLOG_out_fd == NULL)//file not exists or not null 49 | gLOG_out_fd = fopen(file_name, "a+"); 50 | fwrite(data, len, 1, gLOG_out_fd); 51 | fflush(gLOG_out_fd);//write immediately from sys buf 52 | pthread_mutex_unlock(&gLOG_out_file_mutex); 53 | 54 | return 0; 55 | } 56 | int LOG_Print(const char *log_type, int err_n, int line_n, const char *func_name, const char* format, ...) 57 | { 58 | char buf[LOG_CONTENT_MAX_SIZE * 2] = {0}; 59 | char data[LOG_CONTENT_MAX_SIZE] = {0}; 60 | /*get all the params in ...*/ 61 | va_list args_tmp; 62 | va_start(args_tmp, format); 63 | vsnprintf(data, sizeof(data), format, args_tmp); 64 | va_end(args_tmp); 65 | 66 | time_t now; 67 | struct tm *timenow; 68 | time(&now); 69 | timenow = localtime(&now); 70 | /*add the header of the data*/ 71 | int len = sprintf(buf, "[%s %d-%02d-%02d %02d:%02d:%02d]", log_type, 72 | timenow->tm_year + 1900, timenow->tm_mon + 1, timenow->tm_mday, 73 | timenow->tm_hour, timenow->tm_min, timenow->tm_sec); 74 | if (!strcmp(log_type, "ERROR")) 75 | len += sprintf(buf + len, "[ %d ]", err_n); 76 | len += sprintf(buf + len, " <%d>", line_n); 77 | len += sprintf(buf + len, "<%s>", func_name); 78 | len += sprintf(buf + len, " %s", data); 79 | 80 | // int len = sprintf(buf, "%s", data); 81 | printf("%s", buf); 82 | fflush(stdout);//write immediately from sys buf 83 | #ifdef LOG_SAVE 84 | if (strcmp(log_type, "DEBUG")) 85 | LOG_Save(buf, len); 86 | #endif 87 | return 0; 88 | } 89 | int LOG_Free(void) 90 | { 91 | pthread_mutex_destroy(&gLOG_out_file_mutex); 92 | 93 | if (gLOG_out_fd != NULL) 94 | { 95 | fclose(gLOG_out_fd); 96 | gLOG_out_fd = NULL; 97 | } 98 | 99 | 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /record/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __PUSH_LOG_H__ 2 | #define __PUSH_LOG_H__ 3 | 4 | /* error num */ 5 | #define ERR_NONE 0 6 | #define ERR_VTDU_START 1 7 | #define ERR_CMS_START 2 8 | #define ERR_EPOLL_WAIT 3 9 | #define ERR_EPOLL_CTL_DEL 4 10 | #define ERR_IPC_PUSH_INIT 5 11 | #define ERR_CMS_STREAM_START 6 12 | #define ERR_CMS_STREAM_PUSH 7 13 | #define ERR_CMS_STREAM_STOP 8 14 | #define ERR_VTDU_STOP 9 15 | #define ERR_VTDU_SETCB 10 16 | #define ERR_RTMP_SET_URL 11 17 | #define ERR_RTMP_CONNECT 12 18 | #define ERR_RTMP_CONNECT_STREAM 13 19 | #define ERR_REQ_FD_GET 14 20 | #define ERR_REQ_PORT_BIND 15 21 | #define ERR_REQ_LISTEN 16 22 | #define ERR_REQ_EPOLL_GET 17 23 | #define ERR_REQ_EPOLL_CTL 18 24 | #define ERR_REQ_ACCEPT 19 25 | #define ERR_REQ_SEND 20 26 | #define ERR_RTMP_SEND 21 27 | #define ERR_CMS_STOP 22 28 | 29 | #define LOG_INFO(fmt, ...) \ 30 | LOG_Print("INFO", 0, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__) 31 | #define LOG_WARN(fmt, ...) \ 32 | LOG_Print("WARN", 0, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__) 33 | #define LOG_ERROR(n, fmt, ...) \ 34 | LOG_Print("ERROR", n, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__) 35 | #define LOG_DEBUG(fmt, ...) \ 36 | LOG_Print("DEBUG", 0, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__) 37 | 38 | int LOG_Init(void); 39 | int LOG_Save(char* data, int len); 40 | int LOG_Print(const char *log_type, int err_n, int line_n, const char *func_name, const char* format, ...); 41 | int LOG_Free(void); 42 | 43 | #endif -------------------------------------------------------------------------------- /request/req_srv.c: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-06-26 4 | @@Mail : pu17rui@sina.com 5 | @@Description: request listen server 6 | *******************************/ 7 | #include 8 | #include 9 | #include 10 | #include //close、read、write函数需要 11 | #include 12 | #include //F_GETFL设置非阻塞时需要 13 | #include 14 | #include //数据类型定义 15 | #include //ip地址转换 16 | #include "req_srv.h" 17 | #include "log.h" 18 | 19 | /************************************************* 20 | @Description: request listen server init 21 | @Input: serv 22 | @Output: 23 | @Return: 0-success others-fail 24 | @Others: 25 | *************************************************/ 26 | int REQ_ServerInit(struct _srv *server) 27 | { 28 | server->connect_num=0; 29 | server->rxbuf = (unsigned char*)malloc(REQ_SRV_BUF_LEN); 30 | memset(server->rxbuf, 0, REQ_SRV_BUF_LEN); 31 | server->txbuf = (unsigned char*)malloc(REQ_SRV_BUF_LEN); 32 | memset(server->txbuf, 0, REQ_SRV_BUF_LEN); 33 | 34 | server->listen_fd = socket(AF_INET, SOCK_STREAM, 0);//创建套接字 35 | if (server->listen_fd == -1) 36 | { 37 | LOG_ERROR(ERR_REQ_FD_GET, "fail to creat a socket!"); 38 | // perror("error:fail to creat a socket!"); 39 | return 1; 40 | } 41 | int opt = 1; 42 | setsockopt(server->listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));//端口复用 43 | 44 | memset(&(server->serv_addr), 0, sizeof(server->serv_addr)); 45 | server->serv_addr.sin_family = AF_INET; 46 | // inet_pton(AF_INET,SERV_IP,&serv_addr.sin_addr.s_addr);//直接绑定固定ip而不用本地其他ip 47 | server->serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 48 | server->serv_addr.sin_port = htons(REQ_SRV_PORT); 49 | 50 | int temp = 0; 51 | temp = bind(server->listen_fd, (struct sockaddr *)&(server->serv_addr), sizeof(server->serv_addr));/*绑定服务器地址结构体*/ 52 | if (temp == -1) 53 | { 54 | close(server->listen_fd); 55 | LOG_ERROR(ERR_REQ_PORT_BIND, "fail to bind port!"); 56 | // perror("error:fail to bind port!"); 57 | return 2; 58 | } 59 | temp = listen(server->listen_fd, REQ_SRV_CLIE_MAX_NUM); 60 | if (temp == -1) 61 | { 62 | close(server->listen_fd); 63 | LOG_ERROR(ERR_REQ_LISTEN, "fail to listen!"); 64 | // perror("error:fail to listen!"); 65 | return 3; 66 | } 67 | /************************epoll 创建********************/ 68 | server->ep_fd = epoll_create(REQ_SRV_CLIE_MAX_NUM); 69 | if (server->ep_fd == -1) 70 | { 71 | LOG_ERROR(ERR_REQ_EPOLL_GET, "epoll create error"); 72 | // perror("epoll create error"); 73 | return 4; 74 | } 75 | // if (Server::SetNonblock(server->listen_fd))//不知道需不需要!!因为去掉也可!但是注意成功地返回值是0!!!!记住!! 76 | // return 5; 77 | /*将listen_fd及对应的结构体设置到树上,使ep_fd可找到*/ 78 | struct epoll_event evt_temp; 79 | evt_temp.data.fd = server->listen_fd; 80 | evt_temp.events = EPOLLIN ; 81 | if(epoll_ctl(server->ep_fd, EPOLL_CTL_ADD, server->listen_fd, &evt_temp) == -1)//挂到红黑树上去 82 | { 83 | LOG_ERROR(ERR_REQ_EPOLL_CTL, "epoll_ctl listen_fd fail1"); 84 | // perror("epoll_ctl listen_fd fail1"); 85 | return 6; 86 | } 87 | 88 | return 0; 89 | } 90 | 91 | /************************************************* 92 | @Description: set nonblock 93 | @Input: socket 94 | @Output: 95 | @Return: 0-success others-fail 96 | @Others: 97 | *************************************************/ 98 | int REQ_SetNonblock(int fd) 99 | { 100 | int flag = fcntl(fd, F_GETFL); 101 | if (flag == -1) 102 | { 103 | perror("fcntl fail"); 104 | return 1; 105 | } 106 | flag |= O_NONBLOCK; 107 | if (fcntl(fd, F_SETFL, flag) < 0) 108 | { 109 | perror("fcntl fail"); 110 | return 2; 111 | } 112 | 113 | return 0; 114 | } 115 | 116 | /************************************************* 117 | @Description: accept 118 | @Input: serv 119 | @Output: 120 | @Return: 0-success others-fail 121 | @Others: 122 | *************************************************/ 123 | int REQ_ServerAccept(struct _srv *server) 124 | { 125 | socklen_t clie_addr_len = sizeof(server->clie_addr);//传入传出参数,没啥用感觉 126 | server->clie_fd = accept(server->listen_fd, (struct sockaddr *)&(server->clie_addr), &clie_addr_len);//建立与客户端的连接 127 | 128 | if (server->clie_fd == -1) 129 | { 130 | LOG_ERROR(ERR_REQ_ACCEPT, "accept fail\n"); 131 | // perror("accept fail\n"); 132 | return 1; 133 | } 134 | else 135 | { 136 | struct epoll_event evt_temp; 137 | evt_temp.events = EPOLLIN ; 138 | evt_temp.data.fd= server->clie_fd; 139 | if(epoll_ctl(server->ep_fd, EPOLL_CTL_ADD, server->clie_fd, &evt_temp) == -1)//然后挂到红黑树上去 140 | { 141 | LOG_ERROR(ERR_REQ_EPOLL_CTL, "epoll_ctl clie_fd fail!"); 142 | // perror("epoll_ctl clie_fd fail!"); 143 | return 2; 144 | } 145 | #ifdef PRINT_REQ_LINK 146 | // printf("OK: Server has got connection from %s.\n",inet_ntoa(server->clie_addr.sin_addr)); 147 | LOG_INFO("REQ_Server has connected to %s:%d, clie_fd:%d, connect num:%d\n", 148 | inet_ntoa(server->clie_addr.sin_addr), ntohs(server->clie_addr.sin_port), server->clie_fd, ++(server->connect_num));//打印连接的客户端的编号 149 | #endif 150 | } 151 | return 0; 152 | } 153 | 154 | /************************************************* 155 | @Description: send 156 | @Input: fd, buf, len 157 | @Output: 158 | @Return: others - send length -1 - fail 159 | @Others: 160 | *************************************************/ 161 | int REQ_ServerSend(int fd, unsigned char* buf, int length) 162 | { 163 | int num = write(fd, buf, length); 164 | if (num != length) 165 | { 166 | LOG_ERROR(ERR_REQ_SEND, "send fail!"); 167 | // perror("send fail!"); 168 | return -1; 169 | } 170 | return num; 171 | } 172 | 173 | /************************************************* 174 | @Description: recv 175 | @Input: serv 176 | @Output: 177 | @Return: others - recv length -1 - fail 178 | @Others: 179 | *************************************************/ 180 | int REQ_ServerRecv(int fd, struct _srv *server) 181 | { 182 | memset(server->rxbuf, 0, REQ_SRV_BUF_LEN); 183 | int num = read(fd, server->rxbuf, REQ_SRV_BUF_LEN); 184 | if (num < 0) 185 | { 186 | // perror("read fail!"); 187 | return -1; 188 | }else 189 | if(num > 0) 190 | { 191 | #ifdef PRINT_REQ_RECV_RAW 192 | printf("recv length: %d data:\n", num);//将从客户端读到的数据,在屏幕上输出 193 | for (int i = 0; i < num; i++) 194 | printf("[%d]%c ", i, server->rxbuf[i]); 195 | printf("\n"); 196 | #endif 197 | } 198 | return num; 199 | } 200 | 201 | /************************************************* 202 | @Description: free bufs 203 | @Input: serv 204 | @Output: 205 | @Return: 0-success others-fail 206 | @Others: 207 | *************************************************/ 208 | int REQ_FreeServer(struct _srv *server) 209 | { 210 | if(server->rxbuf != NULL) 211 | { 212 | free(server->rxbuf); 213 | server->rxbuf = NULL; 214 | } 215 | if(server->txbuf != NULL) 216 | { 217 | free(server->txbuf); 218 | server->txbuf = NULL; 219 | } 220 | 221 | if(server->listen_fd) 222 | { 223 | close(server->listen_fd); 224 | server->listen_fd = 0; 225 | } 226 | if(server->clie_fd) 227 | { 228 | close(server->clie_fd); 229 | server->clie_fd = 0; 230 | } 231 | if (server->ep_fd) 232 | { 233 | close(server->ep_fd); 234 | server->ep_fd = 0; 235 | } 236 | 237 | return 0; 238 | } 239 | -------------------------------------------------------------------------------- /request/req_srv.h: -------------------------------------------------------------------------------- 1 | /******************************* 2 | @@Author : Charles 3 | @@Date : 2018-06-26 4 | @@Mail : pu17rui@sina.com 5 | @@Description: 6 | *******************************/ 7 | #ifndef __REQ_LISTEN_SRV_H__ 8 | #define __REQ_LISTEN_SRV_H__ 9 | 10 | #include 11 | #include 12 | #include "config.h" 13 | 14 | struct _srv 15 | { 16 | int listen_fd; 17 | int clie_fd; 18 | int connect_num; 19 | struct sockaddr_in serv_addr; 20 | struct sockaddr_in clie_addr; 21 | //初始的接收与发送数组 22 | unsigned char* rxbuf; 23 | unsigned char* txbuf; 24 | 25 | int ep_fd; 26 | // struct epoll_event evt_temp; 27 | struct epoll_event evts[REQ_SRV_CLIE_MAX_NUM];//传出的各个连接信息 28 | }; 29 | 30 | int REQ_ServerInit(struct _srv *); 31 | int REQ_SetNonblock(int fd); 32 | int REQ_ServerAccept(struct _srv *);//与客户端的连接 33 | int REQ_ServerSend(int , unsigned char* , int); 34 | int REQ_ServerRecv(int, struct _srv *); 35 | int REQ_FreeServer(struct _srv *server); 36 | 37 | 38 | #endif --------------------------------------------------------------------------------