2016-10-04 2 views
13

Цель: Я пытаюсь использовать VLC в качестве локального сервера, чтобы расширить возможности видео из приложения, созданного с Adobe AIR, Flex и Actionscript. Я использую VLC для потока до stdout и чтения этого вывода из моего приложения.Синтаксис VLC для перекодирования и потока в stdout?

VLC Streaming capabilities
VLC Flash Video
Stream VLC to Website with asf and Flash

Статус: Я могу запустить VLC как фоновый процесс и управлять им через его remote control interface (more detail). Я могу загружать, транскодировать и транслировать локальный видеофайл. Пример приложения ниже - это тестовый стенд barebones, демонстрирующий это.

Вопрос: Я получаю данные в своем приложении, но это не рендеринг как видео. Я не знаю, если это проблема с моими командами 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=-}" 

Это приводит к данным, поступающим в моем приложении, но по какой-то причине он не делает, как видео при использовании appendBytes с экземпляром NetStream.

Если вместо этого я записываю данные в .flv-файл, создается действительный файл - поэтому сломанная часть, похоже, записывает его в stdout. Одна вещь, которую я заметил: я не получаю метаданные через stdout`method. Если я воспроизведу файл, созданный с помощью приведенной ниже команды, я вижу метаданные.

// 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 + "}"); 

Надеясь кто-то видит, где я неправильно здесь.


Update 1: Просто добавить еще несколько деталей - Я посмотрел на файл .flv, который создается для изучения метаданных (!). Он отображается во главе файла, как показано ниже. У меня есть правильный обработчик onMetaData и посмотреть трассировку этих данных, если я воспроизвожу файл с диска. Я не вижу этот след при чтении от stdout и NetStream находится в Data Generation режиме. Возможно ли, что по какой-то причине он не отправляется в stdout? Я попытался создать собственный заголовок и добавить его до начала потока - возможно, формат заголовка не правильный.

enter image description here


Update 2: Так что в моем AIR приложение, которое я смог разобрать грубо входящий stdout поток, приходящий из VLC. Я хотел посмотреть, были ли отправлены данные заголовка FLV - и, похоже, это так. Я не знаю, соответствует ли он в правильном формате и т. Д., Но, как я упоминал выше, если я пишу в.flv вместо stdout, создается действительный файл .flv.

Полностью в затруднительном положении сейчас - попробовал все, что я мог придумать, и отслеживал каждую ссылку в Интернете, которую я мог найти по вопросам, связанным с этим. Увы - так близко, и было бы так здорово использовать VLC с точностью до AIR.


Update 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 

Примечание: Для того, чтобы получить эту работу в AIR, необходимо определить профиль приложения, как " extendedDesktop»


<?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> 
+2

Итак, я не пробовал ваш реальный сценарий ... но у меня была мысль, что я буду бежать от вас. Когда у меня были проблемы с файлом, не читающим поток, он отлично воспроизводится при загрузке в виде целого файла ... проблема всегда была в том, что данные видео MOOV ATOM были в конце кодированного видео, а не в начале. И поскольку вы упомянули «Я не вижу метаданных», я подумал, что я расскажу об этом и посмотрю, может ли это быть применимо. Если это выглядит так, как это может быть применимо к вам ... проверьте qtfaststart https://github.com/danielgtaylor/qtfaststart, чтобы преобразовать их с данными спереди. –

+1

его не VLC. У меня была эта проблема с различными потоковыми источниками. Это исходный файл mp4. По умолчанию многие кодировщики помещают данные в конец оболочки mp4 ... и если вы попытаетесь передать это ... у получателя нет метаданных для работы. Если вы используете этот инструмент, я дал вам ссылку на ваш mp4, он переместит данные с конца mp4 в начало ... и начнется счастливая потоковая передача! (если это тоже ваша проблема) –

+1

Ну, это была мысль. Я сделал это довольно много с ffmpeg и помимо проблемы с метаданными, все мои проблемы возникли из-за правильного соответствия/определения входных и выходных данных кодека. (что я вижу, вы уже играете). Если у вас этого не будет сделано завтра ... У меня будет некоторое время после работы, чтобы настроить VLC на моей машине и играть с потоком и посмотреть, смогу ли я помочь вам справиться с этим! –

ответ

1

В других ваших комментариях Вопроса ты просил мои мысли:

Я заметил в своем коде вы работаете процесс VLC под средой OSX.
На ПК с Windows следует помнить, что -I rc не отвечает на standardInput отправленных команд. Я пользователь Windows, поэтому не могу помочь с этой частью.

Пробовал использовать --no-rc-fake-tty или даже --rc-fake-tty, VLC все еще не ответил на stdout на ПК.

Вы хотите сделать воспроизведение & искать в VLC, но смотреть результат в AS3 (как проекционный экран), правильно? но я даже не уверен, что VLC вернет вам FLV-теги, начиная с ваших выбранных штампов времени и т. д. (путем поиска, вы получаете доступ к тегу FLV определенной отметки времени & связанных данных a/v) ...

Другое Игроки, работающие на FFmpeg/Mencoder, такие как MPlayer I, тестировали только отправку текстовых данных «статус» в stdout во время воспроизведения (поэтому не могут быть поданы на декодер NetStream для отображения).

я смог разобрать грубо входящий stdout поток, приходящий из VLC. Я хотел посмотреть, были ли отправлены данные заголовка FLV, и появляется . Я не знаю, находится ли он в правильном формате и т. Д.

Проверьте байты: (правильный заголовок FLV начинается с 46 4C 56 01 05 00 00 00 09 00 00 00 00)

Просто обновите свой вопрос с копировальной пастой из «байт проверки результата» из приведенной ниже функции. Тогда вам легче сказать, является ли это играбельным или, может быть, вам нужна альтернатива.

1) Установка некоторых общественных (или частные) вары ...

  • Сделать public var temp_String : String = "";
  • Сделать 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 код:

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(); 
} 

Некоторые другие примечания:

Каждый обжиг ходе событий захватывает только 32кб/64kb пакетов входящих stdout байт в то время.

Вы внесете свой videoStream:ByteArray = new ByteArray(); за пределы progressEvent, чтобы каждый запуск события не создавал новый byteArray (который отбрасывает старые данные, которые могут понадобиться позже для полного тега FLV).

Не записывайте каждый пакет в положение 0, так как оно будет перезаписывать существующие данные. Добавьте к концу существующий, используя videoStream.length в качестве новой позиции записи.

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

Также if (videoStream.length){ ns.appendBytes(videoStream); } является своего рода опасным. Любые неполные данные (заголовка, фрейма или любого другого) будут затормозить декодер NetStream, если вы добавите слишком скоро. Он не перезапустится, если вы не сбросите все и не начнете снова (повторно добавьте байты полного заголовка FLV, полный тег кадра и т. Д.).

+0

Ничего себе, вы действительно получаете FLV-файл! Фу, но я уверен, что это перекод, не так ли? «Stdout» дает что-либо, если вы просто играете FLV с режимом «RC»? Если это так, поиск может быть еще возможен, но я не могу проверить эту сторону. Если транскодирование/FFmpeg работает нормально, остается только проблема с использованием AS3 для точного поиска (для любых секунд продолжительности вместо обычного поведения только для ключевых кадров)? –

+0

Независимо от формата ввода, всегда выбирайте вывод в FLV (h.264) cos appendBytes, предназначенный только для формата FLV. Подтвердите еще раз: ** без транскодирования ** и в режиме RC, если вы используете 'add filename.flv', а затем' play', вы получите байты из 'stdout'? Я хочу видеть эти байты игры. Если они являются тегами фрейма, то вы действительно можете добиться прогресса при воспроизведении. Так что, как вы показали мне байт заголовка FLV для подтверждения правильности, используйте один блок комментариев, чтобы скопировать-вставить столько «присоединенных» _play_ байтов, сколько вы можете поместиться здесь. Я проверю, что у тебя есть. –

+0

Ok -I не уверен, что у меня есть 'VLC' cmd правильно, но с использованием' #standard {mux = ffmpeg {mux = flv}, access = file, dst = -} '(** no transcoding **) Я получаю : '564C43206D6564696120706C6179657220322E' как первый бит очень длинной строки. Рань его несколько раз: тот же результат. Так что это не выглядит правильно. Использование '#standard {mux = flv, access = file, dst = -}' (no 'ffmpeg' Я получаю' 564C43206D6564696120706C6179657220' - похоже, что это так. Итак, это сломано, не так ли? –

1

несколько вещей, я хотел бы попробовать, некоторые из которых вы, возможно, не думали уже:

  1. Попробуйте включить отладку в случае, если вы загрязняете поток stdout.
  2. Попробуйте использовать другой формат видео (а не FLV), если это проблема, связанная с форматом. Например, вы можете попробовать mpeg4
  3. Попробуйте подключить поток stdout к чему-то еще, например ffplay, чтобы узнать, является ли проблема потоком или предположениями вашего получающего приложения о потоке.
+0

Рад, что у вас это работает! Комментарий VC.One - это то, что я получал с моим первым предложением. Я считаю, что вы можете подавить этот вывод с помощью -quiet (в разделе «Дополнительные параметры» здесь: https: //wiki.videolan.org/Документация: Command_line /) – lfalin

Смежные вопросы