如何往mp4视频添加封面图和获取封面图?

前言:

大家好,之前有给大家分享过mp4录像的方案,今天给大家分享的内容是:如何在添加自定义的封面图到mp4里面去,以及在进入回放mp4视频列表的时候,怎么获取mp4视频里面的封面图,当然这个获取到的封面图是有用的,有什么用呢,举例一个比较容易理解的运用,如下图所示:

在嵌入式设备上,做到显示如上在windows上显示的这这种效果。

那上面是如何实现获取和添加封面图的呢?下面我们先要了解一下mp4里面的udta box的作用。

udta box的作用:

首先我们先到iso/iec-14496-12标准里面查找一下udta box的语法结构介绍:

从这个定义来看,User Data Box 是一个container box,用于存放用户信息。这些用户信息以一组更具体的子box形式组织,每个子box用自己的类型来更明确地描述其内容;同时udta box可有可无,不会对mp4播放产生影响,他可以再嵌套在moov box、trak box、moof box、traf box等container box里面。下面是udta box嵌套在 moov box里面:

  • meta(Metadata Box):里面的元数据集合。

  • hdlr((Handler Reference Box):说明元数据的类型。比如 handler type 常见是 "mdir" / "mdta",用来说明这是“metadata”.

  • ilst(Item List Box):实际存放的元数据条目。具体的元数据,我们在下面再做详细的介绍。

但是我们从iso/iec-14496-12标准里面找不到对ilst box的描述。

这里就需要了解一下背景,其实mp4的发展,最开始是从苹果那边来的,后面才有了iso/iec-14496-12标准,最开始对mp4内部组成叫法不是叫box,而是叫做atom,在苹果官方mp4标准里面就可以找到ilst box的描述:

https://developer.apple.com/documentation/quicktime-file-format/metadata_item_list_atom

但是我们去这里查看,并没有对ilst atom里面做具体的说明,也就是看到我们最开始说的封面图box说明,这里只是说明了:

元数据项列表atom(ilst)保存着 实际的元数据值,这些值属于 metadata atom的一部分;元数据项的组织形式是一个 项目列表;元数据项列表atom的类型是 ilst,它包含若干元数据项,而每个元数据项本身也是一个atom.

那该怎么查找这个封面图atom呢?

在iTunes Tagging 规范(Apple 没有在 Developer Docs 完全公开,而是通过 iTunes SDK、开源项目、社区文档流传出来的),比如说:

https://atomicparsley.sourceforge.net/mpeg-4files.html

其中有句话说:

用于 iTunes 的元数据位于 moov.udta.meta.ilst 这一层级结构中。

在 ilst atom下面的那些atom都有特定的名字,但它们本身并不直接保存数据。 这些具名atom的子atom(即 data atom)才真正存放了实际的信息。

上层父atom的 四字符代码 (FourCC) 会列在下面,而在 data atom之后的 atom flags(标志位) 会显示在 “Class” 一栏中。 正是这个 data atom的 class(类别),大体上决定了其中保存的数据是文本、数字还是二进制数据.

换句说,父 atom(如 ©nam, ©ART, covr):只是一个标签,用来表明这是“标题”、“艺术家”、“封面”,子 atom data:才是真正放数据的地方:

  • 如果 class=1 → UTF-8/UTF-16 文本

  • 如果 class=21 → 整数

  • 如果 class=0 或其他 → 二进制(如 covr 里存放 JPEG/PNG)

我们要在找的封面图就是covr atom,可以看到里面支持JPEG和PNG图片。

好了,现在我们明白了原理,那写代码该如何实现呢?

mp4v2实现mp4视频文件添加封面图:

主要实现接口步骤:

*  <b>iTMF Generic add workflow:</b>**      @li MP4ItmfItemAlloc()*      @li MP4ItmfAddItem()*      @li MP4ItmfItemFree()

相关结构体说明:

/** 基本数据类型(在规范中定义的枚举值) */
typedef enum MP4ItmfBasicType_e
{MP4_ITMF_BT_IMPLICIT  = 0,   /**< 隐式类型,适用于不需要明确指明数据类型的标签 */MP4_ITMF_BT_UTF8      = 1,   /**< UTF-8 字符串(没有长度前缀,也没有 null 结尾) */MP4_ITMF_BT_UTF16     = 2,   /**< UTF-16BE 编码字符串 */MP4_ITMF_BT_SJIS      = 3,   /**< Shift-JIS 字符串(主要用于日文,已废弃,除非必须兼容特殊日文字符) */MP4_ITMF_BT_HTML      = 6,   /**< HTML 格式字符串,文件头需说明 HTML 版本 */MP4_ITMF_BT_XML       = 7,   /**< XML 格式字符串,头部必须包含 DTD 或 Schema 声明 */MP4_ITMF_BT_UUID      = 8,   /**< UUID/GUID,二进制存储,占 16 字节,可作为唯一标识符 */MP4_ITMF_BT_ISRC      = 9,   /**< ISRC(国际标准录音编码),UTF-8 文本形式,作为 ID 使用 */MP4_ITMF_BT_MI3P      = 10,  /**< MI3P 标识符,UTF-8 文本形式,作为 ID 使用 */MP4_ITMF_BT_GIF       = 12,  /**< GIF 图像(已废弃) */MP4_ITMF_BT_JPEG      = 13,  /**< JPEG 图像(二进制数据) */MP4_ITMF_BT_PNG       = 14,  /**< PNG 图像(二进制数据) */MP4_ITMF_BT_URL       = 15,  /**< URL 地址,UTF-8 编码的绝对路径 */MP4_ITMF_BT_DURATION  = 16,  /**< 时长,毫秒单位,32 位整数表示 */MP4_ITMF_BT_DATETIME  = 17,  /**< 日期/时间,UTC 格式,从 1904-01-01 00:00:00 开始的秒数,支持 32/64 位 */MP4_ITMF_BT_GENRES    = 18,  /**< 音乐流派,枚举值列表 */MP4_ITMF_BT_INTEGER   = 21,  /**< 大端有符号整数,长度可以是 {1,2,3,4,8} 字节 */MP4_ITMF_BT_RIAA_PA   = 24,  /**< RIAA 家长指引标签:{-1=否, 1=是, 0=未指定},8 位整数 */MP4_ITMF_BT_UPC       = 25,  /**< UPC(通用产品码),UTF-8 文本格式,作为 ID 使用 */MP4_ITMF_BT_BMP       = 27,  /**< BMP 图像(二进制数据) */MP4_ITMF_BT_UNDEFINED = 255  /**< 未定义类型 */
} MP4ItmfBasicType;
/** 数据结构*  用于表示 iTMF metadata item atom 中的 data atom。*/
typedef struct MP4ItmfData_s
{uint8_t          typeSetIdentifier; /**< 类型集合标识符,固定为 0。 */MP4ItmfBasicType typeCode;          /**< iTMF 基本数据类型(枚举值 MP4ItmfBasicType)。 */uint32_t         locale;            /**< 本地化标识符,通常为 0(无区域信息)。 */uint8_t*         value;             /**< 实际数据指针(可能为 NULL)。 */uint32_t         valueSize;         /**< 数据长度(字节数)。 */
} MP4ItmfData;
/** 数据列表*  表示一个 metadata item 中包含的多个 data(例如 covr 中可能有多个封面图片)。*/
typedef struct MP4ItmfDataList_s
{MP4ItmfData* elements; /**< data 元素的数组指针。如果 size=0,则为 NULL。 */uint32_t     size;     /**< data 元素的数量。 */
} MP4ItmfDataList;
/** 元数据项结构*  表示 ilst atom 下的一个 metadata item。*/
typedef struct MP4ItmfItem_s
{void* __handle; /**< 内部使用的句柄,用户无需关心。 */char*           code;     /**< 四字符代码 (FourCC),标识该 atom 类型(例如 "covr", "©nam"),以 NULL 结尾。 */char*           mean;     /**< 可选字段,UTF-8 格式的“意义”描述,可以为 NULL。 */char*           name;     /**< 可选字段,UTF-8 格式的“名称”,可以为 NULL。 */MP4ItmfDataList dataList; /**< data 列表,一个 item 可以有多个 data。可以为 0 个。 */
} MP4ItmfItem;
/** 元数据项列表*  表示 ilst atom 下的一系列 metadata item。*/
typedef struct MP4ItmfItemList_s
{MP4ItmfItem* elements; /**< item 元素的数组指针。如果 size=0,则为 NULL。 */uint32_t     size;     /**< item 的数量。 */
} MP4ItmfItemList;

总结:

  • MP4ItmfBasicType:定义了 data 的数据类型(文本、整数、图片、时间戳等)。

  • MP4ItmfData:表示一个具体的 data 原子(包含类型、区域、本体数据)。

  • MP4ItmfDataList:一个 metadata item 可以包含多个 data(比如 covr 可以有 JPEG + PNG 两种封面)。

  • MP4ItmfItem:一个 ilst 下的 metadata item(如 ©nam = Title,covr = Cover)。

  • MP4ItmfItemList:整个 ilst 里的 item 列表。

下面看具体的接口说明:

/** 在堆上分配一个 metadata item。*  @param code 四字符代码 (FourCC),用于标识该 metadata atom 的类型。*              - 必须是一个以 NULL 结尾的字符串,例如 "©nam"、"©ART"、"covr"。*  @param numData 要为该 item 分配的 data 元素数量。*                 - 必须 >= 1。*                 - 每个 data 对应一个 MP4ItmfData 结构(存储实际的值,比如文本或图片)。*  @return 返回新分配的 MP4ItmfItem 指针。*          - 内部包含一个空的 MP4ItmfDataList(长度 = numData)。*          - 使用完毕后需要调用 MP4ItmfItemFree() 来释放。*/
MP4V2_EXPORT MP4ItmfItem*
MP4ItmfItemAlloc( const char* code, uint32_t numData );
/** 向 MP4 文件中添加一个 metadata item。*  @param hFile MP4 文件句柄(通过 MP4Modify() 或 MP4Read() 获得)。*  @param item  要添加的 metadata item 对象(通常由 MP4ItmfItemAlloc() 创建并填充)。*               - item->code 决定写入的是哪个 key(如 "covr" 表示封面)。*               - item->dataList.elements 里存放真正的数据。*  @return 如果成功写入文件,返回 true;否则返回 false。**  使用场景:*    - 用于向 MP4 文件写入一个新的 metadata 项目(如标题、艺术家、封面)。*    - 如果文件中已有同类型 item,可能会追加或覆盖,具体行为取决于库实现。*/
MP4V2_EXPORT bool
MP4ItmfAddItem( MP4FileHandle hFile, const MP4ItmfItem* item );
/** 释放一个 metadata item(深度释放)。*  @param item 要释放的 item。*              - 包括 item 本身,以及内部所有 data 元素、字符串内存都会被释放。*              - 释放后指针不可再使用。**  注意:*    - 只释放内存,不会影响已经写入 MP4 文件的数据。*    - 正确流程是:MP4ItmfItemAlloc() → 填充数据 → MP4ItmfAddItem() → MP4ItmfItemFree()*/
MP4V2_EXPORT void
MP4ItmfItemFree( MP4ItmfItem* item );

demo实现演示:

FILE* fp = fopen("./test.jpg", "rb" );if (!fp) {printf( "Failed to open JPEG file\n" );//return 1;}fseek( fp, 0, SEEK_END );long size_jpeg = ftell( fp );fseek( fp, 0, SEEK_SET );MP4FileHandle file = MP4Modify(mp4_file_name , 0); if( file == MP4_INVALID_FILE_HANDLE ) {printf( "MP4Modify faile999999999999999999999999999d\n" );return -1;} unsigned char buffer_jpeg[1024 *1024] = {0};size_t ret = fread( buffer_jpeg, 1, size_jpeg, fp );/* allocate item with 1 data element */MP4ItmfItem* preview = MP4ItmfItemAlloc( "covr", 1 );MP4ItmfData* data = &preview->dataList.elements[0];data->typeCode = MP4_ITMF_BT_JPEG;data->valueSize = (uint32_t)size_jpeg;data->value = buffer_jpeg;/* add to mp4 file */MP4ItmfAddItem(file, preview );/* caller responsibility to free */MP4ItmfItemFree( preview );fclose( fp );MP4Close( file ,0 );

mp4v2读取mp4视频里面的封面图实现:

实现步骤:

@li MP4ItmfGetItems()*      @li inspect each item...*      @li MP4ItmfItemListFree()
/** 从 MP4 文件中获取所有 metadata item。*  @param hFile 文件句柄(通过 MP4Read() 或 MP4Modify() 获得)。*  @return 成功时返回一个 MP4ItmfItemList* 指针,包含该文件中所有的 metadata 项;*          失败时返回 NULL。**  返回的 MP4ItmfItemList 结构:*    - elements 指向一个数组,每个元素是一个 MP4ItmfItem。*    - size 表示 metadata item 的数量。*    - 每个 MP4ItmfItem 可能包含多个 MP4ItmfData(比如 covr 里可以有多张图片)。**  内存管理:*    - 返回的 MP4ItmfItemList 必须由调用者在使用完后调用 MP4ItmfItemListFree() 来释放,*      否则会产生内存泄漏。**  使用场景:*    - 遍历并读取 MP4 文件里的所有 iTunes/QuickTime metadata(标题、艺术家、封面等)。*    - 例如获取 ilst 下面的 ©nam (Title)、©ART (Artist)、covr (Cover Art)。*/
MP4V2_EXPORT MP4ItmfItemList*
MP4ItmfGetItems( MP4FileHandle hFile );
/** 释放一个 metadata item 列表(深度释放)。*  @param itemList 要释放的 itemList。*                  - itemList 指针本身、以及其中的每个 MP4ItmfItem、*                    每个 MP4ItmfDataList、字符串 (code/mean/name)、*                    data->value 内存都会被释放。*                  - 调用后该指针不可再使用。**  注意:*    - 该操作仅释放内存,不会影响 MP4 文件中实际存储的数据。*    - 一般在使用完 MP4ItmfGetItems() 的返回结果后调用。*/
MP4V2_EXPORT void
MP4ItmfItemListFree( MP4ItmfItemList* itemList );

demo演示:

MP4FileHandle h = MP4Read(mp4file);if (h == MP4_INVALID_FILE_HANDLE) {fprintf(stderr, "Failed to open file: %s\n", mp4file);return -1;}MP4ItmfItemList* list = MP4ItmfGetItemsByCode(h, "covr");if (!list || list->size == 0) {fprintf(stderr, "No cover art found!\n");MP4Close(h,0);return -1;}// 取第一个 covr 元素MP4ItmfItem* item = list->elements;if (item->dataList.size > 0) {MP4ItmfData* data = &item->dataList.elements[0];FILE* f = fopen(out_jpeg, "wb");if (!f) {fprintf(stderr, "Failed to open output: %s\n", out_jpeg);MP4ItmfItemListFree(list);MP4Close(h,0);return -1;}fwrite(data->value, 1, data->valueSize, f);fclose(f);printf("Cover art extracted to %s (%u bytes)\n", out_jpeg, data->valueSize);}MP4ItmfItemListFree(list);MP4Close(h,0);

总结:

以上就是往mp4视频文件里面添加用户自定义的封面图和获取具体的实现,文章是使用mp4v2方案实现,也可以用其他方案来实现,比如ffmpeg都行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/97833.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/97833.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

你的第一个Transformer模型:从零实现并训练一个迷你ChatBot

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;注册即送-H卡级别算力&#xff0c;80G大显存&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生更享专属优惠。 引言&#xff1a;破除神秘感&#xff0c;拥抱核心思想 …

【20期】沪深指数《实时交易数据》免费获取股票数据API:PythonJava等5种语言调用实例演示与接口API文档说明

​ 随着量化投资在金融市场的快速发展&#xff0c;高质量数据源已成为量化研究的核心基础设施。本文将系统介绍股票量化分析中的数据获取解决方案&#xff0c;涵盖实时行情、历史数据及基本面信息等关键数据类型。 本文将重点演示这些接口在以下技术栈中的实现&#xff1a; P…

RabbitMQ如何保障消息的可靠性

文章目录什么是消息可靠性&#xff1f;RabbitMQ消息可靠性的三个维度1. 生产者到Exchange的可靠性2. Exchange到Queue的可靠性3. Queue到消费者的可靠性核心机制详解Publisher Confirm机制消息持久化Mandatory参数消费者确认机制&#xff08;ACK&#xff09;最佳实践建议1. 合理…

二十、DevOps落地:Jenkins基础入门(一)

二十、DevOps落地&#xff1a;Jenkins基础入门&#xff08;一&#xff09; 文章目录二十、DevOps落地&#xff1a;Jenkins基础入门&#xff08;一&#xff09;1、DevOps初识1.1 什么是DevOps1.2 DevOps相关工具链1.3 什么是CICD&#xff1f;1.4 持续集成CI介绍1.5 持续交付和持…

简单易实现的数据校验方法Checksum

简单易实现的数据校验方法Checksum 在数据传输中&#xff0c;Checksum&#xff08;校验和&#xff09; 扮演着 “数据完整性哨兵” 的角色。它的主要作用是 快速检测数据在传输过程中是否发生了错误 。 下面我将详细解释它的作用、工作原理、优缺点以及典型应用。 核心作用&…

再次深入学习深度学习|花书笔记1

我已经两年没有碰过深度学习了&#xff0c;写此文记录学习过程&#xff0c;加深理解。 深度学习再次深入学习深度学习|花书笔记1信息论第四节 数值计算中的问题上溢出 和 下溢出病态条件优化法再次深入学习深度学习|花书笔记1 这本书说的太繁琐了&#xff0c;如果是想要基于这…

DeerFlow实践:华为LTC流程的评审智能体设计

目录 一、机制设计核心逻辑 二、4 个评审点智能体机制详解 &#xff08;一&#xff09;立项决策&#xff08;ATI&#xff09;智能体机制 1. 知识调用与匹配 2. 评审校验流程 3. 异常处理 &#xff08;二&#xff09;投标决策&#xff08;ATB&#xff09;智能体机制 1. …

C++与Lua交互:从原理到实践指南

核心原理&#xff1a;Lua虚拟栈机制 C与Lua能够高效交互的核心在于Lua虚拟栈的设计&#xff0c;这是一个精巧的中立通信区&#xff0c;解决了两种语言间的本质差异&#xff1a;特性对比CLua语言类型静态编译型动态解释型数据管理明确内存布局虚拟机统一管理类型系统编译时确定运…

CSS 编码规范

CSS 编码规范1 CSS1.1 编码规范1.1.1 【强制】所有声明必须以分号结尾1.1.2 【推荐】使用 2 个空格缩进1.1.3 【推荐】选择器与 { 之间保留一个空格1.1.4 【推荐】属性值规范1.1.5 【推荐】组合器规范1.1.6 【推荐】逗号分隔规范1.1.7 【推荐】注释规范1.1.8 【推荐】右大括号规…

ORA-12514:TNS:监听程序当前无法识别连接描述符中请求的服务

已经不止一次自己本机电脑安装的Oracle使用plsqldev软件登入提示这个了.一般前一天还好好的&#xff0c;今天就不行了.好好总结一下吧&#xff0c;也共大家一起借鉴.主要原因还是数据的归档日志因为内部内存已经耗尽&#xff0c;不能在进行归档导致数据库启动异常&#xff0c;没…

Spring框架的JDBC模板技术和事务管理

SpringJDBCJDBC模板技术概述JDBC的模板类的使用Spring框架的事务管理配置文件方式半注解的方式纯注解的方式JDBC模板技术概述 什么是 JDBC 模板技术&#xff1f; JDBC 模板技术是 Spring 框架为简化持久层&#xff08;数据库操作&#xff09;编程而提供的一种封装机制&#xf…

将文件部署到受管主机

目录 1.ansible.builtin中用于创建、更新或删除多行文本块的模块是什么 2.copy模块的作用 3.fetch模块的作用 4.file模块的作用 5.lineinfile模块的作用 6.stat模块的作用 7.要确保受管主机上存在文件&#xff0c;类似touch命令功能&#xff0c;还能设置权限等的模块及操作是怎…

Dell PowerEdge R620 服务器内存和硬盘罢工了

文章目录前言调查原因查找解决方案硬盘问题内存问题总结前言 月黑风高夜&#xff0c;服务宕机时。做服务端技术的&#xff0c;谁还没半夜遇到个服务挂掉的情况&#xff0c;而像我这种半兼职网管的工作&#xff0c;遇到机器问题的概率也就更大了&#xff0c;本来周五晚上写完总…

2025:SourceTree 启用/禁用Mercurial 或 Git,像素级细节

最近使用Git管理工具的时候&#xff0c;发现还是SourceTree好用些&#xff0c;但是使用SourceTree带来一个问题&#xff1a;就是每次在重新打开SourceTree的时候&#xff0c;都会重新下载Mercurial.zip文件&#xff0c;查了一下&#xff0c;一般情况下我们是不需要使用Mercuria…

安卓 Google Maps 的使用和开发步骤

文章目录1. main2. Android 谷歌地图3. 源码Reference1. main 在国内选择的SDK可以是高德、百度、腾讯、xxxx等&#xff0c;但在国外&#xff0c;你首选是谷歌&#xff0c;因此要进行Google地图的开发你首先要解决下面三个问题 VPN Google账号 信用卡American Express&#x…

Linux -- 应用层协议Http

1.HTTP背景知识 HTTP协议&#xff1a;HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;的本质是运行在 TCP/IP 协议族之上的 “应用层协议”&#xff0c;核心作用是定义客户端&#xff08;如浏览器、APP&#xff09;与服务器之间的 “数据…

R 语言本身并不直接支持 Python 中 f“{series_matrix}.txt“ 这样的字符串字面量格式化(f-string)语法 glue函数

R 语言本身并不直接支持 Python 中 f"{series_matrix}.txt" 这样的字符串字面量格式化&#xff08;f-string&#xff09;语法。 在 R 中&#xff0c;要实现字符串拼接或格式化&#xff0c;你需要使用其他方法。下表对比了 Python f-string 和 R 中常见对应方法的主要…

【AI智能体】亮数据MCP Server × Dify:AI智能体获取实时影音数据就是这么简单

文章目录一、引言&#xff1a;AI 应用与实时影音数据的融合价值1、传统采集方式的痛点2、MCP Server 的创新价值二、亮数据 MCP Server 概览1、什么是 MCP Server&#xff1f;2、支持的影音平台和API接口3、产品特色亮点三、业务场景示例设计1、选定场景&#xff1a;竞品分析与…

从《Attention Is All You Need》深入理解Transformer

2017年的《Attention Is All You Need》论文提出的Transformer架构&#xff0c;不仅彻底改变了自然语言处理的格局&#xff0c;更为现代人工智能的发展奠定了坚实基础。本文将带你深入解析这一划时代模型的核心思想、技术细节及其深远影响。&#x1f504; 一、背景与动机&#…

【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡

【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡引言本次二开布局没有变&#xff0c;但是下一次整体布局会有变&#xff0c;不过本次开发发现朋友圈跳转功能的流程步骤也做了一定的变化。原…