Exemple #1
0
/*****************************************************************************
 * Filter
 *****************************************************************************/
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
{
    picture_t * p_outpic;
    filter_sys_t *p_sys = p_filter->p_sys;

    if( !p_pic ) return NULL;

    p_outpic = filter_NewPicture( p_filter );
    if( !p_outpic )
    {
        picture_Release( p_pic );
        return NULL;
    }

    if( p_sys->b_first )
    {
        picture_CopyPixels( p_sys->p_tmp, p_pic );
        p_sys->b_first = false;
    }

    /* Get a new picture */
    RenderBlur( p_sys, p_pic, p_outpic );

    picture_CopyPixels( p_sys->p_tmp, p_outpic );

    return CopyInfoAndRelease( p_outpic, p_pic );
}
Exemple #2
0
static void Prepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpic)
{
    vout_display_sys_t *sys = vd->sys;
    picture_resource_t rsc = { .p_sys = NULL };
    void *planes[PICTURE_PLANE_MAX];

    sys->pic_opaque = sys->lock(sys->opaque, planes);

    for (unsigned i = 0; i < PICTURE_PLANE_MAX; i++) {
        rsc.p[i].p_pixels = planes[i];
        rsc.p[i].i_lines  = sys->lines[i];
        rsc.p[i].i_pitch  = sys->pitches[i];
    }

    picture_t *locked = picture_NewFromResource(&vd->fmt, &rsc);
    if (likely(locked != NULL)) {
        picture_CopyPixels(locked, pic);
        picture_Release(locked);
    }

    if (sys->unlock != NULL)
        sys->unlock(sys->opaque, sys->pic_opaque, planes);

    (void) subpic;
}
Exemple #3
0
static void SwapUV( picture_t *p_dst, const picture_t *p_src )
{
    picture_t tmp = *p_src;
    tmp.p[1] = p_src->p[2];
    tmp.p[2] = p_src->p[1];

    picture_CopyPixels( p_dst, &tmp );
}
/*****************************************************************************
 * PostprocPict
 *****************************************************************************/
