Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

1. Инициализация API.

Flashphoner.init() code

Code Block
languagejava
themeRDark
Flashphoner.init(this);

...

Flashphoner.createSession() code

Методу передается объект SessionOptions со следующими параметрами

...

3. Подключение к серверу.

Session.connect() code

Code Block
languagejava
themeRDark
session.connect(new Connection());

4. Получение от сервера события, подтверждающего успешное соединение.

session.onConnected() code

Code Block
languagejava
themeRDark
@Override
public void onConnected(final Connection connection) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mStatusView.setText(connection.getStatus());
            ...
        }
    });
});

...

Flashphoner.getMediaDevices().getVideoList(), Flashphoner.getCameraEnumerator().isBackFacing() code

Code Block
languagejava
themeRDark
                                    int cameraId = 0;
                                    List<MediaDevice> videoList = Flashphoner.getMediaDevices().getVideoList();
                                    for (MediaDevice videoDevice : videoList) {
                                        String videoDeviceName = videoDevice.getLabel();
                                        if (Flashphoner.getCameraEnumerator().isBackFacing(videoDeviceName)) {
                                            cameraId = videoDevice.getId();
                                            break;
                                        }
                                    }

...

StreamOptions.setConstraints(), Session.createStream() code

Code Block
languagejava
themeRDark
                                    StreamOptions streamOptions = new StreamOptions(streamName);
                                    VideoConstraints videoConstraints = new VideoConstraints();
                                    videoConstraints.setVideoFps(25);
                                    videoConstraints.setCameraId(cameraId);
                                    Constraints constraints = new Constraints(true, true);
                                    constraints.setVideoConstraints(videoConstraints);
                                    streamOptions.setConstraints(constraints);

                                    /**
                                     * Stream is created with method Session.createStream().
                                     */
                                    publishStream = session.createStream(streamOptions);

...

ActivityCompat.requestPermissions() code

Code Block
languagejava
themeRDark
@Override
public void onConnected(final Connection connection) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            ...
            ActivityCompat.requestPermissions(StreamingMinActivity.this,
                  new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA},
                  PUBLISH_REQUEST_CODE);
            ...
        }
        ...
    });
});

8. Публикация потока после предоставления соответствующих прав

Stream.publish() code

Code Block
languagejava
themeRDark
@Override
 public void onRequestPermissionsResult(int requestCode,
                                        @NonNull String permissions[], @NonNull int[] grantResults) {
     switch (requestCode) {
         case PUBLISH_REQUEST_CODE: {
             if (grantResults.length == 0 ||
                     grantResults[0] != PackageManager.PERMISSION_GRANTED ||
                     grantResults[1] != PackageManager.PERMISSION_GRANTED) {
                 muteButton();
                 session.disconnect();
                 Log.i(TAG, "Permission has been denied by user");
             } else {
                 /**
                  * Method Stream.publish() is called to publish stream.
                  */
                 publishStream.publish();
                 Log.i(TAG, "Permission has been granted by user");
             }
             break;
         }
         ...
    }
}

...

Session.createStream(), Stream.play() code

Code Block
languagejava
themeRDark
publishStream.on(new StreamStatusEvent() {
    @Override
    public void onStreamStatus(final Stream stream, final StreamStatus streamStatus) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (StreamStatus.PUBLISHING.equals(streamStatus)) {
                    ...
                    /**
                     * The options for the stream to play are set.
                     * The stream name is passed when StreamOptions object is created.
                     */
                    StreamOptions streamOptions = new StreamOptions(streamName);
                    streamOptions.setConstraints(new Constraints(true, true));
 
                    /**
                     * Stream is created with method Session.createStream().
                     */
                    playStream = session.createStream(streamOptions);
                    ...
                    /**
                     * Method Stream.play() is called to start playback of the stream.
                     */
                    playStream.play();
                } else {
                    Log.e(TAG, "Can not publish stream " + stream.getName() + " " + streamStatus);
                    onStopped();
                }
                mStatusView.setText(streamStatus.toString());
            }
        });
    }
});

10. Закрытие соединения.

Session.disconnect() code

Code Block
languagejava
themeRDark
mStartButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        muteButton();
        if (mStartButton.getTag() == null || Integer.valueOf(R.string.action_start).equals(mStartButton.getTag())) {
            ...
        } else {
            /**
             * Connection to WCS server is closed with method Session.disconnect().
             */
            session.disconnect();
        }
        ...
    }
});

...

session.onDisconnection() code

Code Block
languagejava
themeRDark
@Override
public void onDisconnection(final Connection connection) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mStatusView.setText(connection.getStatus());
            mStatusView.setText(connection.getStatus());
            onStopped();
        }
    });
}

