一、解封装基本流程

①av_register_All()初始化解封装,注册解析和封装的格式。
  ②avformat_netword_init()//初始化网络,解析rtsp协议
  ③avformat_open_init()//打开
  ④avformat_find_stream_info()//探测
  ⑤av_find_best_stream() //获取音视频的索引
  ⑥av_read_Frame()//读一帧数据,音频可能好几帧、视频是I帧
  ⑦av_seek_frame()//跳转

二、函数介绍

  ①av_register_all();
    初始化解封装,注册解封装格式
    在最开始编译FFmpeg的时候,我们做了一个configure的配置,其中开启或者关闭了很多选项。configure的配置会生成两个文件:config.mk和config.h。
      config.mk:就是makefile文件需要包含进去的子模块,会作用在编译阶段,帮助开发者编译出正确的库。
      config.h:作用在运行阶段,主要是确定需要注册那些容器及编解码格式到FFmpeg框架中。
    调用 av_register_all 就可以注册config.h里面开发的编解码器,然后会注册所有的Muxer和Demuxer(封装格式),最后注册所有的Protocol(协议)。

  ②avformat_network_init();
    初始化网络,rtsp流

  ③avformat_open_input(&ic,path,0,0);
    打开文件并解析视频流、音频流、流的参数,
      参数:AVFormactContext **ps;
           const char *URL;
           AVInputFormat *fmt;
           AVDictionary *options;

  ④avformat_find_stream_info()
    探测

  ⑤av_find_best_stream()
    获取对应的视频流或者视频流 还有一种方式:遍历返回值的一个成员(Stream数组),根据标志位判断是音频还是视频。

  ⑥av_read_frame();
    从AVPacket中,读取帧信息,av_read_packet函数读出的是包,其可能是半帧或者多帧,不保证帧的完整性。
    av_read_frame对av_read_packet进行了封装,使其读出的数据总是完整的帧,av_read_frame函数调用了read_fram_internal。读取码流中若干个音频帧或者I帧视频。例如,在解码视频的时候,每解码一个视频,需要先调用av_read_frame获得一帧视频的压缩数据,然后才能对该数据进行解码
    返回值有三种结果:
      ①如果packet_buffer存在数据,根据PTS返回AVPacket。
      ②如果packet_buffer不存在数据,调用av_read_frame_internal函数。
      ③(待补充)

代码展示:

/*****************************FILE INFOMATION***********************************
**
   
    av_register_all();
     //初始化解封装,注册解封装格式
    在最开始编译FFmpeg的时候,我们做了一个configure的配置,其中开启或者关闭了很多选项。configure的配置会生成两个文件:config.mk和config.h。
        config.mk:就是makefile文件需要包含进去的子模块,会作用在编译阶段,帮助开发者编译出正确的库。
        config.h:作用在运行阶段,主要是确定需要注册那些容器及编解码格式到FFmpeg框架中。
    调用 av_register_all 就可以注册config.h里面开发的编解码器,然后会注册所有的Muxer和Demuxer(封装格式),最后注册所有的Protocol(协议)。

    avformat_network_init();
    //初始化网络,rtsp流

    avformat_open_input(&ic,path,0,0);
    //打开文件并解析视频流、音频流、流的参数,
        参数:AVFormactContext **ps;  
              const char *URL;
              AVInputFormat *fmt;
              AVDictionary *options;

    avformat_find_stream_info()
    //探测

    av_find_best_stream()
    //获取对应的视频流或者视频流 还有一种方式:遍历返回值的一个成员(Stream数组),根据标志位判断是音频还是视频。

    av_read_frame();
    从AVPacket中,读取帧信息,av_read_packet函数读出的是包,其可能是半帧或者多帧,不保证帧的完整性。
    av_read_frame对av_read_packet进行了封装,使其读出的数据总是完整的帧,av_read_frame函数调用了read_fram_internal。
    读取码流中若干个音频帧或者I帧视频。例如,在解码视频的时候,每解码一个视频,需要先调用av_read_frame获得一帧视频的压缩数据,然后才能对该数据进行解码
    返回值有三种结果:
        ①如果packet_buffer存在数据,根据PTS返回AVPacket。
        ②如果packet_buffer不存在数据,调用av_read_frame_internal函数。
        ③不够清晰?(android视频开发书)
    
    
**
*******************************************************************************/


