Ejemplo n.º 1
0
Archivo: iso2022.c Proyecto: aosm/X11
static void
outbuf_flush(Iso2022Ptr is, int fd)
{
    int rc;
    int i = 0;

    if(olog >= 0)
        write(olog, is->outbuf, is->outbuf_count);

    while(i < is->outbuf_count) {
        rc = write(fd, is->outbuf + i, is->outbuf_count - i);
        if(rc > 0) {
            i += rc;
        } else {
            if(rc < 0 && errno == EINTR)
                continue;
            else if((rc == 0) || ((rc < 0) && (errno == EAGAIN))) {
                waitForOutput(fd);
                continue;
            } else
                break;
        }
    }
    is->outbuf_count = 0;
}
Ejemplo n.º 2
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;
}