char *metafile_find(const char *pathmedia, char *pathbuf, unsigned int szpathbuf, int *ploaddefault) { int sz; struct stat st; int loaddefault = 0; if(!pathmedia) { } if(ploaddefault) { loaddefault = *ploaddefault; *ploaddefault = 0; } VSX_DEBUG_METAFILE( LOG(X_DEBUG("META - metafile_find pathmedia: '%s', loaddefault: %d"), pathmedia, loaddefault)); // // Check if the media resource is actually a meta file // if(metafile_isvalidFile(pathmedia)) { return (char *) pathmedia; } // // Try to load the metafile for the media resource // snprintf(pathbuf, szpathbuf, "%s%s", pathmedia, METAFILE_EXT); if(fileops_stat(pathbuf, &st) == 0) { return pathbuf; } // // Try to load the directory wide metafile // if(loaddefault && (sz = mediadb_getdirlen(pathmedia)) > 0) { strncpy(pathbuf, pathmedia, szpathbuf); strncpy(&pathbuf[sz], METAFILE_DEFAULT, szpathbuf - sz); if(fileops_stat(pathbuf, &st) == 0) { if(ploaddefault) { *ploaddefault = 1; } return pathbuf; } } return NULL; }
static int check_filename(const char *filename, const char *path, META_FILE_T *pMetaFile) { int sz; struct stat st; if(fileops_stat(filename, &st) != 0 && (sz = mediadb_getdirlen(path)) > 0) { strncpy(pMetaFile->filestr, path, sizeof(pMetaFile->filestr)); strncpy(&pMetaFile->filestr[sz], filename, sizeof(pMetaFile->filestr) - sz); } else { strncpy(pMetaFile->filestr, filename, sizeof(pMetaFile->filestr)); } return 0; }
static int createTn(const MEDIADB_DESCR_T *pMediaDb, FILE_LIST_ENTRY_T *pFileListEntry, const char *pathMedia, const char *pathTn, int numTn, int maxTnInIter) { int rc = 0; int highestTn = 0; struct stat st; unsigned int idx; char buf[VSX_MAX_PATH_LEN]; char cmd[VSX_MAX_PATH_LEN]; char cmdnice[64]; char tmpfile[VSX_MAX_PATH_LEN]; int numTnCreated = 0; char avcthumbsize[32]; unsigned int secOffset; const char *avcthumb = pMediaDb->avcthumb; const char *avcthumblog = pMediaDb->avcthumblog; const char *avcthumb_file = avcthumb; const char *avcthumblog2 = avcthumblog; #ifdef WIN32 char curdir[VSX_MAX_PATH_LEN]; char avcthumblogpath[VSX_MAX_PATH_LEN]; char avcthumblogpath2[VSX_MAX_PATH_LEN]; char avcthumblogprefix[64]; size_t sz; #endif // WIN32 #if defined(FFMPEG_THUMB_NEW) const char thumbsizedelim = ':'; #else // (FFMPEG_THUMB_NEW) const char thumbsizedelim = 'x'; #endif // (FFMPEG_THUMB_NEW) tmpfile[0] = '\0'; cmdnice[0] = '\0'; //fprintf(stdout, "createTn '%s' numTn:%d, maxTnIter:%d, TN_MAX:%d, g_proc_exit:%d (0x%x)\n", pathTn, numTn, maxTnInIter, SRVMEDIA_TN_MAX, g_proc_exit, &g_proc_exit); for(idx = 0; idx < SRVMEDIA_TN_MAX; idx++) { if(idx > 0) { secOffset = (idx - 1) * SRVMEDIA_TN_INTERVAL_SEC; } else { secOffset = 4; } if(pFileListEntry->duration == 0) { snprintf(tmpfile, sizeof(tmpfile), "%s%s"VSXTMP_EXT, pathTn, pMediaDb->tn_suffix); if(fileops_stat(tmpfile, &st) != 0) { if(numTn == 0 && idx == 0) { //fprintf(stdout, "creating tmp file '%s'\n", tmpfile); // // Create tmpfile which should only exist during // creation of thumbnails for source of unknown duration // Since the "tn=" parameter in the index file denotes // the current number of thumbnails available // if(fileops_touchfile(tmpfile) != 0) { LOG(X_ERROR("Failed to create %s"), tmpfile); } } else if((int) idx >= numTn) { //fprintf(stdout, "breaking out, have all the tns %d > %d\n", idx, numTn); break; } } else if(idx == SRVMEDIA_TN_MAX - 1) { //fprintf(stdout, "removing tmp file '%s'\n", tmpfile); fileops_DeleteFile(tmpfile); } } else if(pFileListEntry->duration > 0 && secOffset >= pFileListEntry->duration - 1) { break; } if(idx == 0) { snprintf(avcthumbsize, sizeof(avcthumbsize), "%d%c%d", pMediaDb->smTnWidth, thumbsizedelim, pMediaDb->smTnHeight); snprintf(buf, sizeof(buf), "%s%s.jpg", pathTn, pMediaDb->tn_suffix); } else { snprintf(avcthumbsize, sizeof(avcthumbsize), "%d%c%d", pMediaDb->lgTnWidth, thumbsizedelim, pMediaDb->lgTnHeight); snprintf(buf, sizeof(buf), "%s%s%u.jpg", pathTn, pMediaDb->tn_suffix, idx - 1); } if(fileops_stat(buf, &st) < 0 || st.st_size == 0) { #ifdef WIN32 // // cd into directory of avcthumb script // avcthumblogprefix[0] = '\0'; curdir[0] = '\0'; fileops_getcwd(curdir, sizeof(curdir)); if((sz = mediadb_getdirlen(avcthumb)) > 0) { if(sz >= sizeof(tmpfile)) { sz = sizeof(tmpfile) - 1; } tmpfile[sizeof(tmpfile) - 1] = '\0'; strncpy(tmpfile, avcthumb, sizeof(tmpfile)); if(sz > 0) { tmpfile[sz] = '\0'; fileops_setcwd(tmpfile); avcthumb_file = &avcthumb[sz]; snprintf(avcthumblogprefix, sizeof(avcthumblogprefix), "..\\"); } } if(avcthumblog) { snprintf(avcthumblogpath, sizeof(avcthumblogpath), "%s%s", avcthumblogprefix, avcthumblog); snprintf(avcthumblogpath2, sizeof(avcthumblogpath2), "%s%s.err", avcthumblogprefix, avcthumblog); avcthumblog2 = avcthumblogpath2; avcthumblog = avcthumblogpath; } #else snprintf(cmdnice, sizeof(cmdnice), "nice -n19 "); #endif // WIN32 #if defined(FFMPEG_THUMB_NEW) // //TODO: create multiple thumbs on one run... will speed thnigs up alot! // '-ss 4 -vf "thumbnail,scale=164:90,fps=1/4" -frames:v 8' // snprintf(cmd, sizeof(cmd), "%s%s -v warning -i \"%s\" -an -vf \"thumbnail,scale=%s\" " "-frames:v 1 -f image2 -vcodec mjpeg -ss %u \"%s\" %s%s %s%s", cmdnice, avcthumb_file, pathMedia, avcthumbsize, secOffset, buf, avcthumblog ? ">>" : "", avcthumblog ? avcthumblog : "", avcthumblog2 ? "2>>" : "", avcthumblog2 ? avcthumblog2 : ""); #else // (FFMPEG_THUMB_NEW) snprintf(cmd, sizeof(cmd), "%s%s -i \"%s\" -an -s \"%s\" " "-vframes 1 -f image2 -vcodec mjpeg -ss %u \"%s\" %s%s %s%s", cmdnice, avcthumb_file, pathMedia, avcthumbsize, secOffset, buf, avcthumblog ? ">>" : "", avcthumblog ? avcthumblog : "", avcthumblog2 ? "2>>" : "", avcthumblog2 ? avcthumblog2 : ""); #endif // (FFMPEG_THUMB_NEW) //if(numcmd++ > 2) { // return 0; //} LOG(X_DEBUG("Creating thumbnail '%s'"), cmd); //TODO: seems that we're not getting SIGINT in the parent here... need a way to spawn (async?) & wait/poll rc = system(cmd); #ifdef WIN32 if(curdir[0] != '\0') { fileops_setcwd(curdir); } #endif // WIN3 //LOG(X_DEBUG("DOING STAT ON '%s'"), buf); if(fileops_stat(buf, &st) == 0 && st.st_size > 0) { rc = 0; highestTn = idx + 1; if(maxTnInIter > 0 && ++numTnCreated >= maxTnInIter) { break; } } else { rc = -1; LOG(X_WARNING("Failed to generate thumbnail '%s'"), buf); if(pFileListEntry->duration == 0) { snprintf(tmpfile, sizeof(tmpfile), "%s%s"VSXTMP_EXT, pathTn, pMediaDb->tn_suffix); if(fileops_stat(tmpfile, &st) == 0) { fileops_DeleteFile(tmpfile); } } else { snprintf(tmpfile, sizeof(tmpfile), "%s%s."NOTN_EXT, pathTn, pMediaDb->tn_suffix); if(fileops_touchfile(tmpfile) != 0) { LOG(X_ERROR("Failed to create %s"), tmpfile); } } if(idx == 0) { return -1; } break; } } else { highestTn = idx + 1; } } return highestTn; }
void mediadb_proc(void *parg) { MEDIADB_DESCR_T *pMediaDb = (MEDIADB_DESCR_T *) parg; struct stat st; char buf[VSX_MAX_PATH_LEN]; const char *avcthumb = NULL; size_t sz; int rc; unsigned int iterIdx = 0; if(!pMediaDb->mediaDir) { return; } memset(buf, 0, sizeof(buf)); sz = mediadb_getdirlen(pMediaDb->dbDir); strncpy(buf, pMediaDb->dbDir, sizeof(buf) - 1); buf[sz] = '\0'; LOG(X_DEBUG("Database dir: '%s'"), pMediaDb->dbDir); if(fileops_stat(buf, &st) != 0) { // // Create database root dir // LOG(X_DEBUG("Creating dir '%s'"), buf); if(fileops_MkDir(buf, S_IRWXU | S_IRWXG | S_IRWXO ) < 0) { LOG(X_CRITICAL("Unable to create database dir '%s'"), buf); return; } } if(fileops_stat(pMediaDb->dbDir, &st) != 0) { // // Create database subdir specific for mediaDir // LOG(X_DEBUG("Creating dir '%s'"), pMediaDb->dbDir); if(fileops_MkDir(pMediaDb->dbDir, S_IRWXU | S_IRWXG | S_IRWXO ) < 0) { LOG(X_CRITICAL("Unable to create database dir '%s'"), pMediaDb->dbDir); return; } } // // Check thumbnail creation script // if(pMediaDb->avcthumb) { if(fileops_stat(pMediaDb->avcthumb, &st) == 0) { // // Truncate the avcthumblog // if(pMediaDb->avcthumblog) { snprintf(buf, sizeof(buf), DATE_CMD" > %s", pMediaDb->avcthumblog); //LOG(X_DEBUG("Executing system command '%s'"), buf); rc = system(buf); if(fileops_stat(pMediaDb->avcthumblog, &st) != 0) { pMediaDb->avcthumblog = NULL; } } if(pMediaDb->lgTnWidth == 0 || pMediaDb->lgTnWidth == 0) { pMediaDb->lgTnWidth = LG_THUMB_WIDTH; pMediaDb->lgTnHeight = LG_THUMB_HEIGHT; } if(pMediaDb->smTnWidth == 0 || pMediaDb->smTnHeight == 0) { pMediaDb->smTnWidth = SM_THUMB_WIDTH; pMediaDb->smTnHeight = SM_THUMB_HEIGHT; } LOG(X_DEBUG("Using %s to generate thumbnails %dx%d %dx%d"), pMediaDb->avcthumb, pMediaDb->smTnWidth, pMediaDb->smTnHeight, pMediaDb->lgTnWidth, pMediaDb->lgTnHeight); } else { LOG(X_WARNING("Unable to find %s Video thumbnails disabled."), pMediaDb->avcthumb); pMediaDb->avcthumb = NULL; } } else { LOG(X_WARNING("Not using video thumbnails. Please set '%s=' in the configuration file."), SRV_CONF_KEY_AVCTHUMB); } // // Set avchumb to null and do not create thumbnails on first // iteration to allow all avcfidx files to be created quickly // avcthumb = pMediaDb->avcthumb; pMediaDb->avcthumb = NULL; if(g_proc_exit == 0) { iterate_subdirs(pMediaDb, pMediaDb->dbDir, pMediaDb->mediaDir, 1, 0); pMediaDb->avcthumb = avcthumb; usleep(2000000); } while(g_proc_exit == 0) { iterate_subdirs(pMediaDb, pMediaDb->dbDir, pMediaDb->mediaDir, 1, iterIdx++); usleep(10000000); } }
int http_gethttplive(CAP_ASYNC_DESCR_T *pCfg, CAPTURE_CBDATA_T *pStreamsOut, CAPTURE_STREAM_T *pStream, const char *puri, HTTP_RESP_T *pHttpResp, HTTP_PARSE_CTXT_T *pHdrCtxt) { int rc = 0; char *path; const char *pbuf = pHdrCtxt->pbuf; unsigned int szbuf = pHdrCtxt->szbuf; const char *pm3ubuf; pthread_t ptd; pthread_attr_t attr; HTTPLIVE_CLIENT_T client; int highestIdx, lowestIdx, firstIdx; memset(&client, 0, sizeof(client)); client.pCfg = pCfg; NETIOSOCK_FD(client.netsock) = INVALID_SOCKET; client.netsock.flags = pCfg->pSockList->netsockets[0].flags; client.pStreamsOut = pStreamsOut; client.pStream = pStream; client.running = -1; pthread_mutex_init(&client.mtx, NULL); do { //fprintf(stderr, "HTTP_GETHTTPLIVE sock: %d\n", NETIOSOCK_FD(pCfg->pSockList->netsockets[0])); if(NETIOSOCK_FD(pCfg->pSockList->netsockets[0]) == INVALID_SOCKET) { //fprintf(stderr, "GOING TO CONNECT FOR M3U...\n"); if((rc = httpcli_connect(&pCfg->pSockList->netsockets[0], &pCfg->pSockList->salist[0], "HTTPLive playlist thread")) < 0) { break; } memset(pHdrCtxt, 0, sizeof(HTTP_PARSE_CTXT_T)); memset(pHttpResp, 0, sizeof(HTTP_RESP_T)); pHdrCtxt->pnetsock = &pCfg->pSockList->netsockets[0]; pHdrCtxt->pbuf = pbuf; pHdrCtxt->szbuf = szbuf; pHdrCtxt->tmtms = 0; } if((rc = mediadb_getdirlen(puri)) > 0) { if(rc >= sizeof(client.uriprefix)) { rc = sizeof(client.uriprefix) - 1; } memcpy(client.uriprefix, puri, rc); } if((pm3ubuf = get_m3u8(pCfg, puri, pHttpResp, pHdrCtxt, (unsigned char *) pbuf, szbuf))) { m3u_free(&client.pl, 0); memset(&client.pl, 0, sizeof(client.pl)); /* pm3ubuf="#EXTM3U\r\n" "#EXT-X-VERSION:3\r\n" "#EXT-X-ALLOW-CACHE:NO\r\n" "#EXT-X-TARGETDURATION:14\r\n" "#EXT-X-MEDIA-SEQUENCE:2699\r\n" "#EXTINF:10,\r\n" "media_2699.ts?wowzasessionid=1144297750\r\n" "#EXTINF:10,\r\n" "media_2700.ts?wowzasessionid=1144297750\r\n" "#EXTINF:7,\r\n" "media_2701.ts?wowzasessionid=1144297750\r\n"; */ VSX_DEBUGLOG("Got m3u contents '%s'", pm3ubuf); //fprintf(stderr, "Got m3u contents '%s'\n", pm3ubuf); pthread_mutex_lock(&client.mtx); rc = m3u_create_buf(&client.pl, pm3ubuf); pthread_mutex_unlock(&client.mtx); if(rc > 0) { path = NULL; lowestIdx = find_lowest_idx(&client.pl, NULL); highestIdx = find_highest_idx(&client.pl, NULL); if(!client.insession) { if(highestIdx < 0) { LOG(X_WARNING("Unable to find httplive starting index from %s"), puri); } else { // // Some segmentors may write the last chunk to the playlist file even though // the chunk is still being appended on disk // //if(highestIdx > lowestIdx) { // firstIdx = highestIdx - 1; //} else { firstIdx = highestIdx; //} client.curidx = firstIdx; client.nextidx = client.curidx; client.insession = 1; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); client.running = 1; if(pthread_create(&ptd, &attr, (void *) httplive_mediaproc, &client) != 0) { LOG(X_ERROR("Unable to create httplive media download thread")); rc = -1; client.running = -1; } } } else { // client.insession //fprintf(stderr, "check playlist falling behind curidx:%d nextidx:%d, lowestIdx:%d, highestIdx:%d\n", client.curidx, client.nextidx, lowestIdx, highestIdx); // // Prevent falling behind playlist, a warning will be printed in the ts get thread // pthread_mutex_lock(&client.mtx); if(client.nextidx < lowestIdx) { client.nextidx = lowestIdx; } pthread_mutex_unlock(&client.mtx); } //if(rc >= 0) { // m3u_dump(&client.pl); //} } } else { // get_m3u8 rc = -1; } netio_closesocket(&pCfg->pSockList->netsockets[0]); if(rc >= 0) { //fprintf(stderr, "M3U SLEEPING FOR %d\n", client.pl.targetDuration); if(client.pl.targetDuration > 0) { sleep(client.pl.targetDuration); } else { sleep(9); } } } while(rc >= 0); client.insession = 0; while(client.running != -1) { usleep(20000); } m3u_free(&client.pl, 0); pthread_mutex_destroy(&client.mtx); return rc; }