void AppendFLVPacket(const BYTE *lpData, UINT size, BYTE type, DWORD timestamp) { if (!bSentSEI && type == 9 && lpData[0] == 0x17 && lpData[1] == 0x1) { //send SEI with first keyframe packet UINT networkDataSize = fastHtonl(size+sei.size); UINT networkTimestamp = fastHtonl(timestamp); UINT streamID = 0; fileOut.OutputByte(type); fileOut.Serialize(((LPBYTE)(&networkDataSize))+1, 3); fileOut.Serialize(((LPBYTE)(&networkTimestamp))+1, 3); fileOut.Serialize(&networkTimestamp, 1); fileOut.Serialize(&streamID, 3); fileOut.Serialize(lpData, 5); fileOut.Serialize(sei.lpPacket, sei.size); fileOut.Serialize(lpData+5, size-5); fileOut.OutputDword(fastHtonl(size+sei.size+11)); bSentSEI = true; } else { UINT networkDataSize = fastHtonl(size); UINT networkTimestamp = fastHtonl(timestamp); UINT streamID = 0; fileOut.OutputByte(type); fileOut.Serialize(((LPBYTE)(&networkDataSize))+1, 3); fileOut.Serialize(((LPBYTE)(&networkTimestamp))+1, 3); fileOut.Serialize(&networkTimestamp, 1); fileOut.Serialize(&streamID, 3); fileOut.Serialize(lpData, size); fileOut.OutputDword(fastHtonl(size+11)); } lastTimeStamp = timestamp; }
void Mesh::SaveMeshFile() { traceIn(Mesh::SaveMeshFile); String path; Engine::ConvertResourceName(strName, TEXT("models"), path, FALSE); XFileOutputSerializer modelFile; if(!modelFile.Open(path, XFILE_CREATEALWAYS)) { AppWarning(TEXT("Could not create model file '%s'"), path); return; } VBData *vbd = VertBuffer->GetData(); DWORD temp = MODELFILE_VER; modelFile << temp; Vect::SerializeList(modelFile, vbd->VertList); Vect::SerializeList(modelFile, vbd->NormalList); modelFile << vbd->TVList[0]; if(vbd->TVList.Num() < 2) { temp = 0; modelFile << temp; } else modelFile << vbd->TVList[1]; Vect::SerializeList(modelFile, vbd->TangentList); modelFile << nFaces; modelFile.Serialize(FaceList, nFaces*sizeof(Face)); modelFile << nEdges; if(nEdges) modelFile.Serialize(EdgeList, nEdges*sizeof(Edge)); modelFile << DefaultMaterialList; modelFile << nSections; modelFile.Serialize(SectionList, nSections*sizeof(DrawSection)); modelFile << bounds; modelFile.Close(); traceOut; }
virtual void AddPacket(BYTE *data, UINT size, DWORD timestamp, PacketType type) { UINT64 offset = fileOut.GetPos(); if(initialTimeStamp == -1 && data[0] != 0x17) return; else if(initialTimeStamp == -1 && data[0] == 0x17) { initialTimeStamp = timestamp; } if(type == PacketType_Audio) { UINT copySize; if(bMP3) { copySize = size-1; fileOut.Serialize(data+1, copySize); } else { copySize = size-2; fileOut.Serialize(data+2, copySize); } MP4AudioFrameInfo audioFrame; audioFrame.fileOffset = offset; audioFrame.size = copySize; audioFrame.timestamp = timestamp-initialTimeStamp; GetChunkInfo<MP4AudioFrameInfo>(audioFrame, audioFrames.Num(), audioChunks, audioSampleToChunk, curAudioChunkOffset, connectedAudioSampleOffset, numAudioSamples); if(audioFrames.Num()) GetAudioDecodeTime(audioFrames.Last(), false); audioFrames << audioFrame; } else { UINT totalCopied = 0; if(data[0] == 0x17 && data[1] == 0) //if SPS/PPS { LPBYTE lpData = data+11; UINT spsSize = fastHtons(*(WORD*)lpData); fileOut.OutputWord(0); fileOut.Serialize(lpData, spsSize+2); lpData += spsSize+3; UINT ppsSize = fastHtons(*(WORD*)lpData); fileOut.OutputWord(0); fileOut.Serialize(lpData, ppsSize+2); totalCopied = spsSize+ppsSize+8; } else { if (!bSentSEI) { DataPacket sei; App->GetVideoEncoder()->GetSEI(sei); if (sei.size > 0) { fileOut.Serialize(sei.lpPacket, sei.size); totalCopied += sei.size; bSentSEI = true; } } totalCopied += size-5; fileOut.Serialize(data+5, size-5); } if(!videoFrames.Num() || (timestamp-initialTimeStamp) != lastVideoTimestamp) { INT timeOffset = 0; mcpy(((BYTE*)&timeOffset)+1, data+2, 3); if(data[2] >= 0x80) timeOffset |= 0xFF; timeOffset = (INT)fastHtonl(DWORD(timeOffset)); if(data[0] == 0x17) //i-frame IFrameIDs << fastHtonl(videoFrames.Num()+1); MP4VideoFrameInfo frameInfo; frameInfo.fileOffset = offset; frameInfo.size = totalCopied; frameInfo.timestamp = timestamp-initialTimeStamp; frameInfo.compositionOffset = timeOffset; GetChunkInfo<MP4VideoFrameInfo>(frameInfo, videoFrames.Num(), videoChunks, videoSampleToChunk, curVideoChunkOffset, connectedVideoSampleOffset, numVideoSamples); if(videoFrames.Num()) GetVideoDecodeTime(frameInfo, false); videoFrames << frameInfo; } else videoFrames.Last().size += totalCopied; lastVideoTimestamp = timestamp-initialTimeStamp; } }
~MP4FileStream() { if(!bStreamOpened) return; App->EnableSceneSwitching(false); //--------------------------------------------------- //HWND hwndProgressDialog = CreateDialog(hinstMain, MAKEINTRESOURCE(IDD_BUILDINGMP4), hwndMain, (DLGPROC)MP4ProgressDialogProc); //SendMessage(GetDlgItem(hwndProgressDialog, IDC_PROGRESS1), PBM_SETRANGE32, 0, 100); mdatStop = fileOut.GetPos(); BufferOutputSerializer output(endBuffer); //set a reasonable initial buffer size endBuffer.SetSize((videoFrames.Num() + audioFrames.Num()) * 20 + 131072); UINT64 audioFrameSize = App->GetAudioEncoder()->GetFrameSize(); DWORD macTime = fastHtonl(DWORD(GetMacTime())); UINT videoDuration = fastHtonl(lastVideoTimestamp + App->GetFrameTime()); UINT audioDuration = fastHtonl(lastVideoTimestamp + DWORD(double(audioFrameSize)*1000.0/double(App->GetSampleRateHz()))); UINT width, height; App->GetOutputSize(width, height); LPCSTR lpVideoTrack = "Video Media Handler"; LPCSTR lpAudioTrack = "Sound Media Handler"; const char videoCompressionName[31] = "AVC Coding"; //------------------------------------------- // get video headers DataPacket videoHeaders; App->GetVideoHeaders(videoHeaders); List<BYTE> SPS, PPS; LPBYTE lpHeaderData = videoHeaders.lpPacket+11; SPS.CopyArray(lpHeaderData+2, fastHtons(*(WORD*)lpHeaderData)); lpHeaderData += SPS.Num()+3; PPS.CopyArray(lpHeaderData+2, fastHtons(*(WORD*)lpHeaderData)); //------------------------------------------- // get AAC headers if using AAC List<BYTE> AACHeader; if(!bMP3) { DataPacket data; App->GetAudioHeaders(data); AACHeader.CopyArray(data.lpPacket+2, data.size-2); } //------------------------------------------- EndChunkInfo(videoChunks, videoSampleToChunk, curVideoChunkOffset, numVideoSamples); EndChunkInfo(audioChunks, audioSampleToChunk, curAudioChunkOffset, numAudioSamples); if (numVideoSamples > 1) GetVideoDecodeTime(videoFrames.Last(), true); if (numAudioSamples > 1) GetAudioDecodeTime(audioFrames.Last(), true); UINT audioUnitDuration = fastHtonl(UINT(lastAudioTimeVal)); //SendMessage(GetDlgItem(hwndProgressDialog, IDC_PROGRESS1), PBM_SETPOS, 25, 0); //------------------------------------------- // sound descriptor thingy. this part made me die a little inside admittedly. UINT maxBitRate = fastHtonl(App->GetAudioEncoder()->GetBitRate()*1000); List<BYTE> esDecoderDescriptor; BufferOutputSerializer esDecoderOut(esDecoderDescriptor); esDecoderOut.OutputByte(bMP3 ? 107 : 64); esDecoderOut.OutputByte(0x15); //stream/type flags. always 0x15 for my purposes. esDecoderOut.OutputByte(0); //buffer size, just set it to 1536 for both mp3 and aac esDecoderOut.OutputWord(WORD_BE(0x600)); esDecoderOut.OutputDword(maxBitRate); //max bit rate (cue bill 'o reily meme for these two) esDecoderOut.OutputDword(maxBitRate); //avg bit rate if(!bMP3) //if AAC, put in headers { esDecoderOut.OutputByte(0x5); //decoder specific descriptor type /*esDecoderOut.OutputByte(0x80); //some stuff that no one should probably care about esDecoderOut.OutputByte(0x80); esDecoderOut.OutputByte(0x80);*/ esDecoderOut.OutputByte(AACHeader.Num()); esDecoderOut.Serialize((LPVOID)AACHeader.Array(), AACHeader.Num()); } List<BYTE> esDescriptor; BufferOutputSerializer esOut(esDescriptor); esOut.OutputWord(0); //es id esOut.OutputByte(0); //stream priority esOut.OutputByte(4); //descriptor type /*esOut.OutputByte(0x80); //some stuff that no one should probably care about esOut.OutputByte(0x80); esOut.OutputByte(0x80);*/ esOut.OutputByte(esDecoderDescriptor.Num()); esOut.Serialize((LPVOID)esDecoderDescriptor.Array(), esDecoderDescriptor.Num()); esOut.OutputByte(0x6); //config descriptor type /*esOut.OutputByte(0x80); //some stuff that no one should probably care about esOut.OutputByte(0x80); esOut.OutputByte(0x80);*/ esOut.OutputByte(1); //len esOut.OutputByte(2); //SL value(? always 2) //------------------------------------------- PushBox(output, DWORD_BE('moov')); //------------------------------------------------------ // header PushBox(output, DWORD_BE('mvhd')); output.OutputDword(0); //version and flags (none) output.OutputDword(macTime); //creation time output.OutputDword(macTime); //modified time output.OutputDword(DWORD_BE(1000)); //time base (milliseconds, so 1000) output.OutputDword(videoDuration); //duration (in time base units) output.OutputDword(DWORD_BE(0x00010000)); //fixed point playback speed 1.0 output.OutputWord(WORD_BE(0x0100)); //fixed point vol 1.0 output.OutputQword(0); //reserved (10 bytes) output.OutputWord(0); output.OutputDword(DWORD_BE(0x00010000)); output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x00000000)); //window matrix row 1 (1.0, 0.0, 0.0) output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x00010000)); output.OutputDword(DWORD_BE(0x00000000)); //window matrix row 2 (0.0, 1.0, 0.0) output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x40000000)); //window matrix row 3 (0.0, 0.0, 16384.0) output.OutputDword(0); //prevew start time (time base units) output.OutputDword(0); //prevew duration (time base units) output.OutputDword(0); //still poster frame (timestamp of frame) output.OutputDword(0); //selection(?) start time (time base units) output.OutputDword(0); //selection(?) duration (time base units) output.OutputDword(0); //current time (0, time base units) output.OutputDword(DWORD_BE(3)); //next free track id (1-based rather than 0-based) PopBox(output); //mvhd //------------------------------------------------------ // audio track PushBox(output, DWORD_BE('trak')); PushBox(output, DWORD_BE('tkhd')); //track header output.OutputDword(DWORD_BE(0x00000007)); //version (0) and flags (0xF) output.OutputDword(macTime); //creation time output.OutputDword(macTime); //modified time output.OutputDword(DWORD_BE(1)); //track ID output.OutputDword(0); //reserved output.OutputDword(audioDuration); //duration (in time base units) output.OutputQword(0); //reserved output.OutputWord(0); //video layer (0) output.OutputWord(WORD_BE(0)); //quicktime alternate track id output.OutputWord(WORD_BE(0x0100)); //volume output.OutputWord(0); //reserved output.OutputDword(DWORD_BE(0x00010000)); output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x00000000)); //window matrix row 1 (1.0, 0.0, 0.0) output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x00010000)); output.OutputDword(DWORD_BE(0x00000000)); //window matrix row 2 (0.0, 1.0, 0.0) output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x40000000)); //window matrix row 3 (0.0, 0.0, 16384.0) output.OutputDword(0); //width (fixed point) output.OutputDword(0); //height (fixed point) PopBox(output); //tkhd /*PushBox(output, DWORD_BE('edts')); PushBox(output, DWORD_BE('elst')); output.OutputDword(0); //version and flags (none) output.OutputDword(DWORD_BE(1)); //count output.OutputDword(audioDuration); //duration output.OutputDword(0); //start time output.OutputDword(DWORD_BE(0x00010000)); //playback speed (1.0) PopBox(); //elst PopBox(); //tdst*/ PushBox(output, DWORD_BE('mdia')); PushBox(output, DWORD_BE('mdhd')); output.OutputDword(0); //version and flags (none) output.OutputDword(macTime); //creation time output.OutputDword(macTime); //modified time output.OutputDword(DWORD_BE(App->GetSampleRateHz())); //time scale output.OutputDword(audioUnitDuration); output.OutputDword(bMP3 ? DWORD_BE(0x55c40000) : DWORD_BE(0x15c70000)); PopBox(output); //mdhd PushBox(output, DWORD_BE('hdlr')); output.OutputDword(0); //version and flags (none) output.OutputDword(0); //quicktime type (none) output.OutputDword(DWORD_BE('soun')); //media type output.OutputDword(0); //manufacturer reserved output.OutputDword(0); //quicktime component reserved flags output.OutputDword(0); //quicktime component reserved mask output.Serialize((LPVOID)lpAudioTrack, (DWORD)strlen(lpAudioTrack)+1); //track name PopBox(output); //hdlr PushBox(output, DWORD_BE('minf')); PushBox(output, DWORD_BE('smhd')); output.OutputDword(0); //version and flags (none) output.OutputDword(0); //balance (fixed point) PopBox(output); //vdhd PushBox(output, DWORD_BE('dinf')); PushBox(output, DWORD_BE('dref')); output.OutputDword(0); //version and flags (none) output.OutputDword(DWORD_BE(1)); //count PushBox(output, DWORD_BE('url ')); output.OutputDword(DWORD_BE(0x00000001)); //version (0) and flags (1) PopBox(output); //url PopBox(output); //dref PopBox(output); //dinf PushBox(output, DWORD_BE('stbl')); PushBox(output, DWORD_BE('stsd')); output.OutputDword(0); //version and flags (none) output.OutputDword(DWORD_BE(1)); //count PushBox(output, DWORD_BE('mp4a')); output.OutputDword(0); //reserved (6 bytes) output.OutputWord(0); output.OutputWord(WORD_BE(1)); //dref index output.OutputWord(0); //quicktime encoding version output.OutputWord(0); //quicktime encoding revision output.OutputDword(0); //quicktime audio encoding vendor output.OutputWord(0); //channels (ignored) output.OutputWord(WORD_BE(16)); //sample size output.OutputWord(0); //quicktime audio compression id output.OutputWord(0); //quicktime audio packet size output.OutputDword(DWORD_BE(App->GetSampleRateHz()<<16)); //sample rate (fixed point) PushBox(output, DWORD_BE('esds')); output.OutputDword(0); //version and flags (none) output.OutputByte(3); //ES descriptor type /*output.OutputByte(0x80); output.OutputByte(0x80); output.OutputByte(0x80);*/ output.OutputByte(esDescriptor.Num()); output.Serialize((LPVOID)esDescriptor.Array(), esDescriptor.Num()); PopBox(output); PopBox(output); PopBox(output); //stsd PushBox(output, DWORD_BE('stts')); //list of keyframe (i-frame) IDs output.OutputDword(0); //version and flags (none) output.OutputDword(fastHtonl(audioDecodeTimes.Num())); for(UINT i=0; i<audioDecodeTimes.Num(); i++) { output.OutputDword(fastHtonl(audioDecodeTimes[i].count)); output.OutputDword(fastHtonl(audioDecodeTimes[i].val)); } PopBox(output); //stss PushBox(output, DWORD_BE('stsc')); //sample to chunk list output.OutputDword(0); //version and flags (none) output.OutputDword(fastHtonl(audioSampleToChunk.Num())); for(UINT i=0; i<audioSampleToChunk.Num(); i++) { SampleToChunk &stc = audioSampleToChunk[i]; output.OutputDword(fastHtonl(stc.firstChunkID)); output.OutputDword(fastHtonl(stc.samplesPerChunk)); output.OutputDword(DWORD_BE(1)); } PopBox(output); //stsc //SendMessage(GetDlgItem(hwndProgressDialog, IDC_PROGRESS1), PBM_SETPOS, 30, 0); //ProcessEvents(); PushBox(output, DWORD_BE('stsz')); //sample sizes output.OutputDword(0); //version and flags (none) output.OutputDword(0); //block size for all (0 if differing sizes) output.OutputDword(fastHtonl(audioFrames.Num())); for(UINT i=0; i<audioFrames.Num(); i++) output.OutputDword(fastHtonl(audioFrames[i].size)); PopBox(output); //SendMessage(GetDlgItem(hwndProgressDialog, IDC_PROGRESS1), PBM_SETPOS, 40, 0); //ProcessEvents(); if(audioChunks.Num() && audioChunks.Last() > 0xFFFFFFFFLL) { PushBox(output, DWORD_BE('co64')); //chunk offsets output.OutputDword(0); //version and flags (none) output.OutputDword(fastHtonl(audioChunks.Num())); for(UINT i=0; i<audioChunks.Num(); i++) output.OutputQword(fastHtonll(audioChunks[i])); PopBox(output); //co64 } else { PushBox(output, DWORD_BE('stco')); //chunk offsets output.OutputDword(0); //version and flags (none) output.OutputDword(fastHtonl(audioChunks.Num())); for(UINT i=0; i<audioChunks.Num(); i++) output.OutputDword(fastHtonl((DWORD)audioChunks[i])); PopBox(output); //stco } PopBox(output); //stbl PopBox(output); //minf PopBox(output); //mdia PopBox(output); //trak //SendMessage(GetDlgItem(hwndProgressDialog, IDC_PROGRESS1), PBM_SETPOS, 50, 0); //ProcessEvents(); //------------------------------------------------------ // video track PushBox(output, DWORD_BE('trak')); PushBox(output, DWORD_BE('tkhd')); //track header output.OutputDword(DWORD_BE(0x00000007)); //version (0) and flags (0x7) output.OutputDword(macTime); //creation time output.OutputDword(macTime); //modified time output.OutputDword(DWORD_BE(2)); //track ID output.OutputDword(0); //reserved output.OutputDword(videoDuration); //duration (in time base units) output.OutputQword(0); //reserved output.OutputWord(0); //video layer (0) output.OutputWord(0); //quicktime alternate track id (0) output.OutputWord(0); //track audio volume (this is video, so 0) output.OutputWord(0); //reserved output.OutputDword(DWORD_BE(0x00010000)); output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x00000000)); //window matrix row 1 (1.0, 0.0, 0.0) output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x00010000)); output.OutputDword(DWORD_BE(0x00000000)); //window matrix row 2 (0.0, 1.0, 0.0) output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x00000000)); output.OutputDword(DWORD_BE(0x40000000)); //window matrix row 3 (0.0, 0.0, 16384.0) output.OutputDword(fastHtonl(width<<16)); //width (fixed point) output.OutputDword(fastHtonl(height<<16)); //height (fixed point) PopBox(output); //tkhd /*PushBox(output, DWORD_BE('edts')); PushBox(output, DWORD_BE('elst')); output.OutputDword(0); //version and flags (none) output.OutputDword(DWORD_BE(1)); //count output.OutputDword(videoDuration); //duration output.OutputDword(0); //start time output.OutputDword(DWORD_BE(0x00010000)); //playback speed (1.0) PopBox(); //elst PopBox(); //tdst*/ PushBox(output, DWORD_BE('mdia')); PushBox(output, DWORD_BE('mdhd')); output.OutputDword(0); //version and flags (none) output.OutputDword(macTime); //creation time output.OutputDword(macTime); //modified time output.OutputDword(DWORD_BE(1000)); //time scale output.OutputDword(videoDuration); output.OutputDword(DWORD_BE(0x55c40000)); PopBox(output); //mdhd PushBox(output, DWORD_BE('hdlr')); output.OutputDword(0); //version and flags (none) output.OutputDword(0); //quicktime type (none) output.OutputDword(DWORD_BE('vide')); //media type output.OutputDword(0); //manufacturer reserved output.OutputDword(0); //quicktime component reserved flags output.OutputDword(0); //quicktime component reserved mask output.Serialize((LPVOID)lpVideoTrack, (DWORD)strlen(lpVideoTrack)+1); //track name PopBox(output); //hdlr PushBox(output, DWORD_BE('minf')); PushBox(output, DWORD_BE('vmhd')); output.OutputDword(DWORD_BE(0x00000001)); //version (0) and flags (1) output.OutputWord(0); //quickdraw graphic mode (copy = 0) output.OutputWord(0); //quickdraw red value output.OutputWord(0); //quickdraw green value output.OutputWord(0); //quickdraw blue value PopBox(output); //vdhd PushBox(output, DWORD_BE('dinf')); PushBox(output, DWORD_BE('dref')); output.OutputDword(0); //version and flags (none) output.OutputDword(DWORD_BE(1)); //count PushBox(output, DWORD_BE('url ')); output.OutputDword(DWORD_BE(0x00000001)); //version (0) and flags (1) PopBox(output); //url PopBox(output); //dref PopBox(output); //dinf PushBox(output, DWORD_BE('stbl')); PushBox(output, DWORD_BE('stsd')); output.OutputDword(0); //version and flags (none) output.OutputDword(DWORD_BE(1)); //count PushBox(output, DWORD_BE('avc1')); output.OutputDword(0); //reserved 6 bytes output.OutputWord(0); output.OutputWord(WORD_BE(1)); //index output.OutputWord(0); //encoding version output.OutputWord(0); //encoding revision level output.OutputDword(0); //encoding vendor output.OutputDword(0); //temporal quality output.OutputDword(0); //spatial quality output.OutputWord(fastHtons(width)); //width output.OutputWord(fastHtons(height)); //height output.OutputDword(DWORD_BE(0x00480000)); //fixed point width pixel resolution (72.0) output.OutputDword(DWORD_BE(0x00480000)); //fixed point height pixel resolution (72.0) output.OutputDword(0); //quicktime video data size output.OutputWord(WORD_BE(1)); //frame count(?) output.OutputByte((BYTE)strlen(videoCompressionName)); //compression name length output.Serialize(videoCompressionName, 31); //31 bytes for the name output.OutputWord(WORD_BE(24)); //bit depth output.OutputWord(0xFFFF); //quicktime video color table id (none = -1) PushBox(output, DWORD_BE('avcC')); output.OutputByte(1); //version output.OutputByte(100); //h264 profile ID output.OutputByte(0); //h264 compatible profiles output.OutputByte(0x1f); //h264 level output.OutputByte(0xff); //reserved output.OutputByte(0xe1); //first half-byte = no clue. second half = sps count output.OutputWord(fastHtons(SPS.Num())); //sps size output.Serialize(SPS.Array(), SPS.Num()); //sps data output.OutputByte(1); //pps count output.OutputWord(fastHtons(PPS.Num())); //pps size output.Serialize(PPS.Array(), PPS.Num()); //pps data PopBox(output); //avcC PopBox(output); //avc1 PopBox(output); //stsd PushBox(output, DWORD_BE('stts')); //frame times output.OutputDword(0); //version and flags (none) output.OutputDword(fastHtonl(videoDecodeTimes.Num())); for(UINT i=0; i<videoDecodeTimes.Num(); i++) { output.OutputDword(fastHtonl(videoDecodeTimes[i].count)); output.OutputDword(fastHtonl(videoDecodeTimes[i].val)); } PopBox(output); //stts //SendMessage(GetDlgItem(hwndProgressDialog, IDC_PROGRESS1), PBM_SETPOS, 60, 0); //ProcessEvents(); if (IFrameIDs.Num()) { PushBox(output, DWORD_BE('stss')); //list of keyframe (i-frame) IDs output.OutputDword(0); //version and flags (none) output.OutputDword(fastHtonl(IFrameIDs.Num())); output.Serialize(IFrameIDs.Array(), IFrameIDs.Num()*sizeof(UINT)); PopBox(output); //stss } PushBox(output, DWORD_BE('ctts')); //list of composition time offsets output.OutputDword(0); //version (0) and flags (none) //output.OutputDword(DWORD_BE(0x01000000)); //version (1) and flags (none) output.OutputDword(fastHtonl(compositionOffsets.Num())); for(UINT i=0; i<compositionOffsets.Num(); i++) { output.OutputDword(fastHtonl(compositionOffsets[i].count)); output.OutputDword(fastHtonl(compositionOffsets[i].val)); } PopBox(output); //ctts //SendMessage(GetDlgItem(hwndProgressDialog, IDC_PROGRESS1), PBM_SETPOS, 70, 0); //ProcessEvents(); PushBox(output, DWORD_BE('stsc')); //sample to chunk list output.OutputDword(0); //version and flags (none) output.OutputDword(fastHtonl(videoSampleToChunk.Num())); for(UINT i=0; i<videoSampleToChunk.Num(); i++) { SampleToChunk &stc = videoSampleToChunk[i]; output.OutputDword(fastHtonl(stc.firstChunkID)); output.OutputDword(fastHtonl(stc.samplesPerChunk)); output.OutputDword(DWORD_BE(1)); } PopBox(output); //stsc PushBox(output, DWORD_BE('stsz')); //sample sizes output.OutputDword(0); //version and flags (none) output.OutputDword(0); //block size for all (0 if differing sizes) output.OutputDword(fastHtonl(videoFrames.Num())); for(UINT i=0; i<videoFrames.Num(); i++) output.OutputDword(fastHtonl(videoFrames[i].size)); PopBox(output); if(videoChunks.Num() && videoChunks.Last() > 0xFFFFFFFFLL) { PushBox(output, DWORD_BE('co64')); //chunk offsets output.OutputDword(0); //version and flags (none) output.OutputDword(fastHtonl(videoChunks.Num())); for(UINT i=0; i<videoChunks.Num(); i++) output.OutputQword(fastHtonll(videoChunks[i])); PopBox(output); //co64 } else { PushBox(output, DWORD_BE('stco')); //chunk offsets output.OutputDword(0); //version and flags (none) output.OutputDword(fastHtonl(videoChunks.Num())); for(UINT i=0; i<videoChunks.Num(); i++) output.OutputDword(fastHtonl((DWORD)videoChunks[i])); PopBox(output); //stco } PopBox(output); //stbl PopBox(output); //minf PopBox(output); //mdia PopBox(output); //trak //SendMessage(GetDlgItem(hwndProgressDialog, IDC_PROGRESS1), PBM_SETPOS, 80, 0); //ProcessEvents(); //------------------------------------------------------ // info thingy PushBox(output, DWORD_BE('udta')); PushBox(output, DWORD_BE('meta')); output.OutputDword(0); //version and flags (none) PushBox(output, DWORD_BE('hdlr')); output.OutputDword(0); //version and flags (none) output.OutputDword(0); //quicktime type output.OutputDword(DWORD_BE('mdir')); //metadata type output.OutputDword(DWORD_BE('appl')); //quicktime manufacturer reserved thingy output.OutputDword(0); //quicktime component reserved flag output.OutputDword(0); //quicktime component reserved flag mask output.OutputByte(0); //null string PopBox(output); //hdlr PushBox(output, DWORD_BE('ilst')); PushBox(output, DWORD_BE('\xa9too')); PushBox(output, DWORD_BE('data')); output.OutputDword(DWORD_BE(1)); //version (1) + flags (0) output.OutputDword(0); //reserved LPSTR lpVersion = OBS_VERSION_STRING_ANSI; output.Serialize(lpVersion, (DWORD)strlen(lpVersion)); PopBox(output); //data PopBox(output); //@too PopBox(output); //ilst PopBox(output); //meta PopBox(output); //udta PopBox(output); //moov fileOut.Serialize(endBuffer.Array(), (DWORD)output.GetPos()); fileOut.Close(); XFile file; if(file.Open(strFile, XFILE_WRITE, XFILE_OPENEXISTING)) { #ifdef USE_64BIT_MP4 file.SetPos((INT64)mdatStart+8, XFILE_BEGIN); UINT64 size = fastHtonll(mdatStop-mdatStart); file.Write(&size, 8); #else file.SetPos((INT64)mdatStart, XFILE_BEGIN); UINT size = fastHtonl((DWORD)(mdatStop-mdatStart)); file.Write(&size, 4); #endif file.Close(); } App->EnableSceneSwitching(true); //DestroyWindow(hwndProgressDialog); }