VLC客户端和SDK的简单应用

VLC_SDK编程指南

VLC 是一款自由、开源的跨平台多媒体播放器及框架,可播放大多数多媒体文件,以及 DVD、音频 CD、VCD 及各类流媒体协议。它可以支持目前市面上大多数的视频解码,除了Real。

VLC_SDK的调用

VLC的SDK使用C语言写成,它的解码库部分的基础是FFMpeg,FFMpeg也是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

VLC的SDK是在其客户端的安装文件根目录下,下载完VLC的客户端,并安装后,在其根目录下可以找到,例如

客户端安装在C:\Program Files\VideoLAN\VLC。因为我们是使用C#语言来调用其SDK,所以只需使用到其plugins文件夹和libvlc.dll、libvlccore.dll两个文件。

libvlc.dll和libvlccore.dll是其两个核心的动态链接库。libvlc对外提供了c语言的接口;libvlccore是VLC 媒体播放器管理线程,VLC 媒体播放器的运行核称之为libvlccore;vlc把编解码和格式解析的支持设计成了插件的形式,所以还必须要带上vlc的plugins目录里的插件。

引用位置

把libvlc.dll和libvlccore.dll和plugins文件夹放在” bin/Debug”下。

封装方式

常规封装

由于两个动态链接库是用C语言写的。所以还要用C#封装一下非托管方法。例如:

// 创建一个libvlc实例,它是引用计数的
[DllImport("libvlc", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)]
[SuppressUnmanagedCodeSecurity]
private static extern IntPtr libvlc_new(int argc, IntPtr argv);

需要引用下面两个命名空间:

using System.Runtime.InteropServices;
using System.Security;

声明式封装

还有一种是声明式封装引用,值得借鉴。

  1. 首先实现一个自定义特性类,定义其属性用法为委托方式。
  2. 定义一个抽象类,例如:VlcInteropsManager,使用windows API调用VLC的DLL
[AttributeUsage(AttributeTargets.Delegate, AllowMultiple = false)]
    internal sealed class LibVlcFunctionAttribute : Attribute
    {
        public string FunctionName { get; private set; }
 
        public LibVlcFunctionAttribute(string functionName)
        {
            FunctionName = functionName;
        }
    }
[DllImport("kernel32", SetLastError = true)]
 public static extern IntPtr LoadLibrary(string lpFileName);

例如:

var libVlcDllPath = Path.Combine(dynamicLinkLibrariesPath.FullName, "libvlc.dll");//获取libvlc的路径
            if (!File.Exists(libVlcDllPath))
                throw new FileNotFoundException();
            myLibVlcDllHandle = Win32Interops.LoadLibrary(libVlcDllPath);//获取libvlc的指针
            if (myLibVlcDllHandle == IntPtr.Zero)
                throw new Win32Exception(Marshal.GetLastWin32Error());

根据自定义特性名称(实际为libvlc方法名称)获取libvlc非托管方法

[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);// hModule为LoadLibrary 方法获取的libvlc的指针,lpProcName为方法名称

例如:

internal T GetInteropDelegate<T>()
        {
            string vlcFunctionName = null;
            try
            {
                var attrs = typeof(T).GetCustomAttributes(typeof(LibVlcFunctionAttribute), false);
                if (attrs.Length == 0)
                    throw new Exception("Could not find the LibVlcFunctionAttribute.");
                var attr = (LibVlcFunctionAttribute)attrs[0];
                vlcFunctionName = attr.FunctionName;
                procAddress = Win32Interops.GetProcAddress(myLibVlcCoreDllHandle, attr.FunctionName);//获取非托管函数的指针
                  if (procAddress == IntPtr.Zero)
                        throw new Win32Exception();
       }
                var delegateForFunctionPointer = Marshal.GetDelegateForFunctionPointer(procAddress, typeof(T));// 因为定义了自定义特性的属性为委托,所以需将非托管函数指针转换为委托
        return (T)Convert.ChangeType(delegateForFunctionPointer, typeof(T), null);
            }
            catch (Win32Exception e)
            {
                throw new MissingMethodException(String.Format("The address of the function ‘{0}‘ does not exist in libvlc library.", vlcFunctionName), e);
            }
        }

