最近在GitHub上看到一款基于IjkPlayer的视频播放控件,觉得不错,所以就体验了一下。

它的功能挺强大的,主要有一下几点:
支持 边播边缓存,使用了AndroidVideoCache。
支持 其他协议和编码concat、rtsp、hls、rtmp、crypto、mpeg等。
支持 DEMO演示获取视频第一帧等实现。
支持 简单滤镜(马赛克、黑白、色彩过滤、高斯、模糊、模糊等等20多种)。
支持 GL效果动画,(xyz轴旋转,放大)。
支持 视频帧截图功能,视频生成gif功能
支持 视频播放效果(水印、画面多重播放等)
支持 列表播放;列表连续播放;重力旋转与手动旋转;视频本身rotation旋转属性。
支持 全屏切换动画效果;小窗口播放,可拖动。
支持 快播和慢播;网络视频加载速度。
支持 调整显示比例:默认、16:9、4:3、填充。
支持 播放时旋转画面角度(0,90,180,270);镜像旋转。
支持 暂停前后台切换不黑屏;调整不同清晰度的支持;无缝切换支持。
支持 Https;IJKPlayer、EXOPlayer、系统播放器切换。
支持 锁定/解锁全屏点击功能;进度条小窗口预览(测试)。
支持 全屏与非全屏两套布局切换;弹幕功能。
支持 没有任何操作控件的纯播放支持。
支持 Demo带有RecyclerView列表滑动自动播放。
支持 多窗体下(包括桌面)的小窗口播放。

我选取了带有弹幕的视频播放例子感受了一下

1.引入:

A、直接引入//完整版引入
compile 'com.shuyu:GSYVideoPlayer:3.0.0'B、添加java和你想要的so支持:compile 'com.shuyu:gsyVideoPlayer-java:3.0.0'//根据你的需求
compile 'com.shuyu:gsyVideoPlayer-armv5:3.0.0'
compile 'com.shuyu:gsyVideoPlayer-armv7a:3.0.0'
compile 'com.shuyu:gsyVideoPlayer-arm64:3.0.0'
compile 'com.shuyu:gsyVideoPlayer-x64:3.0.0'
compile 'com.shuyu:gsyVideoPlayer-x86:3.0.0'

我选择的是第一种。

另外由于还要用到弹幕,还需要引入bilibili的弹幕引擎:

//bilibili 弹幕引擎
compile 'com.github.ctiao:DanmakuFlameMaster:0.9.16'
compile 'com.github.ctiao:ndkbitmap-armv7a:0.9.16'

2.添加播放弹幕视频额外代码:
需要添加解析弹幕的解析器:

