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

如何解决媒体播放器错误(-38,0)

黄涵畅
2023-03-14

我在android应用程序中使用了media player。播放3gp文件,但如果播放mp4或其他格式,则会显示MediaPlayer错误(-38,0)和MediaPlayer错误(1,-2147483648)。有人能帮我解决这个问题吗?

public class VideoPlayerActivity extends Activity implements SurfaceHolder.Callback, MediaPlayer.OnPreparedListener, VideoControllerView.MediaPlayerControl {

SurfaceView videoSurface;
MediaPlayer player;
VideoControllerView controller;
TextView txtvalue;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    registerBaseActivityReceiver();
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_video_player);

    String value = getIntent().getExtras().getString("url");

    txtvalue=(TextView)findViewById(R.id.value);

    videoSurface = (SurfaceView) findViewById(R.id.videoSurface);
    SurfaceHolder videoHolder = videoSurface.getHolder();
    videoHolder.addCallback(this);

    player = new MediaPlayer();
    controller = new VideoControllerView(this);

    try {
        txtvalue.setText(value);
        player.setAudioStreamType(AudioManager.STREAM_MUSIC);
        player.setDataSource(this, Uri.parse(value));
        player.setOnPreparedListener(this);
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    unRegisterBaseActivityReceiver();
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    controller.show();
    return false;
}

// Implement SurfaceHolder.Callback
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    player.setDisplay(holder);
    player.prepareAsync();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {

}
// End SurfaceHolder.Callback

// Implement MediaPlayer.OnPreparedListener
@Override
public void onPrepared(MediaPlayer mp) {
    controller.setMediaPlayer(this);
    controller.setAnchorView((FrameLayout) findViewById(R.id.videoSurfaceContainer));
    player.start();
}
// End MediaPlayer.OnPreparedListener

// Implement VideoMediaController.MediaPlayerControl
@Override
public boolean canPause() {
    return true;
}

@Override
public boolean canSeekBackward() {
    return true;
}

@Override
public boolean canSeekForward() {
    return true;
}

@Override
public int getBufferPercentage() {
    return 0;
}

@Override
public int getCurrentPosition() {
    return player.getCurrentPosition();
}

@Override
public int getDuration() {
    return player.getDuration();
}

@Override
public boolean isPlaying() {
    return player.isPlaying();
}

@Override
public void pause() {
    player.pause();
}

@Override
public void seekTo(int i) {
    player.seekTo(i);
}

@Override
public void start() {
    player.start();
}

@Override
public boolean isFullScreen() {
    return false;
}

@Override
public void toggleFullScreen() {

}
// End VideoMediaController.MediaPlayerControl

}

public class VideoControllerView extends FrameLayout {
private static final String TAG = "VideoControllerView";

private MediaPlayerControl  mPlayer;
private Context             mContext;
private ViewGroup           mAnchor;
private View                mRoot;
private ProgressBar         mProgress;
private TextView            mEndTime, mCurrentTime;
private boolean             mShowing;
private boolean             mDragging;
private static final int    sDefaultTimeout = 3000;
private static final int    FADE_OUT = 1;
private static final int    SHOW_PROGRESS = 2;
private boolean             mUseFastForward;
private boolean             mFromXml;
private boolean             mListenersSet;
private View.OnClickListener mNextListener, mPrevListener;
StringBuilder               mFormatBuilder;
Formatter                   mFormatter;
private ImageButton         mPauseButton;
private ImageButton         mFfwdButton;
private ImageButton         mRewButton;
private ImageButton         mNextButton;
private ImageButton         mPrevButton;
private ImageButton         mFullscreenButton;
private Handler             mHandler = new MessageHandler(this);

public VideoControllerView(Context context, AttributeSet attrs) {
    super(context, attrs);
    mRoot = null;
    mContext = context;
    mUseFastForward = true;
    mFromXml = true;

    Log.i(TAG, TAG);
}

public VideoControllerView(Context context, boolean useFastForward) {
    super(context);
    mContext = context;
    mUseFastForward = useFastForward;

    Log.i(TAG, TAG);
}

public VideoControllerView(Context context) {
    this(context, true);

    Log.i(TAG, TAG);
}

@Override
public void onFinishInflate() {
    if (mRoot != null)
        initControllerView(mRoot);
}

public void setMediaPlayer(MediaPlayerControl player) {
    mPlayer = player;
    updatePausePlay();
    updateFullScreen();
}

/**
 * Set the view that acts as the anchor for the control view.
 * This can for example be a VideoView, or your Activity's main view.
 * @param view The view to which to anchor the controller when it is visible.
 */
public void setAnchorView(ViewGroup view) {
    mAnchor = view;

    FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT
    );

