├── .gitignore
├── .idea
├── caches
│ └── build_file_checksums.ser
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── misc.xml
├── runConfigurations.xml
└── vcs.xml
├── DecodeH264
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── zjf
│ │ └── mediacodecdecodeh264demo
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── zjf
│ │ │ └── mediacodecdecodeh264demo
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── zjf
│ └── mediacodecdecodeh264demo
│ └── ExampleUnitTest.java
├── EncodeH264
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── encodeh264
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── encodeh264
│ │ │ ├── AvcEncoder.java
│ │ │ ├── Camera2Preview.java
│ │ │ ├── EncodeYUVToH264Activity2.java
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ ├── activity_encode_yuvto_h264.xml
│ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── encodeh264
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 |
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/DecodeH264/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/DecodeH264/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "com.example.zjf.mediacodecdecodeh264demo"
7 | minSdkVersion 15
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | implementation 'com.android.support:appcompat-v7:28.0.0'
24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
25 | testImplementation 'junit:junit:4.12'
26 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
28 | }
29 |
--------------------------------------------------------------------------------
/DecodeH264/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/DecodeH264/src/androidTest/java/com/example/zjf/mediacodecdecodeh264demo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.zjf.mediacodecdecodeh264demo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.example.zjf.mediacodecdecodeh264demo", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/DecodeH264/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/DecodeH264/src/main/java/com/example/zjf/mediacodecdecodeh264demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.zjf.mediacodecdecodeh264demo;
2 |
3 | import android.media.MediaCodec;
4 | import android.media.MediaFormat;
5 | import android.os.Build;
6 | import android.os.Environment;
7 | import android.support.annotation.RequiresApi;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.os.Bundle;
10 | import android.view.SurfaceHolder;
11 | import android.view.SurfaceView;
12 |
13 | import java.io.ByteArrayInputStream;
14 | import java.io.ByteArrayOutputStream;
15 | import java.io.DataInputStream;
16 | import java.io.File;
17 | import java.io.FileInputStream;
18 | import java.io.FileNotFoundException;
19 | import java.io.IOException;
20 | import java.io.InputStream;
21 | import java.nio.ByteBuffer;
22 |
23 | public class MainActivity extends AppCompatActivity {
24 | private static final String TAG = "MainActivity";
25 |
26 | private SurfaceView mSurfaceView;
27 | private SurfaceHolder mSurfaceHolder;
28 | private Thread mDecodeThread;
29 | private MediaCodec mCodec;
30 | private boolean mStopFlag = false;
31 | private DataInputStream mInputStream;
32 | private boolean UseSPSandPPS = false;
33 |
34 | private final static String SD_PATH = Environment.getExternalStorageDirectory().getPath();
35 | private final static String H264_FILE = SD_PATH + "/H264.h264";
36 |
37 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_main);
42 | mSurfaceView = (SurfaceView)findViewById(R.id.mSurfaceView);
43 | //获取文件输入流
44 | getFileInputStream();
45 | initMediaCodec();
46 | }
47 |
48 |
49 | /**
50 | * 获取需要解码的文件流
51 | */
52 | public void getFileInputStream() {
53 | try {
54 | File file = new File(H264_FILE);
55 | mInputStream = new DataInputStream(new FileInputStream(file));
56 | } catch (FileNotFoundException e) {
57 | e.printStackTrace();
58 | try {
59 | mInputStream.close();
60 | } catch (IOException e1) {
61 | e1.printStackTrace();
62 | }
63 | }
64 | }
65 |
66 | /**
67 | * 初始化解码器
68 | */
69 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
70 | private void initMediaCodec() {
71 | mSurfaceHolder = mSurfaceView.getHolder();
72 | mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
73 | @Override
74 | public void surfaceCreated(SurfaceHolder holder) {
75 | try {
76 | //创建编码器
77 | mCodec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
78 | } catch (IOException e) {
79 | e.printStackTrace();
80 | }
81 | //初始化编码器
82 | final MediaFormat mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC,holder.getSurfaceFrame().width(),holder.getSurfaceFrame().height());
83 | /*h264常见的帧头数据为:
84 | 00 00 00 01 67 (SPS)
85 | 00 00 00 01 68 (PPS)
86 | 00 00 00 01 65 (IDR帧)
87 | 00 00 00 01 61 (P帧)*/
88 |
89 | //获取H264文件中的pps和sps数据
90 | if (UseSPSandPPS) {
91 | byte[] header_sps = {0, 0, 0, 1, 67, 66, 0, 42, (byte) 149, (byte) 168, 30, 0, (byte) 137, (byte) 249, 102, (byte) 224, 32, 32, 32, 64};
92 | byte[] header_pps = {0, 0, 0, 1, 68, (byte) 206, 60, (byte) 128, 0, 0, 0, 1, 6, (byte) 229, 1, (byte) 151, (byte) 128};
93 | mediaFormat.setByteBuffer("csd-0", ByteBuffer.wrap(header_sps));
94 | mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(header_pps));
95 | }
96 |
97 | //设置帧率
98 | mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE,40);
99 | mCodec.configure(mediaFormat,holder.getSurface(),null,0);
100 |
101 | startDecodingThread();
102 | }
103 |
104 | @Override
105 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
106 |
107 | }
108 |
109 | @Override
110 | public void surfaceDestroyed(SurfaceHolder holder) {
111 |
112 | }
113 | });
114 | }
115 |
116 | /**
117 | * 开启解码器并开启读取文件的线程
118 | */
119 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
120 | private void startDecodingThread(){
121 | mCodec.start();
122 | mDecodeThread = new Thread(new DecodeThread());
123 | mDecodeThread.start();
124 | }
125 |
126 |
127 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
128 | private class DecodeThread implements Runnable{
129 |
130 | @Override
131 | public void run() {
132 | //循环解码
133 | decodeLoop();
134 | }
135 |
136 |
137 | private void decodeLoop(){
138 | //获取一组输入缓存区
139 | ByteBuffer[] inputBuffers = mCodec.getInputBuffers();
140 | //解码后的数据,包含每一个buffer的元数据信息
141 | MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
142 | long startMs = System.currentTimeMillis();
143 | long timeoutUs = 10000;
144 | //用于检测文件头
145 | byte[] maker0 = new byte[]{0,0,0,1};
146 |
147 | byte[] dummyFrame = new byte[]{0x00,0x00,0x01,0x20};
148 | byte[] streamBuffer = null;
149 |
150 | try {
151 | //返回可用的字节数组
152 | streamBuffer = getBytes(mInputStream);
153 | } catch (IOException e) {
154 | e.printStackTrace();
155 | }
156 | int bytes_cnt = 0;
157 | while (mStopFlag == false){
158 | //得到可用字节数组长度
159 | bytes_cnt = streamBuffer.length;
160 |
161 | if (bytes_cnt == 0){
162 | streamBuffer = dummyFrame;
163 | }
164 | int startIndex = 0;
165 | //定义记录剩余字节的变量
166 | int remaining = bytes_cnt;
167 | while (true) {
168 | //当剩余的字节=0或者开始的读取的字节下标大于可用的字节数时 不在继续读取
169 | if (remaining == 0 || startIndex >= remaining) {
170 | break;
171 | }
172 | //寻找帧头部
173 | int nextFrameStart = KMPMatch(maker0,streamBuffer,startIndex + 2,remaining);
174 | //找不到头部返回-1
175 | if (nextFrameStart == -1) {
176 | nextFrameStart = remaining;
177 | }
178 | //得到可用的缓存区
179 | int inputIndex = mCodec.dequeueInputBuffer(timeoutUs);
180 | //有可用缓存区
181 | if (inputIndex >= 0) {
182 | ByteBuffer byteBuffer = inputBuffers[inputIndex];
183 | byteBuffer.clear();
184 | //将可用的字节数组,传入缓冲区
185 | byteBuffer.put(streamBuffer, startIndex, nextFrameStart - startIndex);
186 | //把数据传递给解码器
187 | mCodec.queueInputBuffer(inputIndex, 0, nextFrameStart - startIndex, 0, 0);
188 | //指定下一帧的位置
189 | startIndex = nextFrameStart;
190 | } else {
191 | continue;
192 | }
193 |
194 | int outputIndex = mCodec.dequeueOutputBuffer(info,timeoutUs);
195 | if (outputIndex >= 0) {
196 | //帧控制是不在这种情况下工作,因为没有PTS H264是可用的
197 | while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) {
198 | try {
199 | Thread.sleep(100);
200 | } catch (InterruptedException e) {
201 | e.printStackTrace();
202 | }
203 | }
204 | boolean doRender = (info.size != 0);
205 | //对outputbuffer的处理完后,调用这个函数把buffer重新返回给codec类。
206 | mCodec.releaseOutputBuffer(outputIndex, doRender);
207 | } else {
208 |
209 | }
210 | }
211 | mStopFlag = true;
212 | }
213 | }
214 | }
215 | /**
216 | * 获得可用的字节数组
217 | * @param is
218 | * @return
219 | * @throws IOException
220 | */
221 | public static byte[] getBytes(InputStream is) throws IOException {
222 | int len;
223 | int size = 1024;
224 | byte[] buf;
225 | if (is instanceof ByteArrayInputStream) {
226 | //返回可用的剩余字节
227 | size = is.available();
228 | //创建一个对应可用相应字节的字节数组
229 | buf = new byte[size];
230 | //读取这个文件并保存读取的长度
231 | len = is.read(buf, 0, size);
232 | } else {
233 | ByteArrayOutputStream bos = new ByteArrayOutputStream();
234 | buf = new byte[size];
235 | while ((len = is.read(buf, 0, size)) != -1)
236 | //将读取的数据写入到字节输出流
237 | bos.write(buf, 0, len);
238 | //将这个流转换成字节数组
239 | buf = bos.toByteArray();
240 | }
241 | return buf;
242 | }
243 |
244 |
245 | /**
246 | * 查找帧头部的位置
247 | * @param pattern 文件头字节数组
248 | * @param bytes 可用的字节数组
249 | * @param start 开始读取的下标
250 | * @param remain 可用的字节数量
251 | * @return
252 | */
253 | private int KMPMatch(byte[] pattern, byte[] bytes, int start, int remain) {
254 | try {
255 | Thread.sleep(30);
256 | } catch (InterruptedException e) {
257 | e.printStackTrace();
258 | }
259 | int[] lsp = computeLspTable(pattern);
260 |
261 | int j = 0; // Number of chars matched in pattern
262 | for (int i = start; i < remain; i++) {
263 | while (j > 0 && bytes[i] != pattern[j]) {
264 | // Fall back in the pattern
265 | j = lsp[j - 1]; // Strictly decreasing
266 | }
267 | if (bytes[i] == pattern[j]) {
268 | // Next char matched, increment position
269 | j++;
270 | if (j == pattern.length)
271 | return i - (j - 1);
272 | }
273 | }
274 |
275 | return -1; // Not found
276 | }
277 |
278 | // 0 1 2 0
279 | private int[] computeLspTable(byte[] pattern) {
280 | int[] lsp = new int[pattern.length];
281 | lsp[0] = 0; // Base case
282 | for (int i = 1; i < pattern.length; i++) {
283 | // Start by assuming we're extending the previous LSP
284 | int j = lsp[i - 1];
285 | while (j > 0 && pattern[i] != pattern[j])
286 | j = lsp[j - 1];
287 | if (pattern[i] == pattern[j])
288 | j++;
289 | lsp[i] = j;
290 | }
291 | return lsp;
292 | }
293 | }
294 |
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/DecodeH264/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/DecodeH264/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/DecodeH264/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/DecodeH264/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/DecodeH264/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/DecodeH264/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/DecodeH264/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/DecodeH264/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/DecodeH264/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/DecodeH264/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MediaCodecDecodeH264Demo
3 |
4 |
--------------------------------------------------------------------------------
/DecodeH264/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/DecodeH264/src/test/java/com/example/zjf/mediacodecdecodeh264demo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.zjf.mediacodecdecodeh264demo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/EncodeH264/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/EncodeH264/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 |
6 |
7 |
8 | defaultConfig {
9 | applicationId "com.example.encodeh264"
10 | minSdkVersion 15
11 | targetSdkVersion 28
12 | versionCode 1
13 | versionName "1.0"
14 |
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 |
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 |
26 | }
27 |
28 | dependencies {
29 | implementation fileTree(dir: 'libs', include: ['*.jar'])
30 |
31 | implementation 'com.android.support:appcompat-v7:28.0.0'
32 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
33 | testImplementation 'junit:junit:4.12'
34 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
35 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
36 | }
37 |
--------------------------------------------------------------------------------
/EncodeH264/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/EncodeH264/src/androidTest/java/com/example/encodeh264/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.encodeh264;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.example.encodeh264", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/java/com/example/encodeh264/AvcEncoder.java:
--------------------------------------------------------------------------------
1 | package com.example.encodeh264;
2 |
3 | import android.media.MediaCodec;
4 | import android.media.MediaCodecInfo;
5 | import android.media.MediaFormat;
6 | import android.os.Build;
7 | import android.support.annotation.RequiresApi;
8 |
9 | import java.io.BufferedOutputStream;
10 | import java.io.File;
11 | import java.io.FileNotFoundException;
12 | import java.io.FileOutputStream;
13 | import java.io.IOException;
14 | import java.nio.ByteBuffer;
15 | import java.util.concurrent.ArrayBlockingQueue;
16 |
17 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
18 | public class AvcEncoder {
19 | private static final String TAG = "AvcEncoder";
20 | private int TIMEOUT_USEC = 12000;
21 | private int mYuvQueueSize = 10;
22 |
23 | public ArrayBlockingQueue mYuvQueue = new ArrayBlockingQueue<>(mYuvQueueSize);
24 |
25 | private MediaCodec mMediaCodec;
26 | private int mWidth;
27 | private int mHeight;
28 | private int mFrameRate;
29 |
30 | private File mOutFile;
31 | //true--Camera的预览数据编码
32 | // false--Camera2的预览数据编码
33 | private boolean mIsCamera;
34 |
35 | public byte[] mConfigByte;
36 |
37 |
38 | public AvcEncoder(int width, int height, int frameRate, File outFile, boolean isCamera){
39 | mIsCamera = isCamera;
40 | mWidth = width;
41 | mHeight = height;
42 | mFrameRate = frameRate;
43 | mOutFile = outFile;
44 |
45 | MediaFormat mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC,width,height);
46 | mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
47 | mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE,width * height * 5);
48 | mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE,30);
49 | mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,1);
50 |
51 | try {
52 | mMediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
53 | } catch (IOException e) {
54 | e.printStackTrace();
55 | }
56 | mMediaCodec.configure(mediaFormat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE);
57 | mMediaCodec.start();
58 | createFile();
59 | }
60 |
61 | private BufferedOutputStream outputStream;
62 | private void createFile() {
63 | try {
64 | outputStream = new BufferedOutputStream(new FileOutputStream(mOutFile));
65 | } catch (FileNotFoundException e) {
66 | e.printStackTrace();
67 | }
68 | }
69 |
70 | private void stopEncoder(){
71 | if (mMediaCodec != null) {
72 | mMediaCodec.stop();
73 | mMediaCodec.release();
74 | mMediaCodec = null;
75 | }
76 | }
77 |
78 | public void putYUVData(byte[] buffer) {
79 | if (mYuvQueue.size() >= 10) {
80 | mYuvQueue.poll();
81 | }
82 | mYuvQueue.add(buffer);
83 | }
84 |
85 | public void stopThread(){
86 | if (!isRunning) return;
87 | isRunning = false;
88 | try {
89 | stopEncoder();
90 | if (outputStream != null) {
91 | outputStream.flush();
92 | outputStream.close();
93 | outputStream = null;
94 | }
95 | } catch (IOException e) {
96 | e.printStackTrace();
97 | }
98 |
99 | }
100 |
101 | public boolean isRunning = false;
102 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
103 | public void startEncoderThread(){
104 | Thread encoderThread = new Thread(new Runnable() {
105 | @Override
106 | public void run() {
107 | isRunning = true;
108 | byte[] input = null;
109 | long pts = 0;
110 | long generateIndex = 0;
111 |
112 | while (isRunning) {
113 | if (mYuvQueue.size() > 0) {
114 | input = mYuvQueue.poll();
115 | if (mIsCamera) {//Camera NV21
116 | //NV12数据所需空间为如下,所以建立如下缓冲区
117 | //y=W*h;u=W*H/4;v=W*H/4,so total add is W*H*3/2 (1 + 1/4 + 1/4 = 3/2)
118 | byte[] yuv420sp = new byte[mWidth * mHeight *3 /2];
119 | NV21ToNV12(input, yuv420sp, mWidth, mHeight);
120 | input = yuv420sp;
121 | } else {//Camera 2
122 | byte[] yuv420sp = new byte[mWidth * mHeight *3 /2];
123 | YV12toNV12(input, yuv420sp, mWidth, mHeight);
124 | input = yuv420sp;
125 | }
126 | }
127 |
128 | if (input != null) {
129 | int inputBufferIndex = mMediaCodec.dequeueInputBuffer(-1);
130 | if (inputBufferIndex >= 0) {
131 | pts = computePresentationTime(generateIndex);
132 | ByteBuffer inputBuffer = mMediaCodec.getInputBuffer(inputBufferIndex);
133 | inputBuffer.clear();
134 | inputBuffer.put(input);
135 | mMediaCodec.queueInputBuffer(inputBufferIndex,0,input.length,pts,0);
136 | generateIndex += 1;
137 | }
138 |
139 | MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
140 | int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo,TIMEOUT_USEC);
141 | while (outputBufferIndex >= 0) {
142 | ByteBuffer outputBuffer = mMediaCodec.getOutputBuffer(outputBufferIndex);
143 | byte[] outData = new byte[bufferInfo.size];
144 | outputBuffer.get(outData);
145 | if (bufferInfo.flags == 2) {
146 | mConfigByte = new byte[bufferInfo.size];
147 | mConfigByte = outData;
148 | } else if (bufferInfo.flags == 1) {
149 | byte[] keyframe = new byte[bufferInfo.size + mConfigByte.length];
150 | System.arraycopy(mConfigByte, 0, keyframe, 0, mConfigByte.length);
151 | System.arraycopy(outData, 0, keyframe, mConfigByte.length, outData.length);
152 | try {
153 | outputStream.write(keyframe, 0, keyframe.length);
154 | } catch (IOException e) {
155 | e.printStackTrace();
156 | }
157 | } else {
158 | try {
159 | outputStream.write(outData, 0, outData.length);
160 | } catch (IOException e) {
161 | e.printStackTrace();
162 | }
163 | }
164 |
165 | mMediaCodec.releaseOutputBuffer(outputBufferIndex,false);
166 | outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo,TIMEOUT_USEC);
167 | }
168 | } else {
169 | try {
170 | Thread.sleep(500);
171 | } catch (InterruptedException e) {
172 | e.printStackTrace();
173 | }
174 | }
175 | }
176 | }
177 | });
178 | encoderThread.start();
179 | }
180 |
181 | private void NV21ToNV12(byte[] nv21, byte[] nv12, int width, int height) {
182 | if (nv21 == null || nv12 == null) return;
183 | int framesize = width * height;
184 | int i = 0, j = 0;
185 | System.arraycopy(nv21, 0, nv12, 0, framesize);
186 | for (i = 0; i < framesize; i++) {
187 | nv12[i] = nv21[i];
188 | }
189 | for (j = 0; j < framesize / 2; j += 2) {
190 | nv12[framesize + j - 1] = nv21[j + framesize];
191 | }
192 | for (j = 0; j < framesize / 2; j += 2) {
193 | nv12[framesize + j] = nv21[j + framesize - 1];
194 | }
195 | }
196 |
197 | private void YV12toNV12(byte[] yv12bytes, byte[] nv12bytes, int width, int height) {
198 |
199 | int nLenY = width * height;
200 | int nLenU = nLenY / 4;
201 |
202 |
203 | System.arraycopy(yv12bytes, 0, nv12bytes, 0, width * height);
204 | for (int i = 0; i < nLenU; i++) {
205 | nv12bytes[nLenY + 2 * i] = yv12bytes[nLenY + i];
206 | nv12bytes[nLenY + 2 * i + 1] = yv12bytes[nLenY + nLenU + i];
207 | }
208 | }
209 |
210 | /**
211 | * Generates the presentation time for frame N, in microseconds.
212 | */
213 | private long computePresentationTime(long frameIndex) {
214 | return 132 + frameIndex * 1000000 / mFrameRate;
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/java/com/example/encodeh264/Camera2Preview.java:
--------------------------------------------------------------------------------
1 | package com.example.encodeh264;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.pm.PackageManager;
7 | import android.graphics.ImageFormat;
8 | import android.graphics.Matrix;
9 | import android.graphics.RectF;
10 | import android.graphics.SurfaceTexture;
11 | import android.hardware.camera2.CameraAccessException;
12 | import android.hardware.camera2.CameraCaptureSession;
13 | import android.hardware.camera2.CameraCharacteristics;
14 | import android.hardware.camera2.CameraDevice;
15 | import android.hardware.camera2.CameraManager;
16 | import android.hardware.camera2.CameraMetadata;
17 | import android.hardware.camera2.CaptureRequest;
18 | import android.hardware.camera2.params.StreamConfigurationMap;
19 | import android.media.Image;
20 | import android.media.ImageReader;
21 | import android.os.Build;
22 | import android.os.Environment;
23 | import android.os.Handler;
24 | import android.os.HandlerThread;
25 | import android.support.annotation.NonNull;
26 | import android.support.annotation.RequiresApi;
27 | import android.support.v4.app.ActivityCompat;
28 | import android.text.TextUtils;
29 | import android.util.AttributeSet;
30 | import android.util.Log;
31 | import android.util.Size;
32 | import android.view.Surface;
33 | import android.view.TextureView;
34 | import android.widget.Toast;
35 |
36 | import java.io.File;
37 | import java.io.IOException;
38 | import java.nio.ByteBuffer;
39 | import java.text.SimpleDateFormat;
40 | import java.util.ArrayList;
41 | import java.util.Arrays;
42 | import java.util.Collections;
43 | import java.util.Comparator;
44 | import java.util.Date;
45 | import java.util.List;
46 |
47 | import static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE;
48 | import static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;
49 |
50 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
51 | public class Camera2Preview extends TextureView {
52 | private static final String TAG = "Camera2Preview";
53 | private Handler mBackgroundHandler;
54 | private HandlerThread mBackgroundThread;
55 | private CameraManager mCameraManager;
56 | private CameraDevice mCameraDevice;
57 | protected CameraCaptureSession mCameraCaptureSessions;
58 | protected CaptureRequest.Builder mPreviewRequestBuilder;
59 | private ImageReader mImageReader;
60 | private Context mContext;
61 |
62 | private Size mPreviewSize;
63 |
64 | private static final String CAMERA_FONT = "0";
65 | private static final String CAMERA_BACK = "1";
66 | private String mCameraId;
67 | public Camera2Preview(Context context) {
68 | this(context, null);
69 | }
70 |
71 |
72 | public Camera2Preview(Context context, AttributeSet attrs) {
73 | this(context, attrs, 0);
74 | }
75 |
76 |
77 | public Camera2Preview(Context context, AttributeSet attrs, int defStyleAttr) {
78 | super(context, attrs, defStyleAttr);
79 | this.mContext = context;
80 | setKeepScreenOn(true);
81 | getDefaultCameraId();
82 | }
83 |
84 | SurfaceTextureListener textureListener = new SurfaceTextureListener(){
85 |
86 | @Override
87 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
88 | //开启摄像头
89 | setupCamera();
90 | }
91 |
92 | @Override
93 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
94 |
95 | }
96 |
97 | @Override
98 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
99 | return false;
100 | }
101 |
102 | @Override
103 | public void onSurfaceTextureUpdated(SurfaceTexture surface) {
104 |
105 | }
106 | };
107 |
108 | public void onResume(){
109 | Log.e(TAG, "onResume");
110 | startBackgroundThread();
111 | if (isAvailable()) {
112 | setupCamera();
113 | } else {
114 | setSurfaceTextureListener(textureListener);
115 | }
116 | }
117 |
118 |
119 | public void onPause() {
120 | Log.e(TAG, "onPause");
121 | if (mAvcEncoder != null) {
122 | mAvcEncoder.stopThread();
123 | mAvcEncoder = null;
124 | }
125 | closeCamera();
126 | stopBackgroundThread();
127 | }
128 |
129 | private void stopBackgroundThread() {
130 | mBackgroundThread.quitSafely();
131 | try {
132 | mBackgroundThread.join();
133 | mBackgroundThread = null;
134 | mBackgroundHandler = null;
135 | } catch (InterruptedException e) {
136 | e.printStackTrace();
137 | }
138 |
139 | }
140 |
141 | private void closeCamera() {
142 | closePreviewSession();
143 |
144 | if (null != mCameraDevice) {
145 | mCameraDevice.close();
146 | mCameraDevice = null;
147 | }
148 |
149 | if (null != mImageReader) {
150 | mImageReader.close();
151 | mImageReader = null;
152 | }
153 | }
154 |
155 | private void closePreviewSession() {
156 | if (null != mCameraCaptureSessions) {
157 | mCameraCaptureSessions.close();
158 | mCameraCaptureSessions = null;
159 | }
160 | }
161 |
162 | /**
163 | * 开启摄像机线程
164 | */
165 | private void startBackgroundThread() {
166 | mBackgroundThread = new HandlerThread("Camera Background");
167 | mBackgroundThread.start();
168 | mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
169 |
170 | }
171 |
172 | /**
173 | * 开启摄像头
174 | */
175 | private void setupCamera() {
176 | Log.e(TAG,"setupCamera START");
177 | if (mCameraManager == null) {
178 | Log.e(TAG,"尚未得到CameraManager");
179 | return;
180 | }
181 | try {
182 | //获取相机特征对象
183 | CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(mCameraId);
184 | //获取相机输出流配置
185 | StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
186 | assert map != null;
187 | //获取预览输出尺寸
188 | mPreviewSize = getPreferredPreviewSize(map.getOutputSizes(SurfaceTexture.class),getWidth(),getHeight());
189 | Log.e(TAG, "setupCamera: best preview size width=" + mPreviewSize.getWidth()
190 | + ",height=" + mPreviewSize.getHeight());
191 | transformImage(getWidth(),getHeight());
192 |
193 | if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
194 | return;
195 | }
196 |
197 | setupImageReader();
198 | mCameraManager.openCamera(mCameraId,stateCallback,null);
199 | } catch (CameraAccessException e) {
200 | e.printStackTrace();
201 | }
202 | Log.e(TAG,"setupCamera END");
203 | }
204 |
205 |
206 | private Size getPreferredPreviewSize(Size[] mapSizes, int width, int height) {
207 | Log.e(TAG, "getPreferredPreviewSize: surface width=" + width + ",surface height=" + height);
208 | List collectorSizes = new ArrayList<>();
209 | for (Size option : mapSizes) {
210 | if (width > height) {
211 | if (option.getWidth() > width &&
212 | option.getHeight() > height) {
213 | collectorSizes.add(option);
214 | }
215 | } else {
216 | if (option.getWidth() > height &&
217 | option.getHeight() > width) {
218 | collectorSizes.add(option);
219 | }
220 | }
221 | }
222 | if (collectorSizes.size() > 0) {
223 | return Collections.min(collectorSizes, new Comparator() {
224 | @Override
225 | public int compare(Size lhs, Size rhs) {
226 | return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getWidth() * rhs.getHeight());
227 | }
228 | });
229 | }
230 | Log.e(TAG, "getPreferredPreviewSize: best width=" +
231 | mapSizes[0].getWidth() + ",height=" + mapSizes[0].getHeight());
232 | return mapSizes[0];
233 | }
234 |
235 |
236 | private void transformImage(int width, int height) {
237 | Matrix matrix = new Matrix();
238 | int rotation = ((Activity) mContext).getWindowManager().getDefaultDisplay().getRotation();
239 | RectF textureRectF = new RectF(0, 0, width, height);
240 | RectF previewRectF = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
241 | float centerX = textureRectF.centerX();
242 | float centerY = textureRectF.centerY();
243 | if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
244 | previewRectF.offset(centerX - previewRectF.centerX(),
245 | centerY - previewRectF.centerY());
246 | matrix.setRectToRect(textureRectF, previewRectF, Matrix.ScaleToFit.FILL);
247 | float scale = Math.max((float) width / mPreviewSize.getWidth(),
248 | (float) height / mPreviewSize.getHeight());
249 | matrix.postScale(scale, scale, centerX, centerY);
250 | matrix.postRotate(90 * (rotation - 2), centerX, centerY);
251 | }
252 | setTransform(matrix);
253 | }
254 |
255 | private static final int STATE_PREVIEW = 0;
256 | private static final int STATE_RECORD = 1;
257 | private int mState = STATE_PREVIEW;
258 | private AvcEncoder mAvcEncoder;
259 | private int mFrameRate = 30;
260 |
261 | private void setupImageReader() {
262 | //2代表ImageReader中最多可以获取两帧图像流
263 | mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(),mPreviewSize.getHeight(), ImageFormat.YV12,1);
264 | mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
265 | @Override
266 | public void onImageAvailable(ImageReader reader) {
267 | Log.e(TAG, "onImageAvailable: "+Thread.currentThread().getName() );
268 | //这里一定要调用reader.acquireNextImage()和img.close方法否则不会一直回掉了
269 | Image img = reader.acquireNextImage();
270 | switch (mState){
271 | case STATE_PREVIEW:
272 | Log.e(TAG, "mState: STATE_PREVIEW");
273 | if (mAvcEncoder != null) {
274 | mAvcEncoder.stopThread();
275 | mAvcEncoder = null;
276 | Toast.makeText(mContext,"停止录制视频成功",Toast.LENGTH_SHORT).show();
277 | }
278 | break;
279 | case STATE_RECORD:
280 | Log.e(TAG, "mState: STATE_RECORD");
281 | Image.Plane[] planes = img.getPlanes();
282 | byte[] dataYUV = null;
283 | if (planes.length >= 3) {
284 | ByteBuffer bufferY = planes[0].getBuffer();
285 | ByteBuffer bufferU = planes[1].getBuffer();
286 | ByteBuffer bufferV = planes[2].getBuffer();
287 | int lengthY = bufferY.remaining();
288 | int lengthU = bufferU.remaining();
289 | int lengthV = bufferV.remaining();
290 | dataYUV = new byte[lengthY + lengthU + lengthV];
291 | bufferY.get(dataYUV, 0, lengthY);
292 | bufferU.get(dataYUV, lengthY, lengthU);
293 | bufferV.get(dataYUV, lengthY + lengthU, lengthV);
294 | }
295 |
296 | if (mAvcEncoder == null) {
297 | mAvcEncoder = new AvcEncoder(mPreviewSize.getWidth(),
298 | mPreviewSize.getHeight(), mFrameRate,
299 | getOutputMediaFile(MEDIA_TYPE_VIDEO), false);
300 | mAvcEncoder.startEncoderThread();
301 | Toast.makeText(mContext, "开始录制视频成功", Toast.LENGTH_SHORT).show();
302 | }
303 | mAvcEncoder.putYUVData(dataYUV);
304 | break;
305 | default:
306 | break;
307 | }
308 | img.close();
309 | }
310 | },mBackgroundHandler);
311 | }
312 |
313 | /**
314 | * 获取输出照片视频路径
315 | *
316 | * @param mediaType
317 | * @return
318 | */
319 | public File getOutputMediaFile(int mediaType) {
320 | String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
321 | String fileName = null;
322 | File storageDir = null;
323 | if (mediaType == MEDIA_TYPE_IMAGE) {
324 | fileName = "JPEG_" + timeStamp + "_";
325 | storageDir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
326 | } else if (mediaType == MEDIA_TYPE_VIDEO) {
327 | fileName = "MP4_" + timeStamp + "_";
328 | storageDir = mContext.getExternalFilesDir(Environment.DIRECTORY_MOVIES);
329 | }
330 |
331 | // Create the storage directory if it does not exist
332 | if (!storageDir.exists()) {
333 | if (!storageDir.mkdirs()) {
334 | Log.d(TAG, "failed to create directory");
335 | return null;
336 | }
337 | }
338 |
339 | File file = null;
340 | try {
341 | file = File.createTempFile(
342 | fileName, /* prefix */
343 | (mediaType == MEDIA_TYPE_IMAGE) ? ".jpg" : ".h264", /* suffix */
344 | storageDir /* directory */
345 | );
346 | Log.d(TAG, "getOutputMediaFile: absolutePath==" + file.getAbsolutePath());
347 | } catch (IOException e) {
348 | e.printStackTrace();
349 | }
350 | return file;
351 | }
352 |
353 |
354 | private void getDefaultCameraId() {
355 | mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
356 | try {
357 | String[] cameraList = mCameraManager.getCameraIdList();
358 | for (int i = 0;i < cameraList.length;i++) {
359 | String cameraId = cameraList[i];
360 | if (TextUtils.equals(cameraId,CAMERA_FONT)) {
361 | mCameraId = cameraId;
362 | break;
363 | } else if (TextUtils.equals(cameraId,CAMERA_BACK)) {
364 | mCameraId = cameraId;
365 | break;
366 | }
367 | }
368 | } catch (CameraAccessException e) {
369 | e.printStackTrace();
370 | }
371 | }
372 |
373 | private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
374 | @Override
375 | public void onOpened(@NonNull CameraDevice camera) {
376 | Log.e(TAG,"onOpened...");
377 | mCameraDevice = camera;
378 | createCameraPreview();
379 | }
380 |
381 | @Override
382 | public void onDisconnected(@NonNull CameraDevice camera) {
383 | mCameraDevice.close();
384 | }
385 |
386 | @Override
387 | public void onError(@NonNull CameraDevice camera, int error) {
388 | mCameraDevice.close();
389 | mCameraDevice = null;
390 | }
391 | };
392 |
393 | /**
394 | * 创建预览界面
395 | */
396 | private void createCameraPreview() {
397 | try {
398 | Log.e(TAG,"createCameraPreview");
399 | //获取当前TextureView的SurfaceTexture
400 | SurfaceTexture texture = getSurfaceTexture();
401 | assert texture != null;
402 | //设置SurfaceTexture默认的缓存区大小,为 上面得到的预览的size大小
403 | texture.setDefaultBufferSize(mPreviewSize.getWidth(),mPreviewSize.getHeight());
404 | Surface surface = new Surface(texture);
405 | //创建CaptureRequest对象,并且声明类型为TEMPLATE_PREVIEW,可以看出是一个预览类型
406 |
407 | mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
408 |
409 | //CaptureRequest.
410 | //设置请求的结果返回到到Surface上
411 | mPreviewRequestBuilder.addTarget(surface);
412 |
413 | mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
414 |
415 | //创建CaptureSession对象
416 | mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {
417 | @Override
418 | public void onConfigured(@NonNull CameraCaptureSession session) {
419 | //The camera is already closed
420 | if (null == mCameraDevice) {
421 | return;
422 | }
423 | Log.e(TAG, "onConfigured: ");
424 | // When the session is ready, we start displaying the preview.
425 | mCameraCaptureSessions = session;
426 | //更新预览
427 | updatePreview();
428 | }
429 |
430 | @Override
431 | public void onConfigureFailed(@NonNull CameraCaptureSession session) {
432 | Toast.makeText(mContext, "Configuration change", Toast.LENGTH_SHORT).show();
433 | }
434 | },null);
435 | }catch (CameraAccessException e){
436 | e.printStackTrace();
437 | }
438 | }
439 |
440 | /**
441 | * 更新预览
442 | */
443 | private void updatePreview() {
444 | if (null == mCameraDevice) {
445 | Log.e(TAG, "updatePreview error, return");
446 | }
447 | Log.e(TAG, "updatePreview: ");
448 | //设置相机的控制模式为自动,方法具体含义点进去(auto-exposure, auto-white-balance, auto-focus)
449 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
450 | try {
451 | //设置重复捕获图片信息
452 | mCameraCaptureSessions.setRepeatingRequest(mPreviewRequestBuilder.build(), null, mBackgroundHandler);
453 | } catch (CameraAccessException e) {
454 | e.printStackTrace();
455 | }
456 | }
457 |
458 | public boolean toggleVideo() {
459 | if (mState == STATE_PREVIEW) {
460 | mState = STATE_RECORD;
461 | return true;
462 | } else {
463 | mState = STATE_PREVIEW;
464 | return false;
465 | }
466 | }
467 |
468 | }
469 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/java/com/example/encodeh264/EncodeYUVToH264Activity2.java:
--------------------------------------------------------------------------------
1 | package com.example.encodeh264;
2 |
3 | import android.Manifest;
4 | import android.content.pm.PackageManager;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 | import android.support.annotation.NonNull;
8 | import android.support.annotation.Nullable;
9 | import android.support.annotation.RequiresApi;
10 | import android.support.v4.app.ActivityCompat;
11 | import android.support.v4.content.ContextCompat;
12 | import android.support.v7.app.AppCompatActivity;
13 | import android.view.View;
14 | import android.widget.Button;
15 | import android.widget.FrameLayout;
16 | import android.widget.Toast;
17 |
18 | public class EncodeYUVToH264Activity2 extends AppCompatActivity {
19 | private static final String TAG = "EncodeYUVToH262Activity2";
20 | private static final int REQUEST_CAMERA = 1;
21 | private Camera2Preview camera2Preview;
22 | private Button mRecordBtn;
23 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
24 | @Override
25 | protected void onCreate(@Nullable Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_encode_yuvto_h264);
28 | mRecordBtn = (Button)findViewById(R.id.record_btn);
29 | requestPermissions();
30 | }
31 |
32 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
33 | private void requestPermissions() {
34 | if (ContextCompat.checkSelfPermission(this,
35 | Manifest.permission.CAMERA)
36 | != PackageManager.PERMISSION_GRANTED) {
37 | ActivityCompat.requestPermissions(this,
38 | new String[]{Manifest.permission.CAMERA},
39 | REQUEST_CAMERA);
40 | } else {
41 | initCameraView();
42 | }
43 | }
44 |
45 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
46 | @Override
47 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
48 | switch (requestCode) {
49 | case REQUEST_CAMERA: {
50 | if (grantResults.length > 0
51 | && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
52 | initCameraView();
53 | } else {
54 | Toast.makeText(this, "权限请求失败", Toast.LENGTH_SHORT).show();
55 | finish();
56 | }
57 | return;
58 | }
59 | }
60 | }
61 |
62 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
63 | private void initCameraView() {
64 | camera2Preview = new Camera2Preview(this);
65 | FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
66 | preview.addView(camera2Preview);
67 | }
68 |
69 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
70 | @Override
71 | protected void onResume() {
72 | super.onResume();
73 | if (camera2Preview != null) {
74 | camera2Preview.onResume();
75 | }
76 | }
77 |
78 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
79 | @Override
80 | protected void onPause() {
81 | super.onPause();
82 | if (camera2Preview != null) {
83 | camera2Preview.onPause();
84 | }
85 | }
86 |
87 |
88 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
89 | public void toggleVideo(View view) {
90 | if (camera2Preview.toggleVideo()) {
91 | mRecordBtn.setText("停止录制视频");
92 | } else {
93 | mRecordBtn.setText("开始录制视频");
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/java/com/example/encodeh264/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.encodeh264;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 | import android.widget.Button;
8 |
9 | public class MainActivity extends AppCompatActivity {
10 | private static final String TAG = "MainActivity";
11 | private Button btnEncode;
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.activity_main);
16 | btnEncode = (Button) findViewById(R.id.btnEncode);
17 | btnEncode.setOnClickListener(new View.OnClickListener() {
18 | @Override
19 | public void onClick(View v) {
20 | startActivity(new Intent(MainActivity.this,EncodeYUVToH264Activity2.class));
21 | }
22 | });
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/layout/activity_encode_yuvto_h264.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
19 |
20 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/EncodeH264/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/EncodeH264/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/EncodeH264/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/EncodeH264/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/EncodeH264/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/EncodeH264/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/EncodeH264/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/EncodeH264/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/EncodeH264/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/EncodeH264/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | EncodeH264
3 |
4 |
--------------------------------------------------------------------------------
/EncodeH264/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/EncodeH264/src/test/java/com/example/encodeh264/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.encodeh264;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.2'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaoben336/MediaCodecDecodeH264Demo/cbe240a5a0f488f5a3d5704e53e53dc7413f7fbd/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Nov 05 15:12:19 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':DecodeH264', ':EncodeH264'
2 |
--------------------------------------------------------------------------------