public class BiliDanmukuParser extends BaseDanmakuParser {static {System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");}protected float mDispScaleX;protected float mDispScaleY;@Overridepublic Danmakus parse() {if (mDataSource != null) {AndroidFileSource source = (AndroidFileSource) mDataSource;try {XMLReader xmlReader = XMLReaderFactory.createXMLReader();XmlContentHandler contentHandler = new XmlContentHandler();xmlReader.setContentHandler(contentHandler);xmlReader.parse(new InputSource(source.data()));return contentHandler.getResult();} catch (SAXException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}return null;}public class XmlContentHandler extends DefaultHandler {private static final String TRUE_STRING = "true";public Danmakus result = new Danmakus();public BaseDanmaku item = null;public boolean completed = false;public int index = 0;public Danmakus getResult() {return result;}@Overridepublic void startDocument() throws SAXException {}@Overridepublic void endDocument() throws SAXException {completed = true;}@Overridepublic void startElement(String uri, String localName, String qName, Attributes attributes)throws SAXException {String tagName = localName.length() != 0 ? localName : qName;tagName = tagName.toLowerCase(Locale.getDefault()).trim();if (tagName.equals("d")) {// <d p="23.826000213623,1,25,16777215,1422201084,0,057075e9,757076900">我从未见过如此厚颜无耻之猴</d>// 0:时间(弹幕出现时间)// 1:类型(1从右至左滚动弹幕|6从左至右滚动弹幕|5顶端固定弹幕|4底端固定弹幕|7高级弹幕|8脚本弹幕)// 2:字号// 3:颜色// 4:时间戳 ?// 5:弹幕池id// 6:用户hash// 7:弹幕idString pValue = attributes.getValue("p");// parse p value to danmakuString[] values = pValue.split(",");if (values.length > 0) {long time = (long) (Float.parseFloat(values[0]) * 1000); // 出现时间int type = Integer.parseInt(values[1]); // 弹幕类型float textSize = Float.parseFloat(values[2]); // 字体大小int color = (int) ((0x00000000ff000000 | Long.parseLong(values[3])) & 0x00000000ffffffff); // 颜色// int poolType = Integer.parseInt(values[5]); // 弹幕池类型(忽略item = mContext.mDanmakuFactory.createDanmaku(type, mContext);if (item != null) {item.setTime(time);item.textSize = textSize * (mDispDensity - 0.6f);item.textColor = color;item.textShadowColor = color <= Color.BLACK ? Color.WHITE : Color.BLACK;}}}}@Overridepublic void endElement(String uri, String localName, String qName) throws SAXException {if (item != null && item.text != null) {if (item.duration != null) {String tagName = localName.length() != 0 ? localName : qName;if (tagName.equalsIgnoreCase("d")) {item.setTimer(mTimer);item.flags = mContext.mGlobalFlagValues;Object lock = result.obtainSynchronizer();synchronized (lock) {result.addItem(item);}}}item = null;}}@Overridepublic void characters(char[] ch, int start, int length) {if (item != null) {DanmakuUtils.fillText(item, decodeXmlString(new String(ch, start, length)));item.index = index++;// initial specail danmaku dataString text = String.valueOf(item.text).trim();if (item.getType() == BaseDanmaku.TYPE_SPECIAL && text.startsWith("[")&& text.endsWith("]")) {//text = text.substring(1, text.length() - 1);String[] textArr = null;//text.split(",", -1);try {JSONArray jsonArray = new JSONArray(text);textArr = new String[jsonArray.length()];for (int i = 0; i < textArr.length; i++) {textArr[i] = jsonArray.getString(i);}} catch (JSONException e) {e.printStackTrace();}if (textArr == null || textArr.length < 5 || TextUtils.isEmpty(textArr[4])) {item = null;return;}item.text = textArr[4];float beginX = Float.parseFloat(textArr[0]);float beginY = Float.parseFloat(textArr[1]);float endX = beginX;float endY = beginY;String[] alphaArr = textArr[2].split("-");int beginAlpha = (int) (AlphaValue.MAX * Float.parseFloat(alphaArr[0]));int endAlpha = beginAlpha;if (alphaArr.length > 1) {endAlpha = (int) (AlphaValue.MAX * Float.parseFloat(alphaArr[1]));}long alphaDuraion = (long) (Float.parseFloat(textArr[3]) * 1000);long translationDuration = alphaDuraion;long translationStartDelay = 0;float rotateY = 0, rotateZ = 0;if (textArr.length >= 7) {rotateZ = Float.parseFloat(textArr[5]);rotateY = Float.parseFloat(textArr[6]);}if (textArr.length >= 11) {endX = Float.parseFloat(textArr[7]);endY = Float.parseFloat(textArr[8]);if (!"".equals(textArr[9])) {translationDuration = Integer.parseInt(textArr[9]);}if (!"".equals(textArr[10])) {translationStartDelay = (long) (Float.parseFloat(textArr[10]));}}if (isPercentageNumber(beginX)) {beginX *= DanmakuFactory.BILI_PLAYER_WIDTH;}if (isPercentageNumber(beginY)) {beginY *= DanmakuFactory.BILI_PLAYER_HEIGHT;}if (isPercentageNumber(endX)) {endX *= DanmakuFactory.BILI_PLAYER_WIDTH;}if (isPercentageNumber(endY)) {endY *= DanmakuFactory.BILI_PLAYER_HEIGHT;}item.duration = new Duration(alphaDuraion);item.rotationZ = rotateZ;item.rotationY = rotateY;mContext.mDanmakuFactory.fillTranslationData(item, beginX,beginY, endX, endY, translationDuration, translationStartDelay, mDispScaleX, mDispScaleY);mContext.mDanmakuFactory.fillAlphaData(item, beginAlpha, endAlpha, alphaDuraion);if (textArr.length >= 12) {// 是否有描边if (!TextUtils.isEmpty(textArr[11]) && TRUE_STRING.equals(textArr[11])) {item.textShadowColor = Color.TRANSPARENT;}}if (textArr.length >= 13) {//TODO 字体 textArr[12]}if (textArr.length >= 14) {//TODO 是否有动画缓冲(easing)}if (textArr.length >= 15) {// 路径数据if (!"".equals(textArr[14])) {String motionPathString = textArr[14].substring(1);String[] pointStrArray = motionPathString.split("L");if (pointStrArray != null && pointStrArray.length > 0) {float[][] points = new float[pointStrArray.length][2];for (int i = 0; i < pointStrArray.length; i++) {String[] pointArray = pointStrArray[i].split(",");points[i][0] = Float.parseFloat(pointArray[0]);points[i][1] = Float.parseFloat(pointArray[1]);}mContext.mDanmakuFactory.fillLinePathData(item, points, mDispScaleX,mDispScaleY);}}}}}}private String decodeXmlString(String title) {if (title.contains("&amp;")) {title = title.replace("&amp;", "&");}if (title.contains("&quot;")) {title = title.replace("&quot;", "\"");}if (title.contains("&gt;")) {title = title.replace("&gt;", ">");}if (title.contains("&lt;")) {title = title.replace("&lt;", "<");}return title;}}private boolean isPercentageNumber(float number) {return number >= 0f && number <= 1f;}@Overridepublic BaseDanmakuParser setDisplayer(IDisplayer disp) {super.setDisplayer(disp);mDispScaleX = mDispWidth / DanmakuFactory.BILI_PLAYER_WIDTH;mDispScaleY = mDispHeight / DanmakuFactory.BILI_PLAYER_HEIGHT;return this;}
}