    removeAllViews();
    View v = makeControllerView();
    addView(v, frameParams);
}

/**
 * Create the view that holds the widgets that control playback.
 * Derived classes can override this to create their own.
 * @return The controller view.
 * @hide This doesn't work as advertised
 */
protected View makeControllerView() {
    LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    mRoot = inflate.inflate(R.layout.media_controller, null);

    initControllerView(mRoot);

    return mRoot;
}

private void initControllerView(View v) {
    mPauseButton = (ImageButton) v.findViewById(R.id.pause);
    if (mPauseButton != null) {
        mPauseButton.requestFocus();
        mPauseButton.setOnClickListener(mPauseListener);
    }

    mFullscreenButton = (ImageButton) v.findViewById(R.id.fullscreen);
    if (mFullscreenButton != null) {
        mFullscreenButton.requestFocus();
        mFullscreenButton.setOnClickListener(mFullscreenListener);
    }

    mFfwdButton = (ImageButton) v.findViewById(R.id.ffwd);
    if (mFfwdButton != null) {
        mFfwdButton.setOnClickListener(mFfwdListener);
        if (!mFromXml) {
            mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
        }
    }

    mRewButton = (ImageButton) v.findViewById(R.id.rew);
    if (mRewButton != null) {
        mRewButton.setOnClickListener(mRewListener);
        if (!mFromXml) {
            mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
        }
    }

    // By default these are hidden. They will be enabled when setPrevNextListeners() is called 
    mNextButton = (ImageButton) v.findViewById(R.id.next);
    if (mNextButton != null && !mFromXml && !mListenersSet) {
        mNextButton.setVisibility(View.GONE);
    }
    mPrevButton = (ImageButton) v.findViewById(R.id.prev);
    if (mPrevButton != null && !mFromXml && !mListenersSet) {
        mPrevButton.setVisibility(View.GONE);
    }

    mProgress = (ProgressBar) v.findViewById(R.id.mediacontroller_progress);
    if (mProgress != null) {
        if (mProgress instanceof SeekBar) {
            SeekBar seeker = (SeekBar) mProgress;
            seeker.setOnSeekBarChangeListener(mSeekListener);
        }
        mProgress.setMax(1000);
    }

    mEndTime = (TextView) v.findViewById(R.id.time);
    mCurrentTime = (TextView) v.findViewById(R.id.time_current);
    mFormatBuilder = new StringBuilder();
    mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());

    installPrevNextListeners();
}

/**
 * Show the controller on screen. It will go away
 * automatically after 3 seconds of inactivity.
 */
public void show() {
    show(sDefaultTimeout);
}

/**
 * Disable pause or seek buttons if the stream cannot be paused or seeked.
 * This requires the control interface to be a MediaPlayerControlExt
 */
private void disableUnsupportedButtons() {
    if (mPlayer == null) {
        return;
    }

    try {
        if (mPauseButton != null && !mPlayer.canPause()) {
            mPauseButton.setEnabled(false);
        }
        if (mRewButton != null && !mPlayer.canSeekBackward()) {
            mRewButton.setEnabled(false);
        }
        if (mFfwdButton != null && !mPlayer.canSeekForward()) {
            mFfwdButton.setEnabled(false);
        }
    } catch (IncompatibleClassChangeError ex) {
        // We were given an old version of the interface, that doesn't have
        // the canPause/canSeekXYZ methods. This is OK, it just means we
        // assume the media can be paused and seeked, and so we don't disable
        // the buttons.
    }
}

/**
 * Show the controller on screen. It will go away
 * automatically after 'timeout' milliseconds of inactivity.
 * @param timeout The timeout in milliseconds. Use 0 to show
 * the controller until hide() is called.
 */
public void show(int timeout) {
    if (!mShowing && mAnchor != null) {
        setProgress();
        if (mPauseButton != null) {
            mPauseButton.requestFocus();
        }
        disableUnsupportedButtons();

        FrameLayout.LayoutParams tlp = new FrameLayout.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT,
            Gravity.BOTTOM
        );

        mAnchor.addView(this, tlp);
        mShowing = true;
    }
    updatePausePlay();
    updateFullScreen();

    // cause the progress bar to be updated even if mShowing
    // was already true.  This happens, for example, if we're
    // paused with the progress bar showing the user hits play.
    mHandler.sendEmptyMessage(SHOW_PROGRESS);

    Message msg = mHandler.obtainMessage(FADE_OUT);
    if (timeout != 0) {
        mHandler.removeMessages(FADE_OUT);
        mHandler.sendMessageDelayed(msg, timeout);
    }
}

