| 1 | /* |
| 2 | * RTP packetizer for HEVC/H.265 payload format (draft version 6) |
| 3 | * Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.com> |
| 4 | * |
| 5 | * This file is part of FFmpeg. |
| 6 | * |
| 7 | * FFmpeg is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU Lesser General Public |
| 9 | * License as published by the Free Software Foundation; either |
| 10 | * version 2.1 of the License, or (at your option) any later version. |
| 11 | * |
| 12 | * FFmpeg is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | * Lesser General Public License for more details. |
| 16 | * |
| 17 | * You should have received a copy of the GNU Lesser General Public |
| 18 | * License along with FFmpeg; if not, write to the Free Software |
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 20 | */ |
| 21 | |
| 22 | #include "avc.h" |
| 23 | #include "avformat.h" |
| 24 | #include "rtpenc.h" |
| 25 | |
| 26 | #define RTP_HEVC_HEADERS_SIZE 3 |
| 27 | |
| 28 | static void nal_send(AVFormatContext *ctx, const uint8_t *buf, int len, int last_packet_of_frame) |
| 29 | { |
| 30 | RTPMuxContext *rtp_ctx = ctx->priv_data; |
| 31 | int rtp_payload_size = rtp_ctx->max_payload_size - RTP_HEVC_HEADERS_SIZE; |
| 32 | int nal_type = (buf[0] >> 1) & 0x3F; |
| 33 | |
| 34 | /* send it as one single NAL unit? */ |
| 35 | if (len <= rtp_ctx->max_payload_size) { |
| 36 | /* use the original NAL unit buffer and transmit it as RTP payload */ |
| 37 | ff_rtp_send_data(ctx, buf, len, last_packet_of_frame); |
| 38 | } else { |
| 39 | /* |
| 40 | create the HEVC payload header and transmit the buffer as fragmentation units (FU) |
| 41 | |
| 42 | 0 1 |
| 43 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 |
| 44 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 45 | |F| Type | LayerId | TID | |
| 46 | +-------------+-----------------+ |
| 47 | |
| 48 | F = 0 |
| 49 | Type = 49 (fragmentation unit (FU)) |
| 50 | LayerId = 0 |
| 51 | TID = 1 |
| 52 | */ |
| 53 | rtp_ctx->buf[0] = 49 << 1; |
| 54 | rtp_ctx->buf[1] = 1; |
| 55 | |
| 56 | /* |
| 57 | create the FU header |
| 58 | |
| 59 | 0 1 2 3 4 5 6 7 |
| 60 | +-+-+-+-+-+-+-+-+ |
| 61 | |S|E| FuType | |
| 62 | +---------------+ |
| 63 | |
| 64 | S = variable |
| 65 | E = variable |
| 66 | FuType = NAL unit type |
| 67 | */ |
| 68 | rtp_ctx->buf[2] = nal_type; |
| 69 | /* set the S bit: mark as start fragment */ |
| 70 | rtp_ctx->buf[2] |= 1 << 7; |
| 71 | |
| 72 | /* pass the original NAL header */ |
| 73 | buf += 2; |
| 74 | len -= 2; |
| 75 | |
| 76 | while (len > rtp_payload_size) { |
| 77 | /* complete and send current RTP packet */ |
| 78 | memcpy(&rtp_ctx->buf[RTP_HEVC_HEADERS_SIZE], buf, rtp_payload_size); |
| 79 | ff_rtp_send_data(ctx, rtp_ctx->buf, rtp_ctx->max_payload_size, 0); |
| 80 | |
| 81 | buf += rtp_payload_size; |
| 82 | len -= rtp_payload_size; |
| 83 | |
| 84 | /* reset the S bit */ |
| 85 | rtp_ctx->buf[2] &= ~(1 << 7); |
| 86 | } |
| 87 | |
| 88 | /* set the E bit: mark as last fragment */ |
| 89 | rtp_ctx->buf[2] |= 1 << 6; |
| 90 | |
| 91 | /* complete and send last RTP packet */ |
| 92 | memcpy(&rtp_ctx->buf[RTP_HEVC_HEADERS_SIZE], buf, len); |
| 93 | ff_rtp_send_data(ctx, rtp_ctx->buf, len + 2, last_packet_of_frame); |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | void ff_rtp_send_hevc(AVFormatContext *ctx, const uint8_t *frame_buf, int frame_size) |
| 98 | { |
| 99 | const uint8_t *next_NAL_unit; |
| 100 | const uint8_t *buf_ptr, *buf_end = frame_buf + frame_size; |
| 101 | RTPMuxContext *rtp_ctx = ctx->priv_data; |
| 102 | |
| 103 | /* use the default 90 KHz time stamp */ |
| 104 | rtp_ctx->timestamp = rtp_ctx->cur_timestamp; |
| 105 | |
| 106 | if (rtp_ctx->nal_length_size) |
| 107 | buf_ptr = ff_avc_mp4_find_startcode(frame_buf, buf_end, rtp_ctx->nal_length_size) ? frame_buf : buf_end; |
| 108 | else |
| 109 | buf_ptr = ff_avc_find_startcode(frame_buf, buf_end); |
| 110 | |
| 111 | /* find all NAL units and send them as separate packets */ |
| 112 | while (buf_ptr < buf_end) { |
| 113 | if (rtp_ctx->nal_length_size) { |
| 114 | next_NAL_unit = ff_avc_mp4_find_startcode(buf_ptr, buf_end, rtp_ctx->nal_length_size); |
| 115 | if (!next_NAL_unit) |
| 116 | next_NAL_unit = buf_end; |
| 117 | |
| 118 | buf_ptr += rtp_ctx->nal_length_size; |
| 119 | } else { |
| 120 | while (!*(buf_ptr++)) |
| 121 | ; |
| 122 | next_NAL_unit = ff_avc_find_startcode(buf_ptr, buf_end); |
| 123 | } |
| 124 | /* send the next NAL unit */ |
| 125 | nal_send(ctx, buf_ptr, next_NAL_unit - buf_ptr, next_NAL_unit == buf_end); |
| 126 | |
| 127 | /* jump to the next NAL unit */ |
| 128 | buf_ptr = next_NAL_unit; |
| 129 | } |
| 130 | } |