static int create_and_write_mpd(MPD_CREATE_CTXT_T *pCtxt, const MPD_ADAPTATION_T *pAdaptationList, DASH_MPD_TYPE_T mpdType, int outidx, int idxmax, unsigned int mediaSequenceIndex, int mediaSequenceMin) { int rc = 0; int idxbuf = 0; FILE_HANDLE fp; char buf[4096]; char mpdpath[VSX_MAX_PATH_LEN]; // // Create the .mpd xml file contents // if((idxbuf = mpd_doc_create(mpdType, pAdaptationList, pCtxt, outidx, mediaSequenceIndex, buf, sizeof(buf))) <= 0) { return -1; } // // Write the .mpd xml file to disk // if((rc = write_mpd_path(pCtxt, outidx, mpdType, mpdpath, sizeof(mpdpath))) < 0) { return rc; } if((fp = fileops_Open(mpdpath, O_RDWR | O_CREAT)) == FILEOPS_INVALID_FP) { LOG(X_ERROR("Failed to open DASH mpd '%s' for writing"), mpdpath); return -1; } if((rc = fileops_WriteBinary(fp, (unsigned char *) buf, idxbuf)) < 0) { LOG(X_ERROR("Failed to write %d to DASH mpd '%s'"), idxbuf, mpdpath); } fileops_Close(fp); if(rc >= 0) { LOG(X_DEBUG("Updated DASH playlist '%s' (%d - %d)"), mpdpath, mediaSequenceMin, idxmax); } else { LOG(X_ERROR("Failed to update DASH playlist '%s' (%d - %d)"), mpdpath, mediaSequenceMin, idxmax); } return rc; }
static int httplive_writepl_multibr(const char *path, const HTTPLIVE_DATA_T *pLiveArg) { FILE_HANDLE fp; int sz = 0; int rc = 0; char buf[4096]; char tmp[32]; int progId = 1; unsigned int bitrate; const char *uriprfxdelimeter = ""; const HTTPLIVE_DATA_T *pLive = pLiveArg; if((rc = snprintf(&buf[sz], sizeof(buf) - sz, "#EXTM3U\r\n")) > 0) { sz += rc; } while(pLive) { if((rc = snprintf(&buf[sz], sizeof(buf) - sz, "#%s:PROGRAM-ID=%d", HTTPLIVE_EXTX_STREAM_INFO, progId)) > 0) { sz += rc; } #define HTTPLIVE_BANDWIDTH(bw) (bw>1000 ? bw/1000*1000 : bw>100 ? bw/100*100 : bw>10 ? bw/10*10 : bw) bitrate = pLive->publishedBitrate ? pLive->publishedBitrate : pLive->autoBitrate; if(bitrate > 0) { if((rc = snprintf(&buf[sz], sizeof(buf) - sz, ", BANDWIDTH=%u", HTTPLIVE_BANDWIDTH(bitrate))) > 0) { sz += rc; } } if((rc = snprintf(&buf[sz], sizeof(buf) - sz, "\r\n")) > 0) { sz += rc; } if((rc = strlen(pLive->uriprefix)) > 0 && pLive->uriprefix[rc - 1] != '/') { uriprfxdelimeter = "/"; } if(pLive->outidx > 0) { snprintf(tmp, sizeof(tmp), "%d", pLive->outidx + 1); } else { tmp[0] = '\0'; } if((rc = snprintf(&buf[sz], sizeof(buf) - sz, "%s%s%s%s%s\r\n", (pLive->uriprefix[0] != '\0' ? pLive->uriprefix : ""), uriprfxdelimeter, tmp, //&pLive->fileprefix[pLive->outidx > 0 ? 1 : 0], HTTPLIVE_PL_NAME_EXT)) < 0) { HTTPLIVE_TS_NAME_PRFX, HTTPLIVE_PL_NAME_EXT)) < 0) { break; } else { sz += rc; } pLive = pLive->pnext; } if(rc >= 0) { if((fp = fileops_Open(path, O_RDWR | O_CREAT)) == FILEOPS_INVALID_FP) { LOG(X_ERROR("Failed to open '%s' for writing"), path); return -1; } if((rc = fileops_WriteBinary(fp, (unsigned char *) buf, sz)) < 0) { LOG(X_ERROR("Failed to write %d to '%s'"), sz, path); } fileops_Close(fp); } if(rc >= 0) { LOG(X_DEBUG("Updated master playlist '%s'"), path); } else { LOG(X_ERROR("Failed to update master playlist '%s'"), path); } 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; }
static int httplive_writepl(const char *path, int idxmin, int idxmax, HTTPLIVE_DATA_T *pLive) { FILE_HANDLE fp; int idx; int sz = 0; int rc = 0; char filename[128]; char buf[4096]; const char *uriprfxdelimeter = ""; unsigned int duration = (unsigned int) pLive->duration; if(pLive->duration > (float) duration) { duration++; } if((rc = snprintf(buf, sizeof(buf), "#EXTM3U\r\n#%s:%d\r\n#%s:%d\r\n", HTTPLIVE_EXTX_TARGET_DURATION, duration, HTTPLIVE_EXTX_MEDIA_SEQUENCE, idxmin)) > 0) { sz += rc; if(rc >= 0 && (rc = snprintf(&buf[sz], sizeof(buf) - sz, "#EXT-X-ALLOW-CACHE:NO\r\n")) > 0) { sz += rc; } #if defined(HTTPLIVE_INCLUDE_PROGRAM_DATE_TIME) char tmbuf[256]; time_t tm = s_httplive_tm + (pLive->curIdx * duration); strftime(tmbuf, sizeof(tmbuf) - 1, "%Y-%m-%dT%H:%M:%S+08:00", gmtime(&tm)); //fprintf(stderr, "TM:%u, %u, %d * %d '%s'\n", tm, s_httplive_tm, pLive->curIdx, duration, tmbuf); if(rc >= 0 && (rc = snprintf(&buf[sz], sizeof(buf) - sz, "#EXT-X-PROGRAM-DATE-TIME:%s\r\n", tmbuf)) > 0) { sz += rc; } #endif // HTTPLIVE_INCLUDE_PROGRAM_DATE_TIME if(pLive->uriprefix && (rc = strlen(pLive->uriprefix)) > 0 && pLive->uriprefix[rc - 1] != '/') { uriprfxdelimeter = "/"; } for(idx = idxmin; idx <= idxmax; idx++) { httplive_format_path(filename, sizeof(filename), pLive->fileprefix, idx); if((rc = snprintf(&buf[sz], sizeof(buf) - sz, "#EXTINF:%d,\r\n%s%s%s\r\n" ,duration, (pLive->uriprefix ? pLive->uriprefix : ""), uriprfxdelimeter, filename)) < 0) { break; } else { sz += rc; } } } // // For live streams, do not end with #EXT-X-ENDLIST // if(rc >= 0) { if((fp = fileops_Open(path, O_RDWR | O_CREAT)) == FILEOPS_INVALID_FP) { LOG(X_ERROR("Failed to open httplive playlist '%s' for writing"), path); return -1; } if((rc = fileops_WriteBinary(fp, (unsigned char *) buf, sz)) < 0) { LOG(X_ERROR("Failed to write %d to httplive playlist '%s'"), sz, path); } fileops_Close(fp); } if(rc >= 0) { LOG(X_DEBUG("Updated httplive playlist '%s' (%d - %d)"), path, idxmin, idxmax); } else { LOG(X_ERROR("Failed to update httplive playlist '%s' (%d - %d)"), path, idxmin, idxmax); } return rc; }