LCOV - code coverage report
Current view: top level - libavformat - rtpdec_vp8.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 140 0.0 %
Date: 2017-12-12 11:08:38 Functions: 0 5 0.0 %

          Line data    Source code
       1             : /*
       2             :  * RTP VP8 Depacketizer
       3             :  * Copyright (c) 2010 Josh Allmann
       4             :  * Copyright (c) 2012 Martin Storsjo
       5             :  *
       6             :  * This file is part of FFmpeg.
       7             :  *
       8             :  * FFmpeg is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public
      10             :  * License as published by the Free Software Foundation; either
      11             :  * version 2.1 of the License, or (at your option) any later version.
      12             :  *
      13             :  * FFmpeg is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public
      19             :  * License along with FFmpeg; if not, write to the Free Software
      20             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      21             :  */
      22             : 
      23             : /**
      24             :  * @file
      25             :  * @brief RTP support for the VP8 payload
      26             :  * @author Josh Allmann <joshua.allmann@gmail.com>
      27             :  * @see http://tools.ietf.org/html/draft-ietf-payload-vp8-05
      28             :  */
      29             : 
      30             : #include "libavcodec/bytestream.h"
      31             : 
      32             : #include "avio_internal.h"
      33             : #include "rtpdec_formats.h"
      34             : 
      35             : struct PayloadContext {
      36             :     AVIOContext *data;
      37             :     uint32_t     timestamp;
      38             :     int          is_keyframe;
      39             :     /* If sequence_ok is set, we keep returning data (even if we might have
      40             :      * lost some data, but we haven't lost any too critical data that would
      41             :      * cause the decoder to desynchronize and output random garbage).
      42             :      */
      43             :     int          sequence_ok;
      44             :     int          first_part_size;
      45             :     uint16_t     prev_seq;
      46             :     int          prev_pictureid;
      47             :     int          broken_frame;
      48             :     /* If sequence_dirty is set, we have lost some data (critical or
      49             :      * non-critical) and decoding will have some sort of artifacts, and
      50             :      * we thus should request a new keyframe.
      51             :      */
      52             :     int          sequence_dirty;
      53             :     int          got_keyframe;
      54             : };
      55             : 
      56           0 : static int vp8_broken_sequence(AVFormatContext *ctx, PayloadContext *vp8,
      57             :                                const char *msg)
      58             : {
      59           0 :     vp8->sequence_ok = 0;
      60           0 :     av_log(ctx, AV_LOG_WARNING, "%s", msg);
      61           0 :     ffio_free_dyn_buf(&vp8->data);
      62           0 :     return AVERROR(EAGAIN);
      63             : }
      64             : 
      65           0 : static int vp8_handle_packet(AVFormatContext *ctx, PayloadContext *vp8,
      66             :                              AVStream *st, AVPacket *pkt, uint32_t *timestamp,
      67             :                              const uint8_t *buf, int len, uint16_t seq,
      68             :                              int flags)
      69             : {
      70             :     int start_partition, end_packet;
      71             :     int extended_bits, part_id;
      72           0 :     int pictureid_present = 0, tl0picidx_present = 0, tid_present = 0,
      73           0 :         keyidx_present = 0;
      74           0 :     int pictureid = -1, pictureid_mask = 0;
      75           0 :     int returned_old_frame = 0;
      76           0 :     uint32_t old_timestamp = 0;
      77             : 
      78           0 :     if (!buf) {
      79           0 :         if (vp8->data) {
      80           0 :             int ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index);
      81           0 :             if (ret < 0)
      82           0 :                 return ret;
      83           0 :             *timestamp = vp8->timestamp;
      84           0 :             if (vp8->sequence_dirty)
      85           0 :                 pkt->flags |= AV_PKT_FLAG_CORRUPT;
      86           0 :             return 0;
      87             :         }
      88           0 :         return AVERROR(EAGAIN);
      89             :     }
      90             : 
      91           0 :     if (len < 1)
      92           0 :         return AVERROR_INVALIDDATA;
      93             : 
      94           0 :     extended_bits   = buf[0] & 0x80;
      95           0 :     start_partition = buf[0] & 0x10;
      96           0 :     part_id         = buf[0] & 0x0f;
      97           0 :     end_packet      = flags & RTP_FLAG_MARKER;
      98           0 :     buf++;
      99           0 :     len--;
     100           0 :     if (extended_bits) {
     101           0 :         if (len < 1)
     102           0 :             return AVERROR_INVALIDDATA;
     103           0 :         pictureid_present = buf[0] & 0x80;
     104           0 :         tl0picidx_present = buf[0] & 0x40;
     105           0 :         tid_present       = buf[0] & 0x20;
     106           0 :         keyidx_present    = buf[0] & 0x10;
     107           0 :         buf++;
     108           0 :         len--;
     109             :     }
     110           0 :     if (pictureid_present) {
     111           0 :         if (len < 1)
     112           0 :             return AVERROR_INVALIDDATA;
     113           0 :         if (buf[0] & 0x80) {
     114           0 :             if (len < 2)
     115           0 :                 return AVERROR_INVALIDDATA;
     116           0 :             pictureid = AV_RB16(buf) & 0x7fff;
     117           0 :             pictureid_mask = 0x7fff;
     118           0 :             buf += 2;
     119           0 :             len -= 2;
     120             :         } else {
     121           0 :             pictureid = buf[0] & 0x7f;
     122           0 :             pictureid_mask = 0x7f;
     123           0 :             buf++;
     124           0 :             len--;
     125             :         }
     126             :     }
     127           0 :     if (tl0picidx_present) {
     128             :         // Ignoring temporal level zero index
     129           0 :         buf++;
     130           0 :         len--;
     131             :     }
     132           0 :     if (tid_present || keyidx_present) {
     133             :         // Ignoring temporal layer index, layer sync bit and keyframe index
     134           0 :         buf++;
     135           0 :         len--;
     136             :     }
     137           0 :     if (len < 1)
     138           0 :         return AVERROR_INVALIDDATA;
     139             : 
     140           0 :     if (start_partition && part_id == 0 && len >= 3) {
     141             :         int res;
     142           0 :         int non_key = buf[0] & 0x01;
     143           0 :         if (!non_key) {
     144           0 :             ffio_free_dyn_buf(&vp8->data);
     145             :             // Keyframe, decoding ok again
     146           0 :             vp8->sequence_ok = 1;
     147           0 :             vp8->sequence_dirty = 0;
     148           0 :             vp8->got_keyframe = 1;
     149             :         } else {
     150           0 :             int can_continue = vp8->data && !vp8->is_keyframe &&
     151           0 :                                avio_tell(vp8->data) >= vp8->first_part_size;
     152           0 :             if (!vp8->sequence_ok)
     153           0 :                 return AVERROR(EAGAIN);
     154           0 :             if (!vp8->got_keyframe)
     155           0 :                 return vp8_broken_sequence(ctx, vp8, "Keyframe missing\n");
     156           0 :             if (pictureid >= 0) {
     157           0 :                 if (pictureid != ((vp8->prev_pictureid + 1) & pictureid_mask)) {
     158           0 :                     return vp8_broken_sequence(ctx, vp8,
     159             :                                                "Missed a picture, sequence broken\n");
     160             :                 } else {
     161           0 :                     if (vp8->data && !can_continue)
     162           0 :                         return vp8_broken_sequence(ctx, vp8,
     163             :                                                    "Missed a picture, sequence broken\n");
     164             :                 }
     165             :             } else {
     166           0 :                 uint16_t expected_seq = vp8->prev_seq + 1;
     167           0 :                 int16_t diff = seq - expected_seq;
     168           0 :                 if (vp8->data) {
     169             :                     // No picture id, so we can't know if missed packets
     170             :                     // contained any new frames. If diff == 0, we did get
     171             :                     // later packets from the same frame (matching timestamp),
     172             :                     // so we know we didn't miss any frame. If diff == 1 and
     173             :                     // we still have data (not flushed by the end of frame
     174             :                     // marker), the single missed packet must have been part
     175             :                     // of the same frame.
     176           0 :                     if ((diff == 0 || diff == 1) && can_continue) {
     177             :                         // Proceed with what we have
     178             :                     } else {
     179           0 :                         return vp8_broken_sequence(ctx, vp8,
     180             :                                                    "Missed too much, sequence broken\n");
     181             :                     }
     182             :                 } else {
     183           0 :                     if (diff != 0)
     184           0 :                         return vp8_broken_sequence(ctx, vp8,
     185             :                                                    "Missed unknown data, sequence broken\n");
     186             :                 }
     187             :             }
     188           0 :             if (vp8->data) {
     189           0 :                 vp8->sequence_dirty = 1;
     190           0 :                 if (avio_tell(vp8->data) >= vp8->first_part_size) {
     191           0 :                     int ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index);
     192           0 :                     if (ret < 0)
     193           0 :                         return ret;
     194           0 :                     pkt->flags |= AV_PKT_FLAG_CORRUPT;
     195           0 :                     returned_old_frame = 1;
     196           0 :                     old_timestamp = vp8->timestamp;
     197             :                 } else {
     198             :                     // Shouldn't happen
     199           0 :                     ffio_free_dyn_buf(&vp8->data);
     200             :                 }
     201             :             }
     202             :         }
     203           0 :         vp8->first_part_size = (AV_RL16(&buf[1]) << 3 | buf[0] >> 5) + 3;
     204           0 :         if ((res = avio_open_dyn_buf(&vp8->data)) < 0)
     205           0 :             return res;
     206           0 :         vp8->timestamp = *timestamp;
     207           0 :         vp8->broken_frame = 0;
     208           0 :         vp8->prev_pictureid = pictureid;
     209           0 :         vp8->is_keyframe = !non_key;
     210             :     } else {
     211           0 :         uint16_t expected_seq = vp8->prev_seq + 1;
     212             : 
     213           0 :         if (!vp8->sequence_ok)
     214           0 :             return AVERROR(EAGAIN);
     215             : 
     216           0 :         if (vp8->timestamp != *timestamp) {
     217             :             // Missed the start of the new frame, sequence broken
     218           0 :             return vp8_broken_sequence(ctx, vp8,
     219             :                                        "Received no start marker; dropping frame\n");
     220             :         }
     221             : 
     222           0 :         if (seq != expected_seq) {
     223           0 :             if (vp8->is_keyframe) {
     224           0 :                 return vp8_broken_sequence(ctx, vp8,
     225             :                                            "Missed part of a keyframe, sequence broken\n");
     226           0 :             } else if (vp8->data && avio_tell(vp8->data) >= vp8->first_part_size) {
     227           0 :                 vp8->broken_frame = 1;
     228           0 :                 vp8->sequence_dirty = 1;
     229             :             } else {
     230           0 :                 return vp8_broken_sequence(ctx, vp8,
     231             :                                            "Missed part of the first partition, sequence broken\n");
     232             :             }
     233             :         }
     234             :     }
     235             : 
     236           0 :     if (!vp8->data)
     237           0 :         return vp8_broken_sequence(ctx, vp8, "Received no start marker\n");
     238             : 
     239           0 :     vp8->prev_seq = seq;
     240           0 :     if (!vp8->broken_frame)
     241           0 :         avio_write(vp8->data, buf, len);
     242             : 
     243           0 :     if (returned_old_frame) {
     244           0 :         *timestamp = old_timestamp;
     245           0 :         return end_packet ? 1 : 0;
     246             :     }
     247             : 
     248           0 :     if (end_packet) {
     249             :         int ret;
     250           0 :         ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index);
     251           0 :         if (ret < 0)
     252           0 :             return ret;
     253           0 :         if (vp8->sequence_dirty)
     254           0 :             pkt->flags |= AV_PKT_FLAG_CORRUPT;
     255           0 :         if (vp8->is_keyframe)
     256           0 :             pkt->flags |= AV_PKT_FLAG_KEY;
     257           0 :         return 0;
     258             :     }
     259             : 
     260           0 :     return AVERROR(EAGAIN);
     261             : }
     262             : 
     263           0 : static av_cold int vp8_init(AVFormatContext *s, int st_index, PayloadContext *vp8)
     264             : {
     265           0 :     vp8->sequence_ok = 1;
     266           0 :     return 0;
     267             : }
     268             : 
     269           0 : static void vp8_close_context(PayloadContext *vp8)
     270             : {
     271           0 :     ffio_free_dyn_buf(&vp8->data);
     272           0 : }
     273             : 
     274           0 : static int vp8_need_keyframe(PayloadContext *vp8)
     275             : {
     276           0 :     return vp8->sequence_dirty || !vp8->sequence_ok;
     277             : }
     278             : 
     279             : RTPDynamicProtocolHandler ff_vp8_dynamic_handler = {
     280             :     .enc_name       = "VP8",
     281             :     .codec_type     = AVMEDIA_TYPE_VIDEO,
     282             :     .codec_id       = AV_CODEC_ID_VP8,
     283             :     .priv_data_size = sizeof(PayloadContext),
     284             :     .init           = vp8_init,
     285             :     .close          = vp8_close_context,
     286             :     .parse_packet   = vp8_handle_packet,
     287             :     .need_keyframe  = vp8_need_keyframe,
     288             : };

Generated by: LCOV version 1.13