基于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的函数:
- 复制
ISOWriteMovieToFile的核心逻辑,删除写入ftyp、moov等box的代码块; - 保留片段原子的遍历与写入逻辑,直接输出moof和对应的mdat;
- 在库的头文件中声明新接口(如
ISOWriteMovieFragmentToFile)。
这种方式更优雅,但需要维护库的自定义分支,适合频繁使用该功能的场景。
内容的提问来源于stack exchange,提问作者Kundera
相关产品推荐
相关产品推荐

