static double user_function(unsigned n, const double *x, double *gradient, /* NULL if not needed */ void *d_) { user_function_data *d = (user_function_data *) d_; double f; d->plhs[0] = d->plhs[1] = NULL; memcpy(mxGetPr(d->prhs[d->xrhs]), x, n * sizeof(double)); CHECK0(0 == mexCallMATLAB(gradient ? 2 : 1, d->plhs, d->nrhs, d->prhs, d->f), "error calling user function"); CHECK0(mxIsNumeric(d->plhs[0]) && !mxIsComplex(d->plhs[0]) && mxGetM(d->plhs[0]) * mxGetN(d->plhs[0]) == 1, "user function must return real scalar"); f = mxGetScalar(d->plhs[0]); mxDestroyArray(d->plhs[0]); if (gradient) { CHECK0(mxIsDouble(d->plhs[1]) && !mxIsComplex(d->plhs[1]) && (mxGetM(d->plhs[1]) == 1 || mxGetN(d->plhs[1]) == 1) && mxGetM(d->plhs[1]) * mxGetN(d->plhs[1]) == n, "gradient vector from user function is the wrong size"); memcpy(gradient, mxGetPr(d->plhs[1]), n * sizeof(double)); mxDestroyArray(d->plhs[1]); } d->neval++; if (d->verbose) mexPrintf("nlopt_optimize eval #%d: %g\n", d->neval, f); if (mxIsNaN(f)) nlopt_force_stop(d->opt); return f; }
Stream::Stream(AVFormatContext*& formatCtx, AVStream*& stream, DataSource& dataSource, std::shared_ptr<Timer> timer) : m_formatCtx(formatCtx), m_stream(stream), m_dataSource(dataSource), m_timer(timer), m_codec(nullptr), m_streamID(-1), m_packetList(), m_status(Stopped), m_readerMutex() { CHECK(stream, "Stream::Stream() - invalid stream argument"); CHECK(timer, "Inconcistency error: null timer"); int err = 0; m_stream = stream; m_streamID = stream->index; CHECK(m_stream, "Inconcistency error: null stream") CHECK(m_streamID >= 0, "Inconcistency error: invalid stream id"); // Get the decoder m_codec = avcodec_find_decoder(m_stream->codec->codec_id); CHECK(m_codec, "Stream() - no decoder for " + std::string(avcodec_get_name(m_stream->codec->codec_id)) + " codec"); // Load the codec err = avcodec_open2(m_stream->codec, m_codec, nullptr); CHECK0(err, "Stream() - unable to load decoder for codec " + std::string(avcodec_get_name(m_stream->codec->codec_id))); AVDictionaryEntry* entry = av_dict_get(m_stream->metadata, "language", nullptr, 0); if (entry) { m_language = entry->value; } }
static mxArray *struct_funcval(const mxArray *s, const char *name) { mxArray *val = mxGetField(s, 0, name); if (val) { CHECK0(mxIsChar(val) || mxIsFunctionHandle(val), "opt function field is not a function handle/name"); return val; } return NULL; }
static double struct_val_default(const mxArray *s, const char *name, double dflt) { mxArray *val = mxGetField(s, 0, name); if (val) { CHECK0(mxIsNumeric(val) && !mxIsComplex(val) && mxGetM(val) * mxGetN(val) == 1, "opt fields, other than xtol_abs, must be real scalars"); return mxGetScalar(val); } return dflt; }
static double *struct_arrval(const mxArray *s, const char *name, unsigned n, double *dflt) { mxArray *val = mxGetField(s, 0, name); if (val) { CHECK0(mxIsNumeric(val) && !mxIsComplex(val) && mxGetM(val) * mxGetN(val) == n, "opt vector field is not of length n"); return mxGetPr(val); } return dflt; }
static void user_pre(unsigned n, const double *x, const double *v, double *vpre, void *d_) { user_function_data *d = ((user_function_data *) d_)->dpre; d->plhs[0] = d->plhs[1] = NULL; memcpy(mxGetPr(d->prhs[d->xrhs]), x, n * sizeof(double)); memcpy(mxGetPr(d->prhs[d->xrhs + 1]), v, n * sizeof(double)); CHECK0(0 == mexCallMATLAB(1, d->plhs, d->nrhs, d->prhs, d->f), "error calling user function"); CHECK0(mxIsDouble(d->plhs[0]) && !mxIsComplex(d->plhs[0]) && (mxGetM(d->plhs[0]) == 1 || mxGetN(d->plhs[0]) == 1) && mxGetM(d->plhs[0]) * mxGetN(d->plhs[0]) == n, "vpre vector from user function is the wrong size"); memcpy(vpre, mxGetPr(d->plhs[0]), n * sizeof(double)); mxDestroyArray(d->plhs[0]); d->neval++; if (d->verbose) mexPrintf("nlopt_optimize precond eval #%d\n", d->neval); }
int test_main(int, char*[]) { // An all-blank string is treated as zero. { int const n = 9; double const d[n] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; std::string e(" "); CHECK0(d, n, e); } // Make sure example in comment at top works. // 1 3; 7 5;0; --> 1 1 1 7 7 0... { int const n = 9; double const d[n] = {1, 1, 1, 7, 7, 0, 0, 0, 0}; std::string e("1 3; 7 5;0"); CHECK0(d, n, e); } // Numbers separated by semicolons mean values; the last is // replicated to fill the vector. { int const n = 5; double const d[n] = {1, 2, 3, 3, 3}; std::string e("1; 2; 3"); CHECK0(d, n, e); } // Number-pairs separated by semicolons mean {value, end-duration}. { int const n = 10; double const d[n] = {1, 1, 1, 3, 3, 3, 5, 5, 5, 7}; std::string e("1 3; 3 6; 5 9; 7"); CHECK0(d, n, e); } // {value, @ attained_age} { int const n = 10; double const d[n] = {1, 1, 1, 3, 3, 3, 5, 5, 5, 7}; std::string e("1 @93; 3 @96; 5 @99; 7"); CHECK0(d, n, e); } // {value, # number_of_years_since_last_interval_endpoint} { int const n = 10; double const d[n] = {1, 1, 1, 3, 3, 3, 5, 5, 5, 7}; std::string e("1 #3; 3 #3; 5 #3; 7"); CHECK0(d, n, e); } // {value [|( begin-duration, end-duration ]|) } // Test [x,y). { int const n = 9; double const d[n] = {1, 1, 3, 3, 3, 5, 7, 7, 7}; std::string e("1 [0, 2); 3 [2, 5); 5 [5, 6); 7"); CHECK0(d, n, e); } // Test (x,y]. { int const n = 9; double const d[n] = {1, 1, 1, 3, 3, 3, 5, 7, 7}; std::string e("1; 1 (0, 2]; 3 (2, 5]; 5 (5, 6]; 7"); CHECK0(d, n, e); } // Test a mixture of all five ways of specifying duration. { int const n = 9; double const d[n] = {1, 1, 1, 1, 2, 3, 4, 5, 5}; std::string e("1 [0, 4); 2 5; 3 #1; 4 @97; 5"); CHECK0(d, n, e); } // Test intervals of length one. { int const n = 5; double const d[n] = {1, 3, 5, 7, 7}; std::string e("1 [0, 1); 3 [1, 2); 5 (1, 2]; 7"); CHECK0(d, n, e); } // Test empty intervals. { int const n = 5; double const d[n] = {1, 3, 5, 7, 7}; std::string e("1 [0, 1); 3 [1, 1]; 5 (1, 2]; 7"); CHECK0(d, n, e); } // Test subtly improper intervals. { int const n = 5; double const d[n] = {0, 0, 0, 0, 0}; std::string e("1 [0, 0); 3 (1, 2); 5 (2, 2]; 7"); CHECK0(d, n, e); } // Test grossly improper intervals. { int const n = 9; double const d[n] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; std::string e("1; 9 (2, 0]; 3 [7, 3); 5 (5, 5); 7"); CHECK0(d, n, e); } // Test intervals with 'holes'. Since the last element is replicated, // there can be no 'hole' at the end. { int const n = 9; double const d[n] = {0, 1, 0, 3, 0, 5, 7, 7, 7}; std::string e("1 [1, 2); 3 [3, 3]; 5 (4, 5]; 7"); CHECK0(d, n, e); } // Test overlapping intervals. // TODO ?? Treat these as an error? { int const n = 9; double const d[n] = {1, 1, 1, 3, 3, 5, 5, 7, 7}; std::string e("1; 1 (0, 8]; 3 (2, 7]; 5 (4, 6]; 7"); CHECK0(d, n, e); } // Test intervals with decreasing begin-points. // TODO ?? Should this case be allowed? { int const n = 9; double const d[n] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; std::string e("5 [5, 6); 3 [2, 5); 1 [0, 2); 7"); CHECK0(d, n, e); } // Durations with '@' prefix mean attained age. { int const n = 10; double const d[n] = {0, 12, 0, 27, 0, 1, 7, 7, 7, 7}; std::string e("12 [1, @92); 27 [@93, @93]; 1 (@94, 5]; 7"); CHECK0(d, n, e); } // Test floating-point values; we choose values that we know // must be exactly representable on a binary machine, so that a // simple test for equality suffices. { int const n = 10; double const d[n] = {0, 12.25, 0, 27.875, 0, 1.0625, 7.5, 7.5, 7.5, 7.5}; std::string e("12.25 [1, @92); 27.875 [@93, @93]; 1.0625 (@94, 5]; 7.5"); CHECK0(d, n, e); } // {value, @ age} means {value, to-attained-age} { int const n = 10; double const d[n] = {1, 1, 1, 3, 3, 3, 5, 5, 5, 7}; std::string e("1 @93; 3 @96; 5 @99; 7"); CHECK0(d, n, e); } // TODO ?? Also support and test: // additive expressions e.g. retirement-10 ? // Test construction from vector. // 1 1 1 2 2 --> 1 [0,3);2 [3,5) // TODO ?? Test against canonical representation once we define that. { int const n = 5; double const d[n] = {1, 1, 1, 2, 2}; std::vector<double> v(d, d + n); BOOST_TEST(v == InputSequence(v).linear_number_representation()); } // Test (enumerative) extra keywords. { int const n = 9; char const* c[n] = {"a", "a", "ccc", "ccc", "b", "b", "b", "b", "b"}; double const d[n] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; std::string e("a[0, 2); ccc [2, 4);b[4, 6);"); std::vector<std::string> k; k.push_back("not_used"); k.push_back("a"); k.push_back("b"); k.push_back("c"); k.push_back("cc"); k.push_back("ccc"); CHECK1(d, n, e, k, c); } // Test numbers mixed with (enumerative) extra keywords. { int const n = 9; char const* c[n] = {"", "", "keyword_00", "keyword_00", "", "", "", "", ""}; double const d[n] = {1, 1, 0, 0, 5, 5, 7, 7, 7}; std::string e("1 [0, 2); keyword_00 [2, 4); 5 [4, 6); 7"); std::vector<std::string> k; k.push_back("keyword_00"); CHECK1(d, n, e, k, c); } // Test numbers mixed with (enumerative) extra keywords, with // a default keyword. { int const n = 10; char const* c[n] = {"b", "b", "x", "a", "x", "x", "a", "x", "x", "x"}; double const d[n] = { 0, 0, 0, 0, 5, 5, 0, 7, 7, 7}; std::string e("b [0, 2); a [3, 4); 5 [4, 6); a; 7"); std::vector<std::string> k; k.push_back("a"); k.push_back("b"); k.push_back("x"); std::string w("x"); CHECK2(d, n, e, k, c, w); } // TODO ?? Also test keyword as scalar duration. // Duration keywords: {retirement, maturity} { int const n = 10; double const d[n] = {7, 7, 7, 7, 7, 4, 4, 4, 4, 4}; std::string e("7, retirement; 4"); CHECK0(d, n, e); InputSequence seq("7, retirement; 4", 10, 90, 95, 0, 2002, 0); std::vector<ValueInterval> const& i(seq.interval_representation()); BOOST_TEST(e_inception == i[0].begin_mode); BOOST_TEST(e_retirement == i[0].end_mode ); BOOST_TEST(e_retirement == i[1].begin_mode); BOOST_TEST(e_maturity == i[1].end_mode ); } // TODO ?? Also test default keyword. // TODO ?? Also test keywords-only switch. return 0; }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { double *xptr; mxArray *xopt; const mxArray *func_name, *params; user_function_data udata; size_t nDim; unsigned int ii; bopt_params parameters; double *cat_d; int *cat_i; double fmin; int error_code; /* Check correct number of parameters */ CHECK0(nlhs != 2 || nrhs != 3, "wrong number of arguments"); /* TODO: Change This */ udata.neval = 0; udata.verbose = 0; /* First term is the function handle or name */ func_name = prhs[0]; if (mxIsChar(func_name)) { CHECK0(mxGetString(func_name, udata.f, FLEN) == 0, "error reading function name string (too long?)"); udata.nrhs = 1; udata.xrhs = 0; } #ifndef HAVE_OCTAVE else if (mxIsFunctionHandle(func_name)) { udata.prhs[0] = (mxArray *)func_name; strcpy(udata.f, "feval"); udata.nrhs = 2; udata.xrhs = 1; } #endif else { mexErrMsgTxt("First term should be a function name or function handle"); } /* Second parameter. Categories */ CHECK0(mxIsDouble(prhs[1]) && !mxIsComplex(prhs[1]) && ( (mxGetM(prhs[1]) == 1) && (mxGetN(prhs[1]) == nDim) || (mxGetN(prhs[1]) == 1) && (mxGetM(prhs[1]) == nDim)), "categories must be real row or column vector"); cat_d = mxGetPr(prhs[3]); nDim = (unsigned int) mxGetM(prhs[1]) * mxGetN(prhs[1]); cat_i = (int*)(mxCalloc(nDim,sizeof(int))); for (ii = 0; ii < nDim; ++ii) { cat_i[ii] = (int)(cat_d[ii]+0.5); } udata.prhs[udata.xrhs] = mxCreateDoubleMatrix(1, nDim, mxREAL); xopt = mxCreateDoubleMatrix(1, nDim, mxREAL); xptr = mxGetPr(xopt); /* Third term. Parameters */ if (nrhs != 2) { CHECK0(mxIsStruct(prhs[2]), "3rd element must be a struct"); params = prhs[2]; } else { params = mxCreateStructMatrix(1,1,0,NULL); } parameters = load_parameters(params); error_code = bayes_optimization_categorical(nDim,user_function,&udata,cat_i,xptr, &fmin,parameters); mxFree(cat_i); mxDestroyArray(udata.prhs[udata.xrhs]); plhs[0] = xopt; if (nlhs > 1) { plhs[1] = mxCreateDoubleMatrix(1, 1, mxREAL); *(mxGetPr(plhs[1])) = fmin; } if (nlhs > 2) { plhs[2] = mxCreateDoubleMatrix(1, 1, mxREAL); *(mxGetPr(plhs[2])) = (double)(error_code); } }
int main () { /* Empty string. */ CHECK ("", "", -1, ""); CHECK ("", ".", -1, ""); CHECK ("", "123", -1, ""); /* Empty delimeter list. */ CHECK ("A", "", 0, "A"); CHECK0 ("", -1, ""); CHECK ("12", "", 0, "12"); CHECK0 ("", -1, ""); CHECK ("dcba", "", 0, "dcba"); CHECK0 ("", -1, ""); /* No delimeter symbols are founded. */ CHECK ("\t", " ", 0, "\t"); CHECK0 (" ", -1, ""); CHECK ("THE QUICK BROWN FOX", "thequickbrownfox", 0, "THE QUICK BROWN FOX"); CHECK0 ("thequickbrownfox", -1, ""); /* Delimeter list is 1 byte long. */ CHECK ("1", ".", 0, "1"); CHECK0 (".", -1, ""); CHECK ("A,BC,DEF", ",", 0, "A"); CHECK0 (",", 2, "BC"); CHECK0 (",", 5, "DEF"); CHECK0 (",", -1, ""); /* Delimeter list is 2 bytes long. */ CHECK ("AB", "ab", 0, "AB"); CHECK0 ("ab", -1, ""); CHECK ("123+45-6", "+-", 0, "123"); CHECK0 ("+-", 4, "45"); CHECK0 ("+-", 7, "6"); CHECK0 ("+-", -1, ""); /* Variable delimeter list. */ CHECK ("A:B*C:D", ":", 0, "A"); CHECK0 ("*", 2, "B"); CHECK0 (":", 4, "C"); CHECK0 ("", 6, "D"); CHECK0 (":*", -1, ""); /* Empty field. */ CHECK (".", ".", -1, ""); CHECK ("The quick", "kciuq ehT", -1, ""); CHECK ("1,", ",", 0, "1"); CHECK0 (",", -1, ""); CHECK ("_2", "_", 1, "2"); CHECK0 ("_", -1, ""); CHECK ("A::B", ":", 0, "A"); CHECK0 (":", 3, "B"); CHECK0 (":", -1, ""); CHECK (" a\n\rb ", "\r\n ", 2, "a"); CHECK0 ("\r\n ", 5, "b"); CHECK0 ("\r\n ", -1, ""); /* String is approx. 256 bytes long. */ CHECK ("................................................................" "................................................................" "................................................................" "...............................................................5", ".", 255, "5"); CHECK ("................................................................" "................................................................" "................................................................" "................................................................6", ".", 256, "6"); return 0; }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { double *xptr; mxArray *xopt; const mxArray *func_name, *params; user_function_data udata; size_t nDim; unsigned int ii; bopt_params parameters; double *ub, *lb; /* Upper and lower bound */ double fmin; int error_code; /* Check correct number of parameters */ CHECK0(nlhs != 2 || nrhs != 3 || nrhs != 5, "wrong number of arguments"); /* TODO: Change This */ udata.neval = 0; udata.verbose = 0; /* First term is the function handle or name */ func_name = prhs[0]; if (mxIsChar(func_name)) { CHECK0(mxGetString(func_name, udata.f, FLEN) == 0, "error reading function name string (too long?)"); udata.nrhs = 1; udata.xrhs = 0; } #ifndef HAVE_OCTAVE else if (mxIsFunctionHandle(func_name)) { udata.prhs[0] = (mxArray *)func_name; strcpy(udata.f, "feval"); udata.nrhs = 2; udata.xrhs = 1; } #endif else { mexErrMsgTxt("First term should be a function name or function handle"); } /* Second parameter. nDim */ CHECK0(mxIsNumeric(prhs[1]) && !mxIsComplex(prhs[1]) && mxGetM(prhs[1]) * mxGetN(prhs[1]) == 1, "nDim must be a scalar"); nDim = (unsigned int) mxGetScalar(prhs[1]); udata.prhs[udata.xrhs] = mxCreateDoubleMatrix(1, nDim, mxREAL); xopt = mxCreateDoubleMatrix(1, nDim, mxREAL); xptr = mxGetPr(xopt); /* Third term. Parameters */ if (nrhs != 2) { CHECK0(mxIsStruct(prhs[2]), "3rd element must be a struct"); params = prhs[2]; } else { params = mxCreateStructMatrix(1,1,0,NULL); } parameters = load_parameters(params); if(nrhs == 5) { /* Load bounds */ mexPrintf("Loading bounds..."); CHECK0(mxIsDouble(prhs[3]) && !mxIsComplex(prhs[3]) && (mxGetM(prhs[3]) == 1 || mxGetN(prhs[3]) == 1) && (mxGetM(prhs[3]) == nDim || mxGetN(prhs[3]) == nDim), "lowerBound must be real row or column vector"); lb = mxGetPr(prhs[3]); CHECK0(mxIsDouble(prhs[4]) && !mxIsComplex(prhs[4]) && (mxGetM(prhs[4]) == 1 || mxGetN(prhs[4]) == 1) && (mxGetM(prhs[4]) == nDim || mxGetN(prhs[4]) == nDim), "upperBound must be real row or column vector"); ub = mxGetPr(prhs[4]); mexPrintf("done. \n"); } else { lb = (double*)(mxCalloc(nDim,sizeof(double))); ub = (double*)(mxCalloc(nDim,sizeof(double))); for (ii = 0; ii < nDim; ++ii) { lb[ii] = 0.; ub[ii] = 1.; } } error_code = bayes_optimization(nDim,user_function,&udata,lb,ub,xptr, &fmin,parameters); if(nrhs != 5) { mxFree(lb); mxFree(ub); } mxDestroyArray(udata.prhs[udata.xrhs]); plhs[0] = xopt; if (nlhs > 1) { plhs[1] = mxCreateDoubleMatrix(1, 1, mxREAL); *(mxGetPr(plhs[1])) = fmin; } if (nlhs > 2) { plhs[2] = mxCreateDoubleMatrix(1, 1, mxREAL); *(mxGetPr(plhs[2])) = (double)(error_code); } }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { double *xptr; mxArray *xopt; const mxArray *func_name, *params; user_function_data udata; size_t nDim,nPoints; double* xset; bopt_params parameters; double fmin = 0.0; int error_code; /* Check correct number of parameters */ CHECK0(nlhs != 2 || nrhs != 3, "wrong number of arguments"); /* TODO: Change This */ udata.neval = 0; udata.verbose = 0; /* First term is the function handle or name */ func_name = prhs[0]; if (mxIsChar(func_name)) { CHECK0(mxGetString(func_name, udata.f, FLEN) == 0, "error reading function name string (too long?)"); udata.nrhs = 1; udata.xrhs = 0; } #ifndef HAVE_OCTAVE else if (mxIsFunctionHandle(func_name)) { udata.prhs[0] = (mxArray *)func_name; strcpy(udata.f, "feval"); udata.nrhs = 2; udata.xrhs = 1; } #endif else { mexErrMsgTxt("First term should be a function name " "(Matlab/Octave) or function handle (Matlab)"); } /* Second parameter. Set of values. */ CHECK0(mxIsDouble(prhs[1]) && !mxIsComplex(prhs[1]) && mxGetNumberOfDimensions(prhs[1]) == 2, "The set of values must be a 2D real matrix."); nDim = mxGetM(prhs[1]); nPoints = mxGetN(prhs[1]); xset = mxGetPr(prhs[1]); mexPrintf("Loading set of values. nDims=%i, nPoints=%i\n",nDim,nPoints); udata.prhs[udata.xrhs] = mxCreateDoubleMatrix(1, nDim, mxREAL); xopt = mxCreateDoubleMatrix(1, nDim, mxREAL); xptr = mxGetPr(xopt); /* Third term. Parameters */ if (nrhs != 2) { CHECK0(mxIsStruct(prhs[2]), "3rd element must be a struct"); params = prhs[2]; } else { params = mxCreateStructMatrix(1,1,0,NULL); } parameters = load_parameters(params); error_code = bayes_optimization_disc(nDim,user_function,&udata,xset,nPoints, xptr,&fmin,parameters); mxDestroyArray(udata.prhs[udata.xrhs]); plhs[0] = xopt; if (nlhs > 1) { plhs[1] = mxCreateDoubleMatrix(1, 1, mxREAL); *(mxGetPr(plhs[1])) = fmin; } if (nlhs > 2) { plhs[2] = mxCreateDoubleMatrix(1, 1, mxREAL); *(mxGetPr(plhs[2])) = (double)(error_code); } }
bool Demuxer::didSeek(const Timer &timer, sf::Time oldPosition) { resetEndOfFileStatus(); sf::Time newPosition = timer.getOffset(); std::set< std::shared_ptr<Stream> > connectedStreams; if (m_connectedVideoStream) connectedStreams.insert(m_connectedVideoStream); if (m_connectedAudioStream) connectedStreams.insert(m_connectedAudioStream); if (m_connectedSubtitleStream) connectedStreams.insert(m_connectedSubtitleStream); CHECK(!connectedStreams.empty(), "Inconcistency error: seeking with no active stream"); // Trivial seeking to beginning if (newPosition == sf::Time::Zero) { int64_t timestamp = 0; if (m_formatCtx->iformat->flags & AVFMT_SEEK_TO_PTS && m_formatCtx->start_time != AV_NOPTS_VALUE) timestamp += m_formatCtx->start_time; // Flush all streams for (std::shared_ptr<Stream> stream : connectedStreams) stream->flushBuffers(); flushBuffers(); // Seek to beginning int err = avformat_seek_file(m_formatCtx, -1, INT64_MIN, timestamp, INT64_MAX, AVSEEK_FLAG_BACKWARD); if (err < 0) { sfeLogError("Error while seeking at time " + s(newPosition.asMilliseconds()) + "ms"); return false; } } else // Seeking to some other position { // Initial target seek point int64_t timestamp = newPosition.asSeconds() * AV_TIME_BASE; // < 0 = before seek point // > 0 = after seek point std::map< std::shared_ptr<Stream>, sf::Time> seekingGaps; static const float brokenSeekingThreshold = 60.f; // seconds bool didReseekBackward = false; bool didReseekForward = false; int tooEarlyCount = 0; int tooLateCount = 0; int brokenSeekingCount = 0; int ffmpegSeekFlags = AVSEEK_FLAG_BACKWARD; do { // Flush all streams for (std::shared_ptr<Stream> stream : connectedStreams) stream->flushBuffers(); flushBuffers(); // Seek to new estimated target if (m_formatCtx->iformat->flags & AVFMT_SEEK_TO_PTS && m_formatCtx->start_time != AV_NOPTS_VALUE) timestamp += m_formatCtx->start_time; int err = avformat_seek_file(m_formatCtx, -1, timestamp - 10 * AV_TIME_BASE, timestamp, timestamp, ffmpegSeekFlags); CHECK0(err, "avformat_seek_file failure"); // Compute the new gap for (std::shared_ptr<Stream> stream : connectedStreams) { sf::Time gap = stream->computeEncodedPosition() - newPosition; seekingGaps[stream] = gap; } tooEarlyCount = 0; tooLateCount = 0; brokenSeekingCount = 0; // Check the current situation for (std::pair< std::shared_ptr<Stream>, sf::Time>&& gapByStream : seekingGaps) { // < 0 = before seek point // > 0 = after seek point const sf::Time& gap = gapByStream.second; float absoluteDiff = fabs(gap.asSeconds()); // Before seek point if (gap < sf::Time::Zero) { if (absoluteDiff > brokenSeekingThreshold) { brokenSeekingCount++; tooEarlyCount++; } // else: a bit early but not too much, this is the final situation we want } // After seek point else if (gap > sf::Time::Zero) { tooLateCount++; if (absoluteDiff > brokenSeekingThreshold) brokenSeekingCount++; // TODO: unhandled for now => should seek to non-key frame } if (brokenSeekingCount > 0) sfeLogWarning("Seeking on " + gapByStream.first->description() + " is broken! Gap: " + s(gap.asSeconds()) + "s"); } CHECK(false == (tooEarlyCount && tooLateCount), "Both too late and too early for different streams, unhandled situation!"); // Define what to do next if (tooEarlyCount) { // Go forward by 1 sec timestamp += AV_TIME_BASE; didReseekForward = true; } else if (tooLateCount) { // Go backward by 1 sec timestamp -= AV_TIME_BASE; didReseekBackward = true; } if (brokenSeekingCount) { if (ffmpegSeekFlags & AVSEEK_FLAG_ANY) { sfeLogError("Seeking is really broken in the media, giving up"); return false; } else { // Try to seek to non-key frame before giving up // Image may be wrong but it's better than nothing :) ffmpegSeekFlags |= AVSEEK_FLAG_ANY; sfeLogError("Media has broken seeking index, trying to seek to non-key frame"); } } CHECK(!(didReseekBackward && didReseekForward), "infinitely seeking backward and forward"); } while (tooEarlyCount != 0 || tooLateCount != 0); } return true; }
Demuxer::Demuxer(const std::string& sourceFile, std::shared_ptr<Timer> timer, VideoStream::Delegate& videoDelegate, SubtitleStream::Delegate& subtitleDelegate) : m_formatCtx(nullptr), m_eofReached(false), m_streams(), m_ignoredStreams(), m_synchronized(), m_timer(timer), m_connectedAudioStream(nullptr), m_connectedVideoStream(nullptr), m_connectedSubtitleStream(nullptr), m_duration(sf::Time::Zero) { CHECK(sourceFile.size(), "Demuxer::Demuxer() - invalid argument: sourceFile"); CHECK(timer, "Inconsistency error: null timer"); int err = 0; // Load all the decoders loadFFmpeg(); // Open the movie file err = avformat_open_input(&m_formatCtx, sourceFile.c_str(), nullptr, nullptr); CHECK0(err, "Demuxer::Demuxer() - error while opening media: " + sourceFile); CHECK(m_formatCtx, "Demuxer() - inconsistency: media context cannot be nullptr"); // Read the general movie informations err = avformat_find_stream_info(m_formatCtx, nullptr); CHECK0(err, "Demuxer::Demuxer() - error while retreiving media information"); // Get the media duration if possible (otherwise rely on the streams) if (m_formatCtx->duration != AV_NOPTS_VALUE) { int64_t secs, us; secs = m_formatCtx->duration / AV_TIME_BASE; us = m_formatCtx->duration % AV_TIME_BASE; m_duration = sf::seconds(secs + (float)us / AV_TIME_BASE); } // Find all interesting streams for (unsigned int i = 0; i < m_formatCtx->nb_streams; i++) { AVStream* & ffstream = m_formatCtx->streams[i]; try { std::shared_ptr<Stream> stream; switch (ffstream->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: stream = std::make_shared<VideoStream>(m_formatCtx, ffstream, *this, timer, videoDelegate); if (m_duration == sf::Time::Zero) { extractDurationFromStream(ffstream); } sfeLogDebug("Loaded " + avcodec_get_name(ffstream->codec->codec_id) + " video stream"); break; case AVMEDIA_TYPE_AUDIO: stream = std::make_shared<AudioStream>(m_formatCtx, ffstream, *this, timer); if (m_duration == sf::Time::Zero) { extractDurationFromStream(ffstream); } sfeLogDebug("Loaded " + avcodec_get_name(ffstream->codec->codec_id) + " audio stream"); break; case AVMEDIA_TYPE_SUBTITLE: stream = std::make_shared<SubtitleStream>(m_formatCtx, ffstream, *this, timer, subtitleDelegate); sfeLogDebug("Loaded " + avcodec_get_name(ffstream->codec->codec_id) + " subtitle stream"); break; default: m_ignoredStreams[ffstream->index] = Stream::AVStreamDescription(ffstream); sfeLogDebug(m_ignoredStreams[ffstream->index] + " ignored"); break; } // Don't create an entry in the map unless everything went well and stream did not get ignored if (stream) m_streams[ffstream->index] = stream; } catch (std::runtime_error& e) { std::string streamDesc = Stream::AVStreamDescription(ffstream); sfeLogError("error while loading " + streamDesc + ": " + e.what()); CHECK(m_streams.find(ffstream->index) == m_streams.end(), "Internal inconcistency error: stream whose loading failed should not be stored"); } } if (m_duration == sf::Time::Zero) { sfeLogWarning("The media duration could not be retreived"); } m_timer->addObserver(*this, DemuxerTimerPriority); }