diff --git a/libavcodec/dsd.c b/libavcodec/dsd.c
index 95aab61ea4..db1611c4d5 100644
--- a/libavcodec/dsd.c
+++ b/libavcodec/dsd.c
@@ -54,26 +54,23 @@ void ff_dsd2pcm_translate(DSDContext* s, size_t samples, int lsbf,
                           const uint8_t *src, ptrdiff_t src_stride,
                           float *dst, ptrdiff_t dst_stride)
 {
-    uint8_t buf[FIFOSIZE];
     unsigned pos, i;
     uint8_t* p;
     double sum;
 
     pos = s->pos;
 
-    memcpy(buf, s->buf, sizeof(buf));
-
     while (samples-- > 0) {
-        buf[pos] = lsbf ? ff_reverse[*src] : *src;
+        s->buf[pos] = lsbf ? ff_reverse[*src] : *src;
         src += src_stride;
 
-        p = buf + ((pos - CTABLES) & FIFOMASK);
+        p = s->buf + ((pos - CTABLES) & FIFOMASK);
         *p = ff_reverse[*p];
 
         sum = 0.0;
         for (i = 0; i < CTABLES; i++) {
-            uint8_t a = buf[(pos                   - i) & FIFOMASK];
-            uint8_t b = buf[(pos - (CTABLES*2 - 1) + i) & FIFOMASK];
+            uint8_t a = s->buf[(pos                   - i) & FIFOMASK];
+            uint8_t b = s->buf[(pos - (CTABLES*2 - 1) + i) & FIFOMASK];
             sum += ctables[i][a] + ctables[i][b];
         }
 
@@ -84,5 +81,36 @@ void ff_dsd2pcm_translate(DSDContext* s, size_t samples, int lsbf,
     }
 
     s->pos = pos;
-    memcpy(s->buf, buf, sizeof(buf));
+}
+
+void ff_dsd2dop_translate(int32_t *const dst_planes[], const uint8_t *src,
+                          int num_channels, int num_samples,
+                          int src_is_planar, int src_is_lsbf)
+{
+    int c, i;
+
+    for (c = 0; c < num_channels; c++) {
+        int32_t *dst = dst_planes[c];
+        int marker = 0x05;
+
+        for (i = 0; i < num_samples; i++) {
+            uint8_t dsd[2];
+
+            if (src_is_planar) {
+                dsd[0] = *src++;
+                dsd[1] = *src++;
+            } else {
+                dsd[0] = src[(i * 2 + 0) * num_channels + c];
+                dsd[1] = src[(i * 2 + 1) * num_channels + c];
+            }
+
+            if (src_is_lsbf) {
+                dsd[0] = ff_reverse[dsd[0]];
+                dsd[1] = ff_reverse[dsd[1]];
+            }
+
+            *dst++ = (marker << 24) | (dsd[0] << 16) | (dsd[1] << 8);
+            marker = ~marker;
+        }
+    }
 }
diff --git a/libavcodec/dsd.h b/libavcodec/dsd.h
index ed09cb9b12..63d3c312bd 100644
--- a/libavcodec/dsd.h
+++ b/libavcodec/dsd.h
@@ -49,4 +49,9 @@ void ff_init_dsd_data(void);
 void ff_dsd2pcm_translate(DSDContext* s, size_t samples, int lsbf,
                           const uint8_t *src, ptrdiff_t src_stride,
                           float *dst, ptrdiff_t dst_stride);
+
+void ff_dsd2dop_translate(int32_t *const dst_planes[], const uint8_t *src,
+                          int num_channels, int num_samples,
+                          int src_is_planar, int src_is_lsbf);
+
 #endif /* AVCODEC_DSD_H */
diff --git a/libavcodec/dsddec.c b/libavcodec/dsddec.c
index 21d1d9f5de..e3a1fd6da9 100644
--- a/libavcodec/dsddec.c
+++ b/libavcodec/dsddec.c
@@ -30,88 +30,35 @@
 #include "avcodec.h"
 #include "dsd.h"
 
-#define DSD_SILENCE 0x69
-#define DSD_SILENCE_REVERSED 0x96
-/* 0x69 = 01101001
- * This pattern "on repeat" makes a low energy 352.8 kHz tone
- * and a high energy 1.0584 MHz tone which should be filtered
- * out completely by any playback system --> silence
- */
-
 static av_cold int decode_init(AVCodecContext *avctx)
 {
-    DSDContext * s;
-    int i;
-    uint8_t silence;
-
-    if (!avctx->channels)
-        return AVERROR_INVALIDDATA;
-
-    ff_init_dsd_data();
-
-    s = av_malloc_array(sizeof(DSDContext), avctx->channels);
-    if (!s)
-        return AVERROR(ENOMEM);
-
-    silence = avctx->codec_id == AV_CODEC_ID_DSD_LSBF || avctx->codec_id == AV_CODEC_ID_DSD_LSBF_PLANAR ? DSD_SILENCE_REVERSED : DSD_SILENCE;
-    for (i = 0; i < avctx->channels; i++) {
-        s[i].pos = 0;
-        memset(s[i].buf, silence, sizeof(s[i].buf));
-    }
-
-    avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
-    avctx->priv_data  = s;
-    return 0;
-}
-
-typedef struct ThreadData {
-    AVFrame *frame;
-    const AVPacket *avpkt;
-} ThreadData;
-
-static int dsd_channel(AVCodecContext *avctx, void *tdata, int j, int threadnr)
-{
-    int lsbf = avctx->codec_id == AV_CODEC_ID_DSD_LSBF || avctx->codec_id == AV_CODEC_ID_DSD_LSBF_PLANAR;
-    DSDContext *s = avctx->priv_data;
-    ThreadData *td = tdata;
-    AVFrame *frame = td->frame;
-    const AVPacket *avpkt = td->avpkt;
-    int src_next, src_stride;
-    float *dst = ((float **)frame->extended_data)[j];
-
-    if (avctx->codec_id == AV_CODEC_ID_DSD_LSBF_PLANAR || avctx->codec_id == AV_CODEC_ID_DSD_MSBF_PLANAR) {
-        src_next   = frame->nb_samples;
-        src_stride = 1;
-    } else {
-        src_next   = 1;
-        src_stride = avctx->channels;
-    }
-
-    ff_dsd2pcm_translate(&s[j], frame->nb_samples, lsbf,
-                         avpkt->data + j * src_next, src_stride,
-                         dst, 1);
-
+    avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
     return 0;
 }
 
 static int decode_frame(AVCodecContext *avctx, void *data,
                         int *got_frame_ptr, AVPacket *avpkt)
 {
-    ThreadData td;
     AVFrame *frame = data;
     int ret;
+    int lsbf = avctx->codec_id == AV_CODEC_ID_DSD_LSBF || avctx->codec_id == AV_CODEC_ID_DSD_LSBF_PLANAR;
+    int planar = avctx->codec_id == AV_CODEC_ID_DSD_LSBF_PLANAR || avctx->codec_id == AV_CODEC_ID_DSD_MSBF_PLANAR;
 
-    frame->nb_samples = avpkt->size / avctx->channels;
+    // DoP: 2 dsd bytes per PCM sample.
+    frame->nb_samples = avpkt->size / 2 / avctx->channels;
+    // DoP uses alternating sequence of 05/fa as the most significant byte of
+    // alternating PCM sample. Require number of PCM samples to be even so that
+    // two PCM streams are concatenated the 05/fa sequence is preserved.
+    assert((frame->nb_samples & 1) == 0);
 
     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
         return ret;
 
-    td.frame = frame;
-    td.avpkt = avpkt;
-    avctx->execute2(avctx, dsd_channel, &td, NULL, avctx->channels);
+    ff_dsd2dop_translate((int32_t **)frame->extended_data, avpkt->data,
+                         avctx->channels, frame->nb_samples, planar, lsbf);
 
     *got_frame_ptr = 1;
-    return frame->nb_samples * avctx->channels;
+    return avpkt->size;
 }
 
 #define DSD_DECODER(id_, name_, long_name_) \
@@ -122,8 +69,7 @@ AVCodec ff_##name_##_decoder = { \
     .id           = AV_CODEC_ID_##id_, \
     .init         = decode_init, \
     .decode       = decode_frame, \
-    .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS, \
-    .sample_fmts  = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, \
+    .sample_fmts  = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32P, \
                                                    AV_SAMPLE_FMT_NONE }, \
     .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, \
 };
