• libmp4v2不完全指南封装g711a的坑


    libmp4v2不完全指南封装g711a的坑

    1 添加audio track

    1. int mp4v2_mp4_writer_init_g711(uint32_t sampleRate, uint32_t timeScale)
    2. {
    3. if(g_mp4v2.mp4handle == MP4_INVALID_FILE_HANDLE || RD_STREAM_INIT_STATUS != g_mp4v2.astatus)
    4. {
    5. return -1;
    6. }
    7. g_mp4v2.atrack_id = MP4AddALawAudioTrack(g_mp4v2.mp4handle, u32SampleRate);
    8. //g_mp4v2.atrack_id = MP4AddAudioTrack(g_mp4v2.mp4handle, u32SampleRate, 800, MP4_ALAW_AUDIO_TYPE);
    9. if(0 == g_mp4v2.atrack_id)
    10. {
    11. printf("create audio track success,g_mp4v2.atrack_num:%d\n", g_mp4v2.atrack_id);
    12. return -1;
    13. }
    14. else
    15. {
    16. printf("create audio track success,g_mp4v2.atrack_num:%d\n", g_mp4v2.atrack_id);
    17. }
    18. MP4SetAudioProfileLevel(g_mp4v2.mp4handle, 0x2);
    19. return 0;
    20. }

    看似平平无奇的一段代码对吧,实际上有两个大坑浪费了我半天的时间

    一开始搜索add audio track,看到这个接口

    1. MP4TrackId MP4AddAudioTrack(
    2. MP4FileHandle hFile,
    3. uint32_t timeScale,
    4. MP4Duration sampleDuration,
    5. uint8_t audioType DEFAULT(MP4_MPEG4_AUDIO_TYPE) );

    俺寻思着是不是只要audioType指定MP4_ALAW_AUDIO_TYPE就万事大吉了?没想到视频录出来看音频信息,是AAC编码的,原来这个接口的作用是把audioType形式的音频流按AAC编码保存下来,这显然是不符合需求的

    如果想保存g711a的音频,并且在pc上显示的音频编码也是g711a的话,就要用这个接口

    1. MP4TrackId MP4AddALawAudioTrack(
    2. MP4FileHandle hFile,
    3. uint32_t timeScale);

    明显可以看出,这个接口参数没有sampleDuration,于是这就是我要说的第二个大坑

    接口实现在

    1. mp4v2-2.0.0/src/mp4file.cpp:1886:MP4TrackId MP4File::AddALawAudioTrack( uint32_t timeScale)
    2. MP4TrackId MP4File::AddALawAudioTrack( uint32_t timeScale)
    3. {
    4. memcpy(m_cAudioType, "Alaw", 5);
    5. uint32_t fixedSampleDuration = (timeScale * 20)/1000; // 20mSec/Sample
    6. MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale);
    7. ...
    8. return trackId;
    9. }

    发现什么没有?没错!这个接口写死了duration为一秒50帧,如果你的音频流和这里不一样,那么就会出现音频缺失的问题,比如我的音频是25帧,录出来的文件就是前半段有声音而后半段没有声音的

    想解决这个问题倒也简单,改源码就行,需要按你编码器实际情况修改

    uint32_t fixedSampleDuration = (timeScale * 40)/1000; // 40mSec/Sample

    改完之后重新交叉编译

    2 封装

    音频的封装就平平无奇了

    1. MP4WriteSample(pgpac->mp4handle,
    2. pgpac->atrack_id,
    3. pdata,
    4. data_size,
    5. MP4_INVALID_DURATION,
    6. 0,
    7. 1);

    唯一需要注意的是编码器输出的音频流是不是也带了什么奇奇怪怪的头,如果有,记得剥掉,MP4WriteSample写的是裸流

     

  • 相关阅读:
    mysqldump常用操作示例/命令
    大数据随记 —— Spark Core 与 RDD 简介
    算法通关村第一关-链表青铜挑战笔记
    详解CAN总线:CAN总线报文格式—数据帧
    B. AND 0, Sum Big-Codeforces Round #716 (Div. 2)
    机器学习实战之 随机森林、逻辑回归、SVM算法方法进行垃圾邮件过滤分类 代码+数据
    解决Spring测试出现@EnableAsync annotation metadata was not injected
    Netty网络框架学习笔记-16(心跳(heartbeat)服务源码分析)
    华为数通方向HCIP-DataCom H12-831题库(单选题:281-300)
    当大火的文图生成模型遇见知识图谱,AI画像趋近于真实世界
  • 原文地址:https://blog.csdn.net/xuerongdeng/article/details/128147422