NDKr20编译ffmpeg-4.2.2

在前面,我们已经将ffmpeg引入到Android工程中去了,如果你还不知道如何在Android中使用ffmpeg,可以回头看看这篇文章:
将ffmpeg引入到Android Studio工程中
那么如何使用ffmeg对音视频做一些开发工作呢?今天我们学习来学习一下使用ffmpeg对音视频进行解封装。

我们先来看一张图:
NDKr20编译ffmpeg-4.2.2_第1张图片
从图中可以看出要想对音视频进行解码,首先需要的是对音视频进行解封装。
解封装主要是为了获取一些音视频的信息,比如时长,视频所使用的编码器,音频流的索引、视频流的索引等等。

我们用一张图展示一下解封装的步骤以及需要用到的一些相关API:
NDKr20编译ffmpeg-4.2.2_第2张图片

首先引入log库,定义一个宏,方便后面打印日志。

#ifndef FLYPLAYER_FLYLOG_H
#define FLYPLAYER_FLYLOG_H

#include 

//定义一个宏,使用log库输出日志

#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"FFMPEG",__VA_ARGS__)

#endif //FLYPLAYER_FLYLOG_H

解封装的主要代码:

//引入ffmpeg的头文件
// 因为ffmpeg是纯C代码,要在cpp中使用则需要使用 extern "C"
extern "C" {
#include "libavutil/avutil.h"
#include 
}

/**
 * 将数据转换成double类型的一个方法
 * @param r
 * @return
 */
static double r2d(AVRational r)
{
    return r.num==0||r.den == 0 ? 0 :(double)r.num/(double)r.den;
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_flyer_ffmpeg_FFmpegUtils_analyzeMedia(JNIEnv *env, jclass clazz, jstring media_path) {

    //初始化解封装
    av_register_all();
    //初始化网络
    avformat_network_init();

    //打开文件
    AVFormatContext *ic = NULL;
    const char *path = env->GetStringUTFChars(media_path, 0);
    int re = avformat_open_input(&ic,path,0,0);
    if(re != 0)
    {
        LOGE("avformat_open_input failed!:%s",av_err2str(re));
        return -1;
    }
    LOGE("avformat_open_input %s success!",path);
    //获取流信息
    re = avformat_find_stream_info(ic,0);
    if(re != 0)
    {
        LOGE("avformat_find_stream_info failed!");
        return -3;
    }
    LOGE("duration = %lld nb_streams = %d",ic->duration,ic->nb_streams);

    int fps = 0;
    int videoStream = -1;
    int audioStream = -1;

    // 有两个方法获取视频或者视频流的索引,一种是遍历,一种是使用自动探测的api
    // 通过遍历的方法获取索引
    for(int i = 0; i < ic->nb_streams; i++)
    {
        AVStream *as = ic->streams[i];
        if(as->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            LOGE("视频数据");
            videoStream = i;
            fps = r2d(as->avg_frame_rate);

            LOGE("videoStream=%d,fps = %d,width=%d height=%d codeid=%d pixformat=%d",
                 videoStream,fps,
                 as->codecpar->width,
                 as->codecpar->height,
                 as->codecpar->codec_id,
                 as->codecpar->format
            );
        }
        else if(as->codecpar->codec_type ==AVMEDIA_TYPE_AUDIO )
        {
            LOGE("音频数据");
            audioStream = i;
            LOGE("audioStream=%d,sample_rate=%d channels=%d sample_format=%d",
                 audioStream,
                 as->codecpar->sample_rate,
                 as->codecpar->channels,
                 as->codecpar->format
            );
        }
    }

    // 通过探测的方式获取索引
    //获取音频流信息
    audioStream = av_find_best_stream(ic,AVMEDIA_TYPE_AUDIO,-1,-1,NULL,0);
    LOGE("av_find_best_stream audioStream = %d",audioStream);

    env->ReleaseStringUTFChars(media_path, path);

    //关闭上下文
    avformat_close_input(&ic);

    LOGE("解封装成功","");
    return 0;
}

运行看看打印的日志有没有解封装成功:
NDKr20编译ffmpeg-4.2.2_第3张图片

最后如果你对音视频开发感兴趣可扫码关注,笔者在各个知识点学习完毕之后也会使用ffmepg从零开始编写一个多媒体播放器,包括本地播放及网络流播放等等。欢迎关注,后续我们共同探讨,共同进步。

你可能感兴趣的:(NDKr20编译ffmpeg-4.2.2)