diff --git a/libavcodec/hap.h b/libavcodec/hap.h
index 00c3dbb32d..7e065e4838 100644
--- a/libavcodec/hap.h
+++ b/libavcodec/hap.h
@@ -72,23 +72,18 @@ typedef struct HapContext {
     HapChunk *chunks;
     int *chunk_results;      /* Results from threaded operations */
 
-    int tex_rat;             /* Compression ratio */
-    int tex_rat2;             /* Compression ratio of the second texture */
-    const uint8_t *tex_data; /* Compressed texture */
     uint8_t *tex_buf;        /* Buffer for compressed texture */
     size_t tex_size;         /* Size of the compressed texture */
 
     size_t max_snappy;       /* Maximum compressed size for snappy buffer */
 
-    int slice_count;         /* Number of slices for threaded operations */
-
     int texture_count;      /* 2 for HAQA, 1 for other version */
     int texture_section_size; /* size of the part of the texture section (for HAPQA) */
-    int uncompress_pix_size; /* nb of byte / pixel for the target picture */
 
-    /* Pointer to the selected compress or decompress function */
+    /* Pointer to the selected compress function (encoder only) */
     int (*tex_fun)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block);
-    int (*tex_fun2)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block);
+
+    TextureDSPThreadContext dec[2];
 } HapContext;
 
 /*
diff --git a/libavcodec/hapdec.c b/libavcodec/hapdec.c
index 4a7ac15a8e..685d65d8b8 100644
--- a/libavcodec/hapdec.c
+++ b/libavcodec/hapdec.c
@@ -247,60 +247,6 @@ static int decompress_chunks_thread(AVCodecContext *avctx, void *arg,
     return 0;
 }
 
-static int decompress_texture_thread_internal(AVCodecContext *avctx, void *arg,
-                                              int slice, int thread_nb, int texture_num)
-{
-    HapContext *ctx = avctx->priv_data;
-    AVFrame *frame = arg;
-    const uint8_t *d = ctx->tex_data;
-    int w_block = avctx->coded_width / TEXTURE_BLOCK_W;
-    int h_block = avctx->coded_height / TEXTURE_BLOCK_H;
-    int x, y;
-    int start_slice, end_slice;
-    int base_blocks_per_slice = h_block / ctx->slice_count;
-    int remainder_blocks = h_block % ctx->slice_count;
-
-    /* When the frame height (in blocks) doesn't divide evenly between the
-     * number of slices, spread the remaining blocks evenly between the first
-     * operations */
-    start_slice = slice * base_blocks_per_slice;
-    /* Add any extra blocks (one per slice) that have been added before this slice */
-    start_slice += FFMIN(slice, remainder_blocks);
-
-    end_slice = start_slice + base_blocks_per_slice;
-    /* Add an extra block if there are still remainder blocks to be accounted for */
-    if (slice < remainder_blocks)
-        end_slice++;
-
-    for (y = start_slice; y < end_slice; y++) {
-        uint8_t *p = frame->data[0] + y * frame->linesize[0] * TEXTURE_BLOCK_H;
-        int off  = y * w_block;
-        for (x = 0; x < w_block; x++) {
-            if (texture_num == 0) {
-                ctx->tex_fun(p + x * 4 * ctx->uncompress_pix_size, frame->linesize[0],
-                             d + (off + x) * ctx->tex_rat);
-            } else {
-                ctx->tex_fun2(p + x * 4 * ctx->uncompress_pix_size, frame->linesize[0],
-                              d + (off + x) * ctx->tex_rat2);
-            }
-        }
-    }
-
-    return 0;
-}
-
-static int decompress_texture_thread(AVCodecContext *avctx, void *arg,
-                                     int slice, int thread_nb)
-{
-    return decompress_texture_thread_internal(avctx, arg, slice, thread_nb, 0);
-}
-
-static int decompress_texture2_thread(AVCodecContext *avctx, void *arg,
-                                      int slice, int thread_nb)
-{
-    return decompress_texture_thread_internal(avctx, arg, slice, thread_nb, 1);
-}
-
 static int hap_decode(AVCodecContext *avctx, void *data,
                       int *got_frame, AVPacket *avpkt)
 {
@@ -310,12 +256,9 @@ static int hap_decode(AVCodecContext *avctx, void *data,
     int section_size;
     enum HapSectionType section_type;
     int start_texture_section = 0;
-    int tex_rat[2] = {0, 0};
 
     bytestream2_init(&ctx->gbc, avpkt->data, avpkt->size);
 
-    tex_rat[0] = ctx->tex_rat;
-
     /* check for multi texture header */
     if (ctx->texture_count == 2) {
         ret = ff_hap_parse_section_header(&ctx->gbc, &section_size, &section_type);
@@ -326,7 +269,6 @@ static int hap_decode(AVCodecContext *avctx, void *data,
             return AVERROR_INVALIDDATA;
         }
         start_texture_section = 4;
-        tex_rat[1] = ctx->tex_rat2;
     }
 
     /* Get the output frame ready to receive data */
@@ -344,7 +286,7 @@ static int hap_decode(AVCodecContext *avctx, void *data,
 
         if (ctx->tex_size != (avctx->coded_width  / TEXTURE_BLOCK_W)
             *(avctx->coded_height / TEXTURE_BLOCK_H)
-            *tex_rat[t]) {
+            *ctx->dec[t].tex_ratio) {
             av_log(avctx, AV_LOG_ERROR, "uncompressed size mismatches\n");
             return AVERROR_INVALIDDATA;
         }
@@ -355,11 +297,11 @@ static int hap_decode(AVCodecContext *avctx, void *data,
         if (hap_can_use_tex_in_place(ctx)) {
             int tex_size;
             /* Only DXTC texture compression in a contiguous block */
-            ctx->tex_data = ctx->gbc.buffer;
+            ctx->dec[t].tex_data.in = ctx->gbc.buffer;
             tex_size = FFMIN(ctx->texture_section_size, bytestream2_get_bytes_left(&ctx->gbc));
             if (tex_size < (avctx->coded_width  / TEXTURE_BLOCK_W)
                 *(avctx->coded_height / TEXTURE_BLOCK_H)
-                *tex_rat[t]) {
+                *ctx->dec[t].tex_ratio) {
                 av_log(avctx, AV_LOG_ERROR, "Insufficient data\n");
                 return AVERROR_INVALIDDATA;
             }
@@ -377,15 +319,12 @@ static int hap_decode(AVCodecContext *avctx, void *data,
                     return ctx->chunk_results[i];
             }
 
-            ctx->tex_data = ctx->tex_buf;
+            ctx->dec[t].tex_data.in = ctx->tex_buf;
         }
 
-        /* Use the decompress function on the texture, one block per thread */
-        if (t == 0){
-            avctx->execute2(avctx, decompress_texture_thread, frame, NULL, ctx->slice_count);
-        } else{
-            avctx->execute2(avctx, decompress_texture2_thread, frame, NULL, ctx->slice_count);
-        }
+        ctx->dec[t].frame_data.out = frame->data[0];
+        ctx->dec[t].stride = frame->linesize[0];
+        avctx->execute2(avctx, ff_texturedsp_decompress_thread, &ctx->dec[t], NULL, ctx->dec[t].slice_count);
     }
 
     /* Frame is ready to be output */
@@ -415,40 +354,44 @@ static av_cold int hap_init(AVCodecContext *avctx)
     ff_texturedsp_init(&ctx->dxtc);
 
     ctx->texture_count  = 1;
-    ctx->uncompress_pix_size = 4;
+    ctx->dec[0].raw_ratio = 16;
+    ctx->dec[0].slice_count = av_clip(avctx->thread_count, 1,
+                                      avctx->coded_height / TEXTURE_BLOCK_H);
 
     switch (avctx->codec_tag) {
     case MKTAG('H','a','p','1'):
         texture_name = "DXT1";
-        ctx->tex_rat = 8;
-        ctx->tex_fun = ctx->dxtc.dxt1_block;
+        ctx->dec[0].tex_ratio = 8;
+        ctx->dec[0].tex_funct = ctx->dxtc.dxt1_block;
         avctx->pix_fmt = AV_PIX_FMT_RGB0;
         break;
     case MKTAG('H','a','p','5'):
         texture_name = "DXT5";
-        ctx->tex_rat = 16;
-        ctx->tex_fun = ctx->dxtc.dxt5_block;
+        ctx->dec[0].tex_ratio = 16;
+        ctx->dec[0].tex_funct = ctx->dxtc.dxt5_block;
         avctx->pix_fmt = AV_PIX_FMT_RGBA;
         break;
     case MKTAG('H','a','p','Y'):
         texture_name = "DXT5-YCoCg-scaled";
-        ctx->tex_rat = 16;
-        ctx->tex_fun = ctx->dxtc.dxt5ys_block;
+        ctx->dec[0].tex_ratio = 16;
+        ctx->dec[0].tex_funct = ctx->dxtc.dxt5ys_block;
         avctx->pix_fmt = AV_PIX_FMT_RGB0;
         break;
     case MKTAG('H','a','p','A'):
         texture_name = "RGTC1";
-        ctx->tex_rat = 8;
-        ctx->tex_fun = ctx->dxtc.rgtc1u_gray_block;
+        ctx->dec[0].tex_ratio = 8;
+        ctx->dec[0].tex_funct = ctx->dxtc.rgtc1u_gray_block;
+        ctx->dec[0].raw_ratio = 4;
         avctx->pix_fmt = AV_PIX_FMT_GRAY8;
-        ctx->uncompress_pix_size = 1;
         break;
     case MKTAG('H','a','p','M'):
         texture_name  = "DXT5-YCoCg-scaled / RGTC1";
-        ctx->tex_rat  = 16;
-        ctx->tex_rat2 = 8;
-        ctx->tex_fun  = ctx->dxtc.dxt5ys_block;
-        ctx->tex_fun2 = ctx->dxtc.rgtc1u_alpha_block;
+        ctx->dec[0].tex_ratio = 16;
+        ctx->dec[1].tex_ratio = 8;
+        ctx->dec[0].tex_funct = ctx->dxtc.dxt5ys_block;
+        ctx->dec[1].tex_funct = ctx->dxtc.rgtc1u_alpha_block;
+        ctx->dec[1].raw_ratio = 16;
+        ctx->dec[1].slice_count = ctx->dec[0].slice_count;
         avctx->pix_fmt = AV_PIX_FMT_RGBA;
         ctx->texture_count = 2;
         break;
@@ -458,9 +401,6 @@ static av_cold int hap_init(AVCodecContext *avctx)
 
     av_log(avctx, AV_LOG_DEBUG, "%s texture\n", texture_name);
 
-    ctx->slice_count = av_clip(avctx->thread_count, 1,
-                               avctx->coded_height / TEXTURE_BLOCK_H);
-
     return 0;
 }
 
