[FFmpeg-devel] [PATCH 2/3] ffplay: convert to new decode API

Marton Balint cus at passwd.hu
Sat Mar 18 02:51:39 EET 2017


On Sat, 18 Mar 2017, wallak at free.fr wrote:

> The logs:  http://pastebin.com/1duYR0Ui
>

Log with video only (run ffplay with -an -sn) might show it more clearly, 
but even from the logs above it looks like the CrystalHD codec is 
returning EAGAINs at the same time for both receive_frame and send_packet. 
If it indeed does work in ffmpeg, then I suspect a lot of busy waiting 
there. Philip, you mind taking a look? :)

Thanks,
Marton


> Wallak.
>
>
> ----- Mail original -----
> De: "Marton Balint" <cus at passwd.hu>
> À: "FFmpeg development discussions and patches" <ffmpeg-devel at ffmpeg.org>
> Cc: wallak at free.fr
> Envoyé: Vendredi 17 Mars 2017 23:38:31
> Objet: Re: [FFmpeg-devel] [PATCH 2/3] ffplay: convert to new decode API
>
>
>
> On Fri, 17 Mar 2017, wallak at free.fr wrote:
>
>> I tried the patch. Once av_assert0 test is removed, the crystalhd
>> decoder is running till send_packet triggers AVERROR(EAGAIN), now the
>> crystalhd buffer is likely overflowed, the video freezes. A few seconds
>> later the decoder displays a few frames and the cycle goes on.
>>
>> Im not sure how to properly implement the function to stop or resend
>> send_packet frames, this is likely the only mechanism missing.
>
> Hmm. Theoretically an assertion at send_packet can only happen, if the
> CrystalHD decoder is is returning AVERROR(EAGAIN) for receive_frame
> and for send_packet as well, which is forbidden.
>
> Could you add some logging, and log the return values of both send_packet
> and receive_frame to make sure that is the case, and the crystalHD decoder
> is buggy, not my implementation of the new decode API?
>
> I tested h264_cuvid decoder with ffplay (the only decoder with the new
> API), and that worked so I am inclined to think CrystalHD is buggy. And
> the behaviour you described looks like once the buffers of CrystalHD
> is full, but no decoded frame is available yet, it simply returns
> AVERROR(EAGAIN) instead of blocking receive_frame call which it should do.
>
> Thanks,
> Marton
>
>> Best Regards,
>> Wallak.
>>
>>
>>
>> ----- Mail original -----
>> De: "Marton Balint" <cus at passwd.hu>
>> À: "FFmpeg development discussions and patches" <ffmpeg-devel at ffmpeg.org>
>> Cc: wallak at free.fr
>> Envoyé: Jeudi 16 Mars 2017 23:25:18
>> Objet: Re: [FFmpeg-devel] [PATCH 2/3] ffplay: convert to new decode API
>>
>>
>>
>> On Wed, 15 Mar 2017, Marton Balint wrote:
>>
>>> Since subtitles are not yet supported with the new API, CODEC_CAP_DELAY
>>> subtitle codecs (only libzvbi so far) may loose the last few buffered frames in
>>> the end of the stream.
>>>
>>> The impact of this is so limited, it seemded better to accept it than losing
>>> the simplification benefits of the new API.
>>
>> Hi Wallak,
>>
>> Have you had a chance to test this ffplay patch, and see if it fixes
>> CrystalHD decoding in ffplay or not?
>>
>> Thanks,
>> Marton
>>
>>>
>>> Signed-off-by: Marton Balint <cus at passwd.hu>
>>> ---
>>> ffplay.c | 92 +++++++++++++++++++++++++++++-----------------------------------
>>> 1 file changed, 41 insertions(+), 51 deletions(-)
>>>
>>> diff --git a/ffplay.c b/ffplay.c
>>> index cf138dc..06d1d22 100644
>>> --- a/ffplay.c
>>> +++ b/ffplay.c
>>> @@ -186,13 +186,10 @@ enum {
>>> };
>>>
>>> typedef struct Decoder {
>>> -    AVPacket pkt;
>>> -    AVPacket pkt_temp;
>>>     PacketQueue *queue;
>>>     AVCodecContext *avctx;
>>>     int pkt_serial;
>>>     int finished;
>>> -    int packet_pending;
>>>     SDL_cond *empty_queue_cond;
>>>     int64_t start_pts;
>>>     AVRational start_pts_tb;
>>> @@ -551,40 +548,24 @@ static void decoder_init(Decoder *d, AVCodecContext *avctx, PacketQueue *queue,
>>>     d->queue = queue;
>>>     d->empty_queue_cond = empty_queue_cond;
>>>     d->start_pts = AV_NOPTS_VALUE;
>>> +    d->pkt_serial = -1;
>>> }
>>>
>>> static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
>>> -    int got_frame = 0;
>>> +    int ret = AVERROR(EAGAIN);
>>>
>>> -    do {
>>> -        int ret = -1;
>>> +    for (;;) {
>>> +        AVPacket pkt;
>>>
>>> +        if (d->queue->serial == d->pkt_serial) {
>>> +        do {
>>>         if (d->queue->abort_request)
>>>             return -1;
>>>
>>> -        if (!d->packet_pending || d->queue->serial != d->pkt_serial) {
>>> -            AVPacket pkt;
>>> -            do {
>>> -                if (d->queue->nb_packets == 0)
>>> -                    SDL_CondSignal(d->empty_queue_cond);
>>> -                if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)
>>> -                    return -1;
>>> -                if (pkt.data == flush_pkt.data) {
>>> -                    avcodec_flush_buffers(d->avctx);
>>> -                    d->finished = 0;
>>> -                    d->next_pts = d->start_pts;
>>> -                    d->next_pts_tb = d->start_pts_tb;
>>> -                }
>>> -            } while (pkt.data == flush_pkt.data || d->queue->serial != d->pkt_serial);
>>> -            av_packet_unref(&d->pkt);
>>> -            d->pkt_temp = d->pkt = pkt;
>>> -            d->packet_pending = 1;
>>> -        }
>>> -
>>>         switch (d->avctx->codec_type) {
>>>             case AVMEDIA_TYPE_VIDEO:
>>> -                ret = avcodec_decode_video2(d->avctx, frame, &got_frame, &d->pkt_temp);
>>> -                if (got_frame) {
>>> +                ret = avcodec_receive_frame(d->avctx, frame);
>>> +                if (ret >= 0) {
>>>                     if (decoder_reorder_pts == -1) {
>>>                         frame->pts = av_frame_get_best_effort_timestamp(frame);
>>>                     } else if (!decoder_reorder_pts) {
>>> @@ -593,8 +574,8 @@ static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
>>>                 }
>>>                 break;
>>>             case AVMEDIA_TYPE_AUDIO:
>>> -                ret = avcodec_decode_audio4(d->avctx, frame, &got_frame, &d->pkt_temp);
>>> -                if (got_frame) {
>>> +                ret = avcodec_receive_frame(d->avctx, frame);
>>> +                if (ret >= 0) {
>>>                     AVRational tb = (AVRational){1, frame->sample_rate};
>>>                     if (frame->pts != AV_NOPTS_VALUE)
>>>                         frame->pts = av_rescale_q(frame->pts, av_codec_get_pkt_timebase(d->avctx), tb);
>>> @@ -606,37 +587,46 @@ static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
>>>                     }
>>>                 }
>>>                 break;
>>> -            case AVMEDIA_TYPE_SUBTITLE:
>>> -                ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &d->pkt_temp);
>>> -                break;
>>> +        }
>>> +        if (ret == AVERROR_EOF) {
>>> +            d->finished = d->pkt_serial;
>>> +            avcodec_flush_buffers(d->avctx);
>>> +            return 0;
>>> +        }
>>> +        if (ret >= 0)
>>> +            return 1;
>>> +        } while (ret != AVERROR(EAGAIN));
>>>         }
>>>
>>> -        if (ret < 0) {
>>> -            d->packet_pending = 0;
>>> +        do {
>>> +            if (d->queue->nb_packets == 0)
>>> +                SDL_CondSignal(d->empty_queue_cond);
>>> +            if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)
>>> +                return -1;
>>> +        } while (d->queue->serial != d->pkt_serial);
>>> +
>>> +        if (pkt.data == flush_pkt.data) {
>>> +            avcodec_flush_buffers(d->avctx);
>>> +            d->finished = 0;
>>> +            d->next_pts = d->start_pts;
>>> +            d->next_pts_tb = d->start_pts_tb;
>>>         } else {
>>> -            d->pkt_temp.dts =
>>> -            d->pkt_temp.pts = AV_NOPTS_VALUE;
>>> -            if (d->pkt_temp.data) {
>>> -                if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO)
>>> -                    ret = d->pkt_temp.size;
>>> -                d->pkt_temp.data += ret;
>>> -                d->pkt_temp.size -= ret;
>>> -                if (d->pkt_temp.size <= 0)
>>> -                    d->packet_pending = 0;
>>> +            if (d->avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
>>> +                int got_frame = 0;
>>> +                ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &pkt);
>>> +                if (ret < 0)
>>> +                    ret = AVERROR(EAGAIN);
>>> +                else
>>> +                    ret = got_frame ? 0 : (pkt.data ? AVERROR(EAGAIN) : AVERROR_EOF);
>>>             } else {
>>> -                if (!got_frame) {
>>> -                    d->packet_pending = 0;
>>> -                    d->finished = d->pkt_serial;
>>> -                }
>>> +                av_assert0(avcodec_send_packet(d->avctx, &pkt) != AVERROR(EAGAIN));
>>>             }
>>> +            av_packet_unref(&pkt);
>>>         }
>>> -    } while (!got_frame && !d->finished);
>>> -
>>> -    return got_frame;
>>> +    }
>>> }
>>>
>>> static void decoder_destroy(Decoder *d) {
>>> -    av_packet_unref(&d->pkt);
>>>     avcodec_free_context(&d->avctx);
>>> }
>>>
>>> --
>>> 2.10.2
>>>
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> ffmpeg-devel at ffmpeg.org
>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel at ffmpeg.org
>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>


More information about the ffmpeg-devel mailing list