Как рисовать объекты в предпросмотре потока с камеры TextureView и записывать поток с объектами?

Мне нужна помощь с приложением, над которым я работаю. Приложение должно иметь собственный интерфейс камеры для записи видео со звуком и добавлять некоторые объекты в реальном времени на холст TextureView. Старый API-интерфейс камеры устарел, поэтому я должен использовать Camera2 API для визуализации живого предварительного просмотра в TextureView. Моя цель - нарисовать некоторые объекты поверх холста TextureView, это может быть какой-нибудь текст /jpg/gif, пока поток с камеры рендерится в фоновом режиме и сможет записывать видео с содержимым моего наложенного холста и с камеры.

Проблема в том, что я могу рисовать пользовательский контент в прозрачном режиме наложения, но это только для просмотра пользователем. Я пытался исследовать это в течение нескольких дней, но я не могу найти правильный подход для решения своей задачи.

Я попробовал следующий код после вызова метода openCamera(), но затем я просто вижу нарисованный прямоугольник, но не предварительный просмотр камеры:

Canvas canvas = mTextureView.lockCanvas();
Paint myPaint = new Paint();
myPaint.setColor(Color.WHITE);
myPaint.setStrokeWidth(10);
canvas.drawRect(100, 100, 300, 300, myPaint);
mTextureView.unlockCanvasAndPost(canvas);

Я также попробовал пользовательский класс TextureView и переопределил метод vonDrawForeground(Canvas canvas), но он не работает.

Метод onDraw() в классе TextureView является окончательным, и, следовательно, я не могу ничего сделать на этом этапе, за исключением простой потоковой передачи с камеры.

/**
 * Subclasses of TextureView cannot do their own rendering
 * with the {@link Canvas} object.
 *
 * @param canvas The Canvas to which the View is rendered.
 */
@Override
protected final void onDraw(Canvas canvas) {
}

Короче говоря, я хочу, чтобы пользователь мог записывать видео через приложение камеры с некоторыми опорами здесь и там.

2 ответа

Вероятно, наиболее эффективный вариант заключается в том, чтобы направить канал камеры прямо в графический процессор, нарисовать поверх него и оттуда визуализировать на дисплей и видеокодер напрямую.

Это то, что делают многие приложения видеочата, например, для любых эффектов.

Вы можете использовать SurfaceTexture для подключения camera2 к EGL, а затем вы можете визуализировать предварительный просмотр на квад, а затем ваши дополнения сверху.

Затем вы можете выполнить рендеринг в экранный буфер (например, GLSurfaceView) и в отдельный EGLImage из поверхности MediaRecorder/MediaCodec.

Там задействовано много кода и много инструментов для настройки EGL, поэтому трудно указать на простые примеры.

Модификация видео в реальном времени - это высокая загрузка процессора и, следовательно, высокая нагрузка на батарею - я уверен, что вы это знаете, но стоит сказать, что если вы можете добавить свои модификации на стороне сервера, возможно, отправив поток вместе с набором временных меток текстовых оверлеев на сервер, вы должны иметь больше лошадиных сил на стороне сервера.

Следующий код добавит текст и изображение к неподвижному изображению или кадру, снятому Camera2 на Android. Я не использовал его с видео, поэтому не могу комментировать скорость и целесообразно ли делать это с видеопотоком в реальном времени - он не был оптимизирован для этого, но должен стать отправной точкой для вас:

        //Copy the image to a BitBuffer
        ByteBuffer buffer = mCameraImage.getPlanes()[0].getBuffer();
        byte[] bytes = new byte[buffer.remaining()];
        Log.d(TAG,"ImageSaver bytes.length: " + bytes.length);
        buffer.get(bytes);
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inMutable = true;
        Bitmap cameraBitmap = BitmapFactory.decodeByteArray(bytes,0,bytes.length, opt);
        if (cameraBitmap == null) {
            Log.d(TAG,"ImageSaver cameraBitmap is null");
            return;
        } else {
            camImgBitmap = cameraBitmap;
        }

        //Modify captured picture by drawing on canvas
        Canvas camImgCanvas = new Canvas(camImgBitmap);

        //Draw an image in the middle
        Drawable d = ContextCompat.getDrawable(this, R.drawable.image_to_add);
        int bitMapWidthCenter = camImgBitmap.getWidth()/2;
        int bitMapheightCenter = camImgBitmap.getHeight()/2;
        int imageToDrawSize = camImgBitmap.getWidth()/10;
        int rTop = bitMapheightCenter - sightsSize;
        int rLeft = bitMapWidthCenter - sightsSize;
        int rRight = bitMapWidthCenter + sightsSize;
        int rBot = bitMapheightCenter + sightsSize;
        d.setBounds(rLeft, rTop, rRight, rBot);
        d.draw(camImgCanvas);

        //Now Draw in some text
        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        int textSize = camImgBitmap.getHeight()/20;
        int textPadding = 40;
        paint.setTextSize(textSize);
        camImgCanvas.drawText("Name: " + text1, textPadding, (camImgBitmap.getHeight() - (textSize * 2) ) - textPadding, paint);
        camImgCanvas.drawText("Time: " + text2 + " degrees", textPadding, (camImgBitmap.getHeight() - textSize) - textPadding, paint);
Другие вопросы по тегам