static picture_t *PostprocPict( filter_t *p_filter, picture_t *p_pic )
{
    filter_sys_t *p_sys = p_filter->p_sys;

    const uint8_t *src[3];
    uint8_t *dst[3];
    int i_plane;
    int i_src_stride[3], i_dst_stride[3];

    picture_t *p_outpic = filter_NewPicture( p_filter );
    if( !p_outpic )
    {
        picture_Release( p_pic );
        return NULL;
    }

    /* Lock to prevent issues if pp_mode is changed */
    vlc_mutex_lock( &p_sys->lock );
    if( !p_sys->pp_mode )
    {
        vlc_mutex_unlock( &p_sys->lock );
        picture_CopyPixels( p_outpic, p_pic );
        return CopyInfoAndRelease( p_outpic, p_pic );
    }


    for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
    {
        src[i_plane] = p_pic->p[i_plane].p_pixels;
        dst[i_plane] = p_outpic->p[i_plane].p_pixels;

        /* I'm not sure what happens if i_pitch != i_visible_pitch ...
         * at least it shouldn't crash. */
        i_src_stride[i_plane] = p_pic->p[i_plane].i_pitch;
        i_dst_stride[i_plane] = p_outpic->p[i_plane].i_pitch;
    }

    if( !p_pic->p_q && p_sys->b_had_matrix )
    {
        msg_Warn( p_filter, "Quantification table was not set by video decoder. Postprocessing won't look good." );
        p_sys->b_had_matrix = false;
    }
    else if( p_pic->p_q )
    {
        p_sys->b_had_matrix = true;
    }

    pp_postprocess( src, i_src_stride, dst, i_dst_stride,
                    p_filter->fmt_in.video.i_width,
                    p_filter->fmt_in.video.i_height,
                    p_pic->p_q, p_pic->i_qstride,
                    p_sys->pp_mode, p_sys->pp_context,
                    p_pic->i_qtype == QTYPE_MPEG2 ? PP_PICT_TYPE_QP2 : 0 );
    vlc_mutex_unlock( &p_sys->lock );

    return CopyInfoAndRelease( p_outpic, p_pic );
}
Exemple #5
0
/****************************************************************************
 * Filter: the whole thing
 ****************************************************************************
 * This function is called just after the thread is launched.
 ****************************************************************************/
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
{
    filter_sys_t *p_sys = p_filter->p_sys;
    const video_format_t *p_fmti = &p_filter->fmt_in.video;
    const video_format_t *p_fmto = &p_filter->fmt_out.video;
    picture_t *p_pic_dst;

    /* Check if format properties changed */
    if( Init( p_filter ) )
    {
        picture_Release( p_pic );
        return NULL;
    }

    /* Request output picture */
    p_pic_dst = filter_NewPicture( p_filter );
    if( !p_pic_dst )
    {
        picture_Release( p_pic );
        return NULL;
    }

    /* */
    picture_t *p_src = p_pic;
    picture_t *p_dst = p_pic_dst;
    if( p_sys->i_extend_factor != 1 )
    {
        p_src = p_sys->p_src_e;
        p_dst = p_sys->p_dst_e;

        CopyPad( p_src, p_pic );
    }

    if( p_sys->b_copy && p_sys->b_swap_uvi == p_sys->b_swap_uvo )
        picture_CopyPixels( p_dst, p_src );
    else if( p_sys->b_copy )
        SwapUV( p_dst, p_src );
    else
        Convert( p_filter, p_sys->ctx, p_dst, p_src, p_fmti->i_height, 0, 3,
                 p_sys->b_swap_uvi, p_sys->b_swap_uvo );
    if( p_sys->ctxA )
    {
        /* We extract the A plane to rescale it, and then we reinject it. */
        if( p_fmti->i_chroma == VLC_CODEC_RGBA )
            ExtractA( p_sys->p_src_a, p_src, p_fmti->i_width * p_sys->i_extend_factor, p_fmti->i_height );
        else
            plane_CopyPixels( p_sys->p_src_a->p, p_src->p+A_PLANE );

        Convert( p_filter, p_sys->ctxA, p_sys->p_dst_a, p_sys->p_src_a, p_fmti->i_height, 0, 1, false, false );
        if( p_fmto->i_chroma == VLC_CODEC_RGBA )
            InjectA( p_dst, p_sys->p_dst_a, p_fmto->i_width * p_sys->i_extend_factor, p_fmto->i_height );
        else
            plane_CopyPixels( p_dst->p+A_PLANE, p_sys->p_dst_a->p );
    }
    else if( p_sys->b_add_a )
    {
        /* We inject a complete opaque alpha plane */
        if( p_fmto->i_chroma == VLC_CODEC_RGBA )
            FillA( &p_dst->p[0], OFFSET_A );
        else
            FillA( &p_dst->p[A_PLANE], 0 );
    }

    if( p_sys->i_extend_factor != 1 )
    {
        picture_CopyPixels( p_pic_dst, p_dst );
    }

    picture_CopyProperties( p_pic_dst, p_pic );
    picture_Release( p_pic );
    return p_pic_dst;
}
Exemple #6
0
void picture_Copy( picture_t *p_dst, const picture_t *p_src )
{
    picture_CopyPixels( p_dst, p_src );
    picture_CopyProperties( p_dst, p_src );
}
/*****************************************************************************
 * Filter: displays previously rendered output
 *****************************************************************************
 * This function send the currently rendered image to the internal opencv
 * filter for processing.
 *****************************************************************************/
