parent
56538fec1a
commit
5cdad4b719
Binary file not shown.
Binary file not shown.
@ -1,49 +1,180 @@
|
|||||||
package com.xypower.mpapp;
|
package com.xypower.mpapp;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.SurfaceTexture;
|
||||||
|
import android.hardware.Camera;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
/*
|
||||||
|
import com.chillingvan.canvasgl.ICanvasGL;
|
||||||
|
import com.chillingvan.canvasgl.glcanvas.BasicTexture;
|
||||||
|
import com.chillingvan.canvasgl.glview.texture.GLTexture;
|
||||||
|
import com.chillingvan.canvasgl.textureFilter.BasicTextureFilter;
|
||||||
|
import com.chillingvan.canvasgl.textureFilter.HueFilter;
|
||||||
|
import com.chillingvan.canvasgl.textureFilter.TextureFilter;
|
||||||
import io.antmedia.rtmp_client.RTMPMuxer;
|
import io.antmedia.rtmp_client.RTMPMuxer;
|
||||||
|
|
||||||
|
import com.xypower.stream.camera.InstantVideoCamera;
|
||||||
|
import com.xypower.stream.encoder.video.H264Encoder;
|
||||||
|
import com.xypower.stream.muxer.RTMPStreamMuxer;
|
||||||
|
import com.xypower.stream.publisher.CameraStreamPublisher;
|
||||||
|
import com.xypower.stream.publisher.StreamPublisher;
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class StreamActivity extends AppCompatActivity {
|
public class StreamActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private RTMPMuxer mRtmpMuxer;
|
/*
|
||||||
private String mUrl;
|
private CameraStreamPublisher streamPublisher;
|
||||||
|
private com.chillingvan.instantvideo.sample.test.camera.CameraPreviewTextureView cameraPreviewTextureView;
|
||||||
|
private InstantVideoCamera instantVideoCamera;
|
||||||
|
private Handler handler;
|
||||||
|
private EditText addrEditText;
|
||||||
|
private HandlerThread handlerThread;
|
||||||
|
private TextureFilter textureFilterLT;
|
||||||
|
private TextureFilter textureFilterRT;
|
||||||
|
private com.chillingvan.instantvideo.sample.test.VideoFrameHandlerHelper videoFrameHandlerHelper;
|
||||||
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
initFrameHandlerHelper();
|
||||||
setContentView(R.layout.activity_stream);
|
setContentView(R.layout.activity_stream);
|
||||||
|
/*
|
||||||
|
cameraPreviewTextureView = findViewById(R.id.camera_produce_view);
|
||||||
|
cameraPreviewTextureView.setOnDrawListener(new H264Encoder.OnDrawListener() {
|
||||||
|
@Override
|
||||||
|
public void onGLDraw(ICanvasGL canvasGL, List<GLTexture> producedTextures, List<GLTexture> consumedTextures) {
|
||||||
|
|
||||||
|
GLTexture texture = producedTextures.get(0);
|
||||||
|
drawVideoFrame(canvasGL, texture.getSurfaceTexture(), texture.getRawTexture());
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
addrEditText = (EditText) findViewById(R.id.ip_input_test);
|
||||||
|
|
||||||
|
|
||||||
|
instantVideoCamera = new InstantVideoCamera(Camera.CameraInfo.CAMERA_FACING_FRONT, 640, 480);
|
||||||
|
// instantVideoCamera = new InstantVideoCamera(Camera.CameraInfo.CAMERA_FACING_FRONT, 1280, 720);
|
||||||
|
|
||||||
|
handlerThread = new HandlerThread("StreamPublisherOpen");
|
||||||
|
handlerThread.start();
|
||||||
|
handler = new Handler(handlerThread.getLooper()) {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
super.handleMessage(msg);
|
||||||
|
// StreamPublisher.StreamPublisherParam streamPublisherParam = new StreamPublisher.StreamPublisherParam();
|
||||||
|
// StreamPublisher.StreamPublisherParam streamPublisherParam = new StreamPublisher.StreamPublisherParam(1080, 640, 9500 * 1000, 30, 1, 44100, 19200);
|
||||||
|
StreamPublisher.StreamPublisherParam streamPublisherParam = new StreamPublisher.StreamPublisherParam.Builder().setWidth(540).setHeight(750).setVideoBitRate(1500 * 1000).setFrameRate(30).setIframeInterval(1).setSamplingRate(44100).setAudioBitRate(32000).createStreamPublisherParam();
|
||||||
|
streamPublisherParam.outputFilePath = getExternalFilesDir(null) + "/test_flv_encode.flv";
|
||||||
|
// streamPublisherParam.outputFilePath = getExternalFilesDir(null) + "/test_mp4_encode.mp4";
|
||||||
|
streamPublisher.prepareEncoder(streamPublisherParam, new H264Encoder.OnDrawListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGLDraw(ICanvasGL canvasGL, List<GLTexture> producedTextures, List<GLTexture> consumedTextures) {
|
||||||
|
GLTexture texture = consumedTextures.get(0);
|
||||||
|
drawVideoFrame(canvasGL, texture.getSurfaceTexture(), texture.getRawTexture());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
streamPublisherParam.outputUrl = addrEditText.getText().toString();
|
||||||
|
streamPublisher.startPublish();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
((TextView)findViewById(R.id.test_camera_button)).setText("START");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
streamPublisher = new CameraStreamPublisher(new RTMPStreamMuxer(), cameraPreviewTextureView, instantVideoCamera);
|
||||||
|
// streamPublisher = new CameraStreamPublisher(new MP4Muxer(), cameraPreviewTextureView, instantVideoCamera);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Intent intent = getIntent();
|
private void initFrameHandlerHelper() {
|
||||||
if (intent != null) {
|
/*
|
||||||
mUrl = intent.getStringExtra("url");
|
videoFrameHandlerHelper = new com.chillingvan.instantvideo.sample.test.VideoFrameHandlerHelper(getApplicationContext());
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
private void drawVideoFrame(ICanvasGL canvasGL, @Nullable SurfaceTexture outsideSurfaceTexture, @Nullable BasicTexture outsideTexture) {
|
||||||
|
// Here you can do video process
|
||||||
|
// 此处可以视频处理,例如加水印等等
|
||||||
|
|
||||||
|
if(textureFilterLT == null) {
|
||||||
|
textureFilterLT = new BasicTextureFilter();
|
||||||
|
}
|
||||||
|
if(textureFilterRT == null) {
|
||||||
|
textureFilterRT = new HueFilter(180);
|
||||||
}
|
}
|
||||||
|
int width = outsideTexture.getWidth();
|
||||||
|
int height = outsideTexture.getHeight();
|
||||||
|
canvasGL.drawSurfaceTexture(outsideTexture, outsideSurfaceTexture, 0, 0, width /2, height /2, textureFilterLT);
|
||||||
|
canvasGL.drawSurfaceTexture(outsideTexture, outsideSurfaceTexture, 0, height/2, width/2, height, textureFilterRT);
|
||||||
|
videoFrameHandlerHelper.initDrawHelper(width/2, height/2);
|
||||||
|
videoFrameHandlerHelper.drawText(canvasGL);
|
||||||
|
|
||||||
openRtmpMuxer(mUrl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void openRtmpMuxer(String url) {
|
*/
|
||||||
if (mRtmpMuxer != null) {
|
|
||||||
if (mRtmpMuxer.isConnected()) {
|
@Override
|
||||||
mRtmpMuxer.close();
|
protected void onResume() {
|
||||||
}
|
super.onResume();
|
||||||
} else {
|
// streamPublisher.resumeCamera();
|
||||||
mRtmpMuxer = new RTMPMuxer();
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
/*
|
||||||
|
streamPublisher.pauseCamera();
|
||||||
|
if (streamPublisher.isStart()) {
|
||||||
|
streamPublisher.closeAll();
|
||||||
}
|
}
|
||||||
|
((TextView)findViewById(R.id.test_camera_button)).setText("START");
|
||||||
|
|
||||||
int result = mRtmpMuxer.open(url,0, 0);
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
//handlerThread.quitSafely();
|
||||||
|
}
|
||||||
|
|
||||||
if (mRtmpMuxer != null) {
|
public void clickStartTest(View view) {
|
||||||
mRtmpMuxer.close();
|
TextView textView = (TextView) view;
|
||||||
mRtmpMuxer = null;
|
/*
|
||||||
|
if (streamPublisher.isStart()) {
|
||||||
|
streamPublisher.closeAll();
|
||||||
|
textView.setText("START");
|
||||||
|
} else {
|
||||||
|
streamPublisher.resumeCamera();
|
||||||
|
handler.sendEmptyMessage(1);
|
||||||
|
textView.setText("STOP");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,16 @@
|
|||||||
|
package com.xypower.stream;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Chilling on 2018/8/25.
|
||||||
|
*/
|
||||||
|
public class ScreenUtil {
|
||||||
|
|
||||||
|
public static float dpToPx(Context context, float dp) {
|
||||||
|
if (context == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return dp * context.getResources().getDisplayMetrics().density;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package com.xypower.stream;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
|
||||||
|
import com.chillingvan.canvasgl.ICanvasGL;
|
||||||
|
import com.chillingvan.canvasgl.androidCanvas.IAndroidCanvasHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Chilling on 2022/11/14.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class VideoFrameHandlerHelper {
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public VideoFrameHandlerHelper(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IAndroidCanvasHelper drawTextHelper = IAndroidCanvasHelper.Factory.createAndroidCanvasHelper(IAndroidCanvasHelper.MODE.MODE_ASYNC);
|
||||||
|
private Paint textPaint = new Paint();
|
||||||
|
|
||||||
|
{
|
||||||
|
initTextPaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initTextPaint() {
|
||||||
|
textPaint.setColor(Color.WHITE);
|
||||||
|
textPaint.setTextSize(ScreenUtil.dpToPx(context, 15));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initDrawHelper(int width, int height) {
|
||||||
|
drawTextHelper.init(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawText(ICanvasGL canvasGL) {
|
||||||
|
drawTextHelper.draw(new IAndroidCanvasHelper.CanvasPainter() {
|
||||||
|
@Override
|
||||||
|
public void draw(Canvas androidCanvas, Bitmap drawingBitmap) {
|
||||||
|
androidCanvas.drawText("白色, White", 100, 100, textPaint);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Bitmap outputBitmap = drawTextHelper.getOutputBitmap();
|
||||||
|
canvasGL.invalidateTextureContent(outputBitmap);
|
||||||
|
canvasGL.drawBitmap(outputBitmap, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package com.xypower.stream.camera;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.SurfaceTexture;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import com.chillingvan.canvasgl.ICanvasGL;
|
||||||
|
import com.chillingvan.canvasgl.glview.texture.GLMultiTexProducerView;
|
||||||
|
import com.chillingvan.canvasgl.glview.texture.GLTexture;
|
||||||
|
import com.chillingvan.canvasgl.glview.texture.gles.EglContextWrapper;
|
||||||
|
import com.xypower.stream.VideoFrameHandlerHelper;
|
||||||
|
import com.xypower.stream.encoder.video.H264Encoder;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Leon on 2017/4/19.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CameraPreviewTextureView extends GLMultiTexProducerView {
|
||||||
|
|
||||||
|
private H264Encoder.OnDrawListener onDrawListener;
|
||||||
|
private VideoFrameHandlerHelper videoFrameHandlerHelper = new VideoFrameHandlerHelper(getContext().getApplicationContext());
|
||||||
|
|
||||||
|
public CameraPreviewTextureView(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CameraPreviewTextureView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CameraPreviewTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getInitialTexCount() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
||||||
|
super.onSurfaceTextureAvailable(surface, width, height);
|
||||||
|
if (mSharedEglContext == null) {
|
||||||
|
setSharedEglContext(EglContextWrapper.EGL_NO_CONTEXT_WRAPPER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceChanged(int width, int height) {
|
||||||
|
super.onSurfaceChanged(width, height);
|
||||||
|
videoFrameHandlerHelper.initDrawHelper(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onGLDraw(ICanvasGL canvas, List<GLTexture> producedTextures, List<GLTexture> consumedTextures) {
|
||||||
|
onDrawListener.onGLDraw(canvas, producedTextures, consumedTextures);
|
||||||
|
videoFrameHandlerHelper.drawText(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnDrawListener(H264Encoder.OnDrawListener l) {
|
||||||
|
onDrawListener = l;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
package com.xypower.stream.publisher;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.AssetFileDescriptor;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.media.MediaPlayer;
|
||||||
|
import android.view.Surface;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.chillingvan.canvasgl.util.Loggers;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Chilling on 2018/4/14.
|
||||||
|
*/
|
||||||
|
public class MediaPlayerHelper {
|
||||||
|
|
||||||
|
public static final String TEST_VIDEO_MP4 = "test_video.mp4";
|
||||||
|
private MediaPlayer mediaPlayer;
|
||||||
|
private String videoName;
|
||||||
|
|
||||||
|
public MediaPlayerHelper() {
|
||||||
|
this(TEST_VIDEO_MP4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaPlayerHelper(String videoName) {
|
||||||
|
this.videoName = videoName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPlaying() {
|
||||||
|
if (mediaPlayer != null) {
|
||||||
|
return mediaPlayer.isPlaying();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLooping() {
|
||||||
|
if (mediaPlayer != null) {
|
||||||
|
return mediaPlayer.isLooping();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restart() {
|
||||||
|
if (mediaPlayer != null) {
|
||||||
|
mediaPlayer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playMedia(final Context context, Surface mediaSurface) {
|
||||||
|
mediaPlayer = new MediaPlayer();
|
||||||
|
// mediaPlayer.setVolume(0, 0);
|
||||||
|
try {
|
||||||
|
AssetFileDescriptor afd = context.getAssets().openFd(videoName);
|
||||||
|
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
|
||||||
|
afd.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||||
|
mediaPlayer.setSurface(mediaSurface);
|
||||||
|
mediaPlayer.setLooping(true);
|
||||||
|
|
||||||
|
mediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
|
||||||
|
@Override
|
||||||
|
public void onSeekComplete(MediaPlayer mediaPlayer) {
|
||||||
|
Loggers.i("onSeekComplete","onSeekComplete----"+mediaPlayer.getCurrentPosition());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
|
||||||
|
@Override
|
||||||
|
public void onPrepared(MediaPlayer mediaPlayer) {
|
||||||
|
Toast.makeText(context, "onPrepare --> Start", Toast.LENGTH_SHORT).show();
|
||||||
|
mediaPlayer.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||||
|
@Override
|
||||||
|
public void onCompletion(MediaPlayer m) {
|
||||||
|
Toast.makeText(context, "End Play", Toast.LENGTH_LONG).show();
|
||||||
|
m.stop();
|
||||||
|
m.release();
|
||||||
|
mediaPlayer = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
mediaPlayer.prepare();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pause() {
|
||||||
|
if (mediaPlayer != null) {
|
||||||
|
mediaPlayer.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
if (mediaPlayer != null) {
|
||||||
|
mediaPlayer.release();
|
||||||
|
mediaPlayer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* *
|
||||||
|
* * * Copyright (C) 2017 ChillingVan
|
||||||
|
* * *
|
||||||
|
* * * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* * * you may not use this file except in compliance with the License.
|
||||||
|
* * * You may obtain a copy of the License at
|
||||||
|
* * *
|
||||||
|
* * * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* * *
|
||||||
|
* * * Unless required by applicable law or agreed to in writing, software
|
||||||
|
* * * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* * * See the License for the specific language governing permissions and
|
||||||
|
* * * limitations under the License.
|
||||||
|
* *
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.xypower.stream.publisher;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.SurfaceTexture;
|
||||||
|
import android.opengl.GLES20;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import com.chillingvan.canvasgl.ICanvasGL;
|
||||||
|
import com.chillingvan.canvasgl.glcanvas.BasicTexture;
|
||||||
|
import com.chillingvan.canvasgl.glcanvas.RawTexture;
|
||||||
|
import com.chillingvan.canvasgl.glview.texture.GLSurfaceTextureProducerView;
|
||||||
|
import com.chillingvan.canvasgl.textureFilter.BasicTextureFilter;
|
||||||
|
import com.chillingvan.canvasgl.textureFilter.TextureFilter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Chilling on 2016/11/3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ProduceTextureView extends GLSurfaceTextureProducerView {
|
||||||
|
|
||||||
|
private TextureFilter textureFilter = new BasicTextureFilter();
|
||||||
|
// private Bitmap bitmap;
|
||||||
|
|
||||||
|
public ProduceTextureView(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProduceTextureView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProduceTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceCreated() {
|
||||||
|
// bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.lenna);
|
||||||
|
setProducedTextureTarget(GLES20.GL_TEXTURE_2D);
|
||||||
|
super.onSurfaceCreated();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTextureFilter(TextureFilter textureFilter) {
|
||||||
|
this.textureFilter = textureFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onGLDraw(ICanvasGL canvas, SurfaceTexture producedSurfaceTexture, RawTexture producedRawTexture, @Nullable SurfaceTexture sharedSurfaceTexture, @Nullable BasicTexture sharedTexture) {
|
||||||
|
if (TestVideoEncoder.drawCnt == 19 || TestVideoEncoder.drawCnt == 39) {
|
||||||
|
// canvas.drawBitmap(bitmap, 0, 0);
|
||||||
|
}
|
||||||
|
TestVideoEncoder.drawRect(canvas, TestVideoEncoder.drawCnt);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* *
|
||||||
|
* * * Copyright (C) 2017 ChillingVan
|
||||||
|
* * *
|
||||||
|
* * * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* * * you may not use this file except in compliance with the License.
|
||||||
|
* * * You may obtain a copy of the License at
|
||||||
|
* * *
|
||||||
|
* * * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* * *
|
||||||
|
* * * Unless required by applicable law or agreed to in writing, software
|
||||||
|
* * * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* * * See the License for the specific language governing permissions and
|
||||||
|
* * * limitations under the License.
|
||||||
|
* *
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.xypower.stream.publisher;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.SurfaceTexture;
|
||||||
|
import android.media.MediaCodec;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.chillingvan.canvasgl.ICanvasGL;
|
||||||
|
import com.chillingvan.canvasgl.glcanvas.GLPaint;
|
||||||
|
import com.chillingvan.canvasgl.glcanvas.RawTexture;
|
||||||
|
import com.chillingvan.canvasgl.glview.texture.GLTexture;
|
||||||
|
import com.chillingvan.canvasgl.glview.texture.gles.EglContextWrapper;
|
||||||
|
import com.chillingvan.canvasgl.util.Loggers;
|
||||||
|
import com.xypower.stream.encoder.MediaCodecInputStream;
|
||||||
|
import com.xypower.stream.encoder.video.H264Encoder;
|
||||||
|
import com.xypower.stream.publisher.StreamPublisher;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Chilling on 2016/12/10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TestVideoEncoder {
|
||||||
|
|
||||||
|
private H264Encoder h264Encoder;
|
||||||
|
private byte[] writeBuffer = new byte[1024 * 64];
|
||||||
|
private Context ctx;
|
||||||
|
private EglContextWrapper eglCtx;
|
||||||
|
public static int drawCnt;
|
||||||
|
private OutputStream os;
|
||||||
|
private List<GLTexture> glTextureList = new ArrayList<>();
|
||||||
|
|
||||||
|
public TestVideoEncoder(Context ctx, final EglContextWrapper eglCtx) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.eglCtx = eglCtx;
|
||||||
|
|
||||||
|
try {
|
||||||
|
os = new FileOutputStream(ctx.getExternalFilesDir(null) + File.separator + "test_h264_encode.h264");
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prepareEncoder(H264Encoder.OnDrawListener onDrawListener) {
|
||||||
|
try {
|
||||||
|
h264Encoder = new H264Encoder(new StreamPublisher.StreamPublisherParam.Builder().createStreamPublisherParam(), eglCtx);
|
||||||
|
for (GLTexture texture : glTextureList) {
|
||||||
|
h264Encoder.addSharedTexture(texture);
|
||||||
|
}
|
||||||
|
h264Encoder.setOnDrawListener(onDrawListener);
|
||||||
|
} catch (IOException | IllegalStateException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSharedTexture(RawTexture outsideTexture, SurfaceTexture outsideSurfaceTexture) {
|
||||||
|
glTextureList.add(new GLTexture(outsideTexture, outsideSurfaceTexture));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void drawRect(ICanvasGL canvasGL, int drawCnt) {
|
||||||
|
GLPaint glPaint = new GLPaint();
|
||||||
|
glPaint.setColor(Color.BLUE);
|
||||||
|
canvasGL.drawRect(new Rect(10 * drawCnt - 20, 50, 10 * drawCnt, 100), glPaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
Log.d("TestVideoEncoder", "start: ");
|
||||||
|
h264Encoder.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (h264Encoder == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
h264Encoder.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStart() {
|
||||||
|
return h264Encoder != null && h264Encoder.isStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
try {
|
||||||
|
os.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (h264Encoder == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
h264Encoder.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean encodeAFrame() {
|
||||||
|
if (isStart()) {
|
||||||
|
Loggers.d("TestVideoEncoder", "writeAFrame");
|
||||||
|
h264Encoder.requestRenderAndWait();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write() {
|
||||||
|
MediaCodecInputStream mediaCodecInputStream = h264Encoder.getMediaCodecInputStream();
|
||||||
|
MediaCodecInputStream.readAll(mediaCodecInputStream, writeBuffer, new MediaCodecInputStream.OnReadAllCallback() {
|
||||||
|
@Override
|
||||||
|
public void onReadOnce(byte[] buffer, int readSize, MediaCodec.BufferInfo bufferInfo) {
|
||||||
|
Loggers.d("TestVideoEncoder", String.format("onReadOnce: readSize:%d", readSize));
|
||||||
|
if (readSize <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
os.write(buffer, 0, readSize);
|
||||||
|
os.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue