mpeg4ip的Mp4v2库移植到android系统上,实现h264封装到mp4的容器内

2024-03-27 02:48

本文主要是介绍mpeg4ip的Mp4v2库移植到android系统上,实现h264封装到mp4的容器内,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


     第一步: 首选从官网上下载mpeg4ip源代码,只要其中的lib/mp4v2目录下cpp源文件和.h头文件,和include目录下的mpeg4ip.h和mpeg4ip_version.h头文件。(我下的版本是1.6)。我这里处理了下,把源文件放到src目录下,头文件放到include目录下。

     第二步,源文件做少量修改。

        1、mpeg4ip.h文件中注释掉  #include <mpeg4ip_config.h>

        2、mp4file.cpp文件中的GetNumberOfTracks函数中修改。

        修改前:

        u_int32_t MP4File::GetNumberOfTracks(const char* type, u_int8_t subType)
        {
              if (type == NULL) {
               return m_pTracks.Size();
              } 

              u_int32_t typeSeen = 0;
              const char* normType = MP4NormalizeTrackType(type, m_verbosity);

             for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
                   if (!strcmp(normType, m_pTracks[i]->GetType())) {
                            if (subType) {
                                                          if (normType == MP4_AUDIO_TRACK_TYPE) {
                                                                   if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
                                                                          continue;
                                                                      }
                                                          } else if (normType == MP4_VIDEO_TRACK_TYPE) {
                                                                    if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
                                                                          continue;
                                                                     }
                                                           } 
                             // else unknown subtype, ignore it
                            }
                     typeSeen++;
                 }
            }
           return typeSeen;
       }

       修改后:

        u_int32_t MP4File::GetNumberOfTracks(const char* type, u_int8_t subType)
        {
              if (type == NULL) {
               return m_pTracks.Size();
              } 

              u_int32_t typeSeen = 0;
              const char* normType = MP4NormalizeTrackType(type, m_verbosity);

             for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
                   if (!strcmp(normType, m_pTracks[i]->GetType())) {
                            if (subType) {
                                                          if ( !strcmp(normType, MP4_AUDIO_TRACK_TYPE)) {
                                                                   if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
                                                                          continue;
                                                                      }
                                                          } else if ( !strcmp(normType, MP4_VIDEO_TRACK_TYPE) ) {
                                                                    if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
                                                                          continue;
                                                                     }
                                                           } 
                             // else unknown subtype, ignore it
                            }
                     typeSeen++;
                 }
            }
           return typeSeen;
       }

        MP4TrackId MP4File::FindTrackId(u_int16_t trackIndex, const char* type, u_int8_t subType)函数中字符串比较处做同样的修改。

    第三步:编写android.mk文件,这里要注意,因为android中默认的c++不支持异常处理,所以找到一个完整支持c++的标准c++静态库libstdc++.a,把libstdc++.a放到src目录下,且加上

LOCAL_SRC_FILES += libstdc++.a

LOCAL_LDFLAGS := $(LOCAL_PATH)/src/libstdc++.a 

还要加上

LOCAL_CPPFLAGS := -O2 -fexceptions -DHAVE_SOCKLEN_T -DHAVE_STRUCT_IOVEC

     第四步:源码状态下,mm编译。或者用ndk进行编译。

     第五步:调用库,进行封装。

  

   测试源代码(经过测试,封装的文件vlc能正常播放)

     

#include "mp4.h"

