Last active
July 8, 2025 09:47
-
-
Save xeecos/26e21849cb176a2ac06cb6ca3a0c650c to your computer and use it in GitHub Desktop.
mp4 file fix duration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef FOURCC_H | |
| #define FOURCC_H | |
| #define MKTAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24)) | |
| #define FOURCC_ftyp MKTAG('f','t','y','p') | |
| #define FOURCC_moov MKTAG('m','o','o','v') | |
| #define FOURCC_mvhd MKTAG('m','v','h','d') | |
| #define FOURCC_trak MKTAG('t','r','a','k') | |
| #define FOURCC_tkhd MKTAG('t','k','h','d') | |
| #define FOURCC_edts MKTAG('e','d','t','s') | |
| #define FOURCC_elst MKTAG('e','l','s','t') | |
| #define FOURCC_mdia MKTAG('m','d','i','a') | |
| #define FOURCC_mdhd MKTAG('m','d','h','d') | |
| #define FOURCC_hdlr MKTAG('h','d','l','r') | |
| #define FOURCC_minf MKTAG('m','i','n','f') | |
| #define FOURCC_stbl MKTAG('s','t','b','l') | |
| #define FOURCC_stsd MKTAG('s','t','s','d') | |
| #define FOURCC_stts MKTAG('s','t','t','s') | |
| #define FOURCC_stss MKTAG('s','t','s','s') | |
| #define FOURCC_ctts MKTAG('c','t','t','s') | |
| #define FOURCC_stco MKTAG('s','t','c','o') | |
| #define FOURCC_co64 MKTAG('c','o','6','4') | |
| #define FOURCC_stsc MKTAG('s','t','s','c') | |
| #define FOURCC_stsz MKTAG('s','t','s','z') | |
| #define FOURCC_stz2 MKTAG('s','t','z','2') | |
| #define FOURCC_udta MKTAG('u','d','t','a') | |
| #define FOURCC_meta MKTAG('m','e','t','a') | |
| #define FOURCC_dinf MKTAG('d','i','n','f') | |
| #define FOURCC_pitm MKTAG('p','i','t','m') | |
| #define FOURCC_iinf MKTAG('i','i','n','f') | |
| #define FOURCC_iref MKTAG('i','r','e','f') | |
| #define FOURCC_iloc MKTAG('i','l','o','c') | |
| //encryption | |
| #define FOURCC_sinf MKTAG('s','i','n','f') | |
| #define FOURCC_schi MKTAG('s','c','h','i') | |
| //heif | |
| #define FOURCC_iprp MKTAG('i','p','r','p') | |
| #define FOURCC_ipco MKTAG('i','p','c','o') | |
| #define FOURCC_ipma MKTAG('i','p','m','a') | |
| #define HANDLER_VIDEO MKTAG('v','i','d','e') | |
| #define HANDLER_AUDIO MKTAG('s','o','u','n') | |
| #define HANDLER_HINT MKTAG('h','i','n','t') | |
| #define HANDLER_META MKTAG('m','e','t','a') | |
| #endif // FOURCC_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include <stdio.h> | |
| #include <stdint.h> | |
| #include <stdlib.h> | |
| #include "fourcc.h" | |
| union bytes2u16 | |
| { | |
| uint16_t value; | |
| uint8_t bytes[2]; | |
| }; | |
| union bytes2u32 | |
| { | |
| uint32_t value; | |
| uint8_t bytes[4]; | |
| }; | |
| union bytes2u64 | |
| { | |
| uint64_t value; | |
| uint8_t bytes[8]; | |
| }; | |
| class MP4Repair | |
| { | |
| public: | |
| MP4Repair() | |
| { | |
| fd = NULL; | |
| } | |
| ~MP4Repair() | |
| { | |
| close(); | |
| } | |
| int ReadBox(uint32_t start_pos) | |
| { | |
| int index = 0; | |
| uint32_t size = Read32(); | |
| uint32_t type = Read32(); | |
| index = 8; | |
| if (size == 1) | |
| { | |
| index += 8; | |
| size = Read64(); | |
| } | |
| switch (type) | |
| { | |
| case FOURCC_moov: | |
| case FOURCC_edts: | |
| case FOURCC_mdia: | |
| case FOURCC_minf: | |
| case FOURCC_dinf: | |
| case FOURCC_stbl: | |
| case FOURCC_udta: | |
| case FOURCC_iprp: | |
| case FOURCC_sinf: | |
| case FOURCC_schi: | |
| { | |
| int box_index = 0; | |
| int box_position = start_pos + index; | |
| while (box_index < size - 8) | |
| { | |
| int box_size = ReadBox(box_position + box_index); | |
| box_index += box_size; | |
| SetPos(box_position + box_index); | |
| } | |
| } | |
| break; | |
| case FOURCC_elst: | |
| { | |
| int box_index = 0; | |
| int box_position = start_pos + index; | |
| SetPos(box_position); | |
| int version = Read8(); // version | |
| Read24(); // flags | |
| int elst_count = Read32(); | |
| for (int i = 0; i < elst_count; i++) | |
| { | |
| uint64_t segment_duration; | |
| int64_t media_time; | |
| if (version == 1) | |
| { | |
| Write64(box_position+8,this->duration); | |
| segment_duration = Read64(); | |
| media_time = Read64(); | |
| } | |
| else | |
| { | |
| Write32(box_position+8,this->duration); | |
| segment_duration = Read32(); | |
| media_time = Read32(); | |
| } | |
| printf("edit list box %d:%d %d\n",i, segment_duration, media_time); // | |
| int media_rate_integer = Read16(); | |
| int media_rate_fraction = Read16(); | |
| } | |
| } | |
| break; | |
| case FOURCC_mvhd: | |
| { | |
| int box_index = 0; | |
| int box_position = start_pos + index; | |
| SetPos(box_position); | |
| uint64_t creation_time, modification_time; | |
| uint32_t timescale; | |
| uint64_t duration; | |
| int version = Read8(); | |
| Read24(); | |
| if (version == 1) | |
| { | |
| creation_time = Read64(); | |
| modification_time = Read64(); | |
| timescale = Read32(); | |
| Write64(box_position+24,this->duration); | |
| duration = Read64(); | |
| } | |
| else | |
| { | |
| creation_time = Read32(); | |
| modification_time = Read32(); | |
| timescale = Read32(); | |
| Write32(box_position+16,this->duration); | |
| duration = Read32(); | |
| } | |
| printf("movie header box:%d,%d\n", timescale, duration); | |
| } | |
| break; | |
| case FOURCC_trak: | |
| { | |
| int box_index = 0; | |
| int box_position = start_pos + index; | |
| while (box_index < size - 8) | |
| { | |
| int box_size = ReadBox(box_position + box_index); | |
| box_index += box_size; | |
| SetPos(box_position + box_index); | |
| } | |
| } | |
| break; | |
| case FOURCC_tkhd: | |
| { | |
| int box_index = 0; | |
| int box_position = start_pos + index; | |
| SetPos(box_position); | |
| uint64_t creation_time, modification_time; | |
| uint64_t duration; | |
| uint32_t track_id; | |
| uint8_t version = Read8(); | |
| uint32_t flags = Read24(); | |
| if (version == 1) | |
| { | |
| creation_time = Read64(); | |
| modification_time = Read64(); | |
| track_id = Read32(); | |
| Skip(4); | |
| Write64(box_position+28,this->duration); | |
| duration = Read64(); | |
| } | |
| else | |
| { | |
| creation_time = Read32(); | |
| modification_time = Read32(); | |
| track_id = Read32(); | |
| Skip(4); | |
| Write32(box_position+20,this->duration); | |
| duration = Read32(); | |
| } | |
| printf("track header box:%d\n", duration); | |
| } | |
| break; | |
| case FOURCC_mdhd: | |
| { | |
| int box_index = 0; | |
| int box_position = start_pos + index; | |
| SetPos(box_position); | |
| uint64_t creation_time, modification_time; | |
| uint64_t timescale, duration; | |
| uint8_t version = Read8(); | |
| uint32_t flags = Read24(); | |
| if (version == 1) | |
| { | |
| creation_time = Read64(); | |
| modification_time = Read64(); | |
| timescale = Read32(); | |
| Write32(box_position+24,this->duration); | |
| duration = Read32(); | |
| } | |
| else | |
| { | |
| creation_time = Read32(); | |
| modification_time = Read32(); | |
| timescale = Read32(); | |
| Write32(box_position+16,this->duration); | |
| duration = Read32(); | |
| } | |
| printf("media header box:%d %d\n", timescale, duration); // | |
| } | |
| break; | |
| case FOURCC_hdlr: | |
| break; | |
| case FOURCC_stsd: | |
| break; | |
| case FOURCC_stts: | |
| break; | |
| case FOURCC_stss: | |
| break; | |
| case FOURCC_ctts: | |
| break; | |
| case FOURCC_stco: | |
| case FOURCC_co64: | |
| break; | |
| case FOURCC_stsc: | |
| break; | |
| case FOURCC_stsz: | |
| case FOURCC_stz2: | |
| break; | |
| case FOURCC_meta: | |
| break; | |
| case FOURCC_pitm: | |
| break; | |
| case FOURCC_iinf: | |
| break; | |
| case FOURCC_iref: | |
| break; | |
| case FOURCC_iloc: | |
| break; | |
| case FOURCC_ipco: | |
| break; | |
| case FOURCC_ipma: | |
| break; | |
| default: | |
| break; | |
| } | |
| //__Parse(this, start_pos + index); | |
| return size; | |
| } | |
| int repair(const char *filename, int duration = 10000) | |
| { | |
| this->duration = duration; | |
| int ret = open(filename); | |
| if (ret != 0) | |
| { | |
| return -1; | |
| } | |
| uint32_t cur_pos = 0; | |
| int file_size = GetLength(); | |
| if (file_size <= 8) | |
| { | |
| return -1; | |
| } | |
| Read32(); | |
| uint32_t ftyp = Read32(); | |
| if (ftyp != FOURCC_ftyp) | |
| { | |
| return -1; | |
| } | |
| SetPos(0); | |
| while (cur_pos < file_size) | |
| { | |
| int size = ReadBox(cur_pos); | |
| cur_pos += size; | |
| SetPos(cur_pos); | |
| } | |
| close(); | |
| return 0; | |
| } | |
| int open(const char *fileName) | |
| { | |
| fd = fopen(fileName, "rb+"); | |
| if (fd == NULL) | |
| return -1; | |
| return 0; | |
| } | |
| int close() | |
| { | |
| if (fd) | |
| { | |
| fclose(fd); | |
| fd = NULL; | |
| } | |
| return 0; | |
| } | |
| int GetLength() | |
| { | |
| int cur = ftell(fd); | |
| fseek(fd, 0, SEEK_END); | |
| int file_size = ftell(fd); | |
| fseek(fd, cur, SEEK_SET); | |
| return file_size; | |
| } | |
| int GetPos() | |
| { | |
| return ftell(fd); | |
| } | |
| int SetPos(int pos) | |
| { | |
| fseek(fd, pos, SEEK_SET); | |
| return 0; | |
| } | |
| uint8_t Read8() | |
| { | |
| uint8_t ret; | |
| fread(&ret, 1, 1, fd); | |
| return ret; | |
| } | |
| uint16_t Read16() | |
| { | |
| uint8_t buffer[2]; | |
| fread(buffer, 2, 1, fd); | |
| return ((buffer[0] << 8) | buffer[1]); | |
| } | |
| uint32_t Read24() | |
| { | |
| uint8_t buffer[3]; | |
| fread(buffer, 3, 1, fd); | |
| return ((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]); | |
| } | |
| uint32_t Read32() | |
| { | |
| uint8_t buffer[4] = {0}; | |
| fread(buffer, 4, 1, fd); | |
| return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]); | |
| } | |
| uint64_t Read64() | |
| { | |
| uint64_t h = Read32(); | |
| uint64_t l = Read32(); | |
| return (h << 32) | l; | |
| } | |
| void Write8(int pos, uint8_t value) | |
| { | |
| fseek(fd, pos, SEEK_SET); | |
| fwrite(&value, 1, 1, fd); | |
| fseek(fd, pos, SEEK_SET); | |
| } | |
| void Write16(int pos, uint16_t value) | |
| { | |
| bytes2u16 v; | |
| v.value = value; | |
| for(int i=0; i<2; i++) | |
| { | |
| fseek(fd, pos+i, SEEK_SET); | |
| fwrite(&v.bytes[1-i], 1, 1, fd); | |
| } | |
| fseek(fd, pos, SEEK_SET); | |
| } | |
| void Write32(int pos, uint32_t value) | |
| { | |
| bytes2u32 v; | |
| v.value = value; | |
| for(int i=0; i<4; i++) | |
| { | |
| fseek(fd, pos+i, SEEK_SET); | |
| fwrite(&v.bytes[3-i], 1, 1, fd); | |
| } | |
| fseek(fd, pos, SEEK_SET); | |
| } | |
| void Write64(int pos, uint64_t value) | |
| { | |
| bytes2u64 v; | |
| v.value = value; | |
| for(int i=0; i<8; i++) | |
| { | |
| fseek(fd, pos+i, SEEK_SET); | |
| fwrite(&v.bytes[7-i], 1, 1, fd); | |
| } | |
| fseek(fd, pos, SEEK_SET); | |
| } | |
| int Skip(int len) | |
| { | |
| return fseek(fd, len, SEEK_CUR); | |
| } | |
| int ReadBuffer(char *buffer, int len) | |
| { | |
| return fread(buffer, 1, len, fd); | |
| } | |
| bool isEOF() | |
| { | |
| return feof(fd); | |
| } | |
| private: | |
| FILE *fd; | |
| int duration; | |
| }; | |
| /** | |
| int main() | |
| { | |
| MP4Repair mp4; | |
| mp4.repair("test.mp4", 10000); //ms | |
| } | |
| */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment