LCOV - code coverage report
Current view: top level - ietf - rtp_pck_mpeg4.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 306 343 89.2 %
Date: 2021-04-29 23:48:07 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / IETF RTP/RTSP/SDP sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #include <gpac/internal/ietf_dev.h>
      27             : 
      28             : #ifndef GPAC_DISABLE_STREAMING
      29             : 
      30             : #include <gpac/constants.h>
      31             : 
      32             : //get the size of the RSLH section given the GF_SLHeader and the SLMap
      33       25192 : static u32 gf_rtp_build_au_hdr_size(GP_RTPPacketizer *builder, GF_SLHeader *slh)
      34             : {
      35             :         u32 nbBits = 0;
      36             : 
      37             :         /*sel enc*/
      38       25192 :         if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) nbBits += 8;
      39             :         /*Note: ISMACryp ALWAYS indicates IV (BSO) and KEYIDX, even when sample is not encrypted. This is
      40             :         quite a waste when using selective encryption....*/
      41             : 
      42             :         /*IV*/
      43       25192 :         nbBits += builder->first_sl_in_rtp ? 8*builder->slMap.IV_length : 8*builder->slMap.IV_delta_length;
      44             :         /*keyIndicator*/
      45       25192 :         if (builder->first_sl_in_rtp || (builder->flags & GP_RTP_PCK_KEY_IDX_PER_AU)) {
      46       14502 :                 nbBits += 8*builder->slMap.KI_length;
      47             :         }
      48             : 
      49             :         /*no input header specified, compute the MAX size*/
      50       25192 :         if (!slh) {
      51             :                 /*size length*/
      52           0 :                 if (!builder->slMap.ConstantSize) nbBits += builder->slMap.SizeLength;
      53             :                 /*AU index length*/
      54           0 :                 nbBits += builder->first_sl_in_rtp ? builder->slMap.IndexLength : builder->slMap.IndexDeltaLength;
      55             :                 /*CTS flag*/
      56           0 :                 if (builder->slMap.CTSDeltaLength) {
      57           0 :                         nbBits += 1;
      58             :                         /*all non-first packets have the CTS written if asked*/
      59           0 :                         if (!builder->first_sl_in_rtp) nbBits += builder->slMap.CTSDeltaLength;
      60             :                 }
      61           0 :                 if (builder->slMap.DTSDeltaLength) nbBits += 1 + builder->slMap.DTSDeltaLength;
      62           0 :                 if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) nbBits += 8;
      63             :                 return nbBits;
      64             :         }
      65             : 
      66             :         /*size length*/
      67       25192 :         if (!builder->slMap.ConstantSize) nbBits += builder->slMap.SizeLength;
      68             : 
      69             :         /*AU index*/
      70       25192 :         if (builder->first_sl_in_rtp) {
      71       14502 :                 if (builder->slMap.IndexLength) nbBits += builder->slMap.IndexLength;
      72             :         } else {
      73       10690 :                 if (builder->slMap.IndexDeltaLength) nbBits += builder->slMap.IndexDeltaLength;
      74             :         }
      75             : 
      76             :         /*CTS Flag*/
      77       25192 :         if (builder->slMap.CTSDeltaLength) {
      78             :                 /*CTS not written if first SL*/
      79           0 :                 if (builder->first_sl_in_rtp) slh->compositionTimeStampFlag = 0;
      80             :                 /*but CTS flag is always written*/
      81           0 :                 nbBits += 1;
      82             :         } else {
      83       25192 :                 slh->compositionTimeStampFlag = 0;
      84             :         }
      85             :         /*CTS*/
      86       25192 :         if (slh->compositionTimeStampFlag) nbBits += builder->slMap.CTSDeltaLength;
      87             : 
      88             :         /*DTS Flag*/
      89       25192 :         if (builder->slMap.DTSDeltaLength) {
      90        3157 :                 nbBits += 1;
      91             :         } else {
      92       22035 :                 slh->decodingTimeStampFlag = 0;
      93             :         }
      94             :         /*DTS*/
      95       25192 :         if (slh->decodingTimeStampFlag) nbBits += builder->slMap.DTSDeltaLength;
      96             :         /*RAP indication*/
      97       25192 :         if (builder->slMap.RandomAccessIndication) nbBits ++;
      98             :         /*streamState indication*/
      99       25192 :         nbBits += builder->slMap.StreamStateIndication;
     100             : 
     101       25192 :         return nbBits;
     102             : }
     103             : 
     104             : 
     105             : /*write the AU header section - return the nb of BITS written for AU header*/
     106       20996 : u32 gf_rtp_build_au_hdr_write(GP_RTPPacketizer *builder, u32 PayloadSize, u32 RTP_TS)
     107             : {
     108             :         u32 nbBits = 0;
     109             :         s32 delta;
     110             : 
     111             :         /*selective encryption*/
     112       20996 :         if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) {
     113           0 :                 gf_bs_write_int(builder->pck_hdr, builder->is_encrypted, 1);
     114           0 :                 gf_bs_write_int(builder->pck_hdr, 0, 7);
     115             :                 nbBits = 8;
     116             :         }
     117             :         /*IV*/
     118       20996 :         if (builder->first_sl_in_rtp) {
     119       14502 :                 if (builder->slMap.IV_length) {
     120        1016 :                         gf_bs_write_long_int(builder->pck_hdr, builder->IV, 8*builder->slMap.IV_length);
     121        1016 :                         nbBits += 8*builder->slMap.IV_length;
     122             :                 }
     123             :         } else if (builder->slMap.IV_delta_length) {
     124             :                 /*NOT SUPPORTED!!! this only applies to interleaving*/
     125             :         }
     126             :         /*key*/
     127       20996 :         if (builder->slMap.KI_length) {
     128           0 :                 if (builder->first_sl_in_rtp || (builder->flags & GP_RTP_PCK_KEY_IDX_PER_AU)) {
     129           0 :                         if (builder->key_indicator) gf_bs_write_data(builder->pck_hdr, builder->key_indicator, builder->slMap.KI_length);
     130           0 :                         else gf_bs_write_int(builder->pck_hdr, 0, 8*builder->slMap.KI_length);
     131           0 :                         nbBits += 8*builder->slMap.KI_length;
     132             :                 }
     133             :         }
     134             : 
     135             : 
     136             :         /*size length*/
     137       20996 :         if (builder->slMap.ConstantSize) {
     138           0 :                 if (PayloadSize != builder->slMap.ConstantSize) return nbBits;
     139       20996 :         } else if (builder->slMap.SizeLength) {
     140             :                 /*write the AU size - if not enough bytes (real-time cases) set size to 0*/
     141       10712 :                 if (builder->sl_header.accessUnitLength >= (1<<builder->slMap.SizeLength)) {
     142           0 :                         gf_bs_write_int(builder->pck_hdr, 0, builder->slMap.SizeLength);
     143             :                 } else {
     144       10712 :                         gf_bs_write_int(builder->pck_hdr, builder->sl_header.accessUnitLength, builder->slMap.SizeLength);
     145             :                 }
     146       10712 :                 nbBits += builder->slMap.SizeLength;
     147             :         }
     148             :         /*AU index*/
     149       20996 :         if (builder->first_sl_in_rtp) {
     150       14502 :                 if (builder->slMap.IndexLength) {
     151        4218 :                         gf_bs_write_int(builder->pck_hdr, builder->sl_header.AU_sequenceNumber, builder->slMap.IndexLength);
     152        4218 :                         nbBits += builder->slMap.IndexLength;
     153             :                 }
     154             :         } else {
     155        6494 :                 if (builder->slMap.IndexDeltaLength) {
     156             :                         //check interleaving, otherwise force default (which is currently always the case)
     157        6494 :                         delta = builder->sl_header.AU_sequenceNumber - builder->last_au_sn;
     158        6494 :                         delta -= 1;
     159        6494 :                         gf_bs_write_int(builder->pck_hdr, delta, builder->slMap.IndexDeltaLength);
     160        6494 :                         nbBits += builder->slMap.IndexDeltaLength;
     161             :                 }
     162             :         }
     163             : 
     164             :         /*CTS Flag*/
     165       20996 :         if (builder->slMap.CTSDeltaLength) {
     166           0 :                 if (builder->first_sl_in_rtp) {
     167           0 :                         builder->sl_header.compositionTimeStampFlag = 0;
     168           0 :                         builder->sl_header.compositionTimeStamp = RTP_TS;
     169             :                 }
     170           0 :                 gf_bs_write_int(builder->pck_hdr, builder->sl_header.compositionTimeStampFlag, 1);
     171           0 :                 nbBits += 1;
     172             :         }
     173             :         /*CTS*/
     174       20996 :         if (builder->sl_header.compositionTimeStampFlag) {
     175           0 :                 delta = (u32) builder->sl_header.compositionTimeStamp - RTP_TS;
     176           0 :                 gf_bs_write_int(builder->pck_hdr, delta, builder->slMap.CTSDeltaLength);
     177           0 :                 nbBits += builder->slMap.CTSDeltaLength;
     178             :         }
     179             :         /*DTS Flag*/
     180       20996 :         if (builder->slMap.DTSDeltaLength) {
     181        3157 :                 gf_bs_write_int(builder->pck_hdr, builder->sl_header.decodingTimeStampFlag, 1);
     182        3157 :                 nbBits += 1;
     183             :         }
     184             :         /*DTS*/
     185       20996 :         if (builder->sl_header.decodingTimeStampFlag) {
     186        3157 :                 delta = (u32) (builder->sl_header.compositionTimeStamp - builder->sl_header.decodingTimeStamp);
     187        3157 :                 gf_bs_write_int(builder->pck_hdr, delta, builder->slMap.DTSDeltaLength);
     188        3157 :                 nbBits += builder->slMap.DTSDeltaLength;
     189             :         }
     190             :         /*RAP indication*/
     191       20996 :         if (builder->slMap.RandomAccessIndication) {
     192         956 :                 gf_bs_write_int(builder->pck_hdr, builder->sl_header.randomAccessPointFlag, 1);
     193         956 :                 nbBits ++;
     194             :         }
     195             :         /*stream state - write AUSeqNum*/
     196       20996 :         if (builder->slMap.StreamStateIndication) {
     197           5 :                 gf_bs_write_int(builder->pck_hdr, builder->sl_header.AU_sequenceNumber, builder->slMap.StreamStateIndication);
     198           5 :                 nbBits += builder->slMap.StreamStateIndication;
     199             :         }
     200             : 
     201             :         return nbBits;
     202             : }
     203             : 
     204             : 
     205       18214 : GF_Err gp_rtp_builder_do_mpeg4(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
     206             : {
     207             :         u8 *sl_buffer, *payl_buffer;
     208             :         u32 sl_buffer_size, payl_buffer_size;
     209             :         u32 auh_size_tmp, bytesLeftInPacket, infoSize, pckSize;
     210             :         u64 pos;
     211             :         u8 flush_pck, no_split;
     212             : 
     213             :         flush_pck = 0;
     214             : 
     215             :         bytesLeftInPacket = data_size;
     216             :         /*flush everything*/
     217       18214 :         if (!data) {
     218          45 :                 if (builder->payload) goto flush_packet;
     219             :                 return GF_OK;
     220             :         }
     221       18169 :         if (builder->payload && builder->force_flush) goto flush_packet;
     222             : 
     223             :         //go till done
     224       43377 :         while (bytesLeftInPacket) {
     225             :                 no_split = 0;
     226             : 
     227       25192 :                 if (builder->sl_header.accessUnitStartFlag) {
     228             :                         //init SL
     229       22365 :                         if (builder->sl_header.compositionTimeStamp != builder->sl_header.decodingTimeStamp) {
     230         844 :                                 builder->sl_header.decodingTimeStampFlag = 1;
     231             :                         }
     232       22365 :                         builder->sl_header.compositionTimeStampFlag = 1;
     233       22365 :                         builder->sl_header.accessUnitLength = FullAUSize;
     234             : 
     235             :                         //init some vars - based on the available size and the TS
     236             :                         //we decide if we go with the same RTP TS serie or not
     237       22365 :                         if (builder->payload) {
     238             :                                 //don't store more than what we can (that is 2^slMap->CTSDelta - 1)
     239       10690 :                                 if ( (builder->flags & GP_RTP_PCK_SIGNAL_TS)
     240           0 :                                         && (builder->sl_header.compositionTimeStamp - builder->rtp_header.TimeStamp >= (u32) ( 1 << builder->slMap.CTSDeltaLength) ) ) {
     241             :                                         goto flush_packet;
     242             :                                 }
     243             :                                 //don't split AU if # TS , start a new RTP pck
     244       10690 :                                 if (builder->sl_header.compositionTimeStamp != builder->rtp_header.TimeStamp)
     245             :                                         no_split = 1;
     246             :                         }
     247             :                 }
     248             : 
     249             :                 /*new RTP Packet*/
     250       25192 :                 if (!builder->payload) {
     251             :                         /*first SL in RTP*/
     252       14502 :                         builder->first_sl_in_rtp = GF_TRUE;
     253             : 
     254             :                         /*if this is the end of an AU we will set it to 0 as soon as an AU is splitted*/
     255       14502 :                         builder->rtp_header.Marker = 1;
     256       14502 :                         builder->rtp_header.PayloadType = builder->PayloadType;
     257       14502 :                         builder->rtp_header.SequenceNumber += 1;
     258             : 
     259       14502 :                         builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
     260             :                         /*prepare the mapped headers*/
     261       14502 :                         builder->pck_hdr = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     262       14502 :                         builder->payload = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     263       14502 :                         builder->bytesInPacket = 0;
     264             : 
     265             :                         /*in multiSL there is a MSLHSize structure on 2 bytes*/
     266       14502 :                         builder->auh_size = 0;
     267       14502 :                         if (builder->has_AU_header) {
     268        8156 :                                 builder->auh_size = 16;
     269        8156 :                                 gf_bs_write_int(builder->pck_hdr, 0, 16);
     270             :                         }
     271             :                         flush_pck = 0;
     272             :                         /*and create packet*/
     273       14502 :                         builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
     274             :                 }
     275             : 
     276             :                 //make sure we are not interleaving too much - this should never happen actually
     277       25192 :                 if (builder->slMap.IndexDeltaLength
     278       14908 :                         && !builder->first_sl_in_rtp
     279       10690 :                         && (builder->sl_header.AU_sequenceNumber - builder->last_au_sn >= (u32) 1<<builder->slMap.IndexDeltaLength)) {
     280             :                         //we cannot write this packet here
     281             :                         goto flush_packet;
     282             :                 }
     283             :                 /*check max ptime*/
     284       25192 :                 if (builder->max_ptime && ( (u32) builder->sl_header.compositionTimeStamp >= builder->rtp_header.TimeStamp + builder->max_ptime) )
     285             :                         goto flush_packet;
     286             : 
     287       25192 :                 auh_size_tmp = gf_rtp_build_au_hdr_size(builder, &builder->sl_header);
     288             : 
     289       25192 :                 infoSize = auh_size_tmp + builder->auh_size;
     290       25192 :                 infoSize /= 8;
     291             :                 /*align*/
     292       25192 :                 if ( (builder->auh_size + auh_size_tmp) % 8) infoSize += 1;
     293             : 
     294             : 
     295       25192 :                 if (bytesLeftInPacket + infoSize + builder->bytesInPacket <= builder->Path_MTU) {
     296             :                         //End of our data chunk
     297             :                         pckSize = bytesLeftInPacket;
     298       18169 :                         builder->sl_header.accessUnitEndFlag = IsAUEnd;
     299             : 
     300       18169 :                         builder->auh_size += auh_size_tmp;
     301             : 
     302       18169 :                         builder->sl_header.paddingFlag = builder->sl_header.paddingBits ? 1 : 0;
     303             :                 } else {
     304             : 
     305             :                         //AU cannot fit in packet. If no split, start a new packet
     306        7023 :                         if (no_split) goto flush_packet;
     307             : 
     308        2827 :                         builder->auh_size += auh_size_tmp;
     309             : 
     310        2827 :                         pckSize = builder->Path_MTU - (infoSize + builder->bytesInPacket);
     311             :                         //that's the end of the rtp packet
     312             :                         flush_pck = 1;
     313             :                         //but not of the AU -> marker is 0
     314        2827 :                         builder->rtp_header.Marker = 0;
     315             :                 }
     316             : 
     317       20996 :                 gf_rtp_build_au_hdr_write(builder, pckSize, builder->rtp_header.TimeStamp);
     318             : 
     319             :                 //notify the user of our data structure
     320       20996 :                 if (builder->OnDataReference)
     321       20498 :                         builder->OnDataReference(builder->cbk_obj, pckSize, data_size - bytesLeftInPacket);
     322             :                 else
     323         498 :                         gf_bs_write_data(builder->payload, data + (data_size - bytesLeftInPacket), pckSize);
     324             : 
     325             : 
     326       20996 :                 bytesLeftInPacket -= pckSize;
     327       20996 :                 builder->bytesInPacket += pckSize;
     328             :                 /*update IV*/
     329       20996 :                 builder->IV += pckSize;
     330       20996 :                 builder->sl_header.paddingFlag = 0;
     331       20996 :                 builder->sl_header.accessUnitStartFlag = 0;
     332             : 
     333             :                 //we are splitting a payload, auto increment SL seq num
     334       20996 :                 if (bytesLeftInPacket) {
     335        2827 :                         builder->sl_header.packetSequenceNumber += 1;
     336       18169 :                 } else if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) {
     337        7458 :                         builder->rtp_header.Marker = 1;
     338             :                         flush_pck = 1;
     339             :                 }
     340             : 
     341             :                 //first SL in RTP is done
     342       20996 :                 builder->first_sl_in_rtp = GF_FALSE;
     343             : 
     344             :                 //store current sl
     345       20996 :                 builder->last_au_sn = builder->sl_header.AU_sequenceNumber;
     346             : 
     347       31707 :                 if (!flush_pck) continue;
     348             : 
     349             :                 //done with the packet
     350       14497 : flush_packet:
     351             : 
     352       14497 :                 gf_bs_align(builder->pck_hdr);
     353             : 
     354             :                 /*no aux data yet*/
     355       14497 :                 if (builder->slMap.AuxiliaryDataSizeLength)  {
     356             :                         //write RSLH after the MSLH
     357           0 :                         gf_bs_write_int(builder->pck_hdr, 0, builder->slMap.AuxiliaryDataSizeLength);
     358             :                 }
     359             :                 /*rewrite the size header*/
     360       14497 :                 if (builder->has_AU_header) {
     361        8151 :                         pos = gf_bs_get_position(builder->pck_hdr);
     362        8151 :                         gf_bs_seek(builder->pck_hdr, 0);
     363        8151 :                         builder->auh_size -= 16;
     364        8151 :                         gf_bs_write_int(builder->pck_hdr, builder->auh_size, 16);
     365        8151 :                         gf_bs_seek(builder->pck_hdr, pos);
     366             :                 }
     367             : 
     368       14497 :                 sl_buffer = NULL;
     369       14497 :                 gf_bs_get_content(builder->pck_hdr, &sl_buffer, &sl_buffer_size);
     370             :                 //delete our bitstream
     371       14497 :                 gf_bs_del(builder->pck_hdr);
     372       14497 :                 builder->pck_hdr = NULL;
     373             : 
     374       14497 :                 payl_buffer = NULL;
     375       14497 :                 payl_buffer_size = 0;
     376       14497 :                 if (!builder->OnDataReference)
     377         130 :                         gf_bs_get_content(builder->payload, &payl_buffer, &payl_buffer_size);
     378             : 
     379       14497 :                 gf_bs_del(builder->payload);
     380       14497 :                 builder->payload = NULL;
     381             : 
     382             :                 /*notify header*/
     383       14497 :                 builder->OnData(builder->cbk_obj, sl_buffer, sl_buffer_size, GF_TRUE);
     384             :                 /*notify payload*/
     385       14497 :                 if (payl_buffer) {
     386         130 :                         builder->OnData(builder->cbk_obj, payl_buffer, payl_buffer_size, GF_FALSE);
     387         130 :                         gf_free(payl_buffer);
     388             :                 }
     389             :                 /*flush packet*/
     390       14497 :                 builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
     391       14497 :                 gf_free(sl_buffer);
     392             :         }
     393             :         //packet is done, update AU markers
     394       18185 :         if (IsAUEnd) {
     395       18185 :                 builder->sl_header.accessUnitStartFlag = 1;
     396       18185 :                 builder->sl_header.accessUnitEndFlag = 0;
     397             :         }
     398             :         return GF_OK;
     399             : }
     400             : 
     401             : 
     402        3721 : GF_Err gp_rtp_builder_do_avc(GP_RTPPacketizer *builder, u8 *nalu, u32 nalu_size, u8 IsAUEnd, u32 FullAUSize)
     403             : {
     404             :         u32 do_flush, bytesLeft, size, nal_type;
     405             :         char shdr[2];
     406             :         char stap_hdr;
     407             : 
     408             :         do_flush = 0;
     409        3721 :         if (!nalu) do_flush = 1;
     410             :         /*we only do STAP or SINGLE modes*/
     411        3705 :         else if (builder->sl_header.accessUnitStartFlag) do_flush = 1;
     412             :         /*we must NOT fragment a NALU*/
     413        1529 :         else if (builder->bytesInPacket + nalu_size >= builder->Path_MTU) do_flush = 2;
     414             :         /*aggregation is disabled*/
     415         722 :         else if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) do_flush = 2;
     416             : 
     417        3721 :         if (builder->bytesInPacket && do_flush) {
     418        1228 :                 builder->rtp_header.Marker = (do_flush==1) ? 1 : 0;
     419        1228 :                 builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
     420        1228 :                 builder->bytesInPacket = 0;
     421             :         }
     422             : 
     423        3721 :         if (!nalu) return GF_OK;
     424             : 
     425             :         /*need a new RTP packet*/
     426        3705 :         if (!builder->bytesInPacket) {
     427        3705 :                 builder->rtp_header.PayloadType = builder->PayloadType;
     428        3705 :                 builder->rtp_header.Marker = 0;
     429        3705 :                 builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
     430        3705 :                 builder->rtp_header.SequenceNumber += 1;
     431        3705 :                 builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
     432        3705 :                 builder->avc_non_idr = GF_TRUE;
     433             :         }
     434             : 
     435             :         /*check NAL type to see if disposable or not*/
     436        3705 :         nal_type = nalu[0] & 0x1F;
     437             :         switch (nal_type) {
     438             :         case GF_AVC_NALU_NON_IDR_SLICE:
     439             :         case GF_AVC_NALU_ACCESS_UNIT:
     440             :         case GF_AVC_NALU_END_OF_SEQ:
     441             :         case GF_AVC_NALU_END_OF_STREAM:
     442             :         case GF_AVC_NALU_FILLER_DATA:
     443             :                 break;
     444        1579 :         default:
     445        1579 :                 builder->avc_non_idr = GF_FALSE;
     446        1579 :                 break;
     447             :         }
     448             : 
     449             :         /*at this point we're sure the NALU fits in current packet OR must be splitted*/
     450             : 
     451             :         /*pb: we don't know if next NALU from this AU will be small enough to fit in the packet, so we always
     452             :         go for stap...*/
     453        3705 :         if (builder->bytesInPacket+nalu_size<builder->Path_MTU) {
     454             :                 Bool use_stap = GF_TRUE;
     455             :                 /*if this is the AU end and no NALU in packet, go for single mode*/
     456        2678 :                 if (IsAUEnd && !builder->bytesInPacket) use_stap = GF_FALSE;
     457             : 
     458             :                 if (use_stap) {
     459             :                         /*declare STAP-A NAL*/
     460        1228 :                         if (!builder->bytesInPacket) {
     461             :                                 /*copy over F and NRI from first nal in packet and assign type*/
     462        1228 :                                 stap_hdr = (nalu[0] & 0xE0) | 24;
     463        1228 :                                 builder->OnData(builder->cbk_obj, (char *) &stap_hdr, 1, GF_FALSE);
     464        1228 :                                 builder->bytesInPacket = 1;
     465             :                         }
     466             :                         /*add NALU size*/
     467        1228 :                         shdr[0] = nalu_size>>8;
     468        1228 :                         shdr[1] = nalu_size&0x00ff;
     469        1228 :                         builder->OnData(builder->cbk_obj, (char *)shdr, 2, GF_FALSE);
     470        1228 :                         builder->bytesInPacket += 2;
     471             :                 }
     472             :                 /*add data*/
     473        2678 :                 if (builder->OnDataReference)
     474        2561 :                         builder->OnDataReference(builder->cbk_obj, nalu_size, 0);
     475             :                 else
     476         117 :                         builder->OnData(builder->cbk_obj, nalu, nalu_size, GF_FALSE);
     477             : 
     478        2678 :                 builder->bytesInPacket += nalu_size;
     479             : 
     480        2678 :                 if (IsAUEnd) {
     481        1450 :                         builder->rtp_header.Marker = 1;
     482        1450 :                         builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
     483        1450 :                         builder->bytesInPacket = 0;
     484             :                 }
     485             :         }
     486             :         /*fragmentation unit*/
     487             :         else {
     488             :                 u32 offset;
     489             :                 assert(nalu_size>=builder->Path_MTU);
     490             :                 assert(!builder->bytesInPacket);
     491             :                 /*FU payload doesn't have the NAL hdr*/
     492        1027 :                 bytesLeft = nalu_size - 1;
     493             :                 offset = 1;
     494        4583 :                 while (bytesLeft) {
     495        2529 :                         if (2 + bytesLeft > builder->Path_MTU) {
     496        1502 :                                 size = builder->Path_MTU - 2;
     497             :                         } else {
     498             :                                 size = bytesLeft;
     499             :                         }
     500             : 
     501             :                         /*copy over F and NRI from nal in packet and assign type*/
     502        2529 :                         shdr[0] = (nalu[0] & 0xE0) | 28;
     503             :                         /*copy over NAL type from nal and set start bit and end bit*/
     504        2529 :                         shdr[1] = (nalu[0] & 0x1F);
     505             :                         /*start bit*/
     506        2529 :                         if (offset==1) shdr[1] |= 0x80;
     507             :                         /*end bit*/
     508        1502 :                         else if (size == bytesLeft) shdr[1] |= 0x40;
     509             : 
     510        2529 :                         builder->OnData(builder->cbk_obj, (char *)shdr, 2, GF_FALSE);
     511             : 
     512             :                         /*add data*/
     513        2529 :                         if (builder->OnDataReference)
     514        2477 :                                 builder->OnDataReference(builder->cbk_obj, size, offset);
     515             :                         else
     516          52 :                                 builder->OnData(builder->cbk_obj, nalu+offset, size, GF_FALSE);
     517             : 
     518        2529 :                         offset += size;
     519        2529 :                         bytesLeft -= size;
     520             : 
     521             :                         /*flush no matter what (FUs cannot be agreggated)*/
     522        2529 :                         builder->rtp_header.Marker = (IsAUEnd && !bytesLeft) ? 1 : 0;
     523        2529 :                         builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
     524        2529 :                         builder->bytesInPacket = 0;
     525             : 
     526        2529 :                         if (bytesLeft) {
     527        1502 :                                 builder->rtp_header.PayloadType = builder->PayloadType;
     528        1502 :                                 builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
     529        1502 :                                 builder->rtp_header.SequenceNumber += 1;
     530        1502 :                                 builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
     531             :                         }
     532             :                 }
     533             :         }
     534             : 
     535             :         return GF_OK;
     536             : }
     537             : 
     538        2786 : GF_Err gp_rtp_builder_do_hevc(GP_RTPPacketizer *builder, u8 *nalu, u32 nalu_size, u8 IsAUEnd, u32 FullAUSize)
     539             : {
     540             :         u32 do_flush, bytesLeft, size;
     541             : 
     542             :         do_flush = 0;
     543        2786 :         if (!nalu) do_flush = 1;
     544        2783 :         else if (builder->sl_header.accessUnitStartFlag) do_flush = 1;
     545             :         /*we must NOT fragment a NALU*/
     546        2504 :         else if (builder->bytesInPacket + nalu_size + 4 >= builder->Path_MTU) do_flush = 2; //2 bytes PayloadHdr for AP + 2 bytes NAL size
     547             :         /*aggregation is disabled*/
     548        2199 :         else if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) do_flush = 2;
     549             : 
     550        2786 :         if (builder->bytesInPacket && do_flush) {
     551         539 :                 builder->rtp_header.Marker = (do_flush==1) ? 1 : 0;
     552             :                 /*insert payload_hdr in case of AP*/
     553         539 :                 if (strlen(builder->hevc_payload_hdr)) {
     554         299 :                         builder->OnData(builder->cbk_obj, (char *)builder->hevc_payload_hdr, 2, GF_TRUE);
     555             :                         memset(builder->hevc_payload_hdr, 0, 2);
     556             :                 }
     557         539 :                 builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
     558         539 :                 builder->bytesInPacket = 0;
     559             :         }
     560             : 
     561        2786 :         if (!nalu) return GF_OK;
     562             : 
     563             :         /*need a new RTP packet*/
     564        2783 :         if (!builder->bytesInPacket) {
     565         845 :                 builder->rtp_header.PayloadType = builder->PayloadType;
     566         845 :                 builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
     567         845 :                 builder->rtp_header.SequenceNumber += 1;
     568         845 :                 builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
     569             :         }
     570             : 
     571             :         /*at this point we're sure the NALU fits in current packet OR must be splitted*/
     572             :         /*check that we should use single NALU packet mode or aggreation packets mode*/
     573        2783 :         if (builder->bytesInPacket+nalu_size+4 < builder->Path_MTU) {
     574        2756 :                 Bool use_AP = (builder->flags & GP_RTP_PCK_USE_MULTI) ? GF_TRUE : GF_FALSE;
     575             :                 /*if this is the AU end and no NALU in packet, go for single NALU packet mode*/
     576        2756 :                 if (IsAUEnd && !builder->bytesInPacket) use_AP = GF_FALSE;
     577             : 
     578        2727 :                 if (use_AP) {
     579             :                         char nal_s[2];
     580             :                         /*declare PayloadHdr for AP*/
     581        2487 :                         if (!builder->bytesInPacket) {
     582             :                                 /*copy F bit and assign type*/
     583         549 :                                 builder->hevc_payload_hdr[0] = (nalu[0] & 0x81) | (48 << 1);
     584             :                                 /*copy LayerId and TID*/
     585         549 :                                 builder->hevc_payload_hdr[1] = nalu[1];
     586             :                         }
     587             :                         else {
     588             :                                 /*F bit of AP is 0 if the F nit of each aggreated NALU is 0; otherwise its must be 1*/
     589             :                                 /*LayerId and TID must ne the lowest value of LayerId and TID of all aggreated NALU*/
     590             :                                 u8 cur_LayerId, cur_TID, new_LayerId, new_TID;
     591             : 
     592        1938 :                                 builder->hevc_payload_hdr[0] |= (nalu[0] & 0x80);
     593        1938 :                                 cur_LayerId = ((builder->hevc_payload_hdr[0] & 0x01) << 5) + ((builder->hevc_payload_hdr[1] & 0xF8) >> 3);
     594        1938 :                                 new_LayerId = ((nalu[0] & 0x01) << 5) + ((nalu[1] & 0xF8) >> 3);
     595        1938 :                                 if (cur_LayerId > new_LayerId) {
     596           0 :                                         builder->hevc_payload_hdr[0] = (builder->hevc_payload_hdr[0] & 0xFE) | (nalu[0] & 0x01);
     597           0 :                                         builder->hevc_payload_hdr[1] = (builder->hevc_payload_hdr[1] & 0x07) | (nalu[1] & 0xF8);
     598             :                                 }
     599        1938 :                                 cur_TID = builder->hevc_payload_hdr[1] & 0x07;
     600        1938 :                                 new_TID = nalu[1] & 0x07;
     601        1938 :                                 if (cur_TID > new_TID) {
     602           0 :                                         builder->hevc_payload_hdr[1] = (builder->hevc_payload_hdr[1] & 0xF8) | (nalu[1] & 0x07);
     603             :                                 }
     604             :                         }
     605             : 
     606             :                         /*add NALU size*/
     607        2487 :                         nal_s[0] = nalu_size>>8;
     608        2487 :                         nal_s[1] = nalu_size&0x00ff;
     609        2487 :                         builder->OnData(builder->cbk_obj, (char *)nal_s, 2, GF_FALSE);
     610        2487 :                         builder->bytesInPacket += 2;
     611             :                 }
     612             :                 /*add data*/
     613        2756 :                 if (builder->OnDataReference)
     614        2489 :                         builder->OnDataReference(builder->cbk_obj, nalu_size, 0);
     615             :                 else
     616         267 :                         builder->OnData(builder->cbk_obj, nalu, nalu_size, GF_FALSE);
     617             : 
     618        2756 :                 builder->bytesInPacket += nalu_size;
     619             : 
     620        2756 :                 if (IsAUEnd) {
     621         279 :                         builder->rtp_header.Marker = 1;
     622         279 :                         if (strlen(builder->hevc_payload_hdr)) {
     623         250 :                                 builder->OnData(builder->cbk_obj, (char *)builder->hevc_payload_hdr, 2, GF_TRUE);
     624             :                                 memset(builder->hevc_payload_hdr, 0, 2);
     625             :                         }
     626         279 :                         builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
     627         279 :                         builder->bytesInPacket = 0;
     628             :                 }
     629             :         }
     630             :         /*fragmentation unit*/
     631             :         else {
     632             :                 u32 offset;
     633             :                 char payload_hdr[2];
     634             :                 char shdr;
     635             : 
     636             :                 assert(nalu_size + 4 >=builder->Path_MTU);
     637             :                 assert(!builder->bytesInPacket);
     638             : 
     639             :                 /*FU payload doesn't have the NAL hdr (2 bytes*/
     640          27 :                 bytesLeft = nalu_size - 2;
     641             :                 offset = 2;
     642         158 :                 while (bytesLeft) {
     643         104 :                         if (3 + bytesLeft > builder->Path_MTU) {
     644          77 :                                 size = builder->Path_MTU - 3;
     645             :                         } else {
     646             :                                 size = bytesLeft;
     647             :                         }
     648             : 
     649             :                         /*declare PayloadHdr for FU*/
     650             :                         memset(payload_hdr, 0, 2);
     651             :                         /*copy F bit and assign type*/
     652         104 :                         payload_hdr[0] = (nalu[0] & 0x81) | (49 << 1);
     653             :                         /*copy LayerId and TID*/
     654         104 :                         payload_hdr[1] = nalu[1];
     655         104 :                         builder->OnData(builder->cbk_obj, (char *)payload_hdr, 2, GF_FALSE);
     656             : 
     657             :                         /*declare FU header*/
     658             :                         shdr = 0;
     659             :                         /*assign type*/
     660         104 :                         shdr |= (nalu[0] & 0x7E) >> 1;
     661             :                         /*start bit*/
     662         104 :                         if (offset==2) shdr |= 0x80;
     663             :                         /*end bit*/
     664          77 :                         else if (size == bytesLeft) shdr |= 0x40;
     665             : 
     666         104 :                         builder->OnData(builder->cbk_obj, &shdr, 1, GF_FALSE);
     667             : 
     668             :                         /*add data*/
     669         104 :                         if (builder->OnDataReference)
     670          90 :                                 builder->OnDataReference(builder->cbk_obj, size, offset);
     671             :                         else
     672          14 :                                 builder->OnData(builder->cbk_obj, nalu+offset, size, GF_FALSE);
     673             : 
     674         104 :                         offset += size;
     675         104 :                         bytesLeft -= size;
     676             : 
     677             :                         /*flush no matter what (FUs cannot be agreggated)*/
     678         104 :                         builder->rtp_header.Marker = (IsAUEnd && !bytesLeft) ? 1 : 0;
     679         104 :                         builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
     680         104 :                         builder->bytesInPacket = 0;
     681             : 
     682         104 :                         if (bytesLeft) {
     683          77 :                                 builder->rtp_header.PayloadType = builder->PayloadType;
     684          77 :                                 builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
     685          77 :                                 builder->rtp_header.SequenceNumber += 1;
     686          77 :                                 builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
     687             :                         }
     688             :                 }
     689             :         }
     690             :         return GF_OK;
     691             : }
     692             : 
     693           0 : void latm_flush(GP_RTPPacketizer *builder)
     694             : {
     695          10 :         if (builder->bytesInPacket) {
     696           9 :                 builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
     697           9 :                 builder->bytesInPacket = 0;
     698             :         }
     699          10 :         builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
     700           0 : }
     701             : 
     702          49 : GF_Err gp_rtp_builder_do_latm(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration)
     703             : {
     704             :         u32 size, latm_hdr_size, i, data_offset;
     705             :         Bool fragmented;
     706             : 
     707          49 :         if (!data) {
     708             :                 latm_flush(builder);
     709           2 :                 return GF_OK;
     710             :         }
     711             : 
     712          47 :         if ((builder->flags & GP_RTP_PCK_USE_MULTI) && builder->max_ptime) {
     713           0 :                 if ((u32) builder->sl_header.compositionTimeStamp + duration >= builder->rtp_header.TimeStamp + builder->max_ptime)
     714             :                         latm_flush(builder);
     715             :         }
     716             :         /*compute max size for frame, flush current if this doesn't fit*/
     717          47 :         latm_hdr_size = (data_size / 255) + 1;
     718          47 :         if (latm_hdr_size+data_size > builder->Path_MTU - builder->bytesInPacket) {
     719             :                 latm_flush(builder);
     720             :         }
     721             : 
     722             :         data_offset = 0;
     723             :         fragmented = GF_FALSE;
     724          94 :         while (data_size > 0) {
     725             :                 u8 *latm_hdr;
     726          47 :                 latm_hdr_size = (data_size / 255) + 1;
     727             :                 /*fragmenting*/
     728          47 :                 if (latm_hdr_size + data_size > builder->Path_MTU) {
     729             :                         assert(!builder->bytesInPacket);
     730             :                         fragmented = GF_TRUE;
     731           0 :                         latm_hdr_size = (builder->Path_MTU / 255) + 1;
     732           0 :                         size = builder->Path_MTU - latm_hdr_size;
     733           0 :                         builder->rtp_header.Marker = 0;
     734             :                 }
     735             :                 /*last fragment or full AU*/
     736             :                 else {
     737             :                         fragmented = GF_FALSE;
     738             :                         size = data_size;
     739          47 :                         builder->rtp_header.Marker = 1;
     740             :                 }
     741          47 :                 data_size -= size;
     742             : 
     743             :                 /*create new RTP Packet if needed*/
     744          47 :                 if (!builder->bytesInPacket) {
     745           9 :                         builder->rtp_header.SequenceNumber += 1;
     746           9 :                         builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
     747           9 :                         builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
     748             :                 }
     749             : 
     750             :                 /* compute AudioMuxUnit header */
     751          47 :                 latm_hdr_size = (size / 255) + 1;
     752          47 :                 latm_hdr = (unsigned char *)gf_malloc( sizeof(char) * latm_hdr_size);
     753          47 :                 for (i=0; i<latm_hdr_size-1; i++)  latm_hdr[i] = 255;
     754          47 :                 latm_hdr[latm_hdr_size-1] = size % 255;
     755             : 
     756             :                 /*add LATM header IN ORDER in case we aggregate audioMuxElements in RTP*/
     757          47 :                 builder->OnData(builder->cbk_obj, (char*) latm_hdr, latm_hdr_size, GF_FALSE);
     758          47 :                 builder->bytesInPacket += latm_hdr_size;
     759          47 :                 gf_free(latm_hdr);
     760             : 
     761             :                 /*add payload*/
     762          47 :                 if (builder->OnDataReference) {
     763           0 :                         builder->OnDataReference(builder->cbk_obj, size, data_offset);
     764             :                 } else
     765          47 :                         builder->OnData(builder->cbk_obj, data, size, GF_FALSE);
     766             : 
     767          47 :                 builder->bytesInPacket += size;
     768             : 
     769          47 :                 data_offset += size;
     770             : 
     771             :                 /*fragmented AU, always flush packet*/
     772          47 :                 if (!builder->rtp_header.Marker) latm_flush(builder);
     773             :         }
     774             :         /*if the AU has been fragmented or we don't use RTP aggregation, flush*/
     775          47 :         if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) fragmented = GF_TRUE;
     776          47 :         if (fragmented) latm_flush(builder);
     777             : 
     778             :         return GF_OK;
     779             : }
     780             : 
     781             : 
     782             : #endif /*GPAC_DISABLE_STREAMING*/

Generated by: LCOV version 1.13