当前位置: 首页 > news >正文

音视频解封装demo:使用libmp4v2解封装(demux)出mp4文件中的h264视频数据和aac语音数据

1、README

前言

本demo是使用的mp4v2来将mp4文件解封装得到h264、aac的,目前demo提供的.a静态库文件是在x86_64架构的Ubuntu16.04编译得到的,如果想在其他环境下测试demo,可以自行编译mp4v2并替换相应的库文件(libmp4v2.a)。

a. 编译
$ make # 或者`make DEBUG=1`打开调试打印信息

如果想编译mp4v2,则可以参考以下步骤:

mp4v2源码下载地址:https://github.com/TechSmith/mp4v2

$ tar xjf mp4v2-2.0.0.tar.bz2
$ cd mp4v2-2.0.0/
$ ./configure --prefix=$PWD/_install # 交叉编译可参考加上选项: --host=arm-linux-gnueabihf
$ make -j96
$ make install
b. 使用

注:示例2中的音视频测试源文件是不同步的,不影响本demo的解封装。

$ ./mp4v2_unpack_demo 
Usage: ./mp4v2_unpack_demo ./avfile/test1.mp4 ./test1_out.h264 ./test1_out.aac./mp4v2_unpack_demo ./avfile/test2.mp4 ./test2_out.h264 ./test2_out.aac
c. 参考文章
  • 01.mp4v2应用—mp4转h264 - wade_linux - 博客园.mhtml

  • mp4文件格式解析 - 简书

  • MP4格式详解_DONGHONGBAI的专栏-CSDN博客

  • 使用mp4v2解码mp4转成h264码流和aac码流_lq496387202的博客-CSDN博客_mp4v2解码

d. demo目录结构
.
├── avfile
│   ├── test1.mp4
│   ├── test1_out.aac
│   ├── test1_out.h264
│   ├── test2.mp4
│   ├── test2_out.aac
│   └── test2_out.h264
├── docs
│   ├── 01.mp4v2应用—mp4转h264 - wade_linux - 博客园.mhtml
│   ├── mp4文件格式解析 - 简书.mhtml
│   ├── MP4格式详解_DONGHONGBAI的专栏-CSDN博客.mhtml
│   └── 使用mp4v2解码mp4转成h264码流和aac码流_lq496387202的博客-CSDN博客_mp4v2解码.mhtml
├── include
│   └── mp4v2
│       ├── chapter.h
│       ├── file.h
│       ├── file_prop.h
│       ├── general.h
│       ├── isma.h
│       ├── itmf_generic.h
│       ├── itmf_tags.h
│       ├── mp4v2.h
│       ├── platform.h
│       ├── project.h
│       ├── sample.h
│       ├── streaming.h
│       ├── track.h
│       └── track_prop.h
├── lib
│   └── libmp4v2.a
├── main.c
├── Makefile
└── README.md

2、主要代码片段

