├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── sign.jks └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── vonchenchen │ │ └── mediacodecdemo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── vonchenchen │ │ │ ├── demo │ │ │ └── YuvUtils.java │ │ │ ├── mediacodecdemo │ │ │ ├── DummyActivity.java │ │ │ ├── FlashActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── OpenglDemoActivity.java │ │ │ ├── RecordScreenTestActivity.java │ │ │ ├── SimpleDemoActivity.java │ │ │ ├── camera │ │ │ │ ├── CameraInfo.java │ │ │ │ ├── CameraManager.java │ │ │ │ ├── CameraUtils.java │ │ │ │ └── interfaces │ │ │ │ │ └── OnCameraPreviewListener.java │ │ │ ├── io │ │ │ │ ├── AbsDataProvider.java │ │ │ │ ├── FileDataProvider.java │ │ │ │ ├── H264DataReader.java │ │ │ │ ├── IStreamDataReader.java │ │ │ │ ├── IVFDataReader.java │ │ │ │ ├── MediaDataReader.java │ │ │ │ ├── MediaDataWriter.java │ │ │ │ ├── MuilResolutionDataReader.java │ │ │ │ └── RawFrameReader.java │ │ │ ├── localfile │ │ │ │ ├── LocalFrameManager.java │ │ │ │ └── decoder │ │ │ │ │ └── H264SoftDecoder.java │ │ │ ├── utils │ │ │ │ ├── AppUtils.java │ │ │ │ └── NumUtils.java │ │ │ └── video │ │ │ │ ├── CodecMsg.java │ │ │ │ ├── DecodeTask.java │ │ │ │ ├── DecodeWrapper.java │ │ │ │ ├── DirectDecoder.java │ │ │ │ ├── DirectEncoder.java │ │ │ │ ├── EncodeInfo.java │ │ │ │ ├── EncodeTask.java │ │ │ │ ├── Logger.java │ │ │ │ ├── MsgPipe.java │ │ │ │ ├── RenderTask.java │ │ │ │ ├── ScaleUtils.java │ │ │ │ ├── ScreenRecorder.java │ │ │ │ ├── SimpleDecoder.java │ │ │ │ ├── SimpleEncoder.java │ │ │ │ ├── Utils.java │ │ │ │ ├── VideoEncoderWrapper.java │ │ │ │ ├── egl │ │ │ │ ├── EglCore.java │ │ │ │ ├── EglSurfaceBase.java │ │ │ │ └── WindowSurface.java │ │ │ │ ├── gles │ │ │ │ ├── Drawable2d.java │ │ │ │ ├── FullFrameRect.java │ │ │ │ ├── GlUtil.java │ │ │ │ └── Texture2dProgram.java │ │ │ │ ├── screen │ │ │ │ ├── ScreenCaptor.java │ │ │ │ └── test │ │ │ │ │ ├── RecordScreenH264Activity.java │ │ │ │ │ └── RecordScreenTest1Activity.java │ │ │ │ ├── statistics │ │ │ │ ├── BitrateInfoCounter.java │ │ │ │ ├── StatUtils.java │ │ │ │ └── StatisticsData.java │ │ │ │ └── streamformat │ │ │ │ └── IvfFormat.java │ │ │ └── view │ │ │ └── LineChartView.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_opengldemo.xml │ │ ├── activity_record1_screen.xml │ │ ├── activity_record_screen.xml │ │ ├── activity_simpledemo.xml │ │ ├── activity_splash.xml │ │ └── view_line_chart.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 │ │ ├── raw │ │ └── out.vp8 │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── vonchenchen │ └── mediacodecdemo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── hellocharts-library ├── .classpath ├── .project ├── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── libs │ └── android-support-v4.jar ├── pom.xml ├── proguard-project.txt ├── project.properties ├── res │ ├── values-v11 │ │ └── styles.xml │ ├── values-v14 │ │ └── styles.xml │ └── values │ │ ├── strings.xml │ │ └── styles.xml └── src │ └── lecho │ └── lib │ └── hellocharts │ ├── animation │ ├── ChartAnimationListener.java │ ├── ChartDataAnimator.java │ ├── ChartDataAnimatorV14.java │ ├── ChartDataAnimatorV8.java │ ├── ChartViewportAnimator.java │ ├── ChartViewportAnimatorV14.java │ ├── ChartViewportAnimatorV8.java │ ├── DummyChartAnimationListener.java │ ├── PieChartRotationAnimator.java │ ├── PieChartRotationAnimatorV14.java │ └── PieChartRotationAnimatorV8.java │ ├── computator │ ├── ChartComputator.java │ └── PreviewChartComputator.java │ ├── formatter │ ├── AxisValueFormatter.java │ ├── BubbleChartValueFormatter.java │ ├── ColumnChartValueFormatter.java │ ├── LineChartValueFormatter.java │ ├── PieChartValueFormatter.java │ ├── SimpleAxisValueFormatter.java │ ├── SimpleBubbleChartValueFormatter.java │ ├── SimpleColumnChartValueFormatter.java │ ├── SimpleLineChartValueFormatter.java │ ├── SimplePieChartValueFormatter.java │ └── ValueFormatterHelper.java │ ├── gesture │ ├── ChartScroller.java │ ├── ChartTouchHandler.java │ ├── ChartZoomer.java │ ├── ContainerScrollType.java │ ├── PieChartTouchHandler.java │ ├── PreviewChartTouchHandler.java │ ├── ZoomType.java │ └── ZoomerCompat.java │ ├── listener │ ├── BubbleChartOnValueSelectListener.java │ ├── ColumnChartOnValueSelectListener.java │ ├── ComboLineColumnChartOnValueSelectListener.java │ ├── DummyBubbleChartOnValueSelectListener.java │ ├── DummyColumnChartOnValueSelectListener.java │ ├── DummyCompoLineColumnChartOnValueSelectListener.java │ ├── DummyLineChartOnValueSelectListener.java │ ├── DummyPieChartOnValueSelectListener.java │ ├── DummyVieportChangeListener.java │ ├── LineChartOnValueSelectListener.java │ ├── OnValueDeselectListener.java │ ├── PieChartOnValueSelectListener.java │ └── ViewportChangeListener.java │ ├── model │ ├── AbstractChartData.java │ ├── Axis.java │ ├── AxisValue.java │ ├── BubbleChartData.java │ ├── BubbleValue.java │ ├── ChartData.java │ ├── Column.java │ ├── ColumnChartData.java │ ├── ComboLineColumnChartData.java │ ├── Line.java │ ├── LineChartData.java │ ├── PieChartData.java │ ├── PointValue.java │ ├── SelectedValue.java │ ├── SliceValue.java │ ├── SubcolumnValue.java │ ├── ValueShape.java │ └── Viewport.java │ ├── provider │ ├── BubbleChartDataProvider.java │ ├── ColumnChartDataProvider.java │ ├── ComboLineColumnChartDataProvider.java │ ├── LineChartDataProvider.java │ └── PieChartDataProvider.java │ ├── renderer │ ├── AbstractChartRenderer.java │ ├── AxesRenderer.java │ ├── BubbleChartRenderer.java │ ├── ChartRenderer.java │ ├── ColumnChartRenderer.java │ ├── ComboChartRenderer.java │ ├── ComboLineColumnChartRenderer.java │ ├── LineChartRenderer.java │ ├── PieChartRenderer.java │ ├── PreviewColumnChartRenderer.java │ └── PreviewLineChartRenderer.java │ ├── util │ ├── AxisAutoValues.java │ ├── ChartUtils.java │ └── FloatUtils.java │ └── view │ ├── AbstractChartView.java │ ├── BubbleChartView.java │ ├── Chart.java │ ├── ColumnChartView.java │ ├── ComboLineColumnChartView.java │ ├── LineChartView.java │ ├── PieChartView.java │ ├── PreviewColumnChartView.java │ ├── PreviewLineChartView.java │ └── hack │ ├── HackyDrawerLayout.java │ └── HackyViewPager.java ├── out.vp8 ├── readme.md └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # IntelliJ 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/assetWizardSettings.xml 41 | .idea/dictionaries 42 | .idea/libraries 43 | .idea/caches 44 | 45 | # Keystore files 46 | # Uncomment the following line if you do not want to check your keystore files in. 47 | #*.jks 48 | 49 | # External native build folder generated in Android Studio 2.2 and later 50 | .externalNativeBuild 51 | 52 | # Google Services (e.g. APIs or Firebase) 53 | google-services.json 54 | 55 | # Freeline 56 | freeline.py 57 | freeline/ 58 | freeline_project_description.json 59 | 60 | # fastlane 61 | fastlane/report.xml 62 | fastlane/Preview.html 63 | fastlane/screenshots 64 | fastlane/test_output 65 | fastlane/readme.md 66 | 67 | mediademo/ -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 36 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | signingConfigs { 5 | release { 6 | keyAlias 'vonchenchen' 7 | keyPassword '123456' 8 | storeFile file('./sign.jks') 9 | storePassword '123456' 10 | } 11 | } 12 | compileSdkVersion 26 13 | defaultConfig { 14 | applicationId "com.vonchenchen.mediacodecdemo" 15 | minSdkVersion 19 16 | targetSdkVersion 26 17 | versionCode 3 18 | versionName "1.0.2" 19 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 20 | } 21 | buildTypes { 22 | debug { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 25 | signingConfig signingConfigs.release 26 | } 27 | release { 28 | minifyEnabled true 29 | //signingConfig signingConfigs.signConfig 30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 31 | signingConfig signingConfigs.release 32 | } 33 | } 34 | externalNativeBuild { 35 | ndkBuild { 36 | path '../mediademo/jni/Android.mk' 37 | } 38 | } 39 | } 40 | 41 | dependencies { 42 | implementation fileTree(include: ['*.jar'], dir: 'libs') 43 | compile project(':hellocharts-library') 44 | implementation 'com.android.support:appcompat-v7:26.1.0' 45 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 46 | testImplementation 'junit:junit:4.12' 47 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 48 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 49 | } 50 | -------------------------------------------------------------------------------- /app/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 | -------------------------------------------------------------------------------- /app/sign.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vonchenchen/AndroidMediacodecDemo/c602c5b22cd32f7c5cb580129e499dd21312da22/app/sign.jks -------------------------------------------------------------------------------- /app/src/androidTest/java/com/vonchenchen/mediacodecdemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo; 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() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.vonchenchen.mediacodecdemo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/demo/YuvUtils.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.demo; 2 | 3 | public class YuvUtils { 4 | 5 | static { 6 | System.loadLibrary("demo"); 7 | } 8 | 9 | public static native void testARGBtoI420(byte[] argbData, int width, int heigh); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/DummyActivity.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | 7 | public class DummyActivity extends Activity{ 8 | 9 | @Override 10 | protected void onCreate(@Nullable Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/FlashActivity.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo; 2 | 3 | import android.Manifest; 4 | import android.app.Activity; 5 | import android.content.Intent; 6 | import android.content.pm.PackageManager; 7 | import android.os.Bundle; 8 | import android.support.annotation.NonNull; 9 | import android.support.annotation.Nullable; 10 | import android.support.v4.app.ActivityCompat; 11 | import android.support.v4.content.ContextCompat; 12 | import android.support.v7.app.AppCompatActivity; 13 | import android.util.Log; 14 | import android.view.View; 15 | 16 | import com.vonchenchen.mediacodecdemo.video.screen.test.RecordScreenH264Activity; 17 | import com.vonchenchen.mediacodecdemo.video.screen.test.RecordScreenTest1Activity; 18 | 19 | public class FlashActivity extends AppCompatActivity { 20 | 21 | private static final String TAG = "FlashActivity"; 22 | 23 | private static final int PERMISSION_REQ_ID_CAM = 0; 24 | private static final int PERMISSION_REQ_ID_STORAGE = 1; 25 | 26 | @Override 27 | protected void onCreate(@Nullable Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_splash); 30 | 31 | findViewById(R.id.next).setOnClickListener(new View.OnClickListener() { 32 | @Override 33 | public void onClick(View view) { 34 | startActivity(new Intent(FlashActivity.this, SimpleDemoActivity.class)); 35 | } 36 | }); 37 | 38 | // findViewById(R.id.screenRecord).setOnClickListener(new View.OnClickListener() { 39 | // @Override 40 | // public void onClick(View view) { 41 | // startActivity(new Intent(FlashActivity.this, RecordScreenTestActivity.class)); 42 | // } 43 | // }); 44 | 45 | findViewById(R.id.screenRecord1).setOnClickListener(new View.OnClickListener() { 46 | @Override 47 | public void onClick(View view) { 48 | startActivity(new Intent(FlashActivity.this, RecordScreenTest1Activity.class)); 49 | } 50 | }); 51 | 52 | findViewById(R.id.screenRecord2).setOnClickListener(new View.OnClickListener() { 53 | @Override 54 | public void onClick(View view) { 55 | startActivity(new Intent(FlashActivity.this, RecordScreenH264Activity.class)); 56 | } 57 | }); 58 | 59 | if(checkSelfPermission(FlashActivity.this, Manifest.permission.CAMERA, PERMISSION_REQ_ID_CAM)){ 60 | //openCamera(); 61 | } 62 | } 63 | 64 | public boolean checkSelfPermission(Activity activity, String permission, int requestCode) { 65 | Log.d(TAG, "checkSelfPermission " + permission + " " + requestCode); 66 | if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) { 67 | ActivityCompat.requestPermissions(activity, new String[]{permission}, requestCode); 68 | return false; 69 | } 70 | return true; 71 | } 72 | 73 | @Override 74 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 75 | if(requestCode == PERMISSION_REQ_ID_CAM){ 76 | checkSelfPermission(FlashActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSION_REQ_ID_STORAGE); 77 | //openCamera(); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | public class MainActivity extends AppCompatActivity { 7 | 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | setContentView(R.layout.activity_main); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/OpenglDemoActivity.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo; 2 | 3 | import android.app.Activity; 4 | import android.opengl.GLSurfaceView; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | 8 | import javax.microedition.khronos.egl.EGLConfig; 9 | import javax.microedition.khronos.opengles.GL10; 10 | 11 | public class OpenglDemoActivity extends Activity{ 12 | 13 | private GLSurfaceView mMainGLSurfaceView; 14 | 15 | @Override 16 | protected void onCreate(@Nullable Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_opengldemo); 19 | 20 | mMainGLSurfaceView = findViewById(R.id.gl_mainview); 21 | //mMainGLSurfaceView.setRenderer(); 22 | } 23 | 24 | class MainRenderer implements GLSurfaceView.Renderer { 25 | 26 | @Override 27 | public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) { 28 | 29 | } 30 | 31 | @Override 32 | public void onSurfaceChanged(GL10 gl10, int i, int i1) { 33 | 34 | } 35 | 36 | @Override 37 | public void onDrawFrame(GL10 gl10) { 38 | 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/camera/CameraInfo.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.camera; 2 | 3 | public class CameraInfo { 4 | 5 | public int previewWidth; 6 | 7 | public int previewHeight; 8 | 9 | public int orientation; 10 | 11 | public boolean isFront; 12 | 13 | public int pictureWidth; 14 | 15 | public int pictureHeight; 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/camera/CameraUtils.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.camera; 2 | 3 | import android.hardware.Camera; 4 | 5 | import com.vonchenchen.mediacodecdemo.video.Logger; 6 | 7 | import java.util.List; 8 | 9 | public class CameraUtils { 10 | 11 | private static final String TAG = "CameraUtils"; 12 | 13 | public static Camera.Size getLargePictureSize(Camera camera){ 14 | if(camera != null){ 15 | List sizes = camera.getParameters().getSupportedPictureSizes(); 16 | Camera.Size temp = sizes.get(0); 17 | for(int i = 1;i < sizes.size();i ++){ 18 | float scale = (float)(sizes.get(i).height) / sizes.get(i).width; 19 | if(temp.width < sizes.get(i).width && scale < 0.6f && scale > 0.5f) 20 | temp = sizes.get(i); 21 | } 22 | return temp; 23 | } 24 | return null; 25 | } 26 | 27 | public static Camera.Size getLargePreviewSize(Camera camera){ 28 | if(camera != null){ 29 | List sizes = camera.getParameters().getSupportedPreviewSizes(); 30 | Camera.Size temp = sizes.get(0); 31 | for(int i = 1;i < sizes.size();i ++){ 32 | if(temp.width < sizes.get(i).width) 33 | temp = sizes.get(i); 34 | } 35 | return temp; 36 | } 37 | return null; 38 | } 39 | 40 | public static List getCamSizeList(Camera camera){ 41 | if(camera != null){ 42 | List sizes = camera.getParameters().getSupportedPreviewSizes(); 43 | return sizes; 44 | } 45 | return null; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/camera/interfaces/OnCameraPreviewListener.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.camera.interfaces; 2 | 3 | /** 4 | * Created by vonchenchen on 14/11/2017. 5 | */ 6 | 7 | public interface OnCameraPreviewListener { 8 | void onPreview(int width, int height, byte[] data); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/io/AbsDataProvider.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.io; 2 | 3 | public abstract class AbsDataProvider { 4 | 5 | public class DataInfo{ 6 | public byte[] data; 7 | public int index; 8 | public int length; 9 | } 10 | 11 | abstract public DataInfo provideData(); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/io/FileDataProvider.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.io; 2 | 3 | import com.vonchenchen.mediacodecdemo.video.Logger; 4 | import com.vonchenchen.mediacodecdemo.video.Utils; 5 | 6 | import java.io.FileNotFoundException; 7 | 8 | public class FileDataProvider extends AbsDataProvider { 9 | 10 | private static String TAG = "FileDataProvider"; 11 | 12 | private static final int READ_SIZE = 1024 * 2; 13 | 14 | private String mPath; 15 | private MediaDataReader mMediaDataReader; 16 | private DataInfo mDataInfo; 17 | 18 | public FileDataProvider(String path){ 19 | 20 | mPath = path; 21 | try { 22 | mMediaDataReader = new MediaDataReader(mPath); 23 | } catch (FileNotFoundException e) { 24 | e.printStackTrace(); 25 | return; 26 | } 27 | 28 | mDataInfo = new DataInfo(); 29 | mDataInfo.data = new byte[READ_SIZE]; 30 | mDataInfo.index = 0; 31 | } 32 | 33 | @Override 34 | public DataInfo provideData() { 35 | mDataInfo.length = mMediaDataReader.read(mDataInfo.data, mDataInfo.index, READ_SIZE); 36 | Logger.i(TAG, Utils.byteArrayToHexString(mDataInfo.data)); 37 | return mDataInfo; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/io/IStreamDataReader.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.io; 2 | 3 | public interface IStreamDataReader { 4 | 5 | int readNextFrame(); 6 | void setOnDataParsedListener(OnDataParsedListener onDataParsedListener); 7 | void close(); 8 | 9 | interface OnDataParsedListener { 10 | void onParsed(byte[] data, int index, int length); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/io/IVFDataReader.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.io; 2 | 3 | import com.vonchenchen.mediacodecdemo.video.Logger; 4 | import com.vonchenchen.mediacodecdemo.video.Utils; 5 | import com.vonchenchen.mediacodecdemo.video.streamformat.IvfFormat; 6 | 7 | import java.io.FileNotFoundException; 8 | 9 | public class IVFDataReader extends MediaDataReader implements IStreamDataReader { 10 | 11 | private final String TAG = "IVFDataReader"; 12 | 13 | private byte[] mData; 14 | private int mDataRearIndex; 15 | 16 | private int mMaxFrameSize; 17 | private OnDataParsedListener mOnDataParsedListener = null; 18 | 19 | public IVFDataReader(String path, int maxFrameSize) throws FileNotFoundException { 20 | super(path); 21 | mData = new byte[maxFrameSize]; 22 | mDataRearIndex = 0; 23 | mMaxFrameSize = maxFrameSize; 24 | 25 | //跳过数据头 26 | //read(mData, IvfFormat.IVF_HEADER_LEN); 27 | } 28 | 29 | @Override 30 | public int readNextFrame() { 31 | 32 | //读取每个ivf帧头 33 | int length = read(mData, IvfFormat.IVF_FRAME_HEADER_LEN); 34 | if(length < 12){ 35 | return 0; 36 | } 37 | 38 | //ivf 数据头 不能抛给解码器 39 | if(mData[0] == 'D' && mData[1] == 'K' && mData[2] == 'I' && mData[3] == 'F'){ 40 | read(mData, IvfFormat.IVF_FRAME_HEADER_LEN, IvfFormat.IVF_HEADER_LEN - IvfFormat.IVF_FRAME_HEADER_LEN); 41 | 42 | if(mOnDataParsedListener != null){ 43 | //mOnDataParsedListener.onParsed(mData, 0, IvfFormat.IVF_HEADER_LEN); 44 | } 45 | return IvfFormat.IVF_HEADER_LEN; 46 | } 47 | 48 | //从ivf frame头读出帧长度 49 | int frameLengh = Utils.getLittleEndianUint32(mData, 0); 50 | Logger.i(TAG, "IVF payload frameLengh="+frameLengh); 51 | 52 | //读出后面的帧数据 连ivf封装格式一起抛出 53 | // int readLength = read(mData, 12, frameLengh); 54 | // if(mOnDataParsedListener != null){ 55 | // mOnDataParsedListener.onParsed(mData, 0, IvfFormat.IVF_HEADER_LEN+frameLengh); 56 | // } 57 | 58 | //读出后面的帧数据 去掉ivf封装只抛出数据 59 | int readLength = read(mData, 0, frameLengh); 60 | if(mOnDataParsedListener != null){ 61 | mOnDataParsedListener.onParsed(mData, 0, frameLengh); 62 | } 63 | 64 | return (IvfFormat.IVF_HEADER_LEN+frameLengh); 65 | } 66 | 67 | @Override 68 | public void setOnDataParsedListener(OnDataParsedListener onDataParsedListener) { 69 | mOnDataParsedListener = onDataParsedListener; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/io/MediaDataReader.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.io; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileNotFoundException; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.io.OutputStream; 12 | 13 | /** 14 | * Created by vonchenchen on 2018/5/17. 15 | */ 16 | 17 | public class MediaDataReader{ 18 | 19 | private static final String TAG = "MediaDataReader"; 20 | 21 | private String mPath; 22 | private File mTargetFile; 23 | private InputStream mFileInputStream; 24 | 25 | public MediaDataReader(String path) throws FileNotFoundException { 26 | mPath = path; 27 | mTargetFile = new File(path); 28 | mFileInputStream = new FileInputStream(mTargetFile); 29 | } 30 | 31 | /** 32 | * 尾部追加 33 | * @param data 34 | * @param length 35 | */ 36 | public int read(byte[] data, int length){ 37 | 38 | int ret = -1; 39 | try { 40 | if(mFileInputStream == null){ 41 | mTargetFile = new File(mPath); 42 | mFileInputStream = new FileInputStream(mTargetFile); 43 | } 44 | ret = mFileInputStream.read(data, 0, length); 45 | return ret; 46 | } catch (IOException e) { 47 | Log.e(TAG, "MediaDataReader [readToTail] "+e.toString()); 48 | try { 49 | mFileInputStream.close(); 50 | } catch (IOException e1) { 51 | Log.e(TAG, "MediaDataReader [readToTail] "+e.toString()); 52 | } 53 | } 54 | return ret; 55 | } 56 | 57 | public int read(byte[] data, int index, int length){ 58 | 59 | int ret = -1; 60 | try { 61 | if(mFileInputStream == null){ 62 | mTargetFile = new File(mPath); 63 | mFileInputStream = new FileInputStream(mTargetFile); 64 | } 65 | ret = mFileInputStream.read(data, index, length); 66 | return ret; 67 | } catch (IOException e) { 68 | Log.e(TAG, "MediaDataReader [readToTail] "+e.toString()); 69 | try { 70 | mFileInputStream.close(); 71 | } catch (IOException e1) { 72 | Log.e(TAG, "MediaDataReader [readToTail] "+e.toString()); 73 | } 74 | } 75 | return ret; 76 | } 77 | 78 | public void close(){ 79 | if(mFileInputStream != null){ 80 | try { 81 | mFileInputStream.close(); 82 | mFileInputStream = null; 83 | } catch (IOException e) { 84 | Log.e(TAG, "MediaDataReader [close] "+e.toString()); 85 | } 86 | } 87 | } 88 | 89 | public void reset(){ 90 | close(); 91 | mTargetFile = new File(mPath); 92 | try { 93 | mFileInputStream = new FileInputStream(mTargetFile); 94 | } catch (FileNotFoundException e) { 95 | e.printStackTrace(); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/io/MediaDataWriter.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.io; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.File; 6 | import java.io.FileNotFoundException; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.OutputStream; 10 | 11 | /** 12 | * Created by vonchenchen on 2018/5/19. 13 | */ 14 | 15 | public class MediaDataWriter { 16 | 17 | private static final String TAG = "MediaDataWriter"; 18 | 19 | private String mPath; 20 | private File mTargetFile; 21 | private OutputStream mFileOutputStream; 22 | private int mCurrentIndex; 23 | 24 | public MediaDataWriter(String path) throws FileNotFoundException { 25 | mPath = path; 26 | mTargetFile = new File(path); 27 | mFileOutputStream = new FileOutputStream(mTargetFile); 28 | mCurrentIndex = 0; 29 | } 30 | 31 | /** 32 | * 尾部追加 33 | * @param data 34 | * @param length 35 | */ 36 | public void write(byte[] data, int length){ 37 | 38 | try { 39 | mFileOutputStream.write(data, 0, length); 40 | mFileOutputStream.flush(); 41 | } catch (IOException e) { 42 | Log.e(TAG, "MediaDataWriter [writeToTail] "+e.toString()); 43 | try { 44 | mFileOutputStream.close(); 45 | } catch (IOException e1) { 46 | Log.e(TAG, "MediaDataWriter [writeToIndex] "+e.toString()); 47 | } 48 | } 49 | } 50 | 51 | public void writeToIndex(byte[] data, int index, int length){ 52 | 53 | try { 54 | mFileOutputStream.write(data, index, length); 55 | mFileOutputStream.flush(); 56 | mCurrentIndex = index; 57 | } catch (IOException e) { 58 | Log.e(TAG, "MediaDataWriter [writeToIndex] "+e.toString()); 59 | try { 60 | mFileOutputStream.close(); 61 | } catch (IOException e1) { 62 | Log.e(TAG, "MediaDataWriter [writeToIndex] "+e.toString()); 63 | } 64 | } 65 | } 66 | 67 | public void deleteFile(){ 68 | if(mTargetFile != null && !mTargetFile.isDirectory()){ 69 | mTargetFile.delete(); 70 | } 71 | } 72 | 73 | public void close(){ 74 | if(mFileOutputStream != null){ 75 | try { 76 | mFileOutputStream.close(); 77 | } catch (IOException e) { 78 | Log.e(TAG, "MediaDataWriter [close] "+e.toString()); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/io/MuilResolutionDataReader.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.io; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | /** 8 | * 读取多个H264视频 9 | * 用于模拟传输中对方视频分辨率变化的情况 10 | */ 11 | public class MuilResolutionDataReader implements IStreamDataReader { 12 | 13 | private List mediaDataReaderList; 14 | 15 | public MuilResolutionDataReader(List list) throws FileNotFoundException { 16 | 17 | mediaDataReaderList = list; 18 | } 19 | 20 | @Override 21 | public int readNextFrame() { 22 | 23 | 24 | 25 | return 0; 26 | } 27 | 28 | @Override 29 | public void setOnDataParsedListener(OnDataParsedListener onDataParsedListener) { 30 | 31 | } 32 | 33 | private OnDataParsedListener mOnDataParsedListener = null; 34 | 35 | @Override 36 | public void close() { 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/io/RawFrameReader.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.io; 2 | 3 | import java.io.FileNotFoundException; 4 | 5 | public class RawFrameReader extends MediaDataReader implements IStreamDataReader{ 6 | 7 | private OnDataParsedListener mOnDataParsedListener; 8 | 9 | public RawFrameReader(String path) throws FileNotFoundException { 10 | super(path); 11 | } 12 | 13 | @Override 14 | public int readNextFrame() { 15 | 16 | 17 | 18 | return 0; 19 | } 20 | 21 | @Override 22 | public void setOnDataParsedListener(OnDataParsedListener onDataParsedListener) { 23 | mOnDataParsedListener = onDataParsedListener; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/localfile/LocalFrameManager.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.localfile; 2 | 3 | import android.graphics.SurfaceTexture; 4 | import android.view.SurfaceView; 5 | 6 | import com.vonchenchen.mediacodecdemo.io.IStreamDataReader; 7 | import com.vonchenchen.mediacodecdemo.io.RawFrameReader; 8 | 9 | import java.io.File; 10 | 11 | public class LocalFrameManager { 12 | 13 | private SurfaceTexture mImageSurfaceTexture; 14 | //private SurfaceView 15 | 16 | private IStreamDataReader mRawFrameReader; 17 | 18 | private LocalFrameManager sInstance = null; 19 | 20 | private LocalFrameManager(){} 21 | 22 | public LocalFrameManager getInstance(){ 23 | if(sInstance == null) { 24 | synchronized (LocalFrameManager.class) { 25 | if(sInstance == null) { 26 | sInstance = new LocalFrameManager(); 27 | } 28 | } 29 | } 30 | return sInstance; 31 | } 32 | 33 | public void setRawFrameReader(IStreamDataReader rawFrameReader){ 34 | mRawFrameReader = rawFrameReader; 35 | } 36 | 37 | public void openFile(File file, Codec codec){ 38 | 39 | 40 | } 41 | 42 | public void startCapture(SurfaceTexture surfaceTexture){ 43 | 44 | mImageSurfaceTexture = surfaceTexture; 45 | 46 | //mRawFrameReader. 47 | } 48 | 49 | enum Codec{ 50 | I420, 51 | H264 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/localfile/decoder/H264SoftDecoder.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.localfile.decoder; 2 | 3 | public class H264SoftDecoder { 4 | 5 | public H264SoftDecoder(){ 6 | 7 | } 8 | 9 | 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/utils/AppUtils.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.utils; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | 7 | public class AppUtils { 8 | 9 | public static int packageCode(Context context) { 10 | PackageManager manager = context.getPackageManager(); 11 | int code = 0; 12 | try { 13 | PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0); 14 | code = info.versionCode; 15 | } catch (PackageManager.NameNotFoundException e) { 16 | e.printStackTrace(); 17 | } 18 | return code; 19 | } 20 | 21 | public static String packageName(Context context) { 22 | PackageManager manager = context.getPackageManager(); 23 | String name = null; 24 | try { 25 | PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0); 26 | name = info.versionName; 27 | } catch (PackageManager.NameNotFoundException e) { 28 | e.printStackTrace(); 29 | } 30 | 31 | return name; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/utils/NumUtils.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.utils; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class NumUtils { 6 | 7 | /** 8 | * 保留两位小数 9 | * @param data 10 | * @return 11 | */ 12 | public static String keepTwoDecimals(double data){ 13 | return String.format("%.2f", data); 14 | } 15 | 16 | /** 17 | * 将浮点数字符串 18 | * @param numStr 19 | * @param reserve 20 | * @return 21 | */ 22 | public static String roundFloatString(String numStr, int reserve){ 23 | BigDecimal decimal = new BigDecimal(numStr); 24 | BigDecimal setScale = decimal.setScale(reserve,BigDecimal.ROUND_HALF_DOWN); 25 | return setScale.toString(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/video/CodecMsg.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.video; 2 | 3 | public class CodecMsg { 4 | 5 | enum MSG{ 6 | /** 通知解码成功 */ 7 | MSG_DECODE_FRAME_READY, 8 | /** 结束渲染任务 */ 9 | MSG_STOP_RENDER_TASK, 10 | /** 暂停渲染任务 */ 11 | MSG_PAUSE_RENDER_TASK, 12 | /** 恢复渲染任务 */ 13 | MSG_RESUME_RENDER_TASK, 14 | /** 解码器重置 */ 15 | MSG_RESET_DECODER, 16 | 17 | /** 编码采集帧成功 */ 18 | MSG_ENCODE_CAPTURE_FRAME_READY, 19 | /** 编码恢复渲染 */ 20 | MSG_ENCODE_RESUME_RENDER, 21 | /** 编码暂停渲染 */ 22 | MSG_ENCODE_PAUSE_RENDER, 23 | /** 结束编码任务 */ 24 | MSG_ENCODE_STOP_TASK, 25 | /** 改变编码器参数 */ 26 | MSG_ENCODE_CHANGE_BITRATE, 27 | /** 改变编码帧率 */ 28 | MSG_ENCODE_CHANGE_FRAMERATE; 29 | } 30 | 31 | public CodecMsg(){ 32 | encodeInfo = new EncodeInfo(); 33 | } 34 | 35 | public MSG currentMsg; 36 | 37 | public int currentFrameWidth; 38 | public int currentFrameHeight; 39 | 40 | public EncodeInfo encodeInfo; 41 | 42 | public byte[] data; 43 | public int offset; 44 | public int length; 45 | public long pts; 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/video/DecodeWrapper.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.video; 2 | 3 | import android.view.Surface; 4 | import android.view.SurfaceHolder; 5 | import android.view.SurfaceView; 6 | 7 | /** 8 | * 用来封装decode所使用的数据 9 | */ 10 | public class DecodeWrapper { 11 | 12 | private static final String TAG = "DecodeWrapper"; 13 | 14 | private int mWidth; 15 | private int mHeight; 16 | /** 用于解码的surface */ 17 | private Surface mDecodeSurface; 18 | private SimpleDecoder mSimpleDecoder = null; 19 | 20 | public void init(int width, int height, Surface surface, final String mediaFormatType){ 21 | 22 | mWidth = width; 23 | mHeight = height; 24 | mDecodeSurface = surface; 25 | 26 | if(mSimpleDecoder != null){ 27 | mSimpleDecoder.close(); 28 | } 29 | mSimpleDecoder = new SimpleDecoder(mWidth, mHeight, mDecodeSurface, mediaFormatType); 30 | } 31 | 32 | public int decode(byte[] input, int offset, int count , long pts){ 33 | return mSimpleDecoder.decode(input, offset, count, pts); 34 | } 35 | 36 | public void setOnDecoderEnventLisetener(SimpleDecoder.OnDecoderEnventLisetener lisetener){ 37 | mSimpleDecoder.setOnDecoderEnventLisetener(lisetener); 38 | } 39 | 40 | public void release(){ 41 | 42 | // if(mDecodeSurface != null) { 43 | // mDecodeSurface.release(); 44 | // mDecodeSurface = null; 45 | // } 46 | 47 | if(mSimpleDecoder != null) { 48 | mSimpleDecoder.close(); 49 | mSimpleDecoder = null; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/video/EncodeInfo.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.video; 2 | 3 | import android.media.MediaCodecInfo; 4 | 5 | public class EncodeInfo { 6 | 7 | /** 码率模式 */ 8 | public int bitrateMode; 9 | /** 码率 */ 10 | public int bitrate; 11 | /** 关键帧间隔 */ 12 | public int keyFrameInterval; 13 | /** 帧率 */ 14 | public int framerate; 15 | /** profile */ 16 | public int profile; 17 | 18 | public EncodeInfo(){ 19 | profile = MediaCodecInfo.CodecProfileLevel.AVCProfileBaseline; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/video/Logger.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.video; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Created by vonchenchen on 2018/4/15. 7 | */ 8 | 9 | public class Logger { 10 | 11 | public static void d(String TAG, String msg){ 12 | Log.d(TAG, msg); 13 | } 14 | 15 | public static void i(String TAG, String msg){ 16 | Log.i(TAG, msg); 17 | } 18 | 19 | public static void v(String TAG, String msg){ 20 | Log.v(TAG, msg); 21 | } 22 | 23 | public static void w(String TAG, String msg){ 24 | Log.w(TAG, msg); 25 | } 26 | 27 | public static void e(String TAG, String msg){ 28 | Log.e(TAG, msg); 29 | } 30 | 31 | public static void printErrStackTrace(String TAG, Exception e, String msg){ 32 | Log.e(TAG, msg+e.toString()); 33 | } 34 | 35 | private void writeMsg(){ 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/video/MsgPipe.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.video; 2 | 3 | import java.util.LinkedList; 4 | 5 | public class MsgPipe extends Thread{ 6 | 7 | private static final String TAG = "MsgPipe"; 8 | 9 | private LinkedList mMsgQueue = new LinkedList(); 10 | private OnPipeListener mOnPipeListener = null; 11 | 12 | private volatile boolean mIsLoop; 13 | 14 | @Override 15 | public void run() { 16 | 17 | T msg = null; 18 | 19 | if (mOnPipeListener != null) { 20 | mOnPipeListener.onPipeStart(); 21 | } 22 | 23 | Logger.i(TAG, "MsgPipe start id="+Thread.currentThread().getId()); 24 | 25 | while (mIsLoop){ 26 | if(mMsgQueue.isEmpty()){ 27 | synchronized (mMsgQueue){ 28 | try { 29 | mMsgQueue.wait(1000); 30 | } catch (InterruptedException e) { 31 | e.printStackTrace(); 32 | } 33 | } 34 | }else { 35 | synchronized (mMsgQueue) { 36 | msg = mMsgQueue.removeFirst(); 37 | } 38 | if (mOnPipeListener != null) { 39 | mOnPipeListener.onPipeRecv(msg); 40 | } 41 | } 42 | } 43 | 44 | if (mOnPipeListener != null) { 45 | mOnPipeListener.onPipeRelease(); 46 | } 47 | 48 | Logger.i(TAG, "MsgPipe stop id="+Thread.currentThread().getId()); 49 | } 50 | 51 | public void addLast(T msg){ 52 | synchronized (mMsgQueue) { 53 | mMsgQueue.addLast(msg); 54 | mMsgQueue.notify(); 55 | } 56 | } 57 | 58 | public void addFirst(T msg){ 59 | synchronized (mMsgQueue) { 60 | mMsgQueue.addFirst(msg); 61 | mMsgQueue.notify(); 62 | } 63 | } 64 | 65 | public void startPipe(){ 66 | mIsLoop = true; 67 | start(); 68 | } 69 | 70 | public void stopPipe(){ 71 | mIsLoop = false; 72 | } 73 | 74 | public void clearPipeData(){ 75 | if(mMsgQueue != null){ 76 | synchronized (mMsgQueue) { 77 | mMsgQueue.clear(); 78 | } 79 | } 80 | } 81 | 82 | public void setOnPipeListener(OnPipeListener listener){ 83 | mOnPipeListener = listener; 84 | } 85 | 86 | public interface OnPipeListener{ 87 | void onPipeStart(); 88 | void onPipeRecv(T msg); 89 | void onPipeRelease(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/video/ScaleUtils.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.video; 2 | 3 | import android.widget.RelativeLayout; 4 | 5 | public class ScaleUtils { 6 | 7 | private static final String TAG = "ScaleUtils"; 8 | 9 | public static Param getScale(int outWidth, int outHeight, int imageWidth, int imageHeight) { 10 | 11 | int width, height; 12 | Param params = new Param(); 13 | 14 | if (imageWidth <= 0 || imageHeight <= 0) { 15 | Logger.e(TAG, "setScale fail imageHeight=" + imageHeight + " imageWidth " + imageWidth); 16 | return null; 17 | } 18 | 19 | if (outWidth <= 1 || outHeight <= 1) { 20 | params.width = 1; 21 | params.height = 1; 22 | } else { 23 | //视频帧比例 24 | float k = ((float) imageHeight) / imageWidth; 25 | //外轮廓比例 26 | float ok = ((float) outHeight) / outWidth; 27 | 28 | if (outWidth > outHeight) { 29 | //宽大于高 30 | if (k > ok) { 31 | //按比例 外框比帧宽 32 | height = outHeight; 33 | width = (int) (outHeight / k); 34 | } else { 35 | //按比例 外框比帧窄 36 | width = outWidth; 37 | height = (int) (outWidth * k); 38 | } 39 | } else { 40 | if (k < ok) { 41 | width = outWidth; 42 | height = (int) (outWidth * k); 43 | } else { 44 | height = outHeight; 45 | width = (int) (outHeight / k); 46 | } 47 | } 48 | 49 | params.width = width; 50 | params.height = height; 51 | } 52 | return params; 53 | } 54 | 55 | public static class Param{ 56 | public int width; 57 | public int height; 58 | } 59 | 60 | /** 61 | * 根据屏幕宽高与帧宽高重新计算VertexMat 将图片等比例画入控件框中 62 | * @param displayViewWidth 63 | * @param displayViewHeight 64 | * @param frameWidth 65 | * @param frameHeight 66 | * @return 67 | */ 68 | public static float[] getScaleVertexMat(int displayViewWidth, int displayViewHeight, int frameWidth, int frameHeight){ 69 | 70 | //通过修改顶点坐标 将采集到的视频按比例缩放到窗口中 71 | ScaleUtils.Param param = ScaleUtils.getScale(displayViewWidth, displayViewHeight, frameWidth, frameHeight); 72 | float scaleWidth = ((float) param.width)/displayViewWidth; 73 | float scaleHeight = ((float) param.height)/displayViewHeight; 74 | float[] drawMatrix = new float[8]; 75 | if(scaleWidth == 1){ 76 | float halfHeight = scaleHeight; 77 | drawMatrix[0] = -1; 78 | drawMatrix[1] = -halfHeight; 79 | drawMatrix[2] = 1; 80 | drawMatrix[3] = -halfHeight; 81 | drawMatrix[4] = -1; 82 | drawMatrix[5] = halfHeight; 83 | drawMatrix[6] = 1; 84 | drawMatrix[7] = halfHeight; 85 | }else{ 86 | float halfWidth = scaleWidth; 87 | drawMatrix[0] = -halfWidth; 88 | drawMatrix[1] = -1; 89 | drawMatrix[2] = halfWidth; 90 | drawMatrix[3] = -1; 91 | drawMatrix[4] = -halfWidth; 92 | drawMatrix[5] = 1; 93 | drawMatrix[6] = halfWidth; 94 | drawMatrix[7] = 1; 95 | } 96 | return drawMatrix; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/video/Utils.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.video; 2 | 3 | public class Utils { 4 | 5 | private static final String TAG = "Utils"; 6 | 7 | public static String byteArrayToHexString(byte[] a) { 8 | if (a == null) { 9 | return "null"; 10 | } 11 | int iMax = a.length - 1; 12 | if (iMax == -1) { 13 | return "[]"; 14 | } 15 | 16 | StringBuilder b = new StringBuilder(); 17 | b.append('['); 18 | for (int i = 0; ; i++) { 19 | b.append(Integer.toHexString(0x000000ff & a[i])); 20 | if (i == iMax) { 21 | return b.append(']').toString(); 22 | } 23 | b.append(", "); 24 | } 25 | } 26 | 27 | public static int getLittleEndianUint32(byte[] data, int offset){ 28 | int ret = 0; 29 | ret += (((short)data[offset]) & 0x00ff); 30 | ret += ((short)data[offset+1] & 0x00ff) << 8; 31 | ret += ((short)data[offset+2] & 0x00ff) << 16; 32 | ret += ((short)data[offset+3] & 0x00ff) << 24; 33 | return ret; 34 | } 35 | 36 | public static void printMat(float[] mat, int width, int height){ 37 | 38 | for(int i=0; i 26 | * It's good practice to explicitly release() the surface, preferably from a "finally" block. 27 | */ 28 | public class WindowSurface extends EglSurfaceBase { 29 | private Surface mSurface; 30 | private boolean mReleaseSurface; 31 | 32 | /** 33 | * Associates an EGL surface with the native window surface. 34 | *

