ffmpeg api-band-test.c 讲解

2024-01-08 16:52
文章标签 讲解 ffmpeg test api band

本文主要是介绍ffmpeg api-band-test.c 讲解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ffmpeg 4.0.4 源码讲解

draw_horiz_band

av_pix_fmt_desc_get 函数是 FFmpeg 中用于获取像素格式描述信息的函数。它的作用是根据给定的像素格式(AVPixelFormat)返回对应的像素格式描述结构体(AVPixFmtDescriptor),该结构体包含了关于像素格式的详细信息,如分量数、每个分量的位深度、颜色空间等。

参数说明:
pix_fmt:要查询的像素格式,是一个枚举值,表示视频帧的像素格式,如 AV_PIX_FMT_YUV420P、AV_PIX_FMT_YUV422P 等。
返回值:
如果成功找到对应的像素格式描述结构体,则返回该结构体的指针;如果未找到,则返回 NULL。


static void draw_horiz_band(AVCodecContext *ctx, const AVFrame *fr, int offset[4],int slice_position, int type, int height)
{int i;const AVPixFmtDescriptor *pix_fmt_desc;int chroma_w, chroma_h;int shift_slice_position;int shift_height;// 标记 draw_horiz_band 被调用draw_horiz_band_called = 1;// 获取像素格式描述信息pix_fmt_desc = av_pix_fmt_desc_get(ctx->pix_fmt);// 计算色度分量宽高chroma_w = -((-ctx->width) >> pix_fmt_desc->log2_chroma_w);chroma_h = -((-height) >> pix_fmt_desc->log2_chroma_h);/*ctx->width 表示视频帧的宽度,height 表示视频帧的高度,而 pix_fmt_desc->log2_chroma_w 和 pix_fmt_desc->log2_chroma_h 分别表示色度分量宽度和高度的对数值(即以2为底的对数)。
举个例子,假设视频帧的宽度 ctx->width 为 1920,高度 height 为 1080,而色度分量的采样率为 4:2:0(常见的视频编码格式之一),即色度分量的宽度和高度都是亮度分量的一半。
现在假设 pix_fmt_desc->log2_chroma_w 和 pix_fmt_desc->log2_chroma_h 都为 1(因为 2^1 = 2,所以色度分量的宽度和高度都是亮度分量的一半)。
根据这些假设,我们来看一下这两行代码的计算过程:首先,将视频帧的宽度 ctx->width 取反,即 -1920。然后右移 pix_fmt_desc->log2_chroma_w 位,
即右移 1 位,得到 -960。再次取反,得到最终的 chroma_w 值为 960。将视频帧的高度 height 取反,即 -1080。然后右移 pix_fmt_desc->log2_chroma_h 位,即右移 1 位,
得到 -540。再次取反,得到最终的 chroma_h 值为 540。*/// 计算偏移值shift_slice_position = -((-slice_position) >> pix_fmt_desc->log2_chroma_h);shift_height = -((-ctx->height) >> pix_fmt_desc->log2_chroma_h);// 处理 Y 分量数据for (i = 0; i < height; i++) {// 拷贝 Y 分量数据到缓冲区memcpy(slice_byte_buffer + ctx->width * slice_position + i * ctx->width,fr->data[0] + offset[0] + i * fr->linesize[0], ctx->width);}// 处理 U 分量数据for (i = 0; i < chroma_h; i++) {// 拷贝 U 分量数据到缓冲区memcpy(slice_byte_buffer + ctx->width * ctx->height + chroma_w * shift_slice_position + i * chroma_w,fr->data[1] + offset[1] + i * fr->linesize[1], chroma_w);}// 处理 V 分量数据for (i = 0; i < chroma_h; i++) {// 拷贝 V 分量数据到缓冲区memcpy(slice_byte_buffer + ctx->width * ctx->height + chroma_w * shift_height + chroma_w * shift_slice_position + i * chroma_w,fr->data[2] + offset[2] + i * fr->linesize[2], chroma_w);}
}

