我正在構建Android應用程序,其中一個ExoPlayer將視頻播放到SurfaceView的表面上,並且我正在研究是否可以動態模糊播放的視頻。Android:動態模糊表面與視頻
由於SurfaceView的表面部分不出現在位圖中,所以涉及首先生成視圖的位圖以模糊的模糊技術將不起作用。
表面和視圖用於舊版Android(例如Surface.FX_SURFACE_BLUR)內置的模糊效果,但似乎已在較新的API中棄用。
任何人都可以分享一些關於表面如何動態模糊的見解嗎?謝謝。
我正在構建Android應用程序,其中一個ExoPlayer將視頻播放到SurfaceView的表面上,並且我正在研究是否可以動態模糊播放的視頻。Android:動態模糊表面與視頻
由於SurfaceView的表面部分不出現在位圖中,所以涉及首先生成視圖的位圖以模糊的模糊技術將不起作用。
表面和視圖用於舊版Android(例如Surface.FX_SURFACE_BLUR)內置的模糊效果,但似乎已在較新的API中棄用。
任何人都可以分享一些關於表面如何動態模糊的見解嗎?謝謝。
在StackOverflow上有很多問題需要完成。我會回顧一下我用過的方法,希望對某些人有用。
如果這是一個視頻幀的靜態模糊,那麼在TextureView
中播放視頻就足夠了,使用.getBitmap()
函數並使用諸如Renderscript之類的工具模糊生成的Bitmap。但是,.getBitmap()
在主UI線程上執行,因此滯後於其正在嘗試複製幀的視頻。
爲了對每一幀執行模糊處理,最好的方法似乎是使用帶有自定義渲染器的GLSurfaceView。我用VidEffects中指定的代碼this answer指出是一個很好的起點。
具有大半徑的模糊可能非常計算密集。這就是爲什麼我第一次接近使用兩個單獨的片段着色器(一個模糊水平模糊,一個模糊垂直結果)執行模糊。我實際上最終只使用了一個片段着色器來應用7x7高斯內核。如果您的GLSurfaceView
較大,請記住一個非常重要的事項是在GLSurfaceView
的SurfaceHolder
上撥打setFixedSize()
以使其分辨率低於屏幕的分辨率。結果看起來不是很像素,因爲它無論如何都是模糊的,但是性能的提升非常顯着。
模糊我在大多數設備上設置爲播放24fps,setFixedSize()
指定其分辨率爲100x70。
如果任何人想要單次傳遞片段着色器來完成該圓圈...下面的代碼實現了從VidEffects可用的代碼中定義的ShaderInterface
。我改編自this example on ShaderToy.com。
public class BlurEffect2 implements ShaderInterface {
private final int mMaskSize;
private final int mWidth;
private final int mHeight;
public BlurEffect2(int maskSize, int width, int height) {
mMaskSize = maskSize;
mWidth = width;
mHeight = height;
}
@Override
public String getShader(GLSurfaceView mGlSurfaceView) {
float hStep = 1.0f/mWidth;
float vStep = 1.0f/mHeight;
return "#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;\n" +
//"in" attributes from our vertex shader
"varying vec2 vTextureCoord;\n" +
//declare uniforms
"uniform samplerExternalOES sTexture;\n" +
"float normpdf(in float x, in float sigma) {\n" +
" return 0.39894 * exp(-0.5 * x * x/(sigma * sigma))/sigma;\n" +
"}\n" +
"void main() {\n" +
" vec3 c = texture2D(sTexture, vTextureCoord).rgb;\n" +
//declare stuff
" const int mSize = " + mMaskSize + ";\n" +
" const int kSize = (mSize - 1)/2;\n" +
" float kernel[ mSize];\n" +
" vec3 final_colour = vec3(0.0);\n" +
//create the 1-D kernel
" float sigma = 7.0;\n" +
" float Z = 0.0;\n" +
" for (int j = 0; j <= kSize; ++j) {\n" +
" kernel[kSize + j] = kernel[kSize - j] = normpdf(float(j), sigma);\n" +
" }\n" +
//get the normalization factor (as the gaussian has been clamped)
" for (int j = 0; j < mSize; ++j) {\n" +
" Z += kernel[j];\n" +
" }\n" +
//read out the texels
" for (int i = -kSize; i <= kSize; ++i) {\n" +
" for (int j = -kSize; j <= kSize; ++j) {\n" +
" final_colour += kernel[kSize + j] * kernel[kSize + i] * texture2D(sTexture, (vTextureCoord.xy + vec2(float(i)*" + hStep + ", float(j)*" + vStep + "))).rgb;\n" +
" }\n" +
" }\n" +
" gl_FragColor = vec4(final_colour/(Z * Z), 1.0);\n" +
"}";
}
}
正如邁克爾指出上面,你可以通過使用setFixedSize
設置SurfaceView
的尺寸提高性能。
@BindView(R.id.video_snap)
VideoSurfaceView mVideoView;
@Override
public void showVideo(String cachedPath) {
mImageView.setVisibility(View.GONE);
mVideoView.setVisibility(View.VISIBLE);
//Get width and height of the video
final MediaMetadataRetriever mRetriever = new MediaMetadataRetriever();
mRetriever.setDataSource(cachedPath);
int width = Integer.parseInt(mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
int height = Integer.parseInt(mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
//divide the width and height by 10
width /= 10;
height /= 10;
//set the size of the surface to play on to 1/10 the width and height
mVideoView.getHolder().setFixedSize(width, height);
//Set up the media player
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setLooping(true);
try {
mMediaPlayer.setDataSource(cachedPath);
} catch (Exception e) {
Timber.e(e, e.getMessage());
}
//init and start the video player with the mask size set to 17
mVideoView.init(mMediaPlayer, new BlurEffect2(17, width, height));
mVideoView.onResume();
}
使用TextureView https://github.com/google/ExoPlayer/issues/98再看看http://stackoverflow.com/questions/26633424/how-to-apply-video-effects-過濾器像棕褐色復古等紋理視圖在 –
我明白了。我不清楚你爲什麼推薦一個TextureView而不是SurfaceView。這有什麼不同嗎? – Michael
由於您嘗試應用濾鏡(模糊效果),我認爲您需要使用SurfaceTexture - 我建議您查看http://source.android.com/devices/graphics/architecture.html和Show + Capture Camera應用程序Grafika項目:https://github.com/google/grafika –