| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							| 
									
										
										
										
											2018-06-01 18:19:39 +02:00
										 |  |  |  * of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This program 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 General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2008 Blender Foundation. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-06 15:42:22 +11:00
										 |  |  | /** \file \ingroup blendlib
 | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Time-Code string formatting | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-04 14:14:06 +02:00
										 |  |  | #include "BLI_utildefines.h"
 | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | #include "BLI_string.h"
 | 
					
						
							|  |  |  | #include "BLI_math.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_timecode.h"  /* own include */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "DNA_userdef_types.h"  /* for eTimecodeStyles only */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-30 20:35:59 +11:00
										 |  |  | #include "BLI_strict_flags.h"
 | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Generate timecode/frame number string and store in \a str | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-12-12 12:50:58 +11:00
										 |  |  |  * \param str: destination string | 
					
						
							|  |  |  |  * \param maxncpy: maximum number of characters to copy ``sizeof(str)`` | 
					
						
							|  |  |  |  * \param power: special setting for #View2D grid drawing, | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  |  *        used to specify how detailed we need to be | 
					
						
							| 
									
										
										
										
											2018-12-12 12:50:58 +11:00
										 |  |  |  * \param time_seconds: time total time in seconds | 
					
						
							|  |  |  |  * \param fps: frames per second, typically from the #FPS macro | 
					
						
							|  |  |  |  * \param timecode_style: enum from eTimecodeStyles | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  |  * \return length of \a str | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | size_t BLI_timecode_string_from_time( | 
					
						
							|  |  |  |         char *str, const size_t maxncpy, const int power, const float time_seconds, | 
					
						
							|  |  |  |         const double fps, const short timecode_style) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int hours = 0, minutes = 0, seconds = 0, frames = 0; | 
					
						
							|  |  |  | 	float time = time_seconds; | 
					
						
							|  |  |  | 	char neg[2] = {'\0'}; | 
					
						
							|  |  |  | 	size_t rlen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* get cframes */ | 
					
						
							|  |  |  | 	if (time < 0) { | 
					
						
							|  |  |  | 		/* correction for negative cfraues */ | 
					
						
							|  |  |  | 		neg[0] = '-'; | 
					
						
							|  |  |  | 		time = -time; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-04 15:53:56 +02:00
										 |  |  | 	if (time >= 3600.0f) { | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 		/* hours */ | 
					
						
							|  |  |  | 		/* XXX should we only display a single digit for hours since clips are
 | 
					
						
							|  |  |  | 		 *     VERY UNLIKELY to be more than 1-2 hours max? However, that would | 
					
						
							|  |  |  | 		 *     go against conventions... | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		hours = (int)time / 3600; | 
					
						
							| 
									
										
										
										
											2015-10-04 15:53:56 +02:00
										 |  |  | 		time = fmodf(time, 3600); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-04 15:53:56 +02:00
										 |  |  | 	if (time >= 60.0f) { | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 		/* minutes */ | 
					
						
							|  |  |  | 		minutes = (int)time / 60; | 
					
						
							| 
									
										
										
										
											2015-10-04 15:53:56 +02:00
										 |  |  | 		time = fmodf(time, 60); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (power <= 0) { | 
					
						
							|  |  |  | 		/* seconds + frames
 | 
					
						
							|  |  |  | 		 * Frames are derived from 'fraction' of second. We need to perform some additional rounding | 
					
						
							|  |  |  | 		 * to cope with 'half' frames, etc., which should be fine in most cases | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		seconds = (int)time; | 
					
						
							| 
									
										
										
										
											2017-09-27 11:13:03 +10:00
										 |  |  | 		frames = round_fl_to_int((float)(((double)time - (double)seconds) * fps)); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		/* seconds (with pixel offset rounding) */ | 
					
						
							| 
									
										
										
										
											2017-09-27 11:13:03 +10:00
										 |  |  | 		seconds = round_fl_to_int(time); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (timecode_style) { | 
					
						
							|  |  |  | 		case USER_TIMECODE_MINIMAL: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			/* - In general, minutes and seconds should be shown, as most clips will be
 | 
					
						
							|  |  |  | 			 *   within this length. Hours will only be included if relevant. | 
					
						
							|  |  |  | 			 * - Only show frames when zoomed in enough for them to be relevant | 
					
						
							|  |  |  | 			 *   (using separator of '+' for frames). | 
					
						
							|  |  |  | 			 *   When showing frames, use slightly different display to avoid confusion with mm:ss format | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			if (power <= 0) { | 
					
						
							|  |  |  | 				/* include "frames" in display */ | 
					
						
							|  |  |  | 				if (hours) { | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 					rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				else if (minutes) { | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 					rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d+%02d", neg, minutes, seconds, frames); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				else { | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 					rlen = BLI_snprintf_rlen(str, maxncpy, "%s%d+%02d", neg, seconds, frames); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else { | 
					
						
							|  |  |  | 				/* don't include 'frames' in display */ | 
					
						
							|  |  |  | 				if (hours) { | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 					rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, hours, minutes, seconds); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				else { | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 					rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d", neg, minutes, seconds); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		case USER_TIMECODE_SMPTE_MSF: | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-01-15 23:15:58 +11:00
										 |  |  | 			/* reduced SMPTE format that always shows minutes, seconds, frames.
 | 
					
						
							|  |  |  | 			 * Hours only shown as needed. */ | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 			if (hours) { | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 				rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			else { | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 				rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, minutes, seconds, frames); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		case USER_TIMECODE_MILLISECONDS: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			/* reduced SMPTE. Instead of frames, milliseconds are shown */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* precision of decimal part */ | 
					
						
							|  |  |  | 			const int ms_dp = (power <= 0) ? (1 - power) : 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* to get 2 digit whole-number part for seconds display
 | 
					
						
							|  |  |  | 			 * (i.e. 3 is for 2 digits + radix, on top of full length) */ | 
					
						
							|  |  |  | 			const int s_pad = ms_dp + 3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (hours) { | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 				rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, time); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			else { | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 				rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%0*.*f", neg, minutes, s_pad,  ms_dp, time); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-10-04 15:53:56 +02:00
										 |  |  | 		case USER_TIMECODE_SUBRIP: | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-01-15 23:15:58 +11:00
										 |  |  | 			/* SubRip, like SMPTE milliseconds but seconds and milliseconds
 | 
					
						
							|  |  |  | 			 * are separated by a comma, not a dot... */ | 
					
						
							| 
									
										
										
										
											2015-10-04 15:53:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			/* precision of decimal part */ | 
					
						
							|  |  |  | 			const int ms_dp = (power <= 0) ? (1 - power) : 1; | 
					
						
							| 
									
										
										
										
											2017-09-27 11:13:03 +10:00
										 |  |  | 			const int ms = round_fl_to_int((time - (float)seconds) * 1000.0f); | 
					
						
							| 
									
										
										
										
											2015-10-04 15:53:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			rlen = BLI_snprintf_rlen( | 
					
						
							|  |  |  | 			           str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 		case USER_TIMECODE_SECONDS_ONLY: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			/* only show the original seconds display */ | 
					
						
							|  |  |  | 			/* round to whole numbers if power is >= 1 (i.e. scale is coarse) */ | 
					
						
							|  |  |  | 			if (power <= 0) { | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 				rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			else { | 
					
						
							| 
									
										
										
										
											2017-09-27 11:13:03 +10:00
										 |  |  | 				rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds)); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		case USER_TIMECODE_SMPTE_FULL: | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			/* full SMPTE format */ | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 			rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return rlen; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 14:47:31 +10:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Generate time string and store in \a str | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param str: destination string | 
					
						
							|  |  |  |  * \param maxncpy: maximum number of characters to copy ``sizeof(str)`` | 
					
						
							|  |  |  |  * \param time_seconds: time total time in seconds | 
					
						
							|  |  |  |  * \return length of \a str | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | size_t BLI_timecode_string_from_time_simple( | 
					
						
							|  |  |  |         char *str, const size_t maxncpy, const double time_seconds) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	size_t rlen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* format 00:00:00.00 (hr:min:sec) string has to be 12 long */ | 
					
						
							|  |  |  | 	const int  hr = ( (int)  time_seconds) / (60 * 60); | 
					
						
							|  |  |  | 	const int min = (((int)  time_seconds) / 60 ) % 60; | 
					
						
							|  |  |  | 	const int sec = ( (int)  time_seconds) % 60; | 
					
						
							|  |  |  | 	const int hun = ( (int) (time_seconds   * 100.0)) % 100; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (hr) { | 
					
						
							|  |  |  | 		rlen = BLI_snprintf(str, maxncpy, "%.2d:%.2d:%.2d.%.2d", hr, min, sec, hun); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		rlen = BLI_snprintf(str, maxncpy, "%.2d:%.2d.%.2d", min, sec, hun); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return rlen; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Generate time string and store in \a str | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-12-12 12:50:58 +11:00
										 |  |  |  * \param str: destination string | 
					
						
							|  |  |  |  * \param maxncpy: maximum number of characters to copy ``sizeof(str)`` | 
					
						
							|  |  |  |  * \param power: special setting for #View2D grid drawing, | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  |  *        used to specify how detailed we need to be | 
					
						
							| 
									
										
										
										
											2018-12-12 12:50:58 +11:00
										 |  |  |  * \param time_seconds: time total time in seconds | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  |  * \return length of \a str | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note in some cases this is used to print non-seconds values. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2015-06-30 14:47:31 +10:00
										 |  |  | size_t BLI_timecode_string_from_time_seconds( | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  |         char *str, const size_t maxncpy, const int power, const float time_seconds) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	size_t rlen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* round to whole numbers if power is >= 1 (i.e. scale is coarse) */ | 
					
						
							|  |  |  | 	if (power <= 0) { | 
					
						
							| 
									
										
										
										
											2015-04-22 05:37:22 +10:00
										 |  |  | 		rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							| 
									
										
										
										
											2017-09-27 11:13:03 +10:00
										 |  |  | 		rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds)); | 
					
						
							| 
									
										
										
										
											2014-01-29 20:01:30 +11:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return rlen; | 
					
						
							|  |  |  | } |