首页 > 代码库 > EasyPusher推流服务接口的.NET导出

EasyPusher推流服务接口的.NET导出

本文是在使用由 EasyDarwin 团队开发的EasyPusher时导出的C++接口的.NET实现

public class EasyPushSDK    {        public EasyPushSDK() { }        [StructLayoutAttribute(LayoutKind.Sequential)]        public struct EASY_AV_Frame        {            public uint u32AVFrameFlag;    /* 帧标志  视频 or 音频 */            public uint u32AVFrameLen;     /* 帧的长度 */            public uint u32VFrameType;     /* 视频的类型,I帧或P帧 */            public IntPtr pBuffer;           /* 数据 */            public uint u32TimestampSec;   /* 时间戳(秒)*/            public uint u32TimestampUsec;    /* 时间戳(微秒) */        }        public enum EASY_PUSH_STATE_T        {            EASY_PUSH_STATE_CONNECTING = 1,         /* 连接中 */            EASY_PUSH_STATE_CONNECTED,              /* 连接成功 */            EASY_PUSH_STATE_CONNECT_FAILED,         /* 连接失败 */            EASY_PUSH_STATE_CONNECT_ABORT,          /* 连接异常中断 */            EASY_PUSH_STATE_PUSHING,                /* 推流中 */            EASY_PUSH_STATE_DISCONNECTED,           /* 断开连接 */            EASY_PUSH_STATE_ERROR        }        [StructLayoutAttribute(LayoutKind.Sequential)]        public struct EASY_MEDIA_INFO_T        {            public uint u32VideoCodec;             /* 视频编码类型 */            public uint u32VideoFps;               /* 视频帧率 */            public uint u32AudioCodec;             /* 音频编码类型 */            public uint u32AudioSamplerate;        /* 音频采样率 */            public uint u32AudioChannel;           /* 音频通道数 */            public uint u32AudioBitsPerSample;     /* 音频采样精度 */            public uint u32H264SpsLength;          /* 视频sps帧长度 */            public uint u32H264PpsLength;          /* 视频pps帧长度 */            [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 128)]            public char[] u8H264Sps;                /* 视频sps帧内容 */            [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 36)]            public char[] u8H264Pps;                /* 视频sps帧内容 */        }        /// <summary>        /// Easies the pusher_ activate.        /// </summary>        /// <param name="license">The license.</param>        /// <returns>System.Int32.</returns>        /// <remarks>        ///      <para>创建:***</para>        ///      <para>日期:2016/11/22</para>        /// </remarks>        [DllImport(@"..\bin\libEasyPusher.dll")]        // -1,             /* 无效Key */        // -2,            /* 时间错误 */        // -3,            /* 进程名称长度不匹配 */        // -4,            /* 进程名称不匹配 */        // -5,          /* 有效期校验不一致 */        //-6,            /* 平台不匹配 */        // -7,          /* 授权使用商不匹配 */        // 0,          /* 激活成功 */        public static extern int EasyPusher_Activate(string license);        [DllImport(@"..\bin\libEasyPusher.dll")]        /* 创建推送句柄  返回为句柄值 */        public static extern IntPtr EasyPusher_Create();        [DllImport(@"..\bin\libEasyPusher.dll")]        /* 释放推送句柄 */        public static extern uint EasyPusher_Release(IntPtr pushPtr);        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]        public delegate int EasyPusher_Callback(int _id, EASY_PUSH_STATE_T _state, ref EASY_AV_Frame _frame, IntPtr _userptr);        [DllImport(@"..\bin\libEasyPusher.dll", CallingConvention = CallingConvention.Cdecl)]        /* 设置流传输事件回调 userptr传输自定义对象指针*/        public static extern uint EasyPusher_SetEventCallback(IntPtr handle, EasyPusher_Callback callback, int id, IntPtr userptr);        /* 开始流传输 serverAddr:流媒体服务器地址、port:流媒体端口、streamName:流名称<xxx.sdp>、username/password:推送携带的用户名密码、pstruStreamInfo:推送的媒体定义、bufferKSize:以k为单位的缓冲区大小<512~2048之间,默认512> bool createlogfile:创建日志文件*/        [DllImport(@"..\bin\libEasyPusher.dll")]        public static extern uint EasyPusher_StartStream(IntPtr handle, string serverAddr, uint port,            string streamName, string username, string password, ref EASY_MEDIA_INFO_T pstruStreamInfo, uint bufferKSize, bool createlogfile);        [DllImport(@"..\bin\libEasyPusher.dll")]        /* 停止流传输 */        public static extern uint EasyPusher_StopStream(IntPtr pushPtr);        [DllImport(@"..\bin\libEasyPusher.dll")]        /* 推流 frame:具体推送的流媒体帧 */        public static extern uint EasyPusher_PushFrame(IntPtr pushPtr, ref EASY_AV_Frame frame);    }

 

