X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Frtpdec_vp8.c;h=623d3599f51486cd114747a62ced3948a554af34;hb=24d06cb2089fbe74912e82d613b8c166be1386a8;hp=bfac77d6ef9048ef7175340a46daff2caa0b26e1;hpb=2a9443a110e1865523fee32404890097fb6d1d93;p=ffmpeg diff --git a/libavformat/rtpdec_vp8.c b/libavformat/rtpdec_vp8.c index bfac77d6ef9..623d3599f51 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) @@ -70,7 +80,7 @@ static int vp8_handle_packet(AVFormatContext *ctx, PayloadContext *vp8, int extended_bits, part_id; int pictureid_present = 0, tl0picidx_present = 0, tid_present = 0, keyidx_present = 0; - int pictureid = -1, pictureid_mask; + int pictureid = -1, pictureid_mask = 0; int returned_old_frame = 0; uint32_t old_timestamp; @@ -79,6 +89,9 @@ static int vp8_handle_packet(AVFormatContext *ctx, PayloadContext *vp8, int ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index); if (ret < 0) return ret; + *timestamp = vp8->timestamp; + if (vp8->sequence_dirty) + pkt->flags |= AV_PKT_FLAG_CORRUPT; return 0; } return AVERROR(EAGAIN); @@ -140,11 +153,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, @@ -178,11 +195,12 @@ 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) return ret; - pkt->size = vp8->first_part_size; + pkt->flags |= AV_PKT_FLAG_CORRUPT; returned_old_frame = 1; old_timestamp = vp8->timestamp; } else { @@ -206,11 +224,8 @@ static int vp8_handle_packet(AVFormatContext *ctx, PayloadContext *vp8, if (vp8->timestamp != *timestamp) { // Missed the start of the new frame, sequence broken - vp8->sequence_ok = 0; - av_log(ctx, AV_LOG_WARNING, - "Received no start marker; dropping frame\n"); - vp8_free_buffer(vp8); - return AVERROR(EAGAIN); + return vp8_broken_sequence(ctx, vp8, + "Received no start marker; dropping frame\n"); } if (seq != expected_seq) { @@ -219,6 +234,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"); @@ -230,19 +246,21 @@ static int vp8_handle_packet(AVFormatContext *ctx, PayloadContext *vp8, return vp8_broken_sequence(ctx, vp8, "Received no start marker\n"); vp8->prev_seq = seq; - avio_write(vp8->data, buf, len); + if (!vp8->broken_frame) + avio_write(vp8->data, buf, len); + + if (returned_old_frame) { + *timestamp = old_timestamp; + return end_packet ? 1 : 0; + } if (end_packet) { int ret; - if (returned_old_frame) { - *timestamp = old_timestamp; - return 1; - } ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index); if (ret < 0) return ret; - if (vp8->broken_frame) - pkt->size = vp8->first_part_size; + if (vp8->sequence_dirty) + pkt->flags |= AV_PKT_FLAG_CORRUPT; return 0; } @@ -251,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) @@ -260,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, @@ -267,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, };