前端做项目的网站,138ip地址查询网站,上海app开发公司,导视设计网站推荐try_decode_video_frame
/*** 尝试解码视频帧** param codec_ctx 解码器上下文* param pkt 待解码的视频数据包* param decode 是否解码标志#xff0c;如果为1#xff0c;则进行解码#xff0c;如果为0#xff0c;则不解码* return 返回0表示成功#xff0c;否则表示出错…try_decode_video_frame
/*** 尝试解码视频帧** param codec_ctx 解码器上下文* param pkt 待解码的视频数据包* param decode 是否解码标志如果为1则进行解码如果为0则不解码* return 返回0表示成功否则表示出错*/
static int try_decode_video_frame(AVCodecContext *codec_ctx, AVPacket *pkt, int decode)
{int ret 0;int got_frame 0;AVFrame *frame NULL;int skip_frame codec_ctx-skip_frame;// 如果解码器未打开则打开解码器if (!avcodec_is_open(codec_ctx)) {const AVCodec *codec avcodec_find_decoder(codec_ctx-codec_id);ret avcodec_open2(codec_ctx, codec, NULL);if (ret 0) {av_log(codec_ctx, AV_LOG_ERROR, Failed to open codec\n);goto end;}}// 分配一个AVFrame结构体frame av_frame_alloc();if (!frame) {av_log(NULL, AV_LOG_ERROR, Failed to allocate frame\n);goto end;}// 如果不需要解码并且解码器支持跳帧填充参数则将跳帧设置为AVDISCARD_ALLif (!decode avpriv_codec_get_cap_skip_frame_fill_param(codec_ctx-codec)) {codec_ctx-skip_frame AVDISCARD_ALL;}// 循环解码视频帧do {// 解码视频帧ret avcodec_decode_video2(codec_ctx, frame, got_frame, pkt);av_assert0(decode || (!decode !got_frame));if (ret 0)break;pkt-data ret;pkt-size - ret;// 如果成功解码到一帧视频则退出循环if (got_frame) {break;}} while (pkt-size 0);end:// 恢复skip_frame的原始值codec_ctx-skip_frame skip_frame;// 释放AVFrame结构体av_frame_free(frame);return ret;
}
find_video_stream_info
/*** 查找视频流信息并尝试解码视频帧** param fmt_ctx AVFormatContext 结构体表示输入文件的格式上下文* param decode 是否解码标志如果为 1则进行解码如果为 0则不解码* return 返回 0 表示成功否则表示出错*/
static int find_video_stream_info(AVFormatContext *fmt_ctx, int decode)
{int ret 0;int i, done 0;AVPacket pkt;// 初始化 AVPacket 结构体av_init_packet(pkt);// 循环读取视频帧数据直到所有视频流都有数据包while (!done) {AVCodecContext *codec_ctx NULL;AVStream *st;// 从输入文件中读取视频帧数据包if ((ret av_read_frame(fmt_ctx, pkt)) 0) {av_log(fmt_ctx, AV_LOG_ERROR, Failed to read frame\n);goto end;}// 获取视频流的解码器上下文st fmt_ctx-streams[pkt.stream_index];codec_ctx st-codec;// 不是视频流或已经解码过一帧视频则跳过if (codec_ctx-codec_type ! AVMEDIA_TYPE_VIDEO ||st-codec_info_nb_frames 0) {av_packet_unref(pkt);continue;}// 尝试解码视频帧ret try_decode_video_frame(codec_ctx, pkt, decode);if (ret 0) {av_log(fmt_ctx, AV_LOG_ERROR, Failed to decode video frame\n);goto end;}// 释放 AVPacket 结构体av_packet_unref(pkt);// 检查是否所有视频流都已经解码完毕done 1;for (i 0; i fmt_ctx-nb_streams; i) {st fmt_ctx-streams[i];codec_ctx st-codec;if (codec_ctx-codec_type ! AVMEDIA_TYPE_VIDEO)continue;done st-codec_info_nb_frames 0;/*在 FFmpeg 的 AVCodecContext 结构体中codec_info_nb_frames 是一个用于存储编解码器相关帧数量信息的成员变量。这个变量通常用于在编解码过程中跟踪已经处理的帧数。在 FFmpeg 中帧是视频编码的基本单位而 codec_info_nb_frames 则是与当前编解码器相关联的帧的数量。
在代码中codec_info_nb_frames 被用作检查视频流是否已经解码完成的标志。通过检查 codec_info_nb_frames 是否大于 0可以判断当前视频流是否已经解码了至少一帧。这在处理视频流时非常有用因为它可以帮助确定是否还有待处理的帧数据或者是否已经处理完所有的帧数据。
总之codec_info_nb_frames 是一个用于存储编解码器相关帧数量信息的成员变量它在 FFmpeg 中用于跟踪已经处理的帧数并在视频编解码过程中起到重要的作用。*/}}end:// 释放 AVPacket 结构体av_packet_unref(pkt);// 关闭所有在 try_decode_video_frame 中打开的解码器for (i 0; i fmt_ctx-nb_streams; i) {AVStream *st fmt_ctx-streams[i];avcodec_close(st-codec);}// 返回解码结果return ret 0;
}
/*** 打印视频流信息** param fmt_ctx AVFormatContext 结构体表示输入文件的格式上下文* param decode 是否解码标志如果为 1则进行解码如果为 0则不解码*/
static void dump_video_streams(const AVFormatContext *fmt_ctx, int decode)
{int i;// 遍历所有视频流for (i 0; i fmt_ctx-nb_streams; i) {const AVOption *opt NULL;const AVStream *st fmt_ctx-streams[i];AVCodecContext *codec_ctx st-codec;// 打印视频流的序号和解码标志printf(stream%d, decode%d\n, i, decode);// 遍历视频流的所有选项while (opt av_opt_next(codec_ctx, opt)) {uint8_t *str;// 跳过常量选项if (opt-type AV_OPT_TYPE_CONST)continue;// 跳过帧数选项if (!strcmp(opt-name, frame_number))continue;// 获取选项的值并打印if (av_opt_get(codec_ctx, opt-name, 0, str) 0) {printf( %s%s\n, opt-name, str);av_free(str);}}}
}
/*** 打开输入文件并尝试解码视频流信息** param fmt_ctx AVFormatContext 结构体指针的指针用于存储打开的输入文件的格式上下文* param filename 输入文件名* param decode 是否解码标志如果为 1则进行解码如果为 0则不解码* return 返回 0 表示成功否则表示出错*/
static int open_and_probe_video_streams(AVFormatContext **fmt_ctx, const char *filename, int decode)
{int ret 0;// 打开输入文件并读取格式ret avformat_open_input(fmt_ctx, filename, NULL, NULL);if (ret 0) {av_log(NULL, AV_LOG_ERROR, Failed to open input %s, filename);goto end;}// 获取视频流信息并尝试解码ret find_video_stream_info(*fmt_ctx, decode);if (ret 0) {goto end;}// 打印视频流信息dump_video_streams(*fmt_ctx, decode);end:return ret;
}
/*** 检查两个格式上下文中的视频流是否相同** param fmt_ctx1 第一个输入文件的格式上下文* param fmt_ctx2 第二个输入文件的格式上下文* return 返回 0 表示视频流相同否则表示不同*/
static int check_video_streams(const AVFormatContext *fmt_ctx1, const AVFormatContext *fmt_ctx2)
{int i;int ret 0;// 断言两个格式上下文中的视频流数量相同av_assert0(fmt_ctx1-nb_streams fmt_ctx2-nb_streams);// 遍历每个视频流for (i 0; i fmt_ctx1-nb_streams; i) {const AVOption *opt NULL;const AVStream *st1 fmt_ctx1-streams[i];const AVStream *st2 fmt_ctx2-streams[i];AVCodecContext *codec_ctx1 st1-codec;AVCodecContext *codec_ctx2 st2-codec;// 如果当前流不是视频流则跳过if (codec_ctx1-codec_type ! AVMEDIA_TYPE_VIDEO)continue;// 遍历视频流的所有选项while (opt av_opt_next(codec_ctx1, opt)) {uint8_t *str1 NULL, *str2 NULL;// 跳过常量选项if (opt-type AV_OPT_TYPE_CONST)continue;// 跳过帧数选项if (!strcmp(opt-name, frame_number))continue;// 获取第一个格式上下文中选项的值av_assert0(av_opt_get(codec_ctx1, opt-name, 0, str1) 0);// 获取第二个格式上下文中选项的值av_assert0(av_opt_get(codec_ctx2, opt-name, 0, str2) 0);// 比较两个值是否相同如果不同则打印错误信息if (strcmp(str1, str2)) {av_log(NULL, AV_LOG_ERROR, Field %s differs: %s %s, opt-name, str1, str2);ret AVERROR(EINVAL); // 设置返回值表示不同}// 释放内存av_free(str1);av_free(str2);}}// 返回比较结果return ret;
}