bool MP4Encoder::Write264Metadata(MP4FileHandle hMp4File,LPMP4ENC_Metadata lpMetadata) { m_videoId = MP4AddH264VideoTrack (hMp4File, m_nTimeScale, m_nTimeScale / m_nFrameRate, m_nWidth, // width m_nHeight,// height lpMetadata->Sps[1], // sps[1] AVCProfileIndication lpMetadata->Sps[2], // sps[2] profile_compat lpMetadata->Sps[3], // sps[3] AVCLevelIndication 3); // 4 bytes length before each NAL unit if (m_videoId == MP4_INVALID_TRACK_ID) { printf("add video track failed.\n"); return false; } MP4SetVideoProfileLevel(hMp4File, 0x01); // Simple Profile @ Level 3 // write sps MP4AddH264SequenceParameterSet(hMp4File,m_videoId,lpMetadata->Sps,lpMetadata->nSpsLen); // write pps MP4AddH264PictureParameterSet(hMp4File,m_videoId,lpMetadata->Pps,lpMetadata->nPpsLen); return true; }
static void init_video_track(MP4FileHandle mp4, MP4TrackId *video, switch_frame_t *frame) { int width = 0; int height = 0; uint8_t *sps_buffer = frame->data; uint32_t sps_bytes = frame->datalen; sps_buffer++; if (frame->img) { width = frame->img->d_w; height = frame->img->d_h; } else { parse_sps_video_size(sps_buffer, sps_bytes, &width, &height); } MP4SetTimeScale(mp4, TIMESCALE); *video = MP4AddH264VideoTrack(mp4, TIMESCALE, MP4_INVALID_DURATION, width, height, *(sps_buffer), *(sps_buffer+1), *(sps_buffer+2), SampleLenFieldSize - 1); if (*video == MP4_INVALID_TRACK_ID) { return; } MP4AddH264SequenceParameterSet(mp4, *video, --sps_buffer, sps_bytes); /* MP4SetVideoProfileLevel sets the minumum profile/level of MPEG-4 video support necessary to render the contents of the file. ISO/IEC 14496-1:2001 MPEG-4 Systems defines the following values: 0x00 Reserved 0x01 Simple Profile @ Level 3 0x02 Simple Profile @ Level 2 0x03 Simple Profile @ Level 1 0x04 Simple Scalable Profile @ Level 2 0x05 Simple Scalable Profile @ Level 1 0x06 Core Profile @ Level 2 0x07 Core Profile @ Level 1 0x08 Main Profile @ Level 4 0x09 Main Profile @ Level 3 0x0A Main Profile @ Level 2 0x0B N-Bit Profile @ Level 2 0x0C Hybrid Profile @ Level 2 0x0D Hybrid Profile @ Level 1 0x0E Basic Animated Texture @ Level 2 0x0F Basic Animated Texture @ Level 1 0x10 Scalable Texture @ Level 3 0x11 Scalable Texture @ Level 2 0x12 Scalable Texture @ Level 1 0x13 Simple Face Animation @ Level 2 0x14 Simple Face Animation @ Level 1 0x15-0x7F Reserved 0x80-0xFD User private 0xFE No audio profile specified 0xFF No audio required */ MP4SetVideoProfileLevel(mp4, 0x7F); }
int Mp4Encoder::WriteH264Data(u_char * pData, int size) { int type = pData[4] & 0x1f; if (type == 0x07) { // sps // 添加h264 track if (m_videoId == MP4_INVALID_TRACK_ID) { m_videoId = MP4AddH264VideoTrack(m_hMp4File, m_nVTimeScale, m_nVTimeScale / m_nFrameRate, m_nWidth, // width m_nHeight, // height pData[5], // sps[1] AVCProfileIndication pData[6], // sps[2] profile_compat pData[7], // sps[3] AVCLevelIndication 3); // 4 bytes length before each NAL unit if (m_videoId == MP4_INVALID_TRACK_ID) { printf("add video track failed.\n"); return 0; } MP4SetVideoProfileLevel(m_hMp4File, 0x7F); // Simple Profile @ Level } MP4AddH264SequenceParameterSet(m_hMp4File, m_videoId, pData + 4, size - 4); } else if (type == 0x08) { // pps MP4AddH264PictureParameterSet(m_hMp4File, m_videoId, pData + 4, size - 4); } else { // MP4 Nalu前四个字节表示Nalu长度(no 00 00 00 01) pData[0] = (size - 4) >> 24; pData[1] = (size - 4) >> 16; pData[2] = (size - 4) >> 8; pData[3] = (size - 4) & 0xff; if (!MP4WriteSample (m_hMp4File, m_videoId, pData, size, MP4_INVALID_DURATION, 0, 1)) { return 0; } } return 0; }
MP4TrackId Mp4vCreator(MP4FileHandle mp4File, FILE* inFile, bool doEncrypt, bool allowVariableFrameRate) { bool rc; u_int8_t sampleBuffer[256 * 1024 * 2]; u_int8_t* pCurrentSample = sampleBuffer; u_int32_t maxSampleSize = sizeof(sampleBuffer) / 2; u_int32_t prevSampleSize = 0; // the current syntactical object // typically 1:1 with a sample // but not always, i.e. non-VOP's u_int8_t* pObj = pCurrentSample; u_int32_t objSize; u_int8_t objType; // the current sample MP4SampleId sampleId = 1; MP4Timestamp currentSampleTime = 0; // the last reference VOP MP4SampleId refVopId = 1; MP4Timestamp refVopTime = 0; // track configuration info u_int8_t videoProfileLevel = MPEG4_SP_L3; u_int8_t timeBits = 15; u_int16_t timeTicks = 30000; u_int16_t frameDuration = 3000; u_int16_t frameWidth = 320; u_int16_t frameHeight = 240; u_int32_t esConfigSize = 0; int vopType = 0; int prevVopType = 0; bool foundVOSH = false, foundVO = false, foundVOL = false; u_int32_t lastVopTimeIncrement = 0; bool variableFrameRate = false; bool lastFrame = false; bool haveBframes = false; mpeg4_frame_t *head = NULL, *tail = NULL; // start reading objects until we get the first VOP while (LoadNextObject(inFile, pObj, &objSize, &objType)) { // guard against buffer overflow if (pObj + objSize >= pCurrentSample + maxSampleSize) { fprintf(stderr, "%s: buffer overflow, invalid video stream?\n", ProgName); return MP4_INVALID_TRACK_ID; } #ifdef DEBUG_MP4V if (Verbosity & MP4_DETAILS_SAMPLE) { printf("MP4V type %x size %u\n", objType, objSize); } #endif if (objType == MP4AV_MPEG4_VOSH_START) { MP4AV_Mpeg4ParseVosh(pObj, objSize, &videoProfileLevel); foundVOSH = true; } else if (objType == MP4AV_MPEG4_VO_START) { foundVO = true; } else if (objType == MP4AV_MPEG4_VOL_START) { MP4AV_Mpeg4ParseVol(pObj, objSize, &timeBits, &timeTicks, &frameDuration, &frameWidth, &frameHeight); foundVOL = true; #ifdef DEBUG_MP4V printf("ParseVol: timeBits %u timeTicks %u frameDuration %u\n", timeBits, timeTicks, frameDuration); #endif } else if (foundVOL == true || objType == MP4AV_MPEG4_VOP_START) { esConfigSize = pObj - pCurrentSample; // ready to set up mp4 track break; } /* XXX why do we need this if ? * It looks like it will remove this object ... XXX */ // It does. On Purpose. wmay 6/2004 if (objType != MP4AV_MPEG4_USER_DATA_START) { pObj += objSize; } } if (foundVOSH == false) { fprintf(stderr, "%s: no VOSH header found in MPEG-4 video.\n" "This can cause problems with players other than mp4player. \n", ProgName); } else { if (VideoProfileLevelSpecified && videoProfileLevel != VideoProfileLevel) { fprintf(stderr, "%s: You have specified a different video profile level than was detected in the VOSH header\n" "The level you specified was %d and %d was read from the VOSH\n", ProgName, VideoProfileLevel, videoProfileLevel); } } if (foundVO == false) { fprintf(stderr, "%s: No VO header found in mpeg-4 video.\n" "This can cause problems with players other than mp4player\n", ProgName); } if (foundVOL == false) { fprintf(stderr, "%s: fatal: No VOL header found in mpeg-4 video stream\n", ProgName); return MP4_INVALID_TRACK_ID; } // convert frame duration to canonical time scale // note zero value for frame duration signals variable rate video if (timeTicks == 0) { timeTicks = 1; } u_int32_t mp4FrameDuration = 0; if (VideoFrameRate) { mp4FrameDuration = (u_int32_t)(((double)Mp4TimeScale) / VideoFrameRate); } else if (frameDuration) { VideoFrameRate = frameDuration; VideoFrameRate /= timeTicks; mp4FrameDuration = (Mp4TimeScale * frameDuration) / timeTicks; } else { if (allowVariableFrameRate == false ) { fprintf(stderr, "%s: variable rate video stream signalled," " please specify average frame rate with -r option\n" " or --variable-frame-rate argument\n", ProgName); return MP4_INVALID_TRACK_ID; } variableFrameRate = true; } ismacryp_session_id_t ismaCrypSId; mp4v2_ismacrypParams *icPp = (mp4v2_ismacrypParams *) malloc(sizeof(mp4v2_ismacrypParams)); memset(icPp, 0, sizeof(mp4v2_ismacrypParams)); // initialize ismacryp session if encrypting if (doEncrypt) { if (ismacrypInitSession(&ismaCrypSId,KeyTypeVideo) != 0) { fprintf(stderr, "%s: could not initialize the ISMAcryp session\n", ProgName); return MP4_INVALID_TRACK_ID; } if (ismacrypGetScheme(ismaCrypSId, &(icPp->scheme_type)) != ismacryp_rc_ok) { fprintf(stderr, "%s: could not get ismacryp scheme type. sid %d\n", ProgName, ismaCrypSId); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } if (ismacrypGetSchemeVersion(ismaCrypSId, &(icPp->scheme_version)) != ismacryp_rc_ok) { fprintf(stderr, "%s: could not get ismacryp scheme ver. sid %d\n", ProgName, ismaCrypSId); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } if (ismacrypGetKMSUri(ismaCrypSId, &(icPp->kms_uri)) != ismacryp_rc_ok) { fprintf(stderr, "%s: could not get ismacryp kms uri. sid %d\n", ProgName, ismaCrypSId); CHECK_AND_FREE(icPp->kms_uri); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } if ( ismacrypGetSelectiveEncryption(ismaCrypSId, &(icPp->selective_enc)) != ismacryp_rc_ok ) { fprintf(stderr, "%s: could not get ismacryp selec enc. sid %d\n", ProgName, ismaCrypSId); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } if (ismacrypGetKeyIndicatorLength(ismaCrypSId, &(icPp->key_ind_len)) != ismacryp_rc_ok) { fprintf(stderr, "%s: could not get ismacryp key ind len. sid %d\n", ProgName, ismaCrypSId); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } if (ismacrypGetIVLength(ismaCrypSId, &(icPp->iv_len)) != ismacryp_rc_ok) { fprintf(stderr, "%s: could not get ismacryp iv len. sid %d\n", ProgName, ismaCrypSId); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } } // create the new video track MP4TrackId trackId; if (doEncrypt) { trackId = MP4AddEncVideoTrack( mp4File, Mp4TimeScale, mp4FrameDuration, frameWidth, frameHeight, icPp, MP4_MPEG4_VIDEO_TYPE); } else { trackId = MP4AddVideoTrack( mp4File, Mp4TimeScale, mp4FrameDuration, frameWidth, frameHeight, MP4_MPEG4_VIDEO_TYPE); } if (trackId == MP4_INVALID_TRACK_ID) { fprintf(stderr, "%s: can't create video track\n", ProgName); return MP4_INVALID_TRACK_ID; } if (VideoProfileLevelSpecified) { videoProfileLevel = VideoProfileLevel; } if (MP4GetNumberOfTracks(mp4File, MP4_VIDEO_TRACK_TYPE) == 1) { MP4SetVideoProfileLevel(mp4File, videoProfileLevel); } printf("es config size is %d\n", esConfigSize); if (esConfigSize) { MP4SetTrackESConfiguration(mp4File, trackId, pCurrentSample, esConfigSize); // move past ES config, so it doesn't go into first sample pCurrentSample += esConfigSize; } // Move the current frame to the beginning of the // buffer memmove(sampleBuffer, pCurrentSample, pObj - pCurrentSample + objSize); pObj = sampleBuffer + (pObj - pCurrentSample); pCurrentSample = sampleBuffer; MP4Timestamp prevFrameTimestamp = 0; // now process the rest of the video stream while ( true ) { if ( objType != MP4AV_MPEG4_VOP_START ) { // keep it in the buffer until a VOP comes along // Actually, do nothings, since we only want VOP // headers in the stream - wmay 6/2004 //pObj += objSize; } else { // we have VOP u_int32_t sampleSize = (pObj + objSize) - pCurrentSample; vopType = MP4AV_Mpeg4GetVopType(pObj, objSize); mpeg4_frame_t *fr = MALLOC_STRUCTURE(mpeg4_frame_t); if (head == NULL) { head = tail = fr; } else { tail->next = fr; tail = fr; } fr->vopType = vopType; fr->frameTimestamp = currentSampleTime; fr->next = NULL; if ( variableFrameRate ) { // variable frame rate: recalculate "mp4FrameDuration" if ( lastFrame ) { // last frame mp4FrameDuration = Mp4TimeScale / timeTicks; } else { // not the last frame u_int32_t vopTimeIncrement; MP4AV_Mpeg4ParseVop(pObj, objSize, &vopType, timeBits, timeTicks, &vopTimeIncrement); u_int32_t vopTime = vopTimeIncrement - lastVopTimeIncrement; mp4FrameDuration = (Mp4TimeScale * vopTime) / timeTicks; lastVopTimeIncrement = vopTimeIncrement % timeTicks; } } if ( prevSampleSize > 0 ) { // not the first time // fill sample data & length to write u_int8_t* sampleData2Write = NULL; u_int32_t sampleLen2Write = 0; if ( doEncrypt ) { if ( ismacrypEncryptSampleAddHeader(ismaCrypSId, sampleSize, sampleBuffer, &sampleLen2Write, &sampleData2Write) != 0 ) { fprintf(stderr, "%s: can't encrypt video sample and add header %u\n", ProgName, sampleId); } } else { sampleData2Write = sampleBuffer; sampleLen2Write = prevSampleSize; } if (variableFrameRate == false) { double now_calc; now_calc = sampleId; now_calc *= Mp4TimeScale; now_calc /= VideoFrameRate; MP4Timestamp now_ts = (MP4Timestamp)now_calc; mp4FrameDuration = now_ts - prevFrameTimestamp; prevFrameTimestamp = now_ts; currentSampleTime = now_ts; } // Write the previous sample rc = MP4WriteSample(mp4File, trackId, sampleData2Write, sampleLen2Write, mp4FrameDuration, 0, prevVopType == VOP_TYPE_I); if ( doEncrypt && sampleData2Write ) { // buffer allocated by encrypt function. // must free it! free(sampleData2Write); } if ( !rc ) { fprintf(stderr, "%s: can't write video frame %u\n", ProgName, sampleId); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; } // deal with rendering time offsets // that can occur when B frames are being used // which is the case for all profiles except Simple Profile haveBframes |= (prevVopType == VOP_TYPE_B); if ( lastFrame ) { // finish read frames break; } sampleId++; } // not the first time currentSampleTime += mp4FrameDuration; // Move the current frame to the beginning of the // buffer memmove(sampleBuffer, pCurrentSample, sampleSize); prevSampleSize = sampleSize; prevVopType = vopType; // reset pointers pObj = pCurrentSample = sampleBuffer + sampleSize; } // we have VOP // load next object from bitstream if (!LoadNextObject(inFile, pObj, &objSize, &objType)) { if (objType != MP4AV_MPEG4_VOP_START) break; lastFrame = true; objSize = 0; continue; } // guard against buffer overflow if (pObj + objSize >= pCurrentSample + maxSampleSize) { fprintf(stderr, "%s: buffer overflow, invalid video stream?\n", ProgName); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; } #ifdef DEBUG_MP4V if (Verbosity & MP4_DETAILS_SAMPLE) { printf("MP4V type %x size %u\n", objType, objSize); } #endif } bool doRenderingOffset = false; switch (videoProfileLevel) { case MPEG4_SP_L0: case MPEG4_SP_L1: case MPEG4_SP_L2: case MPEG4_SP_L3: break; default: doRenderingOffset = true; break; } if (doRenderingOffset && haveBframes) { // only generate ctts (with rendering offset for I, P frames) when // we need one. We saved all the frames types and timestamps above - // we can't use MP4ReadSample, because the end frames might not have // been written refVopId = 1; refVopTime = 0; MP4SampleId maxSamples = MP4GetTrackNumberOfSamples(mp4File, trackId); // start with sample 2 - we know the first one is a I frame mpeg4_frame_t *fr = head->next; // skip the first one for (MP4SampleId ix = 2; ix <= maxSamples; ix++) { if (fr->vopType != VOP_TYPE_B) { #ifdef DEBUG_MP4V_TS printf("sample %u %u renderingOffset "U64"\n", refVopId, fr->vopType, fr->frameTimestamp - refVopTime); #endif MP4SetSampleRenderingOffset(mp4File, trackId, refVopId, fr->frameTimestamp - refVopTime); refVopId = ix; refVopTime = fr->frameTimestamp; } fr = fr->next; } #ifdef DEBUG_MP4V_TS printf("sample %u %u renderingOffset "U64"\n", refVopId, fr->vopType, fr->frameTimestamp - refVopTime); #endif MP4SetSampleRenderingOffset(mp4File, trackId, refVopId, fr->frameTimestamp - refVopTime); } while (head != NULL) { tail = head->next; free(head); head = tail; } // terminate session if encrypting if (doEncrypt) { if (ismacrypEndSession(ismaCrypSId) != 0) { fprintf(stderr, "%s: could not end the ISMAcryp session\n", ProgName); } } return trackId; }
int MP4Encoder::WriteH264Data(MP4FileHandle hMp4File,const unsigned char* pData,int size) { if(hMp4File == NULL) { return -1; } if(pData == NULL) { return -1; } MP4ENC_NaluUnit nalu; int pos = 0, len = 0; while (len = ReadOneNaluFromBuf(pData,size,pos,nalu)) { if(nalu.type == 0x07) // sps { // 添加h264 track m_videoId = MP4AddH264VideoTrack (hMp4File, m_nTimeScale, m_nTimeScale / m_nFrameRate, m_nWidth, // width m_nHeight, // height nalu.data[1], // sps[1] AVCProfileIndication nalu.data[2], // sps[2] profile_compat nalu.data[3], // sps[3] AVCLevelIndication 3); // 4 bytes length before each NAL unit if (m_videoId == MP4_INVALID_TRACK_ID) { printf("add video track failed.\n"); return 0; } MP4SetVideoProfileLevel(hMp4File, 1); // Simple Profile @ Level 3 MP4AddH264SequenceParameterSet(hMp4File,m_videoId,nalu.data,nalu.size); } else if(nalu.type == 0x08) // pps { MP4AddH264PictureParameterSet(hMp4File,m_videoId,nalu.data,nalu.size); } else { int datalen = nalu.size+4; unsigned char *data = new unsigned char[datalen]; // MP4 Nalu前四个字节表示Nalu长度 data[0] = nalu.size>>24; data[1] = nalu.size>>16; data[2] = nalu.size>>8; data[3] = nalu.size&0xff; memcpy(data+4,nalu.data,nalu.size); if(!MP4WriteSample(hMp4File, m_videoId, data, datalen,MP4_INVALID_DURATION, 0, 1)) { return 0; } delete[] data; } pos += len; } return pos; }
static MP4TrackId VideoCreate (MP4FileHandle mp4file, mpeg2ps_t *file, int vstream, bool doEncrypt) { double frame_rate = mpeg2ps_get_video_stream_framerate(file, vstream); uint8_t video_type; uint16_t w, h; MP4TrackId id; ismacryp_session_id_t ismaCrypSId; mp4v2_ismacrypParams *icPp = (mp4v2_ismacrypParams *) malloc(sizeof(mp4v2_ismacrypParams)); memset(icPp, 0, sizeof(mp4v2_ismacrypParams)); #ifdef _WIN32 MP4Duration mp4FrameDuration; mp4FrameDuration = (MP4Duration)((double)Mp4TimeScale / frame_rate); #else MP4Duration mp4FrameDuration = (MP4Duration)(Mp4TimeScale / frame_rate); #endif h = mpeg2ps_get_video_stream_height(file, vstream); w = mpeg2ps_get_video_stream_width(file, vstream); video_type = mpeg2ps_get_video_stream_type(file, vstream) == MPEG_VIDEO_MPEG2 ? MP4_MPEG2_MAIN_VIDEO_TYPE : MP4_MPEG1_VIDEO_TYPE; if (doEncrypt) { // initialize session if (ismacrypInitSession(&ismaCrypSId,KeyTypeVideo) != 0) { fprintf(stderr, "%s: could not initialize the ISMAcryp session\n", ProgName); return MP4_INVALID_TRACK_ID; } if (ismacrypGetScheme(ismaCrypSId, &(icPp->scheme_type)) != ismacryp_rc_ok) { fprintf(stderr, "%s: could not get ismacryp scheme type. sid %d\n", ProgName, ismaCrypSId); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } if (ismacrypGetSchemeVersion(ismaCrypSId, &(icPp->scheme_version)) != ismacryp_rc_ok) { fprintf(stderr, "%s: could not get ismacryp scheme ver. sid %d\n", ProgName, ismaCrypSId); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } if (ismacrypGetKMSUri(ismaCrypSId, &(icPp->kms_uri)) != ismacryp_rc_ok) { fprintf(stderr, "%s: could not get ismacryp kms uri. sid %d\n", ProgName, ismaCrypSId); if (icPp->kms_uri != NULL) free(icPp->kms_uri); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } if ( ismacrypGetSelectiveEncryption(ismaCrypSId, &(icPp->selective_enc)) != ismacryp_rc_ok ) { fprintf(stderr, "%s: could not get ismacryp selec enc. sid %d\n", ProgName, ismaCrypSId); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } if (ismacrypGetKeyIndicatorLength(ismaCrypSId, &(icPp->key_ind_len)) != ismacryp_rc_ok) { fprintf(stderr, "%s: could not get ismacryp key ind len. sid %d\n", ProgName, ismaCrypSId); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } if (ismacrypGetIVLength(ismaCrypSId, &(icPp->iv_len)) != ismacryp_rc_ok) { fprintf(stderr, "%s: could not get ismacryp iv len. sid %d\n", ProgName, ismaCrypSId); ismacrypEndSession(ismaCrypSId); return MP4_INVALID_TRACK_ID; } id = MP4AddEncVideoTrack(mp4file, Mp4TimeScale, mp4FrameDuration, w, h, icPp, video_type); } else { id = MP4AddVideoTrack(mp4file, Mp4TimeScale, mp4FrameDuration, w, h, video_type); } //printf("duration "U64" w %d h %d type %x\n", mp4FrameDuration, w, h, video_type); if (MP4GetNumberOfTracks(mp4file, MP4_VIDEO_TRACK_TYPE) == 1) { MP4SetVideoProfileLevel(mp4file, 0xfe); // undefined profile } if (id == MP4_INVALID_TRACK_ID) { fprintf(stderr, "%s:Couldn't add video track %d", ProgName, vstream); return MP4_INVALID_TRACK_ID; } uint8_t *buf; uint32_t blen; uint32_t frames = 1; #if 0 printf("Processing %lu video frames\n", frames_max); #endif uint32_t refFrame = 1; uint8_t frame_type; while (mpeg2ps_get_video_frame(file, vstream, &buf, &blen, &frame_type, TS_90000, NULL)) { if (buf[blen - 4] == 0 && buf[blen - 3] == 0 && buf[blen - 2] == 1) blen -= 4; // encrypt the sample if neeed if (doEncrypt) { u_int8_t* encSampleData = NULL; u_int32_t encSampleLen = 0; if (ismacrypEncryptSampleAddHeader(ismaCrypSId, blen, buf, &encSampleLen, &encSampleData) != 0) { fprintf(stderr, "%s: can't encrypt video sample and add header %u\n", ProgName, id); } MP4WriteSample(mp4file, id, encSampleData, encSampleLen, mp4FrameDuration, 0, frame_type == 1 ? true : false); if (encSampleData != NULL) { free(encSampleData); } } else { MP4WriteSample(mp4file, id, buf, blen, mp4FrameDuration, 0, frame_type == 1 ? true : false); #if 0 printf("frame %d len %d duration "U64" ftype %d\n", frames, blen, mp4FrameDuration, frame_type); #endif } if (frame_type != 3) { // I or P frame MP4SetSampleRenderingOffset(mp4file, id, refFrame, (frames - refFrame) * mp4FrameDuration); refFrame = frames; } frames++; #if 0 if ((frames % 100) == 0) printf("%d frames\n", frames); #endif } // if encrypting, terminate the ismacryp session if (doEncrypt) { if (ismacrypEndSession(ismaCrypSId) != 0) { fprintf(stderr, "%s: could not end the ISMAcryp session\n", ProgName); return MP4_INVALID_TRACK_ID; } } return id; }