pedroSG94 / RootEncoder

RootEncoder for Android (rtmp-rtsp-stream-client-java) is a stream encoder to push video/audio to media servers using protocols RTMP, RTSP, SRT and UDP with all code written in Java/Kotlin
Apache License 2.0
2.54k stars 772 forks source link

Ayuda para implementar camara2 #1596

Closed luigbren closed 5 days ago

luigbren commented 6 days ago

Buenas tardes, asumo que hablas español, estoy tratando de implementar el RTMP en react-native con un modulo nativo, hay algun lugar donde muestres como implementar de forma correcta el api camara2? algun tutorial de como importar la camara2 y un ejemplo de sus funciones por ejemplo de como preparar el video a 1280x720 y audio acc estereo 48kHz y su vista previa para luego iniciar el streaming, muchas gracias

pedroSG94 commented 6 days ago

Hola,

Puedes usar este ejemplo como base: https://github.com/pedroSG94/RootEncoder/blob/master/app/src/main/java/com/pedro/streamer/oldapi/OldApiActivity.kt Para pasarlo a camera2 puedes seguir lo que puse en este post: https://github.com/pedroSG94/RTSP-Server/issues/134#issuecomment-2367371753 En este caso se habla de RtspServerCamera2 pero la migracion es la misma. Solo tienes que usar GenericCamera2 en vez de RtspServerCamera2

Para la resolución y el samplerate/channels puedes poner los valores en los metodos prepareVideo y prepareAudio

luigbren commented 6 days ago

Te comparto el codigo que tengo actual para que por favor me indiques que estoy haciendo mal, la camara en mi dispositivo de prueba android (8.0) se ve muy oscura en comparación como se ve la camara en otras app, intento importar: import com.pedro.library.generic.GenericCamera2 pero me dice que no existe.

Este en mi gradle:

dependencies {
    ...
    implementation 'com.github.pedroSG94.rtmp-rtsp-stream-client-java:rtplibrary:2.1.9'
}
import android.util.Log;
import android.view.SurfaceHolder;

import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;

import com.pedro.rtplibrary.rtmp.RtmpCamera2;
import com.pedro.rtplibrary.view.OpenGlView;
import com.pedro.rtmp.utils.ConnectCheckerRtmp;

public class RNPublishManager extends SimpleViewManager<OpenGlView> implements ConnectCheckerRtmp {

    public static final String REACT_CLASS = "RPublish";
    private static final String TAG = "RNPublishManager";
    private RtmpCamera2 rtmpCamera;
    private String streamUrl;
    private boolean isStreaming = false;

    @Override
    public String getName() {
        return REACT_CLASS;
    }

    @Override
    protected OpenGlView createViewInstance(ThemedReactContext reactContext) {
        OpenGlView openGlView = new OpenGlView(reactContext);
        rtmpCamera = new RtmpCamera2(openGlView, this);

        openGlView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                rtmpCamera.startPreview();
                adjustCameraSettings();
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                if (rtmpCamera.isStreaming()) {
                    rtmpCamera.stopStream();
                }
                rtmpCamera.stopPreview();
            }
        });

        return openGlView;
    }

        private void adjustCameraSettings() {
        try {
            // Set video bitrate
            rtmpCamera.setVideoBitrateOnFly(1200 * 1024); // 1.2 Mbps
            rtmpCamera.enableAutoFocus();
        } catch (Exception e) {
            Log.e(TAG, "Error adjusting camera settings: " + e.getMessage(), e);
        }
    }

    @ReactProp(name = "toggleCamera")
    public void toggleCamera(OpenGlView view, boolean useFrontCamera) {
        rtmpCamera.switchCamera();
        adjustCameraSettings();
    }

    @ReactProp(name = "toggleAudio")
    public void toggleAudio(OpenGlView view, boolean isAudioMuted) {
        if (isAudioMuted) {
            rtmpCamera.disableAudio();
        } else {
            rtmpCamera.enableAudio();
        }
    }

    @ReactProp(name = "url")
    public void setUrl(OpenGlView view, String url) {
        this.streamUrl = url;
    }

    @ReactProp(name = "isStreaming")
    public void setIsStreaming(OpenGlView view, boolean streaming) {
        if (streaming != isStreaming) {
            isStreaming = streaming;
            UiThreadUtil.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (isStreaming) {
                        if (!rtmpCamera.isStreaming()) {
                            if (rtmpCamera.prepareAudio() && rtmpCamera.prepareVideo(1280,  720, 1000 * 1000)) {
                                rtmpCamera.startStream(streamUrl);
                            } else {
                                Log.e(TAG, "Error preparing stream");
                            }
                        }
                    } else {
                        if (rtmpCamera.isStreaming()) {
                            rtmpCamera.stopStream();
                        }
                    }
                }
            });
        }
    }

    // Implement ConnectCheckerRtmp methods
    @Override
    public void onConnectionSuccessRtmp() {
        Log.d(TAG, "RTMP connection success");
    }

    @Override
    public void onConnectionFailedRtmp(String reason) {
        Log.e(TAG, "RTMP connection failed: " + reason);
    }

    @Override
    public void onNewBitrateRtmp(long bitrate) {
        Log.d(TAG, "New RTMP bitrate: " + bitrate);
    }

    @Override
    public void onDisconnectRtmp() {
        Log.d(TAG, "RTMP disconnected");
    }

    @Override
    public void onAuthErrorRtmp() {
        Log.e(TAG, "RTMP authentication error");
    }

    @Override
    public void onAuthSuccessRtmp() {
        Log.d(TAG, "RTMP authentication success");
    }

    @Override
    public void onConnectionStartedRtmp(String rtmpUrl) {
        Log.d(TAG, "RTMP connection started to: " + rtmpUrl);
    }
}

