pedroSG94 / RootEncoder

RootEncoder for Android (rtmp-rtsp-stream-client-java) is a stream encoder to push video/audio to media servers using protocols RTMP, RTSP, SRT and UDP with all code written in Java/Kotlin
Apache License 2.0
2.56k stars 773 forks source link

OpenGl Surface is stretched how to make it normal #139

Closed Rishabhsoti closed 6 years ago

Rishabhsoti commented 6 years ago

OpenGl Surface is stretched how to make it normal

pedroSG94 commented 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?

Rishabhsoti commented 6 years ago

yes please

pedroSG94 commented 6 years ago

Only preview is stretched right? Stream should be fine.

Rishabhsoti commented 6 years ago

both are streched in landscape mode

pedroSG94 commented 6 years ago

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();
    }
  }
}
rkoshti commented 6 years ago

@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

screen shot 2018-05-28 at 17 01 19 2

Thanks