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