Чтение вывода консоли из mplayer для анализа позиции/длины трека

Когда вы запускаете mplayer, он отображает положение и длину воспроизводимой дорожки (среди некоторой другой информации) через, как я полагаю, стандартный вывод.

Вот пример вывода mplayer:

MPlayer2 2.0-728-g2c378c7-4+b1 (C) 2000-2012 MPlayer Team
Cannot open file '/home/pi/.mplayer/input.conf': No such file or directory
Failed to open /home/pi/.mplayer/input.conf.
Cannot open file '/etc/mplayer/input.conf': No such file or directory
Failed to open /etc/mplayer/input.conf.

Playing Bomba Estéreo - La Boquilla [Dixone Remix].mp3.
Detected file format: MP2/3 (MPEG audio layer 2/3) (libavformat)
[mp3 @ 0x75bc15b8]max_analyze_duration 5000000 reached
[mp3 @ 0x75bc15b8]Estimating duration from bitrate, this may be inaccurate
[lavf] stream 0: audio (mp3), -aid 0
Clip info:
 album_artist: Bomba Estéreo
 genre: Latin
 title: La Boquilla [Dixone Remix]
 artist: Bomba Estéreo
 TBPM: 109
 TKEY: 11A
 album: Unknown
 date: 2011
Load subtitles in .
Selected audio codec: MPEG 1.0/2.0/2.5 layers I, II, III [mpg123]
AUDIO: 44100 Hz, 2 ch, s16le, 320.0 kbit/22.68% (ratio: 40000->176400)
AO: [pulse] 44100Hz 2ch s16le (2 bytes per sample)
Video: no video
Starting playback...
A:  47.5 (47.4) of 229.3 (03:49.3)  4.1%

Я пытаюсь прочитать последнюю строку (A: 47.5 (47.4) of 229.3 (03:49.3) 4.1%), но по какой-то причине обработчик событий Process.OutputDataReceived никогда не получает ее.

Я что-то пропустил? Использует ли mplayer какой-то нестандартный способ вывода строки «A:» на консоль?

Вот код, если поможет:

Public Overrides Sub Play()
    player = New Process()
    player.EnableRaisingEvents = True

    With player.StartInfo
        .FileName = "mplayer"
        .Arguments = String.Format("-ss {1} -endpos {2} -volume {3} -nolirc -vc null -vo null ""{0}""",
                                   tmpFileName,
                                   mTrack.StartTime,
                                   mTrack.EndTime,
                                   100)

        .CreateNoWindow = False
        .UseShellExecute = False
        .RedirectStandardOutput = True
        .RedirectStandardError = True
        .RedirectStandardInput = True
    End With

    AddHandler player.OutputDataReceived, AddressOf DataReceived
    AddHandler player.ErrorDataReceived, AddressOf DataReceived
    AddHandler player.Exited, Sub() KillPlayer()

    player.Start()
    player.BeginOutputReadLine()
    player.BeginErrorReadLine()

    waitForPlayer.WaitOne()

    KillPlayer()
End Sub

Private Sub DataReceived(sender As Object, e As DataReceivedEventArgs)
    If e.Data = Nothing Then Exit Sub

    If e.Data.Contains("A: ") Then
        ' Parse the data
    End If
End Sub

person xfx    schedule 27.03.2016    source источник
comment
Посмотрите /proc/$MPLAYERPID/fd/* (как root), чтобы узнать об этом.   -  person Eugen Rieck    schedule 28.03.2016
comment
Я попробовал cat/tail для всех файлов, созданных в /proc/$MPLAYERPID/fd/, но ни один из них не содержит никаких ссылок на строку A:. На самом деле, большинство из них кажутся пустыми.   -  person xfx    schedule 28.03.2016


Ответы (2)


По-видимому, единственным решением является запуск mplayer в режиме «ведомого», как описано здесь: http://www.mplayerhq.hu/DOCS/tech/slave.txt

В этом режиме мы можем отправлять команды в mplayer (через стандартный ввод), а ответ (если есть) будет отправлен через стандартный вывод.

Вот очень простая реализация, отображающая текущую позицию mplayer (в секундах):

using System;
using System.Threading;
using System.Diagnostics;
using System.Collections.Generic;

namespace TestMplayer {
    class MainClass {
        private static Process player;

        public static void Main(string[] args) {
            String fileName = "/home/pi/Documents/Projects/Raspberry/RPiPlayer/RPiPlayer/bin/Electronica/Skrillex - Make It Bun Dem (Damian Marley) [Butch Clancy Remix].mp3";
            player = new Process();
            player.EnableRaisingEvents = true;

            player.StartInfo.FileName = "mplayer";
            player.StartInfo.Arguments = String.Format("-slave -nolirc -vc null -vo null \"{0}\"", fileName);

            player.StartInfo.CreateNoWindow = false;
            player.StartInfo.UseShellExecute = false;
            player.StartInfo.RedirectStandardOutput = true;
            player.StartInfo.RedirectStandardError = true;
            player.StartInfo.RedirectStandardInput = true;

            player.OutputDataReceived += DataReceived;

            player.Start();
            player.BeginOutputReadLine();
            player.BeginErrorReadLine();

            Thread getPosThread = new Thread(GetPosLoop);
            getPosThread.Start();
        }

        private static void DataReceived(object o, DataReceivedEventArgs e) {
            Console.Clear();
            Console.WriteLine(e.Data);
        }

        private static void GetPosLoop() {
            do {
                Thread.Sleep(250);
                player.StandardInput.Write("get_time_pos" + Environment.NewLine);
            } while(!player.HasExited);
        }
    }
}
person xfx    schedule 28.03.2016

Я обнаружил ту же проблему с другим приложением, которое работает более или менее аналогичным образом (dbPowerAmp), в моем случае проблема заключалась в том, что вывод процесса использует кодировку Unicode для записать буфер stdout, поэтому я должен установить для StandardOutputEncoding и StandardError значение Unicode, чтобы иметь возможность начать чтение.

Ваша проблема кажется такой же, потому что, если «A» не может быть найден в опубликованном вами выводе, который ясно показывает, что существующий «A», то, вероятно, означает, что символ отличается при чтении в текущей кодировке, которую вы используете для чтения выход.

Итак, попробуйте установить правильную кодировку при чтении вывода процесса, попробуйте установить для них Unicode.

person ElektroStudios    schedule 28.03.2016