You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于isobmff库仅生成含moof与mdat的m4v文件的技术咨询

解决方案:基于isobmff库生成仅含moof/mdat的m4v文件

问题根源分析

你访问movie->movieFragments返回NULL的核心原因是:ISOStartMovieFragment仅初始化片段上下文,只有完成片段的构建(结束片段、计算原子大小)后,片段才会被添加到movieFragments链表。当前代码直接调用ISOWriteMovieToFile会写入完整的ftyp/moov/moof/mdat结构,并未触发片段链表的填充逻辑。


方案1:手动提取并写入moof/mdat原子(无需修改库源码)

通过补充片段收尾逻辑,直接从私有结构体中提取已构建好的moof和mdat原子,手动写入文件:

ISOMovie moov;       // movie box 
ISOMedia media;
ISOTrack trak;
err = MP4NewMovie(&moov, 0, 0, 0, 0, 0, 0);
err = MP4SetMovieTimeScale (moov, TIMESCALE);
err = ISONewMovieTrack(moov, MP4NewTrackIsVisual, &trak);
err = ISOSetTrackFragmentDefaults(trak, 0, 0, 0, 0);
err = ISONewTrackMedia(trak, &media, ISOVisualHandlerType, TIMESCALE, NULL);
err = ISOBeginMediaEdits(media);

// 写入SPS/PPS
err = ISOAddMediaSamples(media,0,0,durationsH,sizesH,sampleEntryH,0,0);
err = ISOEndMediaEdits(media);

// 启动片段并写入媒体样本
err = ISOStartMovieFragment(moov);
err = ISOSetSamplestoGroupType(media, SAMPLE_GROUP_NORMAL);
err = ISOAddMediaSamples(media,sampleH,1,durationsH,sizesH,sampleEntryH,0,0);
// 关键:结束片段,触发moof原子的构建与大小计算
err = ISOEndMovieFragment(moov);

// 提取并写入moof/mdat
MP4PrivateMovieRecordPtr movie = (MP4PrivateMovieRecordPtr)moov;
if (!movie) return err;

// 验证moof原子是否生成(moovAtomPtr在片段模式下指向moof)
if (movie->moovAtomPtr && MP4GetAtomType(movie->moovAtomPtr) == MP4_MOOF_ATOM_TYPE) {
    MP4AtomPtr moofAtom = movie->moovAtomPtr;
    MP4AtomPtr mdatAtom = movie->mdat;

    if (moofAtom && mdatAtom) {
        FILE* fp = fopen("output.m4v", "wb");
        if (!fp) return -1;

        // 写入moof原子:大小 -> 类型 ->  payload
        u32 moofSize = MP4GetAtomSize(moofAtom);
        fwrite(&moofSize, sizeof(u32), 1, fp);
        fwrite("moof", 4, 1, fp);
        fwrite(MP4GetAtomPayload(moofAtom), moofSize - 8, 1, fp);

        // 写入mdat原子
        u32 mdatSize = MP4GetAtomSize(mdatAtom);
        fwrite(&mdatSize, sizeof(u32), 1, fp);
        fwrite("mdat", 4, 1, fp);
        fwrite(MP4GetAtomPayload(mdatAtom), mdatSize - 8, 1, fp);

        fclose(fp);
    }
}

关键注意点:

  • 必须调用ISOEndMovieFragment:该函数会完成moof原子的内部结构构建(如tfhd、trun子box),并计算原子总大小。
  • 原子访问兼容:如果MP4GetAtomType/MP4GetAtomSize等函数未公开,可直接访问结构体成员(如moofAtom->size、moofAtom->type、moofAtom->payload)。
  • 播放验证:用ffmpeg -i output.m4v检查文件合法性,确认能识别moof/mdat结构。

方案2:修改库源码,新增仅写片段的接口

如果需要长期复用该功能,可参考ISOWriteMovieToFile的实现,封装一个仅写入moof/mdat的函数:

  1. 复制ISOWriteMovieToFile的核心逻辑,删除写入ftyp、moov等box的代码块;
  2. 保留片段原子的遍历与写入逻辑,直接输出moof和对应的mdat;
  3. 在库的头文件中声明新接口(如ISOWriteMovieFragmentToFile)。

这种方式更优雅,但需要维护库的自定义分支,适合频繁使用该功能的场景。


内容的提问来源于stack exchange,提问作者Kundera

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 14:00:39