diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c
index 7236e9b7bb..fbc025449a 100644
--- a/libavcodec/jpeg2000dec.c
+++ b/libavcodec/jpeg2000dec.c
@@ -1169,179 +1169,6 @@ static int jpeg2000_decode_packet_data(Jpeg2000DecoderContext *s, Jpeg2000Tile *
     return 0;
 }
 
-static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, int *tp_index,
-                                  Jpeg2000CodingStyle *codsty,
-                                  Jpeg2000ResLevel *rlevel, int precno,
-                                  int layno, uint8_t *expn, int numgbits)
-{
-    int bandno, cblkno, ret, nb_code_blocks;
-    int cwsno;
-
-    if (layno < rlevel->band[0].prec[precno].decoded_layers)
-        return 0;
-    rlevel->band[0].prec[precno].decoded_layers = layno + 1;
-
-    if (bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8) {
-        if (*tp_index < FF_ARRAY_ELEMS(tile->tile_part) - 1) {
-            s->g = tile->tile_part[++(*tp_index)].tpg;
-        }
-    }
-
-    if (bytestream2_peek_be32(&s->g) == JPEG2000_SOP_FIXED_BYTES)
-        bytestream2_skip(&s->g, JPEG2000_SOP_BYTE_LENGTH);
-
-    if (!(ret = get_bits(s, 1))) {
-        jpeg2000_flush(s);
-        return 0;
-    } else if (ret < 0)
-        return ret;
-
-    for (bandno = 0; bandno < rlevel->nbands; bandno++) {
-        Jpeg2000Band *band = rlevel->band + bandno;
-        Jpeg2000Prec *prec = band->prec + precno;
-
-        if (band->coord[0][0] == band->coord[0][1] ||
-            band->coord[1][0] == band->coord[1][1])
-            continue;
-        nb_code_blocks =  prec->nb_codeblocks_height *
-                          prec->nb_codeblocks_width;
-        for (cblkno = 0; cblkno < nb_code_blocks; cblkno++) {
-            Jpeg2000Cblk *cblk = prec->cblk + cblkno;
-            int incl, newpasses, llen;
-            void *tmp;
-
-            if (cblk->npasses)
-                incl = get_bits(s, 1);
-            else
-                incl = tag_tree_decode(s, prec->cblkincl + cblkno, layno + 1) == layno;
-            if (!incl)
-                continue;
-            else if (incl < 0)
-                return incl;
-
-            if (!cblk->npasses) {
-                int v = expn[bandno] + numgbits - 1 -
-                        tag_tree_decode(s, prec->zerobits + cblkno, 100);
-                if (v < 0 || v > 30) {
-                    av_log(s->avctx, AV_LOG_ERROR,
-                           "nonzerobits %d invalid or unsupported\n", v);
-                    return AVERROR_INVALIDDATA;
-                }
-                cblk->nonzerobits = v;
-            }
-            if ((newpasses = getnpasses(s)) < 0)
-                return newpasses;
-            av_assert2(newpasses > 0);
-            if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) {
-                avpriv_request_sample(s->avctx, "Too many passes");
-                return AVERROR_PATCHWELCOME;
-            }
-            if ((llen = getlblockinc(s)) < 0)
-                return llen;
-            if (cblk->lblock + llen + av_log2(newpasses) > 16) {
-                avpriv_request_sample(s->avctx,
-                                      "Block with length beyond 16 bits");
-                return AVERROR_PATCHWELCOME;
-            }
-
-            cblk->lblock += llen;
-
-            cblk->nb_lengthinc = 0;
-            cblk->nb_terminationsinc = 0;
-            av_free(cblk->lengthinc);
-            cblk->lengthinc  = av_mallocz_array(newpasses    , sizeof(*cblk->lengthinc));
-            if (!cblk->lengthinc)
-                return AVERROR(ENOMEM);
-            tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1, sizeof(*cblk->data_start));
-            if (!tmp)
-                return AVERROR(ENOMEM);
-            cblk->data_start = tmp;
-            do {
-                int newpasses1 = 0;
-
-                while (newpasses1 < newpasses) {
-                    newpasses1 ++;
-                    if (needs_termination(codsty->cblk_style, cblk->npasses + newpasses1 - 1)) {
-                        cblk->nb_terminationsinc ++;
-                        break;
-                    }
-                }
-
-                if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0)
-                    return ret;
-                if (ret > cblk->data_allocated) {
-                    size_t new_size = FFMAX(2*cblk->data_allocated, ret);
-                    void *new = av_realloc(cblk->data, new_size);
-                    if (new) {
-                        cblk->data = new;
-                        cblk->data_allocated = new_size;
-                    }
-                }
-                if (ret > cblk->data_allocated) {
-                    avpriv_request_sample(s->avctx,
-                                        "Block with lengthinc greater than %"SIZE_SPECIFIER"",
-                                        cblk->data_allocated);
-                    return AVERROR_PATCHWELCOME;
-                }
-                cblk->lengthinc[cblk->nb_lengthinc++] = ret;
-                cblk->npasses  += newpasses1;
-                newpasses -= newpasses1;
-            } while(newpasses);
-        }
-    }
-    jpeg2000_flush(s);
-
-    if (codsty->csty & JPEG2000_CSTY_EPH) {
-        if (bytestream2_peek_be16(&s->g) == JPEG2000_EPH)
-            bytestream2_skip(&s->g, 2);
-        else
-            av_log(s->avctx, AV_LOG_ERROR, "EPH marker not found. instead %X\n", bytestream2_peek_be32(&s->g));
-    }
-
-    for (bandno = 0; bandno < rlevel->nbands; bandno++) {
-        Jpeg2000Band *band = rlevel->band + bandno;
-        Jpeg2000Prec *prec = band->prec + precno;
-
-        nb_code_blocks = prec->nb_codeblocks_height * prec->nb_codeblocks_width;
-        for (cblkno = 0; cblkno < nb_code_blocks; cblkno++) {
-            Jpeg2000Cblk *cblk = prec->cblk + cblkno;
-            if (!cblk->nb_terminationsinc && !cblk->lengthinc)
-                continue;
-            for (cwsno = 0; cwsno < cblk->nb_lengthinc; cwsno ++) {
-                if (cblk->data_allocated < cblk->length + cblk->lengthinc[cwsno] + 4) {
-                    size_t new_size = FFMAX(2*cblk->data_allocated, cblk->length + cblk->lengthinc[cwsno] + 4);
-                    void *new = av_realloc(cblk->data, new_size);
-                    if (new) {
-                        cblk->data = new;
-                        cblk->data_allocated = new_size;
-                    }
-                }
-                if (   bytestream2_get_bytes_left(&s->g) < cblk->lengthinc[cwsno]
-                    || cblk->data_allocated < cblk->length + cblk->lengthinc[cwsno] + 4
-                ) {
-                    av_log(s->avctx, AV_LOG_ERROR,
-                        "Block length %"PRIu16" or lengthinc %d is too large, left %d\n",
-                        cblk->length, cblk->lengthinc[cwsno], bytestream2_get_bytes_left(&s->g));
-                    return AVERROR_INVALIDDATA;
-                }
-
-                bytestream2_get_bufferu(&s->g, cblk->data + cblk->length, cblk->lengthinc[cwsno]);
-                cblk->length   += cblk->lengthinc[cwsno];
-                cblk->lengthinc[cwsno] = 0;
-                if (cblk->nb_terminationsinc) {
-                    cblk->nb_terminationsinc--;
-                    cblk->nb_terminations++;
-                    cblk->data[cblk->length++] = 0xFF;
-                    cblk->data[cblk->length++] = 0xFF;
-                    cblk->data_start[cblk->nb_terminations] = cblk->length;
-                }
-            }
-            av_freep(&cblk->lengthinc);
-        }
-    }
-    return 0;
-}
-
 static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
                                              int RSpoc, int CSpoc,
                                              int LYEpoc, int REpoc, int CEpoc,
