| /* ------------------------------------------------------------------ |
| * Copyright (C) 2008 PacketVideo |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| * express or implied. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * ------------------------------------------------------------------- |
| */ |
| // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = |
| |
| // R T S P _ T I M E _ F O R M A T S |
| // ( T I M E / R A N G E R E P R E S E N T A T I O N S ) |
| |
| // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = |
| #ifndef RTSP_TIME_FORMAT_H |
| #define RTSP_TIME_FORMAT_H |
| |
| // - - Inclusion - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| #ifndef OSCL_BASE_H_INCLUDED |
| #include "oscl_base.h" |
| #endif |
| |
| #ifndef OSCL_INT64_UTILS_H_INCLUDED |
| #include "oscl_int64_utils.h" |
| #endif |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| |
| |
| |
| |
| // SMPTE time format allows two decimal digits for each field of the format |
| // The basic format is HH:MM:SS where HH = hours, MM = minutes, SS = seconds |
| // from the beginning of the presentation. It can optionally contain frame-level |
| // with the format HH:MM:SS:FF.ff where FF is the frame number and ff is the |
| // fractional part of the frame (i.e., subframe). |
| |
| struct SmpteTimeFormat |
| { |
| uint8 hours; |
| uint8 minutes; |
| uint8 seconds; |
| uint8 frames; |
| uint8 subframes; |
| }; |
| |
| // NPT (normal play time) format is represents the time offset from the beginning |
| // of the presentation either in seconds (including fractional seconds) or |
| // hours+minutes+secs (including fractional seconds). Unlike the SMPTE time format, |
| // the number of digits in the hours representation is arbitrary. When in the seconds-only |
| // format, the number of digits for that field is also arbitrary. We will allow |
| // 32 bits to hold these arbitrary length fields. The format is one of |
| // "now" | sec+[.frac_sec*] | H+:MM:SS[.frac_sec*] |
| // where "+" means one or more digits, "*" means zero or more digits, and "[ ]" means the |
| // field is optional and may not appear. |
| |
| struct NptSecFormat |
| { |
| uint32 sec; |
| uint32 milli_sec; //added as a sub for floating counterpart. |
| // float frac_sec; |
| }; |
| |
| struct NptHHMMSSFormat |
| { |
| uint32 hours; |
| uint8 min; |
| uint8 sec; |
| float frac_sec; |
| }; |
| |
| struct NptTimeFormat |
| { |
| enum NptFormatType { NOW, NPT_SEC, NPT_HHMMSS}; |
| |
| NptFormatType npt_format; |
| union |
| { |
| NptSecFormat npt_sec; |
| NptHHMMSSFormat npt_hhmmss; |
| }; |
| |
| }; |
| |
| struct PVNSPlaylistTimeFormat |
| { |
| // mbchar iPlaylistUrl[1024]; |
| uint32 iClipIndex; |
| uint32 sec; |
| uint32 milli_sec; |
| }; |
| |
| // Abs time format represents the absolute time value. The this represented as |
| // YYYYMMDD"T"HHMMSS[.frac_sec*]"Z" where YYYY is the four digit year, MM is the two digit |
| // month, DD is the two-digit day, "T" is just the T character, HH is the two-digit hour, |
| // MM is the two-digit minute, SS is the two-digit second, and finally "Z" is simply the Z character. |
| // The time value is based on the UTC (GMT) time coordinates. |
| |
| struct AbsTimeFormat |
| { |
| uint16 year; |
| uint8 month; |
| uint8 day; |
| uint8 hours; |
| uint8 min; |
| uint8 sec; |
| float frac_sec; |
| }; |
| |
| struct RtspRangeType |
| { |
| enum RtspRangeFormat { NPT_RANGE, SMPTE_RANGE, SMPTE_25_RANGE, |
| SMPTE_30_RANGE, |
| ABS_RANGE, |
| //#ifdef RTSP_PLAYLIST_SUPPORT |
| PLAYLIST_TIME_RANGE, |
| //#endif //#ifdef RTSP_PLAYLIST_SUPPORT |
| UNKNOWN_RANGE, INVALID_RANGE |
| }; |
| |
| RtspRangeFormat format; |
| bool start_is_set; |
| union |
| { |
| SmpteTimeFormat smpte_start; |
| NptTimeFormat npt_start; |
| AbsTimeFormat abs_start; |
| PVNSPlaylistTimeFormat playlist_start; |
| }; |
| |
| bool end_is_set; |
| union |
| { |
| SmpteTimeFormat smpte_end; |
| NptTimeFormat npt_end; |
| AbsTimeFormat abs_end; |
| PVNSPlaylistTimeFormat playlist_end; |
| }; |
| |
| //#ifdef RTSP_PLAYLIST_SUPPORT |
| mbchar iPlaylistUrl[1024]; |
| //#endif //#ifdef RTSP_PLAYLIST_SUPPORT |
| /***********************************************************************************/ |
| /*Function : int32 convertToMillisec(int32 &startTime, int32 &stopTime) */ |
| /* */ |
| /* */ |
| /*Parameters : int32 &startTime - Output */ |
| /* int32 &stopTime - Output */ |
| /* */ |
| /*Return values : 0 - if conversion was successful. */ |
| /* -1 - if conversion failed. */ |
| /* */ |
| /*Description : This utility function converts time in different formats to time */ |
| /*in milliseconds. In case of formats that don't fit in 32 bits after conversion, */ |
| /*the function returns an error code. The caller of the function can use the return*/ |
| /*code to decide whether to call the "calculateDelta" utility function. */ |
| /***********************************************************************************/ |
| int32 convertToMilliSec(int32 &startTime, int32 &stopTime) |
| { |
| const int32 MILLISEC_IN_HOUR = 3600000; |
| const int32 MILLISEC_IN_MIN = 60000; |
| const int32 MILLISEC_IN_SEC = 1000; |
| switch (format) |
| { |
| case RtspRangeType::NPT_RANGE: |
| { |
| if (start_is_set) |
| { |
| switch (npt_start.npt_format) |
| { |
| case NptTimeFormat::NOW: |
| { |
| startTime = 0; |
| } |
| break; |
| case NptTimeFormat::NPT_SEC: |
| { |
| startTime = (int32)(MILLISEC_IN_SEC * (npt_start.npt_sec.sec) + |
| npt_start.npt_sec.milli_sec); |
| } |
| break; |
| case NptTimeFormat::NPT_HHMMSS: |
| { |
| startTime = MILLISEC_IN_HOUR * npt_start.npt_hhmmss.hours + |
| MILLISEC_IN_MIN * npt_start.npt_hhmmss.min + |
| MILLISEC_IN_SEC * npt_start.npt_hhmmss.sec + |
| (int32)(MILLISEC_IN_SEC * npt_start.npt_hhmmss.frac_sec); |
| } |
| break; |
| } |
| } |
| else |
| { |
| startTime = 0; |
| } |
| if (end_is_set) |
| { |
| switch (npt_end.npt_format) |
| { |
| case NptTimeFormat::NOW: |
| { |
| stopTime = 0; |
| } |
| break; |
| case NptTimeFormat::NPT_SEC: |
| { |
| stopTime = (int32)(MILLISEC_IN_SEC * (npt_end.npt_sec.sec) + |
| npt_end.npt_sec.milli_sec); |
| } |
| break; |
| case NptTimeFormat::NPT_HHMMSS: |
| { |
| stopTime = MILLISEC_IN_HOUR * npt_end.npt_hhmmss.hours + |
| MILLISEC_IN_MIN * npt_end.npt_hhmmss.min + |
| MILLISEC_IN_SEC * npt_end.npt_hhmmss.sec + |
| (int32)(MILLISEC_IN_SEC * npt_end.npt_hhmmss.frac_sec); |
| } |
| break; |
| } |
| } |
| else |
| { |
| stopTime = 0; |
| } |
| } |
| break; |
| case RtspRangeType::SMPTE_RANGE: |
| case RtspRangeType::SMPTE_25_RANGE: |
| case RtspRangeType::SMPTE_30_RANGE: |
| { |
| if (start_is_set) |
| { |
| startTime = MILLISEC_IN_HOUR * smpte_start.hours + |
| MILLISEC_IN_MIN * smpte_start.minutes + |
| MILLISEC_IN_SEC * smpte_start.seconds; |
| } |
| else |
| { |
| startTime = 0; |
| } |
| if (end_is_set) |
| { |
| stopTime = MILLISEC_IN_HOUR * smpte_end.hours + |
| MILLISEC_IN_MIN * smpte_end.minutes + |
| MILLISEC_IN_SEC * smpte_end.seconds; |
| } |
| else |
| { |
| stopTime = 0; |
| } |
| } |
| break; |
| case RtspRangeType::ABS_RANGE: |
| { |
| if (start_is_set && end_is_set) |
| { |
| startTime = 0; |
| uint64 delta = calculateDelta(); |
| /* |
| *We return valid start and stop times(in millisec) if we see that the delta |
| *between the start and stop times fits in 32 bits. |
| */ |
| if (delta < (uint64)0xffffffff) |
| { |
| startTime = 0; |
| |
| stopTime = Oscl_Int64_Utils::get_uint64_lower32(delta); |
| |
| } |
| else |
| { |
| startTime = 0; |
| stopTime = 0; |
| return -1; |
| } |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| break; |
| case RtspRangeType::UNKNOWN_RANGE: |
| case RtspRangeType::INVALID_RANGE: |
| { |
| startTime = 0; |
| stopTime = 0; |
| return -1; |
| } |
| |
| default: |
| { |
| startTime = 0; |
| stopTime = 0; |
| return -1; |
| } |
| } |
| return 0; |
| } |
| |
| uint64 calculateDelta() |
| { |
| const int32 DAYS_IN_YEAR = 365; |
| const int32 DAYS_IN_LEAP_YEAR = 366; |
| const int32 HOURS_IN_DAY = 24; |
| const int32 MILLISEC_IN_HOUR = 3600000; |
| const int32 MILLISEC_IN_MIN = 60000; |
| const int32 MILLISEC_IN_SEC = 1000; |
| |
| int32 daysOfYear[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; |
| int32 daysOfLeapYear[] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}; |
| uint64 delta = 0; |
| uint64 startTime = 0; |
| uint64 stopTime = 0; |
| |
| /* |
| *Let's calculate the start time first. We need to find the number of days in the |
| *year first. |
| */ |
| if (start_is_set && end_is_set) |
| { |
| int32 numberOfDays = 0; |
| bool leap = leapYear(abs_start.year); |
| if (!leap) |
| { |
| numberOfDays = daysOfYear[abs_start.month-1]; |
| } |
| else |
| { |
| numberOfDays = daysOfLeapYear[abs_start.month-1]; |
| } |
| numberOfDays += abs_start.day - 1; |
| startTime = numberOfDays * HOURS_IN_DAY; |
| startTime += (uint32)abs_start.hours; |
| startTime *= MILLISEC_IN_HOUR; |
| startTime += abs_start.min * MILLISEC_IN_MIN + |
| abs_start.sec * MILLISEC_IN_SEC + |
| (int32)(abs_start.frac_sec * MILLISEC_IN_SEC); |
| /* |
| *Now, let's calculate the stop time. We use the start time's year as the reference |
| *year. |
| */ |
| numberOfDays = 0; |
| for (int32 ii = abs_start.year; ii < abs_end.year; ii++) |
| { |
| if (leapYear(ii)) |
| numberOfDays += DAYS_IN_LEAP_YEAR; |
| else |
| numberOfDays += DAYS_IN_YEAR; |
| } |
| leap = leapYear(abs_end.year); |
| if (!leap) |
| { |
| numberOfDays = daysOfYear[abs_end.month-1]; |
| } |
| else |
| { |
| numberOfDays = daysOfLeapYear[abs_end.month-1]; |
| } |
| |
| numberOfDays += abs_end.day - 1; |
| stopTime = numberOfDays * HOURS_IN_DAY; |
| stopTime += (uint32)abs_end.hours; |
| stopTime *= MILLISEC_IN_HOUR; |
| stopTime += abs_end.min * MILLISEC_IN_MIN + |
| abs_end.sec * MILLISEC_IN_SEC + |
| (int32)(abs_end.frac_sec * MILLISEC_IN_SEC); |
| |
| delta = stopTime - startTime; |
| } |
| else |
| { |
| return delta; |
| } |
| return delta; |
| } |
| |
| bool leapYear(int32 year) |
| { |
| if (year % 4 != 0) |
| return false; |
| else if (year % 400 == 0) |
| return true; |
| else if (year % 100 == 0) |
| return false; |
| else |
| return true; |
| } |
| }; |
| #endif |