TOP

大疆无人机 Android 开发总结——视频解码(一)
2019-09-04 00:58:50 】 浏览:47
Tags:无人机 Android 开发 总结 视频 解码

        DJI_Mobile_SDK是大疆为开发者提供的开发无人机应用的开发接口,可以实现对无人机飞行的控制,也可以利用无人机相机完成一些视觉任务。目前网上的开发教程主要集中于DJI 开发者社区网上的资源非常少。废话不多说~~,现在将在Android项目中学习到的东西总结一下。

 

      使用大疆无人机做计算机视觉项目,第一步就是要将从云台相机中获取的视频流解析成图像帧,DJI在github上提供了视频解码成图像帧的Demo程序。官网说明文档并没有对如何将这个解码Demo集成进自己的项目进行说明,只是简单说明了DJIVideoStreamDecoder和NativeHelper类的主要用途。附上解码的源程序

Android源代码地址https://github.com/DJI-Mobile-SDK-Tutorials/Android-VideoStreamDecodingSample.git

 

下面就将对如何使用这个模块进行说明

一、模块结构

      首先要说明的是,整个解码过程是通过FFmpeg和MediaCodec实现,按照官网的教程,DJIVideoStreamDecoder.java和NativeHelper.java是实现解码的关键类。按照官网的教程分为以下步骤:

 

1. 初始化一个NativeHelper的实例对象,来监听来自无人机高空的视频数据。

2.将原始的H.264视频数据送入FFmpeg中解析。

3.将解析完成的视频数据从FFmpeg中取出,并将解析后的数据缓存到图像帧序列中

4.将MediaCodec作为一个解码器,然后对视频中的I帧进行捕获。

5.解码完成后,可为MediaCodec的输出数据配置一个TextureView或SurfaceView用来对视频画面进行预览,或者调用监听器对解码数据进行监听完成其他操作。

6.释放FFmpeg和MediaCodec资源。

 

二、解码调用

 

       看完上述步骤,我们对解码过程有了初步的认识,以下是DJIVideoStreamDecoder类中的变量。其中instance是解码类的实例,解码出的视频帧会存放在frameQueue中。handle类涉及线程控制,如果需要了解HandleThread的用法,请点击此链接。在Demo中解码线程已经全部实现,不需要我们再做任何处理。

      1.DJIVideoStreamDecoder.java

    private static DJIVideoStreamDecoder instance;
    private Queue<DJIFrame> frameQueue;
    private HandlerThread dataHandlerThread;
    private Handler dataHandler;
    private HandlerThread callbackHandlerThread;
    private Handler callbackHandler;
    private Context context;
    private MediaCodec codec;
    private Surface surface;

    public int frameIndex = -1;
    private long currentTime;
    public int width;
    public int height;
    private boolean hasIFrameInQueue = false;
    private boolean hasIFrameInCodec;
    private ByteBuffer[] inputBuffers;
    private ByteBuffer[] outputBuffers;
    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
    LinkedList<Long> bufferChangedQueue=new LinkedList<Long>();

    private long createTime;

2.Mainactivity.java

       实现流数据转换为图像的关键步骤在MainActivity.java中实现,值得注意的是在Android系统中,图像是以YUVImage的格式传递,因此,在存储数据的时候要使用YUV图像格式,对于每秒解析的图像帧数量,通过DJIVIdeoStreamDecoder.getInstance().frameIndex控制,比如Demo中对30取余,表示仅对序号为30的倍数的图像帧存储,如果每秒帧率为30,则每秒只取一帧图像。进而可通过调节分母的大小实现取帧频率的控制。

 

  将raw数据解析成YUV格式图像的源代码

@Override
    public void onYuvDataReceived(byte[] yuvFrame, int width, int height) {
        //In this demo, we test the YUV data by saving it into JPG files.
        if (DJIVideoStreamDecoder.getInstance().frameIndex % 30 == 0) {
            byte[] y = new byte[width * height];
            byte[] u = new byte[width * height / 4];
            byte[] v = new byte[width * height / 4];
            byte[] nu = new byte[width * height / 4]; //
            byte[] nv = new byte[width * height / 4];
            System.arraycopy(yuvFrame, 0, y, 0, y.length);
            for (int i = 0; i < u.length; i++) {
                v[i] = yuvFrame[y.length + 2 * i];
                u[i] = yuvFrame[y.length + 2 * i + 1];
            }
            int uvWidth = width / 2;
            int uvHeight = height / 2;
            for (int j = 0; j < uvWidth / 2; j++) {
                for (int i = 0; i < uvHeight / 2; i++) {
                    byte uSample1 = u[i * uvWidth + j];
                    byte uSample2 = u[i * uvWidth + j + uvWidth / 2];
                    byte vSample1 = v[(i + uvHeight / 2) * uvWidth + j];
                    byte vSample2 = v[(i + uvHeight / 2) * uvWidth + j + uvWidth / 2];
                    nu[2 * (i * uvWidth + j)] = uSample1;
                    nu[2 * (i * uvWidth + j) + 1] = uSample1;
                    nu[2 * (i * uvWidth + j) + uvWi  
		
大疆无人机 Android 开发总结——视频解码(一) https://www.cppentry.com/bencandy.php?fid=98&id=249987

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇重温Android和Fragment生命周期 下一篇Android进阶之路(1)-详解MVC