@@ -1366,13 +1193,25 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2
                         Jpeg2000ResLevel *rlevel = tile->comp[compno].reslevel +
                                                 reslevelno;
                         ok_reslevel = 1;
-                        for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++)
-                            if ((ret = jpeg2000_decode_packet(s, tile, tp_index,
+                        for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++) {
+                            int process_data = 1;
+                            if ((ret = jpeg2000_decode_packet_header(s, tile, tp_index,
+                                                              codsty, rlevel,
+                                                              precno, layno,
+                                                              qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+                                                              qntsty->nguardbits, &process_data)) < 0)
+                                return ret;
+
+                            if (!process_data)
+                                continue;
+
+                            if ((ret = jpeg2000_decode_packet_data(s, tile, tp_index,
                                                               codsty, rlevel,
                                                               precno, layno,
                                                               qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
                                                               qntsty->nguardbits)) < 0)
                                 return ret;
+                        }
                     }
                 }
             }
@@ -1392,13 +1231,25 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2
                         Jpeg2000ResLevel *rlevel = tile->comp[compno].reslevel +
                                                 reslevelno;
                         ok_reslevel = 1;
-                        for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++)
-                            if ((ret = jpeg2000_decode_packet(s, tile, tp_index,
+                        for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++) {
+                            int process_data = 1;
+                            if ((ret = jpeg2000_decode_packet_header(s, tile, tp_index,
+                                                              codsty, rlevel,
+                                                              precno, layno,
+                                                              qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+                                                              qntsty->nguardbits, &process_data)) < 0)
+                                return ret;
+
+                            if (!process_data)
+                                continue;
+
+                            if ((ret = jpeg2000_decode_packet_data(s, tile, tp_index,
                                                               codsty, rlevel,
                                                               precno, layno,
                                                               qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
                                                               qntsty->nguardbits)) < 0)
                                 return ret;
+                        }
                     }
                 }
             }
