]> git.sesse.net Git - ffmpeg/blob - libavformat/rtpenc_hevc.c
avcodec/jacosubdec: add some memory checks
[ffmpeg] / libavformat / rtpenc_hevc.c
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 "avformat.h"
23 #include "avc.h"
24 #include "rtpenc.h"
25
26 #define RTP_HEVC_HEADERS_SIZE 3
27
28 static const uint8_t *avc_mp4_find_startcode(const uint8_t *start, const uint8_t *end, int nal_length_size)
29 {
30     unsigned int res = 0;
31
32     /* is the given data big enough for 1 NAL unit? */
33     if (end - start < nal_length_size)
34         return NULL;
35
36     while (nal_length_size--)
37         res = (res << 8) | *start++;
38
39     if (res > end - start)
40         return NULL;
41
42     return start + res;
43 }
44
45 static void nal_send(AVFormatContext *ctx, const uint8_t *buf, int len, int last_packet_of_frame)
46 {
47     RTPMuxContext *rtp_ctx = ctx->priv_data;
48     int rtp_payload_size   = rtp_ctx->max_payload_size - RTP_HEVC_HEADERS_SIZE;
49     int nal_type           = (buf[0] >> 1) & 0x3F;
50
51     /* send it as one single NAL unit? */
52     if (len <= rtp_ctx->max_payload_size) {
53         /* use the original NAL unit buffer and transmit it as RTP payload */
54         ff_rtp_send_data(ctx, buf, len, last_packet_of_frame);
55     } else {
56         /*
57           create the HEVC payload header and transmit the buffer as fragmentation units (FU)
58
59              0                   1
60              0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
61             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62             |F|   Type    |  LayerId  | TID |
63             +-------------+-----------------+
64
65                F       = 0
66                Type    = 49 (fragmentation unit (FU))
67                LayerId = 0
68                TID     = 1
69          */
70         rtp_ctx->buf[0] = 49 << 1;
71         rtp_ctx->buf[1] = 1;
72
73         /*
74               create the FU header
75
76               0 1 2 3 4 5 6 7
77              +-+-+-+-+-+-+-+-+
78              |S|E|  FuType   |
79              +---------------+
80
81                 S       = variable
82                 E       = variable
83                 FuType  = NAL unit type
84          */
85         rtp_ctx->buf[2]  = nal_type;
86         /* set the S bit: mark as start fragment */
87         rtp_ctx->buf[2] |= 1 << 7;
88
89         /* pass the original NAL header */
90         buf += 2;
91         len -= 2;
92
93         while (len + RTP_HEVC_HEADERS_SIZE > rtp_ctx->max_payload_size) {
94             /* complete and send current RTP packet */
95             memcpy(&rtp_ctx->buf[RTP_HEVC_HEADERS_SIZE], buf, rtp_payload_size);
96             ff_rtp_send_data(ctx, rtp_ctx->buf, rtp_ctx->max_payload_size, 0);
97
98             buf += rtp_payload_size;
99             len -= rtp_payload_size;
100
101             /* reset the S bit */
102             rtp_ctx->buf[2] &= ~(1 << 7);
103         }
104
105         /* set the E bit: mark as last fragment */
106         rtp_ctx->buf[2] |= 1 << 6;
107
108         /* complete and send last RTP packet */
109         memcpy(&rtp_ctx->buf[RTP_HEVC_HEADERS_SIZE], buf, len);
110         ff_rtp_send_data(ctx, rtp_ctx->buf, len + 2, last_packet_of_frame);
111     }
112 }
113
114 void ff_rtp_send_hevc(AVFormatContext *ctx, const uint8_t *frame_buf, int frame_size)
115 {
116     const uint8_t *next_NAL_unit;
117     const uint8_t *buf_ptr, *buf_end = frame_buf + frame_size;
118     RTPMuxContext *rtp_ctx = ctx->priv_data;
119
120     /* use the default 90 KHz time stamp */
121     rtp_ctx->timestamp = rtp_ctx->cur_timestamp;
122
123     if (rtp_ctx->nal_length_size)
124         buf_ptr = avc_mp4_find_startcode(frame_buf, buf_end, rtp_ctx->nal_length_size) ? frame_buf : buf_end;
125     else
126         buf_ptr = ff_avc_find_startcode(frame_buf, buf_end);
127
128     /* find all NAL units and send them as separate packets */
129     while (buf_ptr < buf_end) {
130         if (rtp_ctx->nal_length_size) {
131             next_NAL_unit = avc_mp4_find_startcode(buf_ptr, buf_end, rtp_ctx->nal_length_size);
132             if (!next_NAL_unit)
133                 next_NAL_unit = buf_end;
134
135             buf_ptr += rtp_ctx->nal_length_size;
136         } else {
137             while (!*(buf_ptr++)) ;
138             next_NAL_unit = ff_avc_find_startcode(buf_ptr, buf_end);
139         }
140         /* send the next NAL unit */
141         nal_send(ctx, buf_ptr, next_NAL_unit - buf_ptr, next_NAL_unit == buf_end);
142
143         /* jump to the next NAL unit */
144         buf_ptr = next_NAL_unit;
145     }
146 }