I tried to play the same video with a SurfaceView and a TextureView and noticed that the image rendered with the TextureView is more aliased (less 'smooth') than with the SurfaceView.
What is the reason for this ? Is there any way to configure rendering of TextureView to look better ?
The TextureView is used like this:
TextureView textureView = new TextureView(this);
textureView.setSurfaceTextureListener(new SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
Log.i("test", "onSurfaceTextureAvailable()");
MediaPlayer player = MediaPlayer.create(TestActivity.this, Uri.parse(VIDEO_URL));
Surface surface = new Surface(surfaceTexture);
player.setSurface(surface);
player.start();
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
Log.i("test", "onSurfaceTextureUpdated()");
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
Log.i("test", "onSurfaceTextureSizeChanged()");
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
Log.i("test", "onSurfaceTextureDestroyed()");
return false;
}
});
setContentView(textureView);
And for the SurfaceView:
SurfaceView surfaceView = new SurfaceView(this);
surfaceView.getHolder().addCallback(new Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i("test", "surfaceCreated()");
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i("test", "surfaceDestroyed()");
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i("test", "surfaceChanged()");
MediaPlayer player = MediaPlayer.create(TestActivity.this, Uri.parse(VIDEO_URL));
player.setSurface(holder.getSurface());
player.start();
}
});
setContentView(surfaceView);
Well, it seems that applying a scaling (other than 1) on the TextureView does the 'smoothing' effect that I'm looking for.
textureView.setScaleX(1.00001f);
That sounds like a strange hack...but it works. Would be interesting to dig out what's done in the scaling that changes the rendering aspect...
Related
I have a TextureView in my xml:
<TextureView
android:id="#+id/textureView"
android:layout_width="300dp"
android:layout_height="300dp"
android:backgroundTint="#FF0000"
/>
I want to draw objects with openGL ES in this TextureView.
I do:
textureView = findViewById(R.id.textureView);
textureView.setSurfaceTextureListener(this);
#Override
public void onSurfaceTextureAvailable(#NonNull SurfaceTexture surface, int width, int height) {
Tools.logd("textureView onSurfaceTextureAvailable");
surface.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
#Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
Tools.logd("textureView onFrameAvailable");
}
});
}
#Override
public void onSurfaceTextureSizeChanged(#NonNull SurfaceTexture surface, int width, int height) {
Tools.logd("textureView onSurfaceTextureSizeChanged");
}
#Override
public boolean onSurfaceTextureDestroyed(#NonNull SurfaceTexture surface) {
Tools.logd("textureView onSurfaceTextureDestroyed");
return false;
}
#Override
public void onSurfaceTextureUpdated(#NonNull SurfaceTexture surface) {
Tools.logd("textureView onSurfaceTextureUpdated");
}
onSurfaceTextureAvailable is executed but then onFrameAvailable is never called (should be called 30 or 60 times per second).
How to solve this problem ?
Thanks.
I wanted to know if it is possible to use SurfaceHolder.Callback (and of course its callbacks) in combination with TextureView?
I mean sth. like the following:
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private TextureView mTextureView;
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
}
Would that be working? The reason I ask is that whenever I see SurfaceHolder.Callback, they use SurfaceView.
No you can't. For TextureView you should use SurfaceTextureListener. In many senses these callbacks are similar to SurfaceHolder callbacks.
For example, instead of
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mPreviewSurface = holder.getSurface();
}
you can write
#Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
mPreviewSurface = new Surface(texture);
}
See https://github.com/google/ExoPlayer/issues/98. Thanks to #BrentM.
I have seen many examples on how to live stream video from android camera to rtmp server using surfaceview. One is here : https://github.com/begeekmyfriend/yasea
But is it possible to stream the video from camera to rtmp using a textureview? If it is, how can we?
Textureview mTextureView;
// inside oncreate
mTextureView = (TextureView) findViewById(R.id.texture_view);
mTextureView.setSurfaceTextureListener(AircraftControlActivity.this);
// Outside OnCreate
#Override
public void onSurfaceTextureAvailable(final SurfaceTexture surface, final int width, final int height) {
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
}
#Override
public void onSurfaceTextureUpdated(final SurfaceTexture surface) {
}
What to do next?
Take a look at Texture View
public class MainActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener
{
Camera camera;
TextureView textureView;
ImageButton button ; //ignore this one
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textureView = (TextureView) findViewById(R.id.textureView);
button = (ImageButton)findViewById(R.id.imageButton);
textureView.setSurfaceTextureListener(this);
}
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)
{
camera = Camera.open();
try
{
camera.setPreviewTexture(surface);
camera.startPreview();
}
catch (IOException ioe)
{
// Something bad happened
}
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)
{
// Ignored, Camera does all the work for us
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface)
{
camera.stopPreview();
camera.release();
return true;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface)
{
// Invoked every time there's a new Camera preview frame
}
}
I want to add SurfaceView which displaying camera preview to my layout. It should be semi-transparent (alpha 0.5). I add View by addView() method.
Ho to do that. I tried animation but it seems to not works with camera.
My Surfave view looks like that:
public class ShowCamera extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holdMe;
private Camera theCamera;
public ShowCamera(Context context,Camera camera) {
super(context);
theCamera = camera;
holdMe = getHolder();
holdMe.addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
theCamera.setPreviewDisplay(holder);
theCamera.startPreview();
} catch (IOException e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
}
}
My minAPI = 8.
I am trying to render camera preview using SurfaceTexture. I read the document but unable to understand how it works.
Can anyone provide one sample example(very basic one) or link which uses SurfaceTexture to preview camera. I googled this but not found what I am looking for.
Thanks in advance.
If you want to use the Camera with TextureSurface you can implement SurfaceTextureListener interface. You'll have to implement 4 methods:
1) onSurfaceTextureAvailable - Here you setup your camera
2)onSurfaceTextureSizeChanged - In your case, the Android's camera will handle this method
3)onSurfaceTextureDestroyed - Here you destroy all camera stuff.
4) onSurfaceTextureUpdated- Update your texture here when you have something to change!
Check the example below:
public class MainActivity extends Activity implements SurfaceTextureListener{
private Camera mCamera;
private TextureView mTextureView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
setContentView(mTextureView);
}
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open();
Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
previewSize.width, previewSize.height, Gravity.CENTER));
try {
mCamera.setPreviewTexture(surface);
} catch (IOException t) {
}
mCamera.startPreview();
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Ignored, the Camera does all the work for us
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mCamera.stopPreview();
mCamera.release();
return true;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Update your view here!
}
}
Two more things: Don't forget to add the camera permissions in your project's manifest and the SurfaceTexture is available from API 11.
public class VideoCapture extends Activity implements OnClickListener, SurfaceHolder.Callback {
MediaRecorder recorder;
SurfaceHolder holder;
boolean recording = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
recorder = new MediaRecorder();
initRecorder();
SurfaceView cameraView = new SurfaceView(this);
holder = cameraView.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
cameraView.setClickable(true);
cameraView.setOnClickListener(this);
}
private void initRecorder() {
recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
CamcorderProfile cpHigh = CamcorderProfile
.get(CamcorderProfile.QUALITY_HIGH);
recorder.setProfile(cpHigh);
recorder.setOutputFile("/sdcard/videocapture_example.mp4");
recorder.setMaxDuration(50000); // 50 seconds
recorder.setMaxFileSize(5000000); // Approximately 5 megabytes
}
private void prepareRecorder() {
recorder.setPreviewDisplay(holder.getSurface());
try {
recorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
finish();
} catch (IOException e) {
e.printStackTrace();
finish();
}
}
public void onClick(View v) {
if (recording) {
recorder.stop();
recording = false;
// Let's initRecorder so we can record again
initRecorder();
prepareRecorder();
} else {
recording = true;
recorder.start();
}
}
public void surfaceCreated(SurfaceHolder holder) {
prepareRecorder();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (recording) {
recorder.stop();
recording = false;
}
recorder.release();
finish();
}
}