Browse Source

deps-libff: Add frame dropping

This, if set, instructs the decoders to drop
frames if a specific timing window is not met.
John Bradley 10 years ago
parent
commit
3628d3402d

+ 13 - 0
deps/libff/libff/ff-audio-decoder.c

@@ -55,6 +55,17 @@ static bool handle_reset_packet(struct ff_decoder *decoder,
 	return true;
 }
 
+static void drop_late_packets(struct ff_decoder *decoder,
+		struct ff_packet *packet)
+{
+	int64_t start_time = ff_clock_start_time(decoder->clock);
+	if (start_time != AV_NOPTS_VALUE) {
+		if (ff_decoder_set_frame_drop_state(decoder, start_time,
+				packet->base.pts))
+			shrink_packet(packet, packet->base.size);
+	}
+}
+
 static int decode_frame(struct ff_decoder *decoder,
 	struct ff_packet *packet, AVFrame *frame, bool *frame_complete)
 {
@@ -65,6 +76,8 @@ static int decode_frame(struct ff_decoder *decoder,
 		while (packet->base.size > 0) {
 			int complete;
 
+			drop_late_packets(decoder, packet);
+
 			packet_length = avcodec_decode_audio4(decoder->codec,
 				frame, &complete,
 				&packet->base);

+ 27 - 0
deps/libff/libff/ff-decoder.c

@@ -320,3 +320,30 @@ double ff_decoder_get_best_effort_pts(struct ff_decoder *decoder,
 
 	return d_pts;
 }
+
+bool ff_decoder_set_frame_drop_state(struct ff_decoder *decoder,
+		int64_t start_time, int64_t pts)
+{
+	if (pts != AV_NOPTS_VALUE) {
+		int64_t rescaled_pts = av_rescale_q(pts,
+				decoder->stream->time_base, AV_TIME_BASE_Q);
+		int64_t master_clock = av_gettime() -
+				start_time;
+
+		int64_t diff = master_clock - rescaled_pts;
+
+		if (diff > (AV_TIME_BASE / 2)) {
+			decoder->codec->skip_frame = decoder->frame_drop;
+			decoder->codec->skip_idct = decoder->frame_drop;
+			decoder->codec->skip_loop_filter = decoder->frame_drop;
+			return true;
+		} else {
+			decoder->codec->skip_frame = AVDISCARD_DEFAULT;
+			decoder->codec->skip_idct = AVDISCARD_DEFAULT;
+			decoder->codec->skip_loop_filter = AVDISCARD_DEFAULT;
+			return false;
+		}
+	}
+
+	return false;
+}

+ 4 - 0
deps/libff/libff/ff-decoder.h

@@ -44,6 +44,7 @@ struct ff_decoder {
 	int64_t current_pts_time;  // clock time when current_pts was set
 
 	bool hwaccel_decoder;
+	enum AVDiscard frame_drop;
 	struct ff_clock *clock;
 	enum ff_av_sync_type natural_sync_clock;
 
@@ -69,3 +70,6 @@ void ff_decoder_refresh(void *opaque);
 
 double ff_decoder_get_best_effort_pts(struct ff_decoder *decoder,
 		AVFrame *frame);
+
+bool ff_decoder_set_frame_drop_state(struct ff_decoder *decoder,
+		int64_t start_time, int64_t pts);

+ 4 - 0
deps/libff/libff/ff-demuxer.c

@@ -194,6 +194,8 @@ static bool initialize_decoder(struct ff_demuxer *demuxer,
 				demuxer->options.audio_frame_queue_size);
 
 		demuxer->audio_decoder->hwaccel_decoder = hwaccel_decoder;
+		demuxer->audio_decoder->frame_drop =
+				demuxer->options.frame_drop;
 		demuxer->audio_decoder->natural_sync_clock =
 				AV_SYNC_AUDIO_MASTER;
 		demuxer->audio_decoder->callbacks = &demuxer->audio_callbacks;
@@ -215,6 +217,8 @@ static bool initialize_decoder(struct ff_demuxer *demuxer,
 				demuxer->options.video_frame_queue_size);
 
 		demuxer->video_decoder->hwaccel_decoder = hwaccel_decoder;
+		demuxer->video_decoder->frame_drop =
+				demuxer->options.frame_drop;
 		demuxer->video_decoder->natural_sync_clock =
 				AV_SYNC_VIDEO_MASTER;
 		demuxer->video_decoder->callbacks = &demuxer->video_callbacks;

+ 1 - 0
deps/libff/libff/ff-demuxer.h

@@ -35,6 +35,7 @@ struct ff_demuxer_options
 	int video_frame_queue_size;
 	bool is_hw_decoding;
 	bool is_looping;
+	enum AVDiscard frame_drop;
 };
 
 typedef struct ff_demuxer_options ff_demuxer_options_t;

+ 15 - 0
deps/libff/libff/ff-video-decoder.c

@@ -73,6 +73,7 @@ void *ff_video_decoder_thread(void *opaque_video_decoder)
 	int complete;
 	AVFrame *frame = av_frame_alloc();
 	int ret;
+	bool key_frame;
 
 	while (!decoder->abort) {
 		ret = packet_queue_get(&decoder->packet_queue, &packet, 1);
@@ -95,6 +96,20 @@ void *ff_video_decoder_thread(void *opaque_video_decoder)
 			continue;
 		}
 
+		int64_t start_time = ff_clock_start_time(decoder->clock);
+		key_frame = packet.base.flags & AV_PKT_FLAG_KEY;
+
+		// We can only make decisions on keyframes for
+		// hw decoders (maybe just OSX?)
+		// For now, always make drop decisions on keyframes
+		bool frame_drop_check = key_frame;
+		// Must have a proper packet pts to drop frames here
+		frame_drop_check &= start_time != AV_NOPTS_VALUE;
+
+		if (frame_drop_check)
+			ff_decoder_set_frame_drop_state(decoder,
+					start_time, packet.base.pts);
+
 		avcodec_decode_video2(decoder->codec, frame,
 				&complete, &packet.base);