public boolean isShowing() {
    return mShowing;
}

/**
 * Remove the controller from the screen.
 */
public void hide() {
    if (mAnchor == null) {
        return;
    }

    try {
        mAnchor.removeView(this);
        mHandler.removeMessages(SHOW_PROGRESS);
    } catch (IllegalArgumentException ex) {
        Log.w("MediaController", "already removed");
    }
    mShowing = false;
}

private String stringForTime(int timeMs) {
    int totalSeconds = timeMs / 1000;

    int seconds = totalSeconds % 60;
    int minutes = (totalSeconds / 60) % 60;
    int hours   = totalSeconds / 3600;

    mFormatBuilder.setLength(0);
    if (hours > 0) {
        return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
    } else {
        return mFormatter.format("%02d:%02d", minutes, seconds).toString();
    }
}

private int setProgress() {
    if (mPlayer == null || mDragging) {
        return 0;
    }

    int position = mPlayer.getCurrentPosition();
    int duration = mPlayer.getDuration();
    if (mProgress != null) {
        if (duration > 0) {
            // use long to avoid overflow
            long pos = 1000L * position / duration;
            mProgress.setProgress( (int) pos);
        }
        int percent = mPlayer.getBufferPercentage();
        mProgress.setSecondaryProgress(percent * 10);
    }

    if (mEndTime != null)
        mEndTime.setText(stringForTime(duration));
    if (mCurrentTime != null)
        mCurrentTime.setText(stringForTime(position));

    return position;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    show(sDefaultTimeout);
    return true;
}

@Override
public boolean onTrackballEvent(MotionEvent ev) {
    show(sDefaultTimeout);
    return false;
}

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (mPlayer == null) {
        return true;
    }

    int keyCode = event.getKeyCode();
    final boolean uniqueDown = event.getRepeatCount() == 0
            && event.getAction() == KeyEvent.ACTION_DOWN;
    if (keyCode ==  KeyEvent.KEYCODE_HEADSETHOOK
            || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
            || keyCode == KeyEvent.KEYCODE_SPACE) {
        if (uniqueDown) {
            doPauseResume();
            show(sDefaultTimeout);
            if (mPauseButton != null) {
                mPauseButton.requestFocus();
            }
        }
        return true;
    } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
        if (uniqueDown && !mPlayer.isPlaying()) {
            mPlayer.start();
            updatePausePlay();
            show(sDefaultTimeout);
        }
        return true;
    } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
            || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
        if (uniqueDown && mPlayer.isPlaying()) {
            mPlayer.pause();
            updatePausePlay();
            show(sDefaultTimeout);
        }
        return true;
    } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
            || keyCode == KeyEvent.KEYCODE_VOLUME_UP
            || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
        // don't show the controls for volume adjustment
        return super.dispatchKeyEvent(event);
    } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
        if (uniqueDown) {
            hide();
        }
        return true;
    }

    show(sDefaultTimeout);
    return super.dispatchKeyEvent(event);
}

private View.OnClickListener mPauseListener = new View.OnClickListener() {
    public void onClick(View v) {
        doPauseResume();
        show(sDefaultTimeout);
    }
};

private View.OnClickListener mFullscreenListener = new View.OnClickListener() {
    public void onClick(View v) {
        doToggleFullscreen();
        show(sDefaultTimeout);
    }
};

public void updatePausePlay() {
    if (mRoot == null || mPauseButton == null || mPlayer == null) {
        return;
    }

    if (mPlayer.isPlaying()) {
        mPauseButton.setImageResource(R.drawable.ic_media_pause);
    } else {
        mPauseButton.setImageResource(R.drawable.ic_media_play);
    }
}

public void updateFullScreen() {
    if (mRoot == null || mFullscreenButton == null || mPlayer == null) {
        return;
    }

    if (mPlayer.isFullScreen()) {
        mFullscreenButton.setImageResource(R.drawable.ic_media_fullscreen_shrink);
    }
    else {
        mFullscreenButton.setImageResource(R.drawable.ic_media_fullscreen_stretch);
    }
}

