我正在学习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的人都能给我一些帮助吗?
我写了一个演示来使用 MediaCodec 和 MediaMuxer 录制视频。
我用我的demo录制了一段视频,用ffprobe查看视频,结果如下:
Duration: 00:00:06.86, start: 0.000000, bitrate: 723 kb/s
Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 320x240, 619 kb/s, SAR 1:1 DAR 4:3, 30.02 fps, 30 tbr, 90k tbn, 180k tbc (default)
Metadata:
creation_time : 2015-06-05 13:19:24
handler_name : VideoHandle
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 96 kb/s (default)
Metadata:
creation_time : 2015-06-05 13:19:24
handler_name : SoundHandle
Run Code Online (Sandbox Code Playgroud)
它包含视频和音频信息,我发现音频属性与我在源代码中设置的相同,但视频属性不正确。我的视频设置源码如下:
MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, 384000); …Run Code Online (Sandbox Code Playgroud) 每个人,
我在 Android 中使用 SurfaceTexture 但我无法理解它的 API:getTransformMatrix(float[] mtx),API 文档如下:
/**
* Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by
* the most recent call to updateTexImage.
*
* This transform matrix maps 2D homogeneous texture coordinates of the form (s, t, 0, 1) with s
* and t in the inclusive range [0, 1] to the texture coordinate that should be used to sample
* that location from the texture. Sampling the texture outside …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) 当我在Android上使用软引用时遇到一个奇怪的问题。我为位图缓存实现了一个类,源代码如下:
public class ImageCache
{
private static HashMap<String, SoftReference<Bitmap>> mCache = new HashMap<String, SoftReference<Bitmap>>();
private static final String TAG = "ImageCache";
public static Bitmap getBitmap(String url)
{
Bitmap bitmap = null;
if (mCache.containsKey(url))
{
Log.d(TAG, "use cache: " + url);
bitmap = mCache.get(url).get();
if (bitmap != null)
{
return bitmap;
}
else
{
Log.w(TAG, "#######################soft ref was collected!!!");
}
}
bitmap = BitmapFactory.decodeFile(url);
if (bitmap == null)
{
Log.e(TAG, "#####jpg not found");
return null;
}
bitmap = Bitmap.createScaledBitmap(bitmap, 320, 240, …Run Code Online (Sandbox Code Playgroud)