1 /****************************************************************************
2 ** libmatroska : parse Matroska files, see http://www.matroska.org/
3 **
4 ** <file/class description>
5 **
6 ** Copyright (C) 2002-2010 Steve Lhomme. All rights reserved.
7 **
8 ** This library is free software; you can redistribute it and/or
9 ** modify it under the terms of the GNU Lesser General Public
10 ** License as published by the Free Software Foundation; either
11 ** version 2.1 of the License, or (at your option) any later version.
12 **
13 ** This library is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 ** Lesser General Public License for more details.
17 **
18 ** You should have received a copy of the GNU Lesser General Public
19 ** License along with this library; if not, write to the Free Software
20 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 **
22 ** See http://www.gnu.org/licenses/lgpl-2.1.html for LGPL licensing information.**
23 ** Contact license@matroska.org if any conditions of this licensing are
24 ** not clear to you.
25 **
26 **********************************************************************/
27
28 /*!
29 \file
30 \version \$Id: KaxCues.cpp 1265 2007-01-14 17:20:35Z mosu $
31 \author Steve Lhomme <robux4 @ users.sf.net>
32 */
33 #include <cassert>
34
35 #include "matroska/KaxCues.h"
36 #include "matroska/KaxCuesData.h"
37 #include "matroska/KaxContexts.h"
38 #include "ebml/EbmlStream.h"
39 #include "matroska/KaxDefines.h"
40 #include "matroska/KaxSemantic.h"
41
42 // sub elements
43 START_LIBMATROSKA_NAMESPACE
44
~KaxCues()45 KaxCues::~KaxCues()
46 {
47 assert(myTempReferences.empty()); // otherwise that means you have added references and forgot to set the position
48 }
49 /* deprecated and wrong
50 bool KaxCues::AddBlockGroup(const KaxBlockGroup & BlockRef)
51 {
52 // Do not add the element if it's already present.
53 std::vector<const KaxBlockBlob *>::iterator ListIdx;
54 KaxBlockBlob *BlockReference = new KaxBlockBlob(BLOCK_BLOB_NO_SIMPLE);
55 BlockReference->SetBlockGroup(*const_cast<KaxBlockGroup*>(&BlockRef));
56
57 for (ListIdx = myTempReferences.begin(); ListIdx != myTempReferences.end(); ListIdx++)
58 if (&(KaxBlockGroup&)*ListIdx == &BlockRef) {
59 delete BlockReference;
60 return true;
61 }
62
63 myTempReferences.push_back(BlockReference);
64 return true;
65 }
66 */
AddBlockBlob(const KaxBlockBlob & BlockReference)67 bool KaxCues::AddBlockBlob(const KaxBlockBlob & BlockReference)
68 {
69 // Do not add the element if it's already present.
70 bool present = std::any_of(myTempReferences.begin(), myTempReferences.end(),
71 [&](const KaxBlockBlob *myTempReference) { return myTempReference == &BlockReference; });
72 if (present) {
73 return true;
74 }
75
76 myTempReferences.push_back(&BlockReference);
77 return true;
78 }
79
PositionSet(const KaxBlockBlob & BlockReference)80 void KaxCues::PositionSet(const KaxBlockBlob & BlockReference)
81 {
82 // look for the element in the temporary references
83 auto it = std::find_if(myTempReferences.begin(), myTempReferences.end(),
84 [&](const KaxBlockBlob *myTempReference){ return myTempReference == &BlockReference; });
85
86 if (it != myTempReferences.end()) {
87 // found, now add the element to the entry list
88 auto & NewPoint = AddNewChild<KaxCuePoint>(*this);
89 NewPoint.PositionSet(BlockReference, GlobalTimecodeScale());
90 myTempReferences.erase(it);
91 }
92 }
93
PositionSet(const KaxBlockGroup & BlockRef)94 void KaxCues::PositionSet(const KaxBlockGroup & BlockRef)
95 {
96 // look for the element in the temporary references
97 auto it = std::find_if(myTempReferences.begin(), myTempReferences.end(),
98 [&](const KaxBlockBlob *myTempReference)
99 { const KaxInternalBlock &refTmp = *myTempReference;
100 return refTmp.GlobalTimecode() == BlockRef.GlobalTimecode()
101 && refTmp.TrackNum() == BlockRef.TrackNumber(); });
102
103 if(it != myTempReferences.end()) {
104 // found, now add the element to the entry list
105 auto & NewPoint = AddNewChild<KaxCuePoint>(*this);
106 NewPoint.PositionSet(**it, GlobalTimecodeScale());
107 myTempReferences.erase(it);
108 }
109 }
110
111 /*!
112 \warning Assume that the list has been sorted (Sort())
113 */
GetTimecodePoint(uint64 aTimecode) const114 const KaxCuePoint * KaxCues::GetTimecodePoint(uint64 aTimecode) const
115 {
116 uint64 TimecodeToLocate = aTimecode / GlobalTimecodeScale();
117 const KaxCuePoint * aPointPrev = nullptr;
118 uint64 aPrevTime = 0;
119 uint64 aNextTime = EBML_PRETTYLONGINT(0xFFFFFFFFFFFF);
120
121 EBML_MASTER_CONST_ITERATOR Itr;
122 for (Itr = begin(); Itr != end(); ++Itr) {
123 if (EbmlId(*(*Itr)) == EBML_ID(KaxCuePoint)) {
124 auto tmp = static_cast<const KaxCuePoint *>(*Itr);
125 // check the tile
126 auto aTime = static_cast<const KaxCueTime *>(tmp->FindFirstElt(EBML_INFO(KaxCueTime)));
127 if (aTime != nullptr) {
128 auto _Time = uint64(*aTime);
129 if (_Time > aPrevTime && _Time < TimecodeToLocate) {
130 aPrevTime = _Time;
131 aPointPrev = tmp;
132 }
133 if (_Time < aNextTime && _Time > TimecodeToLocate) {
134 aNextTime= _Time;
135 }
136 }
137 }
138 }
139
140 return aPointPrev;
141 }
142
GetTimecodePosition(uint64 aTimecode) const143 uint64 KaxCues::GetTimecodePosition(uint64 aTimecode) const
144 {
145 const KaxCuePoint * aPoint = GetTimecodePoint(aTimecode);
146 if (aPoint == nullptr)
147 return 0;
148
149 const KaxCueTrackPositions * aTrack = aPoint->GetSeekPosition();
150 if (aTrack == nullptr)
151 return 0;
152
153 return aTrack->ClusterPosition();
154 }
155
156 END_LIBMATROSKA_NAMESPACE
157