main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>#include "mp4v2/mp4v2.h"// 编译时Makefile里控制
#ifdef ENABLE_DEBUG#define DEBUG(fmt, args...) 	printf(fmt, ##args)
#else#define DEBUG(fmt, args...)
#endifint unpackMp4File(char *mp4FileName, char *videoFileName, char *audioFileName);unsigned char g_sps[64] = {0};
unsigned char g_pps[64] = {0};
unsigned int  g_spslen  = 0;
unsigned int  g_ppslen  = 0;int main(int argc, char **argv)
{if(argc < 2){printf("Usage: \n""   %s ./avfile/test1.mp4 ./test1_out.h264 ./test1_out.aac\n""   %s ./avfile/test2.mp4 ./test2_out.h264 ./test2_out.aac\n",argv[0], argv[0]);return -1;}int ret = unpackMp4File(argv[1], argv[2], argv[3]);if(ret == 0){printf("\033[32mSuccess!\033[0m\n");}else{printf("\033[31mFailed!\033[0m\n");}return 0;
}int getH264Stream(MP4FileHandle mp4Handler, int videoTrackId, int totalSamples, char *saveFileName)
{// 调用的接口要传的参数uint32_t curFrameIndex = 1; // `MP4ReadSample`函数的参数要求是从1开始,但我们打印帧下标还是从0开始uint8_t *pData = NULL;uint32_t nSize = 0;MP4Timestamp pStartTime;MP4Duration pDuration;MP4Duration pRenderingOffset;bool pIsSyncSample = 0;// 写文件要用的参数char naluHeader[4] = {0x00, 0x00, 0x00, 0x01};FILE *fpVideo = NULL;if(!mp4Handler)return -1;fpVideo = fopen(saveFileName, "wb"); if (fpVideo == NULL){printf("open file(%s) error!\n", saveFileName);return -1;}while(curFrameIndex <= totalSamples){   // 如果传入MP4ReadSample的视频pData是null,它内部就会new 一个内存// 如果传入的是已知的内存区域,则需要保证空间bigger then max frames size.MP4ReadSample(mp4Handler, videoTrackId, curFrameIndex, &pData, &nSize, &pStartTime, &pDuration, &pRenderingOffset, &pIsSyncSample);DEBUG("[\033[35mvideo\033[0m] ");if(pIsSyncSample){DEBUG("IDR\t");fwrite(naluHeader, 4, 1, fpVideo);fwrite(g_sps, g_spslen, 1, fpVideo);fwrite(naluHeader, 4, 1, fpVideo);fwrite(g_pps, g_ppslen, 1, fpVideo);}else{DEBUG("SLICE\t");}if(pData && nSize > 4){// `MP4ReadSample`函数的参数要求是从1开始,但我们打印帧下标还是从0开始;而大小已经包含了4字节的start code长度DEBUG("frame index: %d\t size: %d\n", curFrameIndex - 1, nSize);fwrite(naluHeader, 4, 1, fpVideo);fwrite(pData + 4, nSize - 4, 1, fpVideo); // pData+4了,那nSize就要-4}free(pData);pData = NULL;curFrameIndex++;}       fflush(fpVideo);fclose(fpVideo);  return 0;
}int getAACStream(MP4FileHandle mp4Handler, int audioTrackId, int totalSamples, char *saveFileName)
{// 调用的接口要传的参数uint32_t curFrameIndex = 1; // `MP4ReadSample`函数的参数要求是从1开始,但我们打印帧下标还是从0开始uint8_t *pData = NULL;uint32_t nSize = 0;// 写文件要用的参数FILE *fpAudio = NULL;if(!mp4Handler)return -1;fpAudio = fopen(saveFileName, "wb");if (fpAudio == NULL){printf("open file(%s) error!\n", saveFileName);return -1;}while(curFrameIndex <= totalSamples){// 如果传入MP4ReadSample的音频pData是null,它内部就会new 一个内存// 如果传入的是已知的内存区域,则需要保证空间bigger then max frames size.MP4ReadSample(mp4Handler, audioTrackId, curFrameIndex, &pData, &nSize, NULL, NULL, NULL, NULL);DEBUG("[\033[36maudio\033[0m] ");if(pData){			DEBUG("frame index: %d\t size: %d\n", curFrameIndex - 1, nSize);fwrite(pData, nSize, 1, fpAudio);}free(pData);pData = NULL;curFrameIndex++;}		fflush(fpAudio);fclose(fpAudio);  return 0;
}int unpackMp4File(char *mp4FileName, char *videoFileName, char *audioFileName)
{MP4FileHandle mp4Handler = 0;uint32_t trackCnt = 0;	int videoTrackId = -1;int audioTrackId = -1;unsigned int videoSampleCnt = 0;unsigned int audioSampleCnt = 0;mp4Handler = MP4Read(mp4FileName);if (mp4Handler <= 0){printf("MP4Read(%s) error!\n", mp4FileName);return -1;}trackCnt = MP4GetNumberOfTracks(mp4Handler, NULL, 0); //获取音视频轨道数printf("****************************\n");printf("trackCnt: %d\n", trackCnt);for (int i = 0; i < trackCnt; i++){// 获取trackId,判断获取数据类型: 1-获取视频数据,2-获取音频数据MP4TrackId trackId = MP4FindTrackId(mp4Handler, i, NULL, 0);const char* trackType = MP4GetTrackType(mp4Handler, trackId);if (MP4_IS_VIDEO_TRACK_TYPE(trackType)){// 不关心,只是打印出来看看MP4Duration duration = 0;uint32_t timescale = 0;videoTrackId = trackId;duration = MP4GetTrackDuration(mp4Handler, videoTrackId);timescale = MP4GetTrackTimeScale(mp4Handler, videoTrackId);videoSampleCnt = MP4GetTrackNumberOfSamples(mp4Handler, videoTrackId);printf("video params: \n"" - trackId: %d\n"" - duration: %lu\n"" - timescale: %d\n"" - samples count: %d\n",videoTrackId, duration, timescale, videoSampleCnt);// 读取 sps/pps uint8_t **seqheader;			uint32_t *seqheadersize;uint8_t **pictheader;uint32_t *pictheadersize;MP4GetTrackH264SeqPictHeaders(mp4Handler, videoTrackId, &seqheader, &seqheadersize, &pictheader, &pictheadersize);// 获取spsfor (int ix = 0; seqheadersize[ix] != 0; ix++){memcpy(g_sps, seqheader[ix], seqheadersize[ix]);g_spslen = seqheadersize[ix];free(seqheader[ix]);}free(seqheader);free(seqheadersize);// 获取ppsfor (int ix = 0; pictheader[ix] != 0; ix++){memcpy(g_pps, pictheader[ix], pictheadersize[ix]);g_ppslen = pictheadersize[ix];free(pictheader[ix]);}free(pictheader);free(pictheadersize);}else if (MP4_IS_AUDIO_TRACK_TYPE(trackType)){audioTrackId = trackId;audioSampleCnt = MP4GetTrackNumberOfSamples(mp4Handler, audioTrackId);printf("audio params: \n"" - trackId: %d\n"" - samples count: %d\n",audioTrackId, audioSampleCnt);}}printf("****************************\n");// 解析完了mp4,主要是为了获取sps pps 还有video的trackIDif(videoTrackId >= 0){getH264Stream(mp4Handler, videoTrackId, videoSampleCnt, videoFileName);  }if(audioTrackId >= 0){getAACStream(mp4Handler, audioTrackId, audioSampleCnt, audioFileName);}// 需要mp4close 否则在嵌入式设备打开mp4上多了会内存泄露挂掉.MP4Close(mp4Handler, 0);return 0;
}

