* commit 'e5cfc8fdad901c9487fe896421972852f38bcf5':
sdp: Provide out of bound parameter sets for HEVC if extradata is set
Merged-by: Michael Niedermayer <michaelni@gmx.at>
... | ... |
@@ -29,6 +29,7 @@ |
29 | 29 |
#include "avformat.h" |
30 | 30 |
#include "internal.h" |
31 | 31 |
#include "avc.h" |
32 |
+#include "hevc.h" |
|
32 | 33 |
#include "rtp.h" |
33 | 34 |
#if CONFIG_NETWORK |
34 | 35 |
#include "network.h" |
... | ... |
@@ -222,6 +223,107 @@ static char *extradata2psets(AVCodecContext *c) |
222 | 222 |
return psets; |
223 | 223 |
} |
224 | 224 |
|
225 |
+static char *extradata2psets_hevc(AVCodecContext *c) |
|
226 |
+{ |
|
227 |
+ char *psets; |
|
228 |
+ uint8_t *extradata = c->extradata; |
|
229 |
+ int extradata_size = c->extradata_size; |
|
230 |
+ uint8_t *tmpbuf = NULL; |
|
231 |
+ int ps_pos[3] = { 0 }; |
|
232 |
+ static const char * const ps_names[3] = { "vps", "sps", "pps" }; |
|
233 |
+ int num_arrays, num_nalus; |
|
234 |
+ int pos, i, j; |
|
235 |
+ |
|
236 |
+ // Convert to hvcc format. Since we need to group multiple NALUs of |
|
237 |
+ // the same type, and we might need to convert from one format to the |
|
238 |
+ // other anyway, we get away with a little less work by using the hvcc |
|
239 |
+ // format. |
|
240 |
+ if (c->extradata[0] != 1) { |
|
241 |
+ AVIOContext *pb; |
|
242 |
+ if (avio_open_dyn_buf(&pb) < 0) |
|
243 |
+ return NULL; |
|
244 |
+ if (ff_isom_write_hvcc(pb, c->extradata, c->extradata_size, 0) < 0) { |
|
245 |
+ avio_close_dyn_buf(pb, &tmpbuf); |
|
246 |
+ goto err; |
|
247 |
+ } |
|
248 |
+ extradata_size = avio_close_dyn_buf(pb, &extradata); |
|
249 |
+ tmpbuf = extradata; |
|
250 |
+ } |
|
251 |
+ |
|
252 |
+ if (extradata_size < 23) |
|
253 |
+ goto err; |
|
254 |
+ |
|
255 |
+ num_arrays = extradata[22]; |
|
256 |
+ pos = 23; |
|
257 |
+ for (i = 0; i < num_arrays; i++) { |
|
258 |
+ int num_nalus, nalu_type; |
|
259 |
+ if (pos + 3 > extradata_size) |
|
260 |
+ goto err; |
|
261 |
+ nalu_type = extradata[pos] & 0x3f; |
|
262 |
+ // Not including libavcodec/hevc.h to avoid confusion between |
|
263 |
+ // NAL_* with the same name for both H264 and HEVC. |
|
264 |
+ if (nalu_type == 32) // VPS |
|
265 |
+ ps_pos[0] = pos; |
|
266 |
+ else if (nalu_type == 33) // SPS |
|
267 |
+ ps_pos[1] = pos; |
|
268 |
+ else if (nalu_type == 34) // PPS |
|
269 |
+ ps_pos[2] = pos; |
|
270 |
+ num_nalus = AV_RB16(&extradata[pos + 1]); |
|
271 |
+ pos += 3; |
|
272 |
+ for (j = 0; j < num_nalus; j++) { |
|
273 |
+ int len; |
|
274 |
+ if (pos + 2 > extradata_size) |
|
275 |
+ goto err; |
|
276 |
+ len = AV_RB16(&extradata[pos]); |
|
277 |
+ pos += 2; |
|
278 |
+ if (pos + len > extradata_size) |
|
279 |
+ goto err; |
|
280 |
+ pos += len; |
|
281 |
+ } |
|
282 |
+ } |
|
283 |
+ if (!ps_pos[0] || !ps_pos[1] || !ps_pos[2]) |
|
284 |
+ goto err; |
|
285 |
+ |
|
286 |
+ psets = av_mallocz(MAX_PSET_SIZE); |
|
287 |
+ if (!psets) |
|
288 |
+ goto err; |
|
289 |
+ psets[0] = '\0'; |
|
290 |
+ |
|
291 |
+ for (i = 0; i < 3; i++) { |
|
292 |
+ pos = ps_pos[i]; |
|
293 |
+ |
|
294 |
+ if (i > 0) |
|
295 |
+ av_strlcat(psets, "; ", MAX_PSET_SIZE); |
|
296 |
+ av_strlcatf(psets, MAX_PSET_SIZE, "sprop-%s=", ps_names[i]); |
|
297 |
+ |
|
298 |
+ // Skipping boundary checks in the input here; we've already traversed |
|
299 |
+ // the whole hvcc structure above without issues |
|
300 |
+ num_nalus = AV_RB16(&extradata[pos + 1]); |
|
301 |
+ pos += 3; |
|
302 |
+ for (j = 0; j < num_nalus; j++) { |
|
303 |
+ int len = AV_RB16(&extradata[pos]); |
|
304 |
+ int strpos; |
|
305 |
+ pos += 2; |
|
306 |
+ if (j > 0) |
|
307 |
+ av_strlcat(psets, ",", MAX_PSET_SIZE); |
|
308 |
+ strpos = strlen(psets); |
|
309 |
+ if (!av_base64_encode(psets + strpos, MAX_PSET_SIZE - strpos, |
|
310 |
+ &extradata[pos], len)) { |
|
311 |
+ av_free(psets); |
|
312 |
+ goto err; |
|
313 |
+ } |
|
314 |
+ pos += len; |
|
315 |
+ } |
|
316 |
+ } |
|
317 |
+ av_free(tmpbuf); |
|
318 |
+ |
|
319 |
+ return psets; |
|
320 |
+ |
|
321 |
+err: |
|
322 |
+ av_free(tmpbuf); |
|
323 |
+ return NULL; |
|
324 |
+} |
|
325 |
+ |
|
225 | 326 |
static char *extradata2config(AVCodecContext *c) |
226 | 327 |
{ |
227 | 328 |
char *config; |
... | ... |
@@ -425,9 +527,11 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, |
425 | 425 |
break; |
426 | 426 |
case AV_CODEC_ID_HEVC: |
427 | 427 |
if (c->extradata_size) |
428 |
- av_log(NULL, AV_LOG_WARNING, "HEVC extradata not currently " |
|
429 |
- "passed properly through SDP\n"); |
|
428 |
+ config = extradata2psets_hevc(c); |
|
430 | 429 |
av_strlcatf(buff, size, "a=rtpmap:%d H265/90000\r\n", payload_type); |
430 |
+ if (config) |
|
431 |
+ av_strlcatf(buff, size, "a=fmtp:%d %s\r\n", |
|
432 |
+ payload_type, config); |
|
431 | 433 |
break; |
432 | 434 |
case AV_CODEC_ID_MPEG4: |
433 | 435 |
if (c->extradata_size) { |