当前位置: 首页 > 知识库问答 >
问题:

同步媒体播放器javafx

程胡非
2023-03-14

这可能不是一个可以接受的问题,但我现在非常绝望。

我需要一个同步java媒体播放器与快速寻找和平衡修改。

脚本:

我有一个javaFX项目,我必须在循环中播放一个非常短(50-100毫秒)的媒体文件。问题是,在重新启动之前,我需要等待一些要求。

简而言之:播放声音-

javafx提供了一个我修改过的媒体播放器。

// this method is just to show how the modified mediaplayer class is called
public void updateSoundBalance(double currentTimeInCycle) {
    // control the balance of the sound
    if(playingSound && mediaPlayer != null)
    {
        long b = System.nanoTime();

        // 0 <= balance < 4. balance represents the cycle phase.
        double balance = currentTimeInCycle % RADIANCE_FULL_CYCLE / RADIANCE_QUARTER_CYCLE;
        boolean firstHalfCycle = balance < 2;

        double quarterCycleIndex = Math.floor(balance);

        long a = System.nanoTime();
        if(swingingSound)
            mediaPlayer.setBalance(firstHalfCycle ? 1 - balance : balance - 3);
        else
            mediaPlayer.setBalance(balance > 1 && balance < 3? -1 : 1);
        System.out.println("C   :::   sound balance = " + (System.nanoTime() - a));

        if ((quarterCycleIndex == 1 | quarterCycleIndex == 3) &&
            balance - quarterCycleIndex <= Settings.DEFAULT_PATTERN_SMOOTHNESS)
        {
            a = System.nanoTime();

            if (mediaDone){
                mediaPlayer.reset();
                mediaDone = false;
            }
            System.out.println("B   :::   call reset = " + (System.nanoTime() - a));
        }
        System.out.println("A   :::   total time = " + (System.nanoTime() - b));
    }
}
import java.util.concurrent.ScheduledThreadPoolExecutor;

import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;


public class MultiMediaPlayer
{
private MediaPlayer mp1, mp2;
private boolean usingMp1 = true;

private ScheduledThreadPoolExecutor seekService = new ScheduledThreadPoolExecutor(2);
private Runnable seekRun = new Runnable() {
    @Override
    public void run() {
        try
        {
            long a = System.nanoTime();
            if(usingMp1) {
                usingMp1 = false;
                mp1.stop();
                mp2.play();
                mp1.seek(new Duration(0));
            } else {
                usingMp1 = true;
                mp2.stop();
                mp1.play();
                mp2.seek(new Duration(0));
            }
            System.out.println("D   :::   reset sound time taken = " + (System.nanoTime() - a));
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }
};

public MultiMediaPlayer(Media value)
{
    mp1 = new MediaPlayer(value);
    mp2 = new MediaPlayer(value);

    mp1.balanceProperty().bindBidirectional(mp2.balanceProperty());
    mp1.onEndOfMediaProperty().bindBidirectional(mp2.onEndOfMediaProperty());
}

public void setBalance(double value){
    mp1.setBalance(value);
}

public void reset(){
    seekService.execute(seekRun);
}

public void play(){
    if(usingMp1) {
        mp1.play();
    } else {
        mp2.play();
    }
}

public void stop(){
    mp1.stop();
    mp2.stop();
}

public void pause(){
    mp1.pause();
    mp2.pause();
}

public void setOnEndOfMedia(Runnable r) {
    mp1.setOnEndOfMedia(r);
}
}

如果有人能为我指出正确的方向(图书馆/我错过的东西),我将不胜感激

ps允许的java版本是最新的

共有2个答案

狄宜然
2023-03-14

谢谢Olof Kohlhaas,但我想我找到了一个更好的解决方案,它使用了javafx的音频剪辑。然而,由于我缺乏知识,我使用了一种基本的方法来获取文件的长度,它只支持Wave和其他特定格式。如果更改了,该类将使用javafx媒体包支持的任何格式:

import java.io.IOException;
import java.net.URL;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.media.AudioClip;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;

/**
 *
 * this class is to optimize sound pattern playing
 *
 * reasoning:
 * - audio clips are for short repetitive files that don't need live changes to balance
 * - media players are for long files that will have the ability to swing with the visual patted
 * by updating the balance whenever needed (every few updates)
 */
public class AudioPlayer
{
    public enum Controller{
        MEDIA_PLAYER, AUDIO_CLIP;
    }

    /**
     * this class is to help other classes keep track of this particular state of the AudioPlayer
     */
    public class ControllerProperty extends SimpleObjectProperty<Controller>{
        SimpleBooleanProperty isMediaPlayerProperty = new SimpleBooleanProperty();

