From 3581d6a8edbb284856dda9b12cb669086db9c150 Mon Sep 17 00:00:00 2001 From: eumagga0x2a Date: Fri, 13 Mar 2020 19:28:07 +0100 Subject: [PATCH] [demuxers/Mp4] Support fragmented mp4 with default dts increment specified in trex box only, prefill time base for H.264 streams from SPS It is assumed that only one trex box exists and the track id matches the video track. --- avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4.cpp | 3 +- avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4.h | 2 + .../ADM_demuxers/Mp4/ADM_mp4Analyzer.cpp | 73 ++++++++++++++++++- .../ADM_demuxers/Mp4/ADM_mp4Fragments.cpp | 2 + .../ADM_demuxers/Mp4/ADM_mp4Leaf.h | 2 + 5 files changed, 77 insertions(+), 5 deletions(-) diff --git a/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4.cpp b/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4.cpp index 3588b93757..bc289ba2e6 100644 --- a/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4.cpp +++ b/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4.cpp @@ -265,6 +265,7 @@ MP4Header::MP4Header(void) _currentAudioTrack=0; _reordered=0; _videoScale=1; + _defaultDurationEx=0; _videoFound=0; delayRelativeToVideo=0; _flavor=Mp4Regular; @@ -333,7 +334,7 @@ uint8_t MP4Header::getExtraHeaderData(uint32_t *len, uint8_t **data) //______________________________________ uint8_t MP4Header::open(const char *name) { - printf("** opening 3gpp files **"); + printf("** opening 3gpp files **\n"); _fd=ADM_fopen(name,"rb"); if(!_fd) { diff --git a/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4.h b/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4.h index 8ada7e7f91..1c452642d3 100644 --- a/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4.h +++ b/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4.h @@ -186,6 +186,7 @@ class MP4Header :public vidHeader uint64_t delayRelativeToVideo; uint8_t lookupMainAtoms(void *tom); void parseMvhd(void *tom); + uint8_t parseTrex(void *ztom); uint8_t parseTrack(void *ztom); uint8_t parseElst(void *tom,int64_t *delay,int64_t *skip); bool parseMoof(adm_atom &son); @@ -204,6 +205,7 @@ class MP4Header :public vidHeader bool adjustElstDelay(void); uint32_t _videoScale; uint32_t _movieScale; + uint32_t _defaultDurationEx; // dts increment in ticks _videoScale int64_t _movieDuration; // in ms uint32_t _videoFound; bool processAudio( MP4Track *track, uint32_t trackScale, diff --git a/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Analyzer.cpp b/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Analyzer.cpp index 999440a9a1..2c40c8ec04 100644 --- a/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Analyzer.cpp +++ b/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Analyzer.cpp @@ -118,6 +118,12 @@ uint8_t MP4Header::lookupMainAtoms(void *ztom) switch(id) { case ADM_MP4_MVHD: parseMvhd(&son);break; + case ADM_MP4_MVEX: + { + ADM_info("Found mvex at position %u of size %u\n",son.getStartPos(),son.getRemainingSize()); + parseTrex(&son); + } + break; case ADM_MP4_TRACK: if(!parseTrack(&son)) { @@ -199,8 +205,45 @@ void MP4Header::parseMvhd(void *ztom) } /** - \fn parseMvhd - \brief Parse mvhd header + \fn parseTrex + \brief Some iso5 files specify dts increment via trex box only. We ignore other trex data for now. +*/ +uint8_t MP4Header::parseTrex(void *ztom) +{ + if(_defaultDurationEx) + { + ADM_warning("Multiple trex boxes not handled!\n"); + return 0; + } + adm_atom *tom=(adm_atom *)ztom; + ADMAtoms id; + uint32_t container; + uint32_t trackId=0; + while(!tom->isDone()) + { + adm_atom son(tom); + if(!ADM_mp4SearchAtomName(son.getFCC(),&id,&container)) + { + aprintf("[parseTrex] Unknown atom %s\n",fourCC::tostringBE(son.getFCC())); + son.skipAtom(); + continue; + } + if(id!=ADM_MP4_TREX) continue; + ADM_info("Found trex, assuming it is for the video track, reading it.\n"); + son.skipBytes(4); // version and flags + trackId=son.read32(); + son.skipBytes(4); // stsd id + _defaultDurationEx=tom->read32(); + ADM_info("Default duration from trex for track id %u: %u\n",trackId,_defaultDurationEx); + son.skipAtom(); + return 1; + } + ADM_info("trex box not found.\n"); + return 0; +} +/** + \fn parseTrack + \brief Parse track header */ uint8_t MP4Header::parseTrack(void *ztom) { @@ -922,7 +965,12 @@ uint8_t MP4Header::parseStbl(void *ztom,uint32_t trackType,uint32_t trackScale) mixDump(VDEO.extraData+offset,len); // Verify width and height, the values from the container may be wrong. ADM_SPSInfo sps; - if(extractSPSInfo(VDEO.extraData,VDEO.extraDataSize,&sps) && sps.width && sps.height) + if(false==extractSPSInfo(VDEO.extraData,VDEO.extraDataSize,&sps)) + { + ADM_warning("Could not decode H.264 extradata.\n"); + break; + } + if(sps.width && sps.height) { if(lw && lw!=sps.width) ADM_warning("Width mismatch, container says %u, codec %u, trusting codec\n",lw,sps.width); @@ -931,7 +979,24 @@ uint8_t MP4Header::parseStbl(void *ztom,uint32_t trackType,uint32_t trackScale) ADM_warning("Height mismatch, container says %u, codec %u, trusting codec\n",lh,sps.height); _video_bih.biHeight=_mainaviheader.dwHeight=sps.height; }else - ADM_warning("Could not decode H.264 extradata to verify video width and height.\n"); + ADM_warning("Got invalid dimensions from SPS, cannot verify video width and height.\n"); + // Prefill time base from fps1000 value we got from SPS, we handle only standard cases here. + switch(sps.fps1000) + { + case 23976: + _videostream.dwScale=1001; + _videostream.dwRate=24000; + break; + case 29970: + _videostream.dwScale=1001; + _videostream.dwRate=30000; + break; + case 24000: case 25000: case 30000: case 50000: case 60000: + _videostream.dwScale=1000; + _videostream.dwRate=sps.fps1000; + break; + default:break; + } break; } // while son.skipAtom(); diff --git a/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Fragments.cpp b/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Fragments.cpp index 2dd152ec4f..250b1c52b4 100644 --- a/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Fragments.cpp +++ b/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Fragments.cpp @@ -121,6 +121,8 @@ bool MP4Header::parseTraf(adm_atom &tom,uint64_t moofStart) TRAF_INFO(0x20,defaultFlags,32); if(trafFlags&0x10000) {aprintf("Empty duration\n");info.emptyDuration=true;} + if(!info.emptyDuration && !info.defaultDuration && _defaultDurationEx) + info.defaultDuration=_defaultDurationEx; // from trex if(trafFlags&0x20000) { diff --git a/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Leaf.h b/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Leaf.h index 58e86926ac..2b83642c2a 100644 --- a/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Leaf.h +++ b/avidemux_plugins/ADM_demuxers/Mp4/ADM_mp4Leaf.h @@ -18,6 +18,7 @@ /* Container atom */ MKMP4LEAF('moov',MOOV,1), MKMP4LEAF('moof',MOOF,1), +MKMP4LEAF('mvex',MVEX,1), MKMP4LEAF('trak',TRACK,1), MKMP4LEAF('mdia',MDIA,1), MKMP4LEAF('minf',MINF,1), @@ -31,6 +32,7 @@ MKMP4LEAF('trun',TRUN,0), MKMP4LEAF('mfhd',MFHD,0), MKMP4LEAF('mvhd',MVHD,0), MKMP4LEAF('tkhd',TKHD,0), +MKMP4LEAF('trex',TREX,0), MKMP4LEAF('mdhd',MDHD,0), MKMP4LEAF('hdlr',HDLR,0),