转自https://github.com/EasyDarwin/EasyPusher
easydarwin今年开始发力了, 不过有商业价值的模块都不开源,他们也得吃饭,可以理解。
本文仅实际体验一下demo,review一下示例代码,分析一下如何应用。
1)EasyPusher框图预览
2) EasyPusher应用实现
a. 推送h264文件
/* Copyright (c) 2013-2014 EasyDarwin.ORG. All rights reserved. Github: https://github.com/EasyDarwin WEChat: EasyDarwin Website: http://www.EasyDarwin.org */ #include "EasyPusherAPI.h" #include "trace.h" int __EasyPusher_Callback(int _id, EASY_PUSH_STATE_T _state, EASY_AV_Frame *_frame, void *_userptr) { if (_state == EASY_PUSH_STATE_CONNECTING) printf("Connecting... "); else if (_state == EASY_PUSH_STATE_CONNECTED) printf("Connected "); else if (_state == EASY_PUSH_STATE_CONNECT_FAILED) printf("Connect failed "); else if (_state == EASY_PUSH_STATE_CONNECT_ABORT) printf("Connect abort "); else if (_state == EASY_PUSH_STATE_PUSHING) printf("P->"); else if (_state == EASY_PUSH_STATE_DISCONNECTED) printf("Disconnect. "); return 0; } int main() { char szIP[16] = {0}; Easy_Pusher_Handle pusherId = 0; EASY_MEDIA_INFO_T mediainfo; int buf_size = 1024*512; char *pbuf = (char *) malloc(buf_size); FILE *fES = NULL; int position = 0; int iFrameNo = 0; WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); memset(&mediainfo, 0x00, sizeof(EASY_MEDIA_INFO_T)); mediainfo.u32VideoCodec = 0x1C; fES = fopen("./EasyDarwin.264", "rb"); if (NULL == fES) return 0; pusherId = EasyPusher_Create(); EasyPusher_SetEventCallback(pusherId, __EasyPusher_Callback, 0, NULL); EasyPusher_StartStream(pusherId, "127.0.0.1", 554, "live.sdp", "admin", "admin", &mediainfo, 512); //printf("*** live streaming url:rtsp://115.29.139.20:554/live.sdp *** "); while (1) { int nReadBytes = fread(pbuf+position, 1, 1, fES); if (nReadBytes < 1) { if (feof(fES)) { position = 0; fseek(fES, 0, SEEK_SET); continue; } break; } position ++; if (position > 5) { unsigned char naltype = ( (unsigned char)pbuf[position-1] & 0x1F); if ( (unsigned char)pbuf[position-5]== 0x00 && (unsigned char)pbuf[position-4]== 0x00 && (unsigned char)pbuf[position-3] == 0x00 && (unsigned char)pbuf[position-2] == 0x01 && //(((unsigned char)pbuf[position-1] == 0x61) || //((unsigned char)pbuf[position-1] == 0x67) ) ) (naltype==0x07||naltype==0x01) ) { int framesize = position - 5; EASY_AV_Frame avFrame; naltype = (unsigned char)pbuf[4] & 0x1F; memset(&avFrame, 0x00, sizeof(EASY_AV_Frame)); avFrame.u32AVFrameLen = framesize; avFrame.pBuffer = (unsigned char*)pbuf; avFrame.u32VFrameType = (naltype==0x07)?EASY_SDK_VIDEO_FRAME_I:EASY_SDK_VIDEO_FRAME_P; EasyPusher_PushFrame(pusherId, &avFrame); Sleep(30); memmove(pbuf, pbuf+position-5, 5); position = 5; iFrameNo ++; //if (iFrameNo > 100000) break; //break; } } } _TRACE("Press Enter exit... "); getchar(); EasyPusher_StopStream(pusherId); EasyPusher_Release(pusherId); WSACleanup(); return 0; }
b. 推送Camera SDK回调的音视频数据,示例中的SDK是EasyDarwin开源摄像机的配套库,EasyCamera SDK及配套源码可在 http://www.easydarwin.org 或者 https://github.com/EasyDarwin/EasyCamera 获取到,也可以用自己项目中用到的SDK获取音视频数据进行推送;
/* Copyright (c) 2013-2014 EasyDarwin.ORG. All rights reserved. Github: https://github.com/EasyDarwin WEChat: EasyDarwin Website: http://www.EasyDarwin.org */ #define _CRTDBG_MAP_ALLOC #include <stdio.h> #include "EasyPusherAPI.h" #include <winsock2.h> #include "hi_type.h" #include "hi_net_dev_sdk.h" #include "hi_net_dev_errors.h" #include "trace.h" #define UNAME "admin" #define PWORD "admin" #define DHOST "192.168.66.189" //EasyCamera摄像机IP地址 #define DPORT 80 //EasyCamera摄像机端口 #define SHOST "115.29.139.20" //EasyDarwin流媒体服务器地址 #define SPORT 554 //EasyDarwin流媒体服务器端口 HI_U32 u32Handle = 0; Easy_Pusher_Handle pusherHandle = 0; HI_S32 OnEventCallback(HI_U32 u32Handle, /* 句柄 */ HI_U32 u32Event, /* 事件 */ HI_VOID* pUserData /* 用户数据*/ ) { return HI_SUCCESS; } HI_S32 NETSDK_APICALL OnStreamCallback(HI_U32 u32Handle, /* 句柄 */ HI_U32 u32DataType, /* 数据类型,视频或音频数据或音视频复合数据 */ HI_U8* pu8Buffer, /* 数据包含帧头 */ HI_U32 u32Length, /* 数据长度 */ HI_VOID* pUserData /* 用户数据*/ ) { HI_S_AVFrame* pstruAV = HI_NULL; HI_S_SysHeader* pstruSys = HI_NULL; if (u32DataType == HI_NET_DEV_AV_DATA) { pstruAV = (HI_S_AVFrame*)pu8Buffer; if (pstruAV->u32AVFrameFlag == HI_NET_DEV_VIDEO_FRAME_FLAG) { if(pusherHandle == 0 ) return 0; if(pstruAV->u32AVFrameLen > 5) { unsigned char* pbuf = (unsigned char*)(pu8Buffer+sizeof(HI_S_AVFrame)); unsigned char naltype = ( (unsigned char)pbuf[4] & 0x1F); if ( (unsigned char)pbuf[0]== 0x00 && (unsigned char)pbuf[1]== 0x00 && (unsigned char)pbuf[2] == 0x00 && (unsigned char)pbuf[3] == 0x01 && (naltype==0x07 || naltype==0x01) ) { EASY_AV_Frame avFrame; naltype = (unsigned char)pbuf[4] & 0x1F; memset(&avFrame, 0x00, sizeof(EASY_AV_Frame)); avFrame.u32AVFrameLen = pstruAV->u32AVFrameLen; avFrame.pBuffer = (unsigned char*)pbuf; avFrame.u32VFrameType = (naltype==0x07)?EASY_SDK_VIDEO_FRAME_I:EASY_SDK_VIDEO_FRAME_P; EasyPusher_PushFrame(pusherHandle, &avFrame); } } } else if (pstruAV->u32AVFrameFlag == HI_NET_DEV_AUDIO_FRAME_FLAG) { //printf("Audio %u PTS: %u ", pstruAV->u32AVFrameLen, pstruAV->u32AVFramePTS); //SaveRecordFile("Video.hx", pu8Buffer, u32Length); } } else if (u32DataType == HI_NET_DEV_SYS_DATA) { pstruSys = (HI_S_SysHeader*)pu8Buffer; printf("Video W:%u H:%u Audio: %u ", pstruSys->struVHeader.u32Width, pstruSys->struVHeader.u32Height, pstruSys->struAHeader.u32Format); } return HI_SUCCESS; } HI_S32 OnDataCallback(HI_U32 u32Handle, /* 句柄 */ HI_U32 u32DataType, /* 数据类型*/ HI_U8* pu8Buffer, /* 数据 */ HI_U32 u32Length, /* 数据长度 */ HI_VOID* pUserData /* 用户数据*/ ) { return HI_SUCCESS; } int __EasyPusher_Callback(int _id, EASY_PUSH_STATE_T _state, EASY_AV_Frame *_frame, void *_userptr) { if (_state == EASY_PUSH_STATE_CONNECTING) printf("Connecting... "); else if (_state == EASY_PUSH_STATE_CONNECTED) printf("Connected "); else if (_state == EASY_PUSH_STATE_CONNECT_FAILED) printf("Connect failed "); else if (_state == EASY_PUSH_STATE_CONNECT_ABORT) printf("Connect abort "); //else if (_state == EASY_PUSH_STATE_PUSHING) printf("P->"); else if (_state == EASY_PUSH_STATE_DISCONNECTED) printf("Disconnect. "); return 0; } int main() { HI_S32 s32Ret = HI_SUCCESS; HI_S_STREAM_INFO struStreamInfo; HI_U32 a; HI_NET_DEV_Init(); s32Ret = HI_NET_DEV_Login(&u32Handle, UNAME, PWORD, DHOST, DPORT); if (s32Ret != HI_SUCCESS) { HI_NET_DEV_DeInit(); return -1; } //HI_NET_DEV_SetEventCallBack(u32Handle, OnEventCallback, &a); HI_NET_DEV_SetStreamCallBack(u32Handle, (HI_ON_STREAM_CALLBACK)OnStreamCallback, &a); //HI_NET_DEV_SetDataCallBack(u32Handle, OnDataCallback, &a); struStreamInfo.u32Channel = HI_NET_DEV_CHANNEL_1; struStreamInfo.blFlag = HI_FALSE;//HI_FALSE; struStreamInfo.u32Mode = HI_NET_DEV_STREAM_MODE_TCP; struStreamInfo.u8Type = HI_NET_DEV_STREAM_ALL; s32Ret = HI_NET_DEV_StartStream(u32Handle, &struStreamInfo); if (s32Ret != HI_SUCCESS) { HI_NET_DEV_Logout(u32Handle); u32Handle = 0; return -1; } WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); EASY_MEDIA_INFO_T mediainfo; memset(&mediainfo, 0x00, sizeof(EASY_MEDIA_INFO_T)); mediainfo.u32VideoCodec = 0x1C; pusherHandle = EasyPusher_Create(); EasyPusher_SetEventCallback(pusherHandle, __EasyPusher_Callback, 0, NULL); EasyPusher_StartStream(pusherHandle, SHOST, SPORT, "live.sdp", "admin", "admin", &mediainfo, 512); printf("*** live streaming url:rtsp://%s:%d/live.sdp *** ", SHOST, SPORT); while(1) { Sleep(10); }; EasyPusher_StopStream(pusherHandle); EasyPusher_Release(pusherHandle); pusherHandle = 0; HI_NET_DEV_StopStream(u32Handle); HI_NET_DEV_Logout(u32Handle); HI_NET_DEV_DeInit(); return 0; }
3) demo运行
先启动EasyDarwin服务器,然后启动EasyPusher,这里推送H264文件做测试
4)总结
重点:获取数据帧,发送数据帧,查找数据帧帧头。
end