FFmpeg实现简单解码

一、解码函数流程

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

你可能感兴趣的:(FFmpeg实现简单解码)