/* -*- tab-width:4;c-file-style:"cc-mode"; -*- */ /* * index.c -- Stores info about keyframes for indexing. * Copyright (C) 2009 Mozilla Foundation. * * Contributed by Chris Pearce . * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include #include #include "index.h" #include "theorautils.h" #ifndef INT64_MAX #define INT64_MAX (~((ogg_int64_t)1 << 63)) #endif #ifndef INT64_MIN #define INT64_MIN ((ogg_int64_t)1 << 63) #endif void seek_index_init(seek_index* index, int packet_interval) { if (!index) return; memset(index, 0, sizeof(seek_index)); index->prev_packet_time = INT64_MIN; index->packet_interval = packet_interval; index->start_time = INT64_MAX; index->end_time = INT64_MIN; } void seek_index_clear(seek_index* index) { if (!index) return; if (index->packet_capacity && index->packets) { free(index->packets); index->packets = 0; index->packet_capacity = 0; } if (index->pages_capacity && index->pages) { free(index->pages); index->pages = 0; index->pages_capacity = 0; } } /* * Ensures that |*pointer|, which points to |capacity| elements of size * |element_size|, can contain |target_capacity| elements. This will realloc * |*pointer| if necessary, updating |*capacity| when it does so. * Returns 0 on success, -1 on failure (OOM). */ static int ensure_capacity(int* capacity, int target_capacity, size_t element_size, void** pointer) { size_t size = 0; ogg_int64_t new_capacity; if (*capacity > target_capacity) { /* We have capacity to accommodate the increase. No need to resize. */ return 0; } /* Not enough capacity to accommodate increase, resize. * Expand by 3/2 + 1. */ new_capacity = *capacity; while (new_capacity >= 0 && new_capacity <= target_capacity) { new_capacity = (new_capacity * 3) / 2 + 1; } if (new_capacity < 0 || new_capacity > INT_MAX || new_capacity * element_size > INT_MAX) { /* Integer overflow or otherwise ridiculous size. Fail. */ return -1; } size = (size_t)new_capacity * element_size; *pointer = realloc(*pointer, size); if (!*pointer) { return -1; } *capacity = new_capacity; return 0; } /* * Returns 0 on success, -1 on failure. */ int seek_index_record_sample(seek_index* index, int packetno, ogg_int64_t start_time, ogg_int64_t end_time, int is_keyframe) { keyframe_packet* packet; /* Update the end/start times, so we know the extremes of the indexed range. */ if (start_time < index->start_time) { index->start_time = start_time; } if (end_time > index->end_time) { index->end_time = end_time; } if (!is_keyframe || end_time < (index->prev_packet_time + index->packet_interval)) { /* Sample is not a keyframe, or appears too close to the previous keyframe packet, don't add it to the keyframe index. */ return 0; } if (ensure_capacity(&index->packet_capacity, index->packet_num + 1, sizeof(keyframe_packet), (void**)&index->packets) != 0) { /* Can't increase array size, probably OOM. */ return -1; } packet = &index->packets[index->packet_num]; packet->packetno = packetno; packet->start_time = start_time; index->packet_num++; index->prev_packet_time = start_time; return 0; } /* * Returns 0 on success, -1 on failure. */ int seek_index_record_page(seek_index* index, ogg_int64_t offset, ogg_uint32_t checksum, int packet_start_num) { keyframe_page* page; if (ensure_capacity(&index->pages_capacity, index->pages_num + 1, sizeof(keyframe_page), (void**)&index->pages) != 0) { /* Can't increase array size, probably OOM. */ return -1; } page = &index->pages[index->pages_num]; page->offset = offset; page->checksum = checksum; page->packet_start_num = packet_start_num; index->pages_num++; return 0; } void seek_index_set_max_keypoints(seek_index* index, int max_keypoints) { index->max_keypoints = max_keypoints; }