Screenshot_1727902806

pedroSG94 commented 6 days ago

El código está bien, simplemente es que estás usando una versión muy antigua de la librería y por eso GenericCamera2 no existe pero eso es válido igualmente. El por qué se ve oscuro no estoy seguro pero puede ser por la configuración que usen otras apps. Prueba a cambiar la exposición (úsalo después de iniciar la preview): https://github.com/pedroSG94/RootEncoder/blob/master/library/src/main/java/com/pedro/library/base/Camera2Base.java#L825

luigbren commented 6 days ago

Edito el mensaje... ya logre implementar GenericCamera2 y se ve bien la camara, como deberia ser.. ahora te pregunto, mantuve practicamente la misma configuracion, pero la imagen en la vista previa se ve recortada y cuando inicia Stream se ve algo mas grande pero no agarra full screen como deveria ser.. te dejo un capture del emulador para que veas la diferencia

Edito: luego de colocar esta configuracion

    genericCamera2.startPreview();
                adjustCameraSettings();

 private void adjustCameraSettings() {
        try {
            // Ajustar la resolución y el bitrate del video
            genericCamera2.prepareVideo(1280, 720, 30, 2000 * 1024, 0, 90);
            // Configurar el audio para estéreo AAC con buena calidad
            genericCamera2.prepareAudio(MediaRecorder.AudioSource.MIC, 128 * 1024, 44100, true, false, false);
        } catch (Exception e) {
            Log.e(TAG, "Error adjusting camera settings: " + e.getMessage(), e);
        }
    }

Ahora la Camara se ve igual (como la foto) tanto con el Streaming iniciado o no.. antes de agregar la configuración se veía recortado en la vista previa, aunque quite los botones queda un marco negro tanto arriba como abajo

Screenshot_1727928034

pedroSG94 commented 5 days ago

Hola,

La diferencia de cuando inicias el stream, a antes, es por que no has seleccionado la resolución en el startPreview por lo que al iniciar el stream la resolución se actualiza. Prueba a seleccionar la misma resolución en startPreview que en prepareVideo.

Respecto a los bordes negros, eso es lo esperado. Al usar un aspect ratio distinto a el de la vista, la imagen se adapta para evitar deformarla, con el modo adjust lo que hace es dejar bordes negros (lo tienes en el XML), puedes usar el modo fill para que en vez de dejar bordes negros se ponga a pantalla completa y haga recortes para evitar deformarla o quitar esa linea si te da igual que se deforme y quieres que se ponga a pantalla completa. Esto no afecta al resultado del streaming, es solo la forma de mostrar la imagen en la preview.

luigbren commented 5 days ago

Hola,

