Exemplo n.º 1
0
/**
* @brief 
*
* @return 
*/
int FilterSwapUV::run()
{
    if ( waitForProviders() )
    {
        uint16_t inputWidth = videoProvider()->width();
        uint16_t inputHeight = videoProvider()->height();
        PixelFormat inputPixelFormat = videoProvider()->pixelFormat();
        ByteBuffer tempBuffer;
        int yChannelSize = inputWidth*inputHeight;
        int uvChannelSize = yChannelSize/4;

        if ( inputPixelFormat != PIX_FMT_YUV420P )
            Fatal( "Can't swap UV for pixel format %d", inputPixelFormat );

        while ( !mStop )
        {
            mQueueMutex.lock();
            if ( !mFrameQueue.empty() )
            {
                Debug( 3, "Got %zd frames on queue", mFrameQueue.size() );
                for ( FrameQueue::iterator iter = mFrameQueue.begin(); iter != mFrameQueue.end(); iter++ )
                {
                    //const VideoFrame *frame = dynamic_cast<const VideoFrame *>(iter->get());
                    //FramePtr framePtr( *iter );
                    const FeedFrame *frame = (*iter).get();

                    Debug(1, "%s / Provider: %s, Source: %s, Frame: %p (%ju / %.3f) - %lu", cname(), frame->provider()->cidentity(), frame->originator()->cidentity(), frame, frame->id(), frame->age(), frame->buffer().size() );

                    //Image image( inputPixelFormat, inputWidth, inputHeight, frame->buffer().data() );

                    tempBuffer.size( frame->buffer().size() );
                    memcpy( tempBuffer.data(), frame->buffer().data(), yChannelSize );
                    memcpy( tempBuffer.data()+yChannelSize, frame->buffer().data()+yChannelSize+uvChannelSize, uvChannelSize);
                    memcpy( tempBuffer.data()+yChannelSize+uvChannelSize, frame->buffer().data()+yChannelSize, uvChannelSize);
                    VideoFrame *videoFrame = new VideoFrame( this, *iter, mFrameCount, frame->timestamp(), tempBuffer );
                    distributeFrame( FramePtr( videoFrame ) );

                    //delete *iter;
                    mFrameCount++;
                }
                mFrameQueue.clear();
            }
            mQueueMutex.unlock();
            checkProviders();
            // Quite short so we can always keep up with the required packet rate for 25/30 fps
            usleep( INTERFRAME_TIMEOUT );
        }
    }
    FeedProvider::cleanup();
    FeedConsumer::cleanup();
    return( !ended() );
}
/**
* @brief 
*
* @return 
*/
int ImageTimestamper::run()
{
    if ( waitForProviders() )
    {
        uint16_t inputWidth = videoProvider()->width();
        uint16_t inputHeight = videoProvider()->height();
        PixelFormat inputPixelFormat = videoProvider()->pixelFormat();

        while ( !mStop )
        {
            mQueueMutex.lock();
            if ( !mFrameQueue.empty() )
            {
                Debug( 3, "Got %zd frames on queue", mFrameQueue.size() );
                for ( FrameQueue::iterator iter = mFrameQueue.begin(); iter != mFrameQueue.end(); iter++ )
                {
                    //const VideoFrame *frame = dynamic_cast<const VideoFrame *>(iter->get());
                    //FramePtr framePtr( *iter );
                    const FeedFrame *frame = (*iter).get();

                    Debug(1, "%s / Provider: %s, Source: %s, Frame: %p (%ju / %.3f) - %lu", cname(), frame->provider()->cidentity(), frame->originator()->cidentity(), frame, frame->id(), frame->age(), frame->buffer().size() );

                    Image image( inputPixelFormat, inputWidth, inputHeight, frame->buffer().data() );

                    if ( timestampImage( &image, frame->timestamp() ) )
                    {
                        VideoFrame *videoFrame = new VideoFrame( this, *iter, mFrameCount, frame->timestamp(), image.buffer() );
                        distributeFrame( FramePtr( videoFrame ) );
                    }
                    else
                    {
                        distributeFrame( *iter );
                    }

                    //delete *iter;
                    mFrameCount++;
                }
                mFrameQueue.clear();
            }
            mQueueMutex.unlock();
            checkProviders();
            // Quite short so we can always keep up with the required packet rate for 25/30 fps
            usleep( INTERFRAME_TIMEOUT );
        }
    }
    FeedProvider::cleanup();
    FeedConsumer::cleanup();
    return( !ended() );
}
Exemplo n.º 3
0
/**
* @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...
            }
Exemplo n.º 4
0
/**
* @brief 
*
* @return 
*/
int ImageScale::run()
{
    AVFrame *inputFrame = av_frame_alloc();
    AVFrame *outputFrame = av_frame_alloc();

    if ( waitForProviders() )
    {
        uint16_t inputWidth = videoProvider()->width();
        uint16_t inputHeight = videoProvider()->height();
        PixelFormat pixelFormat = videoProvider()->pixelFormat();

        mWidth = inputWidth * mScale;
        mHeight = inputHeight * mScale;

        // Prepare for image format and size conversions
        mScaleContext = sws_getContext( inputWidth, inputHeight, pixelFormat, mWidth, mHeight, pixelFormat, SWS_BILINEAR, NULL, NULL, NULL );
        if ( !mScaleContext )
            Fatal( "Unable to create scale context" );

        Debug( 1,"Scaling from %d x %d -> %d x %d", inputWidth, inputHeight, mWidth, mHeight );
        Debug( 1,"%d bytes -> %d bytes",  avpicture_get_size( pixelFormat, inputWidth, inputHeight ), avpicture_get_size( pixelFormat, mWidth, mHeight ) );

        // Make space for anything that is going to be output
        ByteBuffer outputBuffer;
        outputBuffer.size( avpicture_get_size( pixelFormat, mWidth, mHeight ) );

        // To get offsets only
        avpicture_fill( (AVPicture *)outputFrame, outputBuffer.data(), pixelFormat, mWidth, mHeight );

        while ( !mStop )
        {
            mQueueMutex.lock();
            if ( !mFrameQueue.empty() )
            {
                Debug( 3, "Got %zd frames on queue", mFrameQueue.size() );
                for ( FrameQueue::iterator iter = mFrameQueue.begin(); iter != mFrameQueue.end(); iter++ )
                {
                    //const VideoFrame *frame = dynamic_cast<const VideoFrame *>(iter->get());
                    //FramePtr framePtr( *iter );
                    const FeedFrame *frame = (*iter).get();

                    if ( mWidth != inputWidth || mHeight != inputHeight )
                    {
                        // Requires conversion
                        Debug( 1,"%s / Provider: %s, Source: %s, Frame: %p (%ju / %.3f) - %lu", cname(), frame->provider()->cidentity(), frame->originator()->cidentity(), frame, frame->id(), frame->age(), frame->buffer().size() );

                        avpicture_fill( (AVPicture *)inputFrame, frame->buffer().data(), pixelFormat, inputWidth, inputHeight );

                        // Reformat the input frame to fit the desired output format
                        if ( sws_scale( mScaleContext, inputFrame->data, inputFrame->linesize, 0, inputHeight, outputFrame->data, outputFrame->linesize ) < 0 )
                            Fatal( "Unable to convert input frame (%dx%d) to output frame (%dx%d) at frame %ju", inputWidth, inputHeight, mWidth, mHeight, mFrameCount );

                        VideoFrame *videoFrame = new VideoFrame( this, *iter, mFrameCount, frame->timestamp(), outputBuffer );
                        distributeFrame( FramePtr( videoFrame ) );
                    }
                    else
                    {
                        // Send it out 'as is'
                        distributeFrame( *iter );
                    }
                    //delete *iter;
                    mFrameCount++;
                }
                mFrameQueue.clear();
            }
            mQueueMutex.unlock();
            checkProviders();
            // Quite short so we can always keep up with the required packet rate for 25/30 fps
            usleep( INTERFRAME_TIMEOUT );
        }
        FeedProvider::cleanup();
        FeedConsumer::cleanup();
        sws_freeContext( mScaleContext );
        mScaleContext = NULL;
    }
    av_free( outputFrame );
    av_free( inputFrame );
    return( !ended() );
}