| @@ -408,6 +408,73 @@ static int get_siz(Jpeg2000DecoderContext *s) · 407 unmodified lines |
| 408 | 408 | s->avctx->bits_per_raw_sample = s->precision; |
| 409 | 409 | return 0; |
| 410 | 410 | } |
| 411 | +/* get extended capabilities (CAP) marker segment */ |
| 412 | +static int get_cap(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) |
| 413 | +{ |
| 414 | + uint32_t Pcap; |
| 415 | + uint16_t Ccap_i[32] = { 0 }; |
| 416 | + uint16_t Ccap_15; |
| 417 | + uint8_t P; |
| 418 | + |
| 419 | + if (bytestream2_get_bytes_left(&s->g) < 6) { |
| 420 | + av_log(s->avctx, AV_LOG_ERROR, "Underflow while parsing the CAP marker\n"); |
| 421 | + return AVERROR_INVALIDDATA; |
| 422 | + } |
| 423 | + |
| 424 | + Pcap = bytestream2_get_be32u(&s->g); |
| 425 | + s->isHT = (Pcap >> (31 - (15 - 1))) & 1; |
| 426 | + for (int i = 0; i < 32; i++) { |
| 427 | + if ((Pcap >> (31 - i)) & 1) |
| 428 | + Ccap_i[i] = bytestream2_get_be16u(&s->g); |
| 429 | + } |
| 430 | + Ccap_15 = Ccap_i[14]; |
| 431 | + if (s->isHT == 1) { |
| 432 | + av_log(s->avctx, AV_LOG_INFO, "This codestream uses the HT block coder.\n"); |
| 433 | + // Bits 14-15 |
| 434 | + switch ((Ccap_15 >> 14) & 0x3) { |
| 435 | + case 0x3: |
| 436 | + s->Ccap15_b14_15 = HTJ2K_MIXED; |
| 437 | + break; |
| 438 | + case 0x1: |
| 439 | + s->Ccap15_b14_15 = HTJ2K_HTDECLARED; |
| 440 | + break; |
| 441 | + case 0x0: |
| 442 | + s->Ccap15_b14_15 = HTJ2K_HTONLY; |
| 443 | + break; |
| 444 | + default: |
| 445 | + av_log(s->avctx, AV_LOG_ERROR, "Unknown CCap value.\n"); |
| 446 | + return AVERROR(EINVAL); |
| 447 | + break; |
| 448 | + } |
| 449 | + // Bit 13 |
| 450 | + if ((Ccap_15 >> 13) & 1) { |
| 451 | + av_log(s->avctx, AV_LOG_ERROR, "MULTIHT set is not supported.\n"); |
| 452 | + return AVERROR_PATCHWELCOME; |
| 453 | + } |
| 454 | + // Bit 12 |
| 455 | + s->Ccap15_b12 = (Ccap_15 >> 12) & 1; |
| 456 | + // Bit 11 |
| 457 | + s->Ccap15_b11 = (Ccap_15 >> 11) & 1; |
| 458 | + // Bit 5 |
| 459 | + s->Ccap15_b05 = (Ccap_15 >> 5) & 1; |
| 460 | + // Bit 0-4 |
| 461 | + P = Ccap_15 & 0x1F; |
| 462 | + if (!P) |
| 463 | + s->HT_B = 8; |
| 464 | + else if (P < 20) |
| 465 | + s->HT_B = P + 8; |
| 466 | + else if (P < 31) |
| 467 | + s->HT_B = 4 * (P - 19) + 27; |
| 468 | + else |
| 469 | + s->HT_B = 74; |
| 470 | + |
| 471 | + if (s->HT_B > 31) { |
| 472 | + av_log(s->avctx, AV_LOG_ERROR, "Codestream exceeds available precision (B > 31).\n"); |
| 473 | + return AVERROR_PATCHWELCOME; |
| 474 | + } |
| 475 | + } |
| 476 | + return 0; |
| 477 | +} |
| 411 | 478 | |
| 412 | 479 | /* get common part for COD and COC segments */ |
| 413 | 480 | static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) |
| @@ -802,6 +869,15 @@ static int read_crg(Jpeg2000DecoderContext *s, int n) · 388 unmodified lines |
| 802 | 869 | bytestream2_skip(&s->g, n - 2); |
| 803 | 870 | return 0; |
| 804 | 871 | } |
| 872 | + |
| 873 | +static int read_cpf(Jpeg2000DecoderContext *s, int n) |
| 874 | +{ |
| 875 | + if (bytestream2_get_bytes_left(&s->g) < (n - 2)) |
| 876 | + return AVERROR_INVALIDDATA; |
| 877 | + bytestream2_skip(&s->g, n - 2); |
| 878 | + return 0; |
| 879 | +} |
| 880 | + |
| 805 | 881 | /* Tile-part lengths: see ISO 15444-1:2002, section A.7.1 |
| 806 | 882 | * Used to know the number of tile parts and lengths. |
| 807 | 883 | * There may be multiple TLMs in the header. |
| @@ -965,6 +1041,14 @@ static int init_tile(Jpeg2000DecoderContext *s, int tileno) · 157 unmodified lines |
| 965 | 1041 | comp->roi_shift = s->roi_shift[compno]; |
| 966 | 1042 | if (!codsty->init) |
| 967 | 1043 | return AVERROR_INVALIDDATA; |
| 1044 | + if (s->isHT && (!s->Ccap15_b05) && (!codsty->transform)) { |
| 1045 | + av_log(s->avctx, AV_LOG_ERROR, "Transformation = 0 (lossy DWT) is found in HTREV HT set\n"); |
| 1046 | + return AVERROR_INVALIDDATA; |
| 1047 | + } |
| 1048 | + if (s->isHT && s->Ccap15_b14_15 != (codsty->cblk_style >> 6) && s->Ccap15_b14_15 != HTJ2K_HTONLY) { |
| 1049 | + av_log(s->avctx, AV_LOG_ERROR, "SPcod/SPcoc value does not match bit 14-15 values of Ccap15\n"); |
| 1050 | + return AVERROR_INVALIDDATA; |
| 1051 | + } |
| 968 | 1052 | if (ret = ff_jpeg2000_init_component(comp, codsty, qntsty, |
| 969 | 1053 | s->cbps[compno], s->cdx[compno], |
| 970 | 1054 | s->cdy[compno], s->avctx)) |
| @@ -2187,22 +2271,63 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) · 1216 unmodified lines |
| 2187 | 2271 | if (!s->tile) |
| 2188 | 2272 | s->numXtiles = s->numYtiles = 0; |
| 2189 | 2273 | break; |
| 2274 | + case JPEG2000_CAP: |
| 2275 | + if (!s->ncomponents) { |
| 2276 | + av_log(s->avctx, AV_LOG_ERROR, "CAP marker segment shall come after SIZ\n"); |
| 2277 | + return AVERROR_INVALIDDATA; |
| 2278 | + } |
| 2279 | + ret = get_cap(s, codsty); |
| 2280 | + break; |
| 2190 | 2281 | case JPEG2000_COC: |
| 2282 | + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { |
| 2283 | + av_log(s->avctx, AV_LOG_ERROR, |
| 2284 | + "COC marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); |
| 2285 | + return AVERROR_INVALIDDATA; |
| 2286 | + } |
| 2191 | 2287 | ret = get_coc(s, codsty, properties); |
| 2192 | 2288 | break; |
| 2193 | 2289 | case JPEG2000_COD: |
| 2290 | + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { |
| 2291 | + av_log(s->avctx, AV_LOG_ERROR, |
| 2292 | + "COD marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); |
| 2293 | + return AVERROR_INVALIDDATA; |
| 2294 | + } |
| 2194 | 2295 | ret = get_cod(s, codsty, properties); |
| 2195 | 2296 | break; |
| 2196 | 2297 | case JPEG2000_RGN: |
| 2298 | + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { |
| 2299 | + av_log(s->avctx, AV_LOG_ERROR, |
| 2300 | + "RGN marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); |
| 2301 | + return AVERROR_INVALIDDATA; |
| 2302 | + } |
| 2197 | 2303 | ret = get_rgn(s, len); |
| 2304 | + if ((!s->Ccap15_b12) && s->isHT) { |
| 2305 | + av_log(s->avctx, AV_LOG_ERROR, "RGN marker found but the codestream belongs to the RGNFREE set\n"); |
| 2306 | + return AVERROR_INVALIDDATA; |
| 2307 | + } |
| 2198 | 2308 | break; |
| 2199 | 2309 | case JPEG2000_QCC: |
| 2310 | + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { |
| 2311 | + av_log(s->avctx, AV_LOG_ERROR, |
| 2312 | + "QCC marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); |
| 2313 | + return AVERROR_INVALIDDATA; |
| 2314 | + } |
| 2200 | 2315 | ret = get_qcc(s, len, qntsty, properties); |
| 2201 | 2316 | break; |
| 2202 | 2317 | case JPEG2000_QCD: |
| 2318 | + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { |
| 2319 | + av_log(s->avctx, AV_LOG_ERROR, |
| 2320 | + "QCD marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); |
| 2321 | + return AVERROR_INVALIDDATA; |
| 2322 | + } |
| 2203 | 2323 | ret = get_qcd(s, len, qntsty, properties); |
| 2204 | 2324 | break; |
| 2205 | 2325 | case JPEG2000_POC: |
| 2326 | + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { |
| 2327 | + av_log(s->avctx, AV_LOG_ERROR, |
| 2328 | + "POC marker found in a tile header but the codestream belongs to the HOMOGENEOUS set\n"); |
| 2329 | + return AVERROR_INVALIDDATA; |
| 2330 | + } |
| 2206 | 2331 | ret = get_poc(s, len, poc); |
| 2207 | 2332 | break; |
| 2208 | 2333 | case JPEG2000_SOT: |
| @@ -2252,9 +2377,16 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) · 43 unmodified lines |
| 2252 | 2377 | "Cannot have both PPT and PPM marker.\n"); |
| 2253 | 2378 | return AVERROR_INVALIDDATA; |
| 2254 | 2379 | } |
| 2255 | | − |
| 2380 | + if ((!s->Ccap15_b11) && s->isHT) { |
| 2381 | + av_log(s->avctx, AV_LOG_ERROR, "PPT marker found but the codestream belongs to the HOMOGENEOUS set\n"); |
| 2382 | + return AVERROR_INVALIDDATA; |
| 2383 | + } |
| 2256 | 2384 | ret = get_ppt(s, len); |
| 2257 | 2385 | break; |
| 2386 | + case JPEG2000_CPF: |
| 2387 | + // Corresponding profile marker |
| 2388 | + ret = read_cpf(s, len); |
| 2389 | + break; |
| 2258 | 2390 | default: |
| 2259 | 2391 | av_log(s->avctx, AV_LOG_ERROR, |
| 2260 | 2392 | "unsupported marker 0x%.4"PRIX16" at pos 0x%X\n", |