...

14. Настройка опций объекта захвата камеры для примера Zoom

code

Code Block
languagejava
themeRDark
    private CustomCameraCapturerOptions zoomCameraCapturerOptions = new CustomCameraCapturerOptions() {

            private String cameraName;
            private CameraVideoCapturer.CameraEventsHandler eventsHandler;
            private boolean captureToTexture;

            @Override
            public Class<?>[] getCameraConstructorArgsTypes() {
                return new Class<?>[]{String.class, CameraVideoCapturer.CameraEventsHandler.class, boolean.class};
            }

            @Override
            public Object[] getCameraConstructorArgs() {
                return new Object[]{cameraName, eventsHandler, captureToTexture};
            }

            @Override
            public void setCameraName(String cameraName) {
                this.cameraName = cameraName;
            }

            @Override
            public void setEventsHandler(CameraVideoCapturer.CameraEventsHandler eventsHandler) {
                this.eventsHandler = eventsHandler;
            }

            @Override
            public void setCaptureToTexture(boolean captureToTexture) {
                this.captureToTexture = captureToTexture;
            }

            @Override
            public String getCameraClassName() {
                return "org.webrtc.ZoomCameraCapturer";
            }

            @Override
            public Class<?>[] getEnumeratorConstructorArgsTypes() {
                return new Class[0];
            }

            @Override
            public Object[] getEnumeratorConstructorArgs() {
                return new Object[0];
            }

            @Override
            public String getEnumeratorClassName() {
                return "org.webrtc.ZoomCameraEnumerator";
            }
    };

15. Настройка опций объекта захвата камеры для примера PngOverlay

code

Code Block
languagejava
themeRDark
    private CustomCameraCapturerOptions pngOverlayCameraCapturerOptions = new CustomCameraCapturerOptions() {

        private String cameraName;
        private CameraVideoCapturer.CameraEventsHandler eventsHandler;
        private boolean captureToTexture;

        @Override
        public Class<?>[] getCameraConstructorArgsTypes() {
            return new Class<?>[]{String.class, CameraVideoCapturer.CameraEventsHandler.class, boolean.class};
        }

        @Override
        public Object[] getCameraConstructorArgs() {
            return new Object[]{cameraName, eventsHandler, captureToTexture};
        }

        @Override
        public void setCameraName(String cameraName) {
            this.cameraName = cameraName;
        }

        @Override
        public void setEventsHandler(CameraVideoCapturer.CameraEventsHandler eventsHandler) {
            this.eventsHandler = eventsHandler;
        }

        @Override
        public void setCaptureToTexture(boolean captureToTexture) {
            this.captureToTexture = captureToTexture;
        }

        @Override
        public String getCameraClassName() {
            return "org.webrtc.PngOverlayCameraCapturer";
        }

        @Override
        public Class<?>[] getEnumeratorConstructorArgsTypes() {
            return new Class[0];
        }

        @Override
        public Object[] getEnumeratorConstructorArgs() {
            return new Object[0];
        }

        @Override
        public String getEnumeratorClassName() {
            return "org.webrtc.PngOverlayCameraEnumerator";
        }
    };

16. Настройка опций объекта захвата камеры для примера GPUImage

code

Code Block
languagejava
themeRDark
    private CustomCameraCapturerOptions gpuImageCameraCapturerOptions = new CustomCameraCapturerOptions() {

        private String cameraName;
        private CameraVideoCapturer.CameraEventsHandler eventsHandler;
        private boolean captureToTexture;

        @Override
        public Class<?>[] getCameraConstructorArgsTypes() {
            return new Class<?>[]{String.class, CameraVideoCapturer.CameraEventsHandler.class, boolean.class};
        }

        @Override
        public Object[] getCameraConstructorArgs() {
            return new Object[]{cameraName, eventsHandler, captureToTexture};
        }

        @Override
        public void setCameraName(String cameraName) {
            this.cameraName = cameraName;
        }

        @Override
        public void setEventsHandler(CameraVideoCapturer.CameraEventsHandler eventsHandler) {
            this.eventsHandler = eventsHandler;
        }

        @Override
        public void setCaptureToTexture(boolean captureToTexture) {
            this.captureToTexture = captureToTexture;
        }

        @Override
        public String getCameraClassName() {
            return "org.webrtc.GPUImageCameraCapturer";
        }

        @Override
        public Class<?>[] getEnumeratorConstructorArgsTypes() {
            return new Class[0];
        }

        @Override
        public Object[] getEnumeratorConstructorArgs() {
            return new Object[0];
        }

        @Override
        public String getEnumeratorClassName() {
            return "org.webrtc.GPUImageCameraEnumerator";
        }
    };