video_decode

static int video_decode(const char *input_filename)
{AVCodec *codec = NULL; // 视频编解码器AVCodecContext *ctx = NULL; // 编解码器上下文AVCodecParameters *origin_par = NULL; // 视频流参数uint8_t *byte_buffer = NULL; // 存储解码后图像数据的缓冲区AVFrame *fr = NULL; // 存储解码后图像帧的结构体AVPacket pkt; // 存储视频数据的数据包AVFormatContext *fmt_ctx = NULL; // 存储格式相关的上下文信息int number_of_written_bytes; // 写入字节数int video_stream; // 视频流索引int got_frame = 0; // 是否解码到一帧图像int byte_buffer_size; // 缓冲区大小int result; // 操作结果int end_of_stream = 0; // 是否到达视频流末尾draw_horiz_band_called = 0; // 标志位,用于检查 draw_horiz_band 函数是否被调用过// 打开输入文件并获取格式相关的上下文信息result = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL);if (result < 0) {av_log(NULL, AV_LOG_ERROR, "Can't open file\n");return result;}// 获取流信息result = avformat_find_stream_info(fmt_ctx, NULL);if (result < 0) {av_log(NULL, AV_LOG_ERROR, "Can't get stream info\n");return result;}// 找到视频流video_stream = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);if (video_stream < 0) {av_log(NULL, AV_LOG_ERROR, "Can't find video stream in input file\n");return -1;}// 获取视频流的参数origin_par = fmt_ctx->streams[video_stream]->codecpar;// 查找视频编解码器codec = avcodec_find_decoder(origin_par->codec_id);if (!codec) {av_log(NULL, AV_LOG_ERROR, "Can't find decoder\n");return -1;}// 分配编解码器上下文ctx = avcodec_alloc_context3(codec);if (!ctx) {av_log(NULL, AV_LOG_ERROR, "Can't allocate decoder context\n");return AVERROR(ENOMEM);}// 将流参数拷贝到编解码器上下文result = avcodec_parameters_to_context(ctx, origin_par);if (result) {av_log(NULL, AV_LOG_ERROR, "Can't copy decoder context\n");return result;}// 设置 draw_horiz_band 函数ctx->draw_horiz_band = draw_horiz_band;ctx->thread_count = 1; // 设置线程数量为 1// 打开编解码器result = avcodec_open2(ctx, codec, NULL);if (result < 0) {av_log(ctx, AV_LOG_ERROR, "Can't open decoder\n");return result;}// 分配图像帧结构体fr = av_frame_alloc();if (!fr) {av_log(NULL, AV_LOG_ERROR, "Can't allocate frame\n");return AVERROR(ENOMEM);}// 分配图像数据缓冲区byte_buffer_size = av_image_get_buffer_size(ctx->pix_fmt, ctx->width, ctx->height, 32);byte_buffer = av_malloc(byte_buffer_size);if (!byte_buffer) {av_log(NULL, AV_LOG_ERROR, "Can't allocate buffer\n");return AVERROR(ENOMEM);}// 分配 slice_byte_buffer 存储 slice 数据slice_byte_buffer = av_malloc(byte_buffer_size);if (!slice_byte_buffer) {av_log(NULL, AV_LOG_ERROR, "Can't allocate buffer\n");return AVERROR(ENOMEM);}memset(slice_byte_buffer, 0, byte_buffer_size);slice_byte_buffer_size = byte_buffer_size;// 初始化数据包av_init_packet(&pkt);do {// 读取数据包if (!end_of_stream) {if (av_read_frame(fmt_ctx, &pkt) < 0) {end_of_stream = 1;}}if (end_of_stream) {pkt.data = NULL;pkt.size = 0;}// 解码视频帧if (pkt.stream_index == video_stream || end_of_stream) {got_frame = 0;result = avcodec_decode_video2(ctx, fr, &got_frame, &pkt);if (result < 0) {av_log(NULL, AV_LOG_ERROR, "Error decoding frame\n");return result;}// 如果解码到一帧图像if (got_frame) {// 处理解码后的图像数据process_frame(fr, byte_buffer, byte_buffer_size);}}// 释放数据包av_packet_unref(&pkt);} while (!end_of_stream || got_frame);// 释放资源avcodec_free_context(&ctx);avformat_close_input(&fmt_ctx);av_frame_free(&fr);av_free(byte_buffer);av_free(slice_byte_buffer);return 0;
}

