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