XIRef<XTimeZone> XUTC::Instance() { XGuard lock(_cInstanceLock); static XIRef<XTimeZone> instance; if( instance.IsEmpty() ) instance = new XUTC; return instance; }
XIRef<XTimeZone> XLocalTime::Instance() { XGuard lock(_cInstanceLock); static XIRef<XTimeZone> instance; if( instance.IsEmpty() ) { instance = new XLocalTime; #ifndef WIN32 tzset(); #endif } return instance; }
void TranscodeExport::Create( XIRef<XMemory> output ) { XString tempFileName = _GetTMPName( _fileName ); // If their is only 1 export in progress (us), but the temp file exists then it means we were interrupted // (either a power issue, or a segfault) and we should delete the temporary. if( _exportsInProgress == 1 ) { if( XPath::Exists(tempFileName) ) unlink(tempFileName.c_str()); } if( XPath::Exists(tempFileName) ) X_THROW(("Export in progress exception: %s", tempFileName.c_str())); bool outputToFile = (output.IsEmpty()) ? true : false; H264Decoder decoder( GetFastH264DecoderOptions() ); XRef<YUV420PToARGB24> yuvToARGB = new YUV420PToARGB24; XRef<ARGB24ToYUV420P> argbToYUV = new ARGB24ToYUV420P; XRef<H264Transcoder> transcoder; XRef<H264Encoder> encoder; XRef<AVMuxer> muxer; XRef<ExportOverlay> ov; bool wroteToContainer = false; auto lastProgressTime = steady_clock::now(); // We are going to count how many decoding or encoding exceptions we get... If it // ever exceeds some large threshold, we bail on this export. int64_t codingExceptions = 0; XString recorderURI; while( _recorderURLS.GetNextURL( recorderURI ) ) { auto now = steady_clock::now(); if( wroteToContainer && duration_cast<seconds>(now-lastProgressTime).count() > 2 ) { _progress( _recorderURLS.PercentComplete() ); lastProgressTime = now; } try { XIRef<XMemory> responseBuffer = FRAME_STORE_CLIENT::FetchMedia( _config->GetRecorderIP(), _config->GetRecorderPort(), recorderURI ); ResultParser resultParser; resultParser.Parse( responseBuffer ); FRAME_STORE_CLIENT::ResultStatistics stats = resultParser.GetStatistics(); // If we are not provided with a bit rate or a frame rate, we use the sources values. if( _bitRate == 0 ) _bitRate = stats.averageBitRate; if( _maxRate == 0 ) _maxRate = 2 * stats.averageBitRate; if( _bufSize == 0 ) _bufSize = 2 * stats.averageBitRate; if( _frameRate == 0.0 ) _frameRate = stats.frameRate; // Fix for ffmpeg's inability to make files with fps < 6.0. Don't believe me? Try these 2 commands and play // output in vlc: // // # generate a test movie of the game of life in life.mp4 // ffmpeg -f lavfi -i life -frames:v 1000 life.mp4 // # transcode and drop framerate of life.mp4 to 1 fps. output.mp4 won't play in vlc and will have a weird // # pause at the beginning for other players. // ffmpeg -i life.mp4 -vf fps=fps=1/1 -vcodec h264 output.mp4 // if( _frameRate < 6.0 ) _frameRate = 6.0; int outputTimeBaseNum = 0; int outputTimeBaseDen = 0; int inputTimeBaseNum = 0; int inputTimeBaseDen = 0; AVKit::DToQ( (1/stats.frameRate), inputTimeBaseNum, inputTimeBaseDen ); AVKit::DToQ( (1/_frameRate), outputTimeBaseNum, outputTimeBaseDen ); if( transcoder.IsEmpty() ) { transcoder = new H264Transcoder( inputTimeBaseNum, inputTimeBaseDen, outputTimeBaseNum, outputTimeBaseDen, _speed, // if our input is key only, enable decode skipping... _recorderURLS.KeyFrameOnly() ); } double secondsPer = AVKit::QToD(inputTimeBaseNum, inputTimeBaseDen) / (AVKit::QToD(inputTimeBaseNum, inputTimeBaseDen) / (AVKit::QToD(outputTimeBaseNum, outputTimeBaseDen) * _speed)); int traversalNum = 0; int traversalDen = 0; AVKit::DToQ( secondsPer, traversalNum, traversalDen ); while( !resultParser.EndOfFile() ) { try { if( transcoder->Decode( resultParser, decoder ) ) { if( encoder.IsEmpty() ) _FinishInit( encoder, muxer, decoder, tempFileName, outputToFile, traversalNum, traversalDen ); if( ov.IsEmpty() ) ov = new ExportOverlay( _msg, _withTime, _hAlign, _vAlign, decoder.GetOutputWidth(), decoder.GetOutputHeight(), traversalNum, traversalDen ); yuvToARGB->Transform( decoder.Get(), decoder.GetOutputWidth(), decoder.GetOutputHeight() ); XIRef<Packet> rgb = yuvToARGB->Get(); XIRef<Packet> withOverlay = ov->Process( rgb, resultParser.GetFrameTS() ); argbToYUV->Transform( withOverlay, decoder.GetOutputWidth(), decoder.GetOutputHeight() ); transcoder->EncodeYUV420PAndMux( *encoder, *muxer, argbToYUV->Get() ); wroteToContainer = true; } } catch(XException& ex) { X_LOG_NOTICE("Coding exception: %s",ex.what()); ++codingExceptions; // If we have had a LOT of decoding or encoding exceptions, just give up. if( codingExceptions > 100000 ) throw ex; } } } catch( XException& ex ) { X_LOG_NOTICE("Exception thrown while processing export. Continuing: %s",ex.what()); } } if( wroteToContainer ) _progress( 1.0 ); else X_STHROW( HTTP404Exception, ("No video was found during entire export.")); if( outputToFile ) { muxer->FinalizeFile(); rename( tempFileName.c_str(), _fileName.c_str() ); } else muxer->FinalizeBuffer( output ); }