void packet_queue_flush(struct ff_packet_queue *q) { struct ff_packet_list *packet; pthread_mutex_lock(&q->mutex); for (packet = q->first_packet; packet != NULL; packet = q->first_packet) { q->first_packet = packet->next; av_free_packet(&packet->packet.base); if (packet->packet.clock != NULL) ff_clock_release(&packet->packet.clock); av_freep(&packet); } q->last_packet = q->first_packet = NULL; q->count = 0; q->total_size = 0; pthread_mutex_unlock(&q->mutex); }
void ff_decoder_free(struct ff_decoder *decoder) { void *decoder_thread_result; int i; assert(decoder != NULL); decoder->abort = true; ff_circular_queue_abort(&decoder->frame_queue); packet_queue_abort(&decoder->packet_queue); ff_timer_free(&decoder->refresh_timer); pthread_join(decoder->decoder_thread, &decoder_thread_result); for (i = 0; i < decoder->frame_queue.capacity; i++) { void *item = decoder->frame_queue.slots[i]; struct ff_frame *frame = (struct ff_frame *)item; ff_callbacks_frame_free(frame, decoder->callbacks); if (frame != NULL) { if (frame->frame != NULL) av_frame_unref(frame->frame); if (frame->clock != NULL) ff_clock_release(&frame->clock); av_free(frame); } } packet_queue_free(&decoder->packet_queue); ff_circular_queue_free(&decoder->frame_queue); avcodec_close(decoder->codec); av_free(decoder); }
void ff_decoder_refresh(void *opaque) { struct ff_decoder *decoder = (struct ff_decoder *)opaque; struct ff_frame *frame; if (decoder->stream) { if (decoder->frame_queue.size == 0) { if (!decoder->eof || !decoder->finished) { // We expected a frame, but there were none // available // Schedule another call as soon as possible ff_decoder_schedule_refresh(decoder, 1); } else { ff_callbacks_frame(decoder->callbacks, NULL); decoder->refresh_timer.abort = true; // no more refreshes, we are at the eof av_log(NULL, AV_LOG_INFO, "refresh timer stopping; eof"); return; } } else { double pts_diff; double delay_until_next_wake; bool late_first_frame = false; frame = ff_circular_queue_peek_read( &decoder->frame_queue); // Get frame clock and start it if needed ff_clock_t *clock = ff_clock_move(&frame->clock); if (!ff_clock_start(clock, decoder->natural_sync_clock, &decoder->refresh_timer.abort)) { ff_clock_release(&clock); // Our clock was never started and deleted or // aborted if (decoder->refresh_timer.abort) { av_log(NULL, AV_LOG_INFO, "refresh timer aborted"); return; } // Drop this frame? The only way this can happen // is if one stream finishes before another and // the input is looping or canceled. Until we // get another clock we will unable to continue ff_decoder_schedule_refresh(decoder, 100); // Drop this frame as we have no way of timing // it ff_circular_queue_advance_read( &decoder->frame_queue); return; } decoder->current_pts = frame->pts; decoder->current_pts_time = av_gettime(); // the amount of time until we need to display this // frame pts_diff = frame->pts - decoder->previous_pts; // if the first frame is a very large value, we've most // likely started mid-stream, and the initial diff // should be ignored. if (decoder->first_frame) { late_first_frame = pts_diff >= 1.0; decoder->first_frame = false; } if (pts_diff <= 0 || late_first_frame) { // if diff is invalid, use previous pts_diff = decoder->previous_pts_diff; } // save for next time decoder->previous_pts_diff = pts_diff; decoder->previous_pts = frame->pts; // if not synced against natural clock if (clock->sync_type != decoder->natural_sync_clock) { pts_diff = get_sync_adjusted_pts_diff(clock, frame->pts, pts_diff); } decoder->timer_next_wake += pts_diff; // compute the amount of time until next refresh delay_until_next_wake = decoder->timer_next_wake - (av_gettime() / 1000000.0L); if (delay_until_next_wake < 0.010L) { delay_until_next_wake = 0.010L; } if (delay_until_next_wake > pts_diff) delay_until_next_wake = pts_diff; ff_clock_release(&clock); ff_callbacks_frame(decoder->callbacks, frame); ff_decoder_schedule_refresh(decoder, (int)(delay_until_next_wake * 1000 + 0.5L)); av_frame_free(&frame->frame); ff_circular_queue_advance_read(&decoder->frame_queue); } } else { ff_decoder_schedule_refresh(decoder, 100); } }