以及适配器:

public class DanamakuAdapter extends BaseCacheStuffer.Proxy {private Drawable mDrawable;private IDanmakuView mDanmakuView;public DanamakuAdapter(IDanmakuView mDanmakuView) {super();this.mDanmakuView = mDanmakuView;}@Overridepublic void prepareDrawing(final BaseDanmaku danmaku, boolean fromWorkerThread) {if (danmaku.text instanceof Spanned) { // 根据你的条件检查是否需要需要更新弹幕// FIXME 这里只是简单启个线程来加载远程url图片,请使用你自己的异步线程池,最好加上你的缓存池new Thread() {@Overridepublic void run() {String url = "http://www.bilibili.com/favicon.ico";InputStream inputStream = null;Drawable drawable = mDrawable;if (drawable == null) {try {URLConnection urlConnection = new URL(url).openConnection();inputStream = urlConnection.getInputStream();drawable = BitmapDrawable.createFromStream(inputStream, "bitmap");mDrawable = drawable;} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {IOUtils.closeQuietly(inputStream);}}if (drawable != null) {drawable.setBounds(0, 0, 100, 100);SpannableStringBuilder spannable = createSpannable(drawable);danmaku.text = spannable;if (mDanmakuView != null) {mDanmakuView.invalidateDanmaku(danmaku, false);}return;}}}.start();}}@Overridepublic void releaseResource(BaseDanmaku danmaku) {// TODO 重要:清理含有ImageSpan的text中的一些占用内存的资源 例如drawable}private SpannableStringBuilder createSpannable(Drawable drawable) {String text = "bitmap";SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text);ImageSpan span = new ImageSpan(drawable);//ImageSpan.ALIGN_BOTTOM);spannableStringBuilder.setSpan(span, 0, text.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);spannableStringBuilder.append("图文混排");spannableStringBuilder.setSpan(new BackgroundColorSpan(Color.parseColor("#8A2233B1")), 0, spannableStringBuilder.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);return spannableStringBuilder;}}

还有就是配置弹幕使用的播放器:

public class DanmakuVideoPlayer extends StandardGSYVideoPlayer {private BaseDanmakuParser mParser;//解析器对象private IDanmakuView mDanmakuView;//弹幕viewprivate DanmakuContext mDanmakuContext;private TextView mSendDanmaku, mToogleDanmaku;private long mDanmakuStartSeekPosition = -1;private boolean mDanmaKuShow = true;public DanmakuVideoPlayer(Context context, Boolean fullFlag) {super(context, fullFlag);}public DanmakuVideoPlayer(Context context) {super(context);}public DanmakuVideoPlayer(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic int getLayoutId() {return R.layout.danmaku_layout;}@Overrideprotected void init(Context context) {super.init(context);mDanmakuView = (DanmakuView) findViewById(R.id.danmaku_view);mSendDanmaku = (TextView) findViewById(R.id.send_danmaku);mToogleDanmaku = (TextView) findViewById(R.id.toogle_danmaku);//初始化弹幕显示initDanmaku();mSendDanmaku.setOnClickListener(this);mToogleDanmaku.setOnClickListener(this);}@Overridepublic void onPrepared() {super.onPrepared();onPrepareDanmaku(this);}@Overridepublic void onVideoPause() {super.onVideoPause();if (mDanmakuView != null && mDanmakuView.isPrepared()) {mDanmakuView.pause();}}@Overridepublic void onVideoResume() {super.onVideoResume();if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {mDanmakuView.resume();}}@Overridepublic void onCompletion() {releaseDanmaku(this);}@Overridepublic void onSeekComplete() {super.onSeekComplete();int time = mProgressBar.getProgress() * getDuration() / 100;//如果已经初始化过的,直接seek到对于位置if (mHadPlay && getDanmakuView() != null && getDanmakuView().isPrepared()) {resolveDanmakuSeek(this, time);} else if (mHadPlay && getDanmakuView() != null && !getDanmakuView().isPrepared()) {//如果没有初始化过的,记录位置等待setDanmakuStartSeekPosition(time);}}@Overridepublic void onClick(View v) {super.onClick(v);switch (v.getId()) {case R.id.send_danmaku:addDanmaku(true);break;case R.id.toogle_danmaku:mDanmaKuShow = !mDanmaKuShow;resolveDanmakuShow();break;}}/*** 处理播放器在全屏切换时,弹幕显示的逻辑* 需要格外注意的是,因为全屏和小屏,是切换了播放器,所以需要同步之间的弹幕状态*/@Overridepublic GSYBaseVideoPlayer startWindowFullscreen(Context context, boolean actionBar, boolean statusBar) {GSYBaseVideoPlayer gsyBaseVideoPlayer = super.startWindowFullscreen(context, actionBar, statusBar);if (gsyBaseVideoPlayer != null) {DanmakuVideoPlayer gsyVideoPlayer = (DanmakuVideoPlayer) gsyBaseVideoPlayer;//对弹幕设置偏移记录gsyVideoPlayer.setDanmakuStartSeekPosition(getCurrentPositionWhenPlaying());gsyVideoPlayer.setDanmaKuShow(getDanmaKuShow());onPrepareDanmaku(gsyVideoPlayer);}return gsyBaseVideoPlayer;}/*** 处理播放器在退出全屏时,弹幕显示的逻辑* 需要格外注意的是,因为全屏和小屏,是切换了播放器,所以需要同步之间的弹幕状态*/@Overrideprotected void resolveNormalVideoShow(View oldF, ViewGroup vp, GSYVideoPlayer gsyVideoPlayer) {super.resolveNormalVideoShow(oldF, vp, gsyVideoPlayer);if (gsyVideoPlayer != null) {DanmakuVideoPlayer gsyDanmaVideoPlayer = (DanmakuVideoPlayer) gsyVideoPlayer;setDanmaKuShow(gsyDanmaVideoPlayer.getDanmaKuShow());if (gsyDanmaVideoPlayer.getDanmakuView() != null &&gsyDanmaVideoPlayer.getDanmakuView().isPrepared()) {resolveDanmakuSeek(this, gsyDanmaVideoPlayer.getCurrentPositionWhenPlaying());resolveDanmakuShow();releaseDanmaku(gsyDanmaVideoPlayer);}}}private void initDanmaku() {// 设置最大显示行数HashMap<Integer, Integer> maxLinesPair = new HashMap<Integer, Integer>();maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 5); // 滚动弹幕最大显示5行// 设置是否禁止重叠HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<Integer, Boolean>();overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);DanamakuAdapter danamakuAdapter = new DanamakuAdapter(mDanmakuView);mDanmakuContext = DanmakuContext.create();mDanmakuContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 3).setDuplicateMergingEnabled(false).setScrollSpeedFactor(1.2f).setScaleTextSize(1.2f).setCacheStuffer(new SpannedCacheStuffer(), danamakuAdapter) // 图文混排使用SpannedCacheStuffer.setMaximumLines(maxLinesPair).preventOverlapping(overlappingEnablePair);if (mDanmakuView != null) {//todo 替换成你的数据流mParser = createParser(this.getResources().openRawResource(R.raw.comments));mDanmakuView.setCallback(new master.flame.danmaku.controller.DrawHandler.Callback() {@Overridepublic void updateTimer(DanmakuTimer timer) {}@Overridepublic void drawingFinished() {}@Overridepublic void danmakuShown(BaseDanmaku danmaku) {}@Overridepublic void prepared() {if (getDanmakuView() != null) {getDanmakuView().start();if (getDanmakuStartSeekPosition() != -1) {resolveDanmakuSeek(DanmakuVideoPlayer.this, getDanmakuStartSeekPosition());setDanmakuStartSeekPosition(-1);}resolveDanmakuShow();}}});mDanmakuView.enableDanmakuDrawingCache(true);}}/*** 弹幕的显示与关闭*/private void resolveDanmakuShow() {post(new Runnable() {@Overridepublic void run() {if (mDanmaKuShow) {if (!getDanmakuView().isShown())getDanmakuView().show();mToogleDanmaku.setText("弹幕关");} else {if (getDanmakuView().isShown()) {getDanmakuView().hide();}mToogleDanmaku.setText("弹幕开");}}});}/*** 开始播放弹幕*/private void onPrepareDanmaku(DanmakuVideoPlayer gsyVideoPlayer) {if (gsyVideoPlayer.getDanmakuView() != null && !gsyVideoPlayer.getDanmakuView().isPrepared()) {gsyVideoPlayer.getDanmakuView().prepare(gsyVideoPlayer.getParser(),gsyVideoPlayer.getDanmakuContext());}}/*** 弹幕偏移*/private void resolveDanmakuSeek(DanmakuVideoPlayer gsyVideoPlayer, long time) {if (GSYVideoManager.instance().getMediaPlayer() != null && mHadPlay&& gsyVideoPlayer.getDanmakuView() != null && gsyVideoPlayer.getDanmakuView().isPrepared()) {gsyVideoPlayer.getDanmakuView().seekTo(time);}}/*** 创建解析器对象,解析输入流** @param stream* @return*/private BaseDanmakuParser createParser(InputStream stream) {if (stream == null) {return new BaseDanmakuParser() {@Overrideprotected Danmakus parse() {return new Danmakus();}};}ILoader loader = DanmakuLoaderFactory.create(DanmakuLoaderFactory.TAG_BILI);try {loader.load(stream);} catch (IllegalDataException e) {e.printStackTrace();}BaseDanmakuParser parser = new BiliDanmukuParser();IDataSource<?> dataSource = loader.getDataSource();parser.load(dataSource);return parser;}/*** 释放弹幕控件*/private void releaseDanmaku(DanmakuVideoPlayer danmakuVideoPlayer) {if (danmakuVideoPlayer != null && danmakuVideoPlayer.getDanmakuView() != null) {Debuger.printfError("release Danmaku!");danmakuVideoPlayer.getDanmakuView().release();}}public BaseDanmakuParser getParser() {return mParser;}public DanmakuContext getDanmakuContext() {return mDanmakuContext;}public IDanmakuView getDanmakuView() {return mDanmakuView;}public long getDanmakuStartSeekPosition() {return mDanmakuStartSeekPosition;}public void setDanmakuStartSeekPosition(long danmakuStartSeekPosition) {this.mDanmakuStartSeekPosition = danmakuStartSeekPosition;}public void setDanmaKuShow(boolean danmaKuShow) {mDanmaKuShow = danmaKuShow;}public boolean getDanmaKuShow() {return mDanmaKuShow;}/*** 模拟添加弹幕数据*/private void addDanmaku(boolean islive) {BaseDanmaku danmaku = mDanmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);if (danmaku == null || mDanmakuView == null) {return;}danmaku.text = "这是一条弹幕 " + getCurrentPositionWhenPlaying();danmaku.padding = 5;danmaku.priority = 8;  // 可能会被各种过滤器过滤并隐藏显示,所以提高等级danmaku.isLive = islive;danmaku.setTime(mDanmakuView.getCurrentTime() + 500);danmaku.textSize = 25f * (mParser.getDisplayer().getDensity() - 0.6f);danmaku.textColor = Color.RED;danmaku.textShadowColor = Color.WHITE;danmaku.borderColor = Color.GREEN;mDanmakuView.addDanmaku(danmaku);}}

3.控制视频播放代码:
主要是在activity的oncreate方法中:

//使用自定义的全屏切换图片,!!!注意xml布局中也需要设置为一样的//必须在setUp之前设置danmakuVideoPlayer.setShrinkImageRes(R.drawable.custom_shrink);danmakuVideoPlayer.setEnlargeImageRes(R.drawable.custom_enlarge);String url = "https://res.exexm.com/cw_145225549855002";danmakuVideoPlayer.setUp(url, true, null, "测试视频");//增加封面ImageView imageView = new ImageView(this);imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);imageView.setImageResource(R.mipmap.xxx1);danmakuVideoPlayer.setThumbImageView(imageView);resolveNormalVideoUI();//外部辅助的旋转,帮助全屏orientationUtils = new OrientationUtils(this, danmakuVideoPlayer);//初始化不打开外部的旋转orientationUtils.setEnable(false);danmakuVideoPlayer.setIsTouchWiget(true);//关闭自动旋转danmakuVideoPlayer.setRotateViewAuto(false);danmakuVideoPlayer.setLockLand(false);danmakuVideoPlayer.setShowFullAnimation(false);danmakuVideoPlayer.setNeedLockFull(true);//detailPlayer.setOpenPreView(true);danmakuVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//直接横屏orientationUtils.resolveByClick();//第一个true是否需要隐藏actionbar,第二个true是否需要隐藏statusbardanmakuVideoPlayer.startWindowFullscreen(GsyActivity.this, true, true);}});danmakuVideoPlayer.setStandardVideoAllCallBack(new SampleListener() {@Overridepublic void onPrepared(String url, Object... objects) {super.onPrepared(url, objects);//开始播放了才能旋转和全屏orientationUtils.setEnable(true);isPlay = true;}@Overridepublic void onAutoComplete(String url, Object... objects) {super.onAutoComplete(url, objects);}@Overridepublic void onClickStartError(String url, Object... objects) {super.onClickStartError(url, objects);}@Overridepublic void onQuitFullscreen(String url, Object... objects) {super.onQuitFullscreen(url, objects);if (orientationUtils != null) {orientationUtils.backToProtVideo();}}});danmakuVideoPlayer.setLockClickListener(new LockClickListener() {@Overridepublic void onClick(View view, boolean lock) {if (orientationUtils != null) {//配合下方的onConfigurationChangedorientationUtils.setEnable(!lock);}}});

基于IjkPlayer的视频播放器相关推荐

