VLC 语法转码并流式传输到标准输出?

2024-01-31

Goal:我正在尝试使用VLC http://www.videolan.org/vlc/index.html作为本地服务器来扩展使用以下命令创建的应用程序的视频功能Adobe AIR, Flex and Actionscript。我在用VLC流式传输至stdout并从我的应用程序中读取该输出。

VLC 流媒体功能 http://www.videolan.org/streaming-features.html
VLC 闪存视频 https://wiki.videolan.org/Flash_Video/
使用 asf 和 Flash 将 VLC 流式传输到网站 https://wiki.videolan.org/Stream_VLC_to_Website_with_asf_and_Flash

Status:我能够启动VLC作为后台进程并通过其控制它远程控制接口 https://wiki.videolan.org/documentation:modules/rc/ (更多详情 https://n0tablog.wordpress.com/2009/02/09/controlling-vlc-via-rc-remote-control-interface-using-a-unix-domain-socket-and-no-programming/)。我可以加载、转码和流式传输本地视频文件。下面的示例应用程序是一个演示这一点的准系统测试平台。

Issue:我正在将数据输入到我的应用程序中,但它没有呈现为视频。我不知道这是我的 VLC 命令的问题还是写入/读取的问题stdout。这种阅读技巧stdout在 AIR 作品中(与ffmpeg例如)。

我尝试过的各种转码命令之一:

-I rc  // remote control interface  
-vvv   // verbose debuging  
--sout  // transcode, stream to stdout 
"#transcode{vcodec=FLV1}:std{access=file,mux=ffmpeg{mux=flv},dst=-}"

这会导致数据进入我的应用程序,但由于某种原因,在使用时它不会呈现为视频appendBytesNetStream实例。

