MP4边下载边播放——moov box前置

转载请标明出处: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的在文件中的偏移和大小,然后再调换位置:
需要注意的是,mdat位置变化后,moov下面的stco(chunk offset)也要改成新的offset,否则无法正常寻址播放!
 

#include <stdio.h>
#include <malloc.h>
#include <string.h>

#if _WIN32
#define __func__ __FUNCTION__
#endif

#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,int offset)
{
    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,offset,SEEK_SET);
	flen-=offset;

    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;
}

void changeStco(unsigned char *buf,int len,int chunkDeta)
{
	int i=0;
	unsigned int *pchunkOffset=0;
	for(i=16;i<len;i+=4){
		pchunkOffset=(unsigned int *)(buf+i);
		*pchunkOffset=SWAP_EDIAN_U32(SWAP_EDIAN_U32(*pchunkOffset)+chunkDeta);
	}
}

int main(int argc,char **argv)
{
    if(3!=argc){
        printf("Usage:\n");
        printf("mp4ThumbPick test.mp4 out.mp4");
		return -1;
    }

    MP4Box matBox,moovBox,stcoBox;
    {
        char dstName[4]={'m','d','a','t'};
        memcpy(matBox.name,dstName,4);
        if(findBox(argv[1],&matBox,0)>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)>0){
            printf("moov offset:0x%08x\n",moovBox.offset);    
        }
    }
	{
		MP4Box box;
        char dstName[4]={'t','r','a','k'};
        memcpy(box.name,dstName,4);
		if(findBox(argv[1],&box,moovBox.offset+8)<=0){
            printf("trak box not founc\n");
			return -1;
        }		
		char dstName1[4]={'m','d','i','a'};
        memcpy(box.name,dstName1,4);
		if(findBox(argv[1],&box,box.offset+8)<=0){
            printf("mdia box not founc\n");
			return -1;
        }
		char dstName2[4]={'m','i','n','f'};
        memcpy(box.name,dstName2,4);
		if(findBox(argv[1],&box,box.offset+8)<=0){
            printf("minf box not founc\n");
			return -1;
        }
		char dstName3[4]={'s','t','b','l'};
        memcpy(box.name,dstName3,4);
		if(findBox(argv[1],&box,box.offset+8)<=0){
            printf("stbl box not founc\n");
			return -1;
        }
		char dstName4[4]={'s','t','c','o'};
        memcpy(box.name,dstName4,4);
		if(findBox(argv[1],&box,box.offset+8)<=0){
            printf("stco box not founc\n");
			return -1;
        }
		stcoBox=box;
    }

    int matLen=SWAP_EDIAN_U32(matBox.len);
    int moovLen=SWAP_EDIAN_U32(moovBox.len);
	int stcoLen=SWAP_EDIAN_U32(stcoBox.len);
    printf("matBox.offset:%d,matBox.len=%d\n",matBox.offset,matLen);
    printf("moovBox.offset:%d,moovBox.len=%d\n",moovBox.offset,moovLen);
	printf("stcoBox.offset:%d,stcoBox.len=%d\n",stcoBox.offset,stcoLen);

    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);
		changeStco(buf+stcoBox.offset-moovBox.offset,stcoLen,moovLen);
        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

 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶落西湘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值