3、demo下载地址(任选一个)

  • https://download.csdn.net/download/weixin_44498318/89526730
  • https://gitee.com/linriming/av_mp4_unpack_with_mp4v2.git
  • https://github.com/linriming20/av_mp4_unpack_with_mp4v2.git

相关文章:

音视频解封装demo:使用libmp4v2解封装(demux)出mp4文件中的h264视频数据和aac语音数据

1、README 前言 本demo是使用的mp4v2来将mp4文件解封装得到h264、aac的&#xff0c;目前demo提供的.a静态库文件是在x86_64架构的Ubuntu16.04编译得到的&#xff0c;如果想在其他环境下测试demo&#xff0c;可以自行编译mp4v2并替换相应的库文件&#xff08;libmp4v2.a&#…...

手撸俄罗斯方块(一)——简单介绍

手撸俄罗斯方块 简单介绍 《俄罗斯方块》&#xff08;俄语&#xff1a;Тетрис&#xff0c;英语&#xff1a;Tetris&#xff09;&#xff0c;是1980年末期至1990年代初期风靡全世界的电脑游戏&#xff0c;是落下型益智游戏的始祖&#xff0c;电子游戏领域的代表作之一&a…...

构建LangChain应用程序的示例代码:61、如何使用 LangChain 和 LangSmith 优化链

本示例介绍如何使用 LangChain 和 LangSmith 优化链。 设置 我们将为 LangSmith 设置环境变量&#xff0c;并加载相关数据 import osos.environ["LANGCHAIN_PROJECT"] "movie-qa" # 设置 LANGCHAIN_PROJECT 环境变量为 "movie-qa"import pan…...

Android系统通过属性设置来控制log输出的方案

Android系统通过属性设置来控制log输出的方案 背景 项目中经常需要在针对性的模块或者文件&#xff0c;分析问题的时候输出Log&#xff0c;但问题分析完成后&#xff0c;又由于性能问题&#xff0c;需要关闭这些log输出。当前大多数情况下是控制整个系统的log等级来实现&#…...

