Skip to content

Instantly share code, notes, and snippets.

@xeecos
Last active July 8, 2025 09:47
Show Gist options
  • Select an option

  • Save xeecos/26e21849cb176a2ac06cb6ca3a0c650c to your computer and use it in GitHub Desktop.

Select an option

Save xeecos/26e21849cb176a2ac06cb6ca3a0c650c to your computer and use it in GitHub Desktop.
mp4 file fix duration
#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
#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