释放指针

[DllImport("kernel32", SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);

例如:

if (myLibVlcDllHandle != IntPtr.Zero)
            {
                Win32Interops.FreeLibrary(myLibVlcDllHandle);
                myLibVlcDllHandle = IntPtr.Zero;
            }// myLibVlcDllHandle为LoadLibrary获取的指针
  1. 定义委托方法

例如:定义libvlc中获取版本信息方法” libvlc_get_version”。

[LibVlcFunction("libvlc_get_version")]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr GetVersion();
  1. 继承抽象类VlcInteropsManager调用委托方法
public void GetVersion ()
 {
    return GetInteropDelegate<GetVersion>().Invoke().ToStringAnsi();
  }

播放视频的常用方法

// 创建一个libvlc实例,它是引用计数的
private static extern IntPtr libvlc_new(int argc, IntPtr argv);
 // 释放libvlc实例
public static extern void libvlc_release(IntPtr libvlc_instance);
//获取版本号
public static extern String libvlc_get_version();
// 从视频来源(例如Url)构建一个libvlc_meida
private static extern IntPtr libvlc_media_new_location(IntPtr libvlc_instance, IntPtr path);
// 从本地文件路径构建一个libvlc_media
private static extern IntPtr libvlc_media_new_path(IntPtr libvlc_instance, IntPtr path);
//释放media
public static extern void libvlc_media_release(IntPtr libvlc_media_inst);
 // 创建libvlc_media_player(播放核心)
public static extern IntPtr libvlc_media_player_new(IntPtr libvlc_instance);
// 将视频(libvlc_media)绑定到播放器上
public static extern void libvlc_media_player_set_media(IntPtr libvlc_media_player, IntPtr libvlc_media);
// 设置图像输出的窗口
public static extern void libvlc_media_player_set_hwnd(IntPtr libvlc_mediaplayer, Int32 drawable);
//播放
public static extern void libvlc_media_player_play(IntPtr libvlc_mediaplayer);
//暂停
public static extern void libvlc_media_player_pause(IntPtr libvlc_mediaplayer);
//停止
public static extern void libvlc_media_player_stop(IntPtr libvlc_mediaplayer);
// 解析视频资源的媒体信息(如时长等)
public static extern void libvlc_media_parse(IntPtr libvlc_media);
// 返回视频的时长(必须先调用libvlc_media_parse之后,该函数才会生效)
public static extern Int64 libvlc_media_get_duration(IntPtr libvlc_media);
// 当前播放的时间
public static extern Int64 libvlc_media_player_get_time(IntPtr libvlc_mediaplayer);
// 设置播放位置(拖动)
public static extern void libvlc_media_player_set_time(IntPtr libvlc_mediaplayer, Int64 time);
//释放meidiaPlayer
public static extern void libvlc_media_player_release(IntPtr libvlc_mediaplayer);

方法具体含义请参看其c语言的封装库具体内容。

播放调用流程

播放本地文件

libvlc_new=>libvlc_media_player_new=>libvlc_media_player_set_hwnd=>libvlc_media_new_path=>libvlc_media_parse=>libvlc_media_player_set_media=>libvlc_media_release=>libvlc_media_player_play=>libvlc_media_player_stop=>libvlc_media_player_release=>libvlc_media_release=>libvlc_release

播放URL

libvlc_new=>libvlc_media_player_new=>libvlc_media_player_set_hwnd=>libvlc_media_new_location=>libvlc_media_parse=>libvlc_media_player_set_media=>libvlc_media_release=>libvlc_media_player_play=>libvlc_media_player_stop=>libvlc_media_player_release=>libvlc_media_release=>libvlc_release

开启硬件加速

开启硬件加速命令为:avcodec-hw=any

方法为:libvlc_media_add_option (IntPtr mediaInstance, IntPtr mrl);

var handle = GCHandle.Alloc(Encoding.UTF8.GetBytes(option), GCHandleType.Pinned);//option为命令
//两个参数的获取
mrl= handle.AddrOfPinnedObject();
mediaInstance= libvlc_new(null);

Vlc.DotNet

Vlc.DotNet是一个对VLC封装的C#开源架构。使用Vlc.DotNet框架可以播放本地文件和URL网络视频。在研究过程中,目前还为发现关于解码方面的封装应用。

引用位置

Vlc.DotNet框架包含5个DLL,如下


名称


版本号


Vlc.DotNet.Core.dll


2014.10.15.0


Vlc.DotNet.Core.Interops.dll


2014.10.15.0


Vlc.DotNet.Forms.dll


2014.10.15.0


Vlc.DotNet.Silverlight.dll


2014.10.15.0


Vlc.DotNet.Wpf.dll


2014.10.15.0

根据你做的程序是用什么写的来添加不同的引用,例如:你使用WPF来做的程序就选择Vlc.DotNet.Wpf.dll、Vlc.DotNet.Forms.dll、Vlc.DotNet.Core.dll、Vlc.DotNet.Core.Interops.dll添加到项目中并引用。

把libvlc.dll和libvlccore.dll和plugins文件夹放在” bin/Debug”下。

调用方法(WPF)

具体示例可以参见Vlc.DotNet自带的demo,简要说明如下:

  1. XAML中添加命名空间的引用:

xmlns:wpf="clr-namespace:Vlc.DotNet.Wpf;assembly=Vlc.DotNet.Wpf"

  1. 在<Grid></Grid>标签中添加

<wpf:VlcControl  Grid.Row="0" Grid.Column="0" x:Name="myControl1"/>

  1. 在后台cs代码中注册加载DLL事件
myControl1.VlcLibDirectoryNeeded += OnVlcControlNeedsLibDirectory;
private void OnVlcControlNeedsLibDirectory(object sender, Forms.VlcLibDirectoryNeededEventArgs e)
        {
            var currentAssembly = Assembly.GetEntryAssembly();
            var currentDirectory = new FileInfo(currentAssembly.Location).DirectoryName;
            if (currentDirectory == null)
                return;
            e.VlcLibDirectory = new DirectoryInfo(Path.Combine(currentDirectory, @"VLC\"));
        }
  1. 播放

播放本地文件

myControl1.MediaPlayer.Play(new FileInfo(Environment.CurrentDirectory + @"\video\wow" + i + @".mp4"), null);

播放URI文件

myControl1..MediaPlayer.Play

(new Uri("rtsp://192.168.1.181"),new string[] { "avcodec-hw=any" });//开启硬件加速

  1. 停止播放

myControl1.MediaPlayer.Stop();

其他功能可参见开源框架源码。

VLC客户端作为流媒体转发服务端

VLC客户端可以作为流媒体转发服务端。如下图所以操作:

  1. 打开VLC客户端
  1. 选则【流】选项
  1. 选择【网络】选项卡,设置网络协议,点击【串流】。
  1. 确认流输出媒体源,点击【Next】。
  1. 设置流输出目标,选择输出方式。本例选择HTTP方式。然后点击【添加】
  1. 选择流输出的端口号和路径访问名称,然后点击【Next】。
  1. 选择输出流的转码格式,并点击工具图标按钮设置具体参数。
  1. 输出流
  1. 转发流,标题上显示【流】字样,即表明流媒体开始转发
  1. 流显示

显示的方式使用HTML5Video标签,Html5的Video标签只支持三种视频格式,OGG,WebM,MP4,经过测试,video标签只能播放VLC转发的OGG格式视频。

建立一个html文件:

<html>
<head>
    <title>HTTP Live Streaming Player</title>
</head>
<body>
    <video id="vplayer"
        height="300"
        width="400"
        controls="controls"
        src="http://192.168.1.5:8880/ttl" />
</body>
</html>

也可转发本地视频文件流。

VLC_SDK实现流媒体转码广播功能

上图用客户端实现的功能,可以用SDK实现。

其C语言库为libvlc_vlm.h。在这个文件中包含了“推流器”广播和点播的控制功能。

我把在c#中封装的实现推流器功能核心SDK方法归纳如下:

//添加广播
[LibVlcFunction("libvlc_vlm_add_broadcast")]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate int VlmAddBroadcast(IntPtr libvlc_instance, IntPtr name, IntPtr input, IntPtr output, int optionNumber, string[] options, bool isEnabled, bool isLoop);
//播放广播
[LibVlcFunction("libvlc_vlm_play_media")]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate int PlayVlmMedia(IntPtr libvlcInstance, IntPtr broadcastName); 
//关闭广播
[LibVlcFunction("libvlc_vlm_stop_media")]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate int StopVlmMedia(IntPtr libvlcInstance, IntPtr broadcastName);
//删除广播
[LibVlcFunction("libvlc_vlm_del_media")]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void VlmDelMedia(IntPtr libvlcInstance,IntPtr mediaName);
//释放广播示例
[LibVlcFunction("libvlc_vlm_release")]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void ReleaseVlm(IntPtr libvlcInstance);

在赋值参数时需要注意自定义广播名称、视频源地址和目标地址的字符串转换为指针时需要做如下操作:

var handleName = GCHandle.Alloc(Encoding.UTF8.GetBytes(name), GCHandleType.Pinned);//广播名称
var handleInput = GCHandle.Alloc(Encoding.UTF8.GetBytes(input), GCHandleType.Pinned);//视频源
 var handleOutput = GCHandle.Alloc(Encoding.UTF8.GetBytes(output), GCHandleType.Pinned);//目标

具体实现方式如下:

//播放广播
public bool PlayVlmMedia(string broadcastName, string input, string output, int optionNumber, string[] options, bool isEnabled, bool isLoop)
   {
            bool result = false;
            if (_manager.AddVlmBroadcast(broadcastName, input, output, optionNumber, options, isEnabled, isLoop))//添加广播地址
                result = _manager.PlayVlmMedia(broadcastName);//播放
            return result;
        }
//停止播放广播
public bool StopVlmMedia(string broadcastName)
{
        return _manager.StopVlmMedia(broadcastName);
}

传入参数:

String mediaName = "IPCTest";//广播名称
String url = "rtsp://192.168.1.181";//源地址//string sout = "#transcode{vcodec=h264,vb=800,scale=1,acodec=mpga,ab=128,channels=2,samplerate=44100}:http{mux=ts,dst=:7777/}";//转码目标格式H264格式
string sout = "#transcode{vcodec=theo,vb=1600,scale=1,acodec=vorb,ab=128,channels=2,samplerate=44100}:http{mux=ogg,dst=:8880/ttl}";//转码格式为ogg,端口号为8880,标识为ttl
string[] options = {"screen-top=0", 
                            "screen-left=0",
                            "screen-width=640", 
                            "screen-height=480", 
                            "screen-fps=10"};//码流参数
 
            _vlcControl.PlayVlmMedia(mediaName, url, sout, 5, options, true, false);//转码后广播

VLC_SDK实现视频流回调显示功能

实现实时流回调的流程与普通播放方式相同,唯一区别在于,普通播放方式需要指定播放窗体,实时流回调不需指定播放窗体,只需在回调方法中获取视频流数据然后用自定义方式显示出来。具体操作如下:

首先封装三个委托方法:

//锁定一个图片缓冲区
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]//声明对c语言的约束
public delegate IntPtr VideoLockCB(IntPtr opaque, IntPtr planes);
//解锁一个图片缓冲区
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void VideoUnlockCB(IntPtr opaque, IntPtr picture, IntPtr planes);
//显示图片
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void VideoDisplayCB(IntPtr opaque, IntPtr picture);

其次封装两个方法:

//设置解码后视频格式
[LibVlcFunction("libvlc_video_set_format")]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void VideoSetFormat(IntPtr mediaPlayerInstance, IntPtr chroma, UInt32 width, UInt32 height, UInt32 pitch);
//设置实时流视频解析回调
[LibVlcFunction("libvlc_video_set_callbacks")]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void VideoSetCallBacks(IntPtr mediaPlayInstance, VideoLockCB lockCB, VideoUnlockCB unlockCB, VideoDisplayCB displayCB, IntPtr opaque);

具体调用过程如下:

  1. 创建一个libvlc实例
  2. 创建一个mediaPlayer实例
  3. 创建一个media实例
IntPtr vlcInstance=libvlc_new();//
IntPtr mediaPlayerInstance=libvlc_media_player_new(vlcInstance);

创建实例常用两种方式,一种是根据本地文件路径。

IntPtr mediaInstance= libvlc_media_new_path(vlcInstance,"本地文件地址");

一种是根据网络地址

IntPtr mediaInstance= libvlc_media_new_location(vlcInstance,"网络地址");
  1. 解析视频源信息

经实例运行验证,不是用此方法普通方式和回调方式的视频流也可以播放。

libvlc_media_parse(mediaInstance);
  1. 将视频源绑定到播放器上
  2. 释放视频源
  3. 设置解码后视频格式
  4. 设置实时流视频解析
libvlc_media_player_set_media(mediaPlayerInstance, mediaInstance);
libvlc_media_release(IntPtr libvlc_media_inst);
VideoSetFormat(_mediaPlayer, "RV32", width, height, pitch);//RGBA 颜色不对,YUYV显示错误,I420程序跳出

预先设置的变量

        private const int _width = 1920;
        private const int _height = 1080;
        private const int _pixelBytes = 4;
        private const int _pitch = _width * _pixelBytes;
        private IntPtr _buff = IntPtr.Zero;

初始化三个委托

        private VideoLockCB _videoLockCB;
        private VideoUnlockCB _videoUnlockCB;
        private VideoDisplayCB _videoDisplayCB;
 
        if (_videoLockCB == null)
            _videoLockCB = new VideoLockCB(VideoLockCallBack);
        if (_videoUnlockCB == null)
              _videoUnlockCB = new VideoUnlockCB(VideoUnlockCallBack);
        if (_videoDisplayCB == null)
            _videoDisplayCB = new VideoDisplayCB(VideoDiplayCallBack);

设置回调

VideoSetCallBacks(_mediaPlayer, lockCB, unlockCB, displayCB, IntPtr.Zero);

使用回调前前先定义一个线程锁。

        bool obj = false;
        private void Lock()
        {
            obj = true;
        }
        private void Unlock()
        {
            obj = false;
        }
        private bool Islock()
        {
            return obj;
        }

锁定一个图片缓冲区时先锁定,然后初始化这个缓冲区。

private IntPtr VideoLockCallBack(IntPtr opaque, IntPtr planes)
        {
            Lock();
            _buff = Marshal.AllocHGlobal(_pitch * _height);
            Marshal.WriteIntPtr(planes, _buff);//初始化
            return IntPtr.Zero;
        }

显示图片的委托中进行的处理,我选择了解析为Bitmap,然后显示在pictureBox上。

if (Islock())
            {
                if (DateTime.Now.Subtract(_start).TotalSeconds > 2)
                {
                    using (Bitmap bmp = new Bitmap(_width, _height, PixelFormat.Format32bppPArgb))
                    {
                        Rectangle rect = new Rectangle(0, 0, _width, _height);
                        BitmapData bp = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat);
                        CopyMemory(bp.Scan0, _buff, (uint)(_height * _pitch));
                        bmp.UnlockBits(bp);
                        //bmp.Save("c:\\vlc.bmp");
                        Bitmap bitmap = (Bitmap)bmp.Clone();
                        if (this.pictureBox1.Image != null)
                            this.pictureBox1.Image.Dispose();
                        this.pictureBox1.Image = bitmap;
                    }
                }
            }

此委托中用到了一个winapi函数

[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
private static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);

解锁图片缓冲区

private void VideoUnlockCallBack(IntPtr opaque, IntPtr picture, IntPtr planes)
        {
            Marshal.FreeHGlobal(_buff);//释放缓冲区
            Unlock();
        }
时间: 2024-10-07 23:01:30

VLC客户端和SDK的简单应用的相关文章

网络编程 实现 客户端与服务器端的简单通信

六,代码演示实现客户端与服务器端的简单通信 代码中所使用的 IP号码,必须是本机自己的IP号码 (自行查询:cmd---ipconfig/all ) 1.[客户端向服务器端 发送一个整型数据,服务器端进行接收] (1)先写服务器端 import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java

客户端架构设计的简单总结(转)

from:http://www.cppblog.com/weiym/archive/2014/07/26/207819.html 我们知道,客户端是相对服务端而言的,客户端程序相对普通应用程序,主要是增加了网络通讯功能.在这个移动和云存储的年代,大部分终端应用程序都有网络通讯功能, 所以都可以称为客户端.常见的客户端如浏览器,IM客户端, 网络会议客户端,邮件客户端,微博和微信客户端等... 通过观察,我们会发现所有的客户端基本是大同小异,都会包括一些相同的功能组件, 下面简单例举下: 通讯协议

客户端数据上报的简单实现

发布到外网的安装包和客户端程序,经常需要向后台上报一些数据.实现数据上报的方法有很多,其中最简单的方法是,用IE静默打开一个带有查询字符串的URL.这样,只要在apache上部署一个简单的脚本,就能统计数据上报了. 先看下安装包中数据上报的实现,nsis代码如下: ExecShell "open" "iexplore.exe" "http://127.0.0.1" SW_HIDE 这个脚本对应到win32的API,是ShellExecute.奇怪

java 使用 comet4j 主动向客户端推送信息 简单例子

[背景] 今天,一个前端的师弟问我怎样做实时聊天窗口,我毫不犹豫地说:在前台定时访问服务端呀!师弟默默地百度了一番,最后告诉我,有一种技术是后服务端动推送信息给客户端的,这种技术的名字叫comet,我惊呆了,因为完全没听过,赶紧上网搜集资料,耗了一个晚上写了个简单的例子,实现主动向客户端发送信息.说是说主动,其实还是要客户端先献出它的“第一次”,即只要它有先请求你一下,以后你们熟了,你想主动约它就约它! 关于comet技术介绍及其实现原理,可以参考网站 http://www.ibm.com/de

百度地图SDK的简单使用

要使用百度地图SDK必须下载并配置工程,百度官方文档中有两种方式,一种是手动拖拽下载好的SDK到工程中,然后手动配置环境:另一种是使用CocoaPods自动配置.今天我都试了一下,个人感觉第二种方法比较方便,因为手动配置环境很容易出错,所有建议大家使用cocoaPods.这里只介绍使用cocoaPods的方法(关于cocoaPods的使用可以参照我之前的一篇博客). 第一步:使用Xcode创建一个工程.然后关掉工程. 第二步:打开终端输入   cd + 工程路径   然后回车进入到工程路径中:(

socket编程中客户端常用函数 以及简单实现

1 常用函数 1.1   connect() int connect(int sockfd, const struct sockaddr *servaddr, socklen_taddrlen); 客户端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址.connect()成功返回0,出错返回-1. 1.2   bind():很少用 由于客户端不需要固定的端口号,因此不必调用bind(),客户端的端

android客户端和php服务简单交互

android客户端和php+mysql+apache搭建之间的简单交互,实现log信息存储. 实现原理就是android客户端发送请求,传给服务器log信息,服务器收到这些,连接数据库进行存储,并将存储后的状态返回给客户端. 服务器端: 先在mysql里面建一个testlog的数据库,里面有一个log_info表,记录了LogCategory,System,Executor,Action等信息. 在php的虚拟目录下新建一个php项目testlog,创建conn.php和log_deal.ph

Xamarin QQ Sdk的简单绑定过程

项目中要用到分享功能,但是又不想用第三方的分享Sdk,所有就直接去绑定原生Sdk来实现.这里简单记录一下iOS下QQ SDK的绑定过程,以备以后查询. 前面的准备工作就不说了,这里是在安装好Xcode,Sharpie的情况下去绑定.在这里碰到一个坑,如果你安装的Sharpie版本是3.4以下的版本,使用以下命令是没有问题的,可以正常生成ApiDefinition.cs和Structs.cs两个文件 sharpie bind --output=Static -namespace=TecentIM

MongoDB在MacOS上的客户端Robo 3T 的简单使用(二)

最近写了一个用node来操作MongoDB完成增.删.改.查.排序.分页功能的示例,并且已经放在了服务器上地址:http://39.105.32.180:3333. 本篇文章只做简单介绍,能够使用起来就OK,不深究 项目一共四部分: 1.MacOS下MongoDB数据库的安装配置. 2.MongoDB在MacOS上的客户端Robo 3T 的使用.(本篇文章) 3.Centos 下MongoDB数据库的安装配置. 4.node-express项目的搭建并通过mongoose操作MongoDB数据库