【QT项目——视频播放器——解码】5.1decoder-5.10音频重采样

5.1 avcodec_find_decoder、AVCodecContext、avcodec_parameters_to_context

1、确定解码器,通过avcodec_find_decoder获取解码器,返回AVCodec这个结构体

avcodec_register_all();  // 注册 所有解码器
AVCodec *avcodec_find_decoder(enum AVCodecID id) // 通过传递id号来获取对应的解码器
AVCodec *avcodec_find_decoder_by_name(const char * name) // 通过字符串获取解码器————硬解码
avcodec_find_decoder_by_name("h264_mediacodec"); // 通过名字

2、解码时候还需要解码上下文 AVCodecContext(本次解码的信息)

AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)   // 申请创建上下文空间
void avcodec_free_context(AVCodecContext **avctx)  // 空间释放
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec,AVDictionary **options);  // 打开解码器
/libavcodec/options_table.h  参数设置
int thread_count;   // 多线程解码,充分利用CPU资源
time_base; // 时间基数

3、参数设置,除了手动设置,还可以通过函数avcodec_parameters_to_context

avcodec_parameters_to_context,将参数设置直接进行拷贝,从AVStream里面进行拷贝

5.3 AVFrame (在打开解码器上下文之后开始逐帧进行解码,解码前需要先关注AVFrame这个结构体,用于存放解码后的数据)

AVFrame就是一幅独立的图像!!!

AVFrame * frame = av_frame_alloc()    // 分配空间(分配和释放与AVPacket相同)
void av_frame_free(AVFrame **frame)  // 空间释放
int av_frame_ref(AVFrame *dst, const AVFrame *src);   // 引用计数
AVFrame *av_frame_clone(const AVFrame *src);  // 复制,重新创建空间,引用空间+1
void av_frame_unref(AVFrame *frame);  // 直接引用计数减一(空间释放方法二)

uint8_t *data[AV_NUM_DATA_POINTERS];
int linesize[AV_NUM_DATA_POINTERS];
int width,height; int nb_samples;  // nb_samples单通道的样本数量,一个样本2字节
int64_t pts; int64_t pkt_dts;  
int sample_rate; uint64_t channel_layout; int channels;
int format;  // AVPixelFormat AVSapleFormat;  // 像素格式 

linesize:存放大小,目的是为了对齐
宽度一行数据的大小
通道一行数据的大小
在这里插入图片描述

5.4 解码函数

avcodec_send_packet,将packet写到解码队列中去

int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);   // 内存开销问题

avcodec_receive_frame,从已解码成功的数据中取出一个frame

int avcodec_receive_frame(AVCodecContext *avctx,AVFrame *frame);  

ps:send一次,receive不一定是一次

问题集锦:1、播放最后几帧显示不了,那是缓冲帧的问题。传null,(解决播放时候最后几帧不显示的问题)

// 发送packet 到解码线程,send传NULL(将pkt换成null)后调用多次receive,会取出所有的缓冲帧
re = avcodec_send_packet(cc,pkt);    

2、要加头文件

在这里插入图片描述
包含了库之后要把对应的头文件也包含进来
在这里插入图片描述

3 重采样有报错

在这里插入图片描述

5.6 视频像素格式转换和尺寸转换(可以用GPU来做,效率更高)ffmpeg接口简单(唯一优势),但性能开销大

sws_getContext   像素格式转换上下文,每次都会新创建
struct SwsContext *sws_getCachedContext(struct SwsContext *context(传格式转换上下文地址), 
	int srcW(原宽), int srcH(原高), enum AVPixelForamt srcFormat(原像素格式), 
	int dstW(目标宽), int dstH(目标高), enum AVPixelFormat dstFormat(目标像素格式),
	int flags, SwsFilter * srcFilter,
	SwsFilter *dstFilter, const double *param );
第一个函数sws_getCachedContext只是创建好像素格式转换的上下文,具体的逐帧转换用sws_scale

int sws_scale(struct Swscontext * c, const uint8_t *const srcSlice[],
	const int srcStride[](linesize,一行大小,宽度), int srcSliceY(0, int srcSliceH(图像高度);
	uint8_t *const dst[](目标地址), const int dstStride[](输出的一行大小,linesize));
	
void sws_freeContext(struct SwsContext *swsContext);  // 释放上下文,传地址就可以

int flags, SwsFilter * srcFilter, 这里的flag指的是各种算法,主要是针对尺寸的变化,不涉及像素格式转化,具体如下
在这里插入图片描述

5.9 音频重采样

SwrContext

音频解码出来不能直接播放,需要重采样(解码出来是32位,声卡不支持,所以需要重采样)
ffmpeg所有处理都需要上下文,因为是C 语言的一个特点,上下文,不像C++ 有个对象就行了,而C语言需要有个指针贯穿前后,将他们关联起来,所以有这么一个结构体的上下文

SwrContext *swr_alloc(void);  // 分配和初始化
SwrContext *swr_alloc_set_opts(
	struct SwrContext *s,  //重采样上下文 
	int64_t out_ch_layout,  // 输出的声道标准
	AVSampleFormat out_sample_fmt,  // 输出的样本格式
	int out_sample_rate,  // 输出的样本率
	int64_t in_ch_layout,  
	AVSampleFormat in_sample_fmt, // 输入的格式
	int in_sample_rate, // 输入的样本率
	int log_offset,void *log_ctx); // 两个日志传0就行
int swr_init(struct SwrContext *s); // 初始化上下文,然后进行格式转换
void swr_free
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值