...

Flashphoner.turnOnFlashlight() code

Code Block
languagejava
themeRDark
    private void turnOnFlashlight() {
        if (Flashphoner.turnOnFlashlight()) {
            mSwitchFlashlightButton.setText(getResources().getString(R.string.turn_off_flashlight));
            flashlight = true;
        }
    }

...

Flashphoner.turnOffFlashlight() code

Code Block
languagejava
themeRDark
    private void turnOffFlashlight() {
        Flashphoner.turnOffFlashlight();
        mSwitchFlashlightButton.setText(getResources().getString(R.string.turn_on_flashlight));
        flashlight = false;
    }

...

ZoomCameraCapturer.setZoom() code

Code Block
languagejava
themeRDark
        mZoomSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                CameraVideoCapturer cameraVideoCapturer = CameraCapturerFactory.getInstance().getCameraVideoCapturer();
                if (cameraVideoCapturer instanceof ZoomCameraCapturer) {
                    ((ZoomCameraCapturer) cameraVideoCapturer).setZoom(progress);
                }
            }
            ...
        });

...

PngOverlayCameraCapturer.setPicture() code

Code Block
languagejava
themeRDark
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
            InputStream inputStream = null;
            try {
                inputStream = CameraManagerActivity.this.getBaseContext().getContentResolver().openInputStream(data.getData());
            } catch (FileNotFoundException e) {
                Log.e(TAG, "Can't select picture: " + e.getMessage());
            }
            picture = BitmapFactory.decodeStream(inputStream);
        }

        CameraVideoCapturer cameraVideoCapturer = CameraCapturerFactory.getInstance().getCameraVideoCapturer();
        if (cameraVideoCapturer instanceof PngOverlayCameraCapturer && picture != null) {
            ((PngOverlayCameraCapturer) cameraVideoCapturer).setPicture(picture);
        }
    }

...

23. Создание сессии камеры в классе ZoomCameraCapturer

CameraSession.create() code

Code Block
languagejava
themeRDark
    @Override
    protected void createCameraSession(CameraSession.CreateSessionCallback createSessionCallback, CameraSession.Events events, Context applicationContext, SurfaceTextureHelper surfaceTextureHelper, String cameraName, int width, int height, int framerate) {
        CameraSession.CreateSessionCallback myCallback = new CameraSession.CreateSessionCallback() {
            @Override
            public void onDone(CameraSession cameraSession) {
                ZoomCameraCapturer.this.cameraSession = (ZoomCameraSession) cameraSession;
                createSessionCallback.onDone(cameraSession);
            }

            @Override
            public void onFailure(CameraSession.FailureType failureType, String s) {
                createSessionCallback.onFailure(failureType, s);
            }
        };

        ZoomCameraSession.create(myCallback, events, captureToTexture, applicationContext, surfaceTextureHelper, Camera1Enumerator.getCameraIndex(cameraName), width, height, framerate);
    }

24. Изменение масштаба в классе ZoomCameraCapturer

CameraSession.setZoom() code

Code Block
languagejava
themeRDark
    public boolean setZoom(int value) {
        return cameraSession.setZoom(value);
    }

25. Выделение буфера для захвата камеры в классе ZoomCameraSession

code

Code Block
languagejava
themeRDark
            if (!captureToTexture) {
                int frameSize = captureFormat.frameSize();

                //The implementation is taken from the WebRTC library, so the purpose of the three buffers is not entirely known
                for(int i = 0; i < 3; ++i) {
                    ByteBuffer buffer = ByteBuffer.allocateDirect(frameSize);
                    camera.addCallbackBuffer(buffer.array());
                }
            }

26. Реализация изменение масштаба в классе ZoomCameraSession

code

Code Block
languagejava
themeRDark
    public boolean setZoom(int value) {
        if (!isCameraActive() && camera.getParameters().isZoomSupported()) {
            return false;
        }

        Camera.Parameters parameters = camera.getParameters();
        parameters.setZoom(value);
        camera.setParameters(parameters);
        return true;
    }

27. Установка использования фильтра в классе GPUImageCameraSession

code

Code Block
languagejava
themeRDark
    public void setUsedFilter(boolean usedFilter) {
        isUsedFilter = usedFilter;
    }

28. Применение фильтра к данным из буфера камеры

code

