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