FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/rtpenc_jpeg.c
Date: 2026-10-19 20:11:44
Exec Total Coverage
Lines: 0 137 0.0%
Functions: 0 1 0.0%
Branches: 0 99 0.0%

Line Branch Exec Source
1 /*
2 * RTP JPEG-compressed video Packetizer, RFC 2435
3 * Copyright (c) 2012 Samuel Pitoiset
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 "libavcodec/bytestream.h"
23 #include "libavcodec/mjpeg.h"
24 #include "libavcodec/jpegtables.h"
25 #include "libavutil/intreadwrite.h"
26 #include "rtpenc.h"
27
28 ✗ void ff_rtp_send_jpeg(AVFormatContext *s1, const uint8_t *buf, int size)
29 {
30 ✗ RTPMuxContext *s = s1->priv_data;
31 ✗ const uint8_t *qtables[4] = { NULL };
32 ✗ int nb_qtables = 0;
33 ✗ uint8_t type = 2; /* initialized non-0/1 value for RTP/JPEG type check*/
34 uint8_t w, h;
35 uint8_t *p;
36 ✗ int off = 0; /* fragment offset of the current JPEG frame */
37 int len;
38 int i;
39 ✗ int default_huffman_tables = 0;
40
41 ✗ s->buf_ptr = s->buf;
42 ✗ s->timestamp = s->cur_timestamp;
43
44 /* convert video pixel dimensions from pixels to blocks */
45 ✗ w = AV_CEIL_RSHIFT(s1->streams[0]->codecpar->width, 3);
46 ✗ h = AV_CEIL_RSHIFT(s1->streams[0]->codecpar->height, 3);
47
48 /* preparse the header for getting some info */
49 ✗ for (i = 0; i < size; i++) {
50 ✗ if (buf[i] != 0xff)
51 ✗ continue;
52
53 ✗ if (size - i < 5 || (buf[i + 1] == SOF0 && size - i < 18)) {
54 ✗ av_log(s1, AV_LOG_ERROR, "Too short JPEG header. Aborted!\n");
55 ✗ return;
56 }
57
58 ✗ if (buf[i + 1] == DQT) {
59 int tables, j;
60 ✗ if (buf[i + 4] & 0xF0)
61 ✗ av_log(s1, AV_LOG_WARNING,
62 "Only 8-bit precision is supported.\n");
63
64 /* a quantization table is 64 bytes long */
65 ✗ tables = AV_RB16(&buf[i + 2]) / 65;
66 ✗ if (i + 5 + tables * 65 > size) {
67 ✗ av_log(s1, AV_LOG_ERROR, "Too short JPEG header. Aborted!\n");
68 ✗ return;
69 }
70 ✗ if (nb_qtables + tables > 4) {
71 ✗ av_log(s1, AV_LOG_ERROR, "Invalid number of quantisation tables\n");
72 ✗ return;
73 }
74
75 ✗ for (j = 0; j < tables; j++)
76 ✗ qtables[nb_qtables + j] = buf + i + 5 + j * 65;
77 ✗ nb_qtables += tables;
78 ✗ } else if (buf[i + 1] == SOF0) {
79 ✗ if (buf[i + 14] != 17 || buf[i + 17] != 17) {
80 ✗ av_log(s1, AV_LOG_ERROR,
81 "Only 1x1 chroma blocks are supported. Aborted!\n");
82 ✗ return;
83 }
84
85 /*
86 * Find out the sampling factor in SOF0.
87 * In SOF0, hsample/vsample is inserted in form of (2<<4) | (type ? 2 : 1).
88 * First 4-bit is hsample while Last 4-bit is vsample.
89 */
90
91 /* Luma channel sampling factor in 4:2:2 chroma subsampling are 2x1 */
92 ✗ if (buf[i + 11] == 33) {
93 ✗ type = 0;
94 /* Luma channel sampling factor in 4:2:0 chroma subsampling are 2x2 */
95 ✗ } else if (buf[i + 11] == 34) {
96 ✗ type = 1;
97 } else {
98 ✗ av_log(s1, AV_LOG_ERROR, "Unsupported pixel format\n");
99 ✗ return;
100 }
101 ✗ } else if (buf[i + 1] == DHT) {
102 ✗ int dht_size = AV_RB16(&buf[i + 2]);
103 ✗ default_huffman_tables |= 1 << 4;
104 ✗ i += 3;
105 ✗ dht_size -= 2;
106 ✗ if (i + dht_size >= size)
107 ✗ continue;
108 ✗ while (dht_size > 0)
109 ✗ switch (buf[i + 1]) {
110 ✗ case 0x00:
111 ✗ if ( dht_size >= 29
112 ✗ && !memcmp(buf + i + 2, ff_mjpeg_bits_dc_luminance + 1, 16)
113 ✗ && !memcmp(buf + i + 18, ff_mjpeg_val_dc, 12)) {
114 ✗ default_huffman_tables |= 1;
115 ✗ i += 29;
116 ✗ dht_size -= 29;
117 } else {
118 ✗ i += dht_size;
119 ✗ dht_size = 0;
120 }
121 ✗ break;
122 ✗ case 0x01:
123 ✗ if ( dht_size >= 29
124 ✗ && !memcmp(buf + i + 2, ff_mjpeg_bits_dc_chrominance + 1, 16)
125 ✗ && !memcmp(buf + i + 18, ff_mjpeg_val_dc, 12)) {
126 ✗ default_huffman_tables |= 1 << 1;
127 ✗ i += 29;
128 ✗ dht_size -= 29;
129 } else {
130 ✗ i += dht_size;
131 ✗ dht_size = 0;
132 }
133 ✗ break;
134 ✗ case 0x10:
135 ✗ if ( dht_size >= 179
136 ✗ && !memcmp(buf + i + 2, ff_mjpeg_bits_ac_luminance + 1, 16)
137 ✗ && !memcmp(buf + i + 18, ff_mjpeg_val_ac_luminance, 162)) {
138 ✗ default_huffman_tables |= 1 << 2;
139 ✗ i += 179;
140 ✗ dht_size -= 179;
141 } else {
142 ✗ i += dht_size;
143 ✗ dht_size = 0;
144 }
145 ✗ break;
146 ✗ case 0x11:
147 ✗ if ( dht_size >= 179
148 ✗ && !memcmp(buf + i + 2, ff_mjpeg_bits_ac_chrominance + 1, 16)
149 ✗ && !memcmp(buf + i + 18, ff_mjpeg_val_ac_chrominance, 162)) {
150 ✗ default_huffman_tables |= 1 << 3;
151 ✗ i += 179;
152 ✗ dht_size -= 179;
153 } else {
154 ✗ i += dht_size;
155 ✗ dht_size = 0;
156 }
157 ✗ break;
158 ✗ default:
159 ✗ i += dht_size;
160 ✗ dht_size = 0;
161 ✗ continue;
162 }
163 ✗ } else if (buf[i + 1] == SOS) {
164 /* SOS is last marker in the header */
165 ✗ i += AV_RB16(&buf[i + 2]) + 2;
166 ✗ if (i > size) {
167 ✗ av_log(s1, AV_LOG_ERROR,
168 "Insufficient data. Aborted!\n");
169 ✗ return;
170 }
171 ✗ break;
172 }
173 }
174
175 /* Check validity of RTP/JPEG type */
176 ✗ if (type != 0 && type != 1) {
177 ✗ av_log(s1, AV_LOG_ERROR,
178 "Invalid RTP/JPEG type\n");
179 ✗ return;
180 }
181
182 ✗ if (default_huffman_tables && default_huffman_tables != 31) {
183 ✗ av_log(s1, AV_LOG_ERROR,
184 "RFC 2435 requires standard Huffman tables for jpeg\n");
185 ✗ return;
186 }
187 ✗ if (nb_qtables && nb_qtables != 2)
188 ✗ av_log(s1, AV_LOG_WARNING,
189 "RFC 2435 suggests two quantization tables, %d provided\n",
190 nb_qtables);
191
192 /* skip JPEG header */
193 ✗ buf += i;
194 ✗ size -= i;
195
196 ✗ for (i = size - 2; i >= 0; i--) {
197 ✗ if (buf[i] == 0xff && buf[i + 1] == EOI) {
198 /* Remove the EOI marker */
199 ✗ size = i;
200 ✗ break;
201 }
202 }
203
204 ✗ p = s->buf_ptr;
205 ✗ while (size > 0) {
206 ✗ int hdr_size = 8;
207
208 ✗ if (off == 0 && nb_qtables)
209 ✗ hdr_size += 4 + 64 * nb_qtables;
210
211 /* payload max in one packet */
212 ✗ len = FFMIN(size, s->max_payload_size - hdr_size);
213
214 /* set main header */
215 ✗ bytestream_put_byte(&p, 0);
216 ✗ bytestream_put_be24(&p, off);
217 ✗ bytestream_put_byte(&p, type);
218 ✗ bytestream_put_byte(&p, 255);
219 ✗ bytestream_put_byte(&p, w);
220 ✗ bytestream_put_byte(&p, h);
221
222 ✗ if (off == 0 && nb_qtables) {
223 /* set quantization tables header */
224 ✗ bytestream_put_byte(&p, 0);
225 ✗ bytestream_put_byte(&p, 0);
226 ✗ bytestream_put_be16(&p, 64 * nb_qtables);
227
228 ✗ for (i = 0; i < nb_qtables; i++)
229 ✗ bytestream_put_buffer(&p, qtables[i], 64);
230 }
231
232 /* copy payload data */
233 ✗ memcpy(p, buf, len);
234
235 /* marker bit is last packet in frame */
236 ✗ ff_rtp_send_data(s1, s->buf, len + hdr_size, size == len);
237
238 ✗ buf += len;
239 ✗ size -= len;
240 ✗ off += len;
241 ✗ p = s->buf;
242 }
243 }
244