private void doPauseResume() {
    if (mPlayer == null) {
        return;
    }

    if (mPlayer.isPlaying()) {
        mPlayer.pause();
    } else {
        mPlayer.start();
    }
    updatePausePlay();
}

private void doToggleFullscreen() {
    if (mPlayer == null) {
        return;
    }

    mPlayer.toggleFullScreen();
}

// There are two scenarios that can trigger the seekbar listener to trigger:
//
// The first is the user using the touchpad to adjust the posititon of the
// seekbar's thumb. In this case onStartTrackingTouch is called followed by
// a number of onProgressChanged notifications, concluded by onStopTrackingTouch.
// We're setting the field "mDragging" to true for the duration of the dragging
// session to avoid jumps in the position in case of ongoing playback.
//
// The second scenario involves the user operating the scroll ball, in this
// case there WON'T BE onStartTrackingTouch/onStopTrackingTouch notifications,
// we will simply apply the updated position without suspending regular updates.
private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
    public void onStartTrackingTouch(SeekBar bar) {
        show(3600000);

        mDragging = true;

        // By removing these pending progress messages we make sure
        // that a) we won't update the progress while the user adjusts
        // the seekbar and b) once the user is done dragging the thumb
        // we will post one of these messages to the queue again and
        // this ensures that there will be exactly one message queued up.
        mHandler.removeMessages(SHOW_PROGRESS);
    }

    public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
        if (mPlayer == null) {
            return;
        }

        if (!fromuser) {
            // We're not interested in programmatically generated changes to
            // the progress bar's position.
            return;
        }

        long duration = mPlayer.getDuration();
        long newposition = (duration * progress) / 1000L;
        mPlayer.seekTo( (int) newposition);
        if (mCurrentTime != null)
            mCurrentTime.setText(stringForTime( (int) newposition));
    }

    public void onStopTrackingTouch(SeekBar bar) {
        mDragging = false;
        setProgress();
        updatePausePlay();
        show(sDefaultTimeout);

        // Ensure that progress is properly updated in the future,
        // the call to show() does not guarantee this because it is a
        // no-op if we are already showing.
        mHandler.sendEmptyMessage(SHOW_PROGRESS);
    }
};

@Override
public void setEnabled(boolean enabled) {
    if (mPauseButton != null) {
        mPauseButton.setEnabled(enabled);
    }
    if (mFfwdButton != null) {
        mFfwdButton.setEnabled(enabled);
    }
    if (mRewButton != null) {
        mRewButton.setEnabled(enabled);
    }
    if (mNextButton != null) {
        mNextButton.setEnabled(enabled && mNextListener != null);
    }
    if (mPrevButton != null) {
        mPrevButton.setEnabled(enabled && mPrevListener != null);
    }
    if (mProgress != null) {
        mProgress.setEnabled(enabled);
    }
    disableUnsupportedButtons();
    super.setEnabled(enabled);
}

private View.OnClickListener mRewListener = new View.OnClickListener() {
    public void onClick(View v) {
        if (mPlayer == null) {
            return;
        }

        int pos = mPlayer.getCurrentPosition();
        pos -= 5000; // milliseconds
        mPlayer.seekTo(pos);
        setProgress();

        show(sDefaultTimeout);
    }
};

private View.OnClickListener mFfwdListener = new View.OnClickListener() {
    public void onClick(View v) {
        if (mPlayer == null) {
            return;
        }

        int pos = mPlayer.getCurrentPosition();
        pos += 15000; // milliseconds
        mPlayer.seekTo(pos);
        setProgress();

        show(sDefaultTimeout);
    }
};

private void installPrevNextListeners() {
    if (mNextButton != null) {
        mNextButton.setOnClickListener(mNextListener);
        mNextButton.setEnabled(mNextListener != null);
    }

    if (mPrevButton != null) {
        mPrevButton.setOnClickListener(mPrevListener);
        mPrevButton.setEnabled(mPrevListener != null);
    }
}

public void setPrevNextListeners(View.OnClickListener next, View.OnClickListener prev) {
    mNextListener = next;
    mPrevListener = prev;
    mListenersSet = true;

    if (mRoot != null) {
        installPrevNextListeners();

        if (mNextButton != null && !mFromXml) {
            mNextButton.setVisibility(View.VISIBLE);
        }
        if (mPrevButton != null && !mFromXml) {
            mPrevButton.setVisibility(View.VISIBLE);
        }
    }
}