  1. 基于 IjkPlayer 的视频播放器

    dkplayer 项目地址:dueeeke/dkplayer  简介:基于 IjkPlayer 的视频播放器,支持直播点播,悬浮窗播放,广告播放,边播边缓存:支持重力感应自动全屏:完美实现 ListV ...

  2. 基于ijkplayer的视频播放器,仿Bilibili客户端,集成沉浸式全屏、弹幕、触屏控制、视频源切换等功能

    该视频播放器基于Bilibili的开源项目ijkplayer做的,是在github上的demo基础上搭建了个播放界面,如果你之前有研究过这个demo代码,那你看这个库就非常简单了.至于还不知道ijkp ...

  3. rtsp协议_基于libVLC的视频播放器(支持RTSP协议)

    VLC Media Player是一款优秀的播放器,大多数多媒体开发人员都使用过.VLC是一款开源的.跨平台的.可扩展的.多媒体播放器.流媒体服务器及框架,可播放大多数多媒体文件,以及DVD.音频CD ...

  4. 基于android的视频播放器,基于Android的视频播放器的设计与实现-.doc

    基于Android的视频播放器的设计与实现- 基于Android的视频播放器的设计与实现 中 文 摘 要 如今,随着基于Android的智能手机的,.因此,设计一个基于android手机的多功能播放器 ...

