bool Init(CTSTR lpFile) { strFile = lpFile; initialTimestamp = -1; if(!fileOut.Open(lpFile, XFILE_CREATEALWAYS, 1024*1024)) return false; fileOut.OutputByte('F'); fileOut.OutputByte('L'); fileOut.OutputByte('V'); fileOut.OutputByte(1); fileOut.OutputByte(5); //bit 0 = (hasAudio), bit 2 = (hasAudio) fileOut.OutputDword(DWORD_BE(9)); fileOut.OutputDword(0); metaDataPos = fileOut.GetPos(); char metaDataBuffer[2048]; char *enc = metaDataBuffer; char *pend = metaDataBuffer+sizeof(metaDataBuffer); enc = AMF_EncodeString(enc, pend, &av_onMetaData); char *endMetaData = App->EncMetaData(enc, pend, true); UINT metaDataSize = endMetaData-metaDataBuffer; AppendFLVPacket((LPBYTE)metaDataBuffer, metaDataSize, 18, 0); return true; }
~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); }
bool Init(CTSTR lpFile) { strFile = lpFile; initialTimeStamp = -1; if(!fileOut.Open(lpFile, XFILE_CREATEALWAYS, 1024*1024)) return false; fileOut.OutputDword(DWORD_BE(0x20)); fileOut.OutputDword(DWORD_BE('ftyp')); fileOut.OutputDword(DWORD_BE('isom')); fileOut.OutputDword(DWORD_BE(0x200)); fileOut.OutputDword(DWORD_BE('isom')); fileOut.OutputDword(DWORD_BE('iso2')); fileOut.OutputDword(DWORD_BE('avc1')); fileOut.OutputDword(DWORD_BE('mp41')); fileOut.OutputDword(DWORD_BE(0x8)); fileOut.OutputDword(DWORD_BE('free')); mdatStart = fileOut.GetPos(); fileOut.OutputDword(DWORD_BE(0x1)); fileOut.OutputDword(DWORD_BE('mdat')); #ifdef USE_64BIT_MP4 fileOut.OutputQword(0); #endif bMP3 = scmp(App->GetAudioEncoder()->GetCodec(), TEXT("MP3")) == 0; audioFrameSize = App->GetAudioEncoder()->GetFrameSize(); bStreamOpened = true; return true; }
int main(int argc, char **argv) { int rv; const char *what; const char *filename; const char *outname; TheImg4 *img4; unsigned type; unsigned written; unsigned char ivkey[16 + 32]; unsigned char *iv = NULL, *key = NULL; unsigned char *output = NULL; unsigned outlen = 0; int outdup = 0; DERItem item; unsigned char *data; size_t size; if (argc < 4) { fprintf(stderr, "usage: %s {-image|-extra|-keybag|-ticket} input output [ivkey]\n", argv[0]); return 1; } what = argv[1]; filename = argv[2]; outname = argv[3]; if (argc > 4) { rv = str2hex(sizeof(ivkey), ivkey, argv[4]); if (rv == sizeof(ivkey)) { iv = ivkey; key = ivkey + 16; } } data = read_file(filename, 0, &size); if (data == NULL) { fprintf(stderr, "[e] cannot read '%s'\n", filename); return -1; } img4 = parse(data, size); if (!img4) { fprintf(stderr, "[e] cannot parse '%s'\n", filename); free(data); return -1; } rv = Img4DecodeGetPayloadType(img4, &type); if (rv) { fprintf(stderr, "[e] cannot identify '%s'\n", filename); goto err; } printf("%c%c%c%c\n", FOURCC(type)); if (!strncmp(what, "-i", 2) || !strncmp(what, "-e", 2)) { int decompress; rv = Img4DecodeGetPayload(img4, &item); if (rv) { fprintf(stderr, "[e] cannot extract payload from '%s'\n", filename); goto err; } output = item.data; outlen = item.length; if (iv && key) { if (outlen & 15) { unsigned usize = (outlen + 15) & ~15; unsigned char *tmp = calloc(1, usize); if (!tmp) { fprintf(stderr, "[e] out of memory %u\n", usize); goto err; } memcpy(tmp, output, outlen); OUTSET(tmp); } rv = Img4DecodeGetPayloadKeybag(img4, &item); if (rv || item.length == 0) { fprintf(stderr, "[w] image '%s' has no keybag\n", filename); } #ifdef USE_CORECRYPTO cccbc_one_shot(ccaes_cbc_decrypt_mode(), 32, key, iv, (outlen + 15) / 16, output, output); #else AES_KEY decryptKey; AES_set_decrypt_key(key, 256, &decryptKey); AES_cbc_encrypt(output, output, (outlen + 15) & ~15, &decryptKey, iv, AES_DECRYPT); #endif } #ifdef iOS10 if (img4->payload.compression.data && img4->payload.compression.length) { DERItem tmp[2]; uint32_t deco = 0; uint64_t usize = 0; if (DERParseSequenceContent(&img4->payload.compression, 2, DERImg4PayloadItemSpecs10c, tmp, 0) || DERParseInteger(&tmp[0], &deco) || DERParseInteger64(&tmp[1], &usize)) { fprintf(stderr, "[e] cannot get decompression info\n"); goto err; } if (deco == 1 && what[1] == 'i') { size_t asize = lzfse_decode_scratch_size(); unsigned char *dec, *aux = malloc(asize); if (!aux) { fprintf(stderr, "[e] out of memory %zu\n", asize); goto err; } dec = malloc(usize + 1); if (!dec) { fprintf(stderr, "[e] out of memory %llu\n", usize + 1); free(aux); goto err; } outlen = lzfse_decode_buffer(dec, usize + 1, output, outlen, aux); free(aux); if (outlen != usize) { fprintf(stderr, "[e] decompression error\n"); free(dec); goto err; } OUTSET(dec); } } #endif decompress = (DWORD_BE(output, 0) == 'comp' && DWORD_BE(output, 4) == 'lzss'); if (decompress && what[1] == 'i') { uint32_t csize = DWORD_BE(output, 16); uint32_t usize = DWORD_BE(output, 12); uint32_t adler = DWORD_BE(output, 8); unsigned char *dec = malloc(usize); if (outlen > 0x180 + csize) { fprintf(stderr, "[i] extra 0x%x bytes after compressed chunk\n", outlen - 0x180 - csize); } if (!dec) { fprintf(stderr, "[e] out of memory %u\n", usize); goto err; } outlen = decompress_lzss(dec, output + 0x180, csize); if (adler != lzadler32(dec, outlen)) { fprintf(stderr, "[w] adler32 mismatch\n"); } OUTSET(dec); } else if (decompress) { uint32_t csize = DWORD_BE(output, 16); uint32_t usize = outlen - 0x180 - csize; if (outlen > 0x180 + csize) { unsigned char *dec = malloc(usize); if (!dec) { fprintf(stderr, "[e] out of memory %u\n", usize); goto err; } memcpy(dec, output + 0x180 + csize, usize); outlen = usize; OUTSET(dec); } else { OUTSET(NULL); } } else if (what[1] == 'e') { OUTSET(NULL); } if (!output) { fprintf(stderr, "[e] nothing to do\n"); goto err; } } if (!strncmp(what, "-k", 2)) { rv = Img4DecodeGetPayloadKeybag(img4, &item); if (rv == 0 && item.length) { output = item.data; outlen = item.length; } else { fprintf(stderr, "[e] image '%s' has no keybag\n", filename); goto err; } } if (!strncmp(what, "-t", 2)) { bool exists = false; rv = Img4DecodeManifestExists(img4, &exists); if (rv == 0 && exists) { output = img4->manifestRaw.data; outlen = img4->manifestRaw.length; } else { fprintf(stderr, "[e] image '%s' has no ticket\n", filename); goto err; } } written = write_file(outname, output, outlen); if (written != outlen) { fprintf(stderr, "[e] cannot write '%s'\n", outname); goto err; } rv = 0; out: if (outdup) { free(output); } free(img4); free(data); return rv; err: rv = -1; goto out; }
/* ======================================= PNG 文件读取 ======================================= */ CR_API sFMT_PIC* load_cr_png ( __CR_IO__ iDATIN* datin, __CR_IN__ const sLOADER* param ) { leng_t nbpl; leng_t sbpp; leng_t dptr; uint_t fcrh; uint_t index; uchar* image; uchar* sdata; uchar* ddata; leng_t dsize; int32u ssize; uint_t ww, hh; byte_t pal[768]; /* ----------- */ fsize_t fsze; sPNG_HDR head; sFMT_PIC* rett; sFMT_FRAME temp; /* 这个参数可能为空 */ if (datin == NULL) return (NULL); /* 读取 & 检查头部 */ if (!(CR_VCALL(datin)->geType(datin, &head, sPNG_HDR))) return (NULL); if (mem_cmp(&head, "\x89PNG\r\n\x1A\n\0\0\0\x0DIHDR", 16) != 0) return (NULL); if (head.info.compr != 0 || head.info.filter != 0 || head.info.interlace != 0) return (NULL); /* 对宽高的截断检查 */ if (cut_int32_u(&ww, DWORD_BE(head.info.w))) return (NULL); if (cut_int32_u(&hh, DWORD_BE(head.info.h))) return (NULL); /* 生成图片对象 */ mem_zero(temp.wh, sizeof(temp.wh)); switch (head.info.color) { case 0: /* 灰度图像 */ if (head.info.depth != 1 && head.info.depth != 2 && head.info.depth != 4 && head.info.depth != 8 && head.info.depth != 16) return (NULL); fcrh = CR_INDEX8; temp.fmt = CR_PIC_GREY; temp.bpp = head.info.depth; temp.clr = "I"; temp.wh[0] = head.info.depth; break; case 2: /* 真彩图像 */ if (head.info.depth != 8 && head.info.depth != 16) return (NULL); fcrh = CR_ARGB888; temp.fmt = CR_PIC_ARGB; temp.bpp = head.info.depth * 3; temp.clr = "BGR"; temp.wh[0] = head.info.depth; temp.wh[1] = head.info.depth; temp.wh[2] = head.info.depth; break; case 3: /* 索引图像 */ if (head.info.depth != 1 && head.info.depth != 2 && head.info.depth != 4 && head.info.depth != 8) return (NULL); fcrh = CR_INDEX8; temp.fmt = CR_PIC_PALS; temp.bpp = head.info.depth; temp.clr = "P"; temp.wh[0] = head.info.depth; break; case 4: /* α灰度图像 */ if (head.info.depth != 8 && head.info.depth != 16) return (NULL); fcrh = CR_ARGB8888; temp.fmt = CR_PIC_GREY; temp.bpp = head.info.depth * 2; temp.clr = "AI"; temp.wh[0] = head.info.depth; temp.wh[1] = head.info.depth; break; case 6: /* α真彩图像 */ if (head.info.depth != 8 && head.info.depth != 16) return (NULL); fcrh = CR_ARGB8888; temp.fmt = CR_PIC_ARGB; temp.bpp = head.info.depth * 4; temp.clr = "ABGR"; temp.wh[0] = head.info.depth; temp.wh[1] = head.info.depth; temp.wh[2] = head.info.depth; temp.wh[3] = head.info.depth; break; default: return (NULL); } sbpp = (temp.bpp - 1) / 8 + 1; temp.pic = image_new(0, 0, ww, hh, fcrh, FALSE, 4); if (temp.pic == NULL) return (NULL); /* 生成灰度调色板 */ if (temp.fmt == CR_PIC_GREY) pal_set_gray8(temp.pic->pal, 256); /* 分配 IDAT 的内存 */ fsze = dati_get_size(datin); if (fsze <= sizeof(sPNG_HDR) + sizeof(sIEND) * 2) goto _failure1; fsze -= sizeof(sPNG_HDR) + sizeof(sIEND) * 2; ddata = (byte_t*)mem_malloc64(fsze); if (ddata == NULL) goto _failure1; dsize = (leng_t)fsze; /* 读取数据块 */ dptr = 0; fcrh = 256; /* 这个保存调色板颜色数 */ do { /* 数据块大小 */ if (!(CR_VCALL(datin)->geType(datin, &head.info, sCHUNK))) goto _failure2; ssize = DWORD_BE(head.info.head.size); if (ssize > fsze) goto _failure2; if (head.info.head.name == mk_tag4("PLTE")) { /* 调色板, 安全检查 */ if (ssize > 768 || ssize % 3 != 0) goto _failure2; if (CR_VCALL(datin)->read(datin, pal, ssize) != ssize) goto _failure2; /* 转换到 4B 格式 */ fcrh = (uint_t)ssize / 3; pal_3b_to_4b_sw(temp.pic->pal, pal, fcrh); } else if (head.info.head.name == mk_tag4("IDAT")) { /* 检查缓冲溢出 */ if (dsize < ssize) goto _failure2; if (CR_VCALL(datin)->read(datin, ddata + dptr, ssize) != ssize) goto _failure2; dptr += ssize; dsize -= ssize; } else if (head.info.head.name == mk_tag4("tRNS")) { /* 透明数据 */ if (head.info.color == 0) { if (ssize != 2) goto _failure2; if (CR_VCALL(datin)->read(datin, pal, 2) != 2) goto _failure2; /* 调色板的这个颜色为透明色 */ if (head.info.depth != 16) temp.pic->pal[pal[1]] &= CDWORD_LE(0x00FFFFFFUL); } else if (head.info.color == 2) { if (ssize != 6) goto _failure2; if (CR_VCALL(datin)->read(datin, pal, 6) != 6) goto _failure2; /* 这个颜色为透明色, 这里只能展开来写 否则 C++Builder 2010 编译器编译时会崩溃 */ if (head.info.depth != 16) { temp.pic->keycolor = pal[1]; temp.pic->keycolor <<= 8; temp.pic->keycolor |= pal[3]; temp.pic->keycolor <<= 8; temp.pic->keycolor |= pal[5]; temp.pic->keycolor |= 0xFF000000UL; temp.pic->keycolor = DWORD_LE(temp.pic->keycolor); } } else if (head.info.color == 3) { if (ssize > fcrh) goto _failure2; if (CR_VCALL(datin)->read(datin, pal, ssize) != ssize) goto _failure2; /* 设置调色板的 Alpha 通道 */ for (fcrh = (uint_t)ssize, index = 0; index < fcrh; index++) ((uchar*)temp.pic->pal)[index * 4 + 3] = pal[index]; } else { goto _failure2; } } else { /* 跳过其他数据块 */ if (!CR_VCALL(datin)->seek(datin, ssize, SEEK_CUR)) goto _failure2; } /* 跳过 CRC-32 */ if (!CR_VCALL(datin)->seek(datin, 4, SEEK_CUR)) goto _failure2; } while (head.info.head.name != mk_tag4("IEND")); /* 无 IDAT 块 */ if (dptr == 0) goto _failure2; /* 分配带 filter 的图形内存 */ if (cut_mad(&dsize, ww, sbpp * hh, hh)) goto _failure2; sdata = (byte_t*)mem_malloc(dsize); if (sdata == NULL) goto _failure2; /* 解压图形数据 */ dptr = uncompr_zlib(sdata, dsize, ddata, dptr); mem_free(ddata); ddata = sdata; if (dptr <= hh) goto _failure2; image = temp.pic->data; /* 文件解码完毕, 解析图片的像素数据 */ if (temp.pic->fmt == CR_INDEX8) { switch (head.info.depth) { case 1: if (ww % 8 == 0) nbpl = ww / 8; else nbpl = ww / 8 + 1; if (!png_filter(ddata, nbpl, 1, hh, dptr)) goto _failure2; for (index = hh; index != 0; index--) { sdata = (uchar*)font1_h2l(image, sdata, ww); image += temp.pic->bpl; } break; case 2: if (ww % 4 == 0) nbpl = ww / 4; else nbpl = ww / 4 + 1; if (!png_filter(ddata, nbpl, 1, hh, dptr)) goto _failure2; for (index = hh; index != 0; index--) { sdata = (uchar*)font2_h2l(image, sdata, ww); image += temp.pic->bpl; } break; case 4: if (ww % 2 == 0) nbpl = ww / 2; else nbpl = ww / 2 + 1; if (!png_filter(ddata, nbpl, 1, hh, dptr)) goto _failure2; for (index = hh; index != 0; index--) { sdata = (uchar*)font4_h2l(image, sdata, ww); image += temp.pic->bpl; } break; case 8: nbpl = ww; if (!png_filter(ddata, nbpl, 1, hh, dptr)) goto _failure2; for (index = hh; index != 0; index--) { mem_cpy(image, sdata, nbpl); sdata += nbpl; image += temp.pic->bpl; } break; default: case 16: nbpl = ww; nbpl *= 2; if (!png_filter(ddata, nbpl, 2, hh, dptr)) goto _failure2; for (index = hh; index != 0; index--) { for (fcrh = 0; fcrh < ww; fcrh++, sdata += 2) image[fcrh] = sdata[0]; image += temp.pic->bpl; } break; } } else { nbpl = ww * sbpp; if (!png_filter(ddata, nbpl, sbpp, hh, dptr)) goto _failure2; nbpl = ww * temp.pic->bpc; switch (head.info.color) { case 2: if (head.info.depth == 8) { /* 直接逐行复制 */ for (index = hh; index != 0; index--) { for (dsize = 0; dsize < nbpl; dsize += 3) { image[dsize + 0] = sdata[2]; image[dsize + 1] = sdata[1]; image[dsize + 2] = sdata[0]; sdata += 3; } image += temp.pic->bpl; } } else { /* 跳开一个像素复制 */ for (index = hh; index != 0; index--) { for (dsize = 0; dsize < nbpl; dsize += 3) { image[dsize + 0] = sdata[4]; image[dsize + 1] = sdata[2]; image[dsize + 2] = sdata[0]; sdata += 6; } image += temp.pic->bpl; } } break; case 4: if (head.info.depth == 8) { /* 直接逐行复制 */ for (index = hh; index != 0; index--) { for (dsize = 0; dsize < nbpl; dsize += 4) { image[dsize + 0] = sdata[0]; image[dsize + 1] = sdata[0]; image[dsize + 2] = sdata[0]; image[dsize + 3] = sdata[1]; sdata += 2; } image += temp.pic->bpl; } } else { /* 跳开一个像素复制 */ for (index = hh; index != 0; index--) { for (dsize = 0; dsize < nbpl; dsize += 4) { image[dsize + 0] = sdata[0]; image[dsize + 1] = sdata[0]; image[dsize + 2] = sdata[0]; image[dsize + 3] = sdata[2]; sdata += 4; } image += temp.pic->bpl; } } break; default: case 6: if (head.info.depth == 8) { /* 直接逐行复制 */ for (index = hh; index != 0; index--) { for (dsize = 0; dsize < nbpl; dsize += 4) { image[dsize + 0] = sdata[2]; image[dsize + 1] = sdata[1]; image[dsize + 2] = sdata[0]; image[dsize + 3] = sdata[3]; sdata += 4; } image += temp.pic->bpl; } } else { /* 跳开一个像素复制 */ for (index = hh; index != 0; index--) { for (dsize = 0; dsize < nbpl; dsize += 4) { image[dsize + 0] = sdata[4]; image[dsize + 1] = sdata[2]; image[dsize + 2] = sdata[0]; image[dsize + 3] = sdata[6]; sdata += 8; } image += temp.pic->bpl; } } break; } } mem_free(ddata); /* 返回读取的文件数据 */ rett = struct_new(sFMT_PIC); if (rett == NULL) goto _failure1; rett->frame = struct_dup(&temp, sFMT_FRAME); if (rett->frame == NULL) { mem_free(rett); goto _failure1; } CR_NOUSE(param); rett->type = CR_FMTZ_PIC; rett->count = 1; rett->infor = "Portable Network Graphics (PNG)"; return (rett); _failure2: mem_free(ddata); _failure1: image_del(temp.pic); return (NULL); }