#include <sys/ioctl.h> //for ioctl
#include <fcntl.h> //for open O_* flags
#include <unistd.h> //for read/write/lseek
#include <stdlib.h> //for malloc/free
#include <string.h> //for strlen/memset
#include <stdio.h> //for printf
#include <time.h>
#include "mp4_builder.h"
#include "am_utils.h"
U32 mVideoDuration;
U32 mAudioDuration;
U32 mVideoCnt;
U32 mAudioCnt;
U32 mStssCnt;
UINT _v_stsz[MAX_FRAME_NUM_FOR_SINGLE_FILE]; //sample size
UINT _v_stco[MAX_FRAME_NUM_FOR_SINGLE_FILE]; //chunk_offset
UINT _a_stsz[MAX_FRAME_NUM_FOR_SINGLE_FILE]; //sample size
UINT _a_stco[MAX_FRAME_NUM_FOR_SINGLE_FILE]; //chunk_offset
UINT _ctts[2*MAX_FRAME_NUM_FOR_SINGLE_FILE]; //composition time
UINT _stts[2*MAX_FRAME_NUM_FOR_SINGLE_FILE]; //decoding time
U32 _stss[MAX_FRAME_NUM_FOR_SINGLE_FILE]; //sync sample
int _last_ctts;
U32 _create_time;
U32 _decimal_pts;
U32 mCurPos;
U32 _v_stts_pos;
U32 _v_ctts_pos;
U32 _v_stsz_pos;
U32 _v_stco_pos;
U32 _v_stss_pos;
U32 _a_stsz_pos;
U32 _a_stco_pos;
U32 _mdat_begin_pos;
U32 _mdat_end_pos;
PTS _last_video_pts;
U16 _audio_spec_config;
AM_VIDEO_INFO mH264Info;
AM_AUDIO_INFO _audio_info;
//CMP4MUX_RECORD_INFO _record_info;
U32 _last_idr_num;
int _last_p_num;
int _last_i_num;
int _last_pic_order_cnt;
U64 _last_idr_pts;
U8* _pps;
U8* _sps;
U32 _pps_size;
U32 _sps_size;
sps_info_t mSpsInfo;
ADTS mAdts[max_adts];
U32 mCurrAdtsIndex;
U32 mFrameCount;
bool Adts_IsSyncWordOk(AdtsHeader *adtsHeader)
{
return (0x0FFF == (0x0000 | (adtsHeader->syncword_12to5 << 4) | adtsHeader->syncword_4to1));
}
uint16_t Adts_FrameLength(AdtsHeader *adtsHeader)
{
return (uint16_t)(0x0000 | (adtsHeader->framelength_13to12 << 11)
| (adtsHeader->framelength_11to4 << 3)
| (adtsHeader->framelength_3to1));
}
uint16_t Adts_BufferFullness(AdtsHeader *adtsHeader)
{
return (uint16_t)(0x0000 | (adtsHeader->buffer_fullness_11to7 << 6)
| (adtsHeader->buffer_fullness_6to1));
}
uint8_t Adts_ProtectionAbsent(AdtsHeader *adtsHeader)
{
return (uint8_t)(0x00 | adtsHeader->protection);
}
uint8_t Adts_AacFrameNumber(AdtsHeader *adtsHeader)
{
return (uint8_t)(0x00 | adtsHeader->number_of_aac_frame);
}
uint8_t Adts_AacAudioObjectType(AdtsHeader *adtsHeader)
{
return (uint8_t)((0x00 | adtsHeader->profile) + 1);
}
uint8_t Adts_AacFrequencyIndex(AdtsHeader *adtsHeader)
{
return (uint8_t)(0x00 | adtsHeader->sample_freqency_index);
}
uint8_t Adts_AacChannelConf(AdtsHeader *adtsHeader)
{
return (uint8_t)(0x00 | ((adtsHeader->channel_conf_3 << 2) | adtsHeader->channel_conf_2to1));
}
void Init()
{
mVideoDuration = 0;
mAudioDuration = 0;
mVideoCnt = 0;
mAudioCnt = 0;
mStssCnt = 0;
_last_ctts = 0;
_create_time = 0;
_decimal_pts = 0;
mCurPos = 0;
_v_stts_pos = 0;
_v_ctts_pos = 0;
_v_stsz_pos = 0;
_v_stco_pos = 0;
_v_stss_pos = 0;
_a_stsz_pos = 0;
_a_stco_pos = 0;
_mdat_begin_pos = 0;
_mdat_end_pos = 0;
_last_video_pts = 0;
_audio_spec_config = 0xffff;
_last_idr_num = 0;
_last_p_num = 0;
_last_i_num = 0;
_last_pic_order_cnt = 0;
_last_idr_pts = 0;
_pps = NULL;
_sps = NULL;
_pps_size = 0;
_sps_size = 0;
mCurrAdtsIndex = 0;
mFrameCount = 0;
memset(&mH264Info, 0, sizeof(mH264Info));
memset(&_audio_info, 0, sizeof(_audio_info));
//memset(&_record_info, 0, sizeof(_record_info));
memset(&mSpsInfo, 0, sizeof(mSpsInfo));
//_record_info.max_filesize = 1<<31; // 2G
//_record_info.max_videocnt = -1;
}
void unInit()
{
free(_pps);
free(_sps);
_pps = NULL;
_sps = NULL;
}
void InitH264(AM_VIDEO_INFO* h264_info)
{
if (h264_info)
{
memcpy(&mH264Info, h264_info, sizeof(AM_VIDEO_INFO));
}
else
{
mH264Info.fps = 0;
mH264Info.width = 1280;
mH264Info.height = 720;
mH264Info.M = 3;
mH264Info.N = 30;
mH264Info.rate = 1001;
mH264Info.scale = 30000;
}
}
void InitAudio(AM_AUDIO_INFO* audio_info)
{
if (audio_info)
{
memcpy(&_audio_info, audio_info, sizeof(AM_AUDIO_INFO));
}
else
{ //default value
_audio_info.sampleRate = 16000;//48000;//8000
_audio_info.chunkSize = 1024;//320
_audio_info.sampleSize = 16;//2
_audio_info.channels = 2;//1
_audio_info.pktPtsIncr = 1800;
}
}
ERR InitProcess()
{
put_FileTypeBox();
put_MediaDataBox();
return ME_OK;
}
ERR FinishProcess()
{
printf("FinishProcess\n");
struct timeval start, end, diff;
gettimeofday(&start, NULL);
_mdat_end_pos = mCurPos;
//mVideoDuration = mVideoDuration*58/100;
put_MovieBox();
/* reset internal varibles, except sps/pps related */
mCurPos = 0;
mVideoDuration = 0;
mAudioDuration = 0;
mVideoCnt = 0;
mAudioCnt = 0;
mStssCnt = 0;
_last_ctts = 0;
_decimal_pts = 0;
_v_stts_pos = 0;
_v_ctts_pos = 0;
_v_stsz_pos = 0;
_v_stco_pos = 0;
_v_stss_pos = 0;
_a_stsz_pos = 0;
_a_stco_pos = 0;
_mdat_begin_pos = 0;
_mdat_end_pos = 0;
_last_video_pts = 0;
_last_idr_num = 0;
_last_p_num = 0;
_last_i_num = 0;
_last_pic_order_cnt = 0;
_last_idr_pts = 0;
gettimeofday(&end, NULL);
timersub(&end, &start, &diff);
return ME_OK;
}
ERR get_time(UINT* time_since1904, char * time_str, int len)
{
time_t t;
struct tm * utc;
t= time(NULL);
utc = localtime(&t);
if (strftime(time_str, len, "%Y%m%d%H%M%S",utc) == 0)
{
return ME_ERROR;
}
t = mktime(utc);//seconds since 1970-01-01 00:00:00 UTC
//1904-01-01 00:00:00 UTC -> 1970-01-01 00:00:00 UTC
//66 years plus 17 days of the 17 leap years [1904, 1908, ..., 1968]
*time_since1904 = t+66*365*24*60*60+17*24*60*60;
return ME_OK;
}
//--------------------------------------------------
//big-endian format
inline ERR put_byte(UINT data)
{
U8 w[1];
w[0] = data; //(data&0xFF);
return put_buffer(w, 1);
}
inline ERR put_be16(UINT data)
{
U8 w[2];
w[1] = data; //(data&0x00FF);
w[0] = data>>8; //(data&0xFF00)>>8;
return put_buffer(w, 2);
}
inline ERR put_be24(UINT data)
{
U8 w[3];
w[2] = data; //(data&0x0000FF);
w[1] = data>>8; //(data&0x00FF00)>>8;
w[0] = data>>16; //(data&0xFF0000)>>16;
return put_buffer(w, 3);
}
inline ERR put_be32(UINT data)
{
UINT dataBe = LeToBe32(data);
return put_buffer((U8*)&dataBe, sizeof(data));
}
inline ERR put_buffer(U8 *pdata,UINT size)
{
mCurPos += size;
// return mpMuxedFile->WriteData(pdata, size);
if (pdata == NULL || size <= 0)
{
return ME_BAD_PARAM;
}
return Mp4_WriteFile(pdata, size);
}
ERR put_boxtype(const char* pdata)
{
mCurPos += 4;
// return mpMuxedFile->WriteData((U8 *)pdata, 4);
return Mp4_WriteFile((U8 *)pdata, 4);
}
// get the type and length of a nal unit
UINT GetOneNalUnit(U8 *pNaluType,U8 *pBuffer,UINT size)
{
UINT code, tmp, pos=0;
for (code=0xffffffff, pos = 0; pos <4; pos++)
{
tmp = pBuffer[pos];
code = (code<<8)|tmp;
}
// AM_ASSERT(code == 0x00000001); // check start code 0x00000001 (BE)
*pNaluType = pBuffer[pos++] & 0x1F;
for (code=0xffffffff; pos < size; pos++)
{
tmp = pBuffer[pos];
if ((code=(code<<8)|tmp) == 0x00000001)
{
break; //next start code is found
}
}
if (pos == size )
{
// next start code is not found, this must be the last nalu
return size;
}
else
{
return pos-4+1;
}
}
UINT read_bit(U8* pBuffer, int* value,U8* bit_pos, UINT num)
{
*value = 0;
UINT i=0;
UINT j =0 ;
for (j =0 ; j<num; j++)
{
if (*bit_pos == 8)
{
*bit_pos = 0;
i++;
}
if (*bit_pos == 0)
{
if ((pBuffer[i] == 0x3) &&(*(pBuffer+i-1) == 0) &&(*(pBuffer+i-2) == 0))
{
i++;
}
}
*value <<= 1;
*value += pBuffer[i] >> (7 -(*bit_pos)++) & 0x1;
}
return i;
}
//UINT parse_exp_codes(U8* pBuffer, int* value,U8* bit_pos=0, U8 type=0)
UINT par