35 | * Set releaseSurface to true if you want the Surface to be released when release() is 36 | * called. This is convenient, but can interfere with framework classes that expect to 37 | * manage the Surface themselves (e.g. if you release a SurfaceView's Surface, the 38 | * surfaceDestroyed() callback won't fire). 39 | */ 40 | public WindowSurface(EglCore eglCore, Surface surface, boolean releaseSurface) { 41 | super(eglCore); 42 | createWindowSurface(surface); 43 | mSurface = surface; 44 | mReleaseSurface = releaseSurface; 45 | } 46 | 47 | /** 48 | * Associates an EGL surface with the SurfaceTexture. 49 | */ 50 | public WindowSurface(EglCore eglCore, SurfaceTexture surfaceTexture) { 51 | super(eglCore); 52 | createWindowSurface(surfaceTexture); 53 | } 54 | 55 | /** 56 | * Releases any resources associated with the EGL surface (and, if configured to do so, 57 | * with the Surface as well). 58 | *

59 | * Does not require that the surface's EGL context be current. 60 | */ 61 | public void release() { 62 | releaseEglSurface(); 63 | if (mSurface != null) { 64 | if (mReleaseSurface) { 65 | mSurface.release(); 66 | } 67 | mSurface = null; 68 | } 69 | } 70 | 71 | public void setSurface(Surface surface) { 72 | mSurface = surface; 73 | } 74 | 75 | /** 76 | * Recreate the EGLSurface, using the new EglBase. The caller should have already 77 | * freed the old EGLSurface with releaseEglSurface(). 78 | *

79 | * This is useful when we want to update the EGLSurface associated with a Surface. 80 | * For example, if we want to share with a different EGLContext, which can only 81 | * be done by tearing down and recreating the context. (That's handled by the caller; 82 | * this just creates a new EGLSurface for the Surface we were handed earlier.) 83 | *

84 | * If the previous EGLSurface isn't fully destroyed, e.g. it's still current on a 85 | * context somewhere, the create call will fail with complaints from the Surface 86 | * about already being connected. 87 | */ 88 | public void recreate(EglCore newEglCore) { 89 | if (mSurface == null) { 90 | throw new RuntimeException("not yet implemented for SurfaceTexture"); 91 | } 92 | mEglCore = newEglCore; // switch to new context 93 | createWindowSurface(mSurface); // create new surface 94 | } 95 | 96 | public EGLSurface getEGLSurface(){ 97 | return mEGLSurface; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/video/gles/FullFrameRect.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.vonchenchen.mediacodecdemo.video.gles; 18 | 19 | 20 | /** 21 | * This class essentially represents a viewport-sized sprite that will be rendered with 22 | * a texture, usually from an external source like the camera or video decoder. 23 | */ 24 | public class FullFrameRect { 25 | private final Drawable2d mRectDrawable = new Drawable2d(Drawable2d.Prefab.FULL_RECTANGLE); 26 | private Texture2dProgram mProgram; 27 | 28 | /** 29 | * Prepares the object. 30 | * 31 | * @param program The program to use. FullFrameRect takes ownership, and will release 32 | * the program when no longer needed. 33 | */ 34 | public FullFrameRect(Texture2dProgram program) { 35 | mProgram = program; 36 | } 37 | 38 | /** 39 | * Releases resources. 40 | *

41 | * This must be called with the appropriate EGL context current (i.e. the one that was 42 | * current when the constructor was called). If we're about to destroy the EGL context, 43 | * there's no value in having the caller make it current just to do this cleanup, so you 44 | * can pass a flag that will tell this function to skip any EGL-context-specific cleanup. 45 | */ 46 | public void release(boolean doEglCleanup) { 47 | if (mProgram != null) { 48 | if (doEglCleanup) { 49 | mProgram.release(); 50 | } 51 | mProgram = null; 52 | } 53 | } 54 | 55 | /** 56 | * Returns the program currently in use. 57 | */ 58 | public Texture2dProgram getProgram() { 59 | return mProgram; 60 | } 61 | 62 | /** 63 | * Changes the program. The previous program will be released. 64 | *

65 | * The appropriate EGL context must be current. 66 | */ 67 | public void changeProgram(Texture2dProgram program) { 68 | mProgram.release(); 69 | mProgram = program; 70 | } 71 | 72 | /** 73 | * Creates a texture object suitable for use with drawFrame(). 74 | */ 75 | public int createTextureObject() { 76 | return mProgram.createTextureObject(); 77 | } 78 | 79 | /** 80 | * 将视频按比例缩放到窗口中 81 | * @param vertexBuf 82 | */ 83 | public void rescaleDrawRect(float[] vertexBuf){ 84 | mRectDrawable.setVertexArray(vertexBuf); 85 | } 86 | 87 | /** 88 | * 渲染textureId到framebuffer 89 | * @param textureId 90 | */ 91 | public void beginDrawToTexture(int textureId){ 92 | mProgram.beginDrawToTexture(textureId); 93 | } 94 | 95 | /** 96 | * Draws a viewport-filling rect, texturing it with the specified texture object. 97 | */ 98 | public void drawFrame(int textureId, float[] texMatrix) { 99 | // Use the identity matrix for MVP so our 2x2 FULL_RECTANGLE covers the viewport. 100 | mProgram.draw(GlUtil.IDENTITY_MATRIX, mRectDrawable.getVertexArray(), 0, 101 | mRectDrawable.getVertexCount(), mRectDrawable.getCoordsPerVertex(), 102 | mRectDrawable.getVertexStride(), 103 | texMatrix, mRectDrawable.getTexCoordArray(), textureId, 104 | mRectDrawable.getTexCoordStride()); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/vonchenchen/mediacodecdemo/video/statistics/BitrateInfoCounter.java: -------------------------------------------------------------------------------- 1 | package com.vonchenchen.mediacodecdemo.video.statistics; 2 | 3 | import com.vonchenchen.mediacodecdemo.utils.NumUtils; 4 | 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | 8 | public class BitrateInfoCounter { 9 | 10 | private List mBitrateList; 11 | 12 | public BitrateInfoCounter(){ 13 | 14 | mBitrateList = new LinkedList<>(); 15 | } 16 | 17 | public void addData(int data){ 18 | 19 | mBitrateList.add(data); 20 | } 21 | 22 | public BitrateInfo count(int target){ 23 | 24 | BitrateInfo bitrateInfo = new BitrateInfo(); 25 | 26 | int standCntSum = 0; 27 | int sum = 0; 28 | 29 | if(mBitrateList.size() <= 0){ 30 | return bitrateInfo; 31 | } 32 | 33 | bitrateInfo.min = mBitrateList.get(0)*8; 34 | bitrateInfo.max = mBitrateList.get(0)*8; 35 | 36 | for(int i=0; i bitrateInfo.max){ 41 | bitrateInfo.max = data; 42 | }else if(data < bitrateInfo.min){ 43 | bitrateInfo.min = data; 44 | } 45 | 46 | sum += data; 47 | } 48 | 49 | bitrateInfo.average = sum/mBitrateList.size(); 50 | 51 | for(int i=0; i 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 19 | 20 |