diff --git a/libavcodec/dstdec.c b/libavcodec/dstdec.c
index 819a037c69..ffe44a8f9b 100644
--- a/libavcodec/dstdec.c
+++ b/libavcodec/dstdec.c
@@ -37,8 +37,9 @@
 
 #define DST_MAX_CHANNELS 6
 #define DST_MAX_ELEMENTS (2 * DST_MAX_CHANNELS)
+#define DSD_MAX_FS44 512
 
-#define DSD_FS44(sample_rate) (sample_rate * 8LL / 44100)
+#define DSD_FS44(sample_rate) (sample_rate * 16LL / 44100)
 
 #define DST_SAMPLES_PER_FRAME(sample_rate) (588 * DSD_FS44(sample_rate))
 
@@ -73,14 +74,11 @@ typedef struct DSTContext {
     Table fsets, probs;
     DECLARE_ALIGNED(16, uint8_t, status)[DST_MAX_CHANNELS][16];
     DECLARE_ALIGNED(16, int16_t, filter)[DST_MAX_ELEMENTS][16][256];
-    DSDContext dsdctx[DST_MAX_CHANNELS];
+    uint8_t dsd_frame[588 * DSD_MAX_FS44 / 8 * DST_MAX_CHANNELS];
 } DSTContext;
 
 static av_cold int decode_init(AVCodecContext *avctx)
 {
-    DSTContext *s = avctx->priv_data;
-    int i;
-
     if (avctx->channels > DST_MAX_CHANNELS) {
         avpriv_request_sample(avctx, "Channel count %d", avctx->channels);
         return AVERROR_PATCHWELCOME;
@@ -88,7 +86,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
 
     // the sample rate is only allowed to be 64,128,256 * 44100 by ISO/IEC 14496-3:2005(E)
     // We are a bit more tolerant here, but this check is needed to bound the size and duration
-    if (avctx->sample_rate > 512 * 44100)
+    if (DSD_FS44(avctx->sample_rate) > DSD_MAX_FS44)
         return AVERROR_INVALIDDATA;
 
 
@@ -96,12 +94,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
         return AVERROR_PATCHWELCOME;
     }
 
-    avctx->sample_fmt = AV_SAMPLE_FMT_FLT;
-
-    for (i = 0; i < avctx->channels; i++)
-        memset(s->dsdctx[i].buf, 0x69, sizeof(s->dsdctx[i].buf));
-
-    ff_init_dsd_data();
+    avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
 
     return 0;
 }