int main()
{
   unsigned char sps_pps[24] = {'\0'}; //存储sps和pps
   unsigned char buf[1024*100] = {'\0'};  //存储video数据
   int frameSize = 0;  //取过来的数据长度
   int ret;
   int sps_ppsLen = 0;  //sps和pps的总长度
   int id = start(); //打开数据流
   if(id <0 )
  {
    printf("open video fail %d\n",id);
    return -1;
   }
   ret = getsps(sps_pps,&sps_ppsLen);//取得sps和pps
   if(ret != 0)
   {
    printf("get sps and pps fail %d\n",ret);
    stop(id);
    return -1;
   }

   //创建mp4文件
   MP4FileHandle fileHandle = MP4CreateEx("/data/test.mp4",MP4_DETAILS_ALL,0,1,1,0,0,0,0);
   if(fileHandle == MP4_INVALID_FILE_HANDLE)
   {
    printf("creat mp4 file fail\n");
    stop(id);
    return -1;
   }

   //设置mp4文件的时间单位
    MP4SetTimeScale(fileHandle,90000);

  //创建视频track

   //根据ISO/IEC 14496-10 可知sps的第二个,第三个,第三个字节分别是 AVCProfileIndication,profile_compat,AVCLevelIndication

    MP4TrackId video = MP4AddH264VideoTrack(fileHandle,90000,90000/12,320,240,sps_pps[1],sps_pps[2],sps_pps[3],3);
   if(video == MP4_INVALID_TRACK_ID)
   {
    printf("creat video track fail\n");
    stop(id);
    MP4Close(fileHandle);
    return -1;
   }

  //设置sps和pps
   MP4AddH264SequenceParameterSet(fileHandle,video,sps_pps,sps_ppsLen-5);
   MP4AddH264PictureParameterSet(fileHandle,video,sps_pps+sps_ppsLen-5,5);
   int count = 0;
   int num = 0;
   while(count < 5000)
   {
       while(ret = thakral_getframe(id,buf+4,&frameSize,&num))
      {
        printf("get frame fail %d\n",ret);
       usleep(90*1000);
       }

     //由于传过来的数据没有0x00000001这样的头,都是纯数据,而mp4中的nal结构是 nal长度+nal数据
      int nalsize = frameSize;
      buf[0] = (nalsize&0xff000000)>>24;
      buf[1] = (nalsize&0x00ff0000)>>16;
      buf[2] = (nalsize&0x0000ff00)>>8;
      buf[3] = nalsize&0x000000ff;
      MP4WriteSample(fileHandle,video,buf,frameSize+4,MP4_INVALID_DURATION,0,true);
      count++;
     usleep(85*1000);
    }
    stop(id);
    MP4Close(fileHandle);
   return 0;
 }

这篇关于mpeg4ip的Mp4v2库移植到android系统上,实现h264封装到mp4的容器内的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Python实现终端清屏的几种方式详解

《Python实现终端清屏的几种方式详解》在使用Python进行终端交互式编程时,我们经常需要清空当前终端屏幕的内容,本文为大家整理了几种常见的实现方法,有需要的小伙伴可以参考下... 目录方法一:使用 `os` 模块调用系统命令方法二:使用 `subprocess` 模块执行命令方法三:打印多个换行符模拟

SpringBoot+EasyPOI轻松实现Excel和Word导出PDF

《SpringBoot+EasyPOI轻松实现Excel和Word导出PDF》在企业级开发中,将Excel和Word文档导出为PDF是常见需求,本文将结合​​EasyPOI和​​Aspose系列工具实... 目录一、环境准备与依赖配置1.1 方案选型1.2 依赖配置(商业库方案)二、Excel 导出 PDF

Python实现MQTT通信的示例代码

《Python实现MQTT通信的示例代码》本文主要介绍了Python实现MQTT通信的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 安装paho-mqtt库‌2. 搭建MQTT代理服务器(Broker)‌‌3. pytho

使用zip4j实现Java中的ZIP文件加密压缩的操作方法

《使用zip4j实现Java中的ZIP文件加密压缩的操作方法》本文介绍如何通过Maven集成zip4j1.3.2库创建带密码保护的ZIP文件,涵盖依赖配置、代码示例及加密原理,确保数据安全性,感兴趣的... 目录1. zip4j库介绍和版本1.1 zip4j库概述1.2 zip4j的版本演变1.3 zip4

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处

python生成随机唯一id的几种实现方法

《python生成随机唯一id的几种实现方法》在Python中生成随机唯一ID有多种方法,根据不同的需求场景可以选择最适合的方案,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习... 目录方法 1:使用 UUID 模块(推荐)方法 2:使用 Secrets 模块(安全敏感场景)方法

Spring StateMachine实现状态机使用示例详解

《SpringStateMachine实现状态机使用示例详解》本文介绍SpringStateMachine实现状态机的步骤,包括依赖导入、枚举定义、状态转移规则配置、上下文管理及服务调用示例,重点解... 目录什么是状态机使用示例什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命

Spring Boot 结合 WxJava 实现文章上传微信公众号草稿箱与群发

《SpringBoot结合WxJava实现文章上传微信公众号草稿箱与群发》本文将详细介绍如何使用SpringBoot框架结合WxJava开发工具包,实现文章上传到微信公众号草稿箱以及群发功能,... 目录一、项目环境准备1.1 开发环境1.2 微信公众号准备二、Spring Boot 项目搭建2.1 创建

IntelliJ IDEA2025创建SpringBoot项目的实现步骤

《IntelliJIDEA2025创建SpringBoot项目的实现步骤》本文主要介绍了IntelliJIDEA2025创建SpringBoot项目的实现步骤,文中通过示例代码介绍的非常详细,对大家... 目录一、创建 Spring Boot 项目1. 新建项目2. 基础配置3. 选择依赖4. 生成项目5.

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与