Code Block
languagejava
themeRDark
    private void listenForBytebufferFrames() {
        this.camera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
            public void onPreviewFrame(byte[] data, Camera callbackCamera) {
                GPUImageCameraSession.this.checkIsOnCameraThread();
                if (callbackCamera != GPUImageCameraSession.this.camera) {
                    Logging.e(TAG, CALLBACK_FROM_A_DIFFERENT_CAMERA_THIS_SHOULD_NEVER_HAPPEN);
                } else if (GPUImageCameraSession.this.state != GPUImageCameraSession.SessionState.RUNNING) {
                    Logging.d(TAG, BYTEBUFFER_FRAME_CAPTURED_BUT_CAMERA_IS_NO_LONGER_RUNNING);
                } else {
                    ...
                    applyFilter(data, GPUImageCameraSession.this.captureFormat.width, GPUImageCameraSession.this.captureFormat.height);

                    VideoFrame.Buffer frameBuffer = new NV21Buffer(data, GPUImageCameraSession.this.captureFormat.width, GPUImageCameraSession.this.captureFormat.height, () -> {
                        GPUImageCameraSession.this.cameraThreadHandler.post(() -> {
                            if (GPUImageCameraSession.this.state == GPUImageCameraSession.SessionState.RUNNING) {
                                GPUImageCameraSession.this.camera.addCallbackBuffer(data);
                            }

                        });
                    });
                    VideoFrame frame = new VideoFrame(frameBuffer, GPUImageCameraSession.this.getFrameOrientation(), captureTimeNs);
                    GPUImageCameraSession.this.events.onFrameCaptured(GPUImageCameraSession.this, frame);
                    frame.release();
                }
            }
        });
    }

...

30. Установка картинки для наложения в классе PngOverlayCameraCapturer

code

Code Block
languagejava
themeRDark
    public void setPicture(Bitmap picture) {
        if (cameraSession != null) {
            cameraSession.setPicture(picture);
        }
    }

31. Наложение данных картинки на данные из буфера камеры

code

Code Block
languagejava
themeRDark
    private void listenForBytebufferFrames() {
        this.camera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
            public void onPreviewFrame(byte[] data, Camera callbackCamera) {
                PngOverlayCameraSession.this.checkIsOnCameraThread();
                if (callbackCamera != PngOverlayCameraSession.this.camera) {
                    Logging.e(TAG, CALLBACK_FROM_A_DIFFERENT_CAMERA_THIS_SHOULD_NEVER_HAPPEN);
                } else if (PngOverlayCameraSession.this.state != PngOverlayCameraSession.SessionState.RUNNING) {
                    Logging.d(TAG, BYTEBUFFER_FRAME_CAPTURED_BUT_CAMERA_IS_NO_LONGER_RUNNING);
                } else {
                    ...
                    insertPicture(data, PngOverlayCameraSession.this.captureFormat.width, PngOverlayCameraSession.this.captureFormat.height);

                    VideoFrame.Buffer frameBuffer = new NV21Buffer(data, PngOverlayCameraSession.this.captureFormat.width, PngOverlayCameraSession.this.captureFormat.height, () -> {
                        PngOverlayCameraSession.this.cameraThreadHandler.post(() -> {
                            if (PngOverlayCameraSession.this.state == PngOverlayCameraSession.SessionState.RUNNING) {
                                PngOverlayCameraSession.this.camera.addCallbackBuffer(data);
                            }

                        });
                    });
                    VideoFrame frame = new VideoFrame(frameBuffer, PngOverlayCameraSession.this.getFrameOrientation(), captureTimeNs);
                    PngOverlayCameraSession.this.events.onFrameCaptured(PngOverlayCameraSession.this, frame);
                    frame.release();
                }
            }
        });
    }

32. Реализация наложения картинки

code

Code Block
languagejava
themeRDark
    private void insertPicture(byte[] data, int width, int height) {
        if (picture == null || !isUsedPngOverlay) {
            return;
        }

        Bitmap scaledPicture = rescalingPicture();

        int [] pngArray = new int[scaledPicture.getHeight() * scaledPicture.getWidth()];
        scaledPicture.getPixels(pngArray, 0, scaledPicture.getWidth(), 0, 0, scaledPicture.getWidth(), scaledPicture.getHeight());

        int [] rgbData = new int [width * height];
        GPUImageNativeLibrary.YUVtoARBG(data, width, height, rgbData);

        int pictureW = scaledPicture.getWidth();
        int pictureH = scaledPicture.getHeight();

        for (int c = 0; c < pngArray.length; c++) {
            int pictureColumn = c / pictureW;
            int pictureLine = c - pictureColumn * pictureW;
            int index = (pictureLine * width) + pictureColumn + startX * width + startY;

            if (index >= data.length) {
                break;
            }
            rgbData[index] = pngArray[c];
        }

        byte[] yuvData = Utils.getNV21(width, height, rgbData);
        System.arraycopy(yuvData, 0, data, 0, yuvData.length);
    }

...