        @Override
        public void set(Controller newValue) {
            super.set(newValue);
            if (newValue == Controller.MEDIA_PLAYER)
                isMediaPlayerProperty.set(true);
            else
                isMediaPlayerProperty.set(false);
        }

        public ReadOnlyBooleanProperty isMediaPlayerProperty() {
            return isMediaPlayerProperty;
        }
    }
    // different controllers used
    private Media media;
    private MediaPlayer mediaPlayer;
    private AudioClip audioClip;

    // controllerProperty property indicator
    private ControllerProperty controllerProperty = new ControllerProperty();

    private boolean mediaDonePlaying = true;
    private double durationMillis;

    /**
     * Constructor. This will be the place where you can
     * @param srcUrl
     */
    public AudioPlayer(String srcUrl) {
        boolean formatSupported = true;
        try {
            durationMillis = getLength(srcUrl);
        } catch (IOException | LineUnavailableException e) {
            e.printStackTrace();
        } catch (UnsupportedAudioFileException e) {
            formatSupported = false;
        }
        // if file is long or format unsupported (not one of these: AudioSystem.getAudioFileTypes())
        if (durationMillis > 400 | !formatSupported){
            media = new Media(srcUrl);
            mediaPlayer = new MediaPlayer(media);
            controllerProperty.set(Controller.MEDIA_PLAYER);
            mediaPlayer.setOnEndOfMedia(() -> mediaDonePlaying = true);
        }
        else {
            audioClip = new AudioClip(srcUrl);
            controllerProperty.set(Controller.AUDIO_CLIP);
        }
    }

    /**
     * gets the audio duration of the provided source in milliseconds
     * @param path url string representation of the path
     * @return the length in milliseconds
     * @throws IOException
     * @throws UnsupportedAudioFileException
     * @throws LineUnavailableException
     */
    public static double getLength(String path) throws IOException, UnsupportedAudioFileException, LineUnavailableException
    {
        AudioInputStream stream;
        stream = AudioSystem.getAudioInputStream(new URL(path));
        AudioFormat format = stream.getFormat();
        if (format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {
            format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format
                .getSampleRate(), format.getSampleSizeInBits() * 2, format
                .getChannels(), format.getFrameSize() * 2, format
                .getFrameRate(), true); // big endian
            stream = AudioSystem.getAudioInputStream(format, stream);
        }
        DataLine.Info info = new DataLine.Info(Clip.class, stream.getFormat(),
            ((int) stream.getFrameLength() * format.getFrameSize()));
        Clip clip = (Clip) AudioSystem.getLine(info);
        clip.close();
        return clip.getBufferSize()
            / (clip.getFormat().getFrameSize() * clip.getFormat()
            .getFrameRate());
    }

    public void stop(){
        switch (controllerProperty.get())
        {
            case AUDIO_CLIP:
                if (audioClip != null)
                    audioClip.stop();
                break;

            case MEDIA_PLAYER:
                if (mediaPlayer != null && media != null){
                    mediaPlayer.stop();
                    mediaDonePlaying = true;
                }
                break;
        }
    }

    public void play(){
        switch (controllerProperty.get())
        {
            case AUDIO_CLIP:
                if (audioClip != null)
                    if(!audioClip.isPlaying()){
                        audioClip.play();
                    }
                break;

            case MEDIA_PLAYER:
                if (mediaPlayer != null && media != null){
                    mediaPlayer.play();
                    mediaDonePlaying = false;
                }
                break;
        }
    }

    public void pause(){
        switch (controllerProperty.get())
        {
            case AUDIO_CLIP:
                if (audioClip != null)
                    audioClip.stop();
                break;

            case MEDIA_PLAYER:
                if (mediaPlayer != null && media != null)
                    mediaPlayer.pause();
                break;
        }
    }

    /**
     * sets the balance of the player, if the controller is an {@link AudioClip}, the balance is 
     * updated at the next play cycle, if the controller is a {@link MediaPlayer} the balance is 
     * updated at the next time the {@link MediaPlayer} has Status.READY (read 
     * {@link MediaPlayer#setBalance(double)} for more details)
     * @param balance
     */
    public void setBalance(double balance){
        switch (controllerProperty.get())
        {
            case AUDIO_CLIP:
                if (audioClip != null)
                    audioClip.setBalance(balance);
                break;

            case MEDIA_PLAYER:
                if (mediaPlayer != null && media != null)
                    mediaPlayer.setBalance(balance);
                break;
        }
    }

    public String getSource(){
        switch (controllerProperty.get())
        {
            case AUDIO_CLIP:
                if (audioClip != null)
                    return audioClip.getSource();
                break;

            case MEDIA_PLAYER:
                if (mediaPlayer != null && media != null)
                    return media.getSource();
                break;
        }
        return null;
    }

