Closed Rishabhsoti closed 6 years ago
You can use same aspect ratio in openglview and stream resolution example: stream resolution -> 1280x720 (aspect ratio 16:9, so your view should have 16 pixel of width each 9 of height, of course you can rotate it like 16 of height each 9 of width). Like: stream resolution 1280x720 - openglview size -> 1600px X 900px.
If you want full screen openglview you will need select same aspect ratio than your device screen(on smartphone normally 16:9). I can do a fix for it using opengl but it will result in an image cut. Are you interested?
yes please
Only preview is stretched right? Stream should be fine.
both are streched in landscape mode
New feature added for it. Now you can change stream and preview size on fly (This only rescale size drawed for opengl if you select a resolution below of screen the rest of screen is black). I share you my Activity example, please read comment in onStartChangeResolution method to know more about it.
package com.pedro.rtpstreamer.openglexample;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.pedro.encoder.input.gl.render.filters.AndroidViewFilterRender;
import com.pedro.encoder.input.gl.render.filters.BasicDeformationFilterRender;
import com.pedro.encoder.input.gl.render.filters.BeautyFilterRender;
import com.pedro.encoder.input.gl.render.filters.BlurFilterRender;
import com.pedro.encoder.input.gl.render.filters.BrightnessFilterRender;
import com.pedro.encoder.input.gl.render.filters.CartoonFilterRender;
import com.pedro.encoder.input.gl.render.filters.ColorFilterRender;
import com.pedro.encoder.input.gl.render.filters.ContrastFilterRender;
import com.pedro.encoder.input.gl.render.filters.DuotoneFilterRender;
import com.pedro.encoder.input.gl.render.filters.EarlyBirdFilterRender;
import com.pedro.encoder.input.gl.render.filters.EdgeDetectionFilterRender;
import com.pedro.encoder.input.gl.render.filters.ExposureFilterRender;
import com.pedro.encoder.input.gl.render.filters.FireFilterRender;
import com.pedro.encoder.input.gl.render.filters.GammaFilterRender;
import com.pedro.encoder.input.gl.render.filters.GreyScaleFilterRender;
import com.pedro.encoder.input.gl.render.filters.HalftoneLinesFilterRender;
import com.pedro.encoder.input.gl.render.filters.Image70sFilterRender;
import com.pedro.encoder.input.gl.render.filters.LamoishFilterRender;
import com.pedro.encoder.input.gl.render.filters.MoneyFilterRender;
import com.pedro.encoder.input.gl.render.filters.NegativeFilterRender;
import com.pedro.encoder.input.gl.render.filters.NoFilterRender;
import com.pedro.encoder.input.gl.render.filters.PixelatedFilterRender;
import com.pedro.encoder.input.gl.render.filters.PolygonizationFilterRender;
import com.pedro.encoder.input.gl.render.filters.RainbowFilterRender;
import com.pedro.encoder.input.gl.render.filters.RippleFilterRender;
import com.pedro.encoder.input.gl.render.filters.SaturationFilterRender;
import com.pedro.encoder.input.gl.render.filters.SepiaFilterRender;
import com.pedro.encoder.input.gl.render.filters.SharpnessFilterRender;
import com.pedro.encoder.input.gl.render.filters.TemperatureFilterRender;
import com.pedro.encoder.input.gl.render.filters.ZebraFilterRender;
import com.pedro.encoder.input.video.CameraOpenException;
import com.pedro.encoder.utils.gl.GifStreamObject;
import com.pedro.encoder.utils.gl.ImageStreamObject;
import com.pedro.encoder.utils.gl.TextStreamObject;
import com.pedro.rtplibrary.rtmp.RtmpCamera1;
import com.pedro.rtplibrary.view.OnStartResolution;
import com.pedro.rtplibrary.view.OpenGlView;
import com.pedro.rtpstreamer.R;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import net.ossrs.rtmp.ConnectCheckerRtmp;
/**
* More documentation see:
* {@link com.pedro.rtplibrary.base.Camera1Base}
* {@link com.pedro.rtplibrary.rtmp.RtmpCamera1}
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public class OpenGlRtmpActivity extends AppCompatActivity
implements ConnectCheckerRtmp, View.OnClickListener, SurfaceHolder.Callback {
private static RtmpCamera1 rtmpCamera1;
private Button button;
private Button bRecord;
private EditText etUrl;
private String currentDateAndTime = "";
private File folder = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/rtmp-rtsp-stream-client-java");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_open_gl);
final OpenGlView openGlView = findViewById(R.id.surfaceView);
openGlView.onChangeResolution(new OnStartResolution() {
@Override
public void onStartChangeResolution() {
/* Random values. It is called when you use methods: startPreview, startStream or refreshView(when orientation is changed).
Play with it to customize resolution on fly. You can call this methods on any moment but the
resolution is reset when the last mentioned methods(startPreview, startStream or refreshView) are called.
If any below method is not called full screen by default */
openGlView.setPreviewResolution(50, 50);
openGlView.setEncoderResolution(50, 50);
openGlView.setRotatedEncoderResolution(480, 360);
openGlView.setRotatedPreviewResolution(1000, 1000);
}
});
button = findViewById(R.id.b_start_stop);
button.setOnClickListener(this);
bRecord = findViewById(R.id.b_record);
bRecord.setOnClickListener(this);
Button switchCamera = findViewById(R.id.switch_camera);
switchCamera.setOnClickListener(this);
etUrl = findViewById(R.id.et_rtp_url);
etUrl.setHint(R.string.hint_rtmp);
if (rtmpCamera1 == null) {
rtmpCamera1 = new RtmpCamera1(openGlView, this);
rtmpCamera1.setOnChangeOrientation(true);
} else {
rtmpCamera1.refreshView(openGlView);
}
openGlView.getHolder().addCallback(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.gl_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (rtmpCamera1.isStreaming()) {
switch (item.getItemId()) {
case R.id.e_d_fxaa:
Toast.makeText(this, "FXAA " + (rtmpCamera1.isAAEnabled() ? " enabled" : "disabled"),
Toast.LENGTH_SHORT).show();
rtmpCamera1.enableAA(!rtmpCamera1.isAAEnabled());
return true;
//stream object
case R.id.text:
setTextToStream();
return true;
case R.id.image:
setImageToStream();
return true;
case R.id.gif:
setGifToStream();
return true;
case R.id.clear:
rtmpCamera1.clearStreamObject();
return true;
//filters. NOTE: You can change filter values on fly without re set the filter.
// Example:
// ColorFilterRender color = new ColorFilterRender()
// rtmpCamera1.setFilter(color);
// color.setRGBColor(255, 0, 0); //red tint
case R.id.no_filter:
rtmpCamera1.setFilter(new NoFilterRender());
return true;
case R.id.android_view:
AndroidViewFilterRender androidViewFilterRender = new AndroidViewFilterRender();
androidViewFilterRender.setView(findViewById(R.id.activity_example_rtmp));
rtmpCamera1.setFilter(androidViewFilterRender);
return true;
case R.id.basic_deformation:
rtmpCamera1.setFilter(new BasicDeformationFilterRender());
return true;
case R.id.beauty:
rtmpCamera1.setFilter(new BeautyFilterRender());
return true;
case R.id.blur:
rtmpCamera1.setFilter(new BlurFilterRender());
return true;
case R.id.brightness:
rtmpCamera1.setFilter(new BrightnessFilterRender());
return true;
case R.id.cartoon:
rtmpCamera1.setFilter(new CartoonFilterRender());
return true;
case R.id.color:
rtmpCamera1.setFilter(new ColorFilterRender());
return true;
case R.id.contrast:
rtmpCamera1.setFilter(new ContrastFilterRender());
return true;
case R.id.duotone:
rtmpCamera1.setFilter(new DuotoneFilterRender());
return true;
case R.id.early_bird:
rtmpCamera1.setFilter(new EarlyBirdFilterRender());
return true;
case R.id.edge_detection:
rtmpCamera1.setFilter(new EdgeDetectionFilterRender());
return true;
case R.id.exposure:
rtmpCamera1.setFilter(new ExposureFilterRender());
return true;
case R.id.fire:
rtmpCamera1.setFilter(new FireFilterRender());
return true;
case R.id.gamma:
rtmpCamera1.setFilter(new GammaFilterRender());
return true;
case R.id.grey_scale:
rtmpCamera1.setFilter(new GreyScaleFilterRender());
return true;
case R.id.halftone_lines:
rtmpCamera1.setFilter(new HalftoneLinesFilterRender());
return true;
case R.id.image_70s:
rtmpCamera1.setFilter(new Image70sFilterRender());
return true;
case R.id.lamoish:
rtmpCamera1.setFilter(new LamoishFilterRender());
return true;
case R.id.money:
rtmpCamera1.setFilter(new MoneyFilterRender());
return true;
case R.id.negative:
rtmpCamera1.setFilter(new NegativeFilterRender());
return true;
case R.id.pixelated:
rtmpCamera1.setFilter(new PixelatedFilterRender());
return true;
case R.id.polygonization:
rtmpCamera1.setFilter(new PolygonizationFilterRender());
return true;
case R.id.rainbow:
rtmpCamera1.setFilter(new RainbowFilterRender());
return true;
case R.id.ripple:
rtmpCamera1.setFilter(new RippleFilterRender());
return true;
case R.id.saturation:
rtmpCamera1.setFilter(new SaturationFilterRender());
return true;
case R.id.sepia:
rtmpCamera1.setFilter(new SepiaFilterRender());
return true;
case R.id.sharpness:
rtmpCamera1.setFilter(new SharpnessFilterRender());
return true;
case R.id.temperature:
rtmpCamera1.setFilter(new TemperatureFilterRender());
return true;
case R.id.zebra:
rtmpCamera1.setFilter(new ZebraFilterRender());
return true;
default:
return false;
}
} else {
return false;
}
}
private void setTextToStream() {
try {
TextStreamObject textStreamObject = new TextStreamObject();
textStreamObject.load("Hello world", 22, Color.RED);
rtmpCamera1.setTextStreamObject(textStreamObject);
} catch (IOException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private void setImageToStream() {
try {
ImageStreamObject imageStreamObject = new ImageStreamObject();
imageStreamObject.load(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
rtmpCamera1.setImageStreamObject(imageStreamObject);
} catch (IOException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private void setGifToStream() {
try {
GifStreamObject gifStreamObject = new GifStreamObject();
gifStreamObject.load(getResources().openRawResource(R.raw.banana));
rtmpCamera1.setGifStreamObject(gifStreamObject);
} catch (IOException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onConnectionSuccessRtmp() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OpenGlRtmpActivity.this, "Connection success", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onConnectionFailedRtmp(final String reason) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OpenGlRtmpActivity.this, "Connection failed. " + reason, Toast.LENGTH_SHORT)
.show();
rtmpCamera1.stopStream();
button.setText(R.string.start_button);
}
});
}
@Override
public void onDisconnectRtmp() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OpenGlRtmpActivity.this, "Disconnected", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onAuthErrorRtmp() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OpenGlRtmpActivity.this, "Auth error", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onAuthSuccessRtmp() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OpenGlRtmpActivity.this, "Auth success", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.b_start_stop:
if (!rtmpCamera1.isStreaming()) {
if (rtmpCamera1.prepareAudio() && rtmpCamera1.prepareVideo()) {
button.setText(R.string.stop_button);
rtmpCamera1.startStream(etUrl.getText().toString());
} else {
Toast.makeText(this, "Error preparing stream, This device cant do it",
Toast.LENGTH_SHORT).show();
}
} else {
button.setText(R.string.start_button);
rtmpCamera1.stopStream();
}
break;
case R.id.switch_camera:
try {
rtmpCamera1.switchCamera();
} catch (CameraOpenException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
break;
case R.id.b_record:
if (!rtmpCamera1.isRecording()) {
try {
if (!folder.exists()) {
folder.mkdir();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
currentDateAndTime = sdf.format(new Date());
rtmpCamera1.startRecord(folder.getAbsolutePath() + "/" + currentDateAndTime + ".mp4");
bRecord.setText(R.string.stop_record);
Toast.makeText(this, "Recording... ", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
rtmpCamera1.stopRecord();
bRecord.setText(R.string.start_record);
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
} else {
rtmpCamera1.stopRecord();
bRecord.setText(R.string.start_record);
Toast.makeText(this,
"file " + currentDateAndTime + ".mp4 saved in " + folder.getAbsolutePath(),
Toast.LENGTH_SHORT).show();
currentDateAndTime = "";
}
break;
default:
break;
}
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
rtmpCamera1.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
@Override
protected void onDestroy() {
super.onDestroy();
if (isFinishing()) {
if (rtmpCamera1.isRecording()) {
rtmpCamera1.stopRecord();
bRecord.setText(R.string.start_record);
Toast.makeText(this,
"file " + currentDateAndTime + ".mp4 saved in " + folder.getAbsolutePath(),
Toast.LENGTH_SHORT).show();
currentDateAndTime = "";
}
if (rtmpCamera1.isStreaming()) {
rtmpCamera1.stopStream();
button.setText(getResources().getString(R.string.start_button));
}
rtmpCamera1.stopPreview();
}
}
}
@pedroSG94
Hi i am not able to find this methods in the latest demo
openGlView.onChangeResolution(new OnStartResolution() { @Override public void onStartChangeResolution() { / Random values. It is called when you use methods: startPreview, startStream or refreshView(when orientation is changed). Play with it to customize resolution on fly. You can call this methods on any moment but the resolution is reset when the last mentioned methods(startPreview, startStream or refreshView) are called. If any below method is not called full screen by default / openGlView.setPreviewResolution(50, 50); openGlView.setEncoderResolution(50, 50); openGlView.setRotatedEncoderResolution(480, 360); openGlView.setRotatedPreviewResolution(1000, 1000); } });
rtmpCamera1.setOnChangeOrientation(true);
Can you please update latest demo code May be i have the same problem
Thanks
OpenGl Surface is stretched how to make it normal