JavaDoc的最佳实践

文章目录 一、JavaDoc 使用说明1.1 什么是 JavaDoc1.2 文档注释结构1.3 常见的 Javadoc 标签 二、文档最佳实践2.1 注释原则2.2 实际案例 参考资料 一、JavaDoc 使用说明 1.1 什么是 JavaDoc JavaDoc 是一款能根据源代码中的文档注释来产生 HTML 格式的 API 文档的工具。 Jav…...

数字力量助西部职教全面提升——唯众品牌大数据、人工智能系列产品中标甘肃庆阳职院数字经济人才培养基地!

近日&#xff0c;唯众品牌凭借在大数据和人工智能领域深耕多年的技术积累和卓越产品&#xff0c;成功中标庆阳职业技术学院全国一体化算力网络国家枢纽节点数字经济人才培养基地项目&#xff0c;标志着唯众在助力西部职业教育与数字经济融合发展的新征程上迈出了坚实的一步。 …...

Swagger的原理及应用详解(四)

本系列文章简介: 在当今快速发展的软件开发领域,特别是随着微服务架构和前后端分离开发模式的普及,API(Application Programming Interface,应用程序编程接口)的设计与管理变得愈发重要。一个清晰、准确且易于理解的API文档不仅能够提升开发效率,还能促进前后端开发者之…...

Elasticsearch7.10集群搭建

Elasticsearch详细介绍&#xff1a; Elasticsearch 是一个分布式、RESTful 风格的搜索和分析引擎。它的核心基于 Apache Lucene&#xff0c;能够处理海量的数据&#xff0c;并支持实时的全文搜索。以下是关于 Elasticsearch 的详细介绍。 一、基本概念 索引&#xff08;Index…...

SMU Summer 2024 Contest Round 3

A.Hcode OnlineJudge 先用欧拉筛把质数预处理出来&#xff0c;然后枚举左端点的质数&#xff0c;只需要询问右端点是不是质数并取差值的min就行了 #include<bits/stdc.h> #define endl \n #define mk make_pair #define int long long using namespace std; typedef lon…...

uniapp 封装瀑布流组件

思路&#xff1a; 1.coulumns&#xff1a;需要分成几列 2.如何分布数据 3.计算每列的宽度 4.图片进行高度自适应 <template><view :style"{ margin: boxM }"><view class"flex flex-justify-start bg-red" style"background-colo…...

pd虚拟机去虚拟化是什么意思?pd虚拟机去虚拟化教程 PD虚拟机优化设置

Parallels Desktop for Mac&#xff08;PD虚拟机&#xff09;去虚拟化是指在虚拟机&#xff08;Virtual Machine&#xff0c;简称 VM&#xff09;中禁用或减少虚拟化层的影响&#xff0c;使其表现更接近于物理机。这种操作通常用于提高虚拟机的性能或解决某些软件兼容性问题。具…...

低代码研发项目管理流程优化:提效与创新的双重驱动

随着信息技术的迅猛发展&#xff0c;软件项目的规模和复杂度日益增加&#xff0c;传统的软件开发方式已经难以满足快速迭代和高效交付的需求。在这一背景下&#xff0c;低代码平台应运而生&#xff0c;以其高效、灵活、易用的特点&#xff0c;迅速成为软件行业的新宠。然而&…...

32位版 C 库函数time 将在 2038 年溢出,那到时候,它该何去何从

简单地说&#xff0c;通常不必担心&#xff0c;在64位操作系统已经成为主流的今天这基本上不是问题&#xff08;在写这篇回答的时候&#xff0c;我才发现我甚至找不到32位的机器来测试&#xff09;刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「32库函数的…...

C语言 printf函数缓冲机制

printf不立即打印到stdout的原因 printf函数使用了缓冲机制。当我们调用printf时,输出通常不会立即显示在屏幕上,而是先存储在一个缓冲区中。这是为了提高I/O操作的效率。 缓存数据输出的原理 stdio库维护了一个缓冲区。当缓冲区满了,或者在特定条件下,缓冲区的内容会被刷新…...

