我正在GLSurfaceView
上通过Android中的手机摄像头渲染预览,并希望在可用时立即保存帧。由于将帧保存到SD卡所花费的时间比两次onFrameAvailable
之间的时间要多得多,所以在我从屏幕上读取像素后,我在另一个线程中执行此操作。
public void onDrawFrame(GL10 gl) {
//Process the frame, display it on the screen and other stuff
//Read pixels from the screen into my buffer
glReadPixels(0, 0, offscreenSize_.x, offscreenSize_.y, GL_RGBA, GL_UNSIGNED_BYTE,
intBuffer.clear());
// At the moment this has a counter and happens every 150ms
if(saveImage)
{
Thread thread = new Thread() {
@Override
public void run() {
// Convert to an array for Bitmap.createBitmap().
final int[] pixels = new int[intBuffer.capacity()];
intBuffer.rewind();
intBuffer.get(pixels);
try {
// Create/access a pictures subdirectory.
File directory = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"TangoFrames");
if (!directory.mkdirs() && !directory.isDirectory()) {
Log.d("WRITE ERR", "Couldn't create directory");
return;
}
// Get the current capture index to construct a unique filename.
SharedPreferences prefs = activity_.getPreferences(Context.MODE_PRIVATE);
int index = prefs.getInt("index", 0);
SharedPreferences.Editor prefsEditor = prefs.edit();
prefsEditor.putInt("index", index + 1);
prefsEditor.apply();
// Create the capture file.
File file = new File(directory, String.format("tango%05d.png", index));
FileOutputStream fileOutputStream = new FileOutputStream(file);
// Bitmap conveniently provides file output.
Bitmap bitmap = Bitmap.createBitmap(pixels, offscreenSize_.x, offscreenSize_.y, Bitmap.Config.ARGB_8888);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, fileOutputStream);
fileOutputStream.close();
numberOfFrames++;
}
catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
}
}
我的问题是,当线程开始落后时,有时会发生读取开始的帧:
final int[] pixels = new int[intBuffer.capacity()];
intBuffer.rewind();
intBuffer.get(pixels);
触发下一个回调并运行intBuffer.clear()
,因此其余回调被破坏。
如何以这样的方式同步线程:只有在缓冲区已满时才运行,并注意在线程运行时缓冲区没有被清除?
答案 0 :(得分:0)
听起来像是您遇到了经典的共享数据并发问题。
解决此类问题的最简单方法是停止共享数据。您可以向工作线程发送int
的支持IntBuffer
数组的副本:
...
glReadPixels(0, 0, offscreenSize_.x, offscreenSize_.y, GL_RGBA, GL_UNSIGNED_BYTE,
intBuffer.clear());
final int[] bufferContents = intBuffer.array();
final int[] pixels = Arrays.copyOf(bufferContents , bufferContents .length);
// reset buffer here
if (saveImage) {
...
// use pixels here
对IntBuffer
的读写操作的简单同步将"顺序化"程序的关键部分可能会导致抓取框架的保真度降低(如果您的工作线程仍在读取框架更改事件侦听器,则您无法立即调用glReadPixels
IntBuffer
内容)。它也会更容易出错,所以我不推荐它。
答案 1 :(得分:-1)
我最终只使用了Queue
IntBuffer
个Queue
个对象,并在退出应用之前等待onPause
为空。在调用#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <GL/glut.h>
void init(void)
{
glClearColor(0.8, 0.8, 0.8, 0.0); /* window color white */
glEnable(GL_DEPTH_TEST);
}
void drawScene(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(3.0,3.0,3.0, 0.0,0.0,0.0, 0.0,1.0,0.0);
//used some random parameters...
gluLookAt(0.0, 0.0, 0.0, 5.0, 5.0, 5.0, 0, 1, 0);
//axis
//x
glColor3f(1.0,0.0,0.0);
glLineWidth(1.0);
glBegin(GL_LINES);
glVertex3d(0.0,0.0,0.0);
glVertex3d(1.0,0.0,0.0);
glEnd();
//y
glColor3f(0.0,1.0,0.0);
glLineWidth(1.0);
glBegin(GL_LINES);
glVertex3d(0.0,0.0,0.0);
glVertex3d(1.0,0.0,0.0);
glEnd();
//z
glColor3f(0.0,0.0,1.0);
glLineWidth(1.0);
glBegin(GL_LINES);
glVertex3d(0.0,0.0,0.0);
glVertex3d(1.0,0.0,0.0);
glEnd();
glFlush();
}
void herschaal(){
glViewport(0,0,500,500);
glMatrixMode(GL_PROJECTION);
glOrtho(-10, 10, 10, -10, 10, -10);
glLoadIdentity();
}
int main( int argc, char * argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH );
glutInitWindowPosition(50, 100);
glutInitWindowSize(500, 500);
glutCreateWindow("mijn test");
glutReshapeFunc(herschaal);
init();
glutDisplayFunc(drawScene);
glutMainLoop();
return 0;
}
时基本上运行该函数。
因此,对于读取此内容的人来说,可能只是将数据添加到队列中并等待它在退出之前进行处理。