Re: about deleting KaxBlockBlob objects
"Kao" <[email protected]> Thu, 24 Nov 2011 19:57:01 +0800
| Newsgroups | gmane.comp.multimedia.matroska.user |
|---|---|
| Message-ID | <D69DED1DFB3C4830BCE30412FB8E09C7@rdminglinkao> |
1. It would trigger an segmentation fault when deleting the pointer of a KaxBlockBlob object. (line 83 of the attached program) 2. In KaxCluster::Render() method, all KaxBlockBlob::Block objects are pushed into a KaxCluster object. Then those objects would be pointed by both KaxCluster and KaxBlockBlob. 3. How to include the V2 #defines? Thank you! Best regards, Ming-Lin Kao ----- Original Message ----- Sent: Wednesday, November 23, 2011 7:05 PM Subject: Re: [Matroska-users] about deleting KaxBlockBlob objects > Hey, > > 1. You seem to have reversed the direction in the same; the "source" > file is the directory named "new". The other way around would be > correct. > > 2. Checking for NULL before "delete pointer;" is not needed. That's in > the C++ standard. The patch for this part of the file doesn't change > the functionality at all. > > 3. I'm not convinced that your change is actually necessary. I use > libmatroska as it is in mkvmerge including the V2 #defines, and > mkvmerge doesn't have memory leaks that could be traced back to this > part of libmatroska. Please show me a test case. > > Kind regards, > mosu > _______________________________________________ > Matroska-users mailing list > [email protected] > http://lists.matroska.org/cgi-bin/mailman/listinfo/matroska-users > Read Matroska-Users on GMane: > http://dir.gmane.org/gmane.comp.multimedia.matroska.user _______________________________________________ Matroska-users mailing list [email protected] http://lists.matroska.org/cgi-bin/mailman/listinfo/matroska-users Read Matroska-Users on GMane: http://dir.gmane.org/gmane.comp.multimedia.matroska.user
test7.cpp
(text/plain, 13.1 KB)
/**************************************************************************** ** libmatroska : parse Matroska files, see http://www.matroska.org/ ** ** <file/class description> ** ** Copyright (C) 2002-2004 Steve Lhomme. All rights reserved. ** ** This file is part of libmatroska. ** ** This library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public ** License as published by the Free Software Foundation; either ** version 2.1 of the License, or (at your option) any later version. ** ** This library is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with this library; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** ** See http://www.matroska.org/license/lgpl/ for LGPL licensing information.** ** Contact [email protected] if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ /*! \file \version \$Id: test6.cpp 725 2011-03-27 17:09:02Z robux4 $ \brief Test muxing two tracks into valid clusters/blocks/frames \author Steve Lhomme <robux4 @ users.sf.net> */ #ifdef _MSC_VER #include <windows.h> // for min/max #endif // _MSC_VER #include <iostream> #include <vector> #include "ebml/StdIOCallback.h" #include "ebml/EbmlHead.h" #include "ebml/EbmlSubHead.h" #include "ebml/EbmlVoid.h" #include "matroska/FileKax.h" #include "matroska/KaxSegment.h" #include "matroska/KaxTracks.h" #include "matroska/KaxTrackEntryData.h" #include "matroska/KaxTrackVideo.h" #include "matroska/KaxCluster.h" #include "matroska/KaxClusterData.h" #include "matroska/KaxSeekHead.h" #include "matroska/KaxCues.h" #include "matroska/KaxInfo.h" #include "matroska/KaxInfoData.h" #include "matroska/KaxVersion.h" using namespace LIBMATROSKA_NAMESPACE; using namespace std; static const char *OUTPUT_FILE_NAME = "test1.mkv"; static const bool bWriteDefaultValues = false; static const uint64 TIMECODE_SCALE = 1000000ull; static std::vector<KaxBlockBlob *> usedBlobs; static KaxBlockBlob *AllocateKaxBlockBlob(BlockBlobType type) { KaxBlockBlob *result = new KaxBlockBlob(type); usedBlobs.push_back(result); return result; } static void RecycleAllKaxBlockBlobs() { std::vector<KaxBlockBlob *>::iterator it; for (it = usedBlobs.begin(); it < usedBlobs.end(); it++) { delete *it; } usedBlobs.clear(); } int main(int argc, char **argv) { uint64 fakeTimecode = time(NULL) * 1000000000ull; size_t fakeDataSize = 100; unsigned char fakeData[fakeDataSize]; memset(fakeData, 0xAA, fakeDataSize); IOCallback *pMKVFile = NULL; EbmlHead *pMKVHead = NULL; KaxSegment *pSegment = NULL; filepos_t segmentSize = 0; KaxSeekHead *pMetaSeek = NULL; EbmlVoid *pMetaSeekDummy = NULL; KaxCues *pAllCues = NULL; EbmlVoid *pAllCuesDummy = NULL; KaxTrackEntry *pVideoTrack = NULL; KaxTrackEntry *pSubtitleTrack = NULL; bool isFirstCluster; KaxCluster *pCluster; KaxBlockBlob *pBlockBlob; KaxBlockBlob *pLastVideoBlockBlob; uint64 clusterMinTimecode; uint64 firstFrameTimecode; uint64 lastFrameTimecode; KaxBlockGroup *pLastSubtitleBlockGroup; uint64 lastSubtitleTimecode; uint64 lastSubtitlePosition; unsigned char *pSubtitleData; size_t subtitleDataSize; try { // write the head of the file pMKVFile = new StdIOCallback(OUTPUT_FILE_NAME, MODE_CREATE); // Writing EBML test pMKVHead = new EbmlHead(); *static_cast<EbmlString *>(&GetChild<EDocType>(*pMKVHead)) = "matroska"; *static_cast<EbmlUInteger *>(&GetChild<EDocTypeVersion>(*pMKVHead)) = MATROSKA_VERSION; *static_cast<EbmlUInteger *>(&GetChild<EDocTypeReadVersion>(*pMKVHead)) = MATROSKA_VERSION; pMKVHead->Render(*pMKVFile, true); pSegment = new KaxSegment(); // size is unknown and will always be, we can render it right away // 5 octets can represent 2^35, it is wide enough for almost any file segmentSize = pSegment->WriteHead(*pMKVFile, 5, bWriteDefaultValues); // reserve some space for the Meta Seek writen at the end pMetaSeek = new KaxSeekHead(); pMetaSeekDummy = new EbmlVoid(); pMetaSeekDummy->SetSize(300); segmentSize += pMetaSeekDummy->Render(*pMKVFile, bWriteDefaultValues); // fill the mandatory Info section KaxInfo &segmentInfo = GetChild<KaxInfo>(*pSegment); *static_cast<EbmlUInteger *>(&GetChild<KaxTimecodeScale>(segmentInfo)) = TIMECODE_SCALE; *static_cast<EbmlFloat *>(&GetChild<KaxDuration>(segmentInfo)) = 0.0; // fix it later std::string muxingAppString = "libebml v"; muxingAppString += EbmlCodeVersion.c_str(); muxingAppString += " + libmatroska v"; muxingAppString += KaxCodeVersion.c_str(); UTFstring muxingAppUTFstring; muxingAppUTFstring.SetUTF8(muxingAppString); *(EbmlUnicodeString *)&GetChild<KaxMuxingApp>(segmentInfo) = muxingAppUTFstring; *(EbmlUnicodeString *)&GetChild<KaxWritingApp>(segmentInfo) = L"muxer"; GetChild<KaxDateUTC>(segmentInfo).SetEpochDate(time(NULL)); // FIXME: use the timecode of 1st frame unsigned char segmentUIDBuffer[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; GetChild<KaxSegmentUID>(segmentInfo).CopyBuffer(segmentUIDBuffer, 16); segmentSize += segmentInfo.Render(*pMKVFile, true); pMetaSeek->IndexThis(segmentInfo, *pSegment); KaxTracks &AllTracks = GetChild<KaxTracks>(*pSegment); pVideoTrack = &GetChild<KaxTrackEntry>(AllTracks); pSubtitleTrack = &GetNextChild<KaxTrackEntry>(AllTracks, *pVideoTrack); // fill video track params { pVideoTrack->SetGlobalTimecodeScale(TIMECODE_SCALE); *static_cast<EbmlUInteger *>(&GetChild<KaxTrackNumber>(*pVideoTrack)) = 1; *static_cast<EbmlUInteger *>(&GetChild<KaxTrackUID>(*pVideoTrack)) = 1; *static_cast<EbmlUInteger *>(&GetChild<KaxTrackType>(*pVideoTrack)) = track_video; *static_cast<EbmlString *>(&GetChild<KaxTrackLanguage>(*pVideoTrack)) = "eng"; *static_cast<EbmlString *>(&GetChild<KaxCodecID>(*pVideoTrack)) = "V_MPEG4/ISO/ASP"; pVideoTrack->EnableLacing(false); // video specific params KaxTrackVideo &videoTrackParameters = GetChild<KaxTrackVideo>(*pVideoTrack); *static_cast<EbmlUInteger *>(&GetChild<KaxVideoPixelWidth>(videoTrackParameters)) = 640; *static_cast<EbmlUInteger *>(&GetChild<KaxVideoPixelHeight>(videoTrackParameters)) = 480; } // fill subtitle track params { pSubtitleTrack->SetGlobalTimecodeScale(TIMECODE_SCALE); *static_cast<EbmlUInteger *>(&GetChild<KaxTrackNumber>(*pSubtitleTrack)) = 3; *static_cast<EbmlUInteger *>(&GetChild<KaxTrackUID>(*pSubtitleTrack)) = 3; *static_cast<EbmlUInteger *>(&GetChild<KaxTrackType>(*pSubtitleTrack)) = track_subtitle; *static_cast<EbmlString *>(&GetChild<KaxTrackLanguage>(*pSubtitleTrack)) = "eng"; *static_cast<EbmlString *>(&GetChild<KaxCodecID>(*pSubtitleTrack)) = "S_TEXT/UTF8"; pSubtitleTrack->EnableLacing(false); } segmentSize += AllTracks.Render(*pMKVFile, bWriteDefaultValues); pMetaSeek->IndexThis(AllTracks, *pSegment); pAllCues = new KaxCues(); pAllCues->SetGlobalTimecodeScale(TIMECODE_SCALE); pAllCuesDummy = new EbmlVoid(); pAllCuesDummy->SetSize(400); segmentSize += pAllCuesDummy->Render(*pMKVFile, bWriteDefaultValues); } catch (...) { // some error printf("ERROR: fail to startup\n"); if (pMKVFile != NULL) { pMKVFile->close(); } goto end; } isFirstCluster = true; pCluster = NULL; pBlockBlob = NULL, pLastVideoBlockBlob = NULL; clusterMinTimecode = 0ull; firstFrameTimecode = 0ull; lastFrameTimecode = 0ull; pLastSubtitleBlockGroup = NULL; lastSubtitlePosition = 0ull; pSubtitleData = NULL; subtitleDataSize = 0; try { for (int i = 0; i < 5; i++) { if (firstFrameTimecode == 0ull) { firstFrameTimecode = fakeTimecode; } // release the last cluster if (pCluster != NULL) { segmentSize += pCluster->Render(*pMKVFile, *pAllCues, bWriteDefaultValues); if (pLastSubtitleBlockGroup != NULL) { lastSubtitleTimecode = pLastSubtitleBlockGroup->GlobalTimecode(); lastSubtitlePosition = GetChild<KaxBlockDuration>(*pLastSubtitleBlockGroup).GetElementPosition(); pLastSubtitleBlockGroup = NULL; } if (isFirstCluster) { isFirstCluster = false; pMetaSeek->IndexThis(*pCluster, *pSegment); } pCluster->ReleaseFrames(); delete pCluster; pCluster = NULL; RecycleAllKaxBlockBlobs(); } // allocate a new cluster pCluster = new KaxCluster(); pCluster->SetParent(*pSegment); // mandatory to store references in this Cluster pCluster->InitTimecode(fakeTimecode / TIMECODE_SCALE, TIMECODE_SCALE); pLastVideoBlockBlob = NULL; clusterMinTimecode = fakeTimecode; for (int j = 0; j < 30; j++, fakeTimecode += 33000000ull) { // prepare a frame DataBuffer *pMyData = new DataBuffer((binary *)fakeData, fakeDataSize); KaxTrackEntry *pTrack = j == 0 ? pSubtitleTrack : pVideoTrack; // allocate current blob pBlockBlob = AllocateKaxBlockBlob((pTrack == pSubtitleTrack) ? BLOCK_BLOB_NO_SIMPLE : BLOCK_BLOB_ALWAYS_SIMPLE); pCluster->AddBlockBlob(pBlockBlob); pBlockBlob->SetParent(*pCluster); // add a frame pBlockBlob->AddFrameAuto(*pTrack, fakeTimecode, *pMyData, LACING_AUTO, j > 1 ? pLastVideoBlockBlob : NULL); if (pTrack == pSubtitleTrack) { if (pLastSubtitleBlockGroup != NULL) { // update the timecode of the last subtitle frame pLastSubtitleBlockGroup->SetBlockDuration(fakeTimecode - pLastSubtitleBlockGroup->GlobalTimecode()); } pBlockBlob->SetBlockDuration(1000 * 1000000000ull); // temporarily be the maximal value GetChild<KaxBlockDuration>((KaxBlockGroup &)*pBlockBlob).SetDefaultSize(8); // with a fixed size pLastSubtitleBlockGroup = &(KaxBlockGroup &)*pBlockBlob; if (lastSubtitlePosition != 0ull) { // re-calculate subtitleBlockDuration KaxBlockDuration subtitleBlockDuration; *static_cast<EbmlUInteger *>(&subtitleBlockDuration) = (fakeTimecode - lastSubtitleTimecode) / TIMECODE_SCALE; subtitleBlockDuration.SetDefaultSize(8); // correct subtitleBlockDuration uint64 currentPosition = pMKVFile->getFilePointer(); pMKVFile->setFilePointer(lastSubtitlePosition); subtitleBlockDuration.Render(*pMKVFile, false, true, true); pMKVFile->setFilePointer(currentPosition); lastSubtitlePosition = 0ull; } } // add a cue for any new cluster if ((pTrack == pVideoTrack) && (pLastVideoBlockBlob == NULL)) { pAllCues->AddBlockBlob(*pBlockBlob); } if (pTrack == pVideoTrack) { pLastVideoBlockBlob = pBlockBlob; } lastFrameTimecode = fakeTimecode; } // end for } // end for } catch (...) { // some error printf("ERROR: fail to append a frame\n"); } if (pCluster != NULL) { try { // release the last cluster segmentSize += pCluster->Render(*pMKVFile, *pAllCues, bWriteDefaultValues); pCluster->ReleaseFrames(); delete pCluster; pCluster = NULL; RecycleAllKaxBlockBlobs(); } catch (...) { // some error printf("ERROR: fail to store and release a cluster\n"); } try { // re-calculate segDuration & subtitleBlockDuration KaxDuration &segDuration = GetChild<KaxDuration>(GetChild<KaxInfo>(*pSegment)); *static_cast<EbmlFloat *>(&segDuration) = (lastFrameTimecode - firstFrameTimecode) / TIMECODE_SCALE; KaxBlockDuration subtitleBlockDuration; if (lastSubtitlePosition != 0ull) { *static_cast<EbmlUInteger *>(&subtitleBlockDuration) = (lastFrameTimecode - lastSubtitleTimecode) / TIMECODE_SCALE; subtitleBlockDuration.SetDefaultSize(8); } // correct segDuration & subtitleBlockDuration uint64 currentPosition = pMKVFile->getFilePointer(); pMKVFile->setFilePointer(segDuration.GetElementPosition()); segDuration.Render(*pMKVFile, false, true, true); if (lastSubtitlePosition != 0ull) { pMKVFile->setFilePointer(lastSubtitlePosition); subtitleBlockDuration.Render(*pMKVFile, false, true, true); lastSubtitlePosition = 0ull; } pMKVFile->setFilePointer(currentPosition); pAllCuesDummy->ReplaceWith(*pAllCues, *pMKVFile, bWriteDefaultValues); pMetaSeek->IndexThis(*pAllCues, *pSegment); pMetaSeekDummy->ReplaceWith(*pMetaSeek, *pMKVFile, bWriteDefaultValues); // let's assume we know the size of the Segment element // the size of the pSegment is also computed because mandatory elements we don't write ourself exist if (pSegment->ForceSize(segmentSize - pSegment->HeadSize())) { pSegment->OverwriteHead(*pMKVFile); } } catch (...) { // some error printf("ERROR: fail to close the file\n"); } pMKVFile->close(); } else { // error: empty file pMKVFile->close(); try { remove(OUTPUT_FILE_NAME); } catch (...) { // some error: don't care } } end: delete pSubtitleData; delete pCluster; delete pAllCuesDummy; delete pAllCues; delete pMetaSeekDummy; delete pMetaSeek; delete pSegment; delete pMKVHead; delete pMKVFile; return 0; }