LCOV - code coverage report
Current view: top level - libavformat - rtpenc_h264_hevc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 93 0.0 %
Date: 2017-12-14 01:15:32 Functions: 0 3 0.0 %

          Line data    Source code
       1             : /*
       2             :  * RTP packetization for H.264 (RFC3984)
       3             :  * RTP packetizer for HEVC/H.265 payload format (draft version 6)
       4             :  * Copyright (c) 2008 Luca Abeni
       5             :  * Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.com>
       6             :  *
       7             :  * This file is part of FFmpeg.
       8             :  *
       9             :  * FFmpeg is free software; you can redistribute it and/or
      10             :  * modify it under the terms of the GNU Lesser General Public
      11             :  * License as published by the Free Software Foundation; either
      12             :  * version 2.1 of the License, or (at your option) any later version.
      13             :  *
      14             :  * FFmpeg is distributed in the hope that it will be useful,
      15             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :  * Lesser General Public License for more details.
      18             :  *
      19             :  * You should have received a copy of the GNU Lesser General Public
      20             :  * License along with FFmpeg; if not, write to the Free Software
      21             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      22             :  */
      23             : 
      24             : /**
      25             :  * @file
      26             :  * @brief H.264/HEVC packetization
      27             :  * @author Luca Abeni <lucabe72@email.it>
      28             :  */
      29             : 
      30             : #include "libavutil/intreadwrite.h"
      31             : 
      32             : #include "avformat.h"
      33             : #include "avc.h"
      34             : #include "rtpenc.h"
      35             : 
      36           0 : static void flush_buffered(AVFormatContext *s1, int last)
      37             : {
      38           0 :     RTPMuxContext *s = s1->priv_data;
      39           0 :     if (s->buf_ptr != s->buf) {
      40             :         // If we're only sending one single NAL unit, send it as such, skip
      41             :         // the STAP-A/AP framing
      42           0 :         if (s->buffered_nals == 1) {
      43           0 :             enum AVCodecID codec = s1->streams[0]->codecpar->codec_id;
      44           0 :             if (codec == AV_CODEC_ID_H264)
      45           0 :                 ff_rtp_send_data(s1, s->buf + 3, s->buf_ptr - s->buf - 3, last);
      46             :             else
      47           0 :                 ff_rtp_send_data(s1, s->buf + 4, s->buf_ptr - s->buf - 4, last);
      48             :         } else
      49           0 :             ff_rtp_send_data(s1, s->buf, s->buf_ptr - s->buf, last);
      50             :     }
      51           0 :     s->buf_ptr = s->buf;
      52           0 :     s->buffered_nals = 0;
      53           0 : }
      54             : 
      55           0 : static void nal_send(AVFormatContext *s1, const uint8_t *buf, int size, int last)
      56             : {
      57           0 :     RTPMuxContext *s = s1->priv_data;
      58           0 :     enum AVCodecID codec = s1->streams[0]->codecpar->codec_id;
      59             : 
      60           0 :     av_log(s1, AV_LOG_DEBUG, "Sending NAL %x of len %d M=%d\n", buf[0] & 0x1F, size, last);
      61           0 :     if (size <= s->max_payload_size) {
      62           0 :         int buffered_size = s->buf_ptr - s->buf;
      63             :         int header_size;
      64           0 :         int skip_aggregate = 0;
      65             : 
      66           0 :         if (codec == AV_CODEC_ID_H264) {
      67           0 :             header_size = 1;
      68           0 :             skip_aggregate = s->flags & FF_RTP_FLAG_H264_MODE0;
      69             :         } else {
      70           0 :             header_size = 2;
      71             :         }
      72             : 
      73             :         // Flush buffered NAL units if the current unit doesn't fit
      74           0 :         if (buffered_size + 2 + size > s->max_payload_size) {
      75           0 :             flush_buffered(s1, 0);
      76           0 :             buffered_size = 0;
      77             :         }
      78             :         // If we aren't using mode 0, and the NAL unit fits including the
      79             :         // framing (2 bytes length, plus 1/2 bytes for the STAP-A/AP marker),
      80             :         // write the unit to the buffer as a STAP-A/AP packet, otherwise flush
      81             :         // and send as single NAL.
      82           0 :         if (buffered_size + 2 + header_size + size <= s->max_payload_size &&
      83             :             !skip_aggregate) {
      84           0 :             if (buffered_size == 0) {
      85           0 :                 if (codec == AV_CODEC_ID_H264) {
      86           0 :                     *s->buf_ptr++ = 24;
      87             :                 } else {
      88           0 :                     *s->buf_ptr++ = 48 << 1;
      89           0 :                     *s->buf_ptr++ = 1;
      90             :                 }
      91             :             }
      92           0 :             AV_WB16(s->buf_ptr, size);
      93           0 :             s->buf_ptr += 2;
      94           0 :             memcpy(s->buf_ptr, buf, size);
      95           0 :             s->buf_ptr += size;
      96           0 :             s->buffered_nals++;
      97             :         } else {
      98           0 :             flush_buffered(s1, 0);
      99           0 :             ff_rtp_send_data(s1, buf, size, last);
     100             :         }
     101             :     } else {
     102             :         int flag_byte, header_size;
     103           0 :         flush_buffered(s1, 0);
     104           0 :         if (codec == AV_CODEC_ID_H264 && (s->flags & FF_RTP_FLAG_H264_MODE0)) {
     105           0 :             av_log(s1, AV_LOG_ERROR,
     106             :                    "NAL size %d > %d, try -slice-max-size %d\n", size,
     107             :                    s->max_payload_size, s->max_payload_size);
     108           0 :             return;
     109             :         }
     110           0 :         av_log(s1, AV_LOG_DEBUG, "NAL size %d > %d\n", size, s->max_payload_size);
     111           0 :         if (codec == AV_CODEC_ID_H264) {
     112           0 :             uint8_t type = buf[0] & 0x1F;
     113           0 :             uint8_t nri = buf[0] & 0x60;
     114             : 
     115           0 :             s->buf[0] = 28;        /* FU Indicator; Type = 28 ---> FU-A */
     116           0 :             s->buf[0] |= nri;
     117           0 :             s->buf[1] = type;
     118           0 :             s->buf[1] |= 1 << 7;
     119           0 :             buf  += 1;
     120           0 :             size -= 1;
     121             : 
     122           0 :             flag_byte   = 1;
     123           0 :             header_size = 2;
     124             :         } else {
     125           0 :             uint8_t nal_type = (buf[0] >> 1) & 0x3F;
     126             :             /*
     127             :              * create the HEVC payload header and transmit the buffer as fragmentation units (FU)
     128             :              *
     129             :              *    0                   1
     130             :              *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
     131             :              *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     132             :              *   |F|   Type    |  LayerId  | TID |
     133             :              *   +-------------+-----------------+
     134             :              *
     135             :              *      F       = 0
     136             :              *      Type    = 49 (fragmentation unit (FU))
     137             :              *      LayerId = 0
     138             :              *      TID     = 1
     139             :              */
     140           0 :             s->buf[0] = 49 << 1;
     141           0 :             s->buf[1] = 1;
     142             : 
     143             :             /*
     144             :              *     create the FU header
     145             :              *
     146             :              *     0 1 2 3 4 5 6 7
     147             :              *    +-+-+-+-+-+-+-+-+
     148             :              *    |S|E|  FuType   |
     149             :              *    +---------------+
     150             :              *
     151             :              *       S       = variable
     152             :              *       E       = variable
     153             :              *       FuType  = NAL unit type
     154             :              */
     155           0 :             s->buf[2]  = nal_type;
     156             :             /* set the S bit: mark as start fragment */
     157           0 :             s->buf[2] |= 1 << 7;
     158             : 
     159             :             /* pass the original NAL header */
     160           0 :             buf  += 2;
     161           0 :             size -= 2;
     162             : 
     163           0 :             flag_byte   = 2;
     164           0 :             header_size = 3;
     165             :         }
     166             : 
     167           0 :         while (size + header_size > s->max_payload_size) {
     168           0 :             memcpy(&s->buf[header_size], buf, s->max_payload_size - header_size);
     169           0 :             ff_rtp_send_data(s1, s->buf, s->max_payload_size, 0);
     170           0 :             buf  += s->max_payload_size - header_size;
     171           0 :             size -= s->max_payload_size - header_size;
     172           0 :             s->buf[flag_byte] &= ~(1 << 7);
     173             :         }
     174           0 :         s->buf[flag_byte] |= 1 << 6;
     175           0 :         memcpy(&s->buf[header_size], buf, size);
     176           0 :         ff_rtp_send_data(s1, s->buf, size + header_size, last);
     177             :     }
     178             : }
     179             : 
     180           0 : void ff_rtp_send_h264_hevc(AVFormatContext *s1, const uint8_t *buf1, int size)
     181             : {
     182           0 :     const uint8_t *r, *end = buf1 + size;
     183           0 :     RTPMuxContext *s = s1->priv_data;
     184             : 
     185           0 :     s->timestamp = s->cur_timestamp;
     186           0 :     s->buf_ptr   = s->buf;
     187           0 :     if (s->nal_length_size)
     188           0 :         r = ff_avc_mp4_find_startcode(buf1, end, s->nal_length_size) ? buf1 : end;
     189             :     else
     190           0 :         r = ff_avc_find_startcode(buf1, end);
     191           0 :     while (r < end) {
     192             :         const uint8_t *r1;
     193             : 
     194           0 :         if (s->nal_length_size) {
     195           0 :             r1 = ff_avc_mp4_find_startcode(r, end, s->nal_length_size);
     196           0 :             if (!r1)
     197           0 :                 r1 = end;
     198           0 :             r += s->nal_length_size;
     199             :         } else {
     200           0 :             while (!*(r++));
     201           0 :             r1 = ff_avc_find_startcode(r, end);
     202             :         }
     203           0 :         nal_send(s1, r, r1 - r, r1 == end);
     204           0 :         r = r1;
     205             :     }
     206           0 :     flush_buffered(s1, 1);
     207           0 : }

Generated by: LCOV version 1.13