DJI Mobile SDKでドローンの映像ストリーミングからYUV画像取得

本記事では、DJI Mobile SDKでドローンの映像ストリーミングからYUV画像取得についてご紹介します。

# DJI UX SDK
[DJI UX SDK](https://developer.dji.com/mobile-sdk/documentation/introduction/ux_sdk_introduction.html)は、簡単な組み込み手順でドローンの映像ストリーミングとドローン操作のUIをアプリケーションに取り込みできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/fc1098d9-1382-ea81-69c1-bb03292293c7.png)

# 映像ストリーミングからYUV画像取得
[Android Video Stream Decoding Sample](https://developer.dji.com/mobile-sdk/documentation/sample-code/index.html)サンプルでは、映像ストリーミングをデコードしてYUV画像を出力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/e33f0a94-bd25-d5fd-d135-d7f6e1e0e42d.png)

#### 1. SurfaceTextureに映像を表示とデコーダーを生成

```java
    /**
     * Init a fake texture view to for the codec manager, so that the video raw data can be received
     * by the camera
     */
    private void initPreviewerTextureView() {
        videostreamPreviewTtView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                Log.d(TAG, "real onSurfaceTextureAvailable");
                videoViewWidth = width;
                videoViewHeight = height;
                Log.d(TAG, "real onSurfaceTextureAvailable: width " + videoViewWidth + " height " + videoViewHeight);
                if (mCodecManager == null) {
                    mCodecManager = new DJICodecManager(getApplicationContext(), surface, width, height);
                    //For M300RTK, you need to actively request an I frame.
                    mCodecManager.resetKeyFrame();
                }
            }

        });
    }
```

#### 2. デコーダーにYuvDataCallbackを登録

```java
                    mCodecManager.enabledYuvData(true);
                    mCodecManager.setYuvDataCallback(this);
```

#### 3. デコードしたYUV画像を受け取り
```java
    @Override
    public void onYuvDataReceived(MediaFormat format, final ByteBuffer yuvFrame, int dataSize, final int width, final int height) {
        //In this demo, we test the YUV data by saving it into JPG files.
        //DJILog.d(TAG, "onYuvDataReceived " + dataSize);
        if (count++ % 30 == 0 && yuvFrame != null) {
            final byte[] bytes = new byte[dataSize];
            yuvFrame.get(bytes);
            //DJILog.d(TAG, "onYuvDataReceived2 " + dataSize);
            AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    // two samples here, it may has other color format.
                    int colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT);
                    switch (colorFormat) {
                        case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
                            //NV12
                            if (Build.VERSION.SDK_INT <= 23) {
                                oldSaveYuvDataToJPEG(bytes, width, height);
                            } else {
                                newSaveYuvDataToJPEG(bytes, width, height);
                            }
                            break;
                        case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
                            //YUV420P
                            newSaveYuvDataToJPEG420P(bytes, width, height);
                            break;
                        default:
                            break;
                    }

                }
            });
        }
    }
```