[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