Android 用FFmpeg 播放音视频

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);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

记住我的名字啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值