自己定义一个播放器

博客提及参考智能课件里的PPTVideoView模块,还指出具体使用该播放器可参考PPTVideoView。

参考智能课件里的PPTVideoView模块:

package com.zhl.courseware.filtervideo;

import android.content.Context;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;

import com.zhl.android.exoplayer2.ExoPlayerFactory;
import com.zhl.android.exoplayer2.Player;
import com.zhl.android.exoplayer2.SimpleExoPlayer;
import com.zhl.android.exoplayer2.source.MediaSource;
import com.zhl.android.exoplayer2.source.ProgressiveMediaSource;
import com.zhl.android.exoplayer2.upstream.DataSource;
import com.zhl.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.zhl.android.exoplayer2.util.Util;
import com.zhl.courseware.util.PPTUtils;

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

public class FilterVideoPlayer implements Player.EventListener {

    protected Context mAppContext;
    protected SimpleExoPlayer player;
    protected MediaPlayer mediaPlayer;
    protected boolean isMediaPlayerPrepared;
    protected int lastReportedPlaybackState;
    protected boolean isLastReportedPlayWhenReady;
    protected boolean isPreparing = true;
    protected boolean isBuffering = false;
    protected MediaSource videoSource;
    protected IFilterVideoListener videoListener;

    public FilterVideoPlayer(Context context, Uri videoUri,String path) {
//        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP){
//            intMediaPlayer(path);
//        }else {
//            mAppContext = context.getApplicationContext();
//            DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(mAppContext, Util.getUserAgent(mAppContext, "yourApplicationName"));
//            videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(videoUri);
//            player = ExoPlayerFactory.newSimpleInstance(mAppContext);
//            player.addListener(this);
//        }
        mAppContext = context.getApplicationContext();
        DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(mAppContext, Util.getUserAgent(mAppContext, "yourApplicationName"));
        videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(videoUri);
        player = ExoPlayerFactory.newSimpleInstance(mAppContext);
        player.addListener(this);
    }

//    public FilterVideoPlayer(Context context, Uri videoUri) {
//        mAppContext = context.getApplicationContext();
//        DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(mAppContext, Util.getUserAgent(mAppContext, "yourApplicationName"));
//        videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(videoUri);
//        player = ExoPlayerFactory.newSimpleInstance(mAppContext);
//        player.addListener(this);
//    }

    private void intMediaPlayer(String path){
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.reset();
//            mediaPlayer.release();
//            mediaPlayer.setDataSource(path);

            File file = new File(path);
            if (file.exists()) {
                mediaPlayer.setDataSource(path);

                MediaMetadataRetriever retriever = new MediaMetadataRetriever();
                retriever.setDataSource(path);
//                onDataSourceSet(retriever);
            }

            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    isMediaPlayerPrepared = true;
                    if (videoListener!=null) {
                        videoListener.onPrepared();
                    }
                }
            });
            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    if (videoListener!=null) {
                        videoListener.onCompletion();
                    }
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void reSetUri(Uri videoUri){
        DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(mAppContext, Util.getUserAgent(mAppContext, "yourApplicationName"));
        videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(videoUri);
    }

    public void setVideoListener(IFilterVideoListener videoListener) {
        this.videoListener = videoListener;
    }

    public void prepare(){
//        try {
//            if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP){
//                mediaPlayer.prepareAsync();
//            }else {
//                player.prepare(videoSource);
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        player.prepare(videoSource);
    }
    /**TODO 殷志杰441 调用这个方法可以吗*/
    public void setPlayWhenReady(boolean playWhenReady){
//        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
//            if (isMediaPlayerPrepared) {
//                if (playWhenReady) {
//                    mediaPlayer.start();
//                } else {
//                    mediaPlayer.pause();
//                }
//            }
//        } else {
//            player.setPlayWhenReady(playWhenReady);
//        }
        player.setPlayWhenReady(playWhenReady);
    }

    public SimpleExoPlayer getSimpleExoPlayer() {
        return player;
    }

    public MediaPlayer geMediaPlayer() {
        return mediaPlayer;
    }
    public long getCurrentPosition(){
//        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP){
//            return mediaPlayer.getCurrentPosition();
//        }else {
//            return player.getCurrentPosition();
//        }
        return player.getCurrentPosition();
    }
    public long getDuration(){
//        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP){
//            return mediaPlayer.getDuration();
//        }else {
//            return player.getDuration();
//        }
        return player.getDuration();
    }
    public void stop(){
//        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP){
//            mediaPlayer.stop();
//        }else {
//            player.stop();
//        }
        player.stop();
    }
    public void release(){
//        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP){
//            mediaPlayer.release();
//            mediaPlayer = null;
//        }else {
//            player.release();
//            player = null;
//        }
        player.release();
        player = null;
    }
    public void seekTo(long positionMs){
//        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP){
//            mediaPlayer.seekTo((int) positionMs);
//        }else {
//            player.seekTo(positionMs);
//        }
        player.seekTo(positionMs);
    }


    public boolean isPlaying() {
        if (player == null){
//            Log.e("zhl","判断1");
            return false;
        }
        int state = player.getPlaybackState();
        switch (state) {
            case Player.STATE_BUFFERING:
            case Player.STATE_READY:
//                Log.e("zhl","判断2:"+state);
                return player.getPlayWhenReady();
            case Player.STATE_IDLE:
            case Player.STATE_ENDED:
            default:
//                Log.e("zhl","判断3:"+state);
                return false;
        }
    }
    @Override
    public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
        //重新播放状态顺序为:STATE_IDLE -》STATE_BUFFERING -》STATE_READY
        //缓冲时顺序为:STATE_BUFFERING -》STATE_READY
        //Log.e(TAG, "onPlayerStateChanged: playWhenReady = " + playWhenReady + ", playbackState = " + playbackState);
        if (isLastReportedPlayWhenReady != playWhenReady || lastReportedPlaybackState != playbackState) {
            if (isBuffering) {
                switch (playbackState) {
                    case Player.STATE_ENDED:
                    case Player.STATE_READY:
//                        notifyOnInfo(IMediaPlayer.MEDIA_INFO_BUFFERING_END, mInternalPlayer.getBufferedPercentage());
                        isBuffering = false;
                        break;
                }
            }

            if (isPreparing) {
                switch (playbackState) {
                    case Player.STATE_READY:
                        //TODO 视频准备完成
//                        notifyOnPrepared();
                        if (videoListener!=null) {
                            videoListener.onPrepared();
                        }
                        isPreparing = false;
                        break;
                }
            }

            switch (playbackState) {
                case Player.STATE_BUFFERING:
//                    notifyOnInfo(IMediaPlayer.MEDIA_INFO_BUFFERING_START, mInternalPlayer.getBufferedPercentage());
                    isBuffering = true;
                    break;
                case Player.STATE_READY:
                    break;
                case Player.STATE_ENDED:
                    //TODO 视频播放完成
                    if (videoListener!=null) {
                        videoListener.onCompletion();
                    }
//                    notifyOnCompletion();
                    break;
                default:
                    break;
            }
        }
        isLastReportedPlayWhenReady = playWhenReady;
        lastReportedPlaybackState = playbackState;
    }
}

