EasyPlayer实现直播抓拍

EasyPlayer实现直播抓拍对于一个裸的RTSPURL,存放在播放列表上略显单调与枯燥。大家可以看到EasyPlayer在播放完视频后会保存一帧图片到列表上。那么这个功能是如何做到的呢?如果自己实现解码的话,比如使用ffmpeg解码,这种情况下,将视频帧解码,再编码成jpeg保存下来,应该不是什么难事。相信大多数播放器都是这样处理的。H264格式的视频码流=>解码=>YUV格式的视频帧=>压缩=>jpeg=>保存到

大家好,又见面了,我是你们的朋友全栈君。

对于一个裸的RTSP URL,存放在播放列表上略显单调与枯燥。大家可以看到EasyPlayer在播放完视频后会保存一帧图片到列表上。

EasyPlayer上的播放列表的缩略图

那么这个功能是如何做到的呢?
如果自己实现解码的话,比如使用ffmpeg解码,这种情况下,将视频帧解码,再编码成jpeg保存下来,应该不是什么难事。相信大多数播放器都是这样处理的。

H264格式的视频码流=>解码=>YUV格式的视频帧=>压缩=>jpeg=>保存到本地

但是如果我们用硬解码,很遗憾,安卓的硬解码并没有提供获取视频帧数据的功能,那又该如何实现呢?
有两种方法可以实现硬解码截屏

  • 单独创建只为抓图用的软解码器并用上面的方法来抓图
  • 直接获取TextureView的内容并保存

这里介绍下第二种方法。TextureView提供了一个getBitmap() 的方法,解释如下:

Returns a Bitmap representation of the content of the associated surface texture.

该方法提供了当前TextureView的渲染内容,作为一个Bitbmap对象返回。这样我们可以将这个Bitmap压缩成jpeg、png等格式并保存下来。Bitmap提供了compress 方法可以直接压缩。下面为从TextureView获取并存储Bitmap对象的方法:

public void takePicture(final String path) {
        try {
            if (mWidth <= 0 || mHeight <= 0) {
                return;
            }
            Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
            mSurfaceView.getBitmap(bitmap);
            saveBitmapInFile(path, bitmap);
            bitmap.recycle();
        } catch (OutOfMemoryError error) {
            error.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }

下面是将Bitmap保存成JPEG的方法,这里,同时会将缩略图保存在安卓系统的相册中,以便调用系统的选取图片的方法可以访问到:

    private void saveBitmapInFile(final String path, Bitmap bitmap) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(path);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
            if (mScanner == null) {
                MediaScannerConnection connection = new MediaScannerConnection(getContext(),
                        new MediaScannerConnection.MediaScannerConnectionClient() {
                            public void onMediaScannerConnected() {
                                mScanner.scanFile(path, null /* mimeType */);
                            }

                            public void onScanCompleted(String path1, Uri uri) {
                                if (path1.equals(path)) {
                                    mScanner.disconnect();
                                    mScanner = null;
                                }
                            }
                        });
                try {
                    connection.connect();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                mScanner = connection;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (OutOfMemoryError error) {
            error.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

这里需要注意的是getBitmap函数的调用时机,

  • 首先一定要在TextureView创建之后调用。即在onSurfaceTextureAvailable方法回掉之后才能调用,否则Texture尚未创建,该函数会返回null 。
  • 不仅如此,还需要在视频播放之后再调用。否则TextureView所展示的内容为空,因此您保存的快照可能是纯黑色的。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/150346.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • (5)Spring WebFlux快速上手——响应式Spring的道法术器「建议收藏」

    本系列其他文章见:《响应式Spring的道法术器》。前情提要:响应式流|lambda与函数式|Reactor快速上手1.3.3SpringWebFluxSpringWebFlux是随Spring5推出的响应式Web框架。1)服务端技术栈Spring提供了完整的支持响应式的服务端技术栈。如上图所示,左侧为基于spring-webmvc的技…

    2022年4月10日
    129
  • 数据结构与算法(三):双向链表[通俗易懂]

    数据结构与算法(三):双向链表[通俗易懂]一、双向链表双向链表与单链表基本相似,但是最大的区别在于双向链表在节点中除了指向下一节点的next指针外,还有指向前一节点的prev指针,这使得双向链表在可以在任意节点从头尾两个方向进行遍历,是“双

    2022年8月16日
    7
  • input事件的获取

    input事件的获取loop线程已经运行起来了,如果不出意外,它是不会终止的;不妨以此为起点,再开始一段新的旅程,我要去探索input事件的获取。一EventHub构造函数EventHub是所有输入事件的中央处理站,凡是与输入事件有关的事它都管。上帝创造万事万物都是有原因的,看看构造它是出于什么目的。EventHub::EventHub(void):mBuiltInKeybo

    2022年6月10日
    34
  • zigbee协议栈工作流程 From zigbee菜鸟笔记(十 一)

    zigbee协议栈工作流程 From zigbee菜鸟笔记(十 一)一.ZigBee协议栈简介什么是ZigBee协议栈呢?它和ZigBee协议有什么关系呢?协议是一系列的通信标准,通信双方需要共同按照这一标准进行正常的数据发射和接收。协议栈是协议的具体实现形式,通俗点来理解就是协议栈是协议和用户之间的一个接口,开发人员通过使用协议栈来使用个协议的,进而实现无线数据收发。ZigBee的协议分为两部分,IEEE802.15.4定义了PHY(物理层)和MAC(介质访问层)技术规范;ZigBee联盟定义了NWK(网络层)、APS(应用程序支持子层)、APL(应用层

    2022年5月28日
    45
  • linux用命令dpkg,Linux中dpkg命令起什么作用呢?

    linux用命令dpkg,Linux中dpkg命令起什么作用呢?摘要:下文讲述Linux中dpkg的功能说明,如下所示;dpkg是(Debianpackage英文的缩写)dpkg命令功能:用于管理DebianLinux中的包管理(安装,创建,管理软件)的一种实用性工具dpkg命令的语法格式:dpkg[参数]—–常用参数说明——-i:安装软件包-r:删除软件包-l:输出已安装软件包列表-L:输出于软件包关联的文件-c:输出软件包内文件列表–…

    2022年5月21日
    40
  • python3.8安装scrapy_python没安装成功怎么办

    python3.8安装scrapy_python没安装成功怎么办直接安装scrapy各种报错,后来各种百度终于解决了,如下是亲身的经历。pipinstallscrapy这样直接会报错。第一步:先安装wheelpipinstallwheel第二步:安装twiste,事先下载好Twisted-17.9.0-cp36-cp36m-win32.whl,我用的是32位,切换到twisted路径下安装,这上有http://www.lfd.uci.edu/~g…

    2022年9月18日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号