diff options
author | Martin Storsjö <martin@martin.st> | 2012-12-11 16:03:33 +0200 |
---|---|---|
committer | Martin Storsjö <martin@martin.st> | 2013-01-08 19:23:56 +0200 |
commit | 6f72441120098d0adaca1e063b62bcf4e83f0d62 (patch) | |
tree | 3442fc8985a49e49e2711f1d772b7ec430b79b45 /libavformat | |
parent | 86d9181cf41edc3382bf2481f95a2fb321058689 (diff) | |
download | ffmpeg-6f72441120098d0adaca1e063b62bcf4e83f0d62.tar.gz |
rtpdec_vp8: Request a keyframe if RTP packets are lost
Signed-off-by: Martin Storsjö <martin@martin.st>
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/rtpdec_vp8.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/libavformat/rtpdec_vp8.c b/libavformat/rtpdec_vp8.c index 13efa54421..96a1a3407e 100644 --- a/libavformat/rtpdec_vp8.c +++ b/libavformat/rtpdec_vp8.c @@ -35,11 +35,21 @@ struct PayloadContext { AVIOContext *data; uint32_t timestamp; int is_keyframe; + /* If sequence_ok is set, we keep returning data (even if we might have + * lost some data, but we haven't lost any too critical data that would + * cause the decoder to desynchronize and output random garbage). + */ int sequence_ok; int first_part_size; uint16_t prev_seq; int prev_pictureid; int broken_frame; + /* If sequence_dirty is set, we have lost some data (critical or + * non-critical) and decoding will have some sort of artefacts, and + * we thus should request a new keyframe. + */ + int sequence_dirty; + int got_keyframe; }; static void vp8_free_buffer(PayloadContext *vp8) @@ -141,11 +151,15 @@ static int vp8_handle_packet(AVFormatContext *ctx, PayloadContext *vp8, vp8_free_buffer(vp8); // Keyframe, decoding ok again vp8->sequence_ok = 1; + vp8->sequence_dirty = 0; + vp8->got_keyframe = 1; } else { int can_continue = vp8->data && !vp8->is_keyframe && avio_tell(vp8->data) >= vp8->first_part_size; if (!vp8->sequence_ok) return AVERROR(EAGAIN); + if (!vp8->got_keyframe) + return vp8_broken_sequence(ctx, vp8, "Keyframe missing\n"); if (pictureid >= 0) { if (pictureid != ((vp8->prev_pictureid + 1) & pictureid_mask)) { return vp8_broken_sequence(ctx, vp8, @@ -179,6 +193,7 @@ static int vp8_handle_packet(AVFormatContext *ctx, PayloadContext *vp8, } } if (vp8->data) { + vp8->sequence_dirty = 1; if (avio_tell(vp8->data) >= vp8->first_part_size) { int ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index); if (ret < 0) @@ -220,6 +235,7 @@ static int vp8_handle_packet(AVFormatContext *ctx, PayloadContext *vp8, "Missed part of a keyframe, sequence broken\n"); } else if (vp8->data && avio_tell(vp8->data) >= vp8->first_part_size) { vp8->broken_frame = 1; + vp8->sequence_dirty = 1; } else { return vp8_broken_sequence(ctx, vp8, "Missed part of the first partition, sequence broken\n"); @@ -253,7 +269,11 @@ static int vp8_handle_packet(AVFormatContext *ctx, PayloadContext *vp8, static PayloadContext *vp8_new_context(void) { - return av_mallocz(sizeof(PayloadContext)); + PayloadContext *vp8 = av_mallocz(sizeof(PayloadContext)); + if (!vp8) + return NULL; + vp8->sequence_ok = 1; + return vp8; } static void vp8_free_context(PayloadContext *vp8) @@ -262,6 +282,11 @@ static void vp8_free_context(PayloadContext *vp8) av_free(vp8); } +static int vp8_need_keyframe(PayloadContext *vp8) +{ + return vp8->sequence_dirty || !vp8->sequence_ok; +} + RTPDynamicProtocolHandler ff_vp8_dynamic_handler = { .enc_name = "VP8", .codec_type = AVMEDIA_TYPE_VIDEO, @@ -269,4 +294,5 @@ RTPDynamicProtocolHandler ff_vp8_dynamic_handler = { .alloc = vp8_new_context, .free = vp8_free_context, .parse_packet = vp8_handle_packet, + .need_keyframe = vp8_need_keyframe, }; |