| /* 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; |
| } |