/* * RTP packetizer for HEVC/H.265 payload format (draft version 6) * Copyright (c) 2014 Thomas Volkert * * This file is part of Libav. * * Libav is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * Libav is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avc.h" #include "avformat.h" #include "rtpenc.h" #define RTP_HEVC_HEADERS_SIZE 3 static void nal_send(AVFormatContext *ctx, const uint8_t *buf, int len, int last_packet_of_frame) { RTPMuxContext *rtp_ctx = ctx->priv_data; int rtp_payload_size = rtp_ctx->max_payload_size - RTP_HEVC_HEADERS_SIZE; int nal_type = (buf[0] >> 1) & 0x3F; /* send it as one single NAL unit? */ if (len <= rtp_ctx->max_payload_size) { /* use the original NAL unit buffer and transmit it as RTP payload */ ff_rtp_send_data(ctx, buf, len, last_packet_of_frame); } else { /* create the HEVC payload header and transmit the buffer as fragmentation units (FU) 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |F| Type | LayerId | TID | +-------------+-----------------+ F = 0 Type = 49 (fragmentation unit (FU)) LayerId = 0 TID = 1 */ rtp_ctx->buf[0] = 49 << 1; rtp_ctx->buf[1] = 1; /* create the FU header 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |S|E| FuType | +---------------+ S = variable E = variable FuType = NAL unit type */ rtp_ctx->buf[2] = nal_type; /* set the S bit: mark as start fragment */ rtp_ctx->buf[2] |= 1 << 7; /* pass the original NAL header */ buf += 2; len -= 2; while (len > rtp_payload_size) { /* complete and send current RTP packet */ memcpy(&rtp_ctx->buf[RTP_HEVC_HEADERS_SIZE], buf, rtp_payload_size); ff_rtp_send_data(ctx, rtp_ctx->buf, rtp_ctx->max_payload_size, 0); buf += rtp_payload_size; len -= rtp_payload_size; /* reset the S bit */ rtp_ctx->buf[2] &= ~(1 << 7); } /* set the E bit: mark as last fragment */ rtp_ctx->buf[2] |= 1 << 6; /* complete and send last RTP packet */ memcpy(&rtp_ctx->buf[RTP_HEVC_HEADERS_SIZE], buf, len); ff_rtp_send_data(ctx, rtp_ctx->buf, len + 2, last_packet_of_frame); } } void ff_rtp_send_hevc(AVFormatContext *ctx, const uint8_t *frame_buf, int frame_size) { const uint8_t *next_NAL_unit; const uint8_t *buf_ptr, *buf_end = frame_buf + frame_size; RTPMuxContext *rtp_ctx = ctx->priv_data; /* use the default 90 KHz time stamp */ rtp_ctx->timestamp = rtp_ctx->cur_timestamp; if (rtp_ctx->nal_length_size) buf_ptr = ff_avc_mp4_find_startcode(frame_buf, buf_end, rtp_ctx->nal_length_size) ? frame_buf : buf_end; else buf_ptr = ff_avc_find_startcode(frame_buf, buf_end); /* find all NAL units and send them as separate packets */ while (buf_ptr < buf_end) { if (rtp_ctx->nal_length_size) { next_NAL_unit = ff_avc_mp4_find_startcode(buf_ptr, buf_end, rtp_ctx->nal_length_size); if (!next_NAL_unit) next_NAL_unit = buf_end; buf_ptr += rtp_ctx->nal_length_size; } else { while (!*(buf_ptr++)) ; next_NAL_unit = ff_avc_find_startcode(buf_ptr, buf_end); } /* send the next NAL unit */ nal_send(ctx, buf_ptr, next_NAL_unit - buf_ptr, next_NAL_unit == buf_end); /* jump to the next NAL unit */ buf_ptr = next_NAL_unit; } }