【Linux进阶】文件系统8——硬链接和符号连接:ln

在Linux下面的链接文件有两种&#xff0c; 一种是类似Windows的快捷方式功能的文件&#xff0c;可以让你快速地链接到目标文件&#xff08;或目录)&#xff1b;另一种则是通过文件系统的inode 链接来产生新文件名&#xff0c;而不是产生新文件&#xff0c;这种称为硬链接&…...

代码随想录算法训练营Day64|拓扑排序(卡码网117)、dijkstra朴素版

拓扑排序 117. 软件构建 (kamacoder.com) 拓扑排序简单的说是将一个有向图转为线性的排序。 它将图中的所有结点排序成一个线性序列&#xff0c;使得对于任何的边uv&#xff0c;结点u在序列中都出现在结点v之前&#xff0c;这样的序列满足图中所有的前驱-后继关系。 拓扑排…...

neo4j 图数据库:Cypher 查询语言、医学知识图谱

neo4j 图数据库&#xff1a;Cypher 查询语言、医学知识图谱 Cypher 查询语言创建数据查询数据查询并返回所有节点查询并返回所有带有特定标签的节点查询特定属性的节点及其所有关系和关系的另一端节点查询从名为“小明”的节点到名为“小红”的节点的路径 更新数据更新一个节点…...

数据结构基础--------【二叉树基础】

二叉树基础 二叉树是一种常见的数据结构&#xff0c;由节点组成&#xff0c;每个节点最多有两个子节点&#xff0c;左子节点和右子节点。二叉树可以用来表示许多实际问题&#xff0c;如计算机程序中的表达式、组织结构等。以下是一些二叉树的概念&#xff1a; 二叉树的深度&a…...

数据开源 | Magic Data大模型高质量十万轮对话数据集

能够自然的与人类进行聊天交谈&#xff0c;是现今的大语言模型 (LLM) 区别于传统语言模型的重要能力之一&#xff0c;近日OpenAI推出的GPT-4o给我们展示了这样的可能性。 对话于人类来说是与生俱来的&#xff0c;但构建具备对话能力的大模型是一项不小的挑战&#xff0c;收集高…...

webpack之ts打包

tsconfig.json配置 // 是否对js文件进行编译&#xff0c;默认false"allowJs": true,// 是否检查js代码是否符合语法规范,默认false(引入的外部文件有可能语法有问题)"checkJs": true, allowJs和checkJs基本是同时出现&#xff0c;因为有了allowJs 这个检查…...

MATLAB数据统计描述和分析

描述性统计就是搜集、整理、加工和分析统计数据&#xff0c; 使之系统化、条理化&#xff0c;以显示出数据资料的趋势、特征和数量关系。它是统计推断的基础&#xff0c;实用性较强&#xff0c;在数学建模的数据描述部分经常使用。 目录 1.频数表和直方图 2 .统计量 3.统计…...

设计分享—国外后台界面设计赏析

国外后台界面设计将用户体验放在首位&#xff0c;通过直观易懂的布局和高效的交互设计&#xff0c;提升用户操作效率和满意度。 设计不仅追求美观大方&#xff0c;还注重功能的实用性和数据的有效展示&#xff0c;通过图表和图形化手段使数据更加直观易懂。 采用响应式布局&a…...

最小生成树(算法篇)

算法之最小生成树 最小生成树 概念&#xff1a; 最小生成树是一颗连接图G所有顶点的边构成的一颗权最小的树&#xff0c;最小生成树一般是在无向图中寻找。最小生成树共有N-1条边(N为顶点数)。 算法&#xff1a; Prim算法 概念&#xff1a; Prim(普里姆)算法是生成最小生…...

教师管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;教师管理&#xff0c;个人认证管理&#xff0c;课程信息管理&#xff0c;课堂记录管理&#xff0c;课堂统计管理&#xff0c;留言板管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;课程信息…...

Selenium 等待

环境&#xff1a; Python 3.8 selenium3.141.0 urllib31.26.19 Chromium 109.0.5405.0 &#xff08;32 位&#xff09; # 1 固定等待&#xff08;time&#xff09; # 固定待是利用python语言自带的time库中的sleep()方法&#xff0c;固定等待几秒。 # 这种方式会导致这个脚本运…...