@@ -252,18 +245,16 @@ static int decode_frame(AVCodecContext *avctx, void *data,
     GetBitContext *gb = &s->gb;
     ArithCoder *ac = &s->ac;
     AVFrame *frame = data;
-    uint8_t *dsd;
-    float *pcm;
+    uint8_t *dsd = s->dsd_frame;
     int ret;
 
     if (avpkt->size <= 1)
         return AVERROR_INVALIDDATA;
 
-    frame->nb_samples = samples_per_frame / 8;
+    /* Each DoP sample packs 16 DSD samples. */
+    frame->nb_samples = samples_per_frame / 16;
     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
         return ret;
-    dsd = frame->data[0];
-    pcm = (float *)frame->data[0];
 
     if ((ret = init_get_bits8(gb, avpkt->data, avpkt->size)) < 0)
         return ret;
@@ -337,7 +328,7 @@ static int decode_frame(AVCodecContext *avctx, void *data,
         return ret;
 
     memset(s->status, 0xAA, sizeof(s->status));
-    memset(dsd, 0, frame->nb_samples * 4 * channels);
+    memset(dsd, 0, samples_per_frame / 8 * channels);
 
     ac_get(ac, gb, prob_dst_x_bit(s->fsets.coeff[0][0]), &dst_x_bit);
 
@@ -365,7 +356,7 @@ static int decode_frame(AVCodecContext *avctx, void *data,
 
             ac_get(ac, gb, prob, &residual);
             v = ((predict >> 15) ^ residual) & 1;
-            dsd[((i >> 3) * channels + ch) << 2] |= v << (7 - (i & 0x7 ));
+            dsd[(i >> 3) * channels + ch] |= v << (7 - (i & 0x7 ));
 
             AV_WL64A(status + 8, (AV_RL64A(status + 8) << 1) | ((AV_RL64A(status) >> 63) & 1));
             AV_WL64A(status, (AV_RL64A(status) << 1) | v);
@@ -373,11 +364,9 @@ static int decode_frame(AVCodecContext *avctx, void *data,
     }
 
 dsd:
-    for (i = 0; i < channels; i++) {
-        ff_dsd2pcm_translate(&s->dsdctx[i], frame->nb_samples, 0,
-                             frame->data[0] + i * 4,
-                             channels * 4, pcm + i, channels);
-    }
+    ff_dsd2dop_translate((int32_t **)frame->extended_data, dsd,
+                         channels, frame->nb_samples, 0, 0);
+
 
     *got_frame_ptr = 1;
 
@@ -393,7 +382,7 @@ AVCodec ff_dst_decoder = {
     .init           = decode_init,
     .decode         = decode_frame,
     .capabilities   = AV_CODEC_CAP_DR1,
-    .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
+    .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P,
                                                       AV_SAMPLE_FMT_NONE },
     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
 };
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index fdc3de1b1d..b4b5932886 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -563,10 +563,6 @@ int av_get_exact_bits_per_sample(enum AVCodecID codec_id)
     case AV_CODEC_ID_ADPCM_YAMAHA:
     case AV_CODEC_ID_ADPCM_AICA:
         return 4;
-    case AV_CODEC_ID_DSD_LSBF:
-    case AV_CODEC_ID_DSD_MSBF:
-    case AV_CODEC_ID_DSD_LSBF_PLANAR:
-    case AV_CODEC_ID_DSD_MSBF_PLANAR:
     case AV_CODEC_ID_PCM_ALAW:
     case AV_CODEC_ID_PCM_MULAW:
     case AV_CODEC_ID_PCM_VIDC:
diff --git a/libavformat/dsfdec.c b/libavformat/dsfdec.c
index 71dbf2f112..6f3d35d164 100644
--- a/libavformat/dsfdec.c
+++ b/libavformat/dsfdec.c
@@ -109,7 +109,8 @@ static int dsf_read_header(AVFormatContext *s)
 
     st->codecpar->codec_type   = AVMEDIA_TYPE_AUDIO;
     st->codecpar->channels     = avio_rl32(pb);
-    st->codecpar->sample_rate  = avio_rl32(pb) / 8;
+    // Each DoP sample packs 16 DSD samples.
+    st->codecpar->sample_rate  = avio_rl32(pb) / 16;
 
     if (st->codecpar->channels <= 0)
         return AVERROR_INVALIDDATA;
@@ -122,15 +123,17 @@ static int dsf_read_header(AVFormatContext *s)
         return AVERROR_INVALIDDATA;
     }
 
-    dsf->audio_size = avio_rl64(pb) / 8 * st->codecpar->channels;
+    // Each DoP sample packs 16 DSD samples, but we want an even number of
+    // DoP samples, so truncate DSD sample count to nearest multiple of 32.
+    dsf->audio_size = (avio_rl64(pb) & -32) / 8 * st->codecpar->channels;
     st->codecpar->block_align = avio_rl32(pb);
     if (st->codecpar->block_align > INT_MAX / st->codecpar->channels || st->codecpar->block_align <= 0) {
         avpriv_request_sample(s, "block_align invalid");
         return AVERROR_INVALIDDATA;
     }
     st->codecpar->block_align *= st->codecpar->channels;
-    st->codecpar->bit_rate = st->codecpar->channels * 8LL * st->codecpar->sample_rate;
-    avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
+    st->codecpar->bit_rate = st->codecpar->channels * 16LL * st->codecpar->sample_rate;
+    avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate * 2);
     avio_skip(pb, 4);
 
     /* data chunk */
@@ -167,7 +170,7 @@ static int dsf_read_packet(AVFormatContext *s, AVPacket *pkt)
             int ch, ret;
 
             if (packet_size <= 0 || skip_size <= 0)
-                return AVERROR_INVALIDDATA;
+                return AVERROR_EOF;
 
             if ((ret = av_new_packet(pkt, packet_size)) < 0)
                 return ret;
diff --git a/libavformat/iff.c b/libavformat/iff.c
index 06785c748b..c0ded4e2f8 100644
--- a/libavformat/iff.c
+++ b/libavformat/iff.c
@@ -311,7 +311,7 @@ static int parse_dsd_prop(AVFormatContext *s, AVStream *st, uint64_t eof)
         case MKTAG('F','S',' ',' '):
             if (size < 4)
                 return AVERROR_INVALIDDATA;
-            st->codecpar->sample_rate = avio_rb32(pb) / 8;
+            st->codecpar->sample_rate = avio_rb32(pb) / 16;
             break;
 
         case MKTAG('I','D','3',' '):
