转载请标明出处:https://blog.csdn.net/u013752202/article/details/80557556
文中使用到的工具说明:https://blog.csdn.net/u013752202/article/details/80556729
通过http协议在线播放mp4视频的时候,往往需要把moov信息放在mdat的前面(特别是再IOS浏览器上在线播放),而由录像设备生成的mp4文件一般来说moov信息都位于mdat之后。
为了能够在线播放,就需要把moov信息的位置提前。
下面的代码即可以实现mdat和moov位置调换,先找到mdat和moov的在文件中的偏移和大小,然后再调换位置:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define SWAP_EDIAN_U32(X) (((0x000000ff&X)<<24)|((0x0000ff00&X)<<8)|((0x00ff0000&X)>>8)|((0xff000000&X)>>24))
typedef unsigned long long int VSize_t ;
#pragma pack(1)
typedef struct{
unsigned int len;
char name[4];
unsigned int offset;
}MP4Box;
#pragma pack()
int findBox(const char *vidname,MP4Box *box)
{
FILE *vfp=fopen(vidname,"rb");
if(NULL==vfp){
printf("[%s-%d]:Open %s failed !\n",__func__,__LINE__,vidname);
return -1;
}
fseek(vfp,0,SEEK_END);
VSize_t flen=ftell(vfp);
fseek(vfp,0,SEEK_SET);
VSize_t rlen=0;
int ret=0;
while(rlen<flen){
MP4Box boxtmp;
if(8!=fread((unsigned char *)&boxtmp,1,8,vfp)){
printf("[%s-%d]:Read %s error !\n",__func__,__LINE__,vidname);
ret=-1;
break;
}
char srcname[5];
char dstname[5];
memcpy(srcname,boxtmp.name,4);
srcname[4]=0;
memcpy(dstname,box->name,4);
dstname[4]=0;
//printf("rlen=%x\n",rlen);
//int t=0;
//unsigned char *ppp=(unsigned char *)&boxtmp;
//for(t=0;t<8;t++){
// printf("%02x ",ppp[t]);
//}
//printf("\n");
VSize_t boxLen=SWAP_EDIAN_U32(boxtmp.len);
if(boxLen<8){
printf("[%s-%d]:%s file damage\n",__func__,__LINE__,vidname);
ret=-1;
break;
}
if(0==strcmp(srcname,dstname)){
memcpy((unsigned char *)box,(unsigned char *)&boxtmp,8);
if(rlen+boxLen>flen){
ret=0;
break;
}
box->offset=ftell(vfp)-8;
ret=1;
break;
}
else{
if(rlen+boxLen>flen){
printf("[%s-%d]:Box length beyond file !\n",__func__,__LINE__);
ret=0;
break;
}
fseek(vfp,boxLen-8,SEEK_CUR);
rlen+=boxLen;
}
}
fclose(vfp);
return ret;
}
int main(int argc,char **argv)
{
if(3!=argc){
printf("Usage:\n");
printf("mp4ThumbPick test.mp4 out.mp4");
}
MP4Box matBox,moovBox;
{
char dstName[4]={'m','d','a','t'};
memcpy(matBox.name,dstName,4);
if(findBox(argv[1],&matBox)>0){
printf("mdat offset:0x%08x\n",matBox.offset);
}
}
{
char dstName[4]={'m','o','o','v'};
memcpy(moovBox.name,dstName,4);
if(findBox(argv[1],&moovBox)>0){
printf("moov offset:0x%08x\n",moovBox.offset);
}
}
int matLen=SWAP_EDIAN_U32(matBox.len);
int moovLen=SWAP_EDIAN_U32(moovBox.len);
printf("matBox.offset:%d,matBox.len=%d\n",matBox.offset,matLen);
printf("moovBox.offset:%d,moovBox.len=%d\n",moovBox.offset,moovLen);
FILE *infp=fopen(argv[1],"rb");
FILE *outfp=fopen(argv[2],"wb");
if(NULL==infp||NULL==outfp){
printf("Open %s/%s error!\n",argv[1],argv[2]);
}
fseek(infp,0,SEEK_END);
int flen=ftell(infp);
fseek(infp,0,SEEK_SET);
unsigned char *buf=(unsigned char *)malloc(matBox.offset);
fread(buf,1,matBox.offset,infp);
fwrite(buf,1,matBox.offset,outfp);
free(buf);
//save moov
buf=(unsigned char *)malloc(moovLen);
fseek(infp,moovBox.offset,SEEK_SET);
fread(buf,1,moovLen,infp);
fwrite(buf,1,moovLen,outfp);
free(buf);
//save mdat
int rrlen=0,rlen=0;
buf=(unsigned char *)malloc(1024);
fseek(infp,matBox.offset,SEEK_SET);
while(rlen<matLen){
if(rlen+1024<=matLen){
rrlen=fread(buf,1,1024,infp);
fwrite(buf,1,1024,outfp);
rlen+=rrlen;
}
else{
rrlen=fread(buf,1,matLen-rlen,infp);
fwrite(buf,1,matLen-rlen,outfp);
break;
}
}
free(buf);
//after moov
if(moovBox.offset+moovLen<flen){
int sparelen=flen-(moovBox.offset+moovLen);
buf=(unsigned char *)malloc(sparelen);
fseek(infp,moovBox.offset+moovLen,SEEK_SET);
fread(buf,1,sparelen,infp);
fwrite(buf,1,sparelen,outfp);
free(buf);
}
fclose(infp);
fclose(outfp);
return 0;
}
tttt.mp4为输入的mp4,moov在mdat后
out.mp4为输出的mp4,moov在mdat前
转载请标明出处:https://blog.csdn.net/u013752202/article/details/80557556