这篇关于ffmpeg api-band-test.c 讲解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/584150

相关文章

使用SpringBoot创建一个RESTful API的详细步骤

《使用SpringBoot创建一个RESTfulAPI的详细步骤》使用Java的SpringBoot创建RESTfulAPI可以满足多种开发场景,它提供了快速开发、易于配置、可扩展、可维护的优点,尤... 目录一、创建 Spring Boot 项目二、创建控制器类(Controller Class)三、运行

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

【LabVIEW学习篇 - 21】:DLL与API的调用

文章目录 DLL与API调用DLLAPIDLL的调用 DLL与API调用 LabVIEW虽然已经足够强大,但不同的语言在不同领域都有着自己的优势,为了强强联合,LabVIEW提供了强大的外部程序接口能力,包括DLL、CIN(C语言接口)、ActiveX、.NET、MATLAB等等。通过DLL可以使用户很方便地调用C、C++、C#、VB等编程语言写的程序以及windows自带的大

如何更优雅地对接第三方API

如何更优雅地对接第三方API 本文所有示例完整代码地址:https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/third 我们在日常开发过程中,有不少场景会对接第三方的API,例如第三方账号登录,第三方服务等等。第三方服务会提供API或者SDK,我依稀记得早些年Maven还没那么广泛使用,通常要对接第三方

论文翻译:ICLR-2024 PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS

PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS https://openreview.net/forum?id=KS8mIvetg2 验证测试集污染在黑盒语言模型中 文章目录 验证测试集污染在黑盒语言模型中摘要1 引言 摘要 大型语言模型是在大量互联网数据上训练的,这引发了人们的担忧和猜测,即它们可能已

Java基础回顾系列-第五天-高级编程之API类库

Java基础回顾系列-第五天-高级编程之API类库 Java基础类库StringBufferStringBuilderStringCharSequence接口AutoCloseable接口RuntimeSystemCleaner对象克隆 数字操作类Math数学计算类Random随机数生成类BigInteger/BigDecimal大数字操作类 日期操作类DateSimpleDateForma

Restful API 原理以及实现

先说说API 再说啥是RESRFUL API之前,咱先说说啥是API吧。API大家应该都知道吧,简称接口嘛。随着现在移动互联网的火爆,手机软件,也就是APP几乎快爆棚了。几乎任何一个网站或者应用都会出一款iOS或者Android APP,相比网页版的体验,APP确实各方面性能要好很多。 那么现在问题来了。比如QQ空间网站,如果我想获取一个用户发的说说列表。 QQ空间网站里面需要这个功能。

京东物流查询|开发者调用API接口实现

快递聚合查询的优势 1、高效整合多种快递信息。2、实时动态更新。3、自动化管理流程。 聚合国内外1500家快递公司的物流信息查询服务,使用API接口查询京东物流的便捷步骤,首先选择专业的数据平台的快递API接口:物流快递查询API接口-单号查询API - 探数数据 以下示例是参考的示例代码: import requestsurl = "http://api.tanshuapi.com/a

ffmpeg面向对象-待定

1.常用对象 rtsp拉流第一步都是avformat_open_input,其入参可以看下怎么用: AVFormatContext *fmt_ctx = NULL;result = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL); 其中fmt_ctx 如何分配内存的?如下 int avformat_open_input(