FilterVideoPlayer:就是播放器的播放逻辑,里面目前使用的是SimpleExoPlayer,可以根据需要改为MediaPlayer或其它播放器;这个播放器可以播放音频或视频文件,因为播放视频时画面的显示view没有在这里面定义,而是在EPlayerView里定义的:
package com.zhl.courseware.filtervideo;

import android.content.Context;
import android.util.AttributeSet;
import android.view.SurfaceView;
import android.view.TextureView;

import com.zhl.android.exoplayer2.SimpleExoPlayer;
import com.zhl.android.exoplayer2.video.VideoListener;

//想使用TextureView时,改为继承TextureView,同时setSimpleExoPlayer()里使用setVideoTextureView(EPlayerView.this)即可
//public class EPlayerView extends TextureView implements VideoListener {
public class EPlayerView extends SurfaceView implements VideoListener {
    private SimpleExoPlayer player;

    private float videoAspect = 1f;
    private PlayerScaleType playerScaleType = PlayerScaleType.RESIZE_FIT_WIDTH;//RESIZE_FIT_HEIGHT、RESIZE_NONE
    private boolean isVideoSizeChanged = false;

    public EPlayerView(Context context) {
        this(context, null);
    }

    public EPlayerView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public EPlayerView setSimpleExoPlayer(SimpleExoPlayer player) {
        if (this.player != null) {
            this.player.release();
            this.player = null;
        }
        this.player = player;
        this.player.addVideoListener(this);
//        this.player.setVideoTextureView(EPlayerView.this);
        this.player.setVideoSurfaceView(EPlayerView.this);
        return this;
    }

    public void setPlayerScaleType(PlayerScaleType playerScaleType) {
        this.playerScaleType = playerScaleType;
        requestLayout();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (isVideoSizeChanged) {
            int measuredWidth = getMeasuredWidth();
            int measuredHeight = getMeasuredHeight();

            int viewWidth = measuredWidth;
            int viewHeight = measuredHeight;

            switch (playerScaleType) {
                case RESIZE_FIT_WIDTH:
                    viewHeight = (int) (measuredWidth / videoAspect);
                    break;
                case RESIZE_FIT_HEIGHT:
                    viewWidth = (int) (measuredHeight * videoAspect);
                    break;
            }
            setMeasuredDimension(viewWidth, viewHeight);
        }

    }

