从Silverlight 4(Beta)流式传输网络摄像头

时间:2009-11-20 21:25:35

标签: silverlight silverlight-4.0 webcam

Silverlight 4中的新网络摄像头很酷。通过将其作为画笔公开,它允许超出Flash所具有的任何场景。

与此同时,在本地访问网络摄像头似乎只是故事的一半。没有人购买网络摄像头,这样他们就可以拍摄自己的照片并制作出有趣的面孔。他们购买网络摄像头是因为他们希望其他人看到最终的视频流,即他们希望将该视频流式传输到互联网,Skype或任何其他几十个视频聊天网站/应用程序。到目前为止,我还没有想出如何用

做到这一点

事实证明,保持原始(Format32bppArgb格式化)字节流非常简单,如here所示。

但是,除非我们想将原始字节流传输到服务器(这会占用过多的带宽),否则我们需要以某种方式对其进行编码。这更复杂。 MS已经在Silverlight中实现了几个编解码器,但据我所知,他们都专注于解码视频流,而不是首先对其进行编码。这与我无法弄清楚如何直接访问H.264编解码器的事实不同。

有大量的开源编解码器(例如,在ffmpeg项目here中),但它们都是用C语言编写的,并且它们看起来不容易移植到C#。除非翻译10000多行看起来像这样的代码才是你的乐趣: - )

const int b_xy= h->mb2b_xy[left_xy[i]] + 3;
const int b8_xy= h->mb2b8_xy[left_xy[i]] + 1;
*(uint32_t*)h->mv_cache[list][cache_idx ]= *(uint32_t*)s->current_picture.motion_val[list][b_xy + h->b_stride*left_block[0+i*2]];
*(uint32_t*)h->mv_cache[list][cache_idx+8]= *(uint32_t*)s->current_picture.motion_val[list][b_xy + h->b_stride*left_block[1+i*2]];
h->ref_cache[list][cache_idx ]= s->current_picture.ref_index[list][b8_xy + h->b8_stride*(left_block[0+i*2]>>1)];
h->ref_cache[list][cache_idx+8]= s->current_picture.ref_index[list][b8_xy + h->b8_stride*(left_block[1+i*2]>>1)];

Mono项目中的mooncodecs文件夹(here)在C#(ADPCM和Ogg Vorbis)中有几个音频编解码器,还有一个视频编解码器(Dirac),但它们似乎只实现了它们的解码部分各种格式,以及从中移植它们的java实现。