public interface MediaPlayerControl {
    void    start();
    void    pause();
    int     getDuration();
    int     getCurrentPosition();
    void    seekTo(int pos);
    boolean isPlaying();
    int     getBufferPercentage();
    boolean canPause();
    boolean canSeekBackward();
    boolean canSeekForward();
    boolean isFullScreen();
    void    toggleFullScreen();
}

private static class MessageHandler extends Handler {
    private final WeakReference<VideoControllerView> mView; 

    MessageHandler(VideoControllerView view) {
        mView = new WeakReference<VideoControllerView>(view);
    }
    @Override
    public void handleMessage(Message msg) {
        VideoControllerView view = mView.get();
        if (view == null || view.mPlayer == null) {
            return;
        }

        int pos;
        switch (msg.what) {
            case FADE_OUT:
                view.hide();
                break;
            case SHOW_PROGRESS:
                pos = view.setProgress();
                if (!view.mDragging && view.mShowing && view.mPlayer.isPlaying()) {
                    msg = obtainMessage(SHOW_PROGRESS);
                    sendMessageDelayed(msg, 1000 - (pos % 1000));
                }
                break;
        }
    }
}

}

共有2个答案

施学
2023-03-14

您确定这是唯一出现此错误的场景吗?

您需要在播放器上设置更多侦听器,以便获得更多详细信息:

要点如下:

        mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(MediaPlayer mp, int what, int extra) {
            Log.i("VideoPlayerManager", "Error code (what): " + what);
            if (what == 100) {
                mVideoView.stopPlayback();
                mVideoView.start();
                enforcedStop = true;
            } else if (what == 1) {
                mVideoView.stopPlayback();
                mVideoView.start();
                enforcedStop = true;

            } else if (what == 800) {
                mVideoView.stopPlayback();
                mVideoView.start();
                enforcedStop = true;

            } else if (what == 701) {
                mVideoView.stopPlayback();
                mVideoView.start();
                enforcedStop = true;

            } else if (what == 700) {
                mVideoView.stopPlayback();
                mVideoView.start();
                enforcedStop = true;
            } else if (what == -38) {
                mVideoView.stopPlayback();
                mVideoView.start();
                enforcedStop = true;
            }
            return false;
        }
    });

另一个应该是oncompletion侦听器,如下所示:

mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {
            if (enforcedStop) {
                enforcedStop = false;
                return;
            }
            // setLooping(true) did not work, so we use this 2 lines of code
            mediaPlayer.seekTo(0);
            mediaPlayer.start();
        }
    });
上官和惬
2023-03-14

错误号-38对应于MediaPlayer::start的无效\u操作。请注意,INVALID\u OPERATION被设置为-ENOSYS,这是errno的-38。H

您可能必须调查您的MediaPlayer处于错误状态的原因。

你似乎试图在准备工作完成之前开始演奏。使用setOnPreparedListener()方法设置准备侦听器,并仅在准备完成后调用start()方法。

  mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
   public void onPrepared(MediaPlayer mp) {
     mp.start();
   }
    });
   mediaPlayer.prepareAsync();

并删除当前的mediaPlayer。从代码调用start()。

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

  • 我已经创建了一个使用媒体播放器播放音频的应用程序,但即使其他应用程序(如youtube)开始播放视频,我的播放器也不会停止。 如何停止音频,如果其他应用程序开始播放音频。 我用过mediaPlayer。start();播放音频。 任何帮助都将不胜感激。

  • 我正在开发一个包含两个活动的应用程序,一个是媒体播放器,另一个是要播放的歌曲列表,mp3播放器工作正常,从活动列表中我传递歌曲的名称和播放器工作正常。我有两个问题,如果用户播放一首歌并离开应用程序(这首歌一直在后台播放,这就是假设的工作方式),然后用户返回应用程序,搜索栏设置为0,计时器设置为0,有没有办法“保存”活动......也是如果一首歌正在播放,用户试图播放另一首歌,这首歌在前一首歌的顶部

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

  • 这可能不是一个可以接受的问题,但我现在非常绝望。 我需要一个同步java媒体播放器与快速寻找和平衡修改。 脚本: 我有一个javaFX项目,我必须在循环中播放一个非常短(50-100毫秒)的媒体文件。问题是,在重新启动之前,我需要等待一些要求。 简而言之:播放声音- javafx提供了一个我修改过的媒体播放器。 如果有人能为我指出正确的方向(图书馆/我错过的东西),我将不胜感激 ps允许的java

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