[FFmpeg-devel] [PATCH 5/5] avf: drop entire frame if any packets in it were missed

Martin Carroll martin.carroll at alcatel-lucent.com
Mon Jul 2 21:24:30 CEST 2012


In the current (i.e., prior to this commit) design, when an RTP
packet is lost, the containing -- and incomplete -- encoded frame
is still passed along to the decoder.  With this commit, the read
thread keeps track of how many packets are missed, and when any
are missed, the entire containing frame is dropped.

Signed-off-by: Martin Carroll <martin.carroll at alcatel-lucent.com>
---
 libavcodec/avcodec.h      |    3 +++
 libavcodec/avpacket.c     |    1 +
 libavformat/avformat.h    |    3 +++
 libavformat/rtpdec.c      |   11 ++++++-----
 libavformat/rtpdec_h264.c |   16 ++++++++++------
 libavformat/utils.c       |   18 ++++++++++++++----
 6 files changed, 37 insertions(+), 15 deletions(-)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 8aa939b..0bb9df1 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -915,6 +915,9 @@ typedef struct AVPacket {
      * subtitles are correctly displayed after seeking.
      */
     int64_t convergence_duration;
+
+    int16_t num_pkts_missed_before_this_one;
+
 } AVPacket;
 #define AV_PKT_FLAG_KEY     0x0001 ///< The packet contains a keyframe
 #define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted
diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
index 2f82d29..54f71b4 100644
--- a/libavcodec/avpacket.c
+++ b/libavcodec/avpacket.c
@@ -57,6 +57,7 @@ void av_init_packet(AVPacket *pkt)
     pkt->pos                  = -1;
     pkt->duration             = 0;
     pkt->convergence_duration = 0;
+    pkt->num_pkts_missed_before_this_one = 0;
     pkt->flags                = 0;
     pkt->stream_index         = 0;
     pkt->destruct             = NULL;
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 807c7ac..67bb5e2 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -1120,6 +1120,9 @@ typedef struct AVFormatContext {
      * to know how the duration was estimated.
      */
     enum AVDurationEstimationMethod duration_estimation_method;
+
+    uint64_t num_pkts_missed;
+
 } AVFormatContext;
 
 /**
diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c
index 3a272e3..8986928 100644
--- a/libavformat/rtpdec.c
+++ b/libavformat/rtpdec.c
@@ -637,14 +637,15 @@ static int rtp_parse_queued_packet(RTPDemuxContext *s, AVPacket *pkt)
 {
     int rv;
     RTPPacket *next;
+    uint16_t num_missed = 0;
 
     if (s->queue_len <= 0)
         return -1;
-
-    if (!has_next_packet(s))
-        av_log(s->st ? s->st->codec : NULL, AV_LOG_WARNING,
-               "RTP: missed %d packets\n", s->queue->seq - s->seq - 1);
-
+    if (s->queue)
+        num_missed = s->queue->seq - s->seq - 1;
+    pkt->num_pkts_missed_before_this_one = num_missed;
+    if (num_missed > 0)
+        av_log(s->st ? s->st->codec : NULL, AV_LOG_WARNING, "RTP: missed %d packets\n", num_missed);
     /* Parse the first packet in the queue, and dequeue it */
     rv = rtp_parse_packet_internal(s, pkt, s->queue->buf, s->queue->len);
     next = s->queue->next;
diff --git a/libavformat/rtpdec_h264.c b/libavformat/rtpdec_h264.c
index 063836a..d1d0a4e 100644
--- a/libavformat/rtpdec_h264.c
+++ b/libavformat/rtpdec_h264.c
@@ -188,12 +188,16 @@ static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data,
         type = 1;
     switch (type) {
     case 0:                    // undefined, but pass them through
-    case 1:
-        av_new_packet(pkt, len + sizeof(start_sequence));
-        memcpy(pkt->data, start_sequence, sizeof(start_sequence));
-        memcpy(pkt->data + sizeof(start_sequence), buf, len);
-        COUNT_NAL_TYPE(data, nal);
-        break;
+    case 1: 
+    	{
+    		uint16_t save = pkt->num_pkts_missed_before_this_one;
+    		av_new_packet(pkt, len + sizeof(start_sequence));
+    		pkt->num_pkts_missed_before_this_one = save;
+    	}
+    	memcpy(pkt->data, start_sequence, sizeof(start_sequence));
+    	memcpy(pkt->data + sizeof(start_sequence), buf, len);
+    	COUNT_NAL_TYPE(data, nal);
+    	break;
 
     case 24:                   // STAP-A (one packet, multiple nals)
         // consume the STAP-A NAL
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 27804b8..0333372 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -1169,9 +1169,12 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
         av_init_packet(&flush_pkt);
         pkt = &flush_pkt;
         got_output = 1;
-    } else if (!size && st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) {
-        // preserve 0-size sync packets
-        compute_pkt_fields(s, st, st->parser, pkt);
+    } else {
+    	s->num_pkts_missed += pkt->num_pkts_missed_before_this_one;
+    	if (!size && st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) {
+    		// preserve 0-size sync packets
+    		compute_pkt_fields(s, st, st->parser, pkt);
+    	}
     }
 
     while (size > 0 || (pkt == &flush_pkt && got_output)) {
@@ -1189,8 +1192,15 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
 
         got_output = !!out_pkt.size;
 
-        if (!out_pkt.size)
+        if (!out_pkt.size) {
             continue;
+    	}
+    	if (s->num_pkts_missed > 0) {
+    		av_log(NULL, AV_LOG_ERROR, "discarding packet of size %d\n", out_pkt.size);
+            av_free_packet(&out_pkt);
+    		s->num_pkts_missed = 0;
+    		continue;
+    	}
 
         /* set the duration */
         out_pkt.duration = 0;
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list