static picture_t* Filter( filter_t* p_filter, picture_t* p_pic )
{
    picture_t* p_outpic = filter_NewPicture( p_filter );
    if( p_outpic == NULL ) {
        msg_Err( p_filter, "couldn't get a p_outpic!" );
        picture_Release( p_pic );
        return NULL;
    }

    video_format_t fmt_out;

    // Make a copy if we want to show the original input
    if (p_filter->p_sys->i_wrapper_output == VINPUT)
        picture_Copy( p_outpic, p_pic );

    VlcPictureToIplImage( p_filter, p_pic );
    // Pass the image (as a pointer to the first IplImage*) to the
    // internal OpenCV filter for processing.
    p_filter->p_sys->p_opencv->pf_video_filter( p_filter->p_sys->p_opencv, (picture_t*)&(p_filter->p_sys->p_cv_image[0]) );

    if(p_filter->p_sys->i_wrapper_output == PROCESSED) {
        // Processed video
        if( (p_filter->p_sys->p_proc_image) &&
            (p_filter->p_sys->p_proc_image->i_planes > 0) &&
            (p_filter->p_sys->i_internal_chroma != CINPUT) ) {
            //p_filter->p_sys->p_proc_image->format.i_chroma = VLC_CODEC_RGB24;

            memset( &fmt_out, 0, sizeof(video_format_t) );
            fmt_out = p_pic->format;
            //picture_Release( p_outpic );

            /*
             * We have to copy out the image from image_Convert(), otherwise
             * you leak pictures for some reason:
             * main video output error: pictures leaked, trying to workaround
             */
            picture_t* p_outpic_tmp = image_Convert(
                        p_filter->p_sys->p_image,
                        p_filter->p_sys->p_proc_image,
                        &(p_filter->p_sys->p_proc_image->format),
                        &fmt_out );

            picture_CopyPixels( p_outpic, p_outpic_tmp );
            CopyInfoAndRelease( p_outpic, p_outpic_tmp );
        } else if( p_filter->p_sys->i_internal_chroma == CINPUT ) {
            picture_CopyPixels( p_outpic, p_filter->p_sys->p_proc_image );
            picture_CopyProperties( p_outpic, p_filter->p_sys->p_proc_image );
        }
    }

    ReleaseImages( p_filter );
    picture_Release( p_pic );

#ifndef NDEBUG
    msg_Dbg( p_filter, "Filter() done" );
#endif

    if( p_filter->p_sys->i_wrapper_output != NONE ) {
        return p_outpic;
    } else { // NONE
        picture_Release( p_outpic );
        return NULL;
    }
}
Exemple #8
0
/**
 * @brief VLC filter callback
 * @return picture(s) containing the filtered frames
 */
 static picture_t* y4m_filter(filter_t* intf, picture_t* srcPic)
{
    filter_sys_t* sys = intf->p_sys;

    //msg_Info(intf, ">>>> filter");

    if (!srcPic)
    {
        //msg_Info(intf, ">>> filter: NULL INPUT");
        return NULL;
    }

    // will be stored to sys->lastDate on return
    mtime_t currDate = srcPic->date;


    // if there was a problem with the subprocess then send back
    // the picture unmodified, at least we won't freeze up vlc
    if (sys->startFailed || sys->threadExit)
        goto ECHO_RETURN;


    // start subprocess and write the y4m header
    // fixme: this can go in open() if fmt_in matches the srcPic
    if (!sys->startFailed && !sys->childPid)
    {
        sys->startFailed = !startProcess(intf);
        if (sys->startFailed)
            goto ECHO_RETURN;

        if (0 >= writeY4mHeader(intf, srcPic, sys->stdin))
        {
            msg_Err(intf, "writeY4mHeader failed: errno=%d %s",
                errno, strerror(errno));

            stopProcess(intf);
            sys->startFailed = true;

            goto ECHO_RETURN;
        }
    }

    //
    // control the buffering level by monitoring the input/output fifos
    //
    // the input/output fifos are emptied/filled by input/output threads
    // in response to the subprocess reading/writing frames
    //
    // if the input fifo is empty, then probably the subprocess wants
    // more input, so we should buffer more input
    //
    // if the output fifo is empty, and the input fifo is not empty, then
    // probably the subprocess is about to write out a frame and we
    // can wait for it to arrive. in practice, most of the time there
    // is no waiting needed, unless the filter is too slow to keep up.
    //
    bool inputEmpty = true;
    bool outputEmpty = true;

    picture_t* tmp = picture_fifo_Peek(sys->inputFifo);
    if (tmp)
    {
        picture_Release(tmp);
        inputEmpty = false;
    }

    tmp = picture_fifo_Peek(sys->outputFifo);
    if (tmp)
    {
        picture_Release(tmp);
        outputEmpty = false;
    }

    // copy picture to input fifo, we can't use picture_Hold or else
    // the decoder or vout would run out of pictures in its pool
    picture_t* inPic = picture_NewFromFormat(&srcPic->format);
    picture_Copy(inPic, srcPic);
    picture_fifo_Push(sys->inputFifo, inPic);

    // signal input thread to wake up and write some more data out
    vlc_mutex_lock(&sys->inputMutex);
    sys->bufferedIn++;
    vlc_cond_signal(&sys->inputCond);
    vlc_mutex_unlock(&sys->inputMutex);

    // if echo is enabled, we're done
    // todo: there should be a limiter on the input buffering in case
    // the subprocess can't keep up
    if (sys->echo)
        goto ECHO_RETURN;


    // keeps track of the number of buffered output pictures, assumes
    // an integer ratio
    // fixme: needs modification to support non-integer ratios
    // and ratios < 1
    sys->bufferedOut += sys->bufferRatio;

    // handle buffering
    if (outputEmpty && inputEmpty)
    {
        // we haven't supplied enough input, raise the minimum
        // level of buffer to keep and return
        sys->minBuffered += sys->bufferRatio;

        msg_Info(intf, "buffer more input: buffers:%d:%d:%d",
                sys->bufferedIn, sys->bufferedOut, sys->minBuffered);

        goto NULL_RETURN;
    }

    if (outputEmpty)
        waitForOutput(intf);

    // if we don't know what the frame interval is, make it 0 which
    // probably causes the next frames out to drop
    // note: this happens at least every time y4m_flush() is called
    // for example when seeking
    if (currDate <= sys->lastDate || sys->lastDate == 0)
    {
        //msg_Err(intf, "currDate <= lastDate");
        //goto ECHO_RETURN;
        sys->lastDate = currDate;
    }

    // reference to first and last picture we are returning
    picture_t* first = NULL;
    picture_t* last = NULL;


    picture_t* pic;
    while( (pic = picture_fifo_Pop(sys->outputFifo)) )
    {
        // do output setup when we see the first frame out from the filter,
        // it could have a different frame rate, chroma, size, etc than
        // the frame going in
        if (!sys->gotFirstOutput)
        {
            sys->gotFirstOutput = true;

            // get the in/out frame ratio by comparing frame rates
            float speed =
                    ((float)srcPic->format.i_frame_rate_base * (float)pic->format.i_frame_rate) /
                    ((float)srcPic->format.i_frame_rate      * (float)pic->format.i_frame_rate_base);

            if (speed < 1.0)
            {
                msg_Err(intf, "frame rate reduction isn't supported yet");
            }
            else
            if (speed > 1.0)
            {
                if (ceil(speed) != speed)
                    msg_Err(intf, "frame rate change must be integer ratio");

                sys->bufferRatio = speed;

                // initial ratio was 1.0, need to correct the number of buffered frames
                // now that we know what it is
                sys->bufferedOut *= sys->bufferRatio;
                sys->minBuffered *= sys->bufferRatio;
            }

            intf->fmt_out.video.i_frame_rate = pic->format.i_frame_rate;
            intf->fmt_out.video.i_frame_rate_base = pic->format.i_frame_rate_base;

            if (intf->fmt_out.video.i_chroma != pic->format.i_chroma)
                msg_Err(intf, "filter changed the chroma, expect corruption");

            // this can't be changed after open, crashes the GLX vout
            //intf->fmt_out.i_codec = pic->format.i_chroma;
            //intf->fmt_out.video.i_chroma = pic->format.i_chroma;

            msg_Info(intf, "first output: buffers=%d:%d", sys->bufferedOut, sys->minBuffered);
        }

        sys->numFrames++;
        sys->bufferedOut--;

        // it seems filter_NewPicture is required now. however,
        // sometimes it returns null in which case it seems like
        // the best thing to do is dump frames
        picture_t* copy = first == NULL ? srcPic : filter_NewPicture(intf);
        if (!copy)
        {
            picture_Release(pic);

            // throw away frames

            // vlc already prints warning for this
            //msg_Err(intf, "filter_NewPicture returns null");
            if (sys->bufferedOut < sys->minBuffered)
                break;
            else
                continue;
        }
        else
        {
            picture_CopyPixels(copy, pic);
            picture_Release(pic);
            pic = copy;
        }

        // the time per output frame interval is a fraction of the input frame time
        int frameTime = (currDate - sys->lastDate) / sys->bufferRatio;

        // the pts is whatever the current pts is minus any buffering
        // introduced by the filter
        pic->date = currDate - sys->bufferedOut*frameTime;

//        msg_Info(intf, "frame=%d buffered=%d:%d frameTime=%d ratio:%d:1 fin=%d:%d fout=%d:%d pts=%u",
//            sys->numFrames, sys->bufferedOut, sys->minBuffered,
//            frameTime, sys->bufferRatio,
//            srcPic->format.i_frame_rate, srcPic->format.i_frame_rate_base,
//            pic->format.i_frame_rate, pic->format.i_frame_rate_base,
//            (unsigned int)pic->date);

        if (last)
            last->p_next = pic;
        else
            first = pic;
        last = pic;


        // if we read too many frames on this iteration, on the next
        // one we might not have any frames available which would be
        // bad as vlc would think our intent was to drop frames
        //
        // if we stop reading before the output is completely empty,
        // there will always be some frames for the next iteration,
        // assuming the filter is fast enough to keep up
        if (sys->bufferedOut  < sys->minBuffered)
            break;

        // if there is still some input buffer left, but the fifo is
        // empty, wait for next frame to arrive. otherwise we can
        // build too much input buffering
        if (sys->bufferedIn > 1)
            waitForOutput(intf);
    }

    if (!first)
    {
        // the buffer checks should prevent from getting here, but
        // just in case prevent leaking the input picture
        picture_Release(srcPic);

        sys->minBuffered++;
    }

    sys->lastDate = currDate;
    return first;
ECHO_RETURN:
    sys->lastDate = currDate;
    //msg_Info(intf, "<<<< filter: ECHO");
    return srcPic;
NULL_RETURN:
    sys->lastDate = currDate;
    picture_Release(srcPic);
    //msg_Info(intf, "<<<< filter: NULL");
    return NULL;
}