/** * @brief */ void FeedProvider::removeFromMap() { smProviderMutex.lock(); if ( smProviders.erase( identity() ) != 1 ) Error( "Unable to remove provider %s from map, not found", cidentity() ) smProviderMutex.unlock(); }
/** * @brief */ void FeedProvider::addToMap() { smProviderMutex.lock(); std::pair<ProviderMap::iterator,bool> result = smProviders.insert( ProviderMap::value_type( identity(), this ) ); if ( !result.second ) Fatal( "Unable to add duplicate provider %s to map", cidentity() ) smProviderMutex.unlock(); }
/** * @brief * * @param consumer * @param reciprocate * * @return */ bool FeedProvider::deregisterConsumer( FeedConsumer &consumer, bool reciprocate ) { Debug( 2, "%s - Deregistering consumer %s", cidentity(), consumer.cidentity() ); mConsumerMutex.lock(); bool result = ( mConsumers.erase( &consumer ) == 1 ); mConsumerMutex.unlock(); if ( reciprocate && consumer.hasProvider( *this ) ) consumer.deregisterProvider( *this ); return( result ); }
/** * @brief * * @param consumer * @param link * * @return */ bool FeedProvider::registerConsumer( FeedConsumer &consumer, const FeedLink &link ) { Debug( 2, "%s - Registering consumer %s", cidentity(), consumer.cidentity() ); if ( !mCanPoll && link.isPolled() ) Fatal( "%s - Attempt to register consumer %s with polled link, not supported for this provider", cidentity(), consumer.cidentity() ); mConsumerMutex.lock(); std::pair<ConsumerMap::iterator,bool> result = mConsumers.insert( ConsumerMap::value_type( &consumer, link ) ); mConsumerMutex.unlock(); if ( !consumer.hasProvider( *this ) ) consumer.registerProvider( *this ); return( result.second ); }
/** * @brief * * @return */ int H264Encoder::run() { // TODO - This section needs to be rewritten to read the configuration from the values saved // for the streams via the web gui AVDictionary *opts = NULL; //avSetH264Preset( &opts, "default" ); //avSetH264Profile( &opts, "main" ); //avDictSet( &opts, "level", "4.1" ); avSetH264Preset( &opts, "ultrafast" ); //avSetH264Profile( &opts, "baseline" ); avDictSet( &opts, "level", "31" ); avDictSet( &opts, "g", "24" ); //avDictSet( &opts, "b", (int)mBitRate ); //avDictSet( &opts, "bitrate", (int)mBitRate ); //avDictSet( &opts, "crf", "24" ); //avDictSet( &opts, "framerate", (double)mFrameRate ); //avDictSet( &opts, "fps", (double)mFrameRate ); //avDictSet( &opts, "r", (double)mFrameRate ); //avDictSet( &opts, "timebase", "1/90000" ); avDumpDict( opts ); // Make sure ffmpeg is compiled with libx264 support AVCodec *codec = avcodec_find_encoder( CODEC_ID_H264 ); if ( !codec ) Fatal( "Can't find encoder codec" ); mCodecContext = avcodec_alloc_context3( codec ); mCodecContext->width = mWidth; mCodecContext->height = mHeight; //mCodecContext->time_base = TimeBase( 1, 90000 ); mCodecContext->time_base = mFrameRate.timeBase(); mCodecContext->bit_rate = mBitRate; mCodecContext->pix_fmt = mPixelFormat; mCodecContext->gop_size = 24; //mCodecContext->max_b_frames = 1; Debug( 2, "Time base = %d/%d", mCodecContext->time_base.num, mCodecContext->time_base.den ); Debug( 2, "Pix fmt = %d", mCodecContext->pix_fmt ); /* open it */ if ( avcodec_open2( mCodecContext, codec, &opts ) < 0 ) Fatal( "Unable to open encoder codec" ); avDumpDict( opts ); AVFrame *inputFrame = avcodec_alloc_frame(); Info( "%s:Waiting", cidentity() ); if ( waitForProviders() ) { Info( "%s:Waited", cidentity() ); // Find the source codec context uint16_t inputWidth = videoProvider()->width(); uint16_t inputHeight = videoProvider()->height(); PixelFormat inputPixelFormat = videoProvider()->pixelFormat(); //FrameRate inputFrameRate = videoProvider()->frameRate(); //Info( "CONVERT: %d-%dx%d -> %d-%dx%d", //inputPixelFormat, inputWidth, inputHeight, //mPixelFormat, mWidth, mHeight //); // Make space for anything that is going to be output AVFrame *outputFrame = avcodec_alloc_frame(); ByteBuffer outputBuffer; outputBuffer.size( avpicture_get_size( mCodecContext->pix_fmt, mCodecContext->width, mCodecContext->height ) ); avpicture_fill( (AVPicture *)outputFrame, outputBuffer.data(), mCodecContext->pix_fmt, mCodecContext->width, mCodecContext->height ); // Prepare for image format and size conversions struct SwsContext *convertContext = sws_getContext( inputWidth, inputHeight, inputPixelFormat, mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL ); if ( !convertContext ) Fatal( "Unable to create conversion context for encoder" ); int outSize = 0; uint64_t timeInterval = mFrameRate.intervalUsec(); uint64_t currTime = time64(); uint64_t nextTime = currTime; //outputFrame->pts = currTime; outputFrame->pts = 0; uint32_t ptsInterval = 90000/mFrameRate.toInt(); //uint32_t ptsInterval = mFrameRate.intervalPTS( mCodecContext->time_base ); while ( !mStop ) { // Synchronise the output with the desired output frame rate while ( currTime < nextTime ) { currTime = time64(); usleep( 1000 ); } nextTime += timeInterval; FramePtr framePtr; mQueueMutex.lock(); if ( !mFrameQueue.empty() ) { if ( mInitialFrame.empty() || !mConsumers.empty() ) { FrameQueue::iterator iter = mFrameQueue.begin(); framePtr = *iter; } mFrameQueue.clear(); } mQueueMutex.unlock(); if ( framePtr.get() ) { const FeedFrame *frame = framePtr.get(); const VideoFrame *inputVideoFrame = dynamic_cast<const VideoFrame *>(frame); //Info( "Provider: %s, Source: %s, Frame: %d", inputVideoFrame->provider()->cidentity(), inputVideoFrame->originator()->cidentity(), inputVideoFrame->id() ); //Info( "PF:%d @ %dx%d", inputVideoFrame->pixelFormat(), inputVideoFrame->width(), inputVideoFrame->height() ); avpicture_fill( (AVPicture *)inputFrame, inputVideoFrame->buffer().data(), inputPixelFormat, inputWidth, inputHeight ); //outputFrame->pts = currTime; //Debug( 5, "PTS %jd", outputFrame->pts ); // Reformat the input frame to fit the desired output format //Info( "SCALE: %d -> %d", int(inputFrame->data[0])%16, int(outputFrame->data[0])%16 ); if ( sws_scale( convertContext, inputFrame->data, inputFrame->linesize, 0, inputHeight, outputFrame->data, outputFrame->linesize ) < 0 ) Fatal( "Unable to convert input frame (%d@%dx%d) to output frame (%d@%dx%d) at frame %ju", inputPixelFormat, inputWidth, inputHeight, mCodecContext->pix_fmt, mCodecContext->width, mCodecContext->height, mFrameCount ); // Encode the image outSize = avcodec_encode_video( mCodecContext, outputBuffer.data(), outputBuffer.capacity(), outputFrame ); Debug( 5, "Encoding reports %d bytes", outSize ); if ( outSize > 0 ) { //Info( "CPTS: %jd", mCodecContext->coded_frame->pts ); outputBuffer.size( outSize ); //Debug( 5, "PTS2 %jd", mCodecContext->coded_frame->pts ); if ( mInitialFrame.empty() ) { Debug( 3, "Looking for H.264 stream info" ); const uint8_t *startPos = outputBuffer.head(); startPos = h264StartCode( startPos, outputBuffer.tail() ); while ( startPos < outputBuffer.tail() ) { while( !*(startPos++) ) ; const uint8_t *nextStartPos = h264StartCode( startPos, outputBuffer.tail() ); int frameSize = nextStartPos-startPos; unsigned char type = startPos[0] & 0x1F; unsigned char nri = startPos[0] & 0x60; Debug( 1, "Type %d, NRI %d (%02x)", type, nri>>5, startPos[0] ); if ( type == NAL_SEI ) { // SEI mSei.assign( startPos, frameSize ); } else if ( type == NAL_SPS ) { // SPS Hexdump( 2, startPos, frameSize ); mSps.assign( startPos, frameSize ); if ( frameSize < 4 ) Panic( "H.264 NAL type 7 frame too short (%d bytes) to extract level/profile", frameSize ); mAvcLevel = startPos[3]; mAvcProfile = startPos[1]; Debug( 2, "Got AVC level %d, profile %d", mAvcLevel, mAvcProfile ); } else if ( type == NAL_PPS ) { // PPS Hexdump( 2, startPos, frameSize ); mPps.assign( startPos, frameSize ); } startPos = nextStartPos; } mInitialFrame = outputBuffer; //VideoFrame *outputVideoFrame = new VideoFrame( this, ++mFrameCount, mCodecContext->coded_frame->pts, mInitialFrame ); } else { //av_rescale_q(cocontext->coded_frame->pts, cocontext->time_base, videostm->time_base); VideoFrame *outputVideoFrame = new VideoFrame( this, ++mFrameCount, mCodecContext->coded_frame->pts, outputBuffer ); distributeFrame( FramePtr( outputVideoFrame ) ); } } outputFrame->pts += ptsInterval; ///< FIXME - This can't be right, but it works... }
void test_fn (void) { double complex v = cidentity(4.+3.j); printf("test_fn(): %lg%+lgj\n\n", creal(v), cimag(v)); }