diff options
Diffstat (limited to 'ext/dv/gstsmptetimecode.c')
-rw-r--r-- | ext/dv/gstsmptetimecode.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/ext/dv/gstsmptetimecode.c b/ext/dv/gstsmptetimecode.c new file mode 100644 index 00000000..40a36d3f --- /dev/null +++ b/ext/dv/gstsmptetimecode.c @@ -0,0 +1,240 @@ +/* GStreamer + * Copyright (C) 2009 David A. Schleef <ds@schleef.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +/* + * Utility functions for handing SMPTE Time Codes, as described in + * SMPTE Standard 12M-1999. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstsmptetimecode.h" + +#define NTSC_FRAMES_PER_10_MINS (10*60*30 - 10*2 + 2) +#define NTSC_FRAMES_PER_HOUR (6*NTSC_FRAMES_PER_10_MINS) + +/** + * gst_smpte_time_code_from_frame_number: + * @system: SMPTE Time Code system + * @time_code: pointer to time code structure + * @frame_number: integer frame number + * + * Converts a frame number to a time code. + * + * Returns: TRUE if the conversion was successful + */ +gboolean +gst_smpte_time_code_from_frame_number (GstSMPTETimeCodeSystem system, + GstSMPTETimeCode * time_code, int frame_number) +{ + int ten_mins; + int n; + + g_return_val_if_fail (time_code != NULL, FALSE); + g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE); + + time_code->hours = 99; + time_code->minutes = 99; + time_code->seconds = 99; + time_code->frames = 99; + + if (frame_number < 0) + return FALSE; + + switch (system) { + case GST_SMPTE_TIME_CODE_SYSTEM_30: + if (frame_number >= 24 * NTSC_FRAMES_PER_HOUR) + return FALSE; + + ten_mins = frame_number / NTSC_FRAMES_PER_10_MINS; + frame_number -= ten_mins * NTSC_FRAMES_PER_10_MINS; + + time_code->hours = ten_mins / 6; + time_code->minutes = 10 * (ten_mins % 6); + + if (frame_number < 2) { + /* treat the first two frames of each ten minutes specially */ + time_code->seconds = 0; + time_code->frames = frame_number; + } else { + n = (frame_number - 2) / (60 * 30 - 2); + time_code->minutes += n; + frame_number -= n * (60 * 30 - 2); + + time_code->seconds = frame_number / 30; + time_code->frames = frame_number % 30; + } + break; + case GST_SMPTE_TIME_CODE_SYSTEM_25: + if (frame_number >= 24 * 60 * 60 * 25) + return FALSE; + + time_code->frames = frame_number % 25; + frame_number /= 25; + time_code->seconds = frame_number % 60; + frame_number /= 60; + time_code->minutes = frame_number % 60; + frame_number /= 60; + time_code->hours = frame_number; + break; + case GST_SMPTE_TIME_CODE_SYSTEM_24: + if (frame_number >= 24 * 60 * 60 * 24) + return FALSE; + + time_code->frames = frame_number % 24; + frame_number /= 24; + time_code->seconds = frame_number % 60; + frame_number /= 60; + time_code->minutes = frame_number % 60; + frame_number /= 60; + time_code->hours = frame_number; + break; + } + + return TRUE; +} + +/** + * gst_smpte_time_code_is_valid: + * @system: SMPTE Time Code system + * @time_code: pointer to time code structure + * + * Checks that the time code represents a valid time code. + * + * Returns: TRUE if the time code is valid + */ +gboolean +gst_smpte_time_code_is_valid (GstSMPTETimeCodeSystem system, + GstSMPTETimeCode * time_code) +{ + g_return_val_if_fail (time_code != NULL, FALSE); + g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE); + + if (time_code->hours < 0 || time_code->hours >= 24) + return FALSE; + if (time_code->minutes < 0 || time_code->minutes >= 60) + return FALSE; + if (time_code->seconds < 0 || time_code->seconds >= 60) + return FALSE; + if (time_code->frames < 0) + return FALSE; + + switch (system) { + case GST_SMPTE_TIME_CODE_SYSTEM_30: + if (time_code->frames >= 30) + return FALSE; + if (time_code->frames >= 2 || time_code->seconds > 0) + return TRUE; + if (time_code->minutes % 10 != 0) + return FALSE; + break; + case GST_SMPTE_TIME_CODE_SYSTEM_25: + if (time_code->frames >= 25) + return FALSE; + break; + case GST_SMPTE_TIME_CODE_SYSTEM_24: + if (time_code->frames >= 24) + return FALSE; + break; + } + return TRUE; +} + +/** + * gst_smpte_time_get_frame_number: + * @system: SMPTE Time Code system + * @frame_number: pointer to frame number + * @time_code: pointer to time code structure + * + * Converts the time code structure to a linear frame number. + * + * Returns: TRUE if the time code could be converted + */ +gboolean +gst_smpte_time_code_get_frame_number (GstSMPTETimeCodeSystem system, + int *frame_number, GstSMPTETimeCode * time_code) +{ + int frame = 0; + + g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE); + g_return_val_if_fail (time_code != NULL, FALSE); + + if (!gst_smpte_time_code_is_valid (system, time_code)) { + return FALSE; + } + + switch (system) { + case GST_SMPTE_TIME_CODE_SYSTEM_30: + frame = time_code->hours * NTSC_FRAMES_PER_HOUR; + frame += (time_code->minutes / 10) * NTSC_FRAMES_PER_10_MINS; + frame += (time_code->minutes % 10) * (30 * 60 - 2); + frame += time_code->seconds * 30; + break; + case GST_SMPTE_TIME_CODE_SYSTEM_25: + time_code->frames = + 25 * ((time_code->hours * 60 + time_code->minutes) * 60 + + time_code->seconds); + break; + case GST_SMPTE_TIME_CODE_SYSTEM_24: + time_code->frames = + 24 * ((time_code->hours * 60 + time_code->minutes) * 60 + + time_code->seconds); + break; + } + frame += time_code->frames; + + if (frame_number) { + *frame_number = frame; + } + + return TRUE; +} + +/** + * gst_smpte_time_get_timestamp: + * @system: SMPTE Time Code system + * @time_code: pointer to time code structure + * + * Converts the time code structure to a timestamp. + * + * Returns: Time stamp for time code, or GST_CLOCK_TIME_NONE if time + * code is invalid. + */ +GstClockTime +gst_smpte_time_code_get_timestamp (GstSMPTETimeCodeSystem system, + GstSMPTETimeCode * time_code) +{ + int frame_number; + + g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), + GST_CLOCK_TIME_NONE); + g_return_val_if_fail (time_code != NULL, GST_CLOCK_TIME_NONE); + + if (gst_smpte_time_code_get_frame_number (system, &frame_number, time_code)) { + static int framerate_n[3] = { 3000, 25, 24 }; + static int framerate_d[3] = { 1001, 1, 1 }; + + return gst_util_uint64_scale (frame_number, + GST_SECOND * framerate_d[system], framerate_n[system]); + } + + return GST_CLOCK_TIME_NONE; +} |