Как рисовать объекты в предпросмотре потока с камеры 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);