static int httplive_delete(HTTPLIVE_DATA_T *pLive) { char path[VSX_MAX_PATH_LEN]; char buf[VSX_MAX_PATH_LEN]; struct stat st; httplive_purgetsfiles(pLive, 0xffffffff); // // Delete the playlist // if(snprintf(buf, sizeof(buf), "%s"HTTPLIVE_PL_NAME_EXT, pLive->fileprefix) >= 0) { mediadb_prepend_dir(pLive->dir, buf, path, sizeof(path)); if(fileops_stat(path, &st) == 0 && fileops_DeleteFile(path) != 0) { LOG(X_ERROR("Failed to delete '%s'"), path); } } // // Delete any multi-bitrate playlist // if(snprintf(buf, sizeof(buf), "%s"HTTPLIVE_PL_NAME_EXT, HTTPLIVE_MULTIBITRATE_NAME_PRFX) >= 0) { mediadb_prepend_dir(pLive->dir, buf, path, sizeof(path)); if(fileops_stat(path, &st) == 0 && fileops_DeleteFile(path) != 0) { LOG(X_ERROR("Failed to delete '%s'"), path); } } return 0; }
int mediadb_prepend_dir2(const char *dir1, const char *dir2, const char *path, char *out, unsigned int lenout) { int rc; char tmp[VSX_MAX_PATH_LEN]; if((rc = mediadb_prepend_dir(dir1, dir2, tmp, sizeof(tmp)) >= 0)) { rc = mediadb_prepend_dir(tmp, path, out, lenout); } return rc; }
static float getMediaRateBps(const MPD_CREATE_CTXT_T *pCtxt, unsigned int outidx, const MPD_ADAPTATION_T *pAdaptation) { FILE_OFFSET_T size = 0; struct stat st; float durationSec = 0; float rateBps = 0; char tmp[256]; char mediaPath[VSX_MAX_PATH_LEN]; mpd_format_path(tmp, sizeof(tmp), mpd_format_path_prefix, outidx, pCtxt->init.outfileprefix, pAdaptation->pMedia->mediaUniqIdstr, pCtxt->init.outfilesuffix, pAdaptation->padaptationTag); mediadb_prepend_dir(pAdaptation->pMedia->mediaDir, tmp, mediaPath, sizeof(mediaPath)); if(mediaPath[0] != '\0' && fileops_stat(mediaPath, &st) == 0) { size = (FILE_OFFSET_T) st.st_size; } //LOG(X_DEBUG("GETMEDIARATEBPS mediaPath: '%s', size: %lld"), mediaPath, size); if(pAdaptation->pMedia->timescale > 0) { durationSec = (float) ((double) pAdaptation->pMedia->duration / pAdaptation->pMedia->timescale); } if(durationSec > 0) { rateBps = 8 * size / durationSec; } return rateBps; }
static int httplive_updatepl(HTTPLIVE_DATA_T *pLive) { int rc = 0; unsigned int idxMin; char filename[64]; char path[VSX_MAX_PATH_LEN]; if(pLive->curIdx <= 0) { return 0; } if(pLive->curIdx <= pLive->indexCount) { idxMin = 0; } else { idxMin = pLive->curIdx - pLive->indexCount; } snprintf(filename, sizeof(filename), "%s"HTTPLIVE_PL_NAME_EXT, pLive->fileprefix); mediadb_prepend_dir(pLive->dir, filename, path, sizeof(path)); rc = httplive_writepl(path, idxMin, pLive->curIdx - 1, pLive); // // Write the master playlist containing bitrate specific playlists // only when multi xcode output is set // if(pLive->curIdx == 1 && pLive->outidx == 0) { update_multibr(pLive); if(pLive->count > 1) { snprintf(filename, sizeof(filename), "%s"HTTPLIVE_PL_NAME_EXT, HTTPLIVE_MULTIBITRATE_NAME_PRFX); mediadb_prepend_dir(pLive->dir, filename, path, sizeof(path)); httplive_writepl_multibr(path, pLive); } } return rc; }
static int clearTn(const char *pathMedia, const char *pathDb, const FILE_LIST_T *pFileList) { DIR *pdir; struct dirent *direntry; char buf[VSX_MAX_PATH_LEN]; char buf2[VSX_MAX_PATH_LEN]; size_t sz,sz2; if(!(pdir = fileops_OpenDir(pathDb))) { return -1; } buf[sizeof(buf) - 1] = '\0'; while((direntry = fileops_ReadDir(pdir))) { if(!(direntry->d_type & DT_DIR)) { // "_tn[idx].jpg" if((sz = strlen(direntry->d_name)) > 9 && (!strncasecmp(&direntry->d_name[sz - 4], ".jpg", 4) || !strncasecmp(&direntry->d_name[sz - VSXTMP_EXT_LEN], VSXTMP_EXT, VSXTMP_EXT_LEN) || !strncasecmp(&direntry->d_name[sz - NOTN_EXT_LEN], NOTN_EXT, NOTN_EXT_LEN))) { strncpy(buf, direntry->d_name, sizeof(buf) - 1); for(sz2 = sz - 4; sz2 > sz - 12; sz2--) { if(buf[sz2] == '_') { break; } } buf[sz2] = '\0'; //fprintf(stdout, "check '%s' '%s'\n", buf, direntry->d_name); if(file_list_find(pFileList, buf) == NULL) { mediadb_prepend_dir(pathDb, direntry->d_name, buf2, sizeof(buf)); LOG(X_DEBUG("Removing thumbnail '%s'\n"), buf2); if(fileops_DeleteFile(buf2) != 0) { LOG(X_ERROR("Failed to delete thumbnail %s"), buf2); } } } } } fileops_CloseDir(pdir); return 0; }
static int write_mpd_path(const MPD_CREATE_CTXT_T *pCtxt, int outidx, DASH_MPD_TYPE_T mpdType, char *buf, unsigned int szbuf) { int rc = 0; char stroutidx[32]; char mpdfilename[VSX_MAX_PATH_LEN]; if(outidx >= 0) { snprintf(stroutidx, sizeof(stroutidx), "%d", outidx + 1); } else { stroutidx[0] = '\0'; } snprintf(mpdfilename, sizeof(mpdfilename), "%s%s", stroutidx, mpd_type_to_filename(mpdType)); mediadb_prepend_dir(pCtxt->init.outdir, mpdfilename, buf, szbuf); return rc; }
static int iterate_subdirs(const MEDIADB_DESCR_T *pMediaDb, const char *pathDb, const char *pathMedia, int level, unsigned int iterIdx) { DIR *pdir; FILE_LIST_T fileList; FILE_LIST_ENTRY_T *pFileListEntry; struct dirent *direntry; char bufMedia[VSX_MAX_PATH_LEN]; char bufDb[VSX_MAX_PATH_LEN]; char tmpfile[VSX_MAX_PATH_LEN]; int rc = 0; int rcsub = 0; int fileListChanged = 0; int numTnCreated = 0; int highestTn; struct stat st; //fprintf(stdout, "%d dir:'%s' '%s'\n", level, pathDb, pathMedia); // // TODO: escape invalid chars in pathnames ' , & # $ ' // if(level >= SRVMEDIA_MAX_LEVELS) { LOG(X_WARNING("Path '%s' exceeded max number of subdirs under %s"), pathMedia, pMediaDb->mediaDir); return -1; } if(!(pdir = fileops_OpenDir(pathMedia))) { return -1; } memset(&fileList, 0, sizeof(fileList)); file_list_read(pathDb, &fileList); strncpy(fileList.pathmedia, pathMedia, sizeof(fileList.pathmedia) - 1); while((direntry = fileops_ReadDir(pdir)) && g_proc_exit == 0) { //fprintf(stdout, "- %d %s\n", level, direntry->d_name); if(direntry->d_type & DT_DIR) { if(mediadb_isvalidDirName(pMediaDb, direntry->d_name)) { if(mediadb_prepend_dir(pathDb, direntry->d_name, bufDb, sizeof(bufDb)) < 0) { LOG(X_WARNING("Unable to concatenate subdir %s %s"), bufDb, direntry->d_name); } else if(mediadb_prepend_dir(pathMedia, direntry->d_name, bufMedia, sizeof(bufMedia)) < 0) { LOG(X_WARNING("Unable to concatenate subdir %s %s"), bufMedia, direntry->d_name); } else { if(numTnCreated > 1) { file_list_write(pathDb, &fileList); } if((rcsub = iterate_subdirs(pMediaDb, bufDb, bufMedia, level+1, iterIdx)) < 0) { rc = rcsub; } if(g_proc_exit != 0) { break; } } } else if(direntry->d_name[0] != '.') { //fprintf(stderr, "skipping directory '%s'\n", direntry->d_name); } } else if(mediadb_isvalidFileName(pMediaDb, direntry->d_name, 1, 0)) { //fprintf(stdout, "%d media file %s '%s'\n", level, pathMedia, direntry->d_name); if(fileops_stat(pathDb, &st) != 0 && mediadb_mkdirfull(pMediaDb->dbDir, pathDb) < 0) { continue; } if(mediadb_prepend_dir(pathDb, direntry->d_name, bufDb, sizeof(bufDb)) < 0) { LOG(X_ERROR("Unable to concatenate subdir %s %s"), bufDb, direntry->d_name); continue; } else if(mediadb_prepend_dir(pathMedia, direntry->d_name, bufMedia, sizeof(bufMedia)) < 0) { LOG(X_ERROR("Unable to concatenate subdir %s %s"), bufMedia, direntry->d_name); continue; } if(update_fileentry(&fileList, direntry->d_name, bufMedia, &pFileListEntry) > 0) { LOG(X_DEBUG("'%s' changed ('%s')"), direntry->d_name, pFileListEntry->name); fileListChanged = 1; if(pFileListEntry->numTn < 0) { pFileListEntry->numTn = 0; } } if(pMediaDb->avcthumb && pFileListEntry && pFileListEntry->vstr[0] != '\0' && pFileListEntry->numTn != -1) { // // On very first iteration, check all thumbnails // snprintf(tmpfile, sizeof(tmpfile), "%s%s."NOTN_EXT, bufDb, pMediaDb->tn_suffix); if(fileops_stat(tmpfile, &st) == 0 && iterIdx > 0) { // // Ignore thumbnail creation if the .notn file has been // previously created on an error condition // } else // // Update thumbnail info // if((highestTn = createTn(pMediaDb, pFileListEntry, bufMedia, bufDb, pFileListEntry->numTn, 1)) > pFileListEntry->numTn || highestTn == -1) { pFileListEntry->numTn = highestTn; fileListChanged = 1; // Periodically update the db file if(numTnCreated > 10) { file_list_write(pathDb, &fileList); numTnCreated = 0; } } } } else { //fprintf(stdout, "skipping %s '%s'\n", pathMedia, direntry->d_name); } } fileops_CloseDir(pdir); if(g_proc_exit == 0) { if(file_list_removeunmarked(&fileList) || fileListChanged) { LOG(X_DEBUG("Writing file index in %s"), pathDb); //fprintf(stdout, "level:%u\n", level); file_list_write(pathDb, &fileList); } // //Remove thumbnails which are not included in the fileList // clearTn(pathMedia, pathDb, &fileList); } file_list_close(&fileList); return rc; }
DIR_ENTRY_LIST_T *direntry_getentries(const MEDIADB_DESCR_T *pMediaDb, const char *dir, const char *fidxdir, const char *searchstr, int includedirs, unsigned int startidx, unsigned int max, enum DIR_SORT sort) { DIR *pdir; int rc = 0; struct dirent *direntry; char path[VSX_MAX_PATH_LEN]; struct stat st; int addEntry; FILE_LIST_T fileList; FILE_LIST_ENTRY_T *pFileEntry = NULL; META_FILE_T metaFile; DIR_ENTRY_LIST_T *pEntryList = NULL; DIR_ENTRY_T entry; DIR_ENTRY_T *pEntry; const char *pdispname; unsigned int idx = 0; unsigned int cnt = 0; unsigned int cntInDir = 0; COMPARE_DIR_ENTRY compareFunc = direntry_getcompfunc(sort); VSX_DEBUG_MGR( LOG(X_DEBUG("MGR - direntry_getentries dir: '%s', fidxdir: '%s', searchstr: '%s', " "includedirs: %d, startidx: %d, max: %d"), dir, fidxdir, searchstr, includedirs, startidx, max)); if(!(pdir = fileops_OpenDir(dir))) { return NULL; } memset(&fileList, 0, sizeof(fileList)); if(fidxdir) { file_list_read(fidxdir, &fileList); } // // Read the directory wide metafile to get a list of 'ignore' entries // memset(&metaFile, 0, sizeof(metaFile)); mediadb_prepend_dir(dir, METAFILE_DEFAULT, path, sizeof(path)); if(fileops_stat(path, &st) == 0) { metafile_open(path, &metaFile, 1, 1); } while((direntry = fileops_ReadDir(pdir))) { VSX_DEBUG_MGR( LOG(X_DEBUGV("MGR - direntry_getentries d_name: '%s', isdir: %d"), direntry->d_name, (direntry->d_type & DT_DIR)) ); if(is_entry_ignored(metaFile.pignoreList, direntry->d_name)) { continue; } if(!(pdispname = find_entry_description(metaFile.pDescriptionList, direntry->d_name))) { pdispname = direntry->d_name; } if(searchstr && !is_match_search(pdispname, NULL, searchstr)) { continue; } memset(&entry, 0, sizeof(entry)); strncpy(entry.d_name, direntry->d_name, sizeof(entry.d_name) - 1); if(pdispname != direntry->d_name) { strncpy(entry.displayname, pdispname, sizeof(entry.displayname) - 1); } entry.d_type = direntry->d_type; addEntry = 0; if(direntry->d_type & DT_DIR) { if(includedirs && mediadb_isvalidDirName(pMediaDb, direntry->d_name)) { addEntry = 1; } } else if(mediadb_isvalidFileName(pMediaDb, direntry->d_name, 1, 1)) { mediadb_prepend_dir(dir, direntry->d_name, path, sizeof(path)); if(fileops_stat(path, &st) == 0) { entry.size = st.st_size; //entry.tm = st.st_mtime; entry.tm = st.st_ctime; if(fidxdir && (pFileEntry = file_list_find(&fileList, direntry->d_name))) { entry.numTn = pFileEntry->numTn; entry.duration = pFileEntry->duration; } addEntry = 1; } } if(addEntry) { VSX_DEBUG_MGR( LOG(X_DEBUGV("MGR - direntry_getentries add d_name: '%s', isdir: %d"), direntry->d_name, (direntry->d_type & DT_DIR)) ); if(compareFunc || (idx >= startidx && (max == 0 || cnt < max))) { if(cnt >= DIR_ENTRY_LIST_BUFNUM) { LOG(X_WARNING("Not showing more than %d entries in %s"), cnt, dir); break; } else if(!(pEntry = direntry_addsorted(&pEntryList, &entry, compareFunc))) { LOG(X_ERROR("Failed to add directory entry '%s' to list"), direntry->d_name); rc = -1; break; } cnt++; } idx++; cntInDir++; } } // // Since when a sort is requested we have to sort every entry in the directory. Now we can move the head pointer // to the first desired entry // if(pEntryList && compareFunc && startidx > 0) { pEntry = pEntryList->pHead; for(idx = 0; idx < startidx; idx++) { pEntry = pEntry->pnext; cnt--; } pEntryList->pHead = pEntry; if(cnt > max) { cnt = max; } //fprintf(stderr, "moved phead to %s, cnt:%d, cntInDir:%d\n", pEntryList->pHead ? pEntryList->pHead->d_name : NULL, cnt, cntInDir); } fileops_CloseDir(pdir); if(fidxdir) { file_list_close(&fileList); } metafile_close(&metaFile); if(rc == 0 && !pEntryList) { // If the user requested an index out of bounds, return an empty list with // a valid cntTotalInDir pEntryList = (DIR_ENTRY_LIST_T *) avc_calloc(1, sizeof(DIR_ENTRY_LIST_T)); } if(pEntryList) { pEntryList->cntTotal = cnt; pEntryList->cntTotalInDir = cntInDir; } //if(pEntryList) fprintf(stderr, "DIR '%s' num:%d numAlloc:%d pnext:0x%x TOTAL:%d/%d\n", dir, pEntryList->num, pEntryList->numAlloc, pEntryList->pnext, pEntryList->cntTotal, pEntryList->cntTotalInDir); return pEntryList; }
int http_purge_segments(const char *dirpath, const char *fileprefix, const char *ext, unsigned int idxmin, int purgeNonIdx) { DIR *pdir; struct dirent *direntry; //struct stat st; char path[VSX_MAX_PATH_LEN]; int rc = 0; char stridx[32]; unsigned int idx; size_t sz; size_t szext; unsigned int szprfx; int isNumeric; if(!dirpath || !fileprefix || !ext) { return -1; } //fprintf(stderr, "http_purge_segments '%s', '%s', '%s', idxmin:%d\n", dirpath, fileprefix, ext, idxmin); if(!(pdir = fileops_OpenDir(dirpath))) { return -1; } szprfx = strlen(fileprefix); szext = strlen(ext); while((direntry = fileops_ReadDir(pdir))) { if(!(direntry->d_type & DT_DIR) && (sz = strlen(direntry->d_name)) >= 7 && !strncasecmp(&direntry->d_name[sz - szext], ext, szext) && !strncasecmp(direntry->d_name, fileprefix, szprfx)) { if((sz = (sz - szprfx - szext)) >= sizeof(stridx)) { sz = sizeof(stridx) - 1; } memcpy(stridx, &direntry->d_name[szprfx], sz); stridx[sz] = '\0'; isNumeric = 1; for(idx = 0; idx < sz; idx++) { if(!CHAR_NUMERIC(stridx[idx])) { isNumeric = 0; break; } } if(isNumeric) { idx = atoi(stridx); } else if(purgeNonIdx) { idx = 0; } else { idx = idxmin; } //fprintf(stderr, "purge_segment '%s' idx:%d ('%s') < %d\n", direntry->d_name, idx, stridx, idxmin); if(idx < idxmin) { mediadb_prepend_dir(dirpath, direntry->d_name, path, sizeof(path)); LOG(X_DEBUG("Deleting '%s'"), path); if(fileops_DeleteFile(path) != 0) { LOG(X_ERROR("Failed to delete '%s'"), path); } } } } fileops_CloseDir(pdir); return rc; }
int httplive_cbOnPkt(void *pUserData, const unsigned char *pPktData, unsigned int len) { int rc = 0, rc2; struct timeval tv; char filename[VSX_MAX_PATH_LEN]; unsigned int idxMin = 0; int keepIdx; HTTPLIVE_DATA_T *pLive = (HTTPLIVE_DATA_T *) pUserData; if(!pLive || !pPktData) { return -1; } //fprintf(stderr, "httplive_cbOnPkt len:%d, outidx[%d]\n", len, pLive->outidx); if(len == 0) { LOG(X_WARNING("httplive cb called with 0 length")); return 0; } gettimeofday(&tv, NULL); if(pLive->tvNextRoll.tv_sec == 0 || TIME_TV_DIFF_MS(tv, pLive->tvNextRoll) >= (long) (pLive->duration * 1000.0f)) { if(pLive->fs.fp != FILEOPS_INVALID_FP) { //LOG(X_DEBUG("HTTPLIVE CLOSING fp:0x%x, fileno:%d %s"), pLive->fs.fp, pLive->fs.fp ? fileno(pLive->fs.fp) : -99, pLive->fs.filename); closeFp(pLive); //LOG(X_DEBUG("HTTPLIVE CLOSED fp:0x%x, fileno:%d %s"), pLive->fs.fp, pLive->fs.fp ? fileno(pLive->fs.fp) : -99, pLive->fs.filename); } keepIdx = HTTPLIVE_NUM_INDEXES_KEEP(pLive); if(pLive->curIdx > keepIdx + 2) { idxMin = pLive->curIdx - keepIdx - 2; httplive_purgetsfiles(pLive, idxMin); } // // Update MPEG-DASH playlist using .ts segments // if(pLive->pMpdMp2tsCtxt && pLive->curIdx > 0) { on_new_ts(pLive->curIdx-1, idxMin, pLive->outidx, pLive->dir, pLive->curIdx, //pLive->fs.filename, pLive->pMpdMp2tsCtxt, 90000, (pLive->duration * 90000), TIME_TV_DIFF_MS(pLive->tvPriorRoll, pLive->tvRoll0) * 90); } httplive_format_path(filename, sizeof(filename), pLive->fileprefix, pLive->curIdx); mediadb_prepend_dir(pLive->dir, filename, pLive->fs.filename, sizeof(pLive->fs.filename)); if((pLive->fs.fp = fileops_Open(pLive->fs.filename, O_RDWR | O_CREAT)) == FILEOPS_INVALID_FP) { LOG(X_ERROR("Failed to open '%s' for writing"), pLive->fs.filename); rc = -1; } else { LOG(X_DEBUG("Opened '%s'"), pLive->fs.filename); rc = httplive_updatepl(pLive); } pLive->curIdx++; if(pLive->tvNextRoll.tv_sec == 0) { TIME_TV_SET(pLive->tvNextRoll, tv); TIME_TV_SET(pLive->tvRoll0, tv); } //fprintf(stderr, "TV at %u:%u\n", tv.tv_sec, tv.tv_usec); TIME_TV_SET(pLive->tvPriorRoll, pLive->tvNextRoll); TV_INCREMENT_MS(pLive->tvNextRoll, (pLive->duration * 1000.0f)); //fprintf(stderr, "TV next at %u:%u, msElapsed:%u, idxMin:%d, curIdx:%d\n", pLive->tvNextRoll.tv_sec, pLive->tvNextRoll.tv_usec, TIME_TV_DIFF_MS(pLive->tvNextRoll, pLive->tvRoll0), idxMin, pLive->curIdx); } //LOG(X_DEBUG("HTTPLIVE WRITE %d fp:0x%x, pPktData:0x%x, fileno:%d %s"), len, pLive->fs.fp, pPktData, pLive->fs.fp ? fileno(pLive->fs.fp) : -99, pLive->fs.filename); if(pLive->fs.fp != FILEOPS_INVALID_FP && (rc2 = fileops_WriteBinary(pLive->fs.fp, (unsigned char *) pPktData, len)) != len) { LOG(X_ERROR("Failed to write %d/%d to output ts %s"), rc2, len, pLive->fs.filename); //LOG(X_DEBUG("HTTPLIVE WRITE ERROR %d, %d fp:0x%x, pPktData:0x%x, fileno:%d %s"), rc2, len, pLive->fs.fp, pPktData, pLive->fs.fp ? fileno(pLive->fs.fp) : -99, pLive->fs.filename); return -1; } return rc; }