Синхронизируйте видео субтитры с голосовым преобразованием текста

Я пытаюсь создать видео из текста, в котором текст рассказывается с помощью преобразования текста в речь.

Для создания видео файла я использую VideoFileWriter из Aforge.Net в дальнейшем:

VideoWriter = new VideoFileWriter();

VideoWriter.Open(CurVideoFile, (int)(Properties.Settings.Default.VideoWidth),
    (int)(Properties.Settings.Default.VideoHeight), 25, VideoCodec.MPEG4, 800000);

Чтобы прочитать вслух текст, который я использую SpeechSynthesizer класс и записать вывод в волновой поток

AudioStream = new FileStream(CurAudioFile, FileMode.Create);
synth.SetOutputToWaveStream(AudioStream);

Я хочу выделить слово, которое говорится в видео, поэтому я синхронизирую их по SpeakProgress событие:

    void synth_SpeakProgress(object sender, SpeakProgressEventArgs e)
    {

        curAuidoPosition = e.AudioPosition;
        using (Graphics g = Graphics.FromImage(Screen))
        {
             g.DrawString(e.Text,....); 
        }                    
        VideoWriter.WriteVideoFrame(Screen, curAuidoPosition);
    }

И, наконец, я объединяю видео и аудио, используя ffmpeg

using (Process process = new Process())
{
          process.StartInfo.FileName = exe_path;
          process.StartInfo.Arguments = string.Format(@"-i ""{0}"" -i ""{1}"" -y -acodec copy -vcodec copy ""{2}""",
                                           avi_path, mp3_path, output_file);
......

Проблема в том, что для некоторых голосов, таких как Microsoft Hazel, Zira и David, в Windows 8.1 видео не синхронизируется со звуком, и звук намного быстрее, чем показанные субтитры. Тем не менее, для голосов в Windows 7, это работает.

Как я могу синхронизировать их так, чтобы это работало для любых голосовых преобразований в любой операционной системе?

Кажется e.AudioPosition является неточным, как упомянуто в Неточны ли SpeakProgressEventArgs SpeechSynthesizer? У меня был такой же эксперимент и тот же результат.

Я заметил, что если я настраиваю аудиоформат, я могу приблизиться к фактическому времени, однако это не работает для любого голоса.

    var formats = CurVoice.VoiceInfo.SupportedAudioFormats;
    if (formats.Count > 0)
    {
        var format = formats[0];
        reader.SetOutputToWaveFile(CurAudioFile, format);
    }
    else
    {
         AudioStream = new FileStream(CurAudioFile, FileMode.Create);
         reader.SelectVoice(CurVoice.VoiceInfo.Name);
        var fmt = new SpeechAudioFormatInfo(16000, AudioBitsPerSample.Sixteen, AudioChannel.Mono);
        // this is more close but not precise yet
        MemStream = new MemoryStream();
        var mi = reader.GetType().GetMethod("SetOutputStream", BindingFlags.Instance | BindingFlags.NonPublic);
        mi.Invoke(reader, new object[] { MemStream, fmt, true, true }); 
     }

0 ответов

Другие вопросы по тегам