【问题标题】:Streaming a webcam from Silverlight 4 (Beta)从 Silverlight 4(测试版)流式传输网络摄像头
【发布时间】:2010-12-18 21:39:51
【问题描述】:

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 项目 (here) 中的 mooncodecs 文件夹有几个 C# 音频编解码器(ADPCM 和 Ogg Vorbis)和一个视频编解码器 (Dirac),但它们似乎都只实现了各自格式的解码部分,以及它们被移植的 java 实现。

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

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

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

(1) 等待微软对此提供一些指导;

(2) 花费脑力将 C 或 C++ 编解码器之一移植到与 Silverlight 兼容的 C#;

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

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

还有其他人有更好的指导吗?我是否错过了对其他人来说非常明显的东西? (例如,Silverlight 4 是否有一些我错过的课程可以解决这个问题?)

【问题讨论】:

    标签: silverlight silverlight-4.0 webcam


    【解决方案1】:

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


    在 Mike Taulty 的博客上看到了您关于 Silverlight 4 beta 中的 VideoSink/AudioSink 的帖子。

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

    使用 C# 中的 jpeg 编解码器 FJCore,并将其修改为不输出 JFIF 标头。然后把它们一个接一个地写出来,你就得到了一个 Motion JPEG 编解码器。 RFC2435 解释了如何将其填充到 RTP 数据包中以进行 RTSP 流传输。

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

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

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

    当然,一旦你解决了所有这些问题,下一个 Beta 版可能会提供对压缩和流式传输到 WMS 的原生支持,并带有更好的 WMV 编解码器。


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

    【讨论】:

      【解决方案2】:

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

      在 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 类的工作方式应该与以往几乎相同,尽管我只做了一点点测试来确认这一点。

      有很多我想改进的地方(我不喜欢静态对象——它们应该被实例化并单独传入),但目前它对于我们的目的来说已经足够好了。希望它对其他人有帮助。我会看看我是否可以改进代码/文档/示例代码/等。如果我有时间。

      【讨论】:

      • 感谢您的示例,肯。我有一个 silverlight 应用程序,我希望它允许将用户创建的视频上传到 facebook。然而,即使我得到了 m-jpeg 编码工作,这不是通过 FB 支持的编解码器。呸呸呸。很遗憾 MS 没有在这里帮助我们。
      【解决方案3】:

      我将添加另一条评论。我今天刚刚从 Microsoft 联系人那里得知,Microsoft 计划向 Silverlight 添加对上游音频和视频编码/流式传输的任何支持,因此选项 #1 似乎不在讨论范围内,至少对现在。我的猜测是,找出对此的支持将是社区的责任,即取决于你和我。

      【讨论】:

        【解决方案4】:

        止损?

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

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

        在出现更好的情况之前,这似乎是一个权宜之计。我之前没有与 WME 合作过,所以我不知道这有多可行。想法?

        【讨论】:

        • 除了用户需要安装 Windows Media Encoder 之外,Silverlight 将无法与 WME 对话,除非应用程序在浏览器外运行且处于完全信任模式:此时,不再完全清楚为什么我们需要在 Silverlight 中这样做:-)。
        【解决方案5】:

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

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

        【讨论】:

        • 除非我遗漏了一些重要的东西,否则 WME 不是 Silverlight 客户端实时编码的解决方案。
        • 你错过了一些东西。这不是 WME。因为它支持 QuickTime、H.264、AAC-LC,Windows Media Encoder 目前不支持所有这些。它还支持 AVI、MPEG-2 等。不太确定您的问题,但这是 Microsoft Expressions Endcoder 工具的核心,它是一个客户端应用程序,不仅支持 Windows Media 格式。
        • Nick,Ken 强调的不是“WME”,而是“实时”。
        猜你喜欢
        • 2014-06-18
        • 2013-05-14
        • 2016-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-22
        相关资源
        最近更新 更多