/* ----------------------------------------- * p_replace_file_from_snapshot * ----------------------------------------- */ static void p_replace_file_from_snapshot(GapStoryUndoFileSnapshot* fileSnapshot) { FILE *fp; if(fileSnapshot == NULL) { return; } if(fileSnapshot->filename == NULL) { return; } if(g_file_test(fileSnapshot->filename, G_FILE_TEST_IS_REGULAR)) { if(fileSnapshot->mtimefile == gap_file_get_mtime(fileSnapshot->filename)) { /* the file still exists with same mtime stamp * no further action required in this case.. */ if(gap_debug) { printf("p_replace_file_from_snapshot:%s skipped due to EQUAL mtime:%d\n" , fileSnapshot->filename ,(int)fileSnapshot->mtimefile ); } return; } } if(gap_debug) { printf("p_replace_file_from_snapshot:%s\n", fileSnapshot->filename); } /* open write binary (create or replace) */ fp = g_fopen(fileSnapshot->filename, "wb"); if(fp != NULL) { fwrite(fileSnapshot->filecontent, fileSnapshot->filesize, 1, fp); fclose(fp); /* refresh the modification timestamp after rewrite */ fileSnapshot->mtimefile = gap_file_get_mtime(fileSnapshot->filename); } } /* end p_replace_file_from_snapshot */
/* ----------------------------------------- * p_create_file_snapshot * ----------------------------------------- */ static GapStoryUndoFileSnapshot* p_create_file_snapshot(char *filename) { GapStoryUndoFileSnapshot *fileSnapshot; char *filecontent; fileSnapshot = NULL; if(g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { gint32 filesize; filecontent = gap_file_load_file_len(filename, &filesize); if(filecontent != NULL) { fileSnapshot = g_new(GapStoryUndoFileSnapshot, 1); fileSnapshot->mtimefile = gap_file_get_mtime(filename); fileSnapshot->filename = g_strdup(filename); fileSnapshot->filecontent = filecontent; fileSnapshot->filesize = filesize; } } return (fileSnapshot); } /* end p_create_file_snapshot */
/* ------------------------------ * gap_player_cache_new_image_key * ------------------------------ */ gchar* gap_player_cache_new_image_key(const char *filename) { char *ckey; char *abs_filename; abs_filename = gap_file_build_absolute_filename(filename); ckey = g_strdup_printf("[@IMAGE]:%d:%s" , (int)gap_file_get_mtime(filename) , abs_filename ); g_free(abs_filename); return (ckey); } /* end gap_player_cache_new_image_key */
/* ------------------------------ * gap_player_cache_new_movie_key * ------------------------------ */ gchar * gap_player_cache_new_movie_key(const char *filename , gint32 framenr , gint32 seltrack , gdouble delace ) { char *ckey; char *abs_filename; abs_filename = gap_file_build_absolute_filename(filename); ckey = g_strdup_printf("[@MOVIE]:%d:%s:%06d:%d:%1.3f" , (int)gap_file_get_mtime(filename) , abs_filename , (int)framenr , (int)seltrack , (float)delace ); g_free(abs_filename); return (ckey); } /* end gap_player_cache_new_movie_key */
/* ---------------------------------------------------- * p_ffetch_get_open_gvahand * ---------------------------------------------------- * get videohandle from the cache of already open handles. * opens a new handle if there is no cache hit. * if too many handles are alredy open, the oldest one is closed. * note that the cached handles must not be used outside the * frame fetcher module. Therefore the closing old handles * can be done. */ static t_GVA_Handle* p_ffetch_get_open_gvahand(const char* filename, gint32 seltrack, const char *preferred_decoder) { gint32 l_idx; t_GVA_Handle *l_gvahand; GapFFetchGvahandCacheElem *gvc_ptr; GapFFetchGvahandCacheElem *gvc_last; GapFFetchGvahandCacheElem *gvc_new; GapFFetchGvahandCache *gvcache; if(filename == NULL) { printf("p_ffetch_get_open_gvahand: ** ERROR cant load video filename == NULL!\n"); return (NULL); } if(global_gvcache == NULL) { /* init the global_image cache */ global_gvcache = g_malloc0(sizeof(GapFFetchGvahandCache)); global_gvcache->gvc_list = NULL; global_gvcache->max_vid_cache = p_get_ffetch_max_gvc_cache_elements(); } gvcache = global_gvcache; gvc_last = gvcache->gvc_list; l_idx = 0; for(gvc_ptr = gvcache->gvc_list; gvc_ptr != NULL; gvc_ptr = (GapFFetchGvahandCacheElem *)gvc_ptr->next) { l_idx++; if((strcmp(filename, gvc_ptr->filename) == 0) && (seltrack == gvc_ptr->seltrack)) { /* videohandle found in cache, can skip opening a new handle */ return(gvc_ptr->gvahand); } gvc_last = gvc_ptr; } if(preferred_decoder) { l_gvahand = GVA_open_read_pref(filename , seltrack , 1 /* aud_track */ , preferred_decoder , FALSE /* use MMX if available (disable_mmx == FALSE) */ ); } else { l_gvahand = GVA_open_read(filename ,seltrack ,1 /* aud_track */ ); } if(l_gvahand) { GVA_set_fcache_size(l_gvahand, p_get_ffetch_gva_frames_to_keep_cached()); gvc_new = g_malloc0(sizeof(GapFFetchGvahandCacheElem)); gvc_new->filename = g_strdup(filename); gvc_new->seltrack = seltrack; gvc_new->mtime = gap_file_get_mtime(filename); gvc_new->gvahand = l_gvahand; if(gvcache->gvc_list == NULL) { gvcache->gvc_list = gvc_new; /* 1.st elem starts the list */ } else { gvc_last->next = (GapFFetchGvahandCacheElem *)gvc_new; /* add new elem at end of the cache list */ } if(l_idx > gvcache->max_vid_cache) { /* cache list has more elements than desired, * drop the 1.st (oldest) entry in the cache list * (this closes the droped handle) */ p_drop_gvahand_cache_elem1(gvcache); } } return(l_gvahand); } /* end p_ffetch_get_open_gvahand */
/* ---------------------------------------------------- * p_load_cache_image * ---------------------------------------------------- * load an image from cache or from file (in case image is not already cached) * in case the flag addToCache is TRUE the image will be automatically added * to the cache after read from file operation. */ static gint32 p_load_cache_image(const char* filename, gint32 ffetch_user_id, gboolean addToCache) { gint32 l_image_id; char *l_filename; gint32 *images; gint nimages; gint l_idi; gint l_number_of_cached_images; gint32 l_first_cached_image_id; GimpParasite *l_parasite; if(filename == NULL) { printf("p_load_cache_image: ** ERROR cant load filename == NULL! pid:%d\n", (int)gap_base_getpid()); return -1; } l_image_id = -1; l_first_cached_image_id = -1; l_number_of_cached_images = 0; images = gimp_image_list(&nimages); for(l_idi=0; l_idi < nimages; l_idi++) { l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_CACHE_PARASITE); if(l_parasite) { gint32 *mtime_ptr; gint32 *ffetch_id_ptr; gchar *filename_ptr; mtime_ptr = (gint32 *) l_parasite->data; ffetch_id_ptr = (gint32 *)&l_parasite->data[sizeof(gint32)]; filename_ptr = (gchar *)&l_parasite->data[sizeof(gint32) + sizeof(gint32)]; l_number_of_cached_images++; if (l_first_cached_image_id < 0) { l_first_cached_image_id = images[l_idi]; } if(strcmp(filename, filename_ptr) == 0) { gint32 mtimefile; mtimefile = gap_file_get_mtime(filename); if(mtimefile == *mtime_ptr) { /* image found in cache */ l_image_id = images[l_idi]; } else { /* image found in cache, but has changed modification timestamp * (delete from cache and reload) */ if(gap_debug) { printf("FrameFetcher: DELETE because mtime changed : (image_id:%d) ffetchId:%d name:%s mtimefile:%d mtimecache:%d pid:%d\n" , (int)images[l_idi] , (int)*ffetch_id_ptr , gimp_image_get_filename(images[l_idi]) , (int)mtimefile , (int)*mtime_ptr , (int)gap_base_getpid() ); } gap_image_delete_immediate(images[l_idi]); } l_idi = nimages -1; /* force break at next loop iteration */ } gimp_parasite_free(l_parasite); } } if(images) { g_free(images); } if (l_image_id >= 0) { if(gap_debug) { printf("FrameFetcher: p_load_cache_image CACHE-HIT :%s (image_id:%d) pid:%d\n" , filename, (int)l_image_id, (int)gap_base_getpid()); } return(l_image_id); } l_filename = g_strdup(filename); l_image_id = gap_lib_load_image(l_filename); if(gap_debug) { printf("FrameFetcher: loaded image from disk:%s (image_id:%d) pid:%d\n" , l_filename, (int)l_image_id, (int)gap_base_getpid()); } if((l_image_id >= 0) && (addToCache == TRUE)) { guchar *parasite_data; gint32 parasite_size; gint32 *parasite_mtime_ptr; gint32 *parasite_ffetch_id_ptr; gchar *parasite_filename_ptr; gint32 len_filename0; /* filename length including the terminating 0 */ if (l_number_of_cached_images > p_get_ffetch_max_img_cache_elements()) { /* the image cache already has more elements than desired, * drop the 1st cached image */ if(gap_debug) { printf("FrameFetcher: DELETE because cache is full: (image_id:%d) name:%s number_of_cached_images:%d pid:%d\n" , (int)l_first_cached_image_id , gimp_image_get_filename(l_first_cached_image_id) , (int)l_number_of_cached_images , (int)gap_base_getpid() ); } gap_image_delete_immediate(l_first_cached_image_id); } /* build parasite data including mtime and full filename with terminating 0 byte */ len_filename0 = strlen(filename) + 1; parasite_size = sizeof(gint32) + sizeof(gint32) + len_filename0; parasite_data = g_malloc0(parasite_size); parasite_mtime_ptr = (gint32 *)parasite_data; parasite_ffetch_id_ptr = (gint32 *)¶site_data[sizeof(gint32)]; parasite_filename_ptr = (gchar *)¶site_data[sizeof(gint32) + sizeof(gint32)]; *parasite_mtime_ptr = gap_file_get_mtime(filename); *parasite_ffetch_id_ptr = ffetch_user_id; memcpy(parasite_filename_ptr, filename, len_filename0); /* attach a parasite to mark the image as part of the gap image cache */ l_parasite = gimp_parasite_new(GAP_IMAGE_CACHE_PARASITE ,0 /* GIMP_PARASITE_PERSISTENT 0 for non persistent */ ,parasite_size ,parasite_data ); if(l_parasite) { gimp_image_parasite_attach(l_image_id, l_parasite); gimp_parasite_free(l_parasite); } g_free(parasite_data); } g_free(l_filename); return(l_image_id); } /* end p_load_cache_image */
/* ----------------------------------------------- * p_gap_delete_old_communication_files * ----------------------------------------------- * delete older communication files (if there are any) * this kind of cleanup tries to remove old comminication files * that may be still there * if a previous call to the master video encoder crashed or was killed. */ static void p_gap_delete_old_communication_files() { GDir *l_dirp; const gchar *l_entry; const char *l_directory; #define SECONDS_OF_ONE_HOUR 3600 l_directory = gimp_directory(); l_dirp = g_dir_open( l_directory, 0, NULL ); if(l_dirp) { time_t l_ref_mtime; l_ref_mtime = gap_base_get_current_time(); while ( (l_entry = g_dir_read_name( l_dirp )) != NULL ) { if(gap_debug) { printf("delete_old_communication_files: l_entry:%s\n", l_entry); } if (strncmp(l_entry, "gap_master_videoencoder_", strlen("gap_master_videoencoder_")) == 0) { char *l_filename; time_t l_mtime; time_t l_diff_time; gint32 l_pid; gint32 l_delete_flag; l_delete_flag = FALSE; l_filename = g_build_filename(l_directory, l_entry, NULL); l_pid = p_get_number_at_end_of_string(l_entry); l_mtime = gap_file_get_mtime(l_filename); l_diff_time = l_ref_mtime - l_mtime; if(l_pid >= 0) { /* note: detection of a not-running process works only on unix systems */ if(!gap_base_is_pid_alive(l_pid)) { l_delete_flag = TRUE; /* delete commounication files immediate when refered process is not running */ } else { /* assume old communication file when it did not change in the last hour * (for NON unix operating systems) */ if (l_diff_time > SECONDS_OF_ONE_HOUR) { l_delete_flag = TRUE; /* delete commounication files immediate when refered process is not running */ } } } if (l_delete_flag == TRUE) { if(gap_debug) { printf("DELETE file: %s l_ref_mtime:%d l_mtime:%d diff:%d l_pid:%d\n" , l_filename , (int)l_ref_mtime , (int)l_mtime , (int)l_diff_time , (int)l_pid ); } g_remove(l_filename); } g_free(l_filename); } } g_dir_close( l_dirp ); } } /* end p_gap_delete_old_communication_files */
/* ---------------------------------- * GVA_save_videoindex * ---------------------------------- * save videoindex to fileformat * (always save the new format with dts timecode) */ gboolean GVA_save_videoindex(t_GVA_Videoindex *vindex, const char *filename, const char *decoder_name) { FILE *fp; gint l_flen; if(vindex == NULL) { return (FALSE); } if(filename == NULL) { return (FALSE); } if(decoder_name == NULL) { return (FALSE); } if(vindex->videofile_uri) { g_free(vindex->videofile_uri); } vindex->videofile_uri = GVA_filename_to_uri(filename); if(vindex->videofile_uri == NULL) { return (FALSE); } vindex->mtime = gap_file_get_mtime(filename); /* use one or 2 extra bytes for one or 2 terminating \0 characters * (l_flen must be even number) */ l_flen = 1 + (strlen(vindex->videofile_uri) / 2); l_flen *= 2; g_snprintf(vindex->hdr.key_identifier, sizeof(vindex->hdr), "GVA_VIDEOINDEX"); g_snprintf(vindex->hdr.key_type, sizeof(vindex->hdr.key_type), "TYPE:"); switch(vindex->tabtype) { case GVA_IDX_TT_GDOUBLE: case GVA_IDX_TT_WITHOUT_TIMECODE_GDOUBLE: g_snprintf(vindex->hdr.val_type, sizeof(vindex->hdr.val_type), "GDOUBLE"); break; case GVA_IDX_TT_GINT64: case GVA_IDX_TT_WITHOUT_TIMECODE_GINT64: case GVA_IDX_TT_UNDEFINED: g_snprintf(vindex->hdr.val_type, sizeof(vindex->hdr.val_type), "GINT64"); break; } g_snprintf(vindex->hdr.key_step, sizeof(vindex->hdr.key_step), "STEP"); g_snprintf(vindex->hdr.val_step, sizeof(vindex->hdr.val_step), "%d", (int)vindex->stepsize); g_snprintf(vindex->hdr.key_size, sizeof(vindex->hdr.key_size), "SIZE"); g_snprintf(vindex->hdr.val_size, sizeof(vindex->hdr.val_size), "%d", (int)vindex->tabsize_used); g_snprintf(vindex->hdr.key_trak, sizeof(vindex->hdr.key_trak), "TRAK"); g_snprintf(vindex->hdr.val_trak, sizeof(vindex->hdr.val_trak), "%d", (int)vindex->track); g_snprintf(vindex->hdr.key_ftot, sizeof(vindex->hdr.key_ftot), "FTOT"); g_snprintf(vindex->hdr.val_ftot, sizeof(vindex->hdr.val_ftot), "%d", (int)vindex->total_frames); g_snprintf(vindex->hdr.key_deco, sizeof(vindex->hdr.key_deco), "DECO"); g_snprintf(vindex->hdr.val_deco, sizeof(vindex->hdr.val_deco), "%s", decoder_name); g_snprintf(vindex->hdr.key_mtim, sizeof(vindex->hdr.key_mtim), "MTIM"); g_snprintf(vindex->hdr.val_mtim, sizeof(vindex->hdr.val_mtim), "%ld", (long)vindex->mtime); g_snprintf(vindex->hdr.key_flen, sizeof(vindex->hdr.key_flen), "FLEN"); g_snprintf(vindex->hdr.val_flen, sizeof(vindex->hdr.val_flen), "%d", l_flen); vindex->videoindex_filename = p_build_videoindex_filename(filename, vindex->track, decoder_name); if(vindex->videoindex_filename) { fp = g_fopen(vindex->videoindex_filename, "wb"); if(fp) { /* write HEAEDR */ fwrite(&vindex->hdr, 1, sizeof(vindex->hdr), fp); /* write VIDEOFILE_URI + terminating \0 character(s) */ { gchar *uri_buffer; uri_buffer = g_malloc0(l_flen); g_snprintf(uri_buffer, l_flen, "%s", vindex->videofile_uri); fwrite(uri_buffer, 1, l_flen, fp); g_free(uri_buffer); } /* write offset table */ fwrite(vindex->ofs_tab, 1, sizeof(t_GVA_IndexElem) * vindex->tabsize_used, fp); fclose(fp); return(TRUE); } else { gint l_errno; l_errno = errno; g_message(_("ERROR: Failed to write videoindex file\n" "file: '%s'\n" "%s") , vindex->videoindex_filename , g_strerror (l_errno)); } } return (FALSE); } /* end GVA_save_videoindex */
/* ---------------------------------- * GVA_load_videoindex * ---------------------------------- * load videoindex from file * note that the old fileformat without dts timecode is supported for backwards compatibility. * the old format used lowercase type names "gint64" "gdouble" * the new format uses uppercase "GINT64" "GDOUBLE" */ t_GVA_Videoindex * GVA_load_videoindex(const char *filename, gint32 track, const char *decoder_name) { t_GVA_Videoindex *vindex; FILE *fp; gboolean success; gboolean delete_flag; if(gap_debug) { printf("GVA_load_videoindex START\n"); } if(filename == NULL) { return (NULL); } if(decoder_name == NULL) { return (NULL); } if(gap_debug) { printf("GVA_load_videoindex file:%s\n", filename); } success = FALSE; delete_flag = FALSE; vindex = GVA_new_videoindex(); if(vindex) { vindex->videoindex_filename = p_build_videoindex_filename(filename , track , decoder_name); if(vindex->videoindex_filename) { if(gap_debug) { printf("GVA_load_videoindex videoindex_filename:%s\n", vindex->videoindex_filename); } fp = g_fopen(vindex->videoindex_filename, "rb"); if(fp) { gint32 rd_len; gint32 rd_size; gint l_flen; gint32 l_mtime; rd_len = fread(&vindex->hdr, 1, sizeof(vindex->hdr), fp); if(rd_len) { vindex->stepsize = atol(vindex->hdr.val_step); vindex->tabsize_used = atol(vindex->hdr.val_size); vindex->track = atol(vindex->hdr.val_trak); vindex->total_frames = atol(vindex->hdr.val_ftot); vindex->tabsize_allocated = atol(vindex->hdr.val_size); vindex->mtime = atol(vindex->hdr.val_mtim); if(gap_debug) { printf("GVA_load_videoindex MTIM: vindex->hdr.val_mtim:%s\n" , vindex->hdr.val_mtim); } l_mtime = gap_file_get_mtime(filename); if(p_equal_mtime(l_mtime, vindex->mtime) == TRUE) { l_flen = atol(vindex->hdr.val_flen); if(l_flen > 0) { /* read the videofile_uri of the videofile */ vindex->videofile_uri = g_malloc0(l_flen); if(vindex->videofile_uri) { rd_len = fread(vindex->videofile_uri, 1, l_flen, fp); } else { fseek(fp, l_flen, SEEK_CUR); } } vindex->tabtype = GVA_IDX_TT_UNDEFINED; if(strcmp(vindex->hdr.val_type, "GINT64") == 0) { vindex->tabtype = GVA_IDX_TT_GINT64; } else if(strcmp(vindex->hdr.val_type, "GDOUBLE") == 0) { vindex->tabtype = GVA_IDX_TT_GDOUBLE; } else if(strcmp(vindex->hdr.val_type, "gint64") == 0) { vindex->tabtype = GVA_IDX_TT_WITHOUT_TIMECODE_GINT64; } else if(strcmp(vindex->hdr.val_type, "gdouble") == 0) { vindex->tabtype = GVA_IDX_TT_WITHOUT_TIMECODE_GDOUBLE; } rd_len = 0; rd_size = -1; switch(vindex->tabtype) { case GVA_IDX_TT_WITHOUT_TIMECODE_GINT64: /* old format */ case GVA_IDX_TT_WITHOUT_TIMECODE_GDOUBLE: /* old format */ delete_flag = TRUE; //rd_size = sizeof(t_GVA_IndexElem) * vindex->tabsize_used; //if(rd_size > 0) //{ // vindex->ofs_tab = g_new(t_GVA_IndexElem, vindex->tabsize_used); // if(vindex->ofs_tab) // { // int ii; // t_GVA_IndexElemWithoutTimecode *oldIndexformatTab; // // oldIndexformatTab = g_new(t_GVA_IndexElemWithoutTimecode, vindex->tabsize_used); // rd_len = fread(oldIndexformatTab, 1, rd_size, fp); // // /* migration loop to convert from old index format */ // for(ii=0; ii < vindex->tabsize_used; ii++) // { // vindex->ofs_tab[ii].timecode_dts = AV_NOPTS_VALUE; // vindex->ofs_tab[ii].uni.offset_gint64 = oldIndexformatTab[ii].uni.offset_gint64; // vindex->ofs_tab[ii].seek_nr = oldIndexformatTab[ii].seek_nr; // vindex->ofs_tab[ii].frame_length = oldIndexformatTab[ii].frame_length; // vindex->ofs_tab[ii].checksum = oldIndexformatTab[ii].checksum; // } // } //} break; case GVA_IDX_TT_GINT64: case GVA_IDX_TT_GDOUBLE: rd_size = sizeof(t_GVA_IndexElem) * vindex->tabsize_used; if(rd_size > 0) { vindex->ofs_tab = g_new(t_GVA_IndexElem, vindex->tabsize_used); if(vindex->ofs_tab) { rd_len = fread(vindex->ofs_tab, 1, rd_size, fp); } } break; default: break; } if(rd_len == rd_size) { success = TRUE; if(gap_debug) { p_debug_print_videoindex(vindex); printf("GVA_load_videoindex SUCCESS\n"); } } } else { delete_flag = TRUE; if(gap_debug) { printf("\nGVA_load_videoindex TOO OLD videoindex_filename:%s\n" , vindex->videoindex_filename); printf("GVA_load_videoindex MTIME_INDEX:%ld FILE:%ld\n" , (long)vindex->mtime , (long)l_mtime); } } } fclose(fp); if(delete_flag) { /* delete OLD videoindex * (that has become unusable because mtime does not match with videofile) */ g_remove(vindex->videoindex_filename); } } else { if(gap_debug) { printf("GVA_load_videoindex FILE NOT FOUND %s\n", vindex->videoindex_filename); } } } if(!success) { if(gap_debug) { printf("GVA_load_videoindex NO vindex available\n"); } GVA_free_videoindex(&vindex); } } return(vindex); } /* end GVA_load_videoindex */