一、解碼函數(shù)流程
1、解碼器的注冊
avcodec_register_all();
2、查找解碼器
//軟解碼器 28(codec_id = h264的) ID號解封裝的時候,音頻也是對應(yīng)的
AVCodec *codec = avcodec_find_decoder(ic->streams[videoStream]->codecpar->codec_id);
//硬解碼
codec = avcodec_find_decoder_by_name("h264_mediacodec");
硬解碼時需設(shè)置一下方法,會自動調(diào)用
extern "C"
JNIEXPORT
jint JNI_OnLoad(JavaVM *vm, void *res) {
av_jni_set_java_vm(vm, 0);
return JNI_VERSION_1_4;
}
3、創(chuàng)建和清理編碼環(huán)境
//解碼器初始化
AVCodecContext *vc = avcodec_alloc_context3(codec);
// 清除解碼環(huán)境
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
二、解碼結(jié)構(gòu)體
5、AVFrame(存放解碼后的數(shù)據(jù))
? AVFrame *frame = av_frame_alloc(); //空間分配,創(chuàng)建對象
? 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; //單通道樣本數(shù)量
? int64_t pts;int64_t pkt_dts;
? int sample_rate;uint64_t channel_layout;int channels;
? int format; //AVPixelFormat AVSampleFormat
三、視頻像素尺寸轉(zhuǎn)換和音頻重采樣
①視頻像素尺寸轉(zhuǎn)換
可以采用shader處理,效率高,這里使用FFmpeg本身函數(shù)。
sws_getContext 得到像素尺寸轉(zhuǎn)化上下文
轉(zhuǎn)換函數(shù)
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);
釋放上下文函數(shù)
void sws_freeContext(struct SwsContext *swsContext);
后記
-- 完整代碼GitHub:https://github.com/puhaojie/testffmpeg