文章目录
I . FFMPEG 初始化流程
II . FFMPEG 网络初始化 avformat_network_init()
III . FFMPEG 打开媒体地址 avformat_open_input()
IV . FFMPEG 获取音 / 视频流信息 avformat_find_stream_info()
V . FFMPEG 初始化部分代码示例
I . FFMPEG 初始化流程
FFMPEG 初始化流程 : FFMPEG 执行任何操作前 , 都需要初始化一些环境 , 及相关数据参数 ;
① 网络初始化 : avformat_network_init()
int avformat_network_init(void);
② 打开媒体 ( 音视频 ) 地址 : avformat_open_input()
int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);
③ 查找 ( 音 / 视频 ) 流 : avformat_find_stream_info()
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
④ 正式操作 : 对上述查找到的 音 / 视频 流进行操作 ;
II . FFMPEG 网络初始化 avformat_network_init()
调用 avformat_network_init() 函数进行网络初始化
1 . avformat_network_init() 函数作用 : 初始化网络 , 默认状态下 , FFMPEG 是不允许联网的 , 必须调用该函数 , 初始化网络后 FFMPEG 才能进行联网 ;
2 . avformat_network_init() 函数原型 :
/** * Do global initialization of network libraries. This is optional, * and not recommended anymore. * * This functions only exists to work around thread-safety issues * with older GnuTLS or OpenSSL libraries. If libavformat is linked * to newer versions of those libraries, or if you do not use them, * calling this function is unnecessary. Otherwise, you need to call * this function before any other threads using them are started. * * This function will be deprecated once support for older GnuTLS and * OpenSSL libraries is removed, and this function has no purpose * anymore. */ int avformat_network_init(void);
3 . 使用示例 :
/* * 初始化网络 : * 默认状态下 , FFMPEG 是不允许联网的 * 必须调用该函数 , 初始化网络后 FFMPEG 才能进行联网 */ avformat_network_init();
III . FFMPEG 打开媒体地址 avformat_open_input()
调用 avformat_open_input() 函数打开音视频地址 ( 文件地址 / 网络地址 )
1 . avformat_open_input() 函数作用 : 播放一个音视频多媒体文件之前 , 首先要打开该文件 ; 文件的地址类型可以是文件路径地址 , 也可以是网络地址 ;
2 . avformat_open_input() 函数原型 :
① AVFormatContext **ps 参数 : 封装了文件格式相关信息的结构体 , 如视频宽高 , 音频采样率等信息 ; 该参数是 二级指针 , 意味着在方法中会修改该指针的指向 , 该参数的实际作用是当做返回值用的 ;
② const char *url 参数 : 视频资源地址, 文件地址 / 网络链接 ;
③ int 返回值 : 返回 0 , 代表打开成功 , 否则失败 ; 失败的情况列举 , 文件路径错误 , 网络错误 ;
/** * Open an input stream and read the header. The codecs are not opened. * The stream must be closed with avformat_close_input(). * * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context). * May be a pointer to NULL, in which case an AVFormatContext is allocated by this * function and written into ps. * Note that a user-supplied AVFormatContext will be freed on failure. * @param url URL of the stream to open. * @param fmt If non-NULL, this parameter forces a specific input format. * Otherwise the format is autodetected. * @param options A dictionary filled with AVFormatContext and demuxer-private options. * On return this parameter will be destroyed and replaced with a dict containing * options that were not found. May be NULL. * * @return 0 on success, a negative AVERROR on failure. * * @note If you want to use custom IO, preallocate the format context and set its pb field. */ int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);
3 . 使用示例 :
//1 . 打开音视频地址 ( 播放文件前 , 需要先将文件打开 ) // 地址类型 : ① 文件类型 , ② 音视频流 // 参数解析 : // AVFormatContext **ps : 封装了文件格式相关信息的结构体 , 如视频宽高 , 音频采样率等信息 ; // 该参数是 二级指针 , 意味着在方法中会修改该指针的指向 , // 该参数的实际作用是当做返回值用的 // const char *url : 视频资源地址, 文件地址 / 网络链接 // 返回值说明 : 返回 0 , 代表打开成功 , 否则失败 // 失败的情况 : 文件路径错误 , 网络错误 //int avformat_open_input(AVFormatContext **ps, const char *url, // AVInputFormat *fmt, AVDictionary **options); formatContext = 0; int open_result = avformat_open_input(&formatContext, dataSource, 0, 0); //如果返回值不是 0 , 说明打开视频文件失败 , 需要将错误信息在 Java 层进行提示 // 这里将错误码返回到 Java 层显示即可 if(open_result != 0){ __android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "打开媒体失败 : %s", av_err2str(open_result)); callHelper->onError(pid, 0); }
IV . FFMPEG 获取音 / 视频流信息 avformat_find_stream_info()
调用 avformat_find_stream_info() 函数获取音视频流信息
1 . avformat_find_stream_info() 函数作用 : 打开音视频文件成功后 , 从该地址中获取对应的音视频流 , 获取的流赋值给了 AVFormatContext* 结构体的 nb_streams 成员 ;
2 . avformat_find_stream_info() 函数原型 :
① AVFormatContext **ps 参数 : 封装了文件格式相关信息的结构体 , 如视频宽高 , 音频采样率等信息 ; 该参数是 二级指针 , 意味着在方法中会修改该指针的指向 , 该参数的实际作用是当做返回值用的 ;
调用该方法后 , AVFormatContext 结构体的 nb_streams 元素就有值了 ;
③ int 返回值 : 返回值 >= 0 , 代表打开成功 , 否则失败 ;
/** * Read packets of a media file to get stream information. This * is useful for file formats with no headers such as MPEG. This * function also computes the real framerate in case of MPEG-2 repeat * frame mode. * The logical file position is not changed by this function; * examined packets may be buffered for later processing. * * @param ic media file handle * @param options If non-NULL, an ic.nb_streams long array of pointers to * dictionaries, where i-th member contains options for * codec corresponding to i-th stream. * On return each dictionary will be filled with options that were not found. * @return >=0 if OK, AVERROR_xxx on error * * @note this function isn't guaranteed to open all the codecs, so * options being non-empty at return is a perfectly normal behavior. * * @todo Let the user decide somehow what information is needed so that * we do not waste time getting stuff the user does not need. */ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
3 . 使用示例 :
//2 . 查找媒体 地址 对应的音视频流 ( 给 AVFormatContext* 成员赋值 ) // 方法原型 : int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options); // 调用该方法后 , AVFormatContext 结构体的 nb_streams 元素就有值了 , // 该值代表了音视频流 AVStream 个数 int find_result = avformat_find_stream_info(formatContext, 0); //如果返回值 < 0 , 说明查找音视频流失败 , 需要将错误信息在 Java 层进行提示 // 这里将错误码返回到 Java 层显示即可 if(find_result < 0){ __android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "查找媒体流失败 : %s", av_err2str(find_result)); callHelper->onError(pid, 1); }
V . FFMPEG 初始化部分代码示例
/* * 初始化网络 : * 默认状态下 , FFMPEG 是不允许联网的 * 必须调用该函数 , 初始化网络后 FFMPEG 才能进行联网 */ avformat_network_init(); //0 . 注册组件 // 如果是 4.x 之前的版本需要执行该步骤 // 4.x 及之后的版本 , 就没有该步骤了 //av_register_all(); //1 . 打开音视频地址 ( 播放文件前 , 需要先将文件打开 ) // 地址类型 : ① 文件类型 , ② 音视频流 // 参数解析 : // AVFormatContext **ps : 封装了文件格式相关信息的结构体 , 如视频宽高 , 音频采样率等信息 ; // 该参数是 二级指针 , 意味着在方法中会修改该指针的指向 , // 该参数的实际作用是当做返回值用的 // const char *url : 视频资源地址, 文件地址 / 网络链接 // 返回值说明 : 返回 0 , 代表打开成功 , 否则失败 // 失败的情况 : 文件路径错误 , 网络错误 //int avformat_open_input(AVFormatContext **ps, const char *url, // AVInputFormat *fmt, AVDictionary **options); formatContext = 0; int open_result = avformat_open_input(&formatContext, dataSource, 0, 0); //如果返回值不是 0 , 说明打开视频文件失败 , 需要将错误信息在 Java 层进行提示 // 这里将错误码返回到 Java 层显示即可 if(open_result != 0){ __android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "打开媒体失败 : %s", av_err2str(open_result)); callHelper->onError(pid, 0); } //2 . 查找媒体 地址 对应的音视频流 ( 给 AVFormatContext* 成员赋值 ) // 方法原型 : int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options); // 调用该方法后 , AVFormatContext 结构体的 nb_streams 元素就有值了 , // 该值代表了音视频流 AVStream 个数 int find_result = avformat_find_stream_info(formatContext, 0); //如果返回值 < 0 , 说明查找音视频流失败 , 需要将错误信息在 Java 层进行提示 // 这里将错误码返回到 Java 层显示即可 if(find_result < 0){ __android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "查找媒体流失败 : %s", av_err2str(find_result)); callHelper->onError(pid, 1); }