1///////////////////////////////////////////////////////////////////////////
2//
3// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
4// Digital Ltd. LLC
5//
6// All rights reserved.
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
11// *       Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// *       Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17// *       Neither the name of Industrial Light & Magic nor the names of
18// its contributors may be used to endorse or promote products derived
19// from this software without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32//
33///////////////////////////////////////////////////////////////////////////
34
35
36//-----------------------------------------------------------------------------
37//
38//	class TimeCode
39//
40//-----------------------------------------------------------------------------
41
42#include <ImfTimeCode.h>
43#include "Iex.h"
44
45namespace Imf {
46
47
48TimeCode::TimeCode ()
49{
50    _time = 0;
51    _user = 0;
52}
53
54
55TimeCode::TimeCode
56    (int hours,
57     int minutes,
58     int seconds,
59     int frame,
60     bool dropFrame,
61     bool colorFrame,
62     bool fieldPhase,
63     bool bgf0,
64     bool bgf1,
65     bool bgf2,
66     int binaryGroup1,
67     int binaryGroup2,
68     int binaryGroup3,
69     int binaryGroup4,
70     int binaryGroup5,
71     int binaryGroup6,
72     int binaryGroup7,
73     int binaryGroup8)
74{
75    setHours (hours);
76    setMinutes (minutes);
77    setSeconds (seconds);
78    setFrame (frame);
79    setDropFrame (dropFrame);
80    setColorFrame (colorFrame);
81    setFieldPhase (fieldPhase);
82    setBgf0 (bgf0);
83    setBgf1 (bgf1);
84    setBgf2 (bgf2);
85    setBinaryGroup (1, binaryGroup1);
86    setBinaryGroup (2, binaryGroup2);
87    setBinaryGroup (3, binaryGroup3);
88    setBinaryGroup (4, binaryGroup4);
89    setBinaryGroup (5, binaryGroup5);
90    setBinaryGroup (6, binaryGroup6);
91    setBinaryGroup (7, binaryGroup7);
92    setBinaryGroup (8, binaryGroup8);
93}
94
95
96TimeCode::TimeCode
97    (unsigned int timeAndFlags,
98     unsigned int userData,
99     Packing packing)
100{
101    setTimeAndFlags (timeAndFlags, packing);
102    setUserData (userData);
103}
104
105
106TimeCode::TimeCode (const TimeCode &other)
107{
108    _time = other._time;
109    _user = other._user;
110}
111
112
113TimeCode &
114TimeCode::operator = (const TimeCode &other)
115{
116    _time = other._time;
117    _user = other._user;
118    return *this;
119}
120
121
122namespace {
123
124unsigned int
125bitField (unsigned int value, int minBit, int maxBit)
126{
127    int shift = minBit;
128    unsigned int mask = (~(~0U << (maxBit - minBit + 1)) << minBit);
129    return (value & mask) >> shift;
130}
131
132
133void
134setBitField (unsigned int &value, int minBit, int maxBit, unsigned int field)
135{
136    int shift = minBit;
137    unsigned int mask = (~(~0U << (maxBit - minBit + 1)) << minBit);
138    value = ((value & ~mask) | ((field << shift) & mask));
139}
140
141
142int
143bcdToBinary (unsigned int bcd)
144{
145    return int ((bcd & 0x0f) + 10 * ((bcd >> 4) & 0x0f));
146}
147
148
149unsigned int
150binaryToBcd (int binary)
151{
152    int units = binary % 10;
153    int tens = (binary / 10) % 10;
154    return (unsigned int) (units | (tens << 4));
155}
156
157
158} // namespace
159
160
161int
162TimeCode::hours () const
163{
164    return bcdToBinary (bitField (_time, 24, 29));
165}
166
167
168void
169TimeCode::setHours (int value)
170{
171    if (value < 0 || value > 23)
172	throw Iex::ArgExc ("Cannot set hours field in time code. "
173			   "New value is out of range.");
174
175    setBitField (_time, 24, 29, binaryToBcd (value));
176}
177
178
179int
180TimeCode::minutes () const
181{
182    return bcdToBinary (bitField (_time, 16, 22));
183}
184
185
186void
187TimeCode::setMinutes (int value)
188{
189    if (value < 0 || value > 59)
190	throw Iex::ArgExc ("Cannot set minutes field in time code. "
191			   "New value is out of range.");
192
193    setBitField (_time, 16, 22, binaryToBcd (value));
194}
195
196
197int
198TimeCode::seconds () const
199{
200    return bcdToBinary (bitField (_time, 8, 14));
201}
202
203
204void
205TimeCode::setSeconds (int value)
206{
207    if (value < 0 || value > 59)
208	throw Iex::ArgExc ("Cannot set seconds field in time code. "
209			   "New value is out of range.");
210
211    setBitField (_time, 8, 14, binaryToBcd (value));
212}
213
214
215int
216TimeCode::frame () const
217{
218    return bcdToBinary (bitField (_time, 0, 5));
219}
220
221
222void
223TimeCode::setFrame (int value)
224{
225    if (value < 0 || value > 59)
226	throw Iex::ArgExc ("Cannot set frame field in time code. "
227			   "New value is out of range.");
228
229    setBitField (_time, 0, 5, binaryToBcd (value));
230}
231
232
233bool
234TimeCode::dropFrame () const
235{
236    return bool (bitField (_time, 6, 6));
237}
238
239
240void
241TimeCode::setDropFrame (bool value)
242{
243    setBitField (_time, 6, 6, (unsigned int) !!value);
244}
245
246
247bool
248TimeCode::colorFrame () const
249{
250    return bool (bitField (_time, 7, 7));
251}
252
253
254void
255TimeCode::setColorFrame (bool value)
256{
257    setBitField (_time, 7, 7, (unsigned int) !!value);
258}
259
260
261bool
262TimeCode::fieldPhase () const
263{
264    return bool (bitField (_time, 15, 15));
265}
266
267
268void
269TimeCode::setFieldPhase (bool value)
270{
271    setBitField (_time, 15, 15, (unsigned int) !!value);
272}
273
274
275bool
276TimeCode::bgf0 () const
277{
278    return bool (bitField (_time, 23, 23));
279}
280
281
282void
283TimeCode::setBgf0 (bool value)
284{
285    setBitField (_time, 23, 23, (unsigned int) !!value);
286}
287
288
289bool
290TimeCode::bgf1 () const
291{
292    return bool (bitField (_time, 30, 30));
293}
294
295
296void
297TimeCode::setBgf1 (bool value)
298{
299    setBitField (_time, 30, 30, (unsigned int) !!value);
300}
301
302
303bool
304TimeCode::bgf2 () const
305{
306    return bool (bitField (_time, 31, 31));
307}
308
309
310void
311TimeCode::setBgf2 (bool value)
312{
313    setBitField (_time, 31, 31, (unsigned int) !!value);
314}
315
316
317int
318TimeCode::binaryGroup (int group) const
319{
320    if (group < 1 || group > 8)
321	throw Iex::ArgExc ("Cannot extract binary group from time code "
322		           "user data.  Group number is out of range.");
323
324    int minBit = 4 * (group - 1);
325    int maxBit = minBit + 3;
326    return int (bitField (_user, minBit, maxBit));
327}
328
329
330void
331TimeCode::setBinaryGroup (int group, int value)
332{
333    if (group < 1 || group > 8)
334	throw Iex::ArgExc ("Cannot extract binary group from time code "
335		           "user data.  Group number is out of range.");
336
337    int minBit = 4 * (group - 1);
338    int maxBit = minBit + 3;
339    setBitField (_user, minBit, maxBit, (unsigned int) value);
340}
341
342
343unsigned int
344TimeCode::timeAndFlags (Packing packing) const
345{
346    if (packing == TV50_PACKING)
347    {
348	unsigned int t = _time;
349
350	t &= ~((1 << 6) | (1 << 15) | (1 << 23) | (1 << 30) | (1 << 31));
351
352	t |= ((unsigned int) bgf0() << 15);
353	t |= ((unsigned int) bgf2() << 23);
354	t |= ((unsigned int) bgf1() << 30);
355	t |= ((unsigned int) fieldPhase() << 31);
356
357	return t;
358    }
359    if (packing == FILM24_PACKING)
360    {
361	return _time & ~((1 << 6) | (1 << 7));
362    }
363    else // packing == TV60_PACKING
364    {
365	return _time;
366    }
367}
368
369
370void
371TimeCode::setTimeAndFlags (unsigned int value, Packing packing)
372{
373    if (packing == TV50_PACKING)
374    {
375	_time = value &
376		 ~((1 << 6) | (1 << 15) | (1 << 23) | (1 << 30) | (1 << 31));
377
378	if (value & (1 << 15))
379	    setBgf0 (true);
380
381	if (value & (1 << 23))
382	    setBgf2 (true);
383
384	if (value & (1 << 30))
385	    setBgf1 (true);
386
387	if (value & (1 << 31))
388	    setFieldPhase (true);
389    }
390    else if (packing == FILM24_PACKING)
391    {
392	_time = value & ~((1 << 6) | (1 << 7));
393    }
394    else // packing == TV60_PACKING
395    {
396	_time = value;
397    }
398}
399
400
401unsigned int
402TimeCode::userData () const
403{
404    return _user;
405}
406
407
408void
409TimeCode::setUserData (unsigned int value)
410{
411    _user = value;
412}
413
414
415} // namespace Imf
416