代码之家  ›  专栏  ›  技术社区  ›  Ken Smith

从Silverlight 4流式传输网络摄像机(试用版)

  •  16
  • Ken Smith  · 技术社区  · 15 年前

    Silverlight4中最新的网络摄像头很酷。通过将其作为画笔公开,它允许场景远远超出了Flash的所有功能。

    同时,在本地访问网络摄像头似乎只是故事的一半。没有人会买一个摄像头,这样他们就可以拍下自己的照片,并从中做出有趣的表情。他们购买网络摄像头是因为他们希望其他人看到产生的视频流,也就是说,他们希望将视频流到互联网、Play Skype或其他几十个视频聊天网站/应用程序中的任何一个。到目前为止,我还没弄明白怎么做

    事实证明,获取原始(格式化32bppargb)字节流非常简单,如图所示。 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编解码器(C PCI)(ADPCM和OGG VoRBIS),以及一个视频编解码器(狄拉克),但是它们似乎都只是实现了它们各自格式的解码部分,就像它们移植的Java实现一样。

    我为OggTheora(cstheora, http://www.wreckedgames.com/forum/index.php?topic=1053.0 但同样,它只是解码,就像它所基于的Jheora编解码器一样。

    当然,它可能比从C或C++更容易从Java中移植一个编解码器,但是我发现的唯一的Java视频编解码器只解码。 jheora ,或者JIRAC。

    所以我回到了一号广场。我们通过Silverlight将网络摄像头(或麦克风)连接到Internet的选项如下:

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

    (2)脑循环将C或C++编解码器中的一个移植到Silverlight兼容的C;

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

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

    其他人有更好的指导吗?我错过了一些其他人都看不见的东西吗?(例如,Silverlight4某处是否有一些我错过的类来处理这个问题?)

    5 回复  |  直到 14 年前
        1
  •  3
  •   Ken Smith    15 年前

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


    在MikeTaulty的博客上看到了你关于Silverlight4测试版的视频接收器/音频接收器的帖子。

    我想我会指出,videosink的onsample提供了一个未压缩的32bpp argb帧,可以直接复制到可写入的位图中。

    有了它,抓取fjcore,一个c中的jpeg编解码器,并修改它以不输出jfif头。然后把它们一个接一个地写出来,你就有了一个动作jpeg编解码器。rfc2435解释了如何将其填充到rtp包中以用于rtsp流。

    将pcm音频压缩到adpcm也相当容易,但我还没有找到现成的实现。rfc3551解释了如何将pcm或adpcm放入rtp包中。

    将mjpeg和pcm或adpcm塞入avi文件也应该相当容易。微软在AVI修改的RIFF格式上有一些不错的文档,MJPEG和ADPCM都是广泛支持的编解码器。

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

    当然,一旦你经历了所有这些麻烦,下一个测试版可能会提供本地支持,用更好的WMV编解码器压缩和流媒体到WMS。


    以为我会贴出来。这是我迄今为止看到的最好的建议。

        2
  •  3
  •   Ken Smith    14 年前

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

    当一个流向上和四个流以144x176的速度向下时,我目前每秒获得5帧,总共使用474 Kbps(约82 Kbps/视频流+32 Kbps/音频),并且在我的dev box上占用大约30%的CPU。质量不太好,但大多数视频聊天应用程序都可以接受。

    自从我发布了我最初的问题后,有几次尝试实现一个解决方案。最好的可能是在Socketcoder网站上 here (和) here )

    但是,由于socketcoder motion 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头告诉它要使用什么值(它假定您将以其他带外方式共享这些值)。它还实例化它只需要一次的任何对象(称为“static”),这样您就可以以最小的开销快速地实例化jpegframeencoder和jpegframedecoder。现有的jpegencoder和jpegdecoder类应该和它们一直工作的差不多,尽管我只做了一点测试来确认这一点。

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

        3
  •  0
  •   Ken Smith    15 年前

    我再加一条评论。我今天刚从一位微软联系人那里听说微软 计划向Silverlight添加对上游音频和视频编码/流媒体的任何支持,因此选项1似乎不在考虑范围内,至少目前如此。我的猜测是,找出对这一点的支持将是社区的责任,也就是说,取决于你和我。

        4
  •  0
  •   Grailman    14 年前

    止损?

    是否可以使用 Windows Media编码器 作为原始视频的压缩方法,Silverlight提供了什么?捕获后到 ISO存储器 ,编码W// WME 并通过发送到服务器 网络客户端 . 两大问题是:

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

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

        5
  •  -4
  •   Nick Berardi    14 年前