文章目录
代码语言:txt复制 - [博客简介 . FFMPEG 编解码器获取流程](https://cloud.tencent.com/developer)
- [I . FFMPEG 获取音视频流的编解码参数 AVCodecParameters *codecpar](https://cloud.tencent.com/developer)
- [II . FFMPEG 查找解码器 avcodec_find_decoder ( )](https://cloud.tencent.com/developer)
- [III . FFMPEG 获取编解码器上下文 avcodec_alloc_context3 ( )](https://cloud.tencent.com/developer)
- [IV . FFMPEG 设置编解码器上下文参数 avcodec_parameters_to_context ( )](https://cloud.tencent.com/developer)
- [V . FFMPEG 打开编解码器 avcodec_open2 ( )](https://cloud.tencent.com/developer)
- [VI . FFMPEG 获取编解码器 代码示例](https://cloud.tencent.com/developer)
博客简介 . FFMPEG 编解码器获取流程
FFMPEG 编解码器获取流程 : 在获取音视频流 AVStream *stream 之后 , 执行以下流程 ;
〇 获取 AVStream * 音视频流 ( 获取编解码器前提 ) : 参考博客 【Android FFMPEG 开发】FFMPEG 获取 AVStream 音视频流 ( AVFormatContext 结构体 | 获取音视频流信息 | 获取音视频流个数 | 获取音视频流 )
① 获取音视频流的编码参数 : AVStream *stream 结构体的 AVCodecParameters *codecpar 元素是音视频流的编解码参数 ; 包含 码率 , 宽度 , 高度 , 采样率 等参数信息 ;
代码语言:javascript复制//解码这个媒体流的参数信息 , 包含 码率 , 宽度 , 高度 , 采样率 等参数信息
AVCodecParameters *codecParameters = stream->codecpar;
② 查找编解码器 : 调用 avcodec_find_decoder ( ) 获取当前音视频流使用的编解码器 ;
代码语言:javascript复制//① 查找 当前流 使用的编码方式 , 进而查找编解码器 ( 可能失败 , 不支持的解码方式 )
AVCodec *avCodec = avcodec_find_decoder(codecParameters->codec_id);
③ 获取编解码器上下文 : 调用 avcodec_alloc_context3 ( ) 方法 , 获取编解码器上下文 ;
代码语言:javascript复制//② 获取编解码器上下文
AVCodecContext *avCodecContext = avcodec_alloc_context3(avCodec);
④ 设置编解码器上下文参数 : 调用 avcodec_parameters_to_context ( ) 方法 , 设置编解码器的上下文参数 ;
代码语言:javascript复制//③ 设置 编解码器上下文 参数
// int avcodec_parameters_to_context(AVCodecContext *codec,
// const AVCodecParameters *par);
// 返回值 > 0 成功 , < 0 失败
int parameters_to_context_result =
avcodec_parameters_to_context(avCodecContext, codecParameters);
⑤ 打开编解码器 : 调用 avcodec_open2 ( ) 方法 , 打开编解码器 ;
代码语言:javascript复制//④ 打开编解码器
// int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec,
// 返回 0 成功 , 其它失败
int open_codec_result = avcodec_open2(avCodecContext, avCodec, 0);
I . FFMPEG 获取音视频流的编解码参数 AVCodecParameters *codecpar
1 . 编解码参数封装在 AVStream 结构体中 : FFMPEG 音视频流的编码参数 AVCodecParameters *codecpar 是 AVStream 结构体的元素 ;
代码语言:javascript复制/**
* Stream structure.
* New fields can be added to the end with minor version bumps.
* Removal, reordering and changes to existing fields require a major
* version bump.
* sizeof(AVStream) must not be used outside libav*.
*/
typedef struct AVStream {
...
/**
* Codec parameters associated with this stream. Allocated and freed by
* libavformat in avformat_new_stream() and avformat_free_context()
* respectively.
*
* - demuxing: filled by libavformat on stream creation or in
* avformat_find_stream_info()
* - muxing: filled by the caller before avformat_write_header()
*/
AVCodecParameters *codecpar;
...
}AVStream;
2 . FFMPEG 获取音视频流的编码参数 示例 : 其中 AVStream *stream 是之前获取的音视频流结构体指针 ;
代码语言:javascript复制//解码这个媒体流的参数信息 , 包含 码率 , 宽度 , 高度 , 采样率 等参数信息
AVCodecParameters *codecParameters = stream->codecpar;
3 . 编解码参数 AVCodecParameters *codecpar 中封装的数据 : 这里只列举我们需要使用的 ;
① enum AVCodecID codec_id : 编解码器使用的编码数据的特定类型 , 需要使用该值获取解码器 ;
代码语言:javascript复制/**
* This struct describes the properties of an encoded stream.
*
* sizeof(AVCodecParameters) is not a part of the public ABI, this struct must
* be allocated with avcodec_parameters_alloc() and freed with
* avcodec_parameters_free().
*/
typedef struct AVCodecParameters{
...
/**
* Specific type of the encoded data (the codec used).
*/
enum AVCodecID codec_id;
...
}AVCodecParameters;
II . FFMPEG 查找解码器 avcodec_find_decoder ( )
1 . avcodec_find_decoder ( ) 函数原型 : 根据编解码器 ID , 查找被注册的解码器 ;
① enum AVCodecID id 参数 : 代表了一个编码数据的特定类型 ; ( 详情查看 I . 3 . ① 小节内容 )
② AVCodec *avCodec 返回值 : 返回值是 AVCodec * 结构体指针类型变量 , 代表了获取的解码器 ;
代码语言:javascript复制/** avcodec.h
* Find a registered decoder with a matching codec ID.
*
* @param id AVCodecID of the requested decoder
* @return A decoder if one was found, NULL otherwise.
*/
AVCodec *avcodec_find_decoder(enum AVCodecID id);
2 . FFMPEG 查找解码器 avcodec_find_decoder ( ) 使用示例 :
代码语言:javascript复制//① 查找 当前流 使用的编码方式 , 进而查找编解码器 ( 可能失败 , 不支持的解码方式 )
AVCodec *avCodec = avcodec_find_decoder(codecParameters->codec_id);
//查找失败处理
if(avCodec == NULL){
//如果没有找到编解码器 , 回调失败 , 方法直接返回 , 后续代码不执行
callHelper->onError(pid, 2);
__android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "查找 编解码器 失败");
return;
}
III . FFMPEG 获取编解码器上下文 avcodec_alloc_context3 ( )
avcodec_alloc_context3 ( ) 函数原型 : 获取编解码器上下文 ;
① const AVCodec *codec 参数 : 要获取上下文的编解码器 ;
② AVCodecContext *avCodecContext 返回值 : 编解码器上下文 , 封装了很多编解码器相关参数 ; 如果为 NULL , 说明获取失败 ;
代码语言:javascript复制/** avcodec.h
* Allocate an AVCodecContext and set its fields to default values. The
* resulting struct should be freed with avcodec_free_context().
*
* @param codec if non-NULL, allocate private data and initialize defaults
* for the given codec. It is illegal to then call avcodec_open2()
* with a different codec.
* If NULL, then the codec-specific defaults won't be initialized,
* which may result in suboptimal default settings (this is
* important mainly for encoders, e.g. libx264).
*
* @return An AVCodecContext filled with default values or NULL on failure.
*/
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
2 . FFMPEG 获取编解码器上下文 avcodec_alloc_context3 ( ) 使用示例 :
代码语言:javascript复制//② 获取编解码器上下文
AVCodecContext *avCodecContext = avcodec_alloc_context3(avCodec);
//获取编解码器失败处理
if(avCodecContext == NULL){
callHelper->onError(pid, 3);
__android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "创建编解码器上下文 失败");
return;
}
IV . FFMPEG 设置编解码器上下文参数 avcodec_parameters_to_context ( )
1 . avcodec_parameters_to_context ( ) 函数原型 : 基于编解码器提供的编解码参数设置编解码器上下文参数 ;
① AVCodecContext *codec 参数 : 要设置参数的编解码器上下文 , 这里当做返回值使用 , 这个值之后还要使用 ;
② const AVCodecParameters *par 参数 : 媒体流的参数信息 , 包含 码率 , 宽度 , 高度 , 采样率 等参数信息 , 是 AVStream 结构体封装的元素 ;
③ 返回值 : 如果返回值 >= 0 , 说明设置编解码器上下文参数操作成功 , 如果 < 0 , 设置失败 ;
代码语言:javascript复制/**
* Fill the codec context based on the values from the supplied codec
* parameters. Any allocated fields in codec that have a corresponding field in
* par are freed and replaced with duplicates of the corresponding field in par.
* Fields in codec that do not have a counterpart in par are not touched.
*
* @return >= 0 on success, a negative AVERROR code on failure.
*/
int avcodec_parameters_to_context(AVCodecContext *codec,
const AVCodecParameters *par);
2 . FFMPEG 设置编解码器上下文参数 avcodec_parameters_to_context ( ) 使用示例 :
代码语言:javascript复制//③ 设置 编解码器上下文 参数
// int avcodec_parameters_to_context(AVCodecContext *codec,
// const AVCodecParameters *par);
// 返回值 > 0 成功 , < 0 失败
int parameters_to_context_result =
avcodec_parameters_to_context(avCodecContext, codecParameters);
//设置 编解码器上下文 参数 失败处理
if(parameters_to_context_result < 0){
callHelper->onError(pid, 4);
__android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "设置编解码器上下文参数 失败");
return;
}
V . FFMPEG 打开编解码器 avcodec_open2 ( )
1 . avcodec_open2 ( ) 函数原型 : 打开编解码器 , 之前必须先初始化编解码器上下文 AVCodecContext ;
① AVCodecContext *avctx 参数 : 之前根据编解码器获取上下文参数 avcodec_alloc_context3(avCodec)
, 并为其设置了音视频流编解码参数 avcodec_parameters_to_context(avCodecContext, codecParameters)
;
② const AVCodec *codec 参数 : 需要打开的编解码上下文对应的编解码器 ;
③ 返回值 : 返回 0 成功 , 其它值 失败 ;
代码语言:javascript复制/**
* Initialize the AVCodecContext to use the given AVCodec. Prior to using this
* function the context has to be allocated with avcodec_alloc_context3().
*
* The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(),
* avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for
* retrieving a codec.
*
* @warning This function is not thread safe!
*
* @note Always call this function before using decoding routines (such as
* @ref avcodec_receive_frame()).
*
* @code
* avcodec_register_all();
* av_dict_set(&opts, "b", "2.5M", 0);
* codec = avcodec_find_decoder(AV_CODEC_ID_H264);
* if (!codec)
* exit(1);
*
* context = avcodec_alloc_context3(codec);
*
* if (avcodec_open2(context, codec, opts) < 0)
* exit(1);
* @endcode
*
* @param avctx The context to initialize.
* @param codec The codec to open this context for. If a non-NULL codec has been
* previously passed to avcodec_alloc_context3() or
* for this context, then this parameter MUST be either NULL or
* equal to the previously passed codec.
* @param options A dictionary filled with AVCodecContext and codec-private options.
* On return this object will be filled with options that were not found.
*
* @return zero on success, a negative value on error
* @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(),
* av_dict_set(), av_opt_find().
*/
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
2 . FFMPEG 打开编解码器 avcodec_open2 ( ) 使用示例 :
代码语言:javascript复制//④ 打开编解码器
// int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
// 返回 0 成功 , 其它失败
int open_codec_result = avcodec_open2(avCodecContext, avCodec, 0);
//打开编解码器 失败处理
if(open_codec_result != 0){
callHelper->onError(pid, 5);
__android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "打开 编解码器 失败");
return;
}
VI . FFMPEG 获取编解码器 代码示例
代码语言:javascript复制 //视频 / 音频 处理需要的操作 ( 获取编解码器 )
//① 查找 当前流 使用的编码方式 , 进而查找编解码器 ( 可能失败 , 不支持的解码方式 )
AVCodec *avCodec = avcodec_find_decoder(codecParameters->codec_id);
//查找失败处理
if(avCodec == NULL){
//如果没有找到编解码器 , 回调失败 , 方法直接返回 , 后续代码不执行
callHelper->onError(pid, 2);
__android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "查找 编解码器 失败");
return;
}
//② 获取编解码器上下文
AVCodecContext *avCodecContext = avcodec_alloc_context3(avCodec);
//获取编解码器失败处理
if(avCodecContext == NULL){
callHelper->onError(pid, 3);
__android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "创建编解码器上下文 失败");
return;
}
//③ 设置 编解码器上下文 参数
// int avcodec_parameters_to_context(AVCodecContext *codec,
// const AVCodecParameters *par);
// 返回值 > 0 成功 , < 0 失败
int parameters_to_context_result =
avcodec_parameters_to_context(avCodecContext, codecParameters);
//设置 编解码器上下文 参数 失败处理
if(parameters_to_context_result < 0){
callHelper->onError(pid, 4);
__android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "设置编解码器上下文参数 失败");
return;
}
//④ 打开编解码器
// int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
// 返回 0 成功 , 其它失败
int open_codec_result = avcodec_open2(avCodecContext, avCodec, 0);
//打开编解码器 失败处理
if(open_codec_result != 0){
callHelper->onError(pid, 5);
__android_log_print(ANDROID_LOG_ERROR , "FFMPEG" , "打开 编解码器 失败");
return;
}