一、解码函数流程
1、解码器的注册
avcodec_register_all();
2、查找解码器
//软解码器 28(codec_id = h264的) ID号解封装的时候,音频也是对应的
AVCodec *codec = avcodec_find_decoder(ic->streams[videoStream]->codecpar->codec_id);
//硬解码
codec = avcodec_find_decoder_by_name("h264_mediacodec");
硬解码时需设置一下方法,会自动调用
extern "C"
JNIEXPORT
jint JNI_OnLoad(JavaVM *vm, void *res) {
av_jni_set_java_vm(vm, 0);
return JNI_VERSION_1_4;
}
3、创建和清理编码环境
//解码器初始化
AVCodecContext *vc = avcodec_alloc_context3(codec);
// 清除解码环境
void avcodec_free_context(AVCodecContext **avctx);
4、填充编解码器上下文
int avcodec_parameters_to_context(AVCodecContext *codec,
const AVCodecParameters *par);
5、打开解码器
//打开解码器
re = avcodec_open2(vc, 0, 0);
6、开始解码
int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);//将AVPacket 插入到一个队列中
int avcodec_receive_frame(AVCodecContex t *avctx, AVFrame *frame); // 取出一个解码好的AVFrame
二、解码结构体
5、AVFrame(存放解码后的数据)
• AVFrame *frame = av_frame_alloc(); //空间分配,创建对象
• void av_frame_free(AVFrame **frame); //释放
• int av_frame_ref(AVFrame *dst, const AVFrame *src); //增加引用
• AVFrame *av_frame_clone(const AVFrame *src);
• void av_frame_unref(AVFrame *frame);
/**
* pointer to the picture/channel planes.
* */
• uint8_t *data[AV_NUM_DATA_POINTERS];
/**
* For video, size in bytes of each picture line.
* For audio, size in bytes of each plane.
*
* For audio, only linesize[0] may be set. For planar audio, each channel
* plane must be the same size.
*
* For video the linesizes should be multiples of the CPUs alignment
* preference, this is 16 or 32 for modern desktop CPUs.
* Some code requires such alignment other code can be slower without
* correct alignment, for yet other it makes no difference.
*
* @note The linesize may be larger than the size of usable data -- there
* may be extra padding present for performance reasons.
*/
• int linesize[AV_NUM_DATA_POINTERS];
• int width, height; //视频宽高
• int nb_samples; //单通道样本数量
• int64_t pts;int64_t pkt_dts;
• int sample_rate;uint64_t channel_layout;int channels;
• int format; //AVPixelFormat AVSampleFormat
三、视频像素尺寸转换和音频重采样
①视频像素尺寸转换
可以采用shader处理,效率高,这里使用FFmpeg本身函数。
sws_getContext 得到像素尺寸转化上下文
转换函数
int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
const int srcStride[], int srcSliceY, int srcSliceH,
uint8_t *const dst[], const int dstStride[]);
②音频重采样
//音频重采样上下文初始化
SwrContext *actx = swr_alloc();
actx = swr_alloc_set_opts(actx,
av_get_default_channel_layout(2),
AV_SAMPLE_FMT_S16, ac->sample_rate,
av_get_default_channel_layout(ac->channels),
ac->sample_fmt, ac->sample_rate,
0, 0);
swr_init(actx);
/** Convert audio.
*
* in and in_count can be set to 0 to flush the last few samples out at the
* end.
*
* If more input is provided than output space, then the input will be buffered.
* You can avoid this buffering by using swr_get_out_samples() to retrieve an
* upper bound on the required number of output samples for the given number of
* input samples. Conversion will run directly without copying whenever possible.
*
* @param s allocated Swr context, with parameters set
* @param out output buffers, only the first one need be set in case of packed audio
* @param out_count amount of space available for output in samples per channel
* @param in input buffers, only the first one need to be set in case of packed audio
* @param in_count number of input samples available in one channel
*
* @return number of samples output per channel, negative value on error
*/
int swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
const uint8_t **in , int in_count);
释放上下文函数
void sws_freeContext(struct SwsContext *swsContext);
后记
-- 完整代码GitHub:https://github.com/puhaojie/testffmpeg