    /**
     * @return if the file is done
     */
    public boolean isDonePlaying(){
        switch (controllerProperty.get())
        {
            case AUDIO_CLIP:
                if (audioClip != null)
                    return !audioClip.isPlaying();
                break;

            case MEDIA_PLAYER:
                if (mediaPlayer != null && media != null)
                    return mediaDonePlaying;
                break;
        }
        throw new IllegalStateException("Internal Error");
    }

    public ControllerProperty controllerProperty() {
        return controllerProperty;
    }
}
梁锋
2023-03-14

在这种情况下,您最好使用更低级的Java声音API。它已经是标准API的一部分。你提到你有很短的音频信号。因此,您可以将其缓冲在内存中,然后将其写入大纲多次。乍一看您的代码,pan似乎是正确的选择,而不是平衡。下面的示例演示如何将天平和平移分别切换到其最大值和最小值。Java Sound API与WAVE和AIFF本机协同工作。如果您有其他文件格式,则需要查看Java声音API FormatConversionProviders,例如mp3spi和vorbisspi。

import java.io.File;
import java.io.IOException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

public class Main {

    public static void main(String[] args) {

        try {
            int loops = 20;

            File waveFile = new File(yourWaveFilePath);

            AudioInputStream stream = AudioSystem.getAudioInputStream(waveFile);
            AudioFormat format = stream.getFormat();

            // reading complete audio file into memory
            byte[] frames = new byte[format.getFrameSize() * (int) stream.getFrameLength()];
            stream.read(frames, 0, frames.length);

            DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, format);
            SourceDataLine line = (SourceDataLine) AudioSystem.getLine(lineInfo);
            line.open(format);
            line.start();

            FloatControl balance = (FloatControl) line.getControl(FloatControl.Type.BALANCE);
            FloatControl pan = (FloatControl) line.getControl(FloatControl.Type.PAN);

            for (int i = 0; i < loops; i++) {
                // switching balance and pan with every iteration
                if (i % 2 == 0) {
                    balance.setValue(balance.getMinimum());
                    pan.setValue(pan.getMinimum());
                } else {
                    balance.setValue(balance.getMaximum());
                    pan.setValue(pan.getMaximum());
                }

                // playing complete audio file
                line.write(frames, 0, frames.length);

                System.out.println("iteration: " + i + ", balance: " + balance.getValue() + ", pan: " + pan.getValue());
            } 

            line.drain();
            line.close();
            stream.close();

        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
            e.printStackTrace();
        }
    }

}
 类似资料:
  • 大家好,我正在尝试使用两个独立的媒体播放器实例播放音频和视频文件。当我从一开始播放它时,它工作得很好。但当我寻找时,我可以看到音频和视频的延迟 这是我寻找音频和视频的代码 //sikAudio(msec); if(media播放器!=null) { // 没有直播流,如果(medialayer.get持续时间() }

  • 我正在开发一个包含一些音频播放器的RecyclerView的应用程序。应用程序将下载。3gp文件(如果尚未下载)。 当我单击playAudio按钮时,音频未被播放。 这是我的适配器代码: 我怎样才能解决这个问题?

  • 1.1.1. 多媒体播放 1.1.1. 多媒体播放 我们事实上对上游芯片厂商自带的播放器方式做了调整。 Amlogic 芯片 BaseCode 我们禁用了芯片厂商的原生代码的 libplayer 包,原因是芯片厂商的播放器是直接使用 ALSA 框架来调用音频播放功能的。 这对我们 RokidOS 平台让多个进程使用音频设备造成阻碍。基于这个因素,我们使用了 RokidOS 开发的媒体播放库 lib

  • 当我使用MediaPlayer播放mp3文件时,系统会报告错误日志:。但是RealPlayer是正常的。 我发现它的错误只发生在更高的ROM版本。像4.0版本一样,它有错误。在2.3版中,它没有这个错误。 代码: 日志猫错误:

  • 我已经成功地能够从我的服务器流MP3,现在我想显示一个媒体播放器通知与控制时,歌曲开始播放。我已经遵循了一些教程如何做到这一点,但我仍然得到错误时,试图在我的应用程序中做同样的事情。 这是我尝试在音乐开始播放时显示通知的方式 这是完整的 但是,当我运行代码并单击播放按钮时,应用程序崩溃,logcat返回此错误,但没有指向特定的代码行。

  • 我目前在一个项目中使用Javafx 2,我可能需要长时间无限循环播放一个视频。在windows上,当视频播放时,我的proifiler工具显示非常正常的图片,cpu负载不是很重(在2个内核上运行时约为2x40-50%),内存使用峰值约为250 MB,这是正常的。但是,当我在Ubuntu机器上部署应用程序时,每个内核的cpu负载达到70%左右(尽管它是一个双核atom处理器,所以假设这是正常的),内