  5. 50行代码实现的一个最简单的基于 DirectShow 的视频播放器

    本文介绍一个最简单的基于 DirectShow 的视频播放器.该播放器对于初学者来说是十分有用的,它包含了使用 DirectShow 播放视频所有必备的函数. 直接贴上代码,具体代码的含义都写在注释中 ...

  6. 最简单的基于libVLC的例子:最简单的基于libVLC的视频播放器

    最简单的基于libVLC的例子文章列表: 最简单的基于libVLC的例子:最简单的基于libVLC的视频播放器 最简单的基于libVLC的例子:最简单的基于libVLC的视频播放器(图形界面版) 最简 ...

  7. 最简单的基于 DirectShow 的视频播放器

    源程序下载链接:https://download.csdn.net/download/bmjhappy/11250669 50行代码实现的一个最简单的基于 DirectShow 的视频播放器 本文介绍 ...

  8. QT软件开发-基于FFMPEG设计视频播放器-解码音频(三)

    QT软件开发-基于FFMPEG设计视频播放器-CPU软解视频(一) https://xiaolong.blog.csdn.net/article/details/126832537 QT软件开发-基于 ...

  9. QT软件开发-基于FFMPEG设计视频播放器-软解图像(一)

    QT软件开发-基于FFMPEG设计视频播放器-CPU软解视频(一) https://xiaolong.blog.csdn.net/article/details/126832537 QT软件开发-基于 ...

最新文章

