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

          Line data    Source code
       1             : /*
       2             :  * RTP Depacketization of RAW video (TR-03)
       3             :  * Copyright (c) 2016 Savoir-faire Linux, Inc
       4             :  *
       5             :  * This file is part of FFmpeg.
       6             :  *
       7             :  * FFmpeg is free software; you can redistribute it and/or
       8             :  * modify it under the terms of the GNU Lesser General Public
       9             :  * License as published by the Free Software Foundation; either
      10             :  * version 2.1 of the License, or (at your option) any later version.
      11             :  *
      12             :  * FFmpeg is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with FFmpeg; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : /* Development sponsored by CBC/Radio-Canada */
      23             : 
      24             : #include "avio_internal.h"
      25             : #include "rtpdec_formats.h"
      26             : #include "libavutil/avstring.h"
      27             : #include "libavutil/pixdesc.h"
      28             : 
      29             : struct PayloadContext {
      30             :     char *sampling;
      31             :     int depth;
      32             :     int width;
      33             :     int height;
      34             : 
      35             :     uint8_t *frame;
      36             :     unsigned int frame_size;
      37             :     unsigned int pgroup; /* size of the pixel group in bytes */
      38             :     unsigned int xinc;
      39             : 
      40             :     uint32_t timestamp;
      41             : };
      42             : 
      43           0 : static int rfc4175_parse_format(AVStream *stream, PayloadContext *data)
      44             : {
      45           0 :     enum AVPixelFormat pixfmt = AV_PIX_FMT_NONE;
      46           0 :     int bits_per_sample = 0;
      47           0 :     int tag = 0;
      48             : 
      49           0 :     if (!strncmp(data->sampling, "YCbCr-4:2:2", 11)) {
      50           0 :         tag = MKTAG('U', 'Y', 'V', 'Y');
      51           0 :         data->xinc = 2;
      52             : 
      53           0 :         if (data->depth == 8) {
      54           0 :             data->pgroup = 4;
      55           0 :             bits_per_sample = 16;
      56           0 :             pixfmt = AV_PIX_FMT_UYVY422;
      57           0 :         } else if (data->depth == 10) {
      58           0 :             data->pgroup = 5;
      59           0 :             bits_per_sample = 20;
      60           0 :             pixfmt = AV_PIX_FMT_YUV422P10;
      61             :         } else {
      62           0 :             return AVERROR_INVALIDDATA;
      63             :         }
      64             :     } else {
      65           0 :         return AVERROR_INVALIDDATA;
      66             :     }
      67             : 
      68           0 :     stream->codecpar->format = pixfmt;
      69           0 :     stream->codecpar->codec_tag = tag;
      70           0 :     stream->codecpar->bits_per_coded_sample = bits_per_sample;
      71           0 :     data->frame_size = data->width * data->height * data->pgroup / data->xinc;
      72             : 
      73           0 :     return 0;
      74             : }
      75             : 
      76           0 : static int rfc4175_parse_fmtp(AVFormatContext *s, AVStream *stream,
      77             :                               PayloadContext *data, const char *attr,
      78             :                               const char *value)
      79             : {
      80           0 :     if (!strncmp(attr, "width", 5))
      81           0 :         data->width = atoi(value);
      82           0 :     else if (!strncmp(attr, "height", 6))
      83           0 :         data->height = atoi(value);
      84           0 :     else if (!strncmp(attr, "sampling", 8))
      85           0 :         data->sampling = av_strdup(value);
      86           0 :     else if (!strncmp(attr, "depth", 5))
      87           0 :         data->depth = atoi(value);
      88             : 
      89           0 :     return 0;
      90             : }
      91             : 
      92           0 : static int rfc4175_parse_sdp_line(AVFormatContext *s, int st_index,
      93             :                                   PayloadContext *data, const char *line)
      94             : {
      95             :     const char *p;
      96             : 
      97           0 :     if (st_index < 0)
      98           0 :         return 0;
      99             : 
     100           0 :     if (av_strstart(line, "fmtp:", &p)) {
     101           0 :         AVStream *stream = s->streams[st_index];
     102           0 :         int ret = ff_parse_fmtp(s, stream, data, p, rfc4175_parse_fmtp);
     103             : 
     104           0 :         if (ret < 0)
     105           0 :             return ret;
     106             : 
     107             : 
     108           0 :         if (!data->sampling || !data->depth || !data->width || !data->height)
     109           0 :             return -1;
     110             : 
     111           0 :         stream->codecpar->width = data->width;
     112           0 :         stream->codecpar->height = data->height;
     113             : 
     114           0 :         ret = rfc4175_parse_format(stream, data);
     115           0 :         av_freep(&data->sampling);
     116             : 
     117           0 :         return ret;
     118             :     }
     119             : 
     120           0 :     return 0;
     121             : }
     122             : 
     123           0 : static int rfc4175_finalize_packet(PayloadContext *data, AVPacket *pkt,
     124             :                                    int stream_index)
     125             : {
     126             :    int ret;
     127             : 
     128           0 :    pkt->stream_index = stream_index;
     129           0 :    ret = av_packet_from_data(pkt, data->frame, data->frame_size);
     130           0 :    if (ret < 0) {
     131           0 :        av_freep(&data->frame);
     132             :    }
     133             : 
     134           0 :    data->frame = NULL;
     135             : 
     136           0 :    return ret;
     137             : }
     138             : 
     139           0 : static int rfc4175_handle_packet(AVFormatContext *ctx, PayloadContext *data,
     140             :                                  AVStream *st, AVPacket *pkt, uint32_t *timestamp,
     141             :                                  const uint8_t * buf, int len,
     142             :                                  uint16_t seq, int flags)
     143             : {
     144             :     int length, line, offset, cont;
     145           0 :     const uint8_t *headers = buf + 2; /* skip extended seqnum */
     146           0 :     const uint8_t *payload = buf + 2;
     147           0 :     int payload_len = len - 2;
     148           0 :     int missed_last_packet = 0;
     149             : 
     150             :     uint8_t *dest;
     151             : 
     152           0 :     if (*timestamp != data->timestamp) {
     153           0 :         if (data->frame) {
     154             :             /*
     155             :              * if we're here, it means that two RTP packets didn't have the
     156             :              * same timestamp, which is a sign that they were packets from two
     157             :              * different frames, but we didn't get the flag RTP_FLAG_MARKER on
     158             :              * the first one of these frames (last packet of a frame).
     159             :              * Finalize the previous frame anyway by filling the AVPacket.
     160             :              */
     161           0 :             av_log(ctx, AV_LOG_ERROR, "Missed previous RTP Marker\n");
     162           0 :             missed_last_packet = 1;
     163           0 :             rfc4175_finalize_packet(data, pkt, st->index);
     164             :         }
     165             : 
     166           0 :         data->frame = av_malloc(data->frame_size);
     167             : 
     168           0 :         data->timestamp = *timestamp;
     169             : 
     170           0 :         if (!data->frame) {
     171           0 :             av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
     172           0 :             return AVERROR(ENOMEM);
     173             :         }
     174             :     }
     175             : 
     176             :     /*
     177             :      * looks for the 'Continuation bit' in scan lines' headers
     178             :      * to find where data start
     179             :      */
     180             :     do {
     181           0 :         if (payload_len < 6)
     182           0 :             return AVERROR_INVALIDDATA;
     183             : 
     184           0 :         cont = payload[4] & 0x80;
     185           0 :         payload += 6;
     186           0 :         payload_len -= 6;
     187           0 :     } while (cont);
     188             : 
     189             :     /* and now iterate over every scan lines */
     190             :     do {
     191             :         int copy_offset;
     192             : 
     193           0 :         if (payload_len < data->pgroup)
     194           0 :             return AVERROR_INVALIDDATA;
     195             : 
     196           0 :         length = (headers[0] << 8) | headers[1];
     197           0 :         line = ((headers[2] & 0x7f) << 8) | headers[3];
     198           0 :         offset = ((headers[4] & 0x7f) << 8) | headers[5];
     199           0 :         cont = headers[4] & 0x80;
     200           0 :         headers += 6;
     201             : 
     202           0 :         if (length % data->pgroup)
     203           0 :             return AVERROR_INVALIDDATA;
     204             : 
     205           0 :         if (length > payload_len)
     206           0 :             length = payload_len;
     207             : 
     208             :         /* prevent ill-formed packets to write after buffer's end */
     209           0 :         copy_offset = (line * data->width + offset) * data->pgroup / data->xinc;
     210           0 :         if (copy_offset + length > data->frame_size)
     211           0 :             return AVERROR_INVALIDDATA;
     212             : 
     213           0 :         dest = data->frame + copy_offset;
     214           0 :         memcpy(dest, payload, length);
     215             : 
     216           0 :         payload += length;
     217           0 :         payload_len -= length;
     218           0 :     } while (cont);
     219             : 
     220           0 :     if ((flags & RTP_FLAG_MARKER)) {
     221           0 :         return rfc4175_finalize_packet(data, pkt, st->index);
     222           0 :     } else if (missed_last_packet) {
     223           0 :         return 0;
     224             :     }
     225             : 
     226           0 :     return AVERROR(EAGAIN);
     227             : }
     228             : 
     229             : RTPDynamicProtocolHandler ff_rfc4175_rtp_handler = {
     230             :     .enc_name           = "raw",
     231             :     .codec_type         = AVMEDIA_TYPE_VIDEO,
     232             :     .codec_id           = AV_CODEC_ID_BITPACKED,
     233             :     .priv_data_size     = sizeof(PayloadContext),
     234             :     .parse_sdp_a_line   = rfc4175_parse_sdp_line,
     235             :     .parse_packet       = rfc4175_handle_packet,
     236             : };

Generated by: LCOV version 1.13