1 /*
2  * RTP Packetization of RAW video (RFC4175)
3  * Copyright (c) 2021 Limin Wang
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 #include "avformat.h"
22 #include "rtpenc.h"
23 
ff_rtp_send_raw_rfc4175(AVFormatContext *s1, const uint8_t *buf, int size, int interlaced, int field)24 void ff_rtp_send_raw_rfc4175(AVFormatContext *s1, const uint8_t *buf, int size, int interlaced, int field)
25 {
26     RTPMuxContext *s = s1->priv_data;
27     int width = s1->streams[0]->codecpar->width;
28     int height = s1->streams[0]->codecpar->height;
29     int xinc, yinc, pgroup;
30     int i = 0;
31     int offset = 0;
32 
33     s->timestamp = s->cur_timestamp;
34     switch (s1->streams[0]->codecpar->format) {
35         case AV_PIX_FMT_UYVY422:
36             xinc = 2;
37             yinc = 1 << interlaced;
38             pgroup = 4;
39             break;
40         case AV_PIX_FMT_YUV422P10:
41             xinc = 2;
42             yinc = 1 << interlaced;
43             pgroup = 5;
44             break;
45         case AV_PIX_FMT_YUV420P:
46             xinc = 4;
47             yinc = 1 << interlaced;
48             pgroup = 6;
49             break;
50         case AV_PIX_FMT_RGB24:
51             xinc = 1;
52             yinc = 1 << interlaced;
53             pgroup = 3;
54             break;
55         case AV_PIX_FMT_BGR24:
56             xinc = 1;
57             yinc = 1 << interlaced;
58             pgroup = 3;
59             break;
60         default:
61             return;
62     }
63 
64     while (i < height) {
65         int left = s->max_payload_size;
66         uint8_t *dest = s->buf;
67         uint8_t *headers;
68         const int head_size = 6;
69         int next_line;
70         int length, cont, pixels;
71 
72         /* Extended Sequence Number */
73         *dest++ = 0;
74         *dest++ = 0;
75         left   -= 2;
76 
77         headers = dest;
78         do {
79             int l_line;
80 
81             pixels = width - offset;
82             length = (pixels * pgroup) / xinc;
83 
84             left -= head_size;
85             if (left >= length) {
86                 next_line = 1;
87             } else {
88                 pixels = (left / pgroup) * xinc;
89                 length = (pixels * pgroup) / xinc;
90                 next_line = 0;
91             }
92             left -= length;
93 
94             /* Length */
95             *dest++ = (length >> 8) & 0xff;
96             *dest++ = length & 0xff;
97 
98             /* Line No */
99             l_line = i >> interlaced;
100             *dest++ = ((l_line >> 8) & 0x7f) | ((field << 7) & 0x80);
101             *dest++ = l_line & 0xff;
102             if (next_line) i += yinc;
103 
104             cont = (left > (head_size + pgroup) && i < height) ? 0x80 : 0x00;
105             /* Offset and Continuation marker */
106             *dest++ = ((offset >> 8) & 0x7f) | cont;
107             *dest++ = offset & 0xff;
108 
109             if (next_line)
110                 offset  = 0;
111             else
112                 offset += pixels;
113         } while (cont);
114 
115         do {
116             int l_field;
117             int l_line;
118             int l_off;
119             int copy_offset;
120 
121             length    = (headers[0] << 8) | headers[1];
122             l_field   = (headers[2] & 0x80) >> 7;
123             l_line    = ((headers[2] & 0x7f) << 8) | headers[3];
124             l_off     = ((headers[4] & 0x7f) << 8) | headers[5];
125             cont      = headers[4] & 0x80;
126             headers  += head_size;
127 
128             if (interlaced)
129                 l_line = 2 * l_line + l_field;
130             copy_offset = (l_line * width + l_off) * pgroup / xinc;
131             if (copy_offset + length > size)
132                 break;
133             memcpy (dest, buf + copy_offset, length);
134             dest += length;
135         } while (cont);
136 
137         ff_rtp_send_data (s1, s->buf, s->max_payload_size - left, i >= height);
138     }
139 }
140