deps-libff: Add frame dropping

This, if set, instructs the decoders to drop
frames if a specific timing window is not met.
This commit is contained in:
John Bradley 2015-03-12 16:15:01 -05:00
parent 6b36d39345
commit 3628d3402d
6 changed files with 64 additions and 0 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);