sdk-hwV1.3/external/eyesee-mpp/middleware/sun8iw21/media/LIBRARY/libfilerepair/file_repair.c

1568 lines
58 KiB
C
Executable File

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <utils/plat_log.h>
#include <SystemBase.h>
//#include <log/log_wrapper.h>
#include "record_writer.h"
#include "cdx_list.h"
#include "Mp4Muxer.h"
#include <media_common_vcodec.h>
#include <media_common_acodec.h>
#include "file_repair.h"
#define MINIMAL_FILE_SIZE (MOV_HEADER_RESERVE_SIZE)
#define META_DATA_POSITION (MINIMAL_FILE_SIZE+16)
#define SIMPLE_CACHE_SIZE_VFS (32*1024)
#define MAXIMUM_VIDEO_STRM_NUM 6
typedef struct mp4_file_repair_context_s
{
void *pMuxerCtx;
CDX_RecordWriter *pWriter;
MOV_META file_meta_info;
unsigned int max_frms_tag_interval; // used to control the frequency the frms_tag written,unit:us.
struct list_head frms_tag_list; //list of FRMS_TAG_NODE
unsigned int frms_tag_node_num; //number of frms_tag.
int mbSetFirstPtsFlag;
int64_t nFirstPts; //unit:us
int64_t nCurrentPts; //unit:us
}MP4_FILE_REPAIR_CONTEXT;
struct frms_tag_info_s
{
unsigned int frms_tag_id;
struct frms_tag_s frms_tag;
};
typedef struct frms_tag_node_s
{
struct frms_tag_info_s frms_tag_info;
struct list_head list;
}FRMS_TAG_NODE;
/**
release buffer that is malloced.
*/
static void mp4_file_vos_buff_rls(MP4_FILE_REPAIR_CONTEXT *context)
{
MP4_FILE_REPAIR_CONTEXT *p_repair_ctx = context;
for(int i=0; i<p_repair_ctx->file_meta_info.v_strm_num; ++i)
{
if(NULL != p_repair_ctx->file_meta_info.v_strms_meta[i].v_vos_buff)
{
free(p_repair_ctx->file_meta_info.v_strms_meta[i].v_vos_buff);
p_repair_ctx->file_meta_info.v_strms_meta[i].v_vos_buff = NULL;
}
}
for(int i=0; i<p_repair_ctx->file_meta_info.a_strm_num; ++i)
{
if(NULL != p_repair_ctx->file_meta_info.a_strms_meta[i].a_vos_buff)
{
free(p_repair_ctx->file_meta_info.a_strms_meta[i].a_vos_buff);
p_repair_ctx->file_meta_info.a_strms_meta[i].a_vos_buff = NULL;
}
}
if(NULL != p_repair_ctx->file_meta_info.t_strms_meta.t_vos_buff)
{
free(p_repair_ctx->file_meta_info.t_strms_meta.t_vos_buff);
p_repair_ctx->file_meta_info.t_strms_meta.t_vos_buff = NULL;
}
return;
}
static int mp4_file_meta_data_read(MP4_FILE_REPAIR_CONTEXT *context,int file_fd)
{
MOV_META *p_file_meta = &context->file_meta_info;
long long off = 0;
int stream_num = 0;
unsigned int tmp_max_frms_tag_interval = 0;
int ret = 0;
off = lseek(file_fd,META_DATA_POSITION,SEEK_SET);
if(off != META_DATA_POSITION)
{
aloge("file_repair_position_seek_err,c:%lld,t:%d\n",
off,META_DATA_POSITION);
return -1;
}
#ifdef MP4_FILE_REPAIR_FAST_VERSION
ret = read(file_fd,&tmp_max_frms_tag_interval,sizeof(tmp_max_frms_tag_interval));
if(ret != sizeof(tmp_max_frms_tag_interval))
{
aloge("file_repair_v_tmp_max_frms_tag_interval_read_err,r:%d,stm_num:%x\n",
ret,tmp_max_frms_tag_interval);
return -1;
}
tmp_max_frms_tag_interval = (tmp_max_frms_tag_interval&0xff000000)>>24|((tmp_max_frms_tag_interval&0x00ff0000)>>16)<<8|
((tmp_max_frms_tag_interval&0x0000ff00)>>8)<<16 | (tmp_max_frms_tag_interval&0xff)<<24;
context->max_frms_tag_interval = tmp_max_frms_tag_interval;
#endif
ret = read(file_fd,&stream_num,sizeof(stream_num));
if(ret != sizeof(stream_num))
{
aloge("file_repair_v_stream_num_read_err,r:%d,stm_num:%x\n",
ret,stream_num);
return -1;
}
stream_num = (stream_num&0xff000000)>>24|((stream_num&0x00ff0000)>>16)<<8|
((stream_num&0x0000ff00)>>8)<<16 | (stream_num&0xff)<<24;
p_file_meta->v_strm_num = stream_num;
alogd("file_repair_v_strm_num:%d\n",stream_num);
if(stream_num > MAXIMUM_VIDEO_STRM_NUM)// maybe not contain repair info in file
{
aloge("file_repair_invalid_video_stream_num:%d\n",stream_num);
return -1;
}
for(int i=0; i<stream_num; ++i)// video stream exist
{
ret = read(file_fd,&p_file_meta->v_strms_meta[i],sizeof(V_STRM_META_DATA)-4);
if(ret != sizeof(V_STRM_META_DATA)-4)
{
aloge("file_repair_v:%d_meta_info_read_err,r:%d,t:%d\n",
i,ret,sizeof(V_STRM_META_DATA)-4);
return -1;
}
alogd("file_repair_v:%d_vos_len:%d\n",i,p_file_meta->v_strms_meta[i].v_vos_len);
if(0 != p_file_meta->v_strms_meta[i].v_vos_len)
{
char *tmp_buff = (char *)malloc(p_file_meta->v_strms_meta[i].v_vos_len);
if(NULL == tmp_buff)
{
aloge("file_repair_v:%d_vos_buff_malloc_fail,s:%d\n",
i,p_file_meta->v_strms_meta[i].v_vos_len);
mp4_file_vos_buff_rls(context);
return -1;
}
memset(tmp_buff,0,p_file_meta->v_strms_meta[i].v_vos_len);
ret = read(file_fd,tmp_buff,p_file_meta->v_strms_meta[i].v_vos_len);
if(ret != p_file_meta->v_strms_meta[i].v_vos_len)
{
aloge("file_repair_v:%d_read_vos_fail,r:%d,t:%d\n",
i,ret,p_file_meta->v_strms_meta[i].v_vos_len);
return -1;
}
p_file_meta->v_strms_meta[i].v_vos_buff = tmp_buff;
}
}
ret = read(file_fd,&stream_num,sizeof(stream_num));
if(ret != sizeof(stream_num))
{
aloge("file_repair_a_stream_num_read_err,r:%d,stm_num:%x\n",
ret,stream_num);
return -1;
}
stream_num = (stream_num&0xff000000)>>24|((stream_num&0x00ff0000)>>16)<<8|
((stream_num&0x0000ff00)>>8)<<16 | (stream_num&0xff)<<24;
p_file_meta->a_strm_num = stream_num;
alogd("file_repair_a_strm_num:%d\n",stream_num);
for(int i=0; i<stream_num; ++i)// audio stream exist
{
ret = read(file_fd,&p_file_meta->a_strms_meta[i],sizeof(A_STRM_META_DATA)-4);
if(ret != sizeof(A_STRM_META_DATA)-4)
{
aloge("file_repair_a:%d_meta_info_read_err,r:%d,t:%d\n",
i,ret,sizeof(A_STRM_META_DATA)-4);
return -1;
}
alogd("file_repair_a:%d_vos_len:%d\n",i,p_file_meta->a_strms_meta[i].a_vos_len);
if(0 != p_file_meta->a_strms_meta[i].a_vos_len)
{
char *tmp_buff = (char *)malloc(p_file_meta->a_strms_meta[i].a_vos_len);
if(NULL == tmp_buff)
{
aloge("file_repair_a:%d_vos_buff_malloc_fail,s:%d\n",
i,p_file_meta->a_strms_meta[i].a_vos_len);
mp4_file_vos_buff_rls(context);
return -1;
}
memset(tmp_buff,0,p_file_meta->a_strms_meta[i].a_vos_len);
ret = read(file_fd,tmp_buff,p_file_meta->a_strms_meta[i].a_vos_len);
if(ret != p_file_meta->a_strms_meta[i].a_vos_len)
{
aloge("file_repair_a:%d_read_vos_fail,r:%d,t:%d\n",
i,ret,p_file_meta->a_strms_meta[i].a_vos_len);
return -1;
}
p_file_meta->a_strms_meta[i].a_vos_buff = tmp_buff;
}
}
ret = read(file_fd,&stream_num,sizeof(stream_num));
if(ret != sizeof(stream_num))
{
aloge("file_repair_t_stream_num_read_err,r:%d,stm_num:%x\n",
ret,stream_num);
return -1;
}
stream_num = (stream_num&0xff000000)>>24|((stream_num&0x00ff0000)>>16)<<8|
((stream_num&0x0000ff00)>>8)<<16 | (stream_num&0xff)<<24;
p_file_meta->t_strm_num = stream_num;
alogd("file_repair_t_strm_num:%d\n",stream_num);
if(0<stream_num)// text stream exist
{
ret = read(file_fd,&p_file_meta->t_strms_meta,sizeof(T_STRM_META_DATA)-4);
if(ret != sizeof(T_STRM_META_DATA)-4)
{
aloge("file_repair_t_meta_info_read_err,r:%d,t:%d\n",
ret,sizeof(T_STRM_META_DATA)-4);
return -1;
}
alogw("file_repair_t_vos_len:%d\n",p_file_meta->t_strms_meta.t_vos_len);
if(0 != p_file_meta->t_strms_meta.t_vos_len)
{
char *tmp_buff = (char *)malloc(p_file_meta->t_strms_meta.t_vos_len);
if(NULL == tmp_buff)
{
aloge("file_repair_t_vos_buff_malloc_fail,s:%d\n",
p_file_meta->t_strms_meta.t_vos_len);
mp4_file_vos_buff_rls(context);
return -1;
}
memset(tmp_buff,0,p_file_meta->t_strms_meta.t_vos_len);
ret = read(file_fd,tmp_buff,p_file_meta->t_strms_meta.t_vos_len);
if(ret != p_file_meta->t_strms_meta.t_vos_len)
{
aloge("file_repair_t_read_vos_fail,r:%d,t:%d\n",
ret,p_file_meta->t_strms_meta.t_vos_len);
return -1;
}
p_file_meta->t_strms_meta.t_vos_buff = tmp_buff;
}
}
return 0;
}
static int mp4_file_frm_hdr_read(MP4_FILE_REPAIR_CONTEXT *context,int file_fd,
MOV_FRM_HDR *p_frm_hdr)
{
int tmp_ret = 0;
if(NULL == p_frm_hdr)
{
aloge("mp4_repair_invalid_param!!\n");
return -1;
}
memset(p_frm_hdr,0,sizeof(MOV_FRM_HDR));
tmp_ret = read(file_fd,p_frm_hdr,sizeof(MOV_FRM_HDR));
if(tmp_ret != sizeof(MOV_FRM_HDR))
{
aloge("file_repair_read_frm_hdr_fail,r:%d,t:%d\n",
tmp_ret,sizeof(MOV_FRM_HDR));
return -1;
}
return 0;
}
static int mp4_file_muxer_init(MP4_FILE_REPAIR_CONTEXT *context,int file_fd)
{
int tmp_ret = 0;
MOV_META *p_file_meta = &context->file_meta_info;
_media_file_inf_t media_info;
if(NULL == context->pWriter)
{
context->pWriter = cedarx_record_writer_create(MUXER_MODE_MP4);
if(NULL == context->pWriter)
{
aloge("file_repair_cedarx_record_writer_create_failed!!\n");
return -1;
}
context->pMuxerCtx = context->pWriter->MuxerOpen((int*)&tmp_ret);
if(0 != tmp_ret)
{
aloge("file_repair_muxer_open_failed!!\n");
cedarx_record_writer_destroy(context->pWriter);
return -1;
}
context->pWriter->MuxerIoctrl(context->pMuxerCtx, SETFALLOCATELEN,
0, NULL);
tmp_ret = context->pWriter->MuxerIoctrl(context->pMuxerCtx,SETCACHEFD2,
(unsigned int)file_fd, NULL);
if( tmp_ret != 0)
{
aloge("file_repair_muxer_set_output_fd_failed!!\n");
context->pWriter->MuxerClose(context->pMuxerCtx);
cedarx_record_writer_destroy(context->pWriter);
return -1;
}
context->pWriter->MuxerIoctrl(context->pMuxerCtx, SET_FS_WRITE_MODE,
FSWRITEMODE_SIMPLECACHE, NULL);
context->pWriter->MuxerIoctrl(context->pMuxerCtx, SET_FS_SIMPLE_CACHE_SIZE,
SIMPLE_CACHE_SIZE_VFS, NULL);
}
context->pWriter->MuxerIoctrl(context->pMuxerCtx,SET_FILE_REPAIR_FLAG,1,NULL);
#ifdef MP4_FILE_REPAIR_FAST_VERSION
context->pWriter->MuxerIoctrl(context->pMuxerCtx,SET_FILE_REPAIR_INTERVAL,context->max_frms_tag_interval,NULL);
#endif
memset(&media_info,0,sizeof(_media_file_inf_t));
media_info.mVideoInfoValidNum = p_file_meta->v_strm_num;
for(int i=0; i<p_file_meta->v_strm_num; ++i)
{
MediaVideoInfo *p_dst = &media_info.mMediaVideoInfo[i];
V_STRM_META_DATA *p_src = &p_file_meta->v_strms_meta[i];
p_dst->mVideoEncodeType = p_src->v_enc_type;
p_dst->uVideoFrmRate = p_src->v_frm_rate;
p_dst->nWidth = p_src->v_frm_width;
p_dst->nHeight = p_src->v_frm_height;
p_dst->rotate_degree = p_src->v_frm_rotate_degree;
p_dst->maxKeyInterval = p_src->v_frm_max_key_frm_interval;
p_dst->create_time = p_src->v_create_time;
}
if(0 != p_file_meta->a_strm_num)
{
media_info.audio_encode_type = p_file_meta->a_strms_meta[0].a_enc_type;
media_info.sample_rate = p_file_meta->a_strms_meta[0].a_sample_rate;
media_info.channels = p_file_meta->a_strms_meta[0].a_chn_num;
media_info.bits_per_sample = p_file_meta->a_strms_meta[0].a_bit_depth;
media_info.frame_size = p_file_meta->a_strms_meta[0].a_frm_size;
}
if(0 != p_file_meta->t_strm_num)
{
media_info.geo_available = 1;
}
tmp_ret = context->pWriter->MuxerIoctrl(context->pMuxerCtx,SETAVPARA,0,
(void*)(&media_info));
if(0 != tmp_ret)
{
aloge("file_repair_muxer_set_meta_info_failed!!\n");
context->pWriter->MuxerClose(context->pMuxerCtx);
cedarx_record_writer_destroy(context->pWriter);
return -1;
}
// set video vos
for(int i=0; i<p_file_meta->v_strm_num; ++i)
{
if(0 != p_file_meta->v_strms_meta[i].v_vos_len)
{
context->pWriter->MuxerWriteExtraData(context->pMuxerCtx,
(unsigned char *)(p_file_meta->v_strms_meta[i].v_vos_buff),
p_file_meta->v_strms_meta[i].v_vos_len, i);
}
}
// set audio vos
if(0 != p_file_meta->a_strm_num && 0 != p_file_meta->a_strms_meta[0].a_vos_len)
{
context->pWriter->MuxerWriteExtraData(context->pMuxerCtx,
(unsigned char *)(p_file_meta->a_strms_meta[0].a_vos_buff),
p_file_meta->a_strms_meta[0].a_vos_len,
p_file_meta->v_strm_num);
}
// set text vos
if(0 != p_file_meta->t_strm_num && 0 != p_file_meta->t_strms_meta.t_vos_len)
{
context->pWriter->MuxerWriteExtraData(context->pMuxerCtx,
(unsigned char *)(p_file_meta->t_strms_meta.t_vos_buff),
p_file_meta->t_strms_meta.t_vos_len,
p_file_meta->v_strm_num+1);
}
tmp_ret = context->pWriter->MuxerWriteHeader(context->pMuxerCtx);
if(0 > tmp_ret)
{
aloge("file_repair_wrt_hdr_fail!\n");
context->pWriter->MuxerClose(context->pMuxerCtx);
cedarx_record_writer_destroy(context->pWriter);
return -1;
}
return 0;
}
static void mp4_file_muxer_rls(MP4_FILE_REPAIR_CONTEXT *context)
{
if(NULL != context->pMuxerCtx)
{
context->pWriter->MuxerClose(context->pMuxerCtx);
context->pMuxerCtx = NULL;
}
if(NULL != context->pWriter)
{
cedarx_record_writer_destroy(context->pWriter);
context->pWriter = NULL;
}
}
/**
@return
0: is mp4
-1: not mp4
*/
static int mp4_file_format_chk(int fd)
{
unsigned int size = 0;
char atom_type[5] = {0};
int ret = 0;
ret = read(fd,&size,sizeof(int));
if(ret != sizeof(int))
{
aloge("file_repair_read_ftyp_atom_size_err,r:%d,t:%d\n",ret,sizeof(int));
return -1;
}
ret = read(fd,atom_type,4);
if(ret != 4)
{
aloge("file_repair_read_ftyp_atom_type_err,r:%d\n",ret);
return -1;
}
atom_type[4] = '\0';
if(strcmp(atom_type,"ftyp") != 0)
{
aloge("file_repair_file_type_may_be_err,type:%s\n",atom_type);
return -1;
}
return 0;
}
/**
check if file need repair, and if file can be repaired.
method is: check mdat size field, if size != 0, means file is complete, no need to repair,
if size == 0 or not find mdat atom, file is not complete, then judge if can repair this file.
@return
0: no need repair. file is complete or can't be repaired.
1: need repair and can be repaired.
*/
static int mp4_file_need_repair_chk(int file_fd,long long file_len)
{
// unsigned int ending_maker[4] = {0xAABBAABB,0xCCDDCCDD,0xEEFFEEFF,0xABCDEFAB };
// unsigned int read_ending_maker[4] = {0};
unsigned int atom_size = 0;
char atom_type[5] = {0};
int tmp_ret = 0;
// use encing marker to validate integrality of file
/* tmp_ret = lseek(file_fd,-16,SEEK_CUR);
if(-1 == tmp_ret)
{
aloge("file_repair_integrity_chk_seek_fail,r:%d\n",tmp_ret);
}
tmp_ret = read(file_fd,read_ending_maker,16);
if(16 != tmp_ret)
{
aloge("file_repair_ending_marker_read_fail,r:%d\n",tmp_ret);
}
if((read_ending_maker[0] == ending_maker[0]) &&
(read_ending_maker[1] == ending_maker[1]) &&
(read_ending_maker[2] == ending_maker[2]) &&
(read_ending_maker[3] == ending_maker[3]))
{
return 0; // do not need
}
else
{
return 1; // need to be repaired
} */
// better way to check the existence of ending maker atom
tmp_ret = lseek(file_fd,0,SEEK_SET);
if(-1 == tmp_ret)
{
aloge("file_repair_integrity_chk_seek_fail,r:%d\n",tmp_ret);
}
while(1)
{
tmp_ret = read(file_fd,&atom_size,sizeof(unsigned int));
if(tmp_ret != sizeof(unsigned int))
{
aloge("file_repair_rd_atom_size_err,r:%d\n",tmp_ret);
return 0; // not to repair
}
atom_size = (atom_size&0xff000000)>>24|((atom_size&0x00ff0000)>>16)<<8|
((atom_size&0x0000ff00)>>8)<<16 | (atom_size&0xff)<<24;
tmp_ret = read(file_fd,atom_type,4);
if(tmp_ret != 4)
{
aloge("file_repair_rd_atom_type_err,r:%d\n",tmp_ret);
}
atom_type[4] = '\0';
// improve the checking,just checkt the size field of mdat atom
if(!strcmp(atom_type,"mdat")) // search skip atom
{
if(atom_size != 0)
{
return 0; // do not need
}
else
{
return 1; // do need
}
}
else
{
unsigned int cur_off = lseek(file_fd,0,SEEK_CUR);
if(cur_off+atom_size-8 >= file_len)
{
aloge("file_repair_not_found_ending_marker,o:%d,s:%d,f:%d\n",
cur_off,atom_size,file_len);
return 1;
}
else
{
tmp_ret = lseek(file_fd,atom_size-8,SEEK_CUR);
if(-1 == tmp_ret)
{
aloge("file_repair_jump_atom_err,r:%d,t:%d\n",tmp_ret,atom_size-8);
return 0;
}
}
}
/* if(!strcmp(atom_type,"skip")) // search skip atom
{
tmp_ret = read(file_fd,read_ending_maker,16); // check further
if(16 != tmp_ret)
{
aloge("file_repair_ending_marker_read_fail,r:%d\n",tmp_ret);
}
if((read_ending_maker[0] == ending_maker[0]) &&
(read_ending_maker[1] == ending_maker[1]) &&
(read_ending_maker[2] == ending_maker[2]) &&
(read_ending_maker[3] == ending_maker[3]))
{
return 0; // do not need
}
else
{
return 1; // need to be repaired
}
}
else
{
if(!strcmp(atom_type,"mdat") && atom_size == 0)
{
aloge("file_repair_0_repair\n");
return 1; // need to be repaired
}
unsigned int cur_off = lseek(file_fd,0,SEEK_CUR);
if(cur_off+atom_size-8 >= file_len)
{
aloge("file_repair_not_found_ending_marker,o:%d,s:%d,f:%d\n",
cur_off,atom_size,file_len);
return 1; // do not find skip atom,need to
}
else
{
tmp_ret = lseek(file_fd,atom_size-8,SEEK_CUR);
if(-1 == tmp_ret)
{
aloge("file_repair_jump_atom_err,r:%d,t:%d\n",tmp_ret,atom_size-8);
return 0;
}
}
} */
}
}
#define DATA_READ_CHUNK_SIZE (8192L)
//#define TAG_FOR_FRMS_TAG_FLAG 0xcdcdcdcd
//#define FRMS_TAG_FLAG_FIRST 0xabababab
//#define FRMS_TAG_FLAG_NORMAL 0xbabababa
/**
rst: repair, search target flag.
*/
struct search_flag_rst_s
{
unsigned int tag_for_frms_tag_flag_located; //1:find tag_for_frms_tag, 0:not find
unsigned int tag_for_frms_tag_pos_field_valid; //1:valid, 0:invalid, for tag_for_frms_tag_s->last_frms_tag_pos
unsigned int tag_for_frms_tag_last_pos_field;
unsigned int tag_for_frms_tag_located_cnt;
unsigned int first_frms_tag_flag_located;//1:find first frms_tag, 0:not find
unsigned int frms_tag_flag_located; //1:find frms_tag, 0:not find
unsigned int frms_tag_size_field_valid; //1:valid, 0:invalid, for frms_tag_s->frms_tag_size
unsigned int frms_tag_size_field;
unsigned int frms_tag_last_pos_field_valid;//1:valid, 0:invalid, for frms_tag_s->frms_tag_pos
unsigned int frms_tag_last_pos_field;
unsigned int frms_tag_cur_pos_field_valid;//1:valid, 0:invalid, for frms_tag_s->cur_frms_tag_pos
unsigned int frms_tag_cur_pos_field;
unsigned int frms_tag_frm_hdrs_num_field_valid;//1:valid, 0:invalid, for frms_tag_s->frms_num
unsigned int frms_tag_frm_hdrs_num_field;
unsigned int frms_tag_frm_hdrs_field_valid;//1:valid, 0:invalid, for frms_tag_s->frm_hdrs
MOV_FRM_HDR *p_frms_tag_frm_hdrs;
unsigned int frms_tag_located_cnt;
unsigned int cur_buff_off; //buffer offset, point to tag_flag.
};
/**
file repair: search the target entry in buffer from back to front.
target entry flag(i.d. tag_flag) is TAG_FOR_FRMS_TAG_FLAG, FRMS_TAG_FLAG_NORMAL or FRMS_TAG_FLAG_FIRST.
If find one of these flags and make sure tag entry is complete, we can rebuild moov atom.
To reduce difficulty of program, we do some simplifications:
we find tag entry in buffer from back to front. we must find whole tag entry in one buffer, if we discover that one
tag entry is in tail of buffer and not complete, we give up that tag entry, and continue to find to front. Maybe we
will lost the true last tag entry, but it is very low probability, and our code will be very simple.
tag entry is: frms_tag or tag_for_frms_tag.
we will try to find last whole tag entry in buffer, if find, exit immediately.
@return
0: search is well, but may not search enough info, so may need continue to search.
-1: error, can not continue to search. rebuild fail.
*/
static int mp4_file_search_flag(char *p_buff,struct search_flag_rst_s *p_rst)
{
unsigned int chking_flag = 0;
//unsigned int tag_for_frms_tag_located = 0;
//unsigned int tag_for_frms_tag_located_cnt = 0;
//unsigned int tag_for_frms_tag_pos_field = 0;
char *p_buff_start = p_buff;
char *p_buff_end = p_buff + DATA_READ_CHUNK_SIZE;
char *p_buff_reverse = p_buff_end;
//find from p_buff_end to p_buff
while(p_buff_start < p_buff_reverse)
{
p_buff_reverse--;
chking_flag <<= 8;
chking_flag |= *p_buff_reverse;
if(chking_flag == TAG_FOR_FRMS_TAG_FLAG)
{
p_rst->tag_for_frms_tag_flag_located = 1;
//clear valid flags.
p_rst->tag_for_frms_tag_pos_field_valid = 0;
char *tmp_p_buff = p_buff_reverse+4;
if(tmp_p_buff+4 <= p_buff_end) // pos field valid, but still need to check further for frms_tag exist or not
{
p_rst->tag_for_frms_tag_last_pos_field |= *(tmp_p_buff);
p_rst->tag_for_frms_tag_last_pos_field |= *(tmp_p_buff+1)<<8;
p_rst->tag_for_frms_tag_last_pos_field |= *(tmp_p_buff+2)<<16;
p_rst->tag_for_frms_tag_last_pos_field |= *(tmp_p_buff+3)<<24;
p_rst->tag_for_frms_tag_pos_field_valid = 1;
p_rst->tag_for_frms_tag_located_cnt ++;
p_rst->cur_buff_off = p_buff_reverse - p_buff_start;
alogd("mp4_file_repair: last tag_for_frms_tag is found, last_frms_tag_pos:%d, cur buf offset:%d", p_rst->tag_for_frms_tag_last_pos_field, p_rst->cur_buff_off);
break;
}
else // pos field invalid
{
p_rst->tag_for_frms_tag_pos_field_valid = 0;
alogd("mp4_file_repair: tag_for_frms_tag data_not_enough, continue to find previous");
continue;
}
}
else if(chking_flag == FRMS_TAG_FLAG_NORMAL || chking_flag == FRMS_TAG_FLAG_FIRST) // located one frms_tag in current search chunk(no more than one)
{
alogd("mp4_file_repair_located_one_frms_tag");
if(chking_flag == FRMS_TAG_FLAG_NORMAL)
{
p_rst->frms_tag_flag_located = 1;
}
else if(chking_flag == FRMS_TAG_FLAG_FIRST)
{
p_rst->first_frms_tag_flag_located = 1;
}
//clear valid flags.
p_rst->frms_tag_size_field_valid = 0;
p_rst->frms_tag_last_pos_field_valid = 0;
p_rst->frms_tag_cur_pos_field_valid = 0;
p_rst->frms_tag_frm_hdrs_num_field_valid = 0;
p_rst->frms_tag_frm_hdrs_field_valid = 0;
char *tmp_p_buff = p_buff_reverse+4;
if(tmp_p_buff+4 <= p_buff_end) // frms_tag size field valid
{
p_rst->frms_tag_size_field_valid = 1;
p_rst->frms_tag_size_field |= *tmp_p_buff;
p_rst->frms_tag_size_field |= *(tmp_p_buff+1)<<8;
p_rst->frms_tag_size_field |= *(tmp_p_buff+2)<<16;
p_rst->frms_tag_size_field |= *(tmp_p_buff+3)<<24;
}
else
{
p_rst->frms_tag_size_field_valid = 0;
alogd("mp4_file_repair: frms_tag_size data_not_enough, continue to find previous");
continue;
}
tmp_p_buff += 4; // skip size field
if(tmp_p_buff+4 <= p_buff_end) // frms_tag last_pos field valid
{
p_rst->frms_tag_last_pos_field_valid = 1;
p_rst->frms_tag_last_pos_field |= *tmp_p_buff;
p_rst->frms_tag_last_pos_field |= *(tmp_p_buff+1)<<8;
p_rst->frms_tag_last_pos_field |= *(tmp_p_buff+2)<<16;
p_rst->frms_tag_last_pos_field |= *(tmp_p_buff+3)<<24;
}
else
{
p_rst->frms_tag_last_pos_field_valid = 0;
alogd("mp4_file_repair: frms_tag_pos data_not_enough, continue to find previous");
continue;
}
tmp_p_buff += 4; // skip last pos field
if(tmp_p_buff+4 <= p_buff_end) // frms_tag cur_pos field valid
{
p_rst->frms_tag_cur_pos_field_valid = 1;
p_rst->frms_tag_cur_pos_field |= *tmp_p_buff;
p_rst->frms_tag_cur_pos_field |= *(tmp_p_buff+1)<<8;
p_rst->frms_tag_cur_pos_field |= *(tmp_p_buff+2)<<16;
p_rst->frms_tag_cur_pos_field |= *(tmp_p_buff+3)<<24;
}
else
{
p_rst->frms_tag_cur_pos_field_valid = 0;
alogd("mp4_file_repair: frms_tag_cur_pos data_not_enough, continue to find previous");
continue;
}
tmp_p_buff += 4; // skip cur_pos field
if(tmp_p_buff+4 <= p_buff_end) // frms_tag num field valid
{
p_rst->frms_tag_frm_hdrs_num_field_valid = 1;
p_rst->frms_tag_frm_hdrs_num_field |= *tmp_p_buff;
p_rst->frms_tag_frm_hdrs_num_field |= *(tmp_p_buff+1)<<8;
p_rst->frms_tag_frm_hdrs_num_field |= *(tmp_p_buff+2)<<16;
p_rst->frms_tag_frm_hdrs_num_field |= *(tmp_p_buff+3)<<24;
}
else
{
p_rst->frms_tag_frm_hdrs_num_field_valid = 0;
alogd("mp4_file_repair: frms_tag_num data_not_enough, continue to find previous");
continue;
}
tmp_p_buff += 4; // skip frm_hdrs_num field
if(p_rst->frms_tag_frm_hdrs_num_field >= MAX_FRM_HDRS_IN_FRMS_TAG)
{
aloge("fatal error! frm_hdr_num too many[%d>=%d]", p_rst->frms_tag_frm_hdrs_num_field, MAX_FRM_HDRS_IN_FRMS_TAG);
abort();
}
if(tmp_p_buff+p_rst->frms_tag_frm_hdrs_num_field*sizeof(MOV_FRM_HDR) <= p_buff_end)
{
p_rst->frms_tag_frm_hdrs_field_valid = 1;
if(NULL == p_rst->p_frms_tag_frm_hdrs)
{
//must malloc max buffer size, because maybe reuse p_rst->p_frms_tag_frm_hdrs to copy other frms_tag frame headers.
p_rst->p_frms_tag_frm_hdrs = (MOV_FRM_HDR*)malloc(MAX_FRM_HDRS_IN_FRMS_TAG/*p_rst->frms_tag_frm_hdrs_num_field*/ * sizeof(MOV_FRM_HDR));
if(NULL == p_rst->p_frms_tag_frm_hdrs)
{
aloge("mp4_file_repair: frms_tag_frms_hdr_buff malloc_failed:%d", p_rst->frms_tag_frm_hdrs_num_field*sizeof(MOV_FRM_HDR));
return -1; // fatal error, return -1
}
}
memcpy((char *)p_rst->p_frms_tag_frm_hdrs,tmp_p_buff,p_rst->frms_tag_frm_hdrs_num_field*sizeof(MOV_FRM_HDR));
p_rst->cur_buff_off = p_buff_reverse - p_buff_start;
alogd("mp4_file_repair: last frms_tag is found, last_frms_tag_pos:%d, cur_frms_tag_pos:%d cur buf offset:%d",
p_rst->frms_tag_last_pos_field, p_rst->frms_tag_cur_pos_field, p_rst->cur_buff_off);
if(chking_flag == FRMS_TAG_FLAG_NORMAL)
{
p_rst->frms_tag_located_cnt ++;
}
tmp_p_buff += p_rst->frms_tag_frm_hdrs_num_field*sizeof(MOV_FRM_HDR);
break; // located one frms_tag, then stop the matching
}
else
{
p_rst->frms_tag_frm_hdrs_field_valid = 0; // maybe check furthur, to calculate the acutal number of frm_hdr
alogd("mp4_file_repair: frms_tag_frm_hdrs data_not_enough, continue to find previous");
continue;
}
}
}
alogd("search target entry result:%d-%d-%d-%d, %d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d, %d",
p_rst->tag_for_frms_tag_flag_located,
p_rst->tag_for_frms_tag_pos_field_valid,
p_rst->tag_for_frms_tag_last_pos_field,
p_rst->tag_for_frms_tag_located_cnt,
p_rst->first_frms_tag_flag_located,
p_rst->frms_tag_flag_located,
p_rst->frms_tag_size_field_valid,
p_rst->frms_tag_size_field,
p_rst->frms_tag_last_pos_field_valid,
p_rst->frms_tag_last_pos_field,
p_rst->frms_tag_cur_pos_field_valid,
p_rst->frms_tag_cur_pos_field,
p_rst->frms_tag_frm_hdrs_num_field_valid,
p_rst->frms_tag_frm_hdrs_num_field,
p_rst->frms_tag_frm_hdrs_field_valid,
p_rst->frms_tag_located_cnt,
p_rst->cur_buff_off);
return 0;
}
/**
build frms_tag list.
@return
0: success
-1: fail
*/
int mp4_file_repair_frms_tag_parse(MP4_FILE_REPAIR_CONTEXT *context,int file_fd)
{
int result = 0;
long long ret = 0;
long long off = 0;
long long file_len = 0;
char *tmp_buff = NULL;
unsigned int chunk_num = 1;
long long target_seek_offset = 0;
struct search_flag_rst_s search_rst;
unsigned int start_from_tag_for_frms_tag = 0;
INIT_LIST_HEAD(&context->frms_tag_list);
tmp_buff = (char *)malloc(DATA_READ_CHUNK_SIZE);
if(NULL == tmp_buff)
{
aloge("mp4_file_repair_malloc_4k_buffer_failed");
return -1;
}
memset(tmp_buff,0,DATA_READ_CHUNK_SIZE);
off = lseek(file_fd,0,SEEK_END);
if(-1 == off)
{
aloge("mp4_file_repair_seek_to_file_end_failed");
if (NULL != tmp_buff)
{
free(tmp_buff);
tmp_buff = NULL;
}
return -1;
}
file_len = off;
target_seek_offset = DATA_READ_CHUNK_SIZE*chunk_num;
//(1) find last frms_tag or tag_for_frms_tag
for(;;)
{
off = lseek(file_fd,-target_seek_offset,SEEK_END);
if(-1 == off)
{
aloge("mp4_file_repair_seek_failed:%lld",file_len-DATA_READ_CHUNK_SIZE);
if(NULL != tmp_buff)
{
free(tmp_buff);
}
return -1;
}
ret = read(file_fd,tmp_buff,DATA_READ_CHUNK_SIZE);
if(ret != DATA_READ_CHUNK_SIZE)
{
aloge("fatal error! mp4_file_repair_read_data_failed:%lld-%lld",ret,DATA_READ_CHUNK_SIZE);
}
// to search target flag
memset(&search_rst,0,sizeof(struct search_flag_rst_s));
ret = mp4_file_search_flag(tmp_buff,&search_rst);
if(0 == ret)
{
// check if first frms_tag located
alogd("file_repair_search_rst:%d-%d-%d-%u-%u, %u-%lld-%u-%lld",
search_rst.first_frms_tag_flag_located, search_rst.frms_tag_flag_located, search_rst.tag_for_frms_tag_flag_located,
search_rst.tag_for_frms_tag_located_cnt, search_rst.frms_tag_located_cnt,
chunk_num, off, search_rst.cur_buff_off, file_len);
//check if has valid tag entry
if((1==search_rst.frms_tag_flag_located || 1==search_rst.first_frms_tag_flag_located)
&& 1==search_rst.frms_tag_frm_hdrs_field_valid)
{
struct frms_tag_node_s *p_frms_tag_node = (struct frms_tag_node_s *)malloc(sizeof(struct frms_tag_node_s));
if(NULL != p_frms_tag_node)
{
memset(p_frms_tag_node,0,sizeof(struct frms_tag_node_s));
if(search_rst.first_frms_tag_flag_located)
{
p_frms_tag_node->frms_tag_info.frms_tag.frms_tag_flag = FRMS_TAG_FLAG_FIRST;
}
else
{
p_frms_tag_node->frms_tag_info.frms_tag.frms_tag_flag = FRMS_TAG_FLAG_NORMAL;
}
p_frms_tag_node->frms_tag_info.frms_tag.frms_tag_size = search_rst.frms_tag_size_field;
p_frms_tag_node->frms_tag_info.frms_tag.frms_tag_pos = search_rst.frms_tag_last_pos_field;
p_frms_tag_node->frms_tag_info.frms_tag.cur_frms_tag_pos = search_rst.frms_tag_cur_pos_field;
p_frms_tag_node->frms_tag_info.frms_tag.frms_num = search_rst.frms_tag_frm_hdrs_num_field;
if(NULL == p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs)
{
p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs = (MOV_FRM_HDR *)malloc(search_rst.frms_tag_frm_hdrs_num_field*sizeof(MOV_FRM_HDR));
if(NULL == p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs)
{
aloge("mp4_file_repair_malloc_frm_hdrs_failed,%d",search_rst.frms_tag_frm_hdrs_num_field*sizeof(MOV_FRM_HDR));
if(NULL != p_frms_tag_node)
{
free(p_frms_tag_node);
p_frms_tag_node = NULL;
}
if(NULL != search_rst.p_frms_tag_frm_hdrs)
{
free(search_rst.p_frms_tag_frm_hdrs);
search_rst.p_frms_tag_frm_hdrs = NULL;
}
if(NULL != tmp_buff)
{
free(tmp_buff);
tmp_buff = NULL;
}
return -1;
}
}
memcpy((char *)p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs,(char *)search_rst.p_frms_tag_frm_hdrs,
search_rst.frms_tag_frm_hdrs_num_field*sizeof(MOV_FRM_HDR));
if(NULL != search_rst.p_frms_tag_frm_hdrs)
{
free(search_rst.p_frms_tag_frm_hdrs);
search_rst.p_frms_tag_frm_hdrs = NULL;
}
p_frms_tag_node->frms_tag_info.frms_tag_id ++;
list_add(&p_frms_tag_node->list,&context->frms_tag_list);
context->frms_tag_node_num ++;
alogd("mp4_file_repair: frms_tag_break_search_and_chk");
break; // locate one frms_tag, then break out the search and check loop
}
else
{
aloge("fatal error! malloc fail");
if(NULL != search_rst.p_frms_tag_frm_hdrs)
{
free(search_rst.p_frms_tag_frm_hdrs);
search_rst.p_frms_tag_frm_hdrs = NULL;
}
if(NULL != tmp_buff)
{
free(tmp_buff);
tmp_buff = NULL;
}
return -1;
}
}
else if(1==search_rst.tag_for_frms_tag_flag_located && 1==search_rst.tag_for_frms_tag_pos_field_valid)
{
if(search_rst.tag_for_frms_tag_last_pos_field == 0) // check data valid or not
{
if(NULL != tmp_buff)
{
free(tmp_buff);
tmp_buff = NULL;
}
alogw("mp4_file_repair: tag_for_frms_tag frms_tag_pos is 0, maybe it is before first frms_tag");
return -1;
}
else
{
start_from_tag_for_frms_tag = 1;
alogd("mp4_file_repair: tag_for_frms_tag break_search_and_chk2,%u-%u",
search_rst.tag_for_frms_tag_located_cnt, search_rst.tag_for_frms_tag_last_pos_field);
break; // locate one tag_for_frms_tag,then break search and check loop
}
}
else
{
if((1==search_rst.frms_tag_flag_located || 1==search_rst.first_frms_tag_flag_located)
&& 0==search_rst.frms_tag_frm_hdrs_field_valid)
{
alogd("Be careful! Low probability! frms_tag not complete:%d-%d-%d", search_rst.frms_tag_flag_located,
search_rst.first_frms_tag_flag_located, search_rst.frms_tag_frm_hdrs_field_valid);
}
else if(1==search_rst.tag_for_frms_tag_flag_located && 0==search_rst.tag_for_frms_tag_pos_field_valid)
{
alogd("Be careful! Low probability! tag_for_frms_tag not complete:%d-%d", search_rst.tag_for_frms_tag_flag_located,
search_rst.tag_for_frms_tag_pos_field_valid);
}
if(search_rst.p_frms_tag_frm_hdrs)
{
free(search_rst.p_frms_tag_frm_hdrs);
search_rst.p_frms_tag_frm_hdrs = NULL;
}
chunk_num ++;
target_seek_offset = DATA_READ_CHUNK_SIZE*chunk_num;
}
}
else
{
if(NULL != tmp_buff)
{
free(tmp_buff);
tmp_buff = NULL;
}
aloge("mp4_file_repair: no_more_resource_repair_failed");
return -1; // the result of mp4_file_search_flag is fatal error,such as memory malloc failed
}
}
if(NULL != tmp_buff)
{
free(tmp_buff);
tmp_buff = NULL;
}
//(2) build frms_tag list
// check and process the result of location
unsigned int next_frms_tag_pos = 0;
if(1 == start_from_tag_for_frms_tag) // located tag_for_frms_tag
{
next_frms_tag_pos = search_rst.tag_for_frms_tag_last_pos_field;
if(0 == next_frms_tag_pos)
{
aloge("fatal error! mp4_file_repair: should_not_happen here when build frms_tag list!");
}
}
else // locate frms_tag or first frms_tag
{
if(1 != context->frms_tag_node_num)
{
aloge("fatal error! mp4_file_repair_frms_tag_node_num_err,%u",context->frms_tag_node_num);
}
struct frms_tag_node_s *p_tmp_frms_tag_node = list_first_entry(&context->frms_tag_list,FRMS_TAG_NODE,list);
next_frms_tag_pos = p_tmp_frms_tag_node->frms_tag_info.frms_tag.frms_tag_pos;
if(0 == next_frms_tag_pos)
{
if(p_tmp_frms_tag_node->frms_tag_info.frms_tag.frms_tag_flag!=FRMS_TAG_FLAG_FIRST)
{
aloge("fatal error! why frms_tag_flag[0x%x] is not FRMS TAG_FLAG_FIRST, but prvious frms_tag_pos is 0?");
}
alogw("mp4_file_repair: only_one_frms_tag");
return 0;
}
}
for(;;)
{
off = lseek(file_fd,next_frms_tag_pos,SEEK_SET);
if(-1 == off)
{
aloge("fatal error! mp4_file_repair_seek_failed,%u",next_frms_tag_pos);
return -1;
}
struct frms_tag_node_s *p_frms_tag_node = (struct frms_tag_node_s *)malloc(sizeof(struct frms_tag_node_s));
if(NULL != p_frms_tag_node)
{
memset(p_frms_tag_node,0,sizeof(struct frms_tag_node_s));
ret = read(file_fd,&p_frms_tag_node->frms_tag_info.frms_tag,FRMS_TAG_INFO_HDR_SIZE);
if(ret != FRMS_TAG_INFO_HDR_SIZE) // read flag/size/last_pos/cur_po/frm_hdrs_num
{
aloge("fatal error! mp4_file_repair_read,%lld-%u!",ret,FRMS_TAG_INFO_HDR_SIZE);
if(NULL != p_frms_tag_node)
{
free(p_frms_tag_node);
p_frms_tag_node = NULL;
}
result = -1;
break;
}
if(p_frms_tag_node->frms_tag_info.frms_tag.frms_tag_flag != FRMS_TAG_FLAG_FIRST
&& p_frms_tag_node->frms_tag_info.frms_tag.frms_tag_flag != FRMS_TAG_FLAG_NORMAL)
{
aloge("fatal error! mp4_file_repair: frms_tag flag[0x%x] wrong", p_frms_tag_node->frms_tag_info.frms_tag.frms_tag_flag);
result = -1;
break;
}
if(next_frms_tag_pos != p_frms_tag_node->frms_tag_info.frms_tag.cur_frms_tag_pos)
{
aloge("fatal error! mp4_file_repair_locate_error:%u-%u",next_frms_tag_pos,p_frms_tag_node->frms_tag_info.frms_tag.cur_frms_tag_pos);
result = -1;
break;
}
p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs = (MOV_FRM_HDR *)malloc(p_frms_tag_node->frms_tag_info.frms_tag.frms_num*sizeof(MOV_FRM_HDR));
if(NULL == p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs)
{
aloge("fatal error! mp4_file_repair_malloc_frm_hdrs_failed,%d",p_frms_tag_node->frms_tag_info.frms_tag.frms_num*sizeof(MOV_FRM_HDR));
if(NULL != p_frms_tag_node)
{
free(p_frms_tag_node);
p_frms_tag_node = NULL;
}
result = -1;
break;
}
ret = read(file_fd,(char *)p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs,
p_frms_tag_node->frms_tag_info.frms_tag.frms_num*sizeof(MOV_FRM_HDR));
if(ret != p_frms_tag_node->frms_tag_info.frms_tag.frms_num*sizeof(MOV_FRM_HDR))
{
aloge("fatal error! mp4_file_repair_read,%lld-%u!",ret,p_frms_tag_node->frms_tag_info.frms_tag.frms_num*sizeof(MOV_FRM_HDR));
}
p_frms_tag_node->frms_tag_info.frms_tag_id ++;
list_add(&p_frms_tag_node->list,&context->frms_tag_list);
context->frms_tag_node_num ++;
if(p_frms_tag_node->frms_tag_info.frms_tag.frms_tag_flag == FRMS_TAG_FLAG_FIRST)
{
if(p_frms_tag_node->frms_tag_info.frms_tag.frms_tag_pos != 0)
{
aloge("fatal error! first frms_tag pos[%d] is not 0!", p_frms_tag_node->frms_tag_info.frms_tag.frms_tag_pos);
}
alogd("mp4_file_repair: frms_tag_list_build_done,%d",context->frms_tag_node_num);
break; // meet the first frms_tag in file
}
next_frms_tag_pos = p_frms_tag_node->frms_tag_info.frms_tag.frms_tag_pos;
}
else
{
aloge("fatal error! mp4_file_repair: malloc_frms_tag_node_s_failed,%u",sizeof(struct frms_tag_node_s));
result = -1;
break;
}
}
if(result != 0)
{
if(!list_empty(&context->frms_tag_list))
{
FRMS_TAG_NODE *p_frms_tag_node, *pTmp;
list_for_each_entry_safe(p_frms_tag_node, pTmp, &context->frms_tag_list, list)
{
if(NULL != p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs)
{
free(p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs);
p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs = NULL;
}
list_del(&p_frms_tag_node->list);
free(p_frms_tag_node);
context->frms_tag_node_num --;
}
}
}
return result;
}
static int mp4_file_repair_wrt_pkt(MP4_FILE_REPAIR_CONTEXT *p_repair_ctx,MOV_FRM_HDR *pFrmHdr,int fd)
{
MOV_FRM_HDR frm_hdr;
AVPacket av_pkt;
int tmp_ret = 0;
memcpy(&frm_hdr,pFrmHdr,sizeof(MOV_FRM_HDR));
memset(&av_pkt,0,sizeof(AVPacket));
// construct pkt info
av_pkt.stream_index = frm_hdr.frm_strm_index;
av_pkt.flags = frm_hdr.frm_key_flag;
av_pkt.pts = frm_hdr.frm_pts;
av_pkt.duration = frm_hdr.frm_duration;
av_pkt.size0 = frm_hdr.frm_size;
av_pkt.pos = frm_hdr.frm_off;
if(av_pkt.flags&AVPACKET_FLAG_THUMBNAIL)
{
av_pkt.data0 = malloc(av_pkt.size0);
if(NULL != av_pkt.data0)
{
tmp_ret = lseek(fd,frm_hdr.frm_off,SEEK_SET); // seek to thumbnail pic
if(-1 == tmp_ret)
{
aloge("mp4_file_repair_frms_tag_thumb_nail_seek_failed,%u",frm_hdr.frm_off);
}
tmp_ret = read(fd,av_pkt.data0,av_pkt.size0);
if(tmp_ret != av_pkt.size0)
{
aloge("file_repair_read_thm_data_err,s:%d,t:%d\n",
tmp_ret,av_pkt.size0);
}
// send pkt to muxer
tmp_ret = p_repair_ctx->pWriter->MuxerWritePacket(p_repair_ctx->pMuxerCtx, &av_pkt);
if(0 != tmp_ret)
{
aloge("file_repair_pkt_wrt_fail!!\n");
}
free(av_pkt.data0);
}
else
{
aloge("file_repair_thm_buff_malloc_failed,s:%d\n",
av_pkt.size0);
}
}
else
{
// send pkt to muxer
tmp_ret = p_repair_ctx->pWriter->MuxerWritePacket(p_repair_ctx->pMuxerCtx, &av_pkt);
if(0 != tmp_ret)
{
aloge("file_repair_pkt_wrt_fail!!\n");
}
//adjust file read position to next frm header
// lseek(fd,frm_hdr.frm_size,SEEK_CUR);
//use video stream to calculate duration.
if(0 == av_pkt.stream_index)
{
if(0 == p_repair_ctx->mbSetFirstPtsFlag)
{
p_repair_ctx->nFirstPts = av_pkt.pts;
p_repair_ctx->mbSetFirstPtsFlag = 1;
}
p_repair_ctx->nCurrentPts = av_pkt.pts;
}
}
return 0;
}
static int mp4_file_repair_frm_by_frm(MP4_FILE_REPAIR_CONTEXT *context,int file_fd)
{
MOV_FRM_HDR frm_hdr;
MP4_FILE_REPAIR_CONTEXT *p_repair_ctx = context;
MOV_META *p_meta = &p_repair_ctx->file_meta_info;
AVPacket av_pkt;
long long file_len = 0;
int fd = file_fd;
int tmp_ret = 0;
file_len = lseek(fd,0,SEEK_END);
if(-1 == file_len)
{
aloge("file_repair_file_seek_end_failed\n");
if(-1 != fd)
{
close(fd);
fd = -1;
}
return -1;
}
// seek to the position of the first frm header
long long first_frm_hdr_off = META_DATA_POSITION;
first_frm_hdr_off += sizeof(p_meta->v_strm_num);
for(int j=0; j<p_meta->v_strm_num; ++j)
{
first_frm_hdr_off += (sizeof(V_STRM_META_DATA)-4);
if(0 != p_meta->v_strms_meta[j].v_vos_len)
{
first_frm_hdr_off += p_meta->v_strms_meta[j].v_vos_len;
}
}
first_frm_hdr_off += sizeof(p_meta->a_strm_num);
for(int j=0; j<p_meta->a_strm_num; ++j)
{
first_frm_hdr_off += (sizeof(A_STRM_META_DATA)-4);
if(0 != p_meta->a_strms_meta[j].a_vos_len)
{
first_frm_hdr_off += p_meta->a_strms_meta[j].a_vos_len;
}
}
first_frm_hdr_off += sizeof(p_meta->t_strm_num);
if(0 != p_meta->t_strm_num)
{
first_frm_hdr_off += (sizeof(T_STRM_META_DATA)-4);
if(0 != p_meta->t_strms_meta.t_vos_len)
{
first_frm_hdr_off += p_meta->t_strms_meta.t_vos_len;
}
}
tmp_ret = lseek(fd,first_frm_hdr_off,SEEK_SET);
if(tmp_ret != first_frm_hdr_off)
{
aloge("file_repair_seek_err:%d-%d\n",tmp_ret,first_frm_hdr_off);
}
unsigned int last_frm_off = first_frm_hdr_off;
while(1)
{
// read frm header
tmp_ret = mp4_file_frm_hdr_read(p_repair_ctx,fd,&frm_hdr);
if(0 != tmp_ret)
{
aloge("file_repair_frm_hdr_rd_fail,maybe reach file ending!!\n");
break;
}
if(frm_hdr.frm_strm_index < 0 ||
frm_hdr.frm_strm_index >=(p_meta->v_strm_num+p_meta->a_strm_num+p_meta->t_strm_num)
|| frm_hdr.frm_size<0 || frm_hdr.frm_off<0 || frm_hdr.frm_duration<0) // patch again
{
alogw("file_repair_invalid_frm_hdr_to_end_repair:%d-%d-%d",
frm_hdr.frm_strm_index,frm_hdr.frm_size,frm_hdr.frm_off);
break;
}
// to check the validation of frm hdr
if(frm_hdr.frm_off <= last_frm_off) // patch for the case that only part of frm data is written into file
{
alogw("file_repair_may_reach_the_end_of_valid_data:%d-%d",last_frm_off,frm_hdr.frm_off);
break;
}
// check the validation of frm header
if(frm_hdr.frm_off+frm_hdr.frm_size <= file_len)
{
memset(&av_pkt,0,sizeof(AVPacket));
// construct pkt info
av_pkt.stream_index = frm_hdr.frm_strm_index;
av_pkt.flags = frm_hdr.frm_key_flag;
av_pkt.pts = frm_hdr.frm_pts;
av_pkt.duration = frm_hdr.frm_duration;
av_pkt.size0 = frm_hdr.frm_size;
av_pkt.pos = frm_hdr.frm_off;
last_frm_off = frm_hdr.frm_off;
if(av_pkt.flags&AVPACKET_FLAG_THUMBNAIL)
{
av_pkt.data0 = malloc(av_pkt.size0);
if(NULL != av_pkt.data0)
{
tmp_ret = read(fd,av_pkt.data0,av_pkt.size0);
if(tmp_ret != av_pkt.size0)
{
aloge("file_repair_read_thm_data_err,s:%d,t:%d\n",
tmp_ret,av_pkt.size0);
}
// send pkt to muxer
tmp_ret = p_repair_ctx->pWriter->MuxerWritePacket(p_repair_ctx->pMuxerCtx,
&av_pkt);
if(0 != tmp_ret)
{
aloge("file_repair_pkt_wrt_fail!!\n");
}
free(av_pkt.data0);
}
else
{
aloge("file_repair_thm_buff_malloc_failed,s:%d\n",
av_pkt.size0);
}
}
else
{
tmp_ret = lseek(fd,frm_hdr.frm_size,SEEK_CUR);
if(-1 != tmp_ret)
{
tmp_ret = readahead(fd,tmp_ret,sizeof(MOV_FRM_HDR));
if(-1 == tmp_ret)
{
aloge("readahead_failed");
}
}
// send pkt to muxer
tmp_ret = p_repair_ctx->pWriter->MuxerWritePacket(p_repair_ctx->pMuxerCtx,
&av_pkt);
if(0 != tmp_ret)
{
aloge("file_repair_pkt_wrt_fail!!\n");
}
//adjust file read position to next frm header
// lseek(fd,frm_hdr.frm_size,SEEK_CUR);
}
}
else
{
alogd("file_repair_end!!\n");
break;
}
}
tmp_ret = p_repair_ctx->pWriter->MuxerWriteTrailer(p_repair_ctx->pMuxerCtx);
if(0 != tmp_ret)
{
aloge("file_repair_trailer_wrt_fail!!\n");
}
return 0;
}
/**
repair mp4 file.
@param[in] file_path
the incomplete mp4 file path.
@param[out] pMediaInfo
store mp4 media info. The function don't fill all infos of DEMUX_MEDIA_INFO_S, it only set some useful infos which
is needed by app. It can be NULL.
*/
int mp4_file_repair(char const *file_path, DEMUX_MEDIA_INFO_S *pMediaInfo)
{
MP4_FILE_REPAIR_CONTEXT file_repair_ctx;
MP4_FILE_REPAIR_CONTEXT *p_repair_ctx = &file_repair_ctx;
memset(&file_repair_ctx, 0, sizeof(file_repair_ctx));
long long file_len = 0;
int fd = -1;
int tmp_ret = 0;
if(NULL == file_path)
{
aloge("file_repair_file_path_invalid\n");
return -1;
}
int64_t stamp1 = CDX_GetSysTimeUsMonotonic();
alogd("file_repair_file_name:%s\n",file_path);
fd = open(file_path,O_RDWR,0666);
if(-1 == fd)
{
aloge("file_repair_file_open_failed!!\n");
return -1;
}
// to check file is mp4 or not
tmp_ret = mp4_file_format_chk(fd);
if(0 != tmp_ret)
{
aloge("file_repair_file_type_err!\n");
if(-1 != fd)
{
close(fd);
fd = -1;
}
return -1;
}
file_len = lseek(fd,0,SEEK_END);
if(-1 == file_len)
{
aloge("file_repair_file_seek_end_failed\n");
if(-1 != fd)
{
close(fd);
fd = -1;
}
return -1;
}
// check file validation
if(MINIMAL_FILE_SIZE >= file_len)
{
aloge("file_repair_file_too_small,can't be repaired,s:%lld\n",file_len);
if(-1 != fd)
{
close(fd);
fd = -1;
}
return -1;
}
tmp_ret = mp4_file_need_repair_chk(fd,file_len);
if(0 == tmp_ret)
{
aloge("file_repair_cur_file_do_not_need_to_be_repaired!\n");
if(-1 != fd)
{
close(fd);
fd = -1;
}
return 0;
}
memset(p_repair_ctx,0,sizeof(MP4_FILE_REPAIR_CONTEXT));
// read meta info
tmp_ret = mp4_file_meta_data_read(p_repair_ctx,fd);
if(0 != tmp_ret)
{
aloge("file_repair_meta_info_read_failed!!\n");
if(-1 != fd)
{
close(fd);
fd = -1;
}
return -1;
}
// mp4 muxer initilization
tmp_ret = mp4_file_muxer_init(p_repair_ctx,fd);
if(0 != tmp_ret)
{
aloge("file_repair_muxer_init_failed!!\n");
if(-1 != fd)
{
close(fd);
fd = -1;
}
return -1;
}
#ifdef MP4_FILE_REPAIR_FAST_VERSION
tmp_ret = mp4_file_repair_frms_tag_parse(p_repair_ctx,fd);
if(0 == tmp_ret)
{
if(!list_empty(&p_repair_ctx->frms_tag_list))
{
FRMS_TAG_NODE *p_frms_tag_node, *pTmp;
list_for_each_entry_safe(p_frms_tag_node, pTmp, &p_repair_ctx->frms_tag_list, list)
{
// alogd("file_repair_frms_tag_node_info:%u-%u",p_repair_ctx->frms_tag_node_num,p_frms_tag_node->frms_tag_info.frms_tag.frms_num);
for(int i=0; i<p_frms_tag_node->frms_tag_info.frms_tag.frms_num; i++)
{
mp4_file_repair_wrt_pkt(p_repair_ctx,&p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs[i],fd);
}
if(NULL != p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs)
{
free(p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs);
p_frms_tag_node->frms_tag_info.frms_tag.frm_hdrs = NULL;
}
list_del(&p_frms_tag_node->list);
free(p_frms_tag_node);
p_repair_ctx->frms_tag_node_num --;
}
tmp_ret = p_repair_ctx->pWriter->MuxerWriteTrailer(p_repair_ctx->pMuxerCtx);
if(0 != tmp_ret)
{
aloge("file_repair_trailer_wrt_fail!!\n");
}
}
}
#else
mp4_file_repair_frm_by_frm(p_repair_ctx,fd);
#endif
mp4_file_muxer_rls(p_repair_ctx);
//set MediaInfo, only set some members that will be used by app.
if(0==tmp_ret && pMediaInfo)
{
memset(pMediaInfo, 0, sizeof(*pMediaInfo));
pMediaInfo->mFileSize = lseek(fd, 0, SEEK_END);
pMediaInfo->mDuration = (unsigned int)((p_repair_ctx->nCurrentPts-p_repair_ctx->nFirstPts)/1000);
pMediaInfo->mAudioNum = p_repair_ctx->file_meta_info.a_strm_num;
pMediaInfo->mVideoNum = p_repair_ctx->file_meta_info.v_strm_num;
int i = 0;
for(i=0; i<pMediaInfo->mAudioNum; i++)
{
pMediaInfo->mAudioStreamInfo[i].mCodecType = map_AUDIO_ENCODER_TYPE_to_PAYLOAD_TYPE_E((AUDIO_ENCODER_TYPE)p_repair_ctx->file_meta_info.a_strms_meta[i].a_enc_type);
}
for(i=0; i<pMediaInfo->mVideoNum; i++)
{
pMediaInfo->mVideoStreamInfo[i].mCodecType = map_VENC_CODEC_TYPE_to_PAYLOAD_TYPE_E((VENC_CODEC_TYPE)p_repair_ctx->file_meta_info.v_strms_meta[i].v_enc_type);
}
}
mp4_file_vos_buff_rls(p_repair_ctx);
if(-1 != fd)
{
close(fd);
fd = -1;
}
int64_t stamp2 = CDX_GetSysTimeUsMonotonic();
aloge("file_repair_time_consumed:%lld, ret:%d, duration:[%d]ms, size:[%d]bytes",(stamp2-stamp1)/1000, tmp_ret, pMediaInfo->mDuration, pMediaInfo->mFileSize);
return tmp_ret;
}