相反,如果我将数据写入 .flv 文件,则会创建一个有效文件 - 因此损坏的部分似乎正在将其写入stdout. 我注意到一件事:我没有通过 stdout`方法获取元数据。如果我播放使用以下命令创建的文件,我确实会看到元数据。

// writing to a file
var output:File = File.desktopDirectory.resolvePath("stream.flv");
var outputPath:String = output.nativePath;
"#transcode{vcodec=FLV1}:std{access=file,mux=ffmpeg{mux=flv},dst=" + outputPath + "}");

希望有人看到我在这里出错的地方。


更新1:只是添加一些更多细节 (!) – 我查看了生成的用于检查元数据的 .flv 文件。它出现在文件的头部,如下所示。我有正确的onMetaData如果我从磁盘播放文件,处理程序将设置并查看该数据的踪迹。阅读时我没有看到这条痕迹stdout and NetStream is in Data Generation mode.是否有可能它没有被发送到stdout因为某些原因?我尝试生成自己的标头并在流开始之前附加该标头 - 我的标头格式可能不正确。


更新2:所以在我的AIR我能够粗略地解析传入的应用程序stdout流来自VLC。我想查看 FLV 标头数据是否正在发送 - 看起来确实如此。我不知道它的格式是否正确,等等,但正如我上面提到的,如果我写入 .flv 文件而不是stdout,将创建一个有效的 .flv 文件。

现在完全不知所措——已经尝试了我能想到的一切,并跟踪了我能找到的有关所涉及问题的每个网络链接。唉——如此接近,利用它会很酷VLC从内部AIR. ????


更新3: Per VC ONE's建议,我已经使用他/她的示例代码来检查传入字节的正确数据。我得到一个巨大的字符串(1000 个字符),但这些是第一个:

    What I get:
    464C560105000000090000000012000111000000000000000200
    46 4C 56 01 05 00 00 00 09 00 00 00 00 // check outs  

    What it should be:
    46 4C 56 01 05 00 00 00 09 00 00 00 00

Note:为了使其在 AIR 中工作,您需要将应用程序配置文件定义为“扩展桌面”


  <?xml version="1.0" encoding="utf-8"?>
  <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                       xmlns:s="library://ns.adobe.com/flex/spark" 
                       xmlns:mx="library://ns.adobe.com/flex/mx"
                       width="1024" height="768"
                       showStatusBar="false"
                       applicationComplete="onApplicationCompleteHandler(event)">

    <fx:Script>
        <![CDATA[
            import mx.events.FlexEvent;

            public var dataIn:Number = 0;
            public var dataTotal:Number = 0;
            private var processExe:File;
            private var processArgs:Vector.<String>;
            private var process:NativeProcess;
            private var nc:NetConnection;
            private var ns:NetStream;
            private var vid:Video;

            private var videoPath:String; // video to be streamed

            protected function onApplicationCompleteHandler(event:FlexEvent):void {
                var testFile:File = File.desktopDirectory.resolvePath("test.mp4");
                if (testFile.exists){
                    videoPath = testFile.nativePath;
                }

                setUpNetStream();
                createNativeProcess();
                startNativeProcess();
            }

            protected function setUpNetStream():void {
                nc = new NetConnection();
                nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, errorHandler);
                nc.addEventListener(NetStatusEvent.NET_STATUS, connStatusHandler);
                nc.connect(null);

                ns = new NetStream(nc);
                ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, errorHandler);
                ns.addEventListener(NetStatusEvent.NET_STATUS, streamStatusHandler);

                var client:Object = new Object();
                client.onMetaData = onMetaDataHandler;
                ns.client = client;

                vid = new Video(640,480);
                vid.x= 100;
                vid.y = 200;

                this.stage.addChild(vid);

                vid.attachNetStream(ns);
                ns.play(null);
            }

            private function createNativeProcess():void {
                if(NativeProcess.isSupported) {
                    // This is for OSX; 
                    var pathToVLC:String = "utils/OSX/VLC.app/Contents/MacOS/VLC";
                    processExe = File.applicationDirectory.resolvePath(pathToVLC);

                    if (processExe.exists){
                        process = new NativeProcess();
                        process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData); 
                        process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, onErrorData); 
                        process.addEventListener(ProgressEvent.PROGRESS, onOutputData); 
                        process.addEventListener(ProgressEvent.SOCKET_DATA, onOutputData); 
                        process.addEventListener(IOErrorEvent.STANDARD_OUTPUT_IO_ERROR, onIOError);
                        process.addEventListener(IOErrorEvent.STANDARD_ERROR_IO_ERROR, onIOError);
                    } else {
                        trace("process not found");
                    }
                } else {
                    trace("Native Process not supported");
                }
            }

            private function startNativeProcess():void {
                processArgs = new Vector.<String>();
                processArgs.push("-I rc");
                processArgs.push("-vvv"); // verbose debug output
                processArgs.push("--sout");

                // -------TO WRITE TO A FILE ----------
                // file to playback from
                //var output:File = File.desktopDirectory.resolvePath("stream.flv");
                //var outputPath:String = output.nativePath;
                //processArgs.push("#transcode{vcodec=FLV1}:std{access=file,mux=ffmpeg{mux=flv},dst=" + outputPath + "}");

                processArgs.push("#transcode{vcodec=FLV1,acodec=mp3}:gather:std{access=file,mux=flv,dst=-}");
                processArgs.push("--sout-keep");

                // ------VARIATIONS-------
                //processArgs.push("#transcode{vcodec=FLV1,acodec=mp3}:std{access=file,mux=flv,dst=-}");
                //processArgs.push("#transcode{vcodec=h264,vb=512,acodec=mp3,ab=128,samplerate=44100}:std{mux=ffmpeg{mux=flv},access=file,dst=-}");

                var nativeProcessStartupInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
                nativeProcessStartupInfo.executable = processExe;
                nativeProcessStartupInfo.arguments = processArgs;
                process.start(nativeProcessStartupInfo);

                // add video to playlist and play
                process.standardInput.writeUTFBytes("add " + videoPath + " \n" );
                process.standardInput.writeUTFBytes("play" + "\n" );
            }

            public function onOutputData(event:ProgressEvent):void { 
                if (process && process.running){
                    if (process.standardOutput.bytesAvailable){
                        var videoStream:ByteArray = new ByteArray();
                        process.standardOutput.readBytes(videoStream,0, process.standardOutput.bytesAvailable);

                        dataIn = videoStream.length;
                        dataTotal+= dataIn;
                        report.text = String("Current Bytes: " + dataIn + "\t Total Bytes: "+ dataTotal);

                        if (videoStream.length){
                            ns.appendBytes(videoStream);
                        }
                        //trace(ns.info);
                    }   
                }
            }

            private function errorHandler(e:AsyncErrorEvent):void {
                trace('ERROR: ' + e.text);
            }

            private function connStatusHandler(e:NetStatusEvent):void {
                trace('CONN_STATUS: ' + e.info.code);

                switch(e.info.code){
                    case "NetConnection.Connect.Success":
                        //onFinishSetup();
                        break;
                }
            }

            private function streamStatusHandler(e:NetStatusEvent):void {
                trace('STREAM_STATUS: ' + e.info.code);
            }

            private function streamMetadataHandler(info:Object):void {
                for (var key:String in info) {
                    trace("STREAM_METADATA: " + key + "=" + info[key]);
                }               
            }

            public function onErrorData(event:ProgressEvent):void {
                if (process && process.running){
                    trace(process.standardError.readUTFBytes(process.standardError.bytesAvailable));
                }
            }
            public function onIOError(event:IOErrorEvent):void {
                trace(event.toString());
            }

            private function onMetaDataHandler(metadata:Object):void {
                trace("### Begin Metadata listing : FLV Entries ### "  );
                for (var entry:* in metadata) 
                {
                    var value:Object = metadata[ entry ];
                    trace(" > " + entry + " : " + value);
                }
                trace("### End of Metadata listing for this FLV ### "  );
            }
        ]]>
    </fx:Script>

    <s:Label id="report" x="25" y="25" fontSize="18" />
</s:WindowedApplication>

在您的其他问题的评论中,您询问了我的想法:

我注意到你的代码中你正在 OSX 环境下运行 VLC 进程。
在 Windows PC 上请注意-I rc后来没有回复standardInput发送的命令。我是 Windows 用户,因此无法帮助解决该部分。

尝试使用--no-rc-fake-tty甚至--rc-fake-tty,VLC仍然没有反应stdout on PC.

您想在 VLC 中进行播放和搜索,但在 AS3 中观看结果(就像投影屏幕),对吧?但我什至不确定 VLC 是否会从您选择的时间戳等开始为您返回 FLV 标签(通过寻找您正在访问特定时间戳和相关 a/v 数据的 FLV 标签)...

其他 FFmpeg/Mencoder 支持的播放器(例如我测试过的 MPlayer)仅将“状态”文本数据发送回stdout播放期间(因此无法馈送到NetStream用于显示的解码器)。

我能够粗略地解析传入的stdout流来自 可见光通信。我想查看 FLV 标头数据是否正在发送 – 结果是 看来确实如此。我不知道它的格式是否正确等等。

检查字节:(有效的 FLV 标头以46 4C 56 01 05 00 00 00 09 00 00 00 00)

只需使用以下函数的“字节检查”结果的复制粘贴来更新您的问题。然后更容易告诉您它是否可以玩或者您可能需要一些替代方案。

1)设置一些公共(或私有)变量...

  • Make a public var temp_String : String = "";
  • Make a public var videoStream:ByteArray = new ByteArray();

2)替换你的函数onOutputData用下面的代码...

public function onOutputData(event:ProgressEvent):void 
{ 
    if (process && process.running)
    {
        if (process.standardOutput.bytesAvailable)
        {
            //# make a private/public bytearray outside of this function 
            //var videoStream:ByteArray = new ByteArray();

            process.standardOutput.readBytes(videoStream, videoStream.length, process.standardOutput.bytesAvailable);

            dataIn = process.standardOutput.bytesAvailable; 
            dataTotal += dataIn;
            //report.text = String("Current Bytes: " + dataIn + "\t Total Bytes: "+ dataTotal);

            if (videoStream.length >= 1000 )
            {
                //ns.appendBytes(videoStream);

                temp_String = bytes_toString(videoStream);
                trace("bytes checking : " + "\n");
                trace( temp_String ); //see hex of FLV bytes

                //# temporary pausing of progress events 
                process.removeEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
            }
            //trace(ns.info);
        }
    }
}

配套功能bytes_toString code :

public function bytes_toString ( ba:ByteArray ) : String
{
    var str_Hex:String = "";    var len:uint = ba.length;

    ba.position = 0;

    for (var i:uint = 0; i < len; i++) 
    {
        var n:String=ba.readUnsignedByte().toString(16); 

        if(n.length<2) //padding
        { n="0"+n; }    str_Hex += n ;
    }

    return str_Hex.toUpperCase();
}

其他一些注意事项:

每次触发进度事件仅捕获 32kb / 64kb 传入数据包stdout一次字节。

你让你的videoStream:ByteArray = new ByteArray();在 ProgressEvent 之外,以便每次事件触发都不会生成新的 byteArray(这会丢弃完整 FLV 标记稍后可能需要的旧数据)。

不要将每个数据包写入0位置,因为这将覆盖现有数据。通过使用添加到现有的末尾videoStream.length作为新的写作位置。

process.standardOutput.readBytes(videoStream, videoStream.length, process.standardOutput.bytesAvailable);

Also if (videoStream.length){ ns.appendBytes(videoStream); }有点危险。如果您附加得太快,任何不完整的数据(标头、帧或其他数据)都会堵塞 NetStream 解码器。除非您重置所有内容并重新开始(重新附加完整 FLV 标头、全帧标签等字节),否则它不会重新启动。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VLC 语法转码并流式传输到标准输出? 的相关文章

随机推荐

  • OpenSSL::SSL::SSLError 仅限 Ubuntu 12.04

    我正在使用 Evernote Ruby API 开发 Web 应用程序 使用 Rails 和 oauth 但是在 Ubuntu 12 04 中运行该应用程序时 我收到错误 SSL connect SYSCALL returned 5 err
  • 使用 applescript 我想将文件夹中的每个文件移动到根文件夹

    我一直在尝试制作一个脚本将文件夹中的每个文件移动到根文件夹以包含每个子文件夹 我不想创建新文件夹 只需将其移动到根文件夹即可 我希望能够选择文件夹 然后仅在该特定文件夹上完成操作 原因是为了组织 我的确切情况是我有超过 TB 的电影 并且文
  • 可以在创建时将字典传递给 django 模型吗?

    是否可以用 a 做类似的事情list dictionary或者是其他东西 data dict title awesome title body great body of text Model objects create data dic
  • jQuery 处理表单

    这是一个非常简单的问题 我希望 但由于只是学习 掌握 jQuery 我提前道歉 如果我有一个表格 例如
  • google docs share 上使用了哪些技术

    我需要理解并知道我该如何做某事 在我的项目中 我需要创建类似于谷歌文档上的技术的东西 当我与其他人共享文档并且他和我同时编辑时 我会看到他的更改 我不知道这是否称为反向ajax或其他类型的技术 有人可以向我解释一下这是一种什么样的发展吗 E
  • Google Play 商店:您需要修复高分辨率图标。这不是有效的图像

    这是我尝试在 Play 商店中为我的应用程序提供图像时收到的错误消息 这是图像 它是在 GIMP 中创建的 请帮忙 这使我无法启动我的应用程序 如 Google Play 商店开发者控制台所述 图标图像应为 512 512 32 bitPN
  • Chrome 不缓存预检

    我正在实现一个应该支持跨域请求的 REST API 我想使用 CORS 来实现这一目标 我的几乎所有请求都是 不简单 的 这意味着对于所有非 GET 请求 浏览器必须发送预检请求 为了限制预检 选项请求的数量 我尝试让浏览器缓存选项请求 这
  • 如何识别 Rails 应用程序中的路线

    我有这个非常基本的问题 我正在用这个仪表板导轨发动机 https github com gottfrois dashing rails 这给了我一个views layouts dashing dashboard html erb 这是仪表板
  • Lombok Builder 注释引发 UnsupportedOperationException

    我在我的项目中使用 Lombok 我的模型看起来像 Builder Data AllArgsConstructor public class ScreenDefinitionDTO Singular private List
  • 如何获取可靠的 QGLWidget 快照

    在我的应用程序中 我拍摄 QGLWidget 内容的快照有两个目的 当只有覆盖层发生变化时 不要一直重绘场景 而是使用缓存的像素图 Lat 用户截取特定绘图的屏幕截图 3D 场景 我尝试的第一件事是grabFrameBuffer 对于第一个
  • 如何将 y 轴刻度标签设置在固定位置,以便当我向左或向右滚动时 y 轴刻度标签应该可见?

    在我的程序中 我首先绘制了图形 然后将图形导入到画布中 然后我将画布导入滚动区域 当我运行我的程序时 如果我向左滚动 yaxis 刻度标签会隐藏 或者我向右转动 yaxis 刻度标签也会隐藏 我已经采取了两个轴 轴 轴2 我已经设置了axe
  • 如何始终阻止 TFS 中特定文件的签入

    我总是对一个文件进行更改 但我从不想将其签入 我希望 TFS 阻止我将其签入或提交更改 如何配置 TFS 来执行此操作 细节 该项目的另一位开发人员签入了一些错误代码 我更愿意在本地计算机上注释掉这些代码 由于他们是客户 我更愿意将其保留为
  • Swift 5 结果类型

    苹果在 Swift 5 中引入了Result类型 它是具有两种情况的通用枚举 public enum Result
  • 如何在不恢复报表服务器的情况下将 SSRS 数据源从一台服务器迁移或复制到另一台服务器

    我正在尝试将 SSRS 报告从 SQL 2008r2 迁移到 SQL 2014 服务器 我使用reportsync将报告传输到服务器 报告已成功传输 但角色订阅和数据源未传输 有没有什么方法可以将数据源 角色和订阅从一台服务器复制或迁移到另
  • 如何使用 Python 中的 Selenium-chromeDriver 在 Chrome 中打开新选项卡

    有没有人用过ChromeDriver在 Chrome 中打开新标签页 使用此代码我可以打开我的index html在 Chrome 中 driver webdriver Chrome usr bin chromedriver driver
  • C# 获取调用某个函数的函数列表[重复]

    这个问题在这里已经有答案了 这是这个问题的切线 从方法内检索调用方法名称 https stackoverflow com questions 615940 retrieving the calling method name from wi
  • 用玩笑测试 chrome.storage.local.set

    我是测试的新手 并开始使用 jest 我有这个函数将数据保存在 chrome storage local 中 我想测试 chrome storage local 是否调用了 3 次 这是函数 saveData function chrome
  • C 测试变量是否位于只读部分

    我想编写一个低级日志记录函数 如下所示 DO DBG some string val1 val2 出于性能原因 我想要它做的是存储指向字符串的指针而不是字符串的副本 这假设该字符串是只读文字 为了防止人们必须调试调试器 如果编译器能够抱怨第
  • iOS - UINavigationController,隐藏导航栏

    我在隐藏 UINavigationController 的导航栏时遇到了一些小问题 我已经添加了 self navigation navigationBar hidden true 不幸的是 这会在白色状态栏后面留下某种背景 白色 将内容
  • VLC 语法转码并流式传输到标准输出?

    Goal 我正在尝试使用VLC http www videolan org vlc index html作为本地服务器来扩展使用以下命令创建的应用程序的视频功能Adobe AIR Flex and Actionscript 我在用VLC流式