* ijksdl_thread.c
*****************************************************************************
*
* Copyright (c) 2013 Bilibili
* copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "ijksdl_timer.h"
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#if defined(__APPLE__)
#include <mach/mach_time.h>
static int g_is_mach_base_info_inited = 0;
static kern_return_t g_mach_base_info_ret = 0;
static mach_timebase_info_data_t g_mach_base_info;
int nanosleep(const struct timespec *, struct timespec *) __DARWIN_ALIAS_C(nanosleep);
#endif
#include "ijksdl_log.h"
void SDL_Delay(Uint32 ms)
{
int was_error;
struct timespec elapsed, tv;
elapsed.tv_sec = ms / 1000;
elapsed.tv_nsec = (ms % 1000) * 1000000;
do {
tv.tv_sec = elapsed.tv_sec;
tv.tv_nsec = elapsed.tv_nsec;
was_error = nanosleep(&tv, &elapsed);
} while (was_error);
}
Uint64 SDL_GetTickHR(void)
{
Uint64 clock;
#if defined(__ANDROID__)
struct timespec now;
#ifdef CLOCK_MONOTONIC_COARSE
clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
#else
clock_gettime(CLOCK_MONOTONIC_HR, &now);
#endif
clock = now.tv_sec * 1000 + now.tv_nsec / 1000000;
#elif defined(__APPLE__)
if (!g_is_mach_base_info_inited) {
g_mach_base_info_ret = mach_timebase_info(&g_mach_base_info);
g_is_mach_base_info_inited = 1;
}
if (g_mach_base_info_ret == 0) {
uint64_t now = mach_absolute_time();
clock = now * g_mach_base_info.numer / g_mach_base_info.denom / 1000000;
} else {
struct timeval now;
gettimeofday(&now, NULL);
clock = now.tv_sec * 1000 + now.tv_usec / 1000;
}
#endif
return (clock);
}
void SDL_ProfilerReset(SDL_Profiler* profiler, int max_sample)
{
memset(profiler, 0, sizeof(SDL_Profiler));
if (max_sample < 0)
profiler->max_sample = 3;
else
profiler->max_sample = max_sample;
}
void SDL_ProfilerBegin(SDL_Profiler* profiler)
{
profiler->begin_time = SDL_GetTickHR();
}
int64_t SDL_ProfilerEnd(SDL_Profiler* profiler)
{
int64_t delta = SDL_GetTickHR() - profiler->begin_time;
if (profiler->max_sample > 0) {
profiler->total_elapsed += delta;
profiler->total_counter += 1;
profiler->sample_elapsed += delta;
profiler->sample_counter += 1;
if (profiler->sample_counter > profiler->max_sample) {
profiler->sample_elapsed -= profiler->average_elapsed;
profiler->sample_counter -= 1;
}
if (profiler->sample_counter > 0) {
profiler->average_elapsed = profiler->sample_elapsed / profiler->sample_counter;
}
if (profiler->sample_elapsed > 0) {
profiler->sample_per_seconds = profiler->sample_counter * 1000.f / profiler->sample_elapsed;
}
}
return delta;
}
void SDL_SpeedSamplerReset(SDL_SpeedSampler *sampler)
{
memset(sampler, 0, sizeof(SDL_SpeedSampler));
sampler->capacity = sizeof(sampler->samples) / sizeof(Uint64);
}
float SDL_SpeedSamplerAdd(SDL_SpeedSampler *sampler, int enable_log, const char *log_tag)
{
Uint64 current = SDL_GetTickHR();
sampler->samples[sampler->next_index] = current;
sampler->next_index++;
sampler->next_index %= sampler->capacity;
if (sampler->count + 1 >= sampler->capacity) {
sampler->first_index++;
sampler->first_index %= sampler->capacity;
} else {
sampler->count++;
}
if (sampler->count < 2)
return 0;
float samples_per_second = 1000.0f * (sampler->count - 1) / (current - sampler->samples[sampler->first_index]);
if (enable_log && (sampler->last_log_time + 1000 < current || sampler->last_log_time > current)) {
sampler->last_log_time = current;
ALOGW("%s: %.2f\n", log_tag ? log_tag : "N/A", samples_per_second);
}
return samples_per_second;
}
void SDL_SpeedSampler2Reset(SDL_SpeedSampler2 *sampler, int sample_range)
{
memset(sampler, 0, sizeof(SDL_SpeedSampler2));
sampler->sample_range = sample_range;
sampler->last_profile_tick = (int64_t)SDL_GetTickHR();
}
int64_t SDL_SpeedSampler2Add(SDL_SpeedSampler2 *sampler, int quantity)
{
if (quantity < 0)
return 0;
int64_t sample_range = sampler->sample_range;
int64_t last_tick = sampler->last_profile_tick;
int64_t last_duration = sampler->last_profile_duration;
int64_t last_quantity = sampler->last_profile_quantity;
int64_t now = (int64_t)SDL_GetTickHR();
int64_t elapsed = (int64_t)llabs(now - last_tick);
if (elapsed < 0 || elapsed >= sample_range) {
sampler->last_profile_tick = now;
sampler->last_profile_duration = sample_range;
sampler->last_profile_quantity = quantity;
sampler->last_profile_speed = quantity * 1000 / sample_range;
return sampler->last_profile_speed;
}
int64_t new_quantity = last_quantity + quantity;
int64_t new_duration = last_duration + elapsed;
if (new_duration > sample_range) {
new_quantity = new_quantity * sample_range / new_duration;
new_duration = sample_range;
}
sampler->last_profile_tick = now;
sampler->last_profile_duration = new_duration;
sampler->last_profile_quantity = new_quantity;
if (new_duration > 0)
sampler->last_profile_speed = new_quantity * 1000 / new_duration;
return sampler->last_profile_speed;
}
int64_t SDL_SpeedSampler2GetSpeed(SDL_SpeedSampler2 *sampler)
{
int64_t sample_range = sampler->sample_range;
int64_t last_tick = sampler->last_profile_tick;
int64_t last_quantity = sampler->last_profile_quantity;
int64_t last_duration = sampler->last_profile_duration;
int64_t now = (int64_t)SDL_GetTickHR();
int64_t elapsed = (int64_t)llabs(now - last_tick);
if (elapsed < 0 || elapsed >= sample_range)
return 0;
int64_t new_quantity = last_quantity;
int64_t new_duration = last_duration + elapsed;
if (new_duration > sample_range) {
new_quantity = new_quantity * sample_range / new_duration;
new_duration = sample_range;
}
if (new_duration <= 0)
return 0;
return new_quantity * 1000 / new_duration;
}