  1. 第五课.Python函数(二)
  2. scikit-image 几个案例(下)
  3. Atitit  五种IO模型attilax总结 blocking和non-blocking synchronous IO和asynchronous I
  4. 【JavaFx教程】第三部分:与用户的交互
  5. php删除垃圾文件,Python删除windows垃圾文件的方法
  6. Delphi 7 中使用IdUDPServer1和IdUDPClient1控件实现通信检测
  7. java获取ip地址不重复,如何在android(Java)中验证Ip地址[重复]
  8. Flowable 数据库表结构 ACT_RE_MODEL
  9. codesmith 如何把选中的多个表生成实体
  10. Python入门6_抽象
  11. 自动设定form的高度_自动升降车
  12. 详解FSMO的五种角色
  13. Atitit 语言分类 形式语言 目录 1. 形式语言(英语:Formal language)是用精确的数学或机器可处理的公式定义的语言。 1 1.1. 形式语言理论是用数学方法研究自然语言(如英语
  14. 一些神奇的小函数(一)——gotoxy篇
  15. Linux程序设计——用getopt处理命令行参数
  16. Reflector 3 for Mac(ios屏幕镜像工具)
  17. 软件开发工作量及费用量化评估方法在金融行业的应用
  18. [MySQL/初学者]数据完整性约束
  19. 【踩坑日记 · 前端】为 Excalidraw 添加中文手写字体
  20. 如何做好技术布道——用影响影响影响

热门文章

  1. pe管厂家_mpp管与PE管的区别
  2. 宝马X6和保时捷卡宴,选谁更加高端大气上档次?
  3. Tomcat优化之JDK优化之熵池策略
  4. 2021年高新技术企业认定时间及条件出来了,全国28省
  5. 关于Unity发布的WebGL项目出现问题的解决方法和本地网站部署
  6. iPhone开发初步
  7. 一文带你快速上手正则表达式
  8. Rhel 7 /Centos 7配置快速启动栏启动以Firefox为例
  9. 【python远程linux、执行命令、读取excel】
  10. [MCGC]网络优化_MCGC 下载地址 最新版 持续更新