安装easy-handeye

一、aruco_ros配置 mkdir -p ~/ros_ws/src cd ~/ros_ws/src git clone -b melodic-devel https://github.com/pal-robotics/aruco_ros.git cd .. catkin_make 二、visp配置(需要联外网下载东西&#xff0c;不然会一直出问题&#xff09; sudo apt-get install ros-melodic-…...

【面试题】MySQL 索引(第二篇)

1.索引 索引是数据库中的一个核心概念&#xff0c;它对于提高数据库查询效率至关重要。以下是索引的详细概念解析&#xff1a; 一、索引的定义 基本定义&#xff1a;索引是一个排序的列表&#xff0c;其中存储着索引的值和包含这些值的数据所在行的物理地址&#xff08;或逻…...

4. 小迪安全v2023笔记 javaEE应用

4. 小迪安全v2023笔记 javaEE应用 ​ 大体上跟随小迪安全的课程&#xff0c;本意是记录自己的学习历程&#xff0c;不能说是完全原创吧&#xff0c;大家可以关注一下小迪安全。 若有冒犯&#xff0c;麻烦私信移除。 默认有java基础。 文章目录 4. 小迪安全v2023笔记 javaEE应…...

anaconda修改安装的默认环境

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 &#xff08;目前正在带领大家一起提升认知&#xff0c;感兴趣可以来围观一下&#xff09; &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍 ❤️如遇文章付费&#xff0c;可先看…...

MySQL 9.0 正式发行Innovation创新版已支持向量

从 MySQL 8.1 开始&#xff0c;官方启用了新的版本模型&#xff1a;MySQL 创新版 (Innovation) 和长期支持版 (LTS)。 根据介绍&#xff0c;两者的质量都已达到可用于生产环境级别。区别在于&#xff1a; 如果希望尝试最新的功能和改进&#xff0c;并喜欢与最新技术保持同步&am…...

云南建设厅网站首页/看b站视频下载软件

检测foodname是否重复 select foodname,count(*) as count from tablename group by foodname having count>1;...

房屋装修网/北京seo推广

正如预期的一样&#xff0c;网络犯罪分子会利用Apple最新发表的iPhone 5s消息&#xff0c;几乎在苹果的新产品发表会同时&#xff0c;这个网络钓鱼&#xff08;Phishing&#xff09;信件开始流传。此次&#xff0c;趋势科技病毒防治中心 Trend Labs更深入发现&#xff0c;黑客利…...

受欢迎的大连网站建设/实时军事热点

我们辛辛苦苦做一个网站不容易&#xff0c;一不留神还会被搜索引擎清0给k了&#xff0c;难道搜索引擎给清0了&#xff0c;我们就放弃吗&#xff0c;那样的话也太伤心了。下面我就来谈谈被搜索引擎k的几种类型及处理方式。一\ 大量的网站同一时间被k如果你的网站被k了&#xff0…...

如何免费弄一个网站/网站推广的作用在哪里

新建基础软件工程 作者&#xff1a; RootCode 申明&#xff1a;该文档仅供个人学习使用 一、写在前面 目前 Keil 的四款产品&#xff08;软件&#xff09;&#xff1a;MDK-ARM、C51、C251、C166&#xff0c;在用法上极为相似&#xff0c;包括本文讲述的新建软件工程。 本文以…...

做网站怎么赚钱 111/小说网站排名免费

各位同学、老师们&#xff1a;今天对于热爱计算机技术&#xff0c;热爱编程的同学们来说是个特殊的日子&#xff0c;烟台大学首次迎来了ACM程序设计大赛。ACM是计算机界历史最久的全球性组织&#xff0c;ACM大赛是全球大学生的最高水平的计算机程序设计竞赛&#xff0c;烟台大学…...

网站推广方法有/seo自然排名优化

为什么80%的码农都做不了架构师&#xff1f;>>> 如今&#xff0c;软件通常会作为一种服务来交付&#xff0c;它们被称为网络应用程序&#xff0c;或“软件即服务”&#xff08;SaaS&#xff09;。 “十二要素应用程序”&#xff08;12-Factor App&#xff09;为构建…...