@@ -1460,7 +1311,19 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2
                         }
 
                         for (layno = 0; layno < LYEpoc; layno++) {
-                            if ((ret = jpeg2000_decode_packet(s, tile, tp_index, codsty, rlevel,
+                            int process_data = 1;
+                            if ((ret = jpeg2000_decode_packet_header(s, tile, tp_index,
+                                                              codsty, rlevel,
+                                                              precno, layno,
+                                                              qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+                                                              qntsty->nguardbits, &process_data)) < 0)
+                                return ret;
+
+                            if (!process_data)
+                                continue;
+
+                            if ((ret = jpeg2000_decode_packet_data(s, tile, tp_index,
+                                                              codsty, rlevel,
                                                               precno, layno,
                                                               qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
                                                               qntsty->nguardbits)) < 0)
@@ -1530,14 +1393,25 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2
                             continue;
                         }
 
-                            for (layno = 0; layno < LYEpoc; layno++) {
-                                if ((ret = jpeg2000_decode_packet(s, tile, tp_index,
-                                                                codsty, rlevel,
-                                                                precno, layno,
-                                                                qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
-                                                                qntsty->nguardbits)) < 0)
-                                    return ret;
-                            }
+                        for (layno = 0; layno < LYEpoc; layno++) {
+                            int process_data = 1;
+                            if ((ret = jpeg2000_decode_packet_header(s, tile, tp_index,
+                                                              codsty, rlevel,
+                                                              precno, layno,
+                                                              qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+                                                              qntsty->nguardbits, &process_data)) < 0)
+                                return ret;
+
+                            if (!process_data)
+                                continue;
+
+                            if ((ret = jpeg2000_decode_packet_data(s, tile, tp_index,
+                                                              codsty, rlevel,
+                                                              precno, layno,
+                                                              qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+                                                              qntsty->nguardbits)) < 0)
+                                return ret;
+                        }
                     }
                 }
             }
@@ -1601,7 +1475,19 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2
                         }
 
                         for (layno = 0; layno < LYEpoc; layno++) {
-                            if ((ret = jpeg2000_decode_packet(s, tile, tp_index, codsty, rlevel,
+                            int process_data = 1;
+                            if ((ret = jpeg2000_decode_packet_header(s, tile, tp_index,
+                                                              codsty, rlevel,
+                                                              precno, layno,
+                                                              qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+                                                              qntsty->nguardbits, &process_data)) < 0)
+                                return ret;
+
+                            if (!process_data)
+                                continue;
+
+                            if ((ret = jpeg2000_decode_packet_data(s, tile, tp_index,
+                                                              codsty, rlevel,
                                                               precno, layno,
                                                               qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
                                                               qntsty->nguardbits)) < 0)
@@ -2171,6 +2057,11 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
                 av_log(s->avctx, AV_LOG_ERROR, "Invalid tpend\n");
                 return AVERROR_INVALIDDATA;
             }
+
+            if (tile->has_ppt && tile->tp_idx == 0) {
+                bytestream2_init(&tile->packed_headers_stream, tile->packed_headers, tile->packed_headers_size);
+            }
+
             bytestream2_init(&tp->tpg, s->g.buffer, tp->tp_end - s->g.buffer);
             bytestream2_skip(&s->g, tp->tp_end - s->g.buffer);
 
@@ -2233,6 +2124,10 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
             // Packet length, tile-part header
             ret = get_plt(s, len);
             break;
+        case JPEG2000_PPT:
+            // Packed headers, tile-part header
+            ret = get_ppt(s, len);
+            break;
         default:
             av_log(s->avctx, AV_LOG_ERROR,
                    "unsupported marker 0x%.4"PRIX16" at pos 0x%X\n",
@@ -2262,7 +2157,6 @@ static int jpeg2000_read_bitstream_packets(Jpeg2000DecoderContext *s)
         if ((ret = init_tile(s, tileno)) < 0)
             return ret;
 
-        s->g = tile->tile_part[0].tpg;
         if ((ret = jpeg2000_decode_packets(s, tile)) < 0)
             return ret;
     }
