...
- Select PNG - кнопка выбора файла PNG картинки из галереи устройства
- Use PNG overlay - применить наложение PNG картинки
- X Position, Y position - координаты верхнего левого угла PNG картинки в кадре
- Png width - ширина PNG картинки в кадре в пикселях
- Png height - высота PNG картинки в кадре в пикселях
Скриншот выбора разрешения публикации:
- Camera resolution - селектор выбора разрешения из поддерживаемых камерой
Работа с кодом примера
Для разбора кода возьмем следующие классы примера camera-manager, который доступен для скачивания в
...
сборке 1.1.0.
...
47:
- класс основной активности приложения CameraManagerActivity.java
- класс реализации интерфейса Camera1Capturer примера Zoom ZoomCameraCapturer.java
- класс реализации интерфейса Camera1Enumerator примера Zoom ZoomCameraEnumerator.java
- класс реализации интерфейса CameraSession примера Zoom ZoomCameraSession.java
- класс реализации интерфейса Camera1Capturer примера GPUImage GPUImageCameraCapturer.java
- класс реализации интерфейса Camera1Enumerator примера GPUImage GPUImageCameraEnumerator.java
- класс реализации интерфейса CameraSession примера GPUImage GPUImageCameraSession.java
- класс реализации интерфейса Camera1Capturer примера PngOverlay PngOverlayCameraCapturer.java
- класс реализации интерфейса Camera1Enumerator примера PngOverlay PngOverlayCameraEnumerator.java
- класс реализации интерфейса CameraSession примера PngOverlay PngOverlayCameraSession.java
- класс реализации интерфейса Camera1Capturer примера Resolution ResolutionCameraCapturer.java
- класс реализации интерфейса Camera1Enumerator примера Resolution ResolutionCameraEnumerator.java
- класс реализации интерфейса CameraSession примера Resolution ResolutionCameraSession.java
Обратите внимание, что классы реализации интерфейсов помещены в пакет org.webrtc, это необходимо для доступа к функциям захвата видео и управления камерой
1. Инициализация API.
Flashphoner.init() code
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.init(this); |
2. Создание сессии
Flashphoner.createSession() code
Методу передается объект SessionOptions со следующими параметрами
- URL WCS-сервера
- SurfaceViewRenderer localRenderer, который будет использоваться для отображения публикуемого потока (после применения
...
- изменений)
- SurfaceViewRenderer remoteRenderer, который будет использоваться для отображения воспроизводимого потока
Code Block | ||||
---|---|---|---|---|
| ||||
sessionOptions = new SessionOptions(mWcsUrlView.getText().toString()); sessionOptions.setLocalRenderer(localRender); sessionOptions.setRemoteRenderer(remoteRender); /** * Session for connection to WCS server is created with method createSession(). */ session = Flashphoner.createSession(sessionOptions); |
3. Подключение к серверу.
Session.connect() code
Code Block | ||||
---|---|---|---|---|
| ||||
session.connect(new Connection()); |
4. Получение от сервера события, подтверждающего успешное соединение.
session.onConnected() code
Code Block | ||||
---|---|---|---|---|
| ||||
@Override public void onConnected(final Connection connection) { runOnUiThread(new Runnable() { @Override public void run() { mStatusView.setText(connection.getStatus()); ... } }); }); |
5. Получение идентификатора тыловой камеры
Flashphoner.getMediaDevices().getVideoList(), Flashphoner.getCameraEnumerator().isBackFacing() code
Code Block | ||||
---|---|---|---|---|
| ||||
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; } } |
6. Настройка ограничений и создание потока
StreamOptions.setConstraints(), Session.createStream() code
Code Block | ||||
---|---|---|---|---|
| ||||
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); |
7. Запрос прав на публикацию потока
ActivityCompat.requestPermissions() code
Code Block | ||||
---|---|---|---|---|
| ||||
@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 | ||||
---|---|---|---|---|
| ||||
@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; } ... } } |
9. Воспроизведение потока после успешной публикации
Session.createStream(), Stream.play() code
Code Block | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
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(); } ... } }); |
11. Получение события, подтверждающего разъединение.
session.onDisconnection() code
Code Block | ||||
---|---|---|---|---|
| ||||
@Override public void onDisconnection(final Connection connection) { runOnUiThread(new Runnable() { @Override public void run() { mStatusView.setText(connection.getStatus()); mStatusView.setText(connection.getStatus()); onStopped(); } }); } |
12. Выбор примера
Code Block | ||||
---|---|---|---|---|
| ||||
mCameraCapturer.setOnItemChosenListener(new LabelledSpinner.OnItemChosenListener() { @Override public void onItemChosen(View labelledSpinner, AdapterView<?> adapterView, View itemView, int position, long id) { String captureType = getResources().getStringArray(R.array.camera_capturer)[position]; switch (captureType) { case "Flashlight": changeFlashlightCamera(); break; case "Zoom": changeZoomCamera(); break; case "GPUImage": changeGpuImageCamera(); break; case "PNG overlay": changePngOverlayCamera(); break; }case "Resolution": } @OverridechangeResolutionCamera(); public void onNothingChosen(View labelledSpinner, AdapterView<?> adapterView) { break; } }); } @Override public void onNothingChosen(View labelledSpinner, AdapterView<?> adapterView) { } }); |
13. Установка способа захвата камеры и необходимых опций захвата
Code Block | ||||
---|---|---|---|---|
| ||||
private void changeFlashlightCamera() { CameraCapturerFactory.getInstance().setCameraType(CameraCapturerFactory.CameraType.FLASHLIGHT_CAMERA); ... } private void changeZoomCamera() { CameraCapturerFactory.getInstance().setCustomCameraCapturerOptions(zoomCameraCapturerOptions); CameraCapturerFactory.getInstance().setCameraType(CameraCapturerFactory.CameraType.CUSTOM); ... } private void changePngOverlayCamera() { CameraCapturerFactory.getInstance().setCustomCameraCapturerOptions(pngOverlayCameraCapturerOptions); CameraCapturerFactory.getInstance().setCameraType(CameraCapturerFactory.CameraType.CUSTOM); ... } private void changeGpuImageCamera() { CameraCapturerFactory.getInstance().setCustomCameraCapturerOptions(gpuImageCameraCapturerOptions); CameraCapturerFactory.getInstance().setCameraType(CameraCapturerFactory.CameraType.CUSTOM); ... } |
14. Настройка опций объекта захвата камеры для примера Zoom
Code Block | ||||
---|---|---|---|---|
| ||||
private CustomCameraCapturerOptions zoomCameraCapturerOptions = new CustomCameraCapturerOptionsvoid changeResolutionCamera() { CameraCapturerFactory.getInstance().setCustomCameraCapturerOptions(resolutionCameraCapturerOptions); CameraCapturerFactory.getInstance().setCameraType(CameraCapturerFactory.CameraType.CUSTOM); ... } |
14. Настройка опций объекта захвата камеры для примера Zoom
Code Block | ||||
---|---|---|---|---|
| ||||
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 Block | ||||
---|---|---|---|---|
| ||||
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 Block | ||||
---|---|---|---|---|
| ||||
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"; } }; |
17.
...
Настройка опций объекта захвата камеры для примера Resolution
Code Block | ||||
---|---|---|---|---|
| ||||
private void turnOnFlashlight CustomCameraCapturerOptions resolutionCameraCapturerOptions = new CustomCameraCapturerOptions() { if (Flashphoner.turnOnFlashlight()) {private String cameraName; private mSwitchFlashlightButton.setText(getResources().getString(R.string.turn_off_flashlight))CameraVideoCapturer.CameraEventsHandler eventsHandler; private flashlight = trueboolean captureToTexture; }@Override } |
18. Отключение вспышки
Flashphoner.turnOffFlashlight() code
Code Block | ||||
---|---|---|---|---|
| ||||
private void turnOffFlashlightpublic Class<?>[] getCameraConstructorArgsTypes() { Flashphoner.turnOffFlashlight(); return new mSwitchFlashlightButton.setText(getResources().getString(R.string.turn_on_flashlight))Class<?>[]{String.class, CameraVideoCapturer.CameraEventsHandler.class, boolean.class}; flashlight = false; } } |
19. Управление масштабом при помощи ползунка
ZoomCameraCapturer.setZoom() code
Code Block | ||||
---|---|---|---|---|
| ||||
@Override mZoomSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListenerpublic Object[] getCameraConstructorArgs() { @Override return new Object[]{cameraName, eventsHandler, captureToTexture}; public} void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {@Override public void setCameraName(String cameraName) { CameraVideoCapturer cameraVideoCapturer this.cameraName = CameraCapturerFactory.getInstance().getCameraVideoCapturer()cameraName; } if@Override (cameraVideoCapturer instanceof ZoomCameraCapturer) { public void setEventsHandler(CameraVideoCapturer.CameraEventsHandler eventsHandler) { ((ZoomCameraCapturer) cameraVideoCapturer).setZoom(progress)this.eventsHandler = eventsHandler; } }@Override public void setCaptureToTexture(boolean captureToTexture) }{ ...this.captureToTexture = captureToTexture; }); |
20. Добавление картинки в поток с запросом прав
PngOverlayCameraCapturer.setPicture() code
Code Block | ||||
---|---|---|---|---|
| ||||
@Override protected void onActivityResult(int requestCode, intpublic resultCode, @Nullable Intent dataString getCameraClassName() { super.onActivityResult(requestCode, resultCode, data); return "org.webrtc.ResolutionCameraCapturer"; if} (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {@Override public Class<?>[] InputStream inputStream = null; getEnumeratorConstructorArgsTypes() { return try {new Class[0]; } inputStream = CameraManagerActivity.this.getBaseContext().getContentResolver().openInputStream(data.getData());@Override public } catch (FileNotFoundException eObject[] getEnumeratorConstructorArgs() { return new Object[0]; Log.e(TAG, "Can't select picture: " + e.getMessage()); } @Override } public String getEnumeratorClassName() { picture = BitmapFactory.decodeStream(inputStream)return "org.webrtc.ResolutionCameraEnumerator"; } }; |
18. Включение вспышки
Flashphoner.turnOnFlashlight() code
Code Block | ||||
---|---|---|---|---|
| ||||
CameraVideoCapturerprivate cameraVideoCapturer = CameraCapturerFactory.getInstance().getCameraVideoCapturer();void turnOnFlashlight() { if (cameraVideoCapturer instanceof PngOverlayCameraCapturer && picture != null(Flashphoner.turnOnFlashlight()) { mSwitchFlashlightButton.setText(getResources(PngOverlayCameraCapturer) cameraVideoCapturer).setPicture(picturegetString(R.string.turn_off_flashlight)); flashlight = true; } } |
21. Создание сессии камеры в классе ZoomCameraCapturer
CameraSession.create19. Отключение вспышки
Flashphoner.turnOffFlashlight() code
Code Block | ||||
---|---|---|---|---|
| ||||
private void turnOffFlashlight() @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.CreateSessionCallbackFlashphoner.turnOffFlashlight(); mSwitchFlashlightButton.setText(getResources().getString(R.string.turn_on_flashlight)); flashlight = false; } |
20. Управление масштабом при помощи ползунка
ZoomCameraCapturer.setZoom() code
Code Block | ||||
---|---|---|---|---|
| ||||
mZoomSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onDone(CameraSession cameraSessiononProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { ZoomCameraCapturer.this.cameraSessionCameraVideoCapturer cameraVideoCapturer = CameraCapturerFactory.getInstance().getCameraVideoCapturer(ZoomCameraSession) cameraSession; if createSessionCallback.onDone(cameraSession);(cameraVideoCapturer instanceof ZoomCameraCapturer) { } ((ZoomCameraCapturer) cameraVideoCapturer).setZoom(progress); @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); } |
22. Изменение масштаба в классе ZoomCameraCapturer
...
21. Добавление картинки в поток с запросом прав
PngOverlayCameraCapturer.setPicture() code
Code Block | ||||
---|---|---|---|---|
| ||||
public@Override boolean setZoom(int value protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { return cameraSessionsuper.setZoom(valueonActivityResult(requestCode, resultCode, data); } |
23. Выделение буфера для захвата камеры в классе ZoomCameraSession
Code Block | ||||
---|---|---|---|---|
| ||||
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode if (!captureToTexture== RESULT_OK) { InputStream int frameSize inputStream = captureFormat.frameSize()null; try { //The implementation is taken from the WebRTC library, so the purpose of the threeinputStream buffers is not entirely known= CameraManagerActivity.this.getBaseContext().getContentResolver().openInputStream(data.getData()); } catch for(int i = 0; i < 3; ++iFileNotFoundException e) { Log.e(TAG, "Can't select picture: ByteBuffer" buffer+ = ByteBuffere.allocateDirectgetMessage(frameSize)); } camera.addCallbackBuffer(buffer.array()); picture = BitmapFactory.decodeStream(inputStream); } CameraVideoCapturer cameraVideoCapturer } |
24. Реализация изменение масштаба в классе ZoomCameraSession
Code Block | ||||
---|---|---|---|---|
| ||||
public boolean setZoom(int value) {= CameraCapturerFactory.getInstance().getCameraVideoCapturer(); if (!isCameraActive()cameraVideoCapturer instanceof PngOverlayCameraCapturer && camera.getParameters().isZoomSupported()) picture != null) { return false((PngOverlayCameraCapturer) cameraVideoCapturer).setPicture(picture); } Camera.Parameters parameters } |
22. Установка выбранного разрешения публикации
Code Block | ||||
---|---|---|---|---|
| ||||
mCameraResolutionSpinner = (LabelledSpinner) findViewById(R.id.camera_resolution_spinner);
mCameraResolutionSpinner.setOnItemChosenListener(new LabelledSpinner.OnItemChosenListener() {
@Override
public void onItemChosen(View labelledSpinner, AdapterView<?> adapterView, View itemView, int position, long id) {
String resolution = adapterView.getSelectedItem().toString();
if (resolution.isEmpty()) {
return;
}
setResolutions(resolution);
}
@Override
public void onNothingChosen(View labelledSpinner, AdapterView<?> adapterView) {
}
});
...
private void setResolutions(String resolutionStr) {
String[] resolution = resolutionStr.split("x");
mWidth.setText(resolution[0]);
mHeight.setText(resolution[1]);
}
|
23. Создание сессии камеры в классе ZoomCameraCapturer
CameraSession.create() code
Code Block | ||||
---|---|---|---|---|
| ||||
@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 | ||||
---|---|---|---|---|
| ||||
public boolean setZoom(int value) {
return cameraSession.setZoom(value);
} |
25. Выделение буфера для захвата камеры в классе ZoomCameraSession
Code Block | ||||
---|---|---|---|---|
| ||||
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 Block | ||||
---|---|---|---|---|
| ||||
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 Block | ||||
---|---|---|---|---|
| ||||
public void setUsedFilter(boolean usedFilter) { isUsedFilter = usedFilter; } |
...
28. Применение фильтра к данным из буфера камеры
Code Block | ||||
---|---|---|---|---|
| ||||
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(); } } }); } |
...
29. Реализация фильтра
...
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| private void applyFilter(byte[] data, int width, int height) {
| |||||||
private void initFilter(int width, int height) { filter = new GPUImageMonochromeFilter(); filter.setColor(0,0,0); renderer = new GPUImageRenderer(filter); renderer.setRotation(Rotation.NORMAL, false, false); if (!isUsedFilter) {renderer.setScaleType(GPUImage.ScaleType.CENTER_INSIDE); buffer = new returnPixelBuffer(width, height); }buffer.setRenderer(renderer); } GPUImageMonochromeFilterprivate filter = new GPUImageMonochromeFiltervoid destroyFilter(); { filter.setColordestroy(0,0,0); GPUImageRenderer renderer = new GPUImageRenderer(filter buffer.destroy(); } private void renderer.setRotation(Rotation.NORMAL, false, false);applyFilter(byte[] data, int width, int height) { renderer.setScaleType(GPUImage.ScaleType.CENTER_INSIDE); if (!isUsedFilter) { PixelBuffer buffer = new PixelBuffer(width, height) return; buffer.setRenderer(renderer);} renderer.onPreviewFrame(data, width, height); Bitmap newBitmapRgb = buffer.getBitmap(); byte[] dataYuv = Utils.getNV21(width, height, newBitmapRgb); System.arraycopy(dataYuv, 0, data, 0, dataYuv.length); filter.destroy(); buffer.destroy( dataYuv.length); } |
...
30. Установка картинки для наложения в
...
классе PngOverlayCameraCapturer
Code Block | ||||
---|---|---|---|---|
| ||||
public void setPicture(Bitmap picture) { if (cameraSession != null) { cameraSession.setPicture(picture); } } |
2931. Наложение данных картинки на данные из буфера камеры
Code Block | ||||
---|---|---|---|---|
| ||||
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.cameraThreadHandlercamera.postaddCallbackBuffer((data); -> { } 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(); } } VideoFrame frame = new VideoFrame(frameBuffer, PngOverlayCameraSession.this.getFrameOrientation(), captureTimeNs }); } |
32. Реализация наложения картинки
Code Block | ||||
---|---|---|---|---|
| ||||
private void insertPicture(byte[] data, int width, int height) { PngOverlayCameraSession.this.events.onFrameCaptured(PngOverlayCameraSession.this, frame); if (picture == null || !isUsedPngOverlay) { frame.release()return; } } Bitmap scaledPicture = rescalingPicture(); } int [] pngArray = new int[scaledPicture.getHeight() * }scaledPicture.getWidth()]; } |
30. Реализация наложения картинки
Code Block | ||||
---|---|---|---|---|
| ||||
private void insertPicture(byte[] data, int width, int height) { scaledPicture.getPixels(pngArray, 0, scaledPicture.getWidth(), 0, 0, scaledPicture.getWidth(), scaledPicture.getHeight()); int if[] (picturergbData == new nullint || !isUsedPngOverlay) { [width * height]; GPUImageNativeLibrary.YUVtoARBG(data, width, height, returnrgbData); int } pictureW = scaledPicture.getWidth(); Bitmapint scaledPicturepictureH = rescalingPicturescaledPicture.getHeight(); for (int []c pngArray = new int[scaledPicture.getHeight() * scaledPicture.getWidth()]; 0; c < pngArray.length; c++) { scaledPicture.getPixels(pngArray, 0, scaledPicture.getWidth(), 0, 0, scaledPicture.getWidth(), scaledPicture.getHeight()); int pictureColumn = c / pictureW; int [] rgbDatapictureLine = newc int- [widthpictureColumn * height]pictureW; GPUImageNativeLibrary.YUVtoARBG(data, width, height, rgbData); int pictureWindex = scaledPicture.getWidth(); int pictureH = scaledPicture.getHeight()(pictureLine * width) + pictureColumn + startX * width + startY; for (int c = 0;if c(index <>= pngArraydata.length; c++) { int pictureColumn = c / pictureW; break; } int pictureLinergbData[index] = pngArray[c]; - pictureColumn * pictureW; } intbyte[] indexyuvData = Utils.getNV21(pictureLinewidth, *height, widthrgbData); + pictureColumn + startX * width + startY; System.arraycopy(yuvData, 0, data, 0, yuvData.length); } |
33. Получение списка поддерживаемых разрешений
ResolutionCameraCapturer.getSupportedResolutions code
Code Block | ||||
---|---|---|---|---|
| ||||
if (index >= data.lengthpublic List<Camera.Size> getSupportedResolutions() { Camera camera = Camera.open(Camera1Enumerator.getCameraIndex(cameraName)); List ret = breakCollections.EMPTY_LIST; if (camera != null) }{ rgbData[index]ret = pngArray[c]camera.getParameters().getSupportedVideoSizes(); } camera.release(); byte[] yuvData = Utils.getNV21(width, height, rgbData); } System.arraycopy(yuvData, 0, data, 0, yuvData.length)return ret; } |