#include <jni.h>
#include <string>
#include <android/log.h>
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,"testff",__VA_ARGS__)

extern "C"{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}
#include<iostream>
using namespace std;

static double r2d(AVRational r)
{
    return r.num==0||r.den == 0 ? 0 :(double)r.num/(double)r.den;
}

extern "C"
JNIEXPORT jstring
JNICALL
Java_aplay_testffmpeg_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++ ";
    hello += avcodec_configuration();
    //初始化解封装
    av_register_all();
    //初始化网络
    avformat_network_init();

    //打开文件
    AVFormatContext *ic = NULL;
    char path[] = "/sdcard/1080.mp4";
    //char path[] = "/sdcard/video.flv";
    int re = avformat_open_input(&ic,path,0,0);
    if(re != 0)
    {
        LOGW("avformat_open_input failed!:%s",av_err2str(re));
        return env->NewStringUTF(hello.c_str());
    }
    LOGW("avformat_open_input %s success!",path);
    //获取流信息
    re = avformat_find_stream_info(ic,0);
    if(re != 0)
    {
        LOGW("avformat_find_stream_info failed!");
    }
    LOGW("duration = %lld nb_streams = %d",ic->duration,ic->nb_streams);

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

    for(int i = 0; i < ic->nb_streams; i++)
    {
        AVStream *as = ic->streams[i];
        if(as->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            LOGW("视频数据");
            videoStream = i;
            fps = r2d(as->avg_frame_rate);

            LOGW("fps = %d,width=%d height=%d codeid=%d pixformat=%d",fps,
                 as->codecpar->width,
                 as->codecpar->height,
                 as->codecpar->codec_id,
                 as->codecpar->format
            );
        }
        else if(as->codecpar->codec_type ==AVMEDIA_TYPE_AUDIO )
        {
            LOGW("音频数据");
            audioStream = i;
            LOGW("sample_rate=%d channels=%d sample_format=%d",
                 as->codecpar->sample_rate,
                 as->codecpar->channels,
                 as->codecpar->format
            );
        }
    }
    //ic->streams[videoStream];
    //获取音频流信息
    audioStream = av_find_best_stream(ic,AVMEDIA_TYPE_AUDIO,-1,-1,NULL,0);
    LOGW("av_find_best_stream audioStream = %d",audioStream);

    //读取帧数据
    AVPacket *pkt = av_packet_alloc();
    for(;;)
    {
        int re = av_read_frame(ic,pkt);
        if(re != 0)
        {

            LOGW("读取到结尾处!");
            int pos = 20 * r2d(ic->streams[videoStream]->time_base);
            av_seek_frame(ic,videoStream,pos,AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME );
            continue;
        }
        LOGW("stream = %d size =%d pts=%lld flag=%d",
             pkt->stream_index,pkt->size,pkt->pts,pkt->flags
        );
        //
        
        av_packet_unref(pkt);
    }



    //关闭上下文
    avformat_close_input(&ic);
    return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_aplay_testffmpeg_MainActivity_Open(JNIEnv *env, jobject instance, jstring url_,
                                        jobject handle) {
    const char *url = env->GetStringUTFChars(url_, 0);

    // TODO
    FILE *fp = fopen(url,"rb");
    if(!fp)
    {
        LOGW("File %s open failed!",url);
    }
    else
    {
        LOGW("File %s open succes!",url);
        fclose(fp);
    }
    env->ReleaseStringUTFChars(url_, url);
    return true;
}