您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
11. 完成硬解码并完成NV21和NV12格式的shader显示编写~1
发布时间:2021-06-12 15:34:08编辑:雪饮阅读()
首先要在cpp/FFdecode.cpp中實現硬解碼:
{
#include <libavcodec/avcodec.h>
#include <libavcodec/jni.h>
}
#include "FFDecode.h"
#include "XLog.h"
void FFDecode::InitHard(void *vm)
{
av_jni_set_java_vm(vm,0);
}
bool FFDecode::Open(XParameter para,bool isHard)
{
if(!para.para) return false;
AVCodecParameters *p = para.para;
//1 查找解码器
AVCodec *cd = avcodec_find_decoder(p->codec_id);
if(isHard)
{
cd = avcodec_find_decoder_by_name("h264_mediacodec");
}
if(!cd)
{
XLOGE("avcodec_find_decoder %d failed! %d",p->codec_id,isHard);
return false;
}
XLOGI("avcodec_find_decoder success %d!",isHard);
//2 创建解码上下文,并复制参数
codec = avcodec_alloc_context3(cd);
avcodec_parameters_to_context(codec,p);
codec->thread_count = 8;
//3 打开解码器
int re = avcodec_open2(codec,0,0);
if(re != 0)
{
char buf[1024] = {0};
av_strerror(re,buf,sizeof(buf)-1);
XLOGE("%s",buf);
return false;
}
if(codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
this->isAudio = false;
}
else
{
this->isAudio = true;
}
XLOGI("avcodec_open2 success!");
return true;
}
bool FFDecode::SendPacket(XData pkt)
{
if(pkt.size<=0 || !pkt.data)return false;
if(!codec)
{
return false;
}
int re = avcodec_send_packet(codec,(AVPacket*)pkt.data);
if(re != 0)
{
return false;
}
return true;
}
//从线程中获取解码结果
XData FFDecode::RecvFrame()
{
if(!codec)
{
return XData();
}
if(!frame)
{
frame = av_frame_alloc();
}
int re = avcodec_receive_frame(codec,frame);
if(re != 0)
{
return XData();
}
XData d;
d.data = (unsigned char *)frame;
if(codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
d.size = (frame->linesize[0] + frame->linesize[1] + frame->linesize[2])*frame->height;
d.width = frame->width;
d.height = frame->height;
}
else
{
//样本字节数 * 单通道样本数 * 通道数
d.size = av_get_bytes_per_sample((AVSampleFormat)frame->format)*frame->nb_samples*2;
}
d.format = frame->format;
//if(!isAudio)
// XLOGE("data format is %d",frame->format);
memcpy(d.datas,frame->data,sizeof(d.datas));
return d;
}
爲了實現NV21和NV12格式的shader顯示,我們還需要為其在OpenGL視頻視圖中進行初始化cpp/GLVideoView.cpp:
在cpp/FFDemux.cpp中我們需要增加處理下通道與采樣率處理:
對於片元著色器以及紋理材質等的解析我們也要調整下要兼容新增的硬解碼cpp/XShader.cpp:
#define XPLAY_FFDECODE_H
#include "XParameter.h"
#include "IDecode.h"
struct AVCodecContext;
struct AVFrame;
class FFDecode:public IDecode
{
public:
static void InitHard(void *vm);
virtual bool Open(XParameter para,bool isHard=false);
//future模型 发送数据到线程解码
virtual bool SendPacket(XData pkt);
//从线程中获取解码结果,再次调用会复用上次空间,线程不安全
virtual XData RecvFrame();
protected:
AVCodecContext *codec = 0;
AVFrame *frame = 0;
};
#endif //XPLAY_FFDECODE_H
#include "XTexture.h"
#include "XLog.h"
void GLVideoView::SetRender(void *win)
{
view = win;
}
void GLVideoView::Render(XData data)
{
if(!view) return;
if(!txt)
{
txt = XTexture::Create();
txt->Init(view,(XTextureType)data.format);
}
txt->Draw(data.datas,data.width,data.height);
}
#include "XLog.h"
extern "C"{
#include <libavformat/avformat.h>
}
//打开文件,或者流媒体 rmtp http rtsp
bool FFDemux::Open(const char *url)
{
XLOGI("Open file %s begin",url);
int re = avformat_open_input(&ic,url,0,0);
if(re != 0 )
{
char buf[1024] = {0};
av_strerror(re,buf,sizeof(buf));
XLOGE("FFDemux open %s failed!",url);
return false;
}
XLOGI("FFDemux open %s success!",url);
//读取文件信息
re = avformat_find_stream_info(ic,0);
if(re != 0 )
{
char buf[1024] = {0};
av_strerror(re,buf,sizeof(buf));
XLOGE("avformat_find_stream_info %s failed!",url);
return false;
}
this->totalMs = ic->duration/(AV_TIME_BASE/1000);
XLOGI("total ms = %d!",totalMs);
GetVPara();
GetAPara();
return true;
}
//获取视频参数
XParameter FFDemux::GetVPara()
{
if (!ic) {
XLOGE("GetVPara failed! ic is NULL!");
return XParameter();
}
//获取了视频流索引
int re = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);
if (re < 0) {
XLOGE("av_find_best_stream failed!");
return XParameter();
}
videoStream = re;
XParameter para;
para.para = ic->streams[re]->codecpar;
return para;
}
//获取音频参数
XParameter FFDemux::GetAPara()
{
if (!ic) {
XLOGE("GetVPara failed! ic is NULL!");
return XParameter();
}
//获取了音频流索引
int re = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0);
if (re < 0) {
XLOGE("av_find_best_stream failed!");
return XParameter();
}
audioStream = re;
XParameter para;
para.para = ic->streams[re]->codecpar;
para.channels = ic->streams[re]->codecpar->channels;
para.sample_rate = ic->streams[re]->codecpar->sample_rate;
return para;
}
//读取一帧数据,数据由调用者清理
XData FFDemux::Read()
{
if(!ic)return XData();
XData d;
AVPacket *pkt = av_packet_alloc();
int re = av_read_frame(ic,pkt);
if(re != 0)
{
av_packet_free(&pkt);
return XData();
}
//XLOGI("pack size is %d ptss %lld",pkt->size,pkt->pts);
d.data = (unsigned char*)pkt;
d.size = pkt->size;
if(pkt->stream_index == audioStream)
{
d.isAudio = true;
}
else if(pkt->stream_index == videoStream)
{
d.isAudio = false;
}
else
{
av_packet_free(&pkt);
return XData();
}
return d;
}
FFDemux::FFDemux()
{
static bool isFirst = true;
if(isFirst)
{
isFirst = false;
//注册所有封装器
av_register_all();
//注册所有的解码器
avcodec_register_all();
//初始化网络
avformat_network_init();
XLOGI("register ffmpeg!");
}
} #include "XShader.h"
#include "XLog.h"
#include <GLES2/gl2.h>
//顶点着色器glsl
#define GET_STR(x) #x
static const char *vertexShader = GET_STR(
attribute vec4 aPosition; //顶点坐标
attribute vec2 aTexCoord; //材质顶点坐标
varying vec2 vTexCoord; //输出的材质坐标
void main(){
vTexCoord = vec2(aTexCoord.x,1.0-aTexCoord.y);
gl_Position = aPosition;
}
);
//片元着色器,软解码和部分x86硬解码
static const char *fragYUV420P = GET_STR(
precision mediump float; //精度
varying vec2 vTexCoord; //顶点着色器传递的坐标
uniform sampler2D yTexture; //输入的材质(不透明灰度,单像素)
uniform sampler2D uTexture;
uniform sampler2D vTexture;
void main(){
vec3 yuv;
vec3 rgb;
yuv.r = texture2D(yTexture,vTexCoord).r;
yuv.g = texture2D(uTexture,vTexCoord).r - 0.5;
yuv.b = texture2D(vTexture,vTexCoord).r - 0.5;
rgb = mat3(1.0, 1.0, 1.0,
0.0,-0.39465,2.03211,
1.13983,-0.58060,0.0)*yuv;
//输出像素颜色
gl_FragColor = vec4(rgb,1.0);
}
);
//片元着色器,软解码和部分x86硬解码
static const char *fragNV12 = GET_STR(
precision mediump float; //精度
varying vec2 vTexCoord; //顶点着色器传递的坐标
uniform sampler2D yTexture; //输入的材质(不透明灰度,单像素)
uniform sampler2D uvTexture;
void main(){
vec3 yuv;
vec3 rgb;
yuv.r = texture2D(yTexture,vTexCoord).r;
yuv.g = texture2D(uvTexture,vTexCoord).r - 0.5;
yuv.b = texture2D(uvTexture,vTexCoord).a - 0.5;
rgb = mat3(1.0, 1.0, 1.0,
0.0,-0.39465,2.03211,
1.13983,-0.58060,0.0)*yuv;
//输出像素颜色
gl_FragColor = vec4(rgb,1.0);
}
);
//片元着色器,软解码和部分x86硬解码
static const char *fragNV21 = GET_STR(
precision mediump float; //精度
varying vec2 vTexCoord; //顶点着色器传递的坐标
uniform sampler2D yTexture; //输入的材质(不透明灰度,单像素)
uniform sampler2D uvTexture;
void main(){
vec3 yuv;
vec3 rgb;
yuv.r = texture2D(yTexture,vTexCoord).r;
yuv.g = texture2D(uvTexture,vTexCoord).a - 0.5;
yuv.b = texture2D(uvTexture,vTexCoord).r - 0.5;
rgb = mat3(1.0, 1.0, 1.0,
0.0,-0.39465,2.03211,
1.13983,-0.58060,0.0)*yuv;
//输出像素颜色
gl_FragColor = vec4(rgb,1.0);
}
);
static GLuint InitShader(const char *code,GLint type)
{
//创建shader
GLuint sh = glCreateShader(type);
if(sh == 0)
{
XLOGE("glCreateShader %d failed!",type);
return 0;
}
//加载shader
glShaderSource(sh,
1, //shader数量
&code, //shader代码
0); //代码长度
//编译shader
glCompileShader(sh);
//获取编译情况
GLint status;
glGetShaderiv(sh,GL_COMPILE_STATUS,&status);
if(status == 0)
{
XLOGE("glCompileShader failed!");
return 0;
}
XLOGE("glCompileShader success!");
return sh;
}
bool XShader::Init(XShaderType type)
{
//顶点和片元shader初始化
//顶点shader初始化
vsh = InitShader(vertexShader,GL_VERTEX_SHADER);
if(vsh == 0)
{
XLOGE("InitShader GL_VERTEX_SHADER failed!");
return false;
}
XLOGE("InitShader GL_VERTEX_SHADER success! %d",type);
//片元yuv420 shader初始化
switch (type)
{
case XSHADER_YUV420P:
fsh = InitShader(fragYUV420P,GL_FRAGMENT_SHADER);
break;
case XSHADER_NV12:
fsh = InitShader(fragNV12,GL_FRAGMENT_SHADER);
break;
case XSHADER_NV21:
fsh = InitShader(fragNV21,GL_FRAGMENT_SHADER);
break;
default:
XLOGE("XSHADER format is error");
return false;
}
if(fsh == 0)
{
XLOGE("InitShader GL_FRAGMENT_SHADER failed!");
return false;
}
XLOGE("InitShader GL_FRAGMENT_SHADER success!");
/////////////////////////////////////////////////////////////
//创建渲染程序
program = glCreateProgram();
if(program == 0)
{
XLOGE("glCreateProgram failed!");
return false;
}
//渲染程序中加入着色器代码
glAttachShader(program,vsh);
glAttachShader(program,fsh);
//链接程序
glLinkProgram(program);
GLint status = 0;
glGetProgramiv(program,GL_LINK_STATUS,&status);
if(status != GL_TRUE)
{
XLOGE("glLinkProgram failed!");
return false;
}
glUseProgram(program);
XLOGE("glLinkProgram success!");
/////////////////////////////////////////////////////////////
//加入三维顶点数据 两个三角形组成正方形
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);
//材质纹理初始化
//设置纹理层
glUniform1i( glGetUniformLocation(program,"yTexture"),0); //对于纹理第1层
switch (type) {
case XSHADER_YUV420P:
glUniform1i(glGetUniformLocation(program, "uTexture"), 1); //对于纹理第2层
glUniform1i(glGetUniformLocation(program, "vTexture"), 2); //对于纹理第3层
break;
case XSHADER_NV21:
case XSHADER_NV12:
glUniform1i(glGetUniformLocation(program, "uvTexture"), 1); //对于纹理第2层
break;
}
XLOGI("初始化Shader成功!");
return true;
}
void XShader::Draw()
{
if(!program)
return;
//三维绘制
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
}
void XShader::GetTexture(unsigned int index,int width,int height, unsigned char *buf,bool isa)
{
unsigned int format =GL_LUMINANCE;
if(isa)
format = GL_LUMINANCE_ALPHA;
if(texts[index] == 0)
{
//材质初始化
glGenTextures(1,&texts[index]);
//设置纹理属性
glBindTexture(GL_TEXTURE_2D,texts[index]);
//缩小的过滤器
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默认
format,//gpu内部格式 亮度,灰度图
width,height, //拉升到全屏
0, //边框
format,//数据的像素格式 亮度,灰度图 要与上面一致
GL_UNSIGNED_BYTE, //像素的数据类型
NULL //纹理的数据
);
}
//激活第1层纹理,绑定到创建的opengl纹理
glActiveTexture(GL_TEXTURE0+index);
glBindTexture(GL_TEXTURE_2D,texts[index]);
//替换纹理内容
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,width,height,format,GL_UNSIGNED_BYTE,buf);
}那最後的運行結果是解決了上一次的沒有聲音的bug,但是這次又出現了黑屏的bug。。。
关键字词:NV21
相关文章
-
无相关信息