我正在寻找帮助解决我使用Grafika的CameraCaptureActivity代码所面临的问题.我想构建一个可以记录相机并显示预览的应用程序,所以这个样本和代码看起来就像我想要的那样,到目前为止它很棒,这个问题appart.
我的问题是,当相机预览尺寸与GLSurfaceView我用于显示预览的确切尺寸不匹配时,它会显示拉伸预览.
以下是它的外观:
你可以看到它是水平拉伸的,因为音符表是一个完美的正方形.
用于在三星Galaxy S4这种精确为例,相机预览大小1280x720(从使用预览可用大小提取Camera2API),并且GLSurfaceView是1920x1080覆盖整个屏幕.
什么时候出现?
当SurfaceView与Camera输出相比进行放大时,即使我始终确保比率保持正确(1920x1080= 1.5*1280x720),也会出现此问题.
你用的是什么代码?
我使用Grafika的代码,包括:
有些日志?
这是SurfaceFlinger转储的样子:
Hardware Composer state (version 01030000):
mDebugForceFakeVSync=0
Display[0] configurations (* current):
* 0: 1080x1920, xdpi=442.450989, ydpi=439.351013, secure=1 refresh=16666667
numHwLayers=3, flags=00000000
type | handle | hint | flag | tr | blnd | format | source crop(l,t,r,b) | frame | dirtyRect | name
------------+----------+----------+----------+----+-------+----------+-----------------------------------+---------------------------+-------------------
HWC | b3b12ba0 …Run Code Online (Sandbox Code Playgroud) 我正在学习Grafika的"连续捕获"活动,它是关于使用MediaCodec录制视频.
活动源代码位于https://github.com/google/grafika/blob/master/src/com/android/grafika/ContinuousCaptureActivity.java
该程序使用SurfaceTexture obj从相机接收数据并使用此SurfaceTexture obj创建2个EGLSurface obj,一个EGLSurface obj将数据提供给MediaCodec,另一个将数据提供给SurfaceView以进行相机预览.MediaCodec将数据编码为h264数据,MediaMuxer obj将h264数据写入mp4文件.
但是有一个问题,相机支持的预览尺寸是空间(宽度>高度),如1920*1080,1440*1080,720*480等.通常,我们在录制视频时以纵向方式拍摄手机,因此我们应该使用API:Camera.setDisplayOrientation(90)将图片旋转为肖像,然后录制肖像视频.
但我想用手中的手机肖像录制风景视频,我必须从相机中裁剪每一帧.我的方法是切断每帧图片的底部和顶部并保留图片的中间部分,然后左图片将是一个景观图片.
但我不熟悉opengl,我不知道如何裁剪SurfaceTexture数据.任何擅长opengl的人都能给我一些帮助吗?
我正在使用Google的开源示例:Grafika.我正在使用它的ContinuousCaptureActivity.java此活动中演示了CircularBuffer的实现,但生成的视频文件中没有包含音频.
我想在此活动中添加音频录制功能,并将录制的音频以相同的CircularBuffered时尚添加到视频中.
为实现这一目标,我探索了MediaCodec库,该库已在4.3+版本中推出.我还使用MediaMuxer捕获视频和音频流,并将它们混合到一个视频中.
但是,我不确定如何在ContinuousCaptureActivity.java课堂上实现录音功能.任何帮助都非常感谢.
最近我正在通过grafika(感谢fadden)学习安卓摄像头和OpenglES.它在大多数设备上都很好,但我遇到了一些设备中的错误,特别是MTK设备(如MT6580,MT8163 ......).
例如,当"CameraCaptureActivity"在MTK中运行时.我收到此错误:
java.lang.NullPointerException:尝试在空对象引用上调用虚方法'void android.hardware.Camera.setPreviewTexture(android.graphics.SurfaceTexture)'
所以我将"handleSetSurfaceTexture"函数更改为:
private void handleSetSurfaceTexture(SurfaceTexture st) {
if(mCamera == null)
{
Log.e(TAG, "mCamera return null");
return;
}
st.setOnFrameAvailableListener(this);
try {
mCamera.setPreviewTexture(st);
} catch (Exception ioe) {
Log.e(TAG, "camera failed handleSetSurfaceTexture");
throw new RuntimeException(ioe);
}
mCamera.startPreview();
}
Run Code Online (Sandbox Code Playgroud)
然后错误更改为:
java.lang.RuntimeException:java.io.IOException:setPreviewTexture在jp.co.cyberagent.android.gpuimage.grafika.CameraCaptureActivity.handleSetSurfaceTexture(CameraCaptureActivity.java:1150)失败
我读了许多其他相机应用程序源代码,我想可能在MTK设备中有Camera和SurfaceRender的同步问题.所以我改变了这样的代码:
private void waitUntilSetup()
{
long l = System.currentTimeMillis();
while ((getMaxTextureSize() == 0) && (System.currentTimeMillis() - l < 3000L))
{
SystemClock.sleep(100L);
}
Log.e(TAG,"getMaxTextureSize() = " + getMaxTextureSize());
}
private int getMaxTextureSize() {
int[] maxTextureSize = new int[1];
GLES20.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, …Run Code Online (Sandbox Code Playgroud) 我使用ContinuousCaptureActivity.java实现视频录制.它的工作完美.
现在我想在此视频中添加音频.
我知道使用MediaMuxer可以在视频中添加音频.
但问题是我不知道如何使用MediaMuxer.
此外,如果您有任何其他解决方案,MediaMuxer然后与我分享任何链接或文档.
我也有演示AudioVideoRecordingSample.但我不明白如何将其与我的代码合并.
如果有人知道,请向我解释.
提前致谢.
最近我在 Android 5.0.2 (API 21) 上遇到了一个奇怪的问题。我的应用程序使用 SurfaceTexture 来显示视频。播放机制主要基于google/grafika 的 CameraCaptureAvtivity,但视频源是解码 .mp4 电影文件而不是相机。该应用程序运行良好,直到我在带有 Android 5.0.2 的 Galaxy S6 上运行它(在那之前我成功使用了 4.4.2 和 4.4.4 的设备)。问题是,每次我尝试从 SurfaceTexture 接收时间戳时getTimestamp(),该方法都会返回 0,但播放没问题。在时间戳正确之前我提到的其他设备上。
有人可以告诉我这是否可能是Android错误?有什么办法可以解决吗?
我正在努力使用MediaExtractor进行精确搜索seekTo().虽然我可以毫无问题地寻求同步帧,但我想寻求具体的时间.这个问题让我想到了如何做到这一点,但我不确定它们是否有效.基本上,我必须寻找最接近的前一个同步帧,然后寻求advance()提取器,直到达到目标时间.该过程中的每个帧将被馈送到解码器,即第一个I帧和其余的P帧.这是相关的代码段(基于google/grafika的MoviePlayer):
extractor.seekTo((long) seekTarget[threadNr], MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
...
while (extractor.getSampleTime() < (long) seekTarget[threadNr]) {
Log.d(TAG, "Thread " + threadNr + " advanced to timestamp " + extractor.getSampleTime());
int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC);
if (inputBufIndex >= 0) {
ByteBuffer inBufer = decoderInputBuffers[inputBufIndex];
int chunkSize = extractor.readSampleData(inBufer, 0);
if (chunkSize < 0) {
// End of stream -- send empty frame with EOS flag set.
decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L,
MediaCodec.BUFFER_FLAG_END_OF_STREAM);
inputDone = true;
if (VERBOSE) Log.d(TAG, "sent input …Run Code Online (Sandbox Code Playgroud) 我设法用opengl es播放视频,我使用了grafika的ContinuousCaptureActivity方式,我的数据源是MediaPlayer而不是Camera,这没什么区别.MediaPlayer连续生成视频帧,我在onFrameAvailable回调中绘制每个帧到屏幕.代码如下,效果很好:
mVideoTexture.updateTexImage();
mVideoTexture.getTransformMatrix(mTmpMatrix);
mDisplaySurface.makeCurrent();
int viewWidth = getWidth();
int viewHeight = getHeight();
GLES20.glViewport(0, 0, viewWidth, viewHeight);
mFullFrameBlit.drawFrame(mTextureId, mTmpMatrix);
mDisplaySurface.swapBuffers();
Run Code Online (Sandbox Code Playgroud)
现在我想旋转270度的视频帧,所以我改变了代码:
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
mVideoTexture.updateTexImage();
mVideoTexture.getTransformMatrix(mTmpMatrix);
mDisplaySurface.makeCurrent();
int viewWidth = getWidth();
int viewHeight = getHeight();
GLES20.glViewport(0, 0, viewWidth, viewHeight);
Matrix.rotateM(mTmpMatrix, 0, 270, 1f, 0, 0);
mFullFrameBlit.drawFrame(mTextureId, mTmpMatrix);
mDisplaySurface.swapBuffers();
Run Code Online (Sandbox Code Playgroud)
但我可以使用以下代码成功翻转视频帧:
mVideoTexture.updateTexImage();
mVideoTexture.getTransformMatrix(mTmpMatrix);
mDisplaySurface.makeCurrent();
int viewWidth = getWidth();
int viewHeight = getHeight();
GLES20.glViewport(0, 0, viewWidth, viewHeight);
mTmpMatrix[5] = -1 * mTmpMatrix[5];
mTmpMatrix[13] = 1.0f - mTmpMatrix[13];
mFullFrameBlit.drawFrame(mTextureId, mTmpMatrix);
mDisplaySurface.swapBuffers(); …Run Code Online (Sandbox Code Playgroud) 我设法编写了一个视频录制演示,类似于grafika 的ContinuousCaptureActivity(ContinuousCaptureActivity.java的源代码).
不同之处在于grafika使用了硬件编码,但我使用了软件编码.对于软件编码,我使用PBO从GPU获取每个视频帧非常快并将图像数据复制到ffmpeg,然后执行h264编码.
对于大多数设备来说,性能是可以接受的,glMapBufferRange()花了不到5ms而memcpy()花了不到10ms.
但是华为mate7手机的性能很低.glMapBufferRange()需要15~30ms,memcpy()需要25~35ms.
我在mate7上测试了正常的memcpy(),复制普通内存时速度要快得多.
真的很奇怪,谁可以给我一些帮助?
设备信息:
chipset of the phone: HiSilicon Kirin 925
cpu of the phone: Quad-core 1.8 GHz Cortex-A15 & quad-core 1.3 GHz Cortex-A7
Run Code Online (Sandbox Code Playgroud)
pbo代码如下:
final int buffer_num = 1;
final int pbo_id[] = new int[buffer_num];
private void getPixelFromPBO(int width, int height, boolean isDefaultFb) {
try {
long start = System.currentTimeMillis();
final int pbo_size = width * height * 4;
if (mFrameNum == 0) { …Run Code Online (Sandbox Code Playgroud) 该应用程序基于Grafika的相机捕获活动(https://github.com/google/grafika/tree/master/src/com/android/grafika)。用户点击按钮以录制视频。Nexus 5x随机崩溃。下面发布了2条日志,分别说明何时可以正常工作以及什么时候不工作。请告诉我造成此崩溃的原因是什么,以及是否需要我发布代码的任何部分。
工作方式:
11-21 15:55:22.301 26556-27085/com.testvideo I/OMXClient: MuxOMX ctor
11-21 15:55:22.505 26556-27085/com.testvideo E/ACodec: [OMX.qcom.video.encoder.avc] storeMetaDataInBuffers (output) failed w/ err -1010
11-21 15:55:22.505 26556-27085/com.testvideo W/ACodec: do not know color format 0x7fa30c04 = 2141391876
11-21 15:55:22.506 26556-27085/com.testvideo W/ACodec: do not know color format 0x7f000789 = 2130708361
11-21 15:55:22.518 26556-27085/com.testvideo I/ACodec: setupAVCEncoderParameters with [profile: Baseline] [level: Level31]
11-21 15:55:22.520 26556-27085/com.testvideo I/ACodec: [OMX.qcom.video.encoder.avc] cannot encode color aspects. Ignoring.
11-21 15:55:22.520 26556-27085/com.testvideo I/ACodec: [OMX.qcom.video.encoder.avc] cannot encode HDR static metadata. Ignoring.
11-21 15:55:22.520 26556-27085/com.testvideo …Run Code Online (Sandbox Code Playgroud) 我正在使用依赖于 Google 的 Grafika 存储库的实时流 API。我使用 Grafika EGLSurfaceBase 的 saveFrame 方法来允许用户在流式传输时捕获视频的静态图像。
https://github.com/google/grafika/blob/master/src/com/android/grafika/gles/EglSurfaceBase.java
实际捕获有效,但显然在某些相机方向上图像会翻转。
我发现了很多与从 OpenGL 纹理获取的倒置位图相关的问题 - 但大多数似乎是指绘制的图像并依赖于:
a) 在 OpenG 中翻转纹理。但就我而言,我正在使用实时流 API,因此翻转纹理来捕获图像实际上可能也会翻转视频流上的图像捕获。
或者
b) 在基于资源生成位图后翻转位图。就我而言,我没有资源,我正在从字节缓冲区创建位图,并且不想复制它来翻转它。
这是 API 具有的基本 EGLSurfaceBase 方法 - 我将把相机方向传递给它,但我的问题是:
String filename = file.toString();
int width = getWidth();
int height = getHeight();
ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4);
buf.order(ByteOrder.LITTLE_ENDIAN);
GLES20.glReadPixels(0, 0, width, height,
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);
GlUtil.checkGlError("glReadPixels");
buf.rewind();
BufferedOutputStream bos = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(filename));
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); …Run Code Online (Sandbox Code Playgroud) 我从Grafika开始了一个项目并对其进行了修改。我有一个框架(与原始框架没有太大区别),它可以从 中捕获预览Camera并同时以不同的分辨率将其连续编码为视频。
MediaCodec(用于编码)配置为使用COLOR_FormatSurface,以便我们能够渲染到getInputSurface()使用 GLES查询的 Surface 。
媒体格式设置为 MIME 类型 video/avc
对于大多数手机,此设置非常有效。
但对于一些手机,编码视频的色度值略微倾斜,底部有一个绿色条。
目前编码器表面的分辨率为 640x360。选择渲染到表面的 EGLConfig 支持 32 位 RGBA 格式。
该预览是完美的所有手机。
所以我假设应用程序端或操作系统框架端的编码器参数有问题。
它发生在 Android 4.4 上。- 不确定,是否可以在 5.* 上重现。
] 2
我的目标是拼接多个视频文件中的视频片段。片段由任意开始时间和结束时间定义。最初我想使用像 mp4parser 这样的库来做到这一点,但它只能在同步(IFRAME)点切割流,而我需要更高的精度。
我的场景是从文件中提取编码流 -> 解码 -> 编码 -> 将结果混合到 mp4 文件中。目前,代码通常可以工作,但生成的视频是白噪声。在 Nexus-S 和 Galaxy-S3 上进行了测试。我的代码是几个示例的组合:
我想简化示例,因为我不需要在中间处理帧。我尝试将缓冲区从解码器输出馈送到编码器输入,而中间没有 Surface。整个过程的工作原理是代码运行完成并生成可播放的视频文件。然而文件的内容是白噪声。
这是将帧从解码器提供给编码器的代码片段。有什么问题以及如何使其发挥作用?
...
} else { // decoderStatus >= 0
if (VERBOSE) Log.d(TAG, "surface decoder given buffer "
+ decoderStatus + " (size=" + info.size + ")");
// The ByteBuffers are null references, but we still get a nonzero
// size for the decoded data.
boolean doRender = (info.size != 0);
// As soon as we call …Run Code Online (Sandbox Code Playgroud)