Skip to content

Commit 0f69538

Browse files
committed
To 1.0.2.0; Add MP4Muxer.
1 parent de0e502 commit 0f69538

File tree

14 files changed

+399
-46
lines changed

14 files changed

+399
-46
lines changed

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ allprojects {
2727
2828
// module build.gradle
2929
dependencies {
30-
compile 'com.github.ChillingVan:AndroidInstantVideo:v1.0.1.0'
30+
compile 'com.github.ChillingVan:AndroidInstantVideo:v1.0.2.0'
3131
}
3232
```
3333

@@ -137,11 +137,13 @@ public class TestCameraPublisherActivity extends AppCompatActivity {
137137
}
138138
```
139139

140-
### TODO
140+
### 最近更新
141+
1. 添加使用Android MediaMuxer的 Mp4Muxer,输出Mp4文件。例子 TestMp4MuxerActivity
142+
2. 修改 IMuxer 接口,使之更通用。给StreamPublisherParam添加更多参数。
141143

142-
1. 使用Android的muxer将h264和aac结合生成mp4文件, 最好实现 IMuxer 接口
144+
### TODO
143145

144-
2. RTSP流
146+
1. RTSP流
145147

146148
### 关于 Pull Request
147149

README_EN.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ allprojects {
2929
3030
// module build.gradle
3131
dependencies {
32-
compile 'com.github.ChillingVan:AndroidInstantVideo:v1.0.1.0'
32+
compile 'com.github.ChillingVan:AndroidInstantVideo:v1.0.2.0'
3333
}
3434
```
3535

@@ -137,11 +137,13 @@ public class TestCameraPublisherActivity extends AppCompatActivity {
137137
}
138138
```
139139

140-
### TODO
140+
### Latest Update:
141+
1. Add Mp4Muxer(Use Android MediaMuxer). Sample: TestMp4MuxerActivity
142+
2. Update Interface Imuxer. Add more parameters to StreamPublisherParam.
141143

142-
1. Android Default Muxer. Please implement IMuxer
144+
### TODO
143145

144-
2. RTSP Stream.
146+
1. RTSP Stream.
145147

146148
### Pull Request
147149

app/src/main/AndroidManifest.xml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,24 @@
5959
</activity>
6060
<activity
6161
android:name=".test.camera.TestCameraAndVideoActivity"
62-
android:label="TestCameraAndVideoActivity"
63-
>
62+
android:label="TestCameraAndVideoActivity">
63+
<intent-filter>
64+
<action android:name="android.intent.action.MAIN"/>
65+
66+
<category android:name="com.chillingvan.instantvideo.sample"/>
67+
</intent-filter>
68+
</activity>
69+
<activity
70+
android:name=".test.publisher.TestCameraPublisherActivity"
71+
android:label="TestCameraPublisherActivity">
6472
<intent-filter>
6573
<action android:name="android.intent.action.MAIN"/>
6674

6775
<category android:name="com.chillingvan.instantvideo.sample"/>
6876
</intent-filter>
6977
</activity>
70-
<activity android:name=".test.publisher.TestCameraPublisherActivity"
71-
android:label="TestCameraPublisherActivity"
78+
<activity android:name=".test.publisher.TestMp4MuxerActivity"
79+
android:label="TestMp4MuxerActivity"
7280
>
7381
<intent-filter>
7482
<action android:name="android.intent.action.MAIN"/>
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*
2+
*
3+
* *
4+
* * * Copyright (C) 2017 ChillingVan
5+
* * *
6+
* * * Licensed under the Apache License, Version 2.0 (the "License");
7+
* * * you may not use this file except in compliance with the License.
8+
* * * You may obtain a copy of the License at
9+
* * *
10+
* * * http://www.apache.org/licenses/LICENSE-2.0
11+
* * *
12+
* * * Unless required by applicable law or agreed to in writing, software
13+
* * * distributed under the License is distributed on an "AS IS" BASIS,
14+
* * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* * * See the License for the specific language governing permissions and
16+
* * * limitations under the License.
17+
* *
18+
*
19+
*/
20+
21+
package com.chillingvan.instantvideo.sample.test.publisher;
22+
23+
import android.graphics.SurfaceTexture;
24+
import android.hardware.Camera;
25+
import android.os.Bundle;
26+
import android.os.Handler;
27+
import android.os.HandlerThread;
28+
import android.os.Message;
29+
import android.support.annotation.Nullable;
30+
import android.support.v7.app.AppCompatActivity;
31+
import android.view.View;
32+
import android.widget.TextView;
33+
34+
import com.chillingvan.canvasgl.ICanvasGL;
35+
import com.chillingvan.canvasgl.Loggers;
36+
import com.chillingvan.canvasgl.glcanvas.BasicTexture;
37+
import com.chillingvan.canvasgl.glcanvas.RawTexture;
38+
import com.chillingvan.canvasgl.textureFilter.BasicTextureFilter;
39+
import com.chillingvan.canvasgl.textureFilter.HueFilter;
40+
import com.chillingvan.canvasgl.textureFilter.TextureFilter;
41+
import com.chillingvan.instantvideo.sample.R;
42+
import com.chillingvan.instantvideo.sample.test.camera.CameraPreviewTextureView;
43+
import com.chillingvan.lib.camera.InstantVideoCamera;
44+
import com.chillingvan.lib.encoder.video.H264Encoder;
45+
import com.chillingvan.lib.muxer.MP4Muxer;
46+
import com.chillingvan.lib.publisher.CameraStreamPublisher;
47+
import com.chillingvan.lib.publisher.StreamPublisher;
48+
49+
import java.io.IOException;
50+
51+
public class TestMp4MuxerActivity extends AppCompatActivity {
52+
53+
private CameraStreamPublisher streamPublisher;
54+
private CameraPreviewTextureView cameraPreviewTextureView;
55+
private InstantVideoCamera instantVideoCamera;
56+
private Handler handler;
57+
private HandlerThread handlerThread;
58+
private TextView outDirTxt;
59+
private String outputDir;
60+
61+
@Override
62+
protected void onCreate(Bundle savedInstanceState) {
63+
super.onCreate(savedInstanceState);
64+
outputDir = getExternalFilesDir(null) + "/test_mp4_encode.mp4";
65+
setContentView(R.layout.activity_test_mp4_muxer);
66+
cameraPreviewTextureView = (CameraPreviewTextureView) findViewById(R.id.camera_produce_view);
67+
cameraPreviewTextureView.setOnDrawListener(new H264Encoder.OnDrawListener() {
68+
@Override
69+
public void onGLDraw(ICanvasGL canvasGL, SurfaceTexture surfaceTexture, RawTexture rawTexture, @Nullable SurfaceTexture outsideSurfaceTexture, @Nullable BasicTexture outsideTexture) {
70+
drawVideoFrame(canvasGL, surfaceTexture, rawTexture);
71+
}
72+
});
73+
outDirTxt = (TextView) findViewById(R.id.output_dir_txt);
74+
outDirTxt.setText(outputDir);
75+
76+
77+
instantVideoCamera = new InstantVideoCamera(Camera.CameraInfo.CAMERA_FACING_FRONT, 640, 480);
78+
// instantVideoCamera = new InstantVideoCamera(Camera.CameraInfo.CAMERA_FACING_FRONT, 1280, 720);
79+
80+
handlerThread = new HandlerThread("StreamPublisherOpen");
81+
handlerThread.start();
82+
handler = new Handler(handlerThread.getLooper()) {
83+
@Override
84+
public void handleMessage(Message msg) {
85+
super.handleMessage(msg);
86+
// StreamPublisher.StreamPublisherParam streamPublisherParam = new StreamPublisher.StreamPublisherParam();
87+
// StreamPublisher.StreamPublisherParam streamPublisherParam = new StreamPublisher.StreamPublisherParam(1080, 640, 9500 * 1000, 30, 1, 44100, 19200);
88+
StreamPublisher.StreamPublisherParam streamPublisherParam = new StreamPublisher.StreamPublisherParam(540, 750, 1500 * 1000, 30, 1, 44100, 19200);
89+
streamPublisherParam.outputFilePath = outputDir;
90+
// streamPublisherParam.outputFilePath = getExternalFilesDir(null) + "/test_mp4_encode.mp4";
91+
streamPublisher.prepareEncoder(streamPublisherParam, new H264Encoder.OnDrawListener() {
92+
@Override
93+
public void onGLDraw(ICanvasGL canvasGL, SurfaceTexture surfaceTexture, RawTexture rawTexture, @Nullable SurfaceTexture outsideSurfaceTexture, @Nullable BasicTexture outsideTexture) {
94+
drawVideoFrame(canvasGL, outsideSurfaceTexture, outsideTexture);
95+
96+
Loggers.i("DEBUG", "gl draw");
97+
}
98+
});
99+
try {
100+
streamPublisher.startPublish();
101+
} catch (IOException e) {
102+
e.printStackTrace();
103+
((TextView)findViewById(R.id.test_camera_button)).setText("START");
104+
}
105+
}
106+
};
107+
108+
streamPublisher = new CameraStreamPublisher(new MP4Muxer(), cameraPreviewTextureView, instantVideoCamera);
109+
}
110+
111+
private void drawVideoFrame(ICanvasGL canvasGL, @Nullable SurfaceTexture outsideSurfaceTexture, @Nullable BasicTexture outsideTexture) {
112+
// Here you can do video process
113+
// 此处可以视频处理,例如加水印等等
114+
TextureFilter textureFilterLT = new BasicTextureFilter();
115+
TextureFilter textureFilterRT = new HueFilter(180);
116+
int width = outsideTexture.getWidth();
117+
int height = outsideTexture.getHeight();
118+
canvasGL.drawSurfaceTexture(outsideTexture, outsideSurfaceTexture, 0, 0, width /2, height /2, textureFilterLT);
119+
canvasGL.drawSurfaceTexture(outsideTexture, outsideSurfaceTexture, 0, height/2, width/2, height, textureFilterRT);
120+
121+
}
122+
123+
@Override
124+
protected void onResume() {
125+
super.onResume();
126+
streamPublisher.resumeCamera();
127+
}
128+
129+
@Override
130+
protected void onPause() {
131+
super.onPause();
132+
streamPublisher.pauseCamera();
133+
if (streamPublisher.isStart()) {
134+
streamPublisher.closeAll();
135+
}
136+
}
137+
138+
@Override
139+
protected void onDestroy() {
140+
super.onDestroy();
141+
handlerThread.quitSafely();
142+
}
143+
144+
public void clickStartTest(View view) {
145+
TextView textView = (TextView) view;
146+
if (streamPublisher.isStart()) {
147+
streamPublisher.closeAll();
148+
textView.setText("START");
149+
} else {
150+
streamPublisher.resumeCamera();
151+
handler.sendEmptyMessage(1);
152+
textView.setText("STOP");
153+
}
154+
}
155+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
~ /*
4+
~ *
5+
~ * * Copyright (C) 2017 ChillingVan
6+
~ * *
7+
~ * * Licensed under the Apache License, Version 2.0 (the "License");
8+
~ * * you may not use this file except in compliance with the License.
9+
~ * * You may obtain a copy of the License at
10+
~ * *
11+
~ * * http://www.apache.org/licenses/LICENSE-2.0
12+
~ * *
13+
~ * * Unless required by applicable law or agreed to in writing, software
14+
~ * * distributed under the License is distributed on an "AS IS" BASIS,
15+
~ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
~ * * See the License for the specific language governing permissions and
17+
~ * * limitations under the License.
18+
~ *
19+
~ */
20+
-->
21+
22+
<android.support.constraint.ConstraintLayout
23+
xmlns:android="http://schemas.android.com/apk/res/android"
24+
xmlns:app="http://schemas.android.com/apk/res-auto"
25+
xmlns:tools="http://schemas.android.com/tools"
26+
android:layout_width="match_parent"
27+
android:layout_height="match_parent"
28+
tools:context="com.chillingvan.instantvideo.sample.test.publisher.TestMp4MuxerActivity">
29+
30+
31+
<Button
32+
android:id="@+id/test_camera_button"
33+
android:layout_width="wrap_content"
34+
android:layout_height="wrap_content"
35+
android:text="record"
36+
android:layout_marginRight="8dp"
37+
app:layout_constraintRight_toRightOf="parent"
38+
android:layout_marginLeft="8dp"
39+
app:layout_constraintLeft_toLeftOf="parent"
40+
android:layout_marginBottom="8dp"
41+
android:layout_marginStart="8dp"
42+
android:layout_marginTop="8dp"
43+
android:layout_marginEnd="8dp"
44+
android:onClick="clickStartTest"
45+
app:layout_constraintHorizontal_bias="0.972"
46+
app:layout_constraintTop_toBottomOf="@+id/camera_produce_view"
47+
/>
48+
49+
50+
<com.chillingvan.instantvideo.sample.test.camera.CameraPreviewTextureView
51+
android:id="@+id/camera_produce_view"
52+
android:layout_width="0dp"
53+
android:layout_height="250dp"
54+
app:layout_constraintTop_toTopOf="parent"
55+
android:layout_marginTop="16dp"
56+
android:layout_marginLeft="8dp"
57+
app:layout_constraintLeft_toLeftOf="parent"
58+
android:layout_marginRight="8dp"
59+
app:layout_constraintRight_toRightOf="parent"
60+
android:layout_marginStart="8dp"
61+
android:layout_marginEnd="8dp"/>
62+
63+
<TextView
64+
android:id="@+id/output_dir_txt"
65+
android:layout_width="0dp"
66+
android:layout_height="wrap_content"
67+
android:layout_marginEnd="8dp"
68+
android:layout_marginLeft="8dp"
69+
app:layout_constraintLeft_toLeftOf="@+id/camera_produce_view"
70+
app:layout_constraintRight_toLeftOf="@+id/test_camera_button"
71+
android:layout_marginRight="8dp"
72+
android:layout_marginTop="0dp"
73+
app:layout_constraintTop_toBottomOf="@+id/camera_produce_view"/>
74+
75+
</android.support.constraint.ConstraintLayout>

applibs/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ android {
2929
defaultConfig {
3030
minSdkVersion 18
3131
targetSdkVersion 27
32-
versionCode 100010
33-
versionName "1.0.1.0"
32+
versionCode 100020
33+
versionName "1.0.2.0"
3434

3535
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
3636

applibs/src/main/java/com/chillingvan/lib/encoder/MediaCodecInputStream.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,17 @@ public class MediaCodecInputStream extends InputStream {
4040
public final String TAG = "MediaCodecInputStream";
4141

4242
private MediaCodec mMediaCodec = null;
43+
private MediaFormatCallback mediaFormatCallback;
4344
private BufferInfo mBufferInfo = new BufferInfo();
4445
private ByteBuffer mBuffer = null;
4546
private boolean mClosed = false;
4647

4748
public MediaFormat mMediaFormat;
4849
private ByteBuffer[] encoderOutputBuffers;
4950

50-
public MediaCodecInputStream(MediaCodec mediaCodec) {
51+
public MediaCodecInputStream(MediaCodec mediaCodec, MediaFormatCallback mediaFormatCallback) {
5152
mMediaCodec = mediaCodec;
53+
this.mediaFormatCallback = mediaFormatCallback;
5254
}
5355

5456
@Override
@@ -83,6 +85,9 @@ public int read(byte[] buffer, int offset, int length) throws IOException {
8385
break;
8486
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
8587
mMediaFormat = mMediaCodec.getOutputFormat();
88+
if (mediaFormatCallback != null) {
89+
mediaFormatCallback.onChangeMediaFormat(mMediaFormat);
90+
}
8691
Log.i(TAG, mMediaFormat.toString());
8792
} else if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
8893
Log.v(TAG, "No buffer available...");
@@ -131,15 +136,29 @@ public static void readAll(MediaCodecInputStream is, byte[] buffer, @NonNull OnR
131136
do {
132137
try {
133138
readSize = is.read(readBuf, 0, readBuf.length);
134-
onReadAllCallback.onReadOnce(readBuf, readSize, is.getLastBufferInfo());
139+
onReadAllCallback.onReadOnce(readBuf, readSize, copyBufferInfo(is.getLastBufferInfo()));
135140
} catch (IOException e) {
136141
e.printStackTrace();
137142
return;
138143
}
139144
} while (readSize > 0);
140145
}
141146

147+
@NonNull
148+
private static BufferInfo copyBufferInfo(BufferInfo lastBufferInfo) {
149+
BufferInfo bufferInfo = new BufferInfo();
150+
bufferInfo.presentationTimeUs = lastBufferInfo.presentationTimeUs;
151+
bufferInfo.flags = lastBufferInfo.flags;
152+
bufferInfo.offset = lastBufferInfo.offset;
153+
bufferInfo.size = lastBufferInfo.size;
154+
return bufferInfo;
155+
}
156+
142157
public interface OnReadAllCallback {
143158
void onReadOnce(byte[] buffer, int readSize, BufferInfo mediaBufferSize);
144159
}
160+
161+
public interface MediaFormatCallback {
162+
void onChangeMediaFormat(MediaFormat mediaFormat);
163+
}
145164
}

0 commit comments

Comments
 (0)