[FFmpeg-user] playing a stream at the correct speed from a file. help needed please

JULIAN GARDNER joolzg at btinternet.com
Thu Apr 2 14:18:01 CEST 2015


I have a thread that I am trying and failing to get to play a stream from disc as the correct rate.

I have an input thread which does this in its packet loop, code is in to pause and resume the process depending on how many frames have been buffered.

                while (!inputSource->quit && !stop_all_tasks && av_read_frame(inputSource->fmt_ctx, &inputSource->pkt) >= 0) {
                int cnt;

                    do {
                        ret = decode_packet(&got_frame, 0, inputSource);
                        if (ret < 0)
                            break;
                        inputSource->pkt.data += ret;
                        inputSource->pkt.size -= ret;
                    } while (!inputSource->quit && !stop_all_tasks && inputSource->pkt.size > 0);
                    cnt = localNumberOfPackets( inputSource, VIDEO_INDEX);
                    if( cnt>25) {
                        do {
                            sleep(1);
                            cnt = localNumberOfPackets( inputSource, VIDEO_INDEX);
                        } while( !inputSource->quit && !stop_all_tasks && cnt>15);
                    }
                }
            }

now the decode_packet does this, all standard stuff

    if (inputSource->pkt.stream_index == inputSource->video_stream_idx) {
        /* decode video frame */
        ret = avcodec_decode_video2(inputSource->video_dec_ctx, frame, got_frame, &inputSource->pkt);
        if (ret < 0) {
            fprintf(stderr, "Error decoding video frame (%s)\n", av_err2str(ret));
            return ret;
        }
        index = VIDEO_INDEX;
    } else if (inputSource->pkt.stream_index == inputSource->audio_stream_idx) {
        /* decode audio frame */
        ret = avcodec_decode_audio4(inputSource->audio_dec_ctx, frame, got_frame, &inputSource->pkt);
        if (ret < 0) {
            fprintf(stderr, "Error decoding audio frame (%s)\n", av_err2str(ret));
            return ret;
        }
        /* Some audio decoders decode only part of the packet, and have to be
         * called again with the remainder of the packet data.
         * Sample: fate-suite/lossless-audio/luckynight-partial.shn
         * Also, some decoders might over-read the packet. */
        decoded = FFMIN(ret, inputSource->pkt.size);
        index = AUDIO_INDEX;
    }
    if( *got_frame && index<MAX_INDEX) {
    videoFrames *current = calloc( 1, sizeof( videoFrames));
    double pts;

        if( (pts = av_frame_get_best_effort_timestamp( frame))==AV_NOPTS_VALUE) {
            pts = 0;
        }

        if( index==VIDEO_INDEX)
            pts *= av_q2d(inputSource->video_dec_ctx->time_base);
        else
            pts *= av_q2d(inputSource->audio_dec_ctx->time_base);

        current->frame = frame;
        current->pts   = pts;
        current->next  = NULL;
        localAddPacketToList( inputSource, index, current);
    }