    @Override
    public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
        isVideoSizeChanged = true;
        videoAspect = ((float) width / height) * pixelWidthHeightRatio;
        requestLayout();
    }

    @Override
    public void onRenderedFirstFrame() {
        // do nothing
    }
}

具体怎么使用这个播放器参考:PPTVideoView

<think>好的,我需要帮用户解决如何使用仓颉编程语言创建音乐播放器的问题。首先,用户可能需要一个基本的示例代码,这样他们可以快速上手。根据提供的引用,特别是引用[3]和[4],仓颉支持面向对象和函数式编程,还有struct和mut函数,以及Lambda表达式。我应该结合这些特性来设计示例。 首先,音乐播放器需要管理播放列表和当前状态。定义一个结构体MusicPlayer,包含播放列表、当前索引和播放状态。引用[3]提到创建struct实例,所以这一步是可行的。然后,需要实现一些方法,比如添加歌曲、切换歌曲、播放/暂停。这里可以用mut函数,因为需要修改结构体的状态,引用[3]中的mut函数应该用在这里。 接下来,初始化播放器,添加歌曲,并模拟播放控制。考虑到仓颉支持函数式特性,如Lambda表达式,可能在事件处理中使用,比如绑定按钮点击事件。不过示例代码可能需要简化,所以先展示基本功能。 用户可能需要知道如何组织代码,比如使用面向对象的方式。引用[2]提到类与对象、继承等,但这里用struct可能更合适,因为仓颉支持多范式。另外,引用[4]提到高阶函数,可能在播放完成后的回调中使用,比如onPlayEnd。 需要检查代码是否符合仓颉语法,比如函数定义、方法调用。比如,switchTo方法使用match进行模式匹配,这是函数式特性,符合引用[4]中的模式匹配。同时,togglePlay使用mut修饰符,说明修改内部状态,引用[3]中的mut函数应用正确。 可能还需要解释代码的结构,比如结构体定义、方法实现,以及主程序流程。用户可能需要了解如何运行和测试这段代码,但仓颉的具体运行环境未提及,所以保持示例通用。 最后,生成相关问题,覆盖扩展功能、UI开发、多线程等,引用中的内容,如引用[3]提到UI开发,引用[4]提到多范式,所以相关问题可以涉及这些方面。确保问题引导用户深入学习和应用仓颉的不同特性。</think>以下是以仓颉编程语言创建音乐播放器的分步教程及示例代码,结合其面向对象与函数式编程特性实现: ### 一、基础结构定义 ```仓颉 // 定义音乐播放器结构体(引用[3]struct特性) struct 音乐播放器 { 播放列表: 列表<字符串> 当前索引: 整数 播放状态: 枚举<"播放中", "已暂停"> } // 定义成员方法(引用[3]mut函数特性) mut func 切换歌曲(方向: 整数) -> 音乐播放器 { this.当前索引 = match 方向 { 1 => (当前索引 + 1) % 播放列表.长度() -1 => (当前索引 - 1 + 播放列表.长度()) % 播放列表.长度() _ => 当前索引 } } mut func 切换播放状态() { this.播放状态 = match 播放状态 { "播放中" => "已暂停" "已暂停" => "播放中" } } ``` ### 二、功能实现 ```仓颉 // 创建播放器实例(引用[2]面向对象特性) let 播放器 = 音乐播放器( 播放列表: ["夜曲.mp3", "青花瓷.wav", "七里香.flac"], 当前索引: 0, 播放状态: "已暂停" ) // 添加歌曲(引用[4]函数式特性) func 添加歌曲(播放器: mut 音乐播放器, 路径: 字符串) { 播放器.播放列表.追加(路径) } // 播放控制逻辑 func 播放音频(路径: 字符串) { // 调用系统音频接口(假设存在音频服务模块) 音频服务::播放(路径, onPlayEnd: { 播放器.切换歌曲(1) }) // 尾随lambda(引用[3]特性) } ``` ### 三、主程序流程 ```仓颉 // 初始化UI(引用[3]UI开发特性) let 界面 = 图形界面::创建([ 按钮("播放/暂停", 点击: { 播放器.切换播放状态() }), 按钮("下一首", 点击: { 播放器.切换歌曲(1) }), 列表视图(播放器.播放列表) ]) // 状态监听循环 while 真 { if 播放器.播放状态 == "播放中" { 播放音频(播放器.播放列表[播放器.当前索引]) } 系统::等待(1000) // 降低CPU占用 } ``` ### 关键特性应用说明: 1. **文化融合特性**:所有标识符使用中文命名,如`播放状态`、`切换歌曲`等(引用[1]文化特性) 2. **多范式编程**:结合面向对象(struct)、函数式(lambda)和命令式(while循环)(引用[4]多范式支持) 3. **类型安全**:明确定义结构体字段类型,确保运行时稳定性(引用[4]类型安全)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值