我为Ogg Theora(csTheora,http://www.wreckedgames.com/forum/index.php?topic=1053.0)找到了一个C#编解码器,但同样,它只是解码,就像它所基于的jheora编解码器一样。

当然,从Java移植编解码器可能比从C或C ++移植更容易,但我发现的唯一java视频编解码器只能解码(例如jheora或jirac)。 / p>

所以我有点回到第一个方向。看起来我们通过Silverlight将网络摄像头(或麦克风)连接到互联网的选项是:

(1)等待Microsoft就此提供一些指导;

(2)花费大脑周期将一个C或C ++编解码器移植到兼容Silverlight的C#;

(3)将原始的,未压缩的字节流发送到服务器(或者用zlib之类的东西稍微压缩),然后在服务器端编码;或

(4)等待比我更聪明的人解决这个问题并提供解决方案。

还有其他人有更好的指导吗?我是否错过了对其他人来说非常明显的事情? (例如,Silverlight 4在某个地方是否有一些我错过的关注这个的课程?)

5 个答案:

答案 0 :(得分:3)

我刚在博客上收到Jason Clary的回复:


在Mike Taulty的博客上看到关于Silverlight 4测试版中的VideoSink / AudioSink的帖子。

我想我会指出VideoSink的OnSample为您提供了一个未压缩的32bpp ARGB帧,可以直接复制到WritableBitmap中。

用手拿着FJCore,C#中的jpeg编解码器,并修改它不输出JFIF头。然后一个接一个地写出来,你就得到了一个Motion JPEG编解码器。 RFC2435解释了如何将其填充到RTTP流的RTP数据包中。

将PCM音频压缩到ADPCM也相当容易,但我还没有找到现成的实现。 RFC3551解释了如何将PCM或ADPCM放入RTP数据包。

将MJPEG和PCM或ADPCM填充到AVI文件中也应该相当容易。 MS在AVI修改后的RIFF格式上有一些不错的文档,MJPEG和ADPCM都是广泛支持的编解码器。

无论如何,这是一个开始。

当然,一旦你遇到了所有这些麻烦,下一个Beta版可能会提供原生支持,可以使用更好的WMV编解码器压缩和流式传输到WMS。


以为我会发布它。这是迄今为止我见过的最好的建议。

答案 1 :(得分:3)

我想我会让感兴趣的人知道我实际采取的方法。我正在使用CSpeex对语音进行编码,但我编写了自己的基于块的视频编解码器来对视频进行编码。它将每个帧划分为16x16块,确定哪些块已经充分改变以保证发送,然后使用经过大量修改的FJCore版本对已更改的块进行Jpeg编码。 (FJCore通常做得很好,但需要修改它以不编写JFIF头,并加速各种对象的初始化。)所有这些都是使用专有协议传递给专有媒体服务器,大致基于RTP。

当一个流向上并且四个流在144x176下降时,我目前每秒获得5帧,总共474 Kbps(~82 Kbps /视频流+ 32 Kbps /音频),并且咀嚼了大约30%我的开发箱上的CPU。质量不是很好,但对大多数视频聊天应用来说都是可以接受的。

自从我发布原始问题以来,已经有多次尝试实施解决方案。可能最好的是在SocketCoder网站here(和here)。

然而,由于SocketCoder动态JPEG风格的视频编解码器会转换每一帧的整体而不仅仅是已经改变的块,我的假设是CPU和带宽要求对大多数应用来说都是过高的。

不幸的是,在可预见的未来,我自己的解决方案必须保持专有: - (。

编辑7/3/10:我有权分享我对FJCore库的修改。我发布了这个项目(不幸的是没有任何示例代码):

http://www.alanta.com/Alanta.Client.Media.Jpeg.zip

如何使用它的(非常粗略)示例:

    public void EncodeAsJpeg()
    {
        byte[][,] raster = GetSubsampledRaster();
        var image = new Alanta.Client.Media.Jpeg.Image(colorModel, raster);
        EncodedStream = new MemoryStream();
        var encoder = new JpegFrameEncoder(image, MediaConstants.JpegQuality, EncodedStream);
        encoder.Encode();
    }


    public void DecodeFromJpeg()
    {
        EncodedStream.Seek(0, SeekOrigin.Begin);
        var decoder = new JpegFrameDecoder(EncodedStream, height, width, MediaConstants.JpegQuality);
        var raster = decoder.Decode();
    }

我的大多数更改都围绕着两个新类JpegFrameEncoder(而不是JpegEncoder)和JpegFrameDecoder(而不是JpegDecoder)。基本上,JpegFrameEncoder写入没有任何JFIF头的编码帧,JpegFrameDecoder对帧进行解码,而不期望任何JFIF头告诉它使用什么值(它假设你将以其他一些带外方式共享值) )。它还实例化它只需要一次的任何对象(作为“静态”),这样您就可以以最小的开销快速实例化JpegFrameEncoder和JpegFrameDecoder。预先存在的JpegEncoder和JpegDecoder类应该像以前一样工作,尽管我只做了很少的测试来确认。

我想要改进很多东西(我不喜欢静态对象 - 它们应该被实例化并单独传递),但它目前在我们的目的下运行良好。希望它对其他人有帮助。我会看看我是否可以改进代码/文档/示例代码/等。如果我有时间的话。

答案 2 :(得分:0)

我将添加另一条评论。我今天刚刚从一位微软联系人那里听说微软计划为Silverlight添加对上游音频和视频编码/流媒体的任何支持,因此选项#1似乎不在议事日程中,至少对于现在。我的猜测是,找出对此的支持将是社区的责任,即由你和我决定。

答案 3 :(得分:0)

权宜?

是否可以使用 Windows Media Encoder 作为Silverlight提供的原始视频的压缩方法?捕获到 ISO存储后,使用 WME 进行编码,然后通过 WebClient 发送到服务器。两个大问题是:

  • 需要用户安装编码器
  • WME 将不再受支持

似乎这可能是一个止损解决方案,直到有更好的东西出现。我之前没有用 WME 工作,所以我不知道这有多可行。想法?

答案 4 :(得分:-4)

您是否尝试过新的Expression 4编码器?

http://www.microsoft.com/expression/products/EncoderPro_Overview.aspx