And finally where i seem to be having the problem the, video decode thread

    double frame_delay;
    double basicDelay = av_q2d(inputSource->video_dec_ctx->time_base) * inputSource->video_dec_ctx->ticks_per_frame;
    NextPts = PrePts = 0;

    gettimeofday(&start_time, NULL);
    start_usec = TIMEOFDAY(start_time);
    while( !inputSource->quit && !stop_all_tasks) {
    int cnt = localNumberOfPackets( inputSource, VIDEO_INDEX);

        if( cnt) {
            videoFrames *here;
            AVFrame *frame;
            int t;
            double pts;

                pthread_mutex_lock( &inputSource->list_mutex);
                here  = inputSource->packets_list[VIDEO_INDEX];
                inputSource->packets_list[VIDEO_INDEX] = here->next;
                frame = here->frame;
                pts   = here->pts;
                pthread_mutex_unlock( &inputSource->list_mutex);

// code from github, 3rd try See values at end
                if( !NextPts && !PrePts) {
                    NextPts = PrePts = frame->pkt_pts;
                }
                if( frame->pkt_pts != AV_NOPTS_VALUE) {
                    drift = frame->pkt_pts - NextPts;
                    NextPts = ( frame->pkt_pts - PrePts) + frame->pkt_pts;
                    Delay = NextPts - frame->pkt_pts - drift;
                    if( Delay < 0)
                        Delay = 0;
                    frame_delay = Delay * 1000 * av_q2d( inputSource->video_dec_ctx->time_base);
                    PrePts = frame->pkt_pts;
                }
                else {
                    frame_delay = basicDelay * frame->repeat_pict * (basicDelay * 0.5);
                    frame_delay *= 1000;
                }

                frame_delay = FFMIN( frame_delay, 200);
                if( inputSource->video_dec_ctx->codec_id == AV_CODEC_ID_H264) {
                    frame_delay = FFMAX( frame_delay, 10);
                }
        printf( "Frame Display delay:%f drift:%8ld next:%8ld prev:%8ld Delay:%8ld (%d)\r\n", frame_delay, drift, NextPts, PrePts, Delay, cnt);
                usleep( frame_delay * 1000);

                if (frame->key_frame) {
                    if (verbose) {
                        printf("%s video_frame n:%d coded_n:%d pts:%s %f %c\n",
                               inputSource->name, inputSource->video_frame_count, frame->display_picture_number,
                                av_ts2timestr(frame->pts, &inputSource->video_dec_ctx->time_base), here->pts,
                                frame->key_frame ? 'K':' ');
                    }
                }
            }

Now the problem is the stream does not play at the corerct speed and i have cannot see why this fails. I have tried 3 different ways and the one above is taken from a videoplayer on github.

Examples of files/streams tried
Live stream - time_base:1/50 ticks_per_frame:2 delay:8 framerate:25/1 pkt_timebase:1/90000
   Stream #0:0[0x100]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p, 720x288 [SAR 32:45 DAR 16:9], 25 fps, 25 tbr, 90k tbn, 50 tbc
Frame Display delay:10.000000 drift:       0 next:8317753200 prev:8317753200 Delay:       0 (9,0)
Frame Display delay:10.000000 drift:    3600 next:8317760400 prev:8317756800 Delay:       0 (9,0)
Frame Display delay:200.000000 drift:       0 next:8317764000 prev:8317760400 Delay:    3600 (9,5)

Mp4 File - time_base:1/50 ticks_per_frame:2 delay:8 framerate:25/1 pkt_timebase:1/100
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 720x544 [SAR 1:1 DAR 45:34], 1391 kb/s, 25 fps, 25 tbr, 100 tbn, 50 tbc (default)
Frame Display delay:10.000000 drift:       0 next:       8 prev:       8 Delay:       0 (10,15)
Frame Display delay:10.000000 drift:       4 next:      16 prev:      12 Delay:       0 (20,30)
Frame Display delay:80.000000 drift:       0 next:      20 prev:      16 Delay:       4 (31,44)

Mp4 File - time_base:1/60000 ticks_per_frame:2 delay:8 framerate:0/1 pkt_timebase:1/30000
    Stream #0:1(und): Video: h264 (Baseline) (avc1 / 0x31637661), yuv420p, 480x320 [SAR 1:1 DAR 3:2], 501 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 60k tbc (default)
Frame Display delay:10.000000 drift:       0 next:       0 prev:       0 Delay:       0 (15,43)
Frame Display delay:10.000000 drift:       0 next:    1001 prev:    1001 Delay:       0 (66,109)
Frame Display delay:10.000000 drift:    1001 next:    3003 prev:    2002 Delay:       0 (103,175)
Frame Display delay:16.683333 drift:       0 next:    4004 prev:    3003 Delay:    1001 (142,230)
Frame Display delay:16.683333 drift:       0 next:    5005 prev:    4004 Delay:    1001 (214,328)

Can anyone help or point me in the direction of code that will show me the errors in my ways? I would like to be able to work out the delays needed for any file type.

joolz


More information about the ffmpeg-user mailing list