由于vlc的安装文件一般是比较大,所以制作出来的cab文件也是很大的,在网络带宽不是很好的时候,光下载这个cab可能就很长很长时间,基本上可以说这样的方式是行不通的。所以
8. Activex的卸载
卸载是安装的反向操作,知道怎么安装,卸载很简单。
vlc-0.8.6i的Activex的卸载:新建uninstall.bat,内容如下:
regsvr32 dlls/axvlc.dll /u
vlc-0.9.4的Activex的卸载:新建uninstall.reg,内容如下:
Windows Registry Editor Version 5.00
[-HKEY_LOCAL_MACHINE/SOFTWARE/VideoLAN]
新建uninstall.bat,内容如下:
regsvr32 dlls/axvlc.dll /u
regedit /s uninstall.reg
双击uninstall.bat,提示dlls/axvlc.dll中的DllUnregisterServer成功。就卸载完毕了。
9. 让vlc安装的时候自动安装Activex
4里面提到cab包的制作及5里面提到了cab包的使用。cab其实就是让客户自动下载vlc的安装文件,然后启动安装。但是安装过程中,出现这样一步:
Activex plugin默认是没有被选中的,如何让它这一步默认是选中的,或者选中并且是灰色的(比如像Media Player这一项),不让客户改变呢?我们需要修改编译完的vlc的vlc.win32.nsi文件。然后用它重新制作vlc-0.9.4-win32.exe.
具体修改过程如下:
在vlc.win32.nsi文件中,找到:
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
Section /o $Name_Section04 SEC04
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
SectionIn 3
修改为:
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
Section $Name_Section04 SEC04
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
SectionIn 1 2 3
或者在1 2 3后面加入“空格RO”,表示这项是必须的不能去掉,就是选中并且是灰色的。$Name_Section04可以替换为"My ActiveX plugin (required)"等自己的名字。
然后根据前面博客讲的制作vlc-0.9.4-win32.exe的过程执行一遍,然后再制作cab包就okay了。
10. 关于vlc的Activex的说明
根据我对vlc的Activex的使用,发现这个Activex做的真是不好,很多方法没有封装进来,如果扩展这个Activex,工作量不小。如果是做C/S程序,
强烈不建议用Activex来开发。除非是想简单做一下,快速开发等。做C/S播放器还是看我这篇博客:《
vlc的应用之三:动态调用vlc-0.9.4的libvlc.dll 》,开发过程虽然慢点,但是比较可控。
Activex只适合应用于B/S项目,只适合WEB开发,这是Jeremiah的一点忠告,但是只属于个人意见,仅供参考。
vlc的应用之三:动态调用vlc-0.9.4的libvlc.dll
vlc-0.9.4提供的libvlc.dll是可以动态调用的,Jeremiah这一篇博客就介绍下如何用C#和WinForm框架调用libvlc.dll作个简易播放器。
1. vs2005新建工程,将vlc-0.9.4的libvlc.dll,libvlccore.dll,plugins目录全部拷贝到工程目录下面/bin/Debug中。
2. 创建异常结构体
using System;
using System.Collections.Generic;
using System.Text;
namespace MyOwnPlayer
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
//异常结构体
public
struct ExceptionStruct
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
private
int raised;
private
int code;
private
string message;
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
class MediaException
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
3. CoreHandle和Core类
using System;
using System.Runtime.InteropServices;
namespace MyOwnPlayer
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
class CoreHandle : SafeHandle
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
//构造方法
public CoreHandle()
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
:
base(IntPtr.Zero,
true)
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
//重写的方法
public
override
bool IsInvalid
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
get {
return handle == IntPtr.Zero; }
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
protected
override
bool ReleaseHandle()
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
if (!IsInvalid)
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
libvlc_release(
this);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
handle = IntPtr.Zero;
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
return
true;
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
protected
override
void Dispose(
bool disposing)
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
ReleaseHandle();
base.Dispose(disposing);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
//Dll动态导入
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
[DllImport(
"libvlc")]
private
static
extern
void libvlc_release(CoreHandle coreHandle);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
using System;
using System.Runtime.InteropServices;
namespace MyOwnPlayer
{
class Core
{
//coreHandle字段和属性
private CoreHandle coreHandle;
public CoreHandle CoreHandle
{
get { return coreHandle; }
}
//构造方法
public Core(string[] argv, ref ExceptionStruct ex)
{
coreHandle = libvlc_new(argv.Length, argv, ref ex);
}
//Dll动态导入
[DllImport("libvlc")]
private static extern CoreHandle libvlc_new(int argc, string[] args, ref ExceptionStruct ex);
}
}
3. MediaHandle和Media类,注意里面的非英文路径处理方法。
using System;
using System.Runtime.InteropServices;
namespace MyOwnPlayer
{
class MediaHandle : SafeHandle
{
//构造方法
public MediaHandle()
: base(IntPtr.Zero, true)
{
}
//重写的方法
public override bool IsInvalid
{
get { return handle == IntPtr.Zero; }
}
protected override bool ReleaseHandle()
{
if (!IsInvalid)
{
libvlc_media_release(this);
handle = IntPtr.Zero;
}
return true;
}
protected override void Dispose(bool disposing)
{
ReleaseHandle();
base.Dispose(disposing);
}
//Dll动态导入
[DllImport("libvlc")]
private static extern void libvlc_media_release(MediaHandle mediaHandle);
}
}
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace MyOwnPlayer
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
class Media
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
//mediaHandle字段和属性
private MediaHandle mediaHandle;
public MediaHandle MediaHandle
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
get {
return mediaHandle; }
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
//构造方法
public Media(CoreHandle coreHandle, String filename,
ref ExceptionStruct ex)
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
//c#为UTF-16编码, libvlc.dll为UTF-8编码, 需要转换.
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
UTF8Encoding utf8 =
new UTF8Encoding();
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
mediaHandle = libvlc_media_new(coreHandle, utf8.GetBytes(filename),
ref ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
//Dll动态导入
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
[DllImport(
"libvlc")]
private
static
extern MediaHandle libvlc_media_new
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
(CoreHandle coreHandle, [MarshalAs(UnmanagedType.LPArray)]
byte[] link,
ref ExceptionStruct ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
5. MediaPlayerHandle和MediaPlayer类
using System;
using System.Runtime.InteropServices;
namespace MyOwnPlayer
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
class MediaPlayerHandle : SafeHandle
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
//构造方法
public MediaPlayerHandle()
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
:
base(IntPtr.Zero,
true)
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
//重写的方法
public
override
bool IsInvalid
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
get {
return handle == IntPtr.Zero; }
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
protected
override
bool ReleaseHandle()
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
if (!IsInvalid)
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
libvlc_media_player_release(this);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
handle = IntPtr.Zero;
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
return
true;
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
protected
override
void Dispose(
bool disposing)
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
ReleaseHandle();
base.Dispose(disposing);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
//Dll动态导入
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
[DllImport(
"libvlc")]
private
static
extern
void libvlc_media_player_release(MediaPlayerHandle mediaPlayerHandle);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
using System;
using System.Runtime.InteropServices;
namespace MyOwnPlayer
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
class MediaPlayer
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
//mediaPlayerHandle字段和属性
private MediaPlayerHandle mediaPlayerHandle;
public MediaPlayerHandle MediaPlayerHandle
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
get {
return mediaPlayerHandle; }
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
//构造方法
public MediaPlayer(MediaHandle mediaHandle,
ref ExceptionStruct ex)
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
mediaPlayerHandle = libvlc_media_player_new_from_media(mediaHandle,
ref ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
//设置父窗口
public
void VedioSetParent(CoreHandle coreHandle, IntPtr hDT,
ref ExceptionStruct ex)
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
libvlc_video_set_parent(coreHandle, hDT,
ref ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
//播放
public
void Play(
ref ExceptionStruct ex)
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
libvlc_media_player_play(mediaPlayerHandle,
ref ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
//停止
public
void Stop(
ref ExceptionStruct ex)
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
{
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
libvlc_media_player_stop(mediaPlayerHandle,
ref ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
//Dll动态导入
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
[DllImport(
"libvlc")]
private
static
extern MediaPlayerHandle libvlc_media_player_new_from_media(MediaHandle libvlc_media_handle,
ref ExceptionStruct ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
[DllImport(
"libvlc")]
private
static
extern
void libvlc_video_set_parent(CoreHandle coreHandle, IntPtr hDT,
ref ExceptionStruct ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
[DllImport(
"libvlc")]
private
static
extern
void libvlc_media_player_play(MediaPlayerHandle mediaPlayerHandle,
ref ExceptionStruct ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
[DllImport(
"libvlc")]
private
static
extern
void libvlc_media_player_stop(MediaPlayerHandle mediaPlayerHandle,
ref ExceptionStruct ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
}
6. 基本工作做好了。下一步建立一个Form,里面画一个Panel(播放容器),画一个Textbox(播放地址),画一个Button(播放按钮),Button的点击事件为:
private void button1_Click(object sender, EventArgs e)
{
//要播放的文件的uri
string uri = this.textBox1.Text;
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
//进行播放的控件的句柄
IntPtr hdl = this.panel1.Handle;
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
//播放参数
string[] argv = new string[] { "-I", "--ignore-config" };
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
//vlc对象的创建
ExceptionStruct ex = new ExceptionStruct();
Core core = new Core(argv, ref ex);
Media media = new Media(core.CoreHandle, uri, ref ex);
MediaPlayer player = new MediaPlayer(media.MediaHandle, ref ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
//垃圾回收
GC.Collect();
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
//播放
player.VedioSetParent(core.CoreHandle, hdl, ref ex);
player.Play(ref ex);
![](http://img.e-com-net.com/image/info5/7222debe630e4b02bdc4ad2b7da56134.gif)
//继续回收垃圾等相关操作
GC.Collect();
GC.WaitForPendingFinalizers();
}
7. 基本的播放功能就是这样实现的。其他接口请参考源码下面的/include/vlc/libvlc.h文件,里面有比较详细的对外接口的说明。
8. 以上代码已经发送到附件中(MyOwnPlayer.rar),参考网址的楼主写的代码也在附件中(Marx_libvlc_wrapper(2).zip)。调试附件请注意第1步。
vlc的应用之四:vlc的Mozilla Plugin
Jeremiah最近研究了下让vlc支持Mozilla的火狐浏览器,也就是类似于IE的Activex。现在将研究的结果共享一下。
1. 测试的版本为vlc-0.9.4,当然编译的环境为旧版本的Cygwin(我的叫法,不是官方的叫法),具体的安装配置编译vlc-0.9.4,不明白的去看我的前几篇博客,里面详细的介绍了。
2. 编译脚本为configure-vlc04.sh(附件提供)。
PATH=/usr/win32/bin:$PATH /
PKG_CONFIG_LIBDIR=/usr/win32/lib/pkgconfig /
CPPFLAGS="-I/usr/win32/include -I/usr/win32/include/ebml" /
LDFLAGS=-L/usr/win32/lib /
CC="gcc -mno-cygwin" CXX="g++ -mno-cygwin" /
./configure /
--host=i686-pc-mingw32 /
--disable-gtk /
--enable-nls --enable-sdl --with-sdl-config-path=/usr/win32/bin /
--enable-avcodec --enable-avformat --enable-swscale /
--enable-faad --enable-flac --enable-theora /
--with-wx-config-path=/usr/win32/bin /
--with-freetype-config-path=/usr/win32/bin /
--with-fribidi-config-path=/usr/win32/bin /
--enable-live555 --with-live555-tree=/usr/win32/live.com /
--enable-caca --with-caca-config-path=/usr/win32/bin /
--with-xml2-config-path=/usr/win32/bin /
--with-dvdnav-config-path=/usr/win32/bin /
--disable-cddax --disable-vcdx --enable-goom /
--enable-twolame --enable-dvdread /
--enable-debug --enable-dca /
--enable-mozilla --with-mozilla-sdk-path=/usr/win32/gecko-sdk /
--disable-mkv --disable-taglib
3. 编译中出错及解决方法见[url]http://jeremiah.blog.51cto.com/539865/115322[/url]
4. 编译完成后打包(make package-win32-base)。
5. 将打包好的vlc-0.9.4文件夹下面的libvlc.dll,libvlccore.dll, plugins, mozilla/npvlc.dll拷贝到一个单独的目录下,比如E:/WorkBack/vlc-0.9.4/Mozilla Plugin/dlls。
6. 新建注册表文件mozilla_plugin.reg(见附件),内容为:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE/SOFTWARE/MozillaPlugins/@videolan.org/vlc,version=0.9.4]
"De.ion"="VLC Multimedia Plugin"
"Path"="E://WorkBack//vlc-0.9.4//Mozilla Plugin//dlls//npvlc.dll"
"Product"="VLC media player"
"Vendor"="VideoLAN"
"Version"="0.9.4"
[HKEY_LOCAL_MACHINE/SOFTWARE/VideoLAN/VLC]
"InstallDir"="E://WorkBack//vlc-0.9.4//Mozilla Plugin//dlls"
"Version"="0.9.4"
"Language"="2052"
7. 运行这个注册表文件。
8. 到打包好的vlc-0.9.4下面的activex目录中,用火狐打开test.html测试,done!
vlc的应用之五:动态调用libvlc.dll的补充
最近Jeremiah在增加以前播放器的功能的时候,被一个中文路径转码问题恶心了两天,最后终于让我给解决了。在这跟大家分享这个转码的解决方法,以及用视频本次存储的接口实现。
在看本篇日志之前,请先看我以前写的《vlc的应用之三:动态调用vlc-0.9.4的libvlc.dll 》。
补充一:libvlc_new(...)接口的中文路径转码处理
using System;
using System.Runtime.InteropServices;
namespace MyOwnPlayer
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
{
class Core
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
{
//coreHandle字段和属性
private CoreHandle coreHandle;
public CoreHandle CoreHandle
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
{
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
get {
return coreHandle; }
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
}
//构造方法
public Core(
string[] argv,
ref ExceptionStruct ex)
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
{
byte[][] argvbytes =
new
byte[argv.Length][];
for (
int i = 0; i < argv.Length; i++)
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
{
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
argvbytes[i] = Encoding.UTF8.GetBytes(argv[i]);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
}
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
coreHandle = libvlc_new(argv.Length, ReturnIntPtr(argvbytes, argv.Length),
ref ex);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
}
//转换函数
private IntPtr ReturnIntPtr(
byte[][] data,
int length)
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
{
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
IntPtr[] dataIntPtrArr =
new IntPtr[length];
for (
int i = 0; i < length; i++)
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
{
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
dataIntPtrArr[i] = Marshal.AllocHGlobal(data[i].Length *
sizeof(
byte));
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
Marshal.Copy(data[i], 0, dataIntPtrArr[i], data[i].Length);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
}
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
IntPtr dataIntPtr = Marshal.AllocHGlobal(length * Marshal.SizeOf(
typeof(IntPtr)));
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
Marshal.Copy(dataIntPtrArr, 0, dataIntPtr, length);
return dataIntPtr;
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
}
//Dll动态导入
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
[DllImport(
"libvlc")]
private
static
extern CoreHandle libvlc_new(
int argc, IntPtr argv,
ref ExceptionStruct ex);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
}
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
}
补充二:本地存储。
对libvlc_new的argv进行转码的主要目的就是为了进行本地存储,由于要将存储路径传入到argv中,所以要对中文的存储路径进行转码。下面的做法是将视频流默认存储为ts流,边播放边存储。
//avPath是本地存储路径,需要注意路径的/和/的问题。
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
argv =
new
string[] {
"--sout=#duplicate{dst=display,dst=std{access=file,mux=ts,dst=" + avPath +
"}}" };
//其他的就跟上一篇博客一样了。
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
core =
new Core(argv,
ref ex);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
media =
new Media(core.CoreHandle, link,
ref ex);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
player =
new MediaPlayer(media.MediaHandle,
ref ex);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
player.Play(
ref ex);
//一面播放一面存储
关于其他形式的argv,可以在vlc的存储里面获得。vlc -> 媒体 -> convert/save -> 转换/保存。根据选择不同的形式,在vlc界面的下半部分会有Generated stream output string。这个就是具体的argv。不过,请注意将:sout换成--sout。
参考网址:
1.
[url]http://rogerfd.cn/?p=189[/url]
写在这篇博客之后:
1. Jeremiah对vlc其实并不熟,我也不是vlc专家,视频服务器专家,呵呵,所以,有时候大家问我的问题,其实,我自己也很不明白,不能误导大家。但是我只要明白的,懂得的,都会毫不保留的跟大家交流。Jeremiah只是根据自己的业务需求来用vlc,当然,用vlc第一步就是要编译它。编译vlc花了我N多心血。其他的业务需求主要是借用vlc作一个自己的软解码器,播放网络H264流。所以,对vlc客户端的学习多一些,包括C#调用vlc接口,还有activex控件的相关内容。但是对vlc的服务器方面的应用掌握的不够多。Jeremiah略懂java,略懂C#,但是对C,C++,VC及控件等,非常不熟悉,所以,研习vlc代码,一直迟迟没有进行。
2. Jeremiah编译这几个版本的vlc,都是经过严格的测试,才发到博客上面的,而且,尽量的写的已经不能再详细的地步。所以,如果根据我的博客编译不成功,肯定是哪一步没有搞正确。如果每一步都搞正确了,最后还没有编译成功,我只能说RP到极点了。
3. 很多时候Google比Jeremiah好用许多。很多信息都会出现在官网的文档上。还有./configure -h和vlc -H这些命令也能提供很多资料,研习下这些资料,比Jeremiah直接告知,能学到更多的东西。
4. vlc研究群里面有N多高手,如果有问题得不到解决,去群里面忽悠忽悠吧。
5. vlc这个专题的文章,Jeremiah以后会继续发,但是由于本人能力有限,估计不会经常更新了。不过只要我学到了新的关于vlc的东西,我就会整理了发上来。也希望各位高手能能多多帮助我,多多提意见。
6. vlc的调用过程大体说一下,一般都是vlc界面或者activex或者自己写的程序->libvlc.dll->libcore.dll->plugins,所以,在进行相关调试的时候,这样的目录结构是不能变的,也就是libvlc.dll,libcore.dll,plugins目录是在一级目录下面,而不是一堆dll在一个目录下面。
7. 2009-03-11开通vlc中文论坛,地址为:http://bbs.dvbcn.com/vlc/。
写得比较乱,先到此,以后想起什么,再补充。
vlc的应用之六:简单的视频点播系统(B/S)的实现
前两天帮“猪小妹”考虑毕业设计的时候,想了想视频点播系统的该如何实现。在这写一下自己的想法和非常简单的实现方式,纯属娱乐,请勿拍砖。
1. 大体的架构及流程
实现视频点播系统,B/S架构,服务端至少应该是两个服务器:流媒体服务器,web服务器。客户端则就是web页面。当开启页面后则是客户端和服务器的第一次交互,通过http协议得到页面。里面会有流媒体地址的信息,浏览器里面点击显示视频组件,将流媒体的地址传给流媒体播放器,并启动播放器去请求视频。这是第二次交互。服务器端流媒体服务器发送流给客户端,页面上播放就okay了。
2. 环境及所需软件
Jeremiah的测试环境是xp sp2及IE8浏览器。IP地址:172.16.128.8. 与IP有关的地址,请根据个人情况自己改。
服务端:
流媒体服务器先用个简单的:live555 Media Server(http://www.live555.com/mediaServer/windows/live555MediaServer.exe)
Web服务器:Jeremiah以前学的JAVA,所以用Tomcat。IIS或者其他的Web服务器都可以。其实Jeremiah这个小系统用的是静态页面,所以如果是在本机测试的话,不用Web服务器也是okay的。模拟本地打开为Web浏览。
客户端:vlc-0.9.4的Activex。需要把Activex注册好(参考http://jeremiah.blog.51cto.com/539865/115943)
3. 配置流媒体服务器
下载完live555 Media Server之后放到d:/video下面,启动时会有以下信息:
"Play streams from this server using the URL
rtsp://172.16.128.8/<filename>
where <filename> is a file present in the current directory."
并且后面还会有live555支持的视频格式。
本测试就用的mp3和ts格式。其他格式没有试验过。
mp3好说,ts怎么得到呢?这时候vlc就出场了。vlc有转换保存功能,媒体->转换/保存->选择某个文件后点击转换/保存->流输出页面勾选本地播放,勾选文件并且浏览得到个文件名,注意后缀为ts而不是ps,方案封装选MPEG-TS,然后点击save。把你选择的视频播放一遍之后,ts格式的文件就生成好了。
将生成好的ts文件和网上下载的mp3放到d:/video下面,本测试为01.ts及02.mp3。这样流媒体服务器就配置好了。
4. web页面代码
本web页面代码是vlc的Activex测试代码test.html上修改精简的。(没写注释,因为看着不难。)
vod.html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<
html
xmlns
="http://www.w3.org/1999/xhtml"
>
<
head
>
<
meta
http-equiv
="Content-Type"
content
="text/html; charset=UTF-8"
/>
<
script
>
var itemId = 0;
function getVLC(name)
{
if (window.document[name])
{
return window.document[name];
}
if (navigator.appName.indexOf("Microsoft Internet")==-1)
{
if (document.embeds && document.embeds[name])
return document.embeds[name];
}
else
{
return document.getElementById(name);
}
}
function doGo(mrl)
{
var vlc = getVLC("vlc");
itemId=vlc.playlist.add(mrl);
vlc.playlist.playItem(itemId);
document.getElementById("btn_stop").disabled = false;
}
function updateVolume(deltaVol)
{
var vlc = getVLC("vlc");
vlc.audio.volume += deltaVol;
}
function doPlay()
{
vlc.playlist.playItem(itemId);
document.getElementById("btn_stop").disabled = false;
document.getElementById("btn_play").disabled = true;
}
function doStop()
{
getVLC("vlc").playlist.stop();
document.getElementById("btn_stop").disabled = true;
document.getElementById("btn_play").disabled = false;
}
</script>
</head>
<
body
>
<
div
style
="margin: 50px"
>
<
a
title
="rtsp://172.16.128.8/01.ts"
href
="#"
onclick
="doGo(this.title);return false;"
>01.ts
</a>
<
span
style
="margin: 20px;"
/>
<
a
title
="rtsp://172.16.128.8/02.mp3"
href
="#"
onclick
="doGo(this.title);return false;"
>02.mp3
</a>
<
span
style
="margin: 20px;"
/>
</div>
<
div
>
<object classid="clsid:9be31822-fdad-461b-ad51-be1d1c159921"
width="640"
height="480"
id="vlc"
events="true">
<
param
name
="mrl" value=""
/>
<
param
name
="showdisplay"
value
="true"
/>
<
param
name
="autoloop"
value
="false"
/>
<
param
name
="autoplay"
value
="false"
/>
<
param
name
="volume"
value
="50"
/>
<
param
name
="starttime"
value
="0"
/>
<embed pluginspage="http://www.videolan.org"
type="application/x-vlc-plugin"
version="videolan.vlcplugin.2"
width="640"
height="480"
name="vlc">
</embed>
</object>
</div>
<
div
>
<
input type=button
id
="btn_play"
value
=" 播放 "
onClick
='doPlay();'
disabled
="true"
>
<
input type=button
id
="btn_stop"
value
="停止"
onClick
='doStop();'
disabled
="true"
>
<
input type=button
value
="静音切换"
onclick
='getVLC("vlc").audio.togglemute();'
>
<
input type=button
value
="减小音量"
onclick
='updateVolume(-10)'
>
<
input type=button
value
="增加音量"
onclick
='updateVolume(+10)'
>
</div>
</body>
</html>
将vod.html放置到Web服务器中。我就不多说了。so简单。
5. 访问vod.html
访问前请确保客户端Activex控件已注册成功。
打开IE输入http://172.16.128.8:8080/vod/vod.html后访问到我们上面写的页面。然后点击01.ts超链接,在下面的vlc的Activex上就会显示视频了。这样,一个简单的点播系统就做好了。
请注意下面图片的视频上的地址。
6. C/S架构的实现
做成跟pplive类似的客户端,考虑与服务器的两次交流,第二次交流是没有问题的,关键在第一次交流上。如果客户端做成嵌入IE的方式,如C#的WebBrowser,则点击某个视频地址的信息模块,如超链接,无法将超链接的地址传给播放器组件了。Jeremiah考虑的解决的方法就是第一次与Web服务器的交流可以用xml来实现。客户端获取xml,然后解析,然后显示到某个组件里面,如C#的Listbox,这样点击这个组件就可以轻易的将视频地址传给播放器组件了。pplive的频道列表,估计就是用的这种方式。
vlc的应用之七:用vlc做单播,组播及点播服务器
还是前两天帮“猪小妹”考虑毕业设计的时候,想了想vlc能不能作为vod的服务器,替代上一篇博客里面的live555 media server,因为live555 media server做的确实不是太好。查了些资料,在vlc群里面乱问了一通,终于解决了。好东西啊,大家共享。
在这感谢vlc研究群“樱木”童鞋提供的帮助。
1. 所需软件
vlc-0.9.9或vlc-0.8.6i,主要测试的是比较新的0.9.9版本的。
putty:一款集telnet,ssh远端登陆的非常好的软件。下载地址:http://wrc.gro.clinux.org/putty/putty.exe
2. 命令行启动vlc,并打开后台信息显示,有助于观察后台信息
开启cmd,并cd到vlc的目录,执行
vlc -vv --extraintf=logger
3. 开启vlc的telnet服务
vlc-0.9.9在界面上选择工具->界面->telnet控制台
后台dos窗口会有反应,显示
[00000403] main interface debug: looking for interface module: 1 candidate
[00000403] main interface debug: creating VLM
[00000405] main vlm daemon debug: thread 5112 (vlm thread) created at priority 0
(../../src/input/vlm.c:112)
[00000405] main vlm daemon debug: thread started
[00000403] telnet interface: using the VLM interface plugin...
[00000403] main interface debug: net: listening to 127.0.0.1 port 4212
[00000403] telnet interface: telnet interface started on interface 127.0.0.1 421
2
[00000403] main interface debug: using interface module "telnet"
[00000403] main interface debug: TIMER module_Need() : 19.000 ms - Total 19.000
ms / 1 intvls (Avg 19.000 ms)
[00000403] main interface debug: thread 5136 (interface) created at priority 0 (
../../src/interface/interface.c:168)
[00000403] main interface debug: thread started
注意观察main interface debug: net: listening to 127.0.0.1 port 4212这句话,说明vlc现在的telnet监听的是127.0.0.1这个地址和4212这个端口。如果没有显示ip的话,一般用127.0.0.1是没有问题的。127.0.0.1就表示的本机,与localhost是同一个意义。
4. 启动putty.exe
主机名称(或ip)输入:127.0.0.1
端口:4212
连接类型:选Telnet
点打开。
如果没有出现"Password:"字样,点打开就关闭了,那就说明没有telnet上。(这个时候可以在cmd里面输入telnet 127.0.0.1 4212,看结果应该是正在连接到127.0.0.1...不能打开到主机的连接, 在端口 4212: 连接失败,或者是与主机失去连接。不用cmd的telnet连接的主要原因是过会输入命令的时候看不到。)这个时候,请关闭防火墙,杀毒软件及一切相关软件,不过中毒了别找我哎。(*^__^*) 嘻嘻……继续继续。
如果没有出现以上问题,在Password:后面输入"admin",没有明文回显。登录成功后会显示:Welcome, Master。
5. 架设点播服务vod
分别输入:
new vod1 vod enabled
setup vod1 input d:/01.avi
解释下:
new了一个名字叫vod1的vod,设置vod1的input为d:/01.avi。
验证:开启另一个vlc,打开rtsp://127.0.0.1/vod1。应该就可以播放了。127.0.0.1可以换成自己的ip。
6. 架设组播服务器
继续输入:
new ch1 broadcast enabled
setup ch1 input d:/02.avi [loop]
setup ch1 output #duplicate{dst=rtp{dst=226.0.0.6,mux=ts,port=1234}}
control ch1 play
解释下:
new了一个名字叫ch1的broadcast。设置ch1的input为d:/02.avi,loop可选,表示循环播放。设置ch1的output为#duplicate{dst=rtp{dst=226.0.0.6,mux=ts,port=1234}},表示rtp协议的ts流发送到组播地址为226.0.0.6,端口1234。控制ch1播放。
扩充:
1) output后面可以跟sout参数。具体可以参考vlc->媒体->流->流输出界面的已生成的流输出字符串。
2) control ch1后面还可以加stop,pause,seek 百分比。表示停止,暂停和跳转到百分之几的位置。
验证:开启一个vlc,打开rtp://226.0.0.6:1234。应该就可以播放了。
7. 架设单播服务器
第6步里面的output换成单播的地址就行了。其他的都一样的。注意不要new重名了。
8. 保存刚才操作
继续输入
将刚才操作保存到了d:/01.cfg里面,除了control。可以通过记事本等文本编辑器查看一下里面的内容。
如果重新开启了vlc,则可以输入
将刚才保存的操作读入进来,继续操作或控制。
通过这样的配置,一个vlc的实例可以提供多个服务,包括单播,组播和点播。确实强大啊。
这样上一篇博客的流媒体服务器可以替换为vlc了。跟上一篇日志结合作个简单的流媒体服务的网站或者类似于pplive的客户端,就不是太有技术难度的事情了。
vlc的应用之八:MFC调用libvlc.dll
本篇博客将简单介绍MFC调用libvlc.dll作一个简单的播放器,抛砖引玉,各位VC++达人继续深入研究,Jeremiah对VC++确实不太感兴趣,所以就不做太深入的研究了。
2009.10.29修改:加入clip_children属性设置。参考第1步。
2010.04.14修改:中文路径问题。参考第7步。
环境:
1) VC6 SP5
2) vlc-0.9.9a
0. 引言
根据上一篇博客的研究,任何一个VC环境都可以调用MinGW/Gcc编译得到的libvlc.dll。VLC在编译打包之后(也就是执行完make package-win32-base),或者去官网下载zip包解压之后,或者是安装完VLC之后,在vlc-0.9.9a目录下有个sdk文件夹,里面又包含两个文件夹:include--头文件及lib--库。这些都是我们用MFC调用libvlc.dll所必须的。头文件没啥好说的,库里面的libvlc.dll.a及libvlccore.dll.a就是上一篇博客所说的静态库,我们分别手动改成libvlc.lib及libvlccore.lib就可以在VC环境中调用啦。下面简要说一下调用的过程,对各位VC++达人来说绝对是小菜一碟。
1. 建立工程
新建MFC AppWizard(exe)工程,名字为:MFCVLC。选择项目为Dialog based,点击完成。删除Dialog窗体上的所有的控件,包括“确定”、“取消”按钮及"TODO"静态文本。勾选窗口的clip_children属性,这样就会避免拖动、最大化最小化及全屏还原时找不到图像的缺陷。
2. 画控件
画四个控件,两个静态文本框,一个输入框,一个按钮。其中,第一个静态文本框修改Caption为“路径:”,第二个文本框为视频的显示区域,所以讲ID改为IDC_DISPLAY,Caption去掉。输入框关联一个变量,CString类型,命名为m_path。按钮的Caption改为“播放”,并为BN_CLICKED增加一个Function。在CMFCVLCdlg的构造方法中加入一下语句方便调试。
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
m_path = _T(
"d:/01.avi");
// 输入常用的视频地址
3. 拷贝vlc的相关库及头文件
在资源管理器的MFCVLC工程目录下新建文件夹vlc,lib,将vlc-0.9.9a/sdk/include/vlc.h拷贝到MFCVLC工程目录下,将vlc-0.9.9a/sdk/include除了vlc.h之外的所有文件拷贝到vlc目录下,将vlc-0.9.9a/sdk/lib下的libvlc.dll.a及libvlccore.dll.a拷贝到lib下,并分别修改为libvlc.lib及libvlccore.lib。将vlc-0.9.9a目录下的libvlc.dll, libvlccore.dll, plugins目录拷贝到Debug目录下。如果有Cygwin环境,需要将stdint.h(/usr/include/stdint.h)这个头文件也拷贝到MFCVLC工程目录下。在VC6环境中FileView中新建文件夹及导入上述文件,最后入下图所示。
4. 修改头文件
1) 修改vlc.h,将所有的#include <***>改为 #include "***"
2) 修改stdint.h,将所有的long long替换为__int64
3) 修改libvlc_structures.h,#include <stdint.h>为#include "stdint.h"
5. 编写代码
在MFCVLCDlg.cpp中加入头文件导入。
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
#include
"vlc.h"
在button的onclick关联函数中加入代码:
void CMFCVLCDlg::OnButton1()
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
{
// TODO: Add your control notification handler code here
char path[100];
this->GetDlgItemText(IDC_EDIT1, path, 100);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
libvlc_exception_t ex;
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
libvlc_exception_init(&ex);
int vlc_argc = 0;
char *vlc_argv[100];
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
vlc_argv[vlc_argc++] =
"--ignore-config";
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
libvlc_instance_t *p_instance = libvlc_new(
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
vlc_argc, vlc_argv, &ex);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
libvlc_media_t *p_media = libvlc_media_new(
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
p_instance, path, &ex);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
libvlc_media_player_t *p_media_player
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
= libvlc_media_player_new_from_media(
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
p_media, &ex);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
libvlc_drawable_t hwnd =
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
(libvlc_drawable_t)
this->GetDlgItem(IDC_DISPLAY)->GetSafeHwnd();
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
libvlc_media_player_set_drawable(p_media_player, hwnd, &ex);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
libvlc_media_player_play(p_media_player, &ex);
![](http://img.e-com-net.com/image/info5/788e72afe1ac400fbfef35c3fd22d5bf.gif)
}
6. 关联静态库及编译运行
打开Project Setting,在link标签的Object/library modules:下输入
lib/libvlc.lib lib/libvlccore.lib。
build项目,应该没有错误。
Execute Program就可以执行了。
7. 两个BUG
第6步执行的是Execute模式,如果是Debug模式,点击“播放”后,后台会显示加载的vlc的plugins的dll的信息,但是加载完最后一个dll的时候程序就Block住了。暂时不晓得为啥。经过更多的测试(win2003虚拟机里的vc6),发现Jeremiah的VC6可能真的有问题,debug的时候,打开Output窗口显示加载的dll的情况,就会block住。不打开Output窗口偶尔会set_drawable不成功,弹出新窗口。其他几位朋友测试则正常。
上面的代码如果开带中文路径的地址会无法打开,因为传入的中文路径vlc识别不了。需要将路径也就是path变量从ANSIZ转换为UTF8代码。具体怎么转换,各位VC达人自己研究吧。
8. 用VC6以上版本调试结果
Jeremiah使用了vs2003及vs2005。
1) 会两个重复定义的错误,解决方法是将stdint.h中注释掉:
2) 发布Release版本会报内存错误。具体原因待查,应该是.lib不兼容的问题。不知道为啥Debug版就可以而Release版就不行。解决方法是用dll2lib.exe(附件提供)将0.9.9a的libvlc.dll及libvlccore.dll转换为相应的lib库,替换工程的lib/下面的相应的库,然后再次Release即可。
Jeremiah对MFC只有一点点了解,所以上述的各个过程如果重复烦琐,及如何修复第7,8步讲的BUG及问题,请各位VC++达人指导Jeremiah。先谢过。本文附件中提供了MFCVLC的源码,只是需要把vlc-0.9.9a的libvlc.dll, libvlccore.dll, plugins目录拷贝到Debug目录下就可以编译执行。需要的自己下载添加调试。
vlc的应用之九:用vlc串流摄像头
n就没有更新博客了,主要是Jeremiah最近对vlc研究的非常的少了,工作重点转移了,又增加了管理工作,让Jeremiah忙的晕头转向的。
这篇博客是很久之前就想写的,今天终于提笔写了,心情还是比较爽的。废话不多说。
0. 环境搭建
Jeremiah这次主要是用的vlc-1.0.0(英文版)进行讲解。首先需要准备摄像头,Jeremiah用的是一个普通摄像头(以前钓MM用的,嘻嘻),驱动安装好后,在“我的电脑”中显示如下。
1. vlc播放摄像头
开启vlc-1.0.0,media->open capture device,进入Capture Device页面。这个也可以通过media->Advanced open file,选取此标签页。
video device name选择VIMICRO USB PC Camera (ZC0301PLH),如果没有,请先选择Refresh list刷新列表。
audio device name选择SoundMAX HD Audio,这个是Jeremiah的声卡。
之后可以勾选show more options,里面可是设置缓冲及看到MRL和Edit Options,这些信息都是很重要的。Advance Option按钮里面有一些详细设置,大家可以进去选择,其中video size是可以做调整的。下面会讲到。
之后点play,就可以播放了。
2. 用命令行开启vlc播放摄像头
命令行的最大好处就是,vlc命令后面的参数,就是我们在编程的时候调用libvlc_new的argv,将这些参数搞明白,我们就可以在编程的时候调用了。
开启cmd,切换到vlc目录下。
根据1中的MRL和Edit Options信息,设置vlc播放参数如下。
vlc dshow:// :dshow-vdev="VIMICRO USB PC Camera (ZC0301PLH)" :dshow-adev="SoundMAX HD Audio" :dshow-size=320*240
各个参数什么意思都是很明显的,如果不明白,就运行vlc -H,然后到vlc目录下面去找vlc-help.txt,里面是全部的参数的介绍。
3. 将vlc播放的摄像头信息存入文件中
播放成功之后,在达到我们的目的前,我们先做一个简单的验证工作,就是播放摄像头并存入文件。
根据以前stream到文件的参数,修改2的参数如下。
vlc dshow:// :dshow-vdev="VIMICRO USB PC Camera (ZC0301PLH)" :dshow-adev="SoundMAX HD udio" :dshow-size=320*240 :sout=#transcode{vcodec=h264,vb=800,scale=1,acodec=mp3,ab=128,channels=2,samplerate=44100}:std{access=file,mux=ts,dst=D:/01.ts}}
这里用到了转码,就是将摄像头的视频编码为h264,音频编码为MP3,然后封装为ts写入到d:/01.ts中。
这个不会显示摄像头,但是通过刷新d:/01.ts就会发现这个文件是在增大的,也就是有视频流在写入。
4. 将摄像头串流到网络中
根据3的参数做简单的修改就可以达到串流摄像头视频流到网络的目的了。修改3的参数如下。
vlc dshow:// :dshow-vdev="VIMICRO USB PC Camera (ZC0301PLH)" :dshow-adev="SoundMAX HD Audio" :dshow-size=320*240 :sout=#transcode{vcodec=h264,vb=800,scale=1,acodec=mp3,ab=128,channels=2,samplerate=44100}:duplicate{dst=display,dst=rtp{dst=127.0.0.1,mux=ts,port=1234}}
这里的duplicate大家应该都很熟悉了,因为在录像,vlm里面都讲过这个参数。参数的意思是,将摄像头的音视频流分别编码为MP3和h264之后封装为ts,然后通过rtp发送到127.0.0.1的1234端口上,同时显示出来。如果希望发送到其他网络地址或组播里面只需要改变127.0.0.1和1234为我们需要的地址和端口即可。
再开启一个vlc,播放这个ts over rtp流。
vlc rtp://@:1234 --rtp-caching=1500
成功后就可以看到了。切图如下:
左边的是摄像头的流服务,右边的是流的客户端,从下边的地址就能看的很清楚。
5. 遗留问题:
从图片可以看出,播放的视频颜色是不对的,是摄像头的问题还是vlc本身的问题还是参数设置的问题,现在不得而知,当然摄像头本身是没问题的,因为qq视频都很正常。希望谁研究出来告诉我一声。谢谢。