blob: 0c88fc2a23dfbf02f4d500110442c429dbaff241
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 | static void flush_buffered(AVFormatContext *s1, int last) |
37 | { |
38 | RTPMuxContext *s = s1->priv_data; |
39 | 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 | if (s->buffered_nals == 1) { |
43 | enum AVCodecID codec = s1->streams[0]->codecpar->codec_id; |
44 | if (codec == AV_CODEC_ID_H264) |
45 | ff_rtp_send_data(s1, s->buf + 3, s->buf_ptr - s->buf - 3, last); |
46 | else |
47 | ff_rtp_send_data(s1, s->buf + 4, s->buf_ptr - s->buf - 4, last); |
48 | } else |
49 | ff_rtp_send_data(s1, s->buf, s->buf_ptr - s->buf, last); |
50 | } |
51 | s->buf_ptr = s->buf; |
52 | s->buffered_nals = 0; |
53 | } |
54 | |
55 | static void nal_send(AVFormatContext *s1, const uint8_t *buf, int size, int last) |
56 | { |
57 | RTPMuxContext *s = s1->priv_data; |
58 | enum AVCodecID codec = s1->streams[0]->codecpar->codec_id; |
59 | |
60 | av_log(s1, AV_LOG_DEBUG, "Sending NAL %x of len %d M=%d\n", buf[0] & 0x1F, size, last); |
61 | if (size <= s->max_payload_size) { |
62 | int buffered_size = s->buf_ptr - s->buf; |
63 | int header_size; |
64 | int skip_aggregate = 0; |
65 | |
66 | if (codec == AV_CODEC_ID_H264) { |
67 | header_size = 1; |
68 | skip_aggregate = s->flags & FF_RTP_FLAG_H264_MODE0; |
69 | } else { |
70 | header_size = 2; |
71 | } |
72 | |
73 | // Flush buffered NAL units if the current unit doesn't fit |
74 | if (buffered_size + 2 + size > s->max_payload_size) { |
75 | flush_buffered(s1, 0); |
76 | 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 | if (buffered_size + 2 + header_size + size <= s->max_payload_size && |
83 | !skip_aggregate) { |
84 | if (buffered_size == 0) { |
85 | if (codec == AV_CODEC_ID_H264) { |
86 | *s->buf_ptr++ = 24; |
87 | } else { |
88 | *s->buf_ptr++ = 48 << 1; |
89 | *s->buf_ptr++ = 1; |
90 | } |
91 | } |
92 | AV_WB16(s->buf_ptr, size); |
93 | s->buf_ptr += 2; |
94 | memcpy(s->buf_ptr, buf, size); |
95 | s->buf_ptr += size; |
96 | s->buffered_nals++; |
97 | } else { |
98 | flush_buffered(s1, 0); |
99 | ff_rtp_send_data(s1, buf, size, last); |
100 | } |
101 | } else { |
102 | int flag_byte, header_size; |
103 | flush_buffered(s1, 0); |
104 | if (codec == AV_CODEC_ID_H264 && (s->flags & FF_RTP_FLAG_H264_MODE0)) { |
105 | 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 | return; |
109 | } |
110 | av_log(s1, AV_LOG_DEBUG, "NAL size %d > %d\n", size, s->max_payload_size); |
111 | if (codec == AV_CODEC_ID_H264) { |
112 | uint8_t type = buf[0] & 0x1F; |
113 | uint8_t nri = buf[0] & 0x60; |
114 | |
115 | s->buf[0] = 28; /* FU Indicator; Type = 28 ---> FU-A */ |
116 | s->buf[0] |= nri; |
117 | s->buf[1] = type; |
118 | s->buf[1] |= 1 << 7; |
119 | buf += 1; |
120 | size -= 1; |
121 | |
122 | flag_byte = 1; |
123 | header_size = 2; |
124 | } else { |
125 | 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 | s->buf[0] = 49 << 1; |
141 | 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 | s->buf[2] = nal_type; |
156 | /* set the S bit: mark as start fragment */ |
157 | s->buf[2] |= 1 << 7; |
158 | |
159 | /* pass the original NAL header */ |
160 | buf += 2; |
161 | size -= 2; |
162 | |
163 | flag_byte = 2; |
164 | header_size = 3; |
165 | } |
166 | |
167 | while (size + header_size > s->max_payload_size) { |
168 | memcpy(&s->buf[header_size], buf, s->max_payload_size - header_size); |
169 | ff_rtp_send_data(s1, s->buf, s->max_payload_size, 0); |
170 | buf += s->max_payload_size - header_size; |
171 | size -= s->max_payload_size - header_size; |
172 | s->buf[flag_byte] &= ~(1 << 7); |
173 | } |
174 | s->buf[flag_byte] |= 1 << 6; |
175 | memcpy(&s->buf[header_size], buf, size); |
176 | ff_rtp_send_data(s1, s->buf, size + header_size, last); |
177 | } |
178 | } |
179 | |
180 | void ff_rtp_send_h264_hevc(AVFormatContext *s1, const uint8_t *buf1, int size) |
181 | { |
182 | const uint8_t *r, *end = buf1 + size; |
183 | RTPMuxContext *s = s1->priv_data; |
184 | |
185 | s->timestamp = s->cur_timestamp; |
186 | s->buf_ptr = s->buf; |
187 | if (s->nal_length_size) |
188 | r = ff_avc_mp4_find_startcode(buf1, end, s->nal_length_size) ? buf1 : end; |
189 | else |
190 | r = ff_avc_find_startcode(buf1, end); |
191 | while (r < end) { |
192 | const uint8_t *r1; |
193 | |
194 | if (s->nal_length_size) { |
195 | r1 = ff_avc_mp4_find_startcode(r, end, s->nal_length_size); |
196 | if (!r1) |
197 | r1 = end; |
198 | r += s->nal_length_size; |
199 | } else { |
200 | while (!*(r++)); |
201 | r1 = ff_avc_find_startcode(r, end); |
202 | } |
203 | nal_send(s1, r, r1 - r, r1 == end); |
204 | r = r1; |
205 | } |
206 | flush_buffered(s1, 1); |
207 | } |
208 |