La diferencia de cuando inicias el stream, a antes, es por que no has seleccionado la resolución en el startPreview por lo que al iniciar el stream la resolución se actualiza. Prueba a seleccionar la misma resolución en startPreview que en prepareVideo.

Respecto a los bordes negros, eso es lo esperado. Al usar un aspect ratio distinto a el de la vista, la imagen se adapta para evitar deformarla, con el modo adjust lo que hace es dejar bordes negros (lo tienes en el XML), puedes usar el modo fill para que en vez de dejar bordes negros se ponga a pantalla completa y haga recortes para evitar deformarla o quitar esa linea si te da igual que se deforme y quieres que se ponga a pantalla completa. Esto no afecta al resultado del streaming, es solo la forma de mostrar la imagen en la preview.

recuerda que estoy trabajando en react-native, xml es en Android, el View donde muestro el componente de la Camara lo tengo en Flex: 1, abarca todo el espacio, pero te cuento, eso es alguna configuracion en GenericCamera2, ya que cuando usaba RtmpCamera2 como te mostré en la primera foto, la camara tanto preview como en streaming abarcaba toda la pantalla solo que se veía demás de oscura, y en mi codigo yo nunca ajuste el aspect radio, luego cambie a GenericCamera2 y si se ve bien la camara pero con los bordes negros, luego que pruebas hice? :

inicie con esta configuracion:

            public void surfaceCreated(SurfaceHolder holder) {
                genericCamera2.startPreview();
                adjustCameraSettings();
                adaptPreview(openGlView);
            }

    private void adjustCameraSettings() {
        try {
            /////Ajustar la resolución y el bitrate del video
            genericCamera2.prepareVideo(1280, 720, 30, 2000 * 1024, 0, 90);
            /////Configurar el audio para estéreo AAC con buena calidad
            genericCamera2.prepareAudio(MediaRecorder.AudioSource.MIC, 128 * 1024, 44100, true, false, false);
        } catch (Exception e) {
            Log.e(TAG, "Error adjusting camera settings: " + e.getMessage(), e);
        }
    }

    private void adaptPreview(OpenGlView openGlView) {
        boolean isPortrait = openGlView.getContext().getResources().getConfiguration().orientation  == Configuration.ORIENTATION_PORTRAIT;
        int w = isPortrait ? 720 : 1280;
        int h = isPortrait ? 1280 : 720;

        // Ajustar el tamaño de la vista
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(w, h);
        params.gravity = android.view.Gravity.CENTER;
        openGlView.setLayoutParams(params);

        // Forzar una nueva medición y diseño
        openGlView.requestLayout();
    }

igual se veía el marco superior e inferior en negro, luego volví a compilar pero esta ves quite la función adaptPreview() y en adjustCameraSettings() coloque: genericCamera2.prepareVideo(); sin parámetros, por ningún lado establecí una resolución ni para Preview ni tampoco para streaming y la camara se veia muy recortada como la siguiente foto:

Screenshot_1727969880

tambien probe el mismo codigo con la libreria 'com.pedro.library.rtmp.RtmpCamera2' y es lo mismo, por eso te comente que parece que es alguna configuración en las nuevas librerias que falta agregarle a diferencia de la libreria vieja que usaba antes 'pedro.rtplibrary.rtmp.RtmpCamera2' que sin yo agregarle parámetros de resolución si abarcaba toda la pantalla y en las nuevas librerias no, como que no hace escalado de pantalla, si yo establezco una resolucion fija en mi View de react-native donde muestro la cámara ejep: <View style:{{width: 720, height: 1280}}> Mi camara <View /> y en la configuracion de StarPreview y preparevideo ajusto la misma resolucion alli si se ve completo y abarca toda la pantalla sin bordes negros, pero no puedo establecer una resolución fija en el View por los diferentes tamaños de dispositivos, estoy atascado sin poder avanzar

pedroSG94 commented 5 days ago

Hola,

No se exactamente lo que dices pero lo de la preview está funcionando como debería. Si quieres no usar bordes negros pon la configuración de la preview a fill en vez de adjust (adjust se usa por defecto). Puedes hacerlo por codigo en vez de usar un XML:

    OpenGlView openGlView = new OpenGlView(context);
    openGlView.setAspectRatioMode(AspectRatioMode.Fill);