上海八号桥 网站建设,在重庆 那里可以做诚信网站认证,制作app怎么做,卡曼科技网站建设视频上很容易就可以做到倍速播放#xff0c;一般的视频格式都是每秒固定的帧数#xff0c;按比例跳帧就可以了。音频上其实也可以用这种方式来直接删除一些周期#xff0c;因为电脑里的音频也是数字化离散化地储存的。但是为了使声音不失真#xff0c;应该都用了稍复杂一点…
视频上很容易就可以做到倍速播放一般的视频格式都是每秒固定的帧数按比例跳帧就可以了。音频上其实也可以用这种方式来直接删除一些周期因为电脑里的音频也是数字化离散化地储存的。但是为了使声音不失真应该都用了稍复杂一点的算法的比方说把相邻时钟周期内的声音电平信号取平均或者用高斯平均值代替原信号再精细点可以自适应地在音调信号比较丰富的地方设置比较高的权重来尽量少压缩保持音色总之有很多种方法都可以做到啦。因为没有关注过这个所以并不知道在软件里具体是怎么实现的但是数字信号的缩放、滤波这些算法应该都差不多是这么做的音频的加速也不像是需要使用更复杂的非线性自适应滤波的样子。
我们很多时候需要实现的效果是变速不变调。项目基于FFMpeg和WebRtc通过FFMpeg从网络读取视频流经过解封装、解复用分离成音频数据包和视频数据包。并分别对音视频数据包进行解码解码完成之后的音频PCM44100Hz16bitMONO数据通过WebRtc提供的接口抛给AudioTrack视频YUV420数据抛给WebRtc通过VideoRenderer进行渲染。
弯路 1.一下子给播放设备通过WebRtc注册的Audio Playout Device喂两倍的数据可以实现两倍速不变调原理未知WebRtc内部实现机制但是有刺啦刺啦的噪音推测是基音周期的问题会产生基音断裂定位困难靠自己实现困难放弃了该方案。
2.将解码的速率变成22050Hz通过WebRtc播放播放器初始化为44100Hz可以实现两倍但是会变调放弃。
3.丢帧每隔一帧丢一帧可以实现音频倍速但是也会有刺啦刺啦的噪音基音断裂的问题而且声音会产生断续体验十分差放弃。
解决方法
靠自己解决这个基音周期的问题需要算法和实现不现实只能通过调用现有的库进行处理。经过调研发现有两个库支持倍速处理一个是SoundTouch另一个是Sonic。由于谷歌官方提供了一个ExoPlayer播放器其中应用的方法是Sonic并且网上有对两个库进行比较的文章Sonic的效果要略好于SoundTouch于是决定用Sonic库。
Sonic库有两种实现一种是Java实现的Sonic.java一种是C实现的Sonic-ndk因为我们要和FFMpeg共同处理所以需要使用ndk开发。对于没有自研究条件的团队选择第三方是最好的方案。
以JiaoZiVideoPlayer为例 本身自带的播放引擎是MediaPlayer也就是Android自带的播放器有很多不完善的地方倍速切换只支持5.0以上否则报NoClassDefFoundError 错误。而且还不支持rtmp类型的播放流。
所以在播放引擎上建议不要使用默认的目前比较流行的是 ijkplayer
但是只使用ijkplayer还需要自己写逻辑布局等等。为了简便直接给 JiaoZiVideoPlayer 使用 ijk 播放引擎省去了写布局和播放逻辑的麻烦。
实例
首先引入相关的jar包支持 implementation cn.jzvd:jiaozivideoplayer:6.2.7 implementation tv.danmaku.ijk.media:ijkplayer-java:0.8.4 implementation tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4 implementation com.jwkj:M3U8Manger:v2.1.9
Android Studio 3.0 以上建议使用 implementation 方式引入第三方库以下使用 compile。
自定义播放器布局
JiaoZi的播放器控件是 JZVideoPlayerStandard。所有关于播放器布局控件的操作都需要通过该控件能满足一般的视频播放需求。但是如果需要在 JiaoZi 播放器中添加按钮就需要自定义JZVideoPlayerStandard 比如倍速播放、下载、清晰度切换等功能。如果不需要修改布局直接在xml布局文件中使用即可。
a、重写 XML 如果需要给播放器添加新的控件或者更换图片修改按钮位置等必须要把原来的 XML 完整拷贝至新建 XML 中控件名称建议不能修改只添加你需要的控件就行了。通过 getLayoutId() 方法设置自定义布局文件。例如 Override public int getLayoutId() { return
b、添加倍速切换、下载控件 在 init 方法中初始化控件。 video_speed (TextView) findViewById(R.id.video_speed); video_speed.setOnClickListener(this); c、监听 注意JZVideoPlayerStandard 只是提供了布局的相关操作。倍速切换涉及到引擎的加速所以暂时用广播的方式去通知 Activity 调用引擎。 Override public void onClick(View v) { super.onClick(v); int i v.getId(); if (i R.id.video_speed) { // 切换倍速 video_speed.setText(resolveTypeUI(mFloat) X); mFloat resolveTypeUI(mFloat); EventBus.getDefault().post(new SpeedEvent(mFloat)); // 更新播放状态 onStatePreparingChangingUrl(0, getCurrentPositionWhenPlaying()); }else if (i R.id.video_download) { // 下载 } } /*显示倍速比例*/ public static float resolveTypeUI(float speed) { if (speed 1) { speed 1.25f; } else if (speed 1.25f) { speed 1.5f; } else if (speed 1.5f) { speed 2f; } else if (speed 2f) { speed 1f; } return d针对播放状态控制控件显隐 实际需求中如果是在全屏状态才需要展示控件那么就需要这一步操作。 JiaoZiVideoPlayer 默认有清晰度切换的控件不需要重复写相关逻辑。 Override public void setUp(Object[] dataSourceObjects, int defaultUrlMapIndex, int screen, Object... objects) { super.setUp(dataSourceObjects, defaultUrlMapIndex, screen, objects); //如果是全屏才显示相关按钮 Log.e(data:, dataSourceObjects.length); if (currentScreen SCREEN_WINDOW_FULLSCREEN) { video_speed.setVisibility(VISIBLE); video_download.setVisibility(VISIBLE); } else if (currentScreen SCREEN_WINDOW_NORMAL) { video_speed.setVisibility(GONE); video_download.setVisibility(GONE); } else if 自定义播放引擎
如果要实现倍速播放不管是 自带的MediaPlayer 还是 ijkPlayer 都必须要自定义播放引擎只不过各自继承的引擎不同。
a、提供倍速切换的方法 //播放速度默认1 public float speeding1f; public float getSpeeding() { return speeding; } public void setSpeeding(float speeding) { this.speeding speeding; } 通过引擎切换倍速ijkPlayer。 Override public void onPrepared(IMediaPlayer iMediaPlayer) { Log.e(speed:, getSpeeding() ); ijkMediaPlayer.setSpeed(getSpeeding()); ijkMediaPlayer.start(); } MediaPlayer: Override public void onPrepared(MediaPlayer mediaPlayer) { //设置倍速,5.0以下不支持会抛异常 try { mediaPlayer.setPlaybackParams(new PlaybackParams().setSpeed(getSpeeding())); }catch 使用实例
a设置播放控件 com.wapchief.qiniuplayer.views.myjzvideoplayerstandard android:layout_widthmatch_parent android:layout_height200dp android:idid/jiaozi_player stylefont-size: inherit;color: inherit; line-height: inherit;/com.wapchief.qiniuplayer.views.myjzvideoplayerstandard b初始化播放地址 如果不需要清晰度切换直接把objects 替换成视频 URL链接就行了。 private String[] mediaName {普通,高清,原画}; private void initPlayerUrl() { Object[] objects new Object[3]; LinkedHashMap map new LinkedHashMap(); for (int i 0; i 3; i) { map.put(mediaName[i], MediaUrl.URL_M3U8); } objects[0] map; objects[1] false; objects[2] new HashMap(); ((HashMap) objects[2]).put(key, value); mPlayerStandard.setUp(objects, 0, JZVideoPlayer.SCREEN_WINDOW_NORMAL, ); } c初始化播放引擎
登录后复制 //自定义 MediaPlayer MyJZMediaSystem mJZMediaSystem new MyJZMediaSystem(); //自定义 ijk MyIJKMediaSystem mIJKMediaSystem new MyIJKMediaSystem(); Override protected void onPause() { super.onPause(); JZVideoPlayer.releaseAllVideos(); JZVideoPlayer.setMediaInterface(mIJKMediaSystem); } Override public void onBackPressed() { if (JZVideoPlayer.backPress()) { return; } super.onBackPressed(); } d倍速切换事件 public void onMessageEventPostSpeed(SpeedEvent event) { mJZMediaSystem.setSpeeding(event.getSpeed()); mIJKMediaSystem.setSpeeding(event.getSpeed()); Toast.makeText(this, 正在切换倍速:event.getSpeed(), Toast.LENGTH_LONG).show(); }