package com.azhon.videoh264;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import java.nio.ByteBuffer;
/**
* 项目名: VideoH264
* 包名 com.azhon.videoh264
* 文件名: NV21EncoderH264
* 创建时间: 2020/2/26 on 23:19
* 描述: TODO YUV420下的NV21视频帧数据编码成H264
*
* @author 阿钟
*/
public class NV21EncoderH264 {
private int width, height;
private int frameRate = 30;
private MediaCodec mediaCodec;
private EncoderListener encoderListener;
public NV21EncoderH264(int width, int height) {
this.width = width;
this.height = height;
initMediaCodec();
}
private void initMediaCodec() {
try {
mediaCodec = MediaCodec.createEncoderByType("video/avc");
//height和width一般都是照相机的height和width。
//TODO 因为获取到的视频帧数据是逆时针旋转了90度的,所以这里宽高需要对调
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", height, width);
//描述平均位速率(以位/秒为单位)的键。 关联的值是一个整数
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, width * height * 5);
//描述视频格式的帧速率(以帧/秒为单位)的键。帧率,一般在15至30之内,太小容易造成视频卡顿。
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
//色彩格式,具体查看相关API,不同设备支持的色彩格式不尽相同
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
//关键帧间隔时间,单位是秒
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
//开始编码
mediaCodec.start();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将NV21编码成H264
*/
public void encoderH264(byte[] data) {
//将NV21编码成NV12
byte[] bytes = NV21ToNV12(data, width, height);
//视频顺时针旋转90度
byte[] nv12 = rotateNV290(bytes, width, height);
try {
//拿到输入缓冲区,用于传送数据进行编码
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
//拿到输出缓冲区,用于取到编码后的数据
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
//当输入缓冲区有效时,就是>=0
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
//往输入缓冲区写入数据
inputBuffer.put(nv12);
//五个参数,第一个是输入缓冲区的索引,第二个数据是输入缓冲区起始索引,第三个是放入的数据大小,第四个是时间戳,保证递增就是
mediaCodec.queueInputBuffer(inputBufferIndex, 0, nv12.length, System.nanoTime() / 1000, 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
//拿到输出缓冲区的索引
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
while (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size];
outputBuffer.get(outData);
//outData就是输出的h264数据
if (encoderListener != null) {
encoderListener.h264(outData);
}
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
/**
* 因为从MediaCodec不支持NV21的数据编码,所以需要先讲NV21的数据转码为NV12
*/
private byte[] NV21ToNV12(byte[] nv21, int width, int height) {
byte[] nv12 = new byte[width * height * 3 / 2];
int frameSize = width * height;
int i, j;
System.arraycopy(nv21, 0, nv12, 0, frameSize);
for (i = 0; i < frameSize; i++) {
nv12[i] = nv21[i];
}
for (j = 0; j < frameSize / 2; j += 2) {
nv12[frameSize + j - 1] = nv21[j + frameSize];
}
for (j = 0; j < frameSize / 2; j += 2) {
nv12[frameSize + j] = nv21[j + frameSize - 1];
}
return nv12;
}
/**
* 此处为顺时针旋转旋转90度
*
* @param data 旋转前的数据
* @param imageWidth 旋转前数据的宽
* @param imageHeight 旋转前数据的高
* @return 旋转后的数据
*/
private byte[] rotateNV290(byte[] data, int imageWidth, int imageHeight) {
byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2];
// Rotate the Y luma
int i = 0;
for (int x = 0; x < imageWidth; x++) {
for (int y = imageHeight - 1; y >= 0; y--) {
yuv[i] = data[y * imageWidth + x];
i++;
}
}
// Rotate the U and V color components
i = imageWidth * imageHeight * 3 / 2 - 1;
for (int x = imageWidth - 1; x > 0; x = x - 2) {
for (int y = 0; y < imageHeight / 2; y++) {
yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x];
i--;
yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x - 1)];
i--;
}
}
return yuv;
}
/**
* 设置编码成功后数据回调
*/
public void setEncoderListener(EncoderListener listener) {
encoderListener = listener;
}
public interface EncoderListener {
void h264(byte[] data);
}
}
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
VideoH264.zip (101个子文件)
gradlew.bat 2KB
executionHistory.bin 547KB
jarAnalysis.bin 73KB
classAnalysis.bin 58KB
fileHashes.bin 41KB
taskHistory.bin 26KB
outputFiles.bin 20KB
resourceHashesCache.bin 18KB
last-build.bin 1B
.DS_Store 6KB
.gitignore 208B
build.gradle 927B
build.gradle 572B
settings.gradle 44B
gradlew 5KB
app.iml 11KB
VideoH264.iml 863B
gradle-wrapper.jar 53KB
NV21EncoderH264.java 6KB
MainActivity.java 5KB
ExampleInstrumentedTest.java 754B
ExampleUnitTest.java 380B
buildOutputCleanup.lock 17B
executionHistory.lock 17B
fileContent.lock 17B
javaCompile.lock 17B
fileHashes.lock 17B
ic_launcher_round.png 16KB
ic_launcher_round.png 12KB
ic_launcher.png 10KB
ic_launcher.png 8KB
ic_launcher_round.png 7KB
ic_launcher_round.png 5KB
ic_launcher.png 5KB
ic_launcher.png 4KB
ic_launcher_round.png 3KB
ic_launcher.png 3KB
proguard-rules.pro 751B
gradle.properties 1KB
local.properties 425B
gradle-wrapper.properties 232B
cache.properties 51B
gc.properties 0B
gc.properties 0B
build_file_checksums.ser 535B
workspace.xml 6KB
misc.xml 6KB
ic_launcher_background.xml 5KB
Project.xml 3KB
ic_launcher_foreground.xml 2KB
Gradle__androidx_test_espresso_espresso_idling_resource_3_2_0_aar.xml 963B
Gradle__androidx_test_espresso_espresso_core_3_2_0_aar.xml 886B
Gradle__androidx_drawerlayout_drawerlayout_1_0_0_aar.xml 858B
Gradle__androidx_appcompat_appcompat_1_1_0_aar.xml 834B
Gradle__androidx_fragment_fragment_1_1_0_aar.xml 826B
Gradle__androidx_test_monitor_1_2_0_aar.xml 817B
Gradle__androidx_test_ext_junit_1_1_1_aar.xml 815B
Gradle__androidx_test_runner_1_2_0_aar.xml 810B
Gradle__androidx_test_core_1_2_0_aar.xml 796B
Gradle__androidx_core_core_1_1_0_aar.xml 794B
Gradle__org_hamcrest_hamcrest_integration_1_3_jar.xml 781B
AndroidManifest.xml 778B
Gradle__androidx_annotation_annotation_1_1_0_jar.xml 753B
Gradle__org_hamcrest_hamcrest_library_1_3_jar.xml 752B
gradle.xml 748B
Gradle__androidx_vectordrawable_vectordrawable_animated_1_1_0_aar.xml 733B
Gradle__org_hamcrest_hamcrest_core_1_3_jar.xml 732B
Gradle__com_squareup_javawriter_2_1_1_jar.xml 725B
Gradle__androidx_versionedparcelable_versionedparcelable_1_1_0_aar.xml 723B
Gradle__androidx_lifecycle_lifecycle_livedata_core_2_0_0_aar.xml 723B
Gradle__javax_inject_javax_inject_1_jar.xml 711B
Gradle__androidx_lifecycle_lifecycle_viewmodel_2_1_0_aar.xml 703B
Gradle__androidx_appcompat_appcompat_resources_1_1_0_aar.xml 703B
Gradle__androidx_lifecycle_lifecycle_livedata_2_0_0_aar.xml 698B
Gradle__androidx_lifecycle_lifecycle_runtime_2_1_0_aar.xml 693B
Gradle__androidx_vectordrawable_vectordrawable_1_1_0_aar.xml 688B
Gradle__net_sf_kxml_kxml2_2_3_0_jar.xml 686B
Gradle__androidx_cursoradapter_cursoradapter_1_0_0_aar.xml 681B
Gradle__androidx_interpolator_interpolator_1_0_0_aar.xml 674B
Gradle__androidx_arch_core_core_runtime_2_0_0_aar.xml 668B
Gradle__androidx_savedstate_savedstate_1_0_0_aar.xml 660B
Gradle__androidx_customview_customview_1_0_0_aar.xml 660B
Gradle__junit_junit_4_12_jar.xml 655B
Gradle__androidx_viewpager_viewpager_1_0_0_aar.xml 653B
Gradle__androidx_activity_activity_1_0_0_aar.xml 646B
Gradle__androidx_loader_loader_1_0_0_aar.xml 632B
Gradle__androidx_lifecycle_lifecycle_common_2_1_0_jar.xml 584B
runConfigurations.xml 564B
Gradle__androidx_arch_core_core_common_2_1_0_jar.xml 559B
Gradle__androidx_collection_collection_1_1_0_jar.xml 557B
activity_main.xml 490B
Gradle__androidx_constraintlayout_constraintlayout_1_1_3_aar.xml 488B
Gradle__androidx_constraintlayout_constraintlayout_solver_1_1_3_jar.xml 412B
modules.xml 395B
styles.xml 383B
Gradle__com_google_code_findbugs_jsr305_2_0_1_jar.xml 359B
ic_launcher_round.xml 272B
ic_launcher.xml 272B
colors.xml 208B
encodings.xml 159B
共 101 条
- 1
- 2
资源评论
- xiaoxiongaa1232023-01-10感谢楼主分享
Code-Porter
- 粉丝: 1w+
- 资源: 39
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功