1 FFmpeg 播放视频
1.1 通过自定义GLSurfaceView
1.1.1 java 操作
- 自定义GLSurfaceView
- 创建native 方法并调用
HPlay extends GLSurfaceView
public native void OpenBySurface(String url, Object surface);
1.1.2 c++ 操作
- ANativeWindow 原始窗口初始化
- 设置窗口buffer大小
- 锁定窗口,然后等待绘制surface
- 解锁窗口,并且绘制窗口
//显示窗口初始化
ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env,surface);
//设置窗口buffer大小
ANativeWindow_setBuffersGeometry(nativeWindow,width,height,WINDOW_FORMAT_RGBA_8888);
ANativeWindow_Buffer windowsBuf;
//锁定窗口,然后等待绘制surface
ANativeWindow_lock(nativeWindow,&windowsBuf,0);
uint8_t *dst = (uint8_t*)wbuf.bits;
memcpy(dst,rgb,width*height*4);
//解锁窗口,并且绘制窗口
ANativeWindow_unlockAndPost(nativeWindow);
1.2 通过自定义OpenGL shader
1.2.1 获取原始窗口
ANativeWindow *nwin = ANativeWindow_fromSurface(env, surface);
1.2.2 EGL display创建和初始化
- 1 EGL display创建和初始化
//1 获取原始窗口
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- 2 surface的配置和创建
//输出配置
EGLConfig config;
EGLint configNum;
EGLint configSpec[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE
};
//创建surface
EGLSurface winsurface = eglCreateWindowSurface(display, config, nwin, 0);
- 3 context 创建关联的上下文
const EGLint ctxAttr[] = {
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
};
EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctxAttr);
- 4 顶点和片元shader初始化
//顶点shader初始化
GLint vsh = InitShader(vertexShader, GL_VERTEX_SHADER);
//片元yuv420 shader初始化
GLint fsh = InitShader(fragYUV420P, GL_FRAGMENT_SHADER);
- 5 创建渲染程序
//创建渲染程序
GLint program = glCreateProgram();
//渲染程序中加入着色器代码
glAttachShader(program, vsh);
glAttachShader(program, fsh);
//链接程序
glLinkProgram(program);
GLint status = 0;
glGetProgramiv(program, GL_LINK_STATUS, &status);
glUseProgram(program);
- 6 加入顶点坐标和材质顶点坐标
//加入三维顶点数据 两个三角形组成正方形
static float vers[] = {
1.0f, -1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
};
GLuint apos = (GLuint) glGetAttribLocation(program, "aPosition");
glEnableVertexAttribArray(apos);
//传递顶点
glVertexAttribPointer(apos, 3, GL_FLOAT, GL_FALSE, 12, vers);
//加入材质坐标数据
static float txts[] = {
1.0f, 0.0f, //右下
0.0f, 0.0f,
1.0f, 1.0f,
0.0, 1.0
};
GLuint atex = (GLuint) glGetAttribLocation(program, "aTexCoord");
glEnableVertexAttribArray(atex);
glVertexAttribPointer(atex, 2, GL_FLOAT, GL_FALSE, 8, txts);
- 7 材质纹理初始化
//设置纹理层
glUniform1i(glGetUniformLocation(program, "yTexture"), 0); //对于纹理第1层
glUniform1i(glGetUniformLocation(program, "uTexture"), 1); //对于纹理第2层
glUniform1i(glGetUniformLocation(program, "vTexture"), 2); //对于纹理第3层
//创建opengl纹理
GLuint texts[3] = {0};
//创建三个纹理
glGenTextures(3, texts);
//设置纹理属性
glBindTexture(GL_TEXTURE_2D, texts[0]);
//缩小的过滤器
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//设置纹理的格式和大小
glTexImage2D(GL_TEXTURE_2D,
0, //细节基本 0默认
GL_LUMINANCE,//gpu内部格式 亮度,灰度图
width, height, //拉升到全屏
0, //边框
GL_LUMINANCE,//数据的像素格式 亮度,灰度图 要与上面一致
GL_UNSIGNED_BYTE, //像素的数据类型
NULL //纹理的数据
);
......
- 8 纹理的修改和显示
unsigned char *buf[3] = {0};
buf[0] = new unsigned char[width * height];
buf[1] = new unsigned char[width * height / 4];
buf[2] = new unsigned char[width * height / 4];
//420p yyyyyyyy uu vv
if (feof(fp) == 0) {
//yyyyyyyy
fread(buf[0], 1, width * height, fp);
fread(buf[1], 1, width * height / 4, fp);
fread(buf[2], 1, width * height / 4, fp);
}
//激活第1层纹理,绑定到创建的opengl纹理
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texts[0]);
//替换纹理内容
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE,
buf[0]);
//三维绘制
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
//窗口显示
eglSwapBuffers(display, winsurface);
1.2.3 获取原始窗口
2 OpenSL ES 播放PCM音频
2.1 配置环境
cmake
target_link_libraries(
...
OpenSLES
...)
2.2 C++ 操作步骤
2.2.1 创建引擎
SLObjectltf engineObject = NULL;//存放引擎对象
SLEngineltf engineEngine = NULL;//存放引擎接口
slCraeateEngine(&engineObject ,
0, //SLuint32 numOptions
NULL, //选择项目 默认参数const SLEngineOption *pEngineOption
0, //Sluint32 numInterface 支持接口的数量
NULL, //SLInterfaceID支持的接口
NULL) // 接口表示数值,是否支持,也是一个数组
//实例化引擎
(*engineObject)->Realize(engineObject,//对象
SL_BOOLEAN_FALSE);//SL_BOOLEAN_FALSE 是阻塞,true是立马返回
//获取接口
(*engineObject)->GetInterface(engineObject,//对应
SL_IID_ENGINE,//SL_IID_ENGINE接口类型 通过ID号获取接口
&engineEngine);
2.2.2 创建混音器
SLEngineltf engineEngine = NULL;//存放引擎接口
SLObjectltf outputMixObject= NULL;//存放引擎对象
(*engineEngine )->CreateOutputMix(engineEngine,&outMixObject,0,0,0);
//实例化引擎
(*outputMixObject)->Realize(outputMixObject,//对象
SL_BOOLEAN_FALSE);//SL_BOOLEAN_FALSE 是阻塞,true是立马返回
//获取接口
SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX,outputMixObject}
SDLDataSink audioSnk = {&outputMix,NULL};
2.2.3 配置音频信息
SLDataLocator_AndroidSimpleBufferQueue
android_queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,2};
SLDataFormat_OPCM pcm={
SL_DATAFORMAT_PCM,//播放pcm格式的数据
2, //2个声道
SL_SAMPLINGRATE_44_1,// 44100hz的频率
SL_PCMSAMPLEFORMAT_FIXED_16,//位数16位
SL_PCMSAMPLEFORMAT_FIXED_16,//
SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,//立体声(前左前右)
SL_BYTEBORDER_LITTLEENDIAN//高位在前还是低位在前
}
SLDataSource slDataSource ={&android_queue,&pcm};//缓存队列的配置信息
2.2.4 创建播放器
SLObjectltf pcmPlayerObject= NULL;//存放引擎对象
SLEngineltf pcmPlayerPlay= NULL;//存放引擎接口
const SLInterfaceID ids[1] {SL_IID_BUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
(*pcmPlayerPlay)->CreateAudioPlay(pcmPlayerPlay,
&pcmPlayerObject,&slDataSource,
&audioSnk,1,ids,req);
//初始化播放器
(*pcmPlayerObject)->Realize(pcmPlayerObject,//对象
SL_BOOLEAN_FALSE);
//得到接口后调用,获取Player接口
(*pcmPlayerObject)->GetInterface(pcmPlayerObject,//对应
SL_IID_PLAY,//SL_IID_ENGINE接口类型 通过ID号获取接口
&pcmPlayerPlay);