附加将海康的PS流转换为H264流的.NET实现GetH246FromPS

public static class Utils    {        public static bool IsIFrame(byte[] buf)        {            int naltype = (buf[4] & 0x1F);            switch (naltype)            {                case 7: //sps                case 8: // pps                case 6: // i                case 5: //idr                    return true;                case 1: // slice                case 9: // unknown ???                default:                    return false;            }        }        /// <summary>        /// Gets the H246 from ps.        /// </summary>        /// <param name="pBuffer">PS 流数据</param>        /// <param name="pH264">转换后的H264流数据(音视频)</param>        /// <param name="bVideo">if set to <c>true</c> [b video].</param>        /// <param name="bAudio">if set to <c>true</c> [b audio].</param>        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>        /// <remarks>        ///      <para>创建:***</para>        ///      <para>日期:2016/11/25</para>        /// </remarks>        public static bool GetH246FromPS(byte[] pBuffer, ref byte[] pH264, out bool bVideo, out bool bAudio)        {            var _nBufLenth = (int)pBuffer.Length;            if (pBuffer == null || _nBufLenth <= 0)            {                bVideo = bAudio = false;                return false;            }            int nHerderLen = 0;            if (pBuffer != null                && pBuffer[0] == 0x00                && pBuffer[1] == 0x00                && pBuffer[2] == 0x01                && pBuffer[3] == 0xE0)//E==视频数据(此处E0标识为视频)            {                bVideo = true;                bAudio = false;                nHerderLen = 9 + (int)pBuffer[8];//9个为固定的数据包头长度,pBuffer[8]为填充头部分的长度                var nH264Lenth = _nBufLenth - nHerderLen;                if (pH264 == null)                {                    pH264 = new byte[nH264Lenth];                }                if (pH264 != null && nH264Lenth > 0)                {                    pH264 = pBuffer.Skip(nHerderLen).Take(nH264Lenth).ToArray();                }                return true;            }            else if (pBuffer != null                && pBuffer[0] == 0x00                && pBuffer[1] == 0x00                && pBuffer[2] == 0x01                && pBuffer[3] == 0xC0) //C==音频数据?            {                pH264 = null;                bVideo = false;                bAudio = true;                var nH264Lenth = _nBufLenth - nHerderLen;                nHerderLen = 9 + (int)pBuffer[8];//9个为固定的数据包头长度,pBuffer[8]为填充头部分的长度                if (pH264 == null)                {                    pH264 = new byte[nH264Lenth];                }                if (pH264 != null && nH264Lenth > 0)                {                    pH264 = pBuffer.Skip(nHerderLen).Take(nH264Lenth).ToArray();                }                return true;            }            else if (pBuffer != null                && pBuffer[0] == 0x00                && pBuffer[1] == 0x00                && pBuffer[2] == 0x01                && pBuffer[3] == 0xBA)//视频流数据包 包头            {                bVideo = true;                bAudio = false;                pH264 = null;                return false;            }            bVideo = bAudio = false;            return false;        }    }

 

TIPS:

  把.NET 数组数据转为指针的方法

Byte[] _h264Buf = new Byte[1000];                            //申请内存并返回指针                            IntPtr fStreamAudioHandle = Marshal.AllocHGlobal(_h264Buf.Length);                            Marshal.Copy(_h264Buf, 0, fStreamAudioHandle, _h264Buf.Length);                                                       Marshal.FreeHGlobal(fStreamAudioHandle);//使用过后释放内存

  取出指针处的数据到.NET数组

//取出指针处数据                        //pBuffer 指针                        //dwBufSize 指针缓存区大小                        byte[] byx = new byte[(int)dwBufSize];                        Marshal.Copy(pBuffer, byx, 0, (int)dwBufSize);

 

小建议:在导出C++接口的时候,最好自己使用C++再一次封装原有接口。这样导出自己实现的C++接口的时候就可以打断点,会比较方便的知道导出的.NET方法/传入的参数是否正确,总之可以自己有调试的手段了

 

参考:http://www.voidcn.com/blog/bigpudding24/article/p-5036339.html

EasyPusher推流服务接口的.NET导出