c - FFmpeg video from file to network -
i working ffmpeg in video streaming solution on rtp. bugs me how stream @ correct framerate. using sleep in main streaming loop:
while (av_read_frame (input_format_ctx, &packet) >= 0) { // read video packet long eof not reached or error occurr if(packet.stream_index == 0) { if (av_interleaved_write_frame(output_format_ctx, &packet) < 0) { // write packet output stream av_packet_unref(&packet); // wipe packet av_free_packet(&packet); // release packet , finishes if problem occured break; } av_packet_unref(&packet); // wipe packet av_free_packet(&packet); // release packet } current_time = getsystemtime(); // system time adaptativesleep ((last_time + 1/(output_framerate)) - current_time); // sleep according framerate last_time = getsystemtime(); // finish } is there correct way of letting ffmpeg handle framerate?
thanks in advance
p.s.: remux stream, result ffmpeg runs through file in few seconds witought "sleep".
the avcodeccontext.pkt_timebase , avcodeccontext.time_base need keep stream running smoothly. each stream has own pkt_timebase. when broadcasting, use 1 stream sync system clock. use avpacket.pts , ffmpegs function av_q2d() convert pts value seconds double value.
double time_base = av_q2d(ctx->pkt_timebase); int64_t time_stamp = packet->pts; double packet_time = time_base * time_stamp; // time stamp in seconds from there sync first streams packet system clock. pauses between sending following packets easier handle.
the following function nothing streaming illustrate syncing system clock.
ffvideoframe *ffmpeg::getvideoframe(double r_time) { // r_time current system time ffvideoframe *vframe = nullptr; double timestamp; double clock_current_time = r_time - sys_clock_start; double clock_current_frame = 0.0; mutex_vid_queues.lock(); int vid_queue_size = vid_queue.size(); if (playback_started) { if (vid_queue_size > max_vid_overrun) { // keep buffer queues low playback_clock_start += 0.75; logd("timeshift buffers on max_vid_overrun"); } else if (vid_queue_size < 20) { playback_clock_start -= 0.4; // resync logd("timeshift buffers below 20"); } } if (!playback_started) { // queued video buffers need @ least 1 second network stream if (((vid_queue_size > min_vid_frames_start_non_network && !isnetworkstream) || (vid_queue_size > min_vid_frames_start && isnetworkstream)) ) { playback_started = true; vframe = vid_queue.front(); vid_queue.pop_front(); playback_clock_start = vframe->timestamp_f; // set stream start time time stamp sys_clock_start = r_time; // set system start time current time } } else { bool in_bounds = true; ffvideoframe *frame_temp; int drop_count = 0; while (in_bounds) { if (vid_queue_size == 0) { in_bounds = false; } else { frame_temp = vid_queue.front(); timestamp = frame_temp->timestamp_f; clock_current_frame = timestamp - playback_clock_start; if (clock_current_frame > clock_current_time) { in_bounds = false; } else { // adds 0.xx of second tolerance video playback removed here // may increased @ point vid_queue.pop_front(); vid_queue_size--; if (isnetworkstream && fabs(clock_current_time - clock_current_frame) < 0.05) { in_bounds = false; } if (vframe) { vid_unused.push_back(vframe); drop_count++; } vframe = frame_temp; } } } // if rendering takes long dropped frames occur if (drop_count > 0) logd("dumped %d video frames", drop_count); } mutex_vid_queues.unlock(); if (vframe) clock_last_frame = (int64_t)timestamp; return vframe; }
Comments
Post a Comment