| /* 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., 51 Franklin St, Fifth Floor, | |
| * Boston, MA 02110-1301, 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 const int framerate_n[3] = { 3000, 25, 24 }; | |
| static const 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; | |
| } |