diff mbox

[FFmpeg-devel,14/17] mjpegdec: Add hwaccel hooks

Message ID 20171124005134.5683-14-sw@jkqxz.net
State New
Headers show

Commit Message

Mark Thompson Nov. 24, 2017, 12:51 a.m. UTC
Also adds some extra fields to the main context structure that may
be needed by a hwaccel decoder.
---
The YUVJ formats really mess with this.  This patch hacks them out so that the hwaccel works, suggestions welcome on what to actually do about them.


 libavcodec/mjpegdec.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++--
 libavcodec/mjpegdec.h | 11 ++++++++
 2 files changed, 79 insertions(+), 2 deletions(-)

Comments

Jun Zhao Nov. 24, 2017, 7:25 a.m. UTC | #1
On 2017/11/24 8:51, Mark Thompson wrote:
> Also adds some extra fields to the main context structure that may
> be needed by a hwaccel decoder.
> ---
> The YUVJ formats really mess with this.  This patch hacks them out so that the hwaccel works, suggestions welcome on what to actually do about them.
>
>
>  libavcodec/mjpegdec.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++--
>  libavcodec/mjpegdec.h | 11 ++++++++
>  2 files changed, 79 insertions(+), 2 deletions(-)
>
> diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
> index f01d44a169..846dec2f42 100644
> --- a/libavcodec/mjpegdec.c
> +++ b/libavcodec/mjpegdec.c
> @@ -36,6 +36,7 @@
>  #include "avcodec.h"
>  #include "blockdsp.h"
>  #include "copy_block.h"
> +#include "hwaccel.h"
>  #include "idctdsp.h"
>  #include "internal.h"
>  #include "jpegtables.h"
> @@ -147,6 +148,7 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx)
>      s->org_height    = avctx->coded_height;
>      avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
>      avctx->colorspace = AVCOL_SPC_BT470BG;
> +    s->hwaccel_pix_fmt = s->hwaccel_sw_pix_fmt = AV_PIX_FMT_NONE;
>  
>      if ((ret = build_basic_mjpeg_vlc(s)) < 0)
>          return ret;
> @@ -279,6 +281,11 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s)
>                                   code_max + 1, 0, 0)) < 0)
>                  return ret;
>          }
> +
> +        for (i = 0; i < 16; i++)
> +            s->raw_huffman_lengths[class][index][i] = bits_table[i + 1];
> +        for (i = 0; i < 256; i++)
> +            s->raw_huffman_values[class][index][i] = val_table[i];
>      }
>      return 0;
>  }
> @@ -636,6 +643,26 @@ unk_pixfmt:
>          return AVERROR_BUG;
>      }
>  
> +    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ420P)
> +        s->avctx->pix_fmt = AV_PIX_FMT_YUV420P;
> +    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ422P)
> +        s->avctx->pix_fmt = AV_PIX_FMT_YUV422P;
> +
Maybe need to give a comments in the code for this workaround, not just
in the commit message.
> +    if (s->avctx->pix_fmt == s->hwaccel_sw_pix_fmt) {
> +        s->avctx->pix_fmt = s->hwaccel_pix_fmt;
> +    } else {
> +        enum AVPixelFormat pix_fmts[] = {
> +            s->avctx->pix_fmt,
> +            AV_PIX_FMT_NONE,
> +        };
> +        s->hwaccel_pix_fmt = ff_get_format(s->avctx, pix_fmts);
> +        if (s->hwaccel_pix_fmt < 0)
> +            return AVERROR(EINVAL);
> +
> +        s->hwaccel_sw_pix_fmt = s->avctx->pix_fmt;
> +        s->avctx->pix_fmt = s->hwaccel_pix_fmt;
> +    }
> +
>      if (s->avctx->skip_frame == AVDISCARD_ALL) {
>          s->picture_ptr->pict_type = AV_PICTURE_TYPE_I;
>          s->picture_ptr->key_frame = 1;
> @@ -683,6 +710,19 @@ unk_pixfmt:
>          }
>          memset(s->coefs_finished, 0, sizeof(s->coefs_finished));
>      }
> +
> +    if (s->avctx->hwaccel) {
> +        s->hwaccel_picture_private =
> +            av_mallocz(s->avctx->hwaccel->frame_priv_data_size);
> +        if (!s->hwaccel_picture_private)
> +            return AVERROR(ENOMEM);
> +
> +        ret = s->avctx->hwaccel->start_frame(s->avctx, s->raw_buffer,
> +                                             s->raw_buffer_size);
> +        if (ret < 0)
> +            return ret;
> +    }
> +
>      return 0;
>  }
>  
> @@ -1510,7 +1550,7 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask,
>          }
>      }
>  
> -    av_assert0(s->picture_ptr->data[0]);
> +    //av_assert0(s->picture_ptr->data[0]);
Remove the assert ?
>      /* XXX: verify len field validity */
>      len = get_bits(&s->gb, 16);
>      nb_components = get_bits(&s->gb, 8);
> @@ -1600,7 +1640,18 @@ next_field:
>      for (i = 0; i < nb_components; i++)
>          s->last_dc[i] = (4 << s->bits);
>  
> -    if (s->lossless) {
> +    if (s->avctx->hwaccel) {
> +        int bytes_to_start = get_bits_count(&s->gb) / 8;
> +        av_assert0(bytes_to_start >= 0 &&
> +                   s->raw_buffer_size >= bytes_to_start);
> +
> +        ret = s->avctx->hwaccel->decode_slice(s->avctx,
> +                                              s->raw_buffer      + bytes_to_start,
> +                                              s->raw_buffer_size - bytes_to_start);
> +        if (ret < 0)
> +            return ret;
> +
> +    } else if (s->lossless) {
>          av_assert0(s->picture_ptr == s->picture);
>          if (CONFIG_JPEGLS_DECODER && s->ls) {
>  //            for () {
> @@ -2226,6 +2277,9 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
>              goto fail;
>          }
>  
> +        s->raw_buffer      = buf_ptr;
> +        s->raw_buffer_size = buf_end - buf_ptr;
> +
>          s->start_code = start_code;
>          if (s->avctx->debug & FF_DEBUG_STARTCODE)
>              av_log(avctx, AV_LOG_DEBUG, "startcode: %X\n", start_code);
> @@ -2349,6 +2403,13 @@ eoi_parser:
>                  s->got_picture = 0;
>                  goto the_end_no_picture;
>              }
> +            if (s->avctx->hwaccel) {
> +                ret = s->avctx->hwaccel->end_frame(s->avctx);
> +                if (ret < 0)
> +                    return ret;
> +
> +                av_freep(&s->hwaccel_picture_private);
> +            }
>              if ((ret = av_frame_ref(frame, s->picture_ptr)) < 0)
>                  return ret;
>              *got_frame = 1;
> @@ -2673,6 +2734,8 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx)
>  
>      reset_icc_profile(s);
>  
> +    av_freep(&s->hwaccel_picture_private);
> +
>      return 0;
>  }
>  
> @@ -2713,6 +2776,9 @@ AVCodec ff_mjpeg_decoder = {
>      .priv_class     = &mjpegdec_class,
>      .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
>                        FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
> +    .hw_configs     = (const AVCodecHWConfigInternal*[]) {
> +                        NULL
> +                    },
>  };
>  #endif
>  #if CONFIG_THP_DECODER
> diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h
> index c84a40aa6e..50443937b4 100644
> --- a/libavcodec/mjpegdec.h
> +++ b/libavcodec/mjpegdec.h
> @@ -135,6 +135,17 @@ typedef struct MJpegDecodeContext {
>      int *iccdatalens;
>      int iccnum;
>      int iccread;
> +
> +    // Raw stream data for hwaccel use.
> +    const uint8_t *raw_buffer;
> +    size_t         raw_buffer_size;
> +
> +    uint8_t raw_huffman_lengths[2][4][16];
> +    uint8_t raw_huffman_values[2][4][256];
> +
> +    enum AVPixelFormat hwaccel_sw_pix_fmt;
> +    enum AVPixelFormat hwaccel_pix_fmt;
> +    void *hwaccel_picture_private;
>  } MJpegDecodeContext;
>  
>  int ff_mjpeg_decode_init(AVCodecContext *avctx);
Carl Eugen Hoyos Nov. 24, 2017, 11:17 a.m. UTC | #2
2017-11-24 1:51 GMT+01:00 Mark Thompson <sw@jkqxz.net>:
> Also adds some extra fields to the main context structure
> that may be needed by a hwaccel decoder.
> ---
> The YUVJ formats really mess with this.  This patch hacks
> them out so that the hwaccel works, suggestions welcome
> on what to actually do about them.

> +    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ420P)
> +        s->avctx->pix_fmt = AV_PIX_FMT_YUV420P;
> +    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ422P)
> +        s->avctx->pix_fmt = AV_PIX_FMT_YUV422P;

The hardware decoders output mpeg-scaled frames?

Carl Eugen
Mark Thompson Nov. 24, 2017, 11:18 a.m. UTC | #3
On 24/11/17 07:25, Jun Zhao wrote:
> 
> 
> On 2017/11/24 8:51, Mark Thompson wrote:
>> Also adds some extra fields to the main context structure that may
>> be needed by a hwaccel decoder.
>> ---
>> The YUVJ formats really mess with this.  This patch hacks them out so that the hwaccel works, suggestions welcome on what to actually do about them.
>>
>>
>>  libavcodec/mjpegdec.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++--
>>  libavcodec/mjpegdec.h | 11 ++++++++
>>  2 files changed, 79 insertions(+), 2 deletions(-)
>>
>> diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
>> index f01d44a169..846dec2f42 100644
>> --- a/libavcodec/mjpegdec.c
>> +++ b/libavcodec/mjpegdec.c
>> @@ -36,6 +36,7 @@
>>  #include "avcodec.h"
>>  #include "blockdsp.h"
>>  #include "copy_block.h"
>> +#include "hwaccel.h"
>>  #include "idctdsp.h"
>>  #include "internal.h"
>>  #include "jpegtables.h"
>> @@ -147,6 +148,7 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx)
>>      s->org_height    = avctx->coded_height;
>>      avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
>>      avctx->colorspace = AVCOL_SPC_BT470BG;
>> +    s->hwaccel_pix_fmt = s->hwaccel_sw_pix_fmt = AV_PIX_FMT_NONE;
>>  
>>      if ((ret = build_basic_mjpeg_vlc(s)) < 0)
>>          return ret;
>> @@ -279,6 +281,11 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s)
>>                                   code_max + 1, 0, 0)) < 0)
>>                  return ret;
>>          }
>> +
>> +        for (i = 0; i < 16; i++)
>> +            s->raw_huffman_lengths[class][index][i] = bits_table[i + 1];
>> +        for (i = 0; i < 256; i++)
>> +            s->raw_huffman_values[class][index][i] = val_table[i];
>>      }
>>      return 0;
>>  }
>> @@ -636,6 +643,26 @@ unk_pixfmt:
>>          return AVERROR_BUG;
>>      }
>>  
>> +    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ420P)
>> +        s->avctx->pix_fmt = AV_PIX_FMT_YUV420P;
>> +    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ422P)
>> +        s->avctx->pix_fmt = AV_PIX_FMT_YUV422P;
>> +
> Maybe need to give a comments in the code for this workaround, not just
> in the commit message.

This hack is not intended to be applied.  The note above after the commit message is inviting comment on what to actually do.

- Mark
Mark Thompson Nov. 24, 2017, 11:23 a.m. UTC | #4
On 24/11/17 11:17, Carl Eugen Hoyos wrote:
> 2017-11-24 1:51 GMT+01:00 Mark Thompson <sw@jkqxz.net>:
>> Also adds some extra fields to the main context structure
>> that may be needed by a hwaccel decoder.
>> ---
>> The YUVJ formats really mess with this.  This patch hacks
>> them out so that the hwaccel works, suggestions welcome
>> on what to actually do about them.
> 
>> +    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ420P)
>> +        s->avctx->pix_fmt = AV_PIX_FMT_YUV420P;
>> +    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ422P)
>> +        s->avctx->pix_fmt = AV_PIX_FMT_YUV422P;
> 
> The hardware decoders output mpeg-scaled frames?

I think some do, though I haven't seen it myself.  Those that don't (like VAAPI) will use the color_range metadata - I think don't it is sensible to add lots of extra paths to support YUVJ formats in AVHWFramesContext.sw_format.

Thanks,

- Mark
Philip Langdale Nov. 24, 2017, 5:38 p.m. UTC | #5
On Fri, 24 Nov 2017 00:51:31 +0000
Mark Thompson <sw@jkqxz.net> wrote:

> Also adds some extra fields to the main context structure that may
> be needed by a hwaccel decoder.
> ---
> The YUVJ formats really mess with this.  This patch hacks them out so
> that the hwaccel works, suggestions welcome on what to actually do
> about them.
> 
> 
>  libavcodec/mjpegdec.c | 70
> +++++++++++++++++++++++++++++++++++++++++++++++++--
> libavcodec/mjpegdec.h | 11 ++++++++ 2 files changed, 79
> insertions(+), 2 deletions(-)
> 
> diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
> index f01d44a169..846dec2f42 100644
> --- a/libavcodec/mjpegdec.c
> +++ b/libavcodec/mjpegdec.c
> @@ -36,6 +36,7 @@
>  #include "avcodec.h"
>  #include "blockdsp.h"
>  #include "copy_block.h"
> +#include "hwaccel.h"
>  #include "idctdsp.h"
>  #include "internal.h"
>  #include "jpegtables.h"
> @@ -147,6 +148,7 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext
> *avctx) s->org_height    = avctx->coded_height;
>      avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
>      avctx->colorspace = AVCOL_SPC_BT470BG;
> +    s->hwaccel_pix_fmt = s->hwaccel_sw_pix_fmt = AV_PIX_FMT_NONE;
>  
>      if ((ret = build_basic_mjpeg_vlc(s)) < 0)
>          return ret;
> @@ -279,6 +281,11 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s)
>                                   code_max + 1, 0, 0)) < 0)
>                  return ret;
>          }
> +
> +        for (i = 0; i < 16; i++)
> +            s->raw_huffman_lengths[class][index][i] = bits_table[i +
> 1];
> +        for (i = 0; i < 256; i++)
> +            s->raw_huffman_values[class][index][i] = val_table[i];
>      }
>      return 0;
>  }
> @@ -636,6 +643,26 @@ unk_pixfmt:
>          return AVERROR_BUG;
>      }
>  
> +    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ420P)
> +        s->avctx->pix_fmt = AV_PIX_FMT_YUV420P;
> +    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ422P)
> +        s->avctx->pix_fmt = AV_PIX_FMT_YUV422P;
> +
> +    if (s->avctx->pix_fmt == s->hwaccel_sw_pix_fmt) {
> +        s->avctx->pix_fmt = s->hwaccel_pix_fmt;
> +    } else {
> +        enum AVPixelFormat pix_fmts[] = {
> +            s->avctx->pix_fmt,
> +            AV_PIX_FMT_NONE,
> +        };
> +        s->hwaccel_pix_fmt = ff_get_format(s->avctx, pix_fmts);
> +        if (s->hwaccel_pix_fmt < 0)
> +            return AVERROR(EINVAL);
> +
> +        s->hwaccel_sw_pix_fmt = s->avctx->pix_fmt;
> +        s->avctx->pix_fmt = s->hwaccel_pix_fmt;
> +    }
> +

If I'm reading this right, your hack here means that the pix_fmt is
changed for all usage, whether hwaccel is used or not, right?
Presumably you just want to do this if an hwaccel ends up being used;
so at least you want to restore the original fmt in the non-hwaccel
case?

>      if (s->avctx->skip_frame == AVDISCARD_ALL) {
>          s->picture_ptr->pict_type = AV_PICTURE_TYPE_I;
>          s->picture_ptr->key_frame = 1;
> @@ -683,6 +710,19 @@ unk_pixfmt:
>          }
>          memset(s->coefs_finished, 0, sizeof(s->coefs_finished));
>      }
> +
> +    if (s->avctx->hwaccel) {
> +        s->hwaccel_picture_private =
> +            av_mallocz(s->avctx->hwaccel->frame_priv_data_size);
> +        if (!s->hwaccel_picture_private)
> +            return AVERROR(ENOMEM);
> +
> +        ret = s->avctx->hwaccel->start_frame(s->avctx, s->raw_buffer,
> +                                             s->raw_buffer_size);

nvdec needs the entire avpkt->data to be able to decode successfully.

> +        if (ret < 0)
> +            return ret;
> +    }
> +
>      return 0;
>  }
>  
> @@ -1510,7 +1550,7 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s,
> const uint8_t *mb_bitmask, }
>      }
>  
> -    av_assert0(s->picture_ptr->data[0]);
> +    //av_assert0(s->picture_ptr->data[0]);
>      /* XXX: verify len field validity */
>      len = get_bits(&s->gb, 16);
>      nb_components = get_bits(&s->gb, 8);
> @@ -1600,7 +1640,18 @@ next_field:
>      for (i = 0; i < nb_components; i++)
>          s->last_dc[i] = (4 << s->bits);
>  
> -    if (s->lossless) {
> +    if (s->avctx->hwaccel) {
> +        int bytes_to_start = get_bits_count(&s->gb) / 8;
> +        av_assert0(bytes_to_start >= 0 &&
> +                   s->raw_buffer_size >= bytes_to_start);
> +
> +        ret = s->avctx->hwaccel->decode_slice(s->avctx,
> +                                              s->raw_buffer      +
> bytes_to_start,
> +                                              s->raw_buffer_size -
> bytes_to_start);
> +        if (ret < 0)
> +            return ret;
> +
> +    } else if (s->lossless) {
>          av_assert0(s->picture_ptr == s->picture);
>          if (CONFIG_JPEGLS_DECODER && s->ls) {
>  //            for () {
> @@ -2226,6 +2277,9 @@ int ff_mjpeg_decode_frame(AVCodecContext
> *avctx, void *data, int *got_frame, goto fail;
>          }
>  
> +        s->raw_buffer      = buf_ptr;
> +        s->raw_buffer_size = buf_end - buf_ptr;
> +
>          s->start_code = start_code;
>          if (s->avctx->debug & FF_DEBUG_STARTCODE)
>              av_log(avctx, AV_LOG_DEBUG, "startcode: %X\n",
> start_code); @@ -2349,6 +2403,13 @@ eoi_parser:
>                  s->got_picture = 0;
>                  goto the_end_no_picture;
>              }
> +            if (s->avctx->hwaccel) {
> +                ret = s->avctx->hwaccel->end_frame(s->avctx);
> +                if (ret < 0)
> +                    return ret;
> +
> +                av_freep(&s->hwaccel_picture_private);
> +            }
>              if ((ret = av_frame_ref(frame, s->picture_ptr)) < 0)
>                  return ret;
>              *got_frame = 1;
> @@ -2673,6 +2734,8 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext
> *avctx) 
>      reset_icc_profile(s);
>  
> +    av_freep(&s->hwaccel_picture_private);
> +
>      return 0;
>  }
>  
> @@ -2713,6 +2776,9 @@ AVCodec ff_mjpeg_decoder = {
>      .priv_class     = &mjpegdec_class,
>      .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
>                        FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
> +    .hw_configs     = (const AVCodecHWConfigInternal*[]) {
> +                        NULL
> +                    },
>  };
>  #endif
>  #if CONFIG_THP_DECODER
> diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h
> index c84a40aa6e..50443937b4 100644
> --- a/libavcodec/mjpegdec.h
> +++ b/libavcodec/mjpegdec.h
> @@ -135,6 +135,17 @@ typedef struct MJpegDecodeContext {
>      int *iccdatalens;
>      int iccnum;
>      int iccread;
> +
> +    // Raw stream data for hwaccel use.
> +    const uint8_t *raw_buffer;
> +    size_t         raw_buffer_size;
> +
> +    uint8_t raw_huffman_lengths[2][4][16];
> +    uint8_t raw_huffman_values[2][4][256];
> +
> +    enum AVPixelFormat hwaccel_sw_pix_fmt;
> +    enum AVPixelFormat hwaccel_pix_fmt;
> +    void *hwaccel_picture_private;
>  } MJpegDecodeContext;
>  
>  int ff_mjpeg_decode_init(AVCodecContext *avctx);




--phil
Michael Niedermayer Nov. 24, 2017, 6:38 p.m. UTC | #6
On Fri, Nov 24, 2017 at 12:51:31AM +0000, Mark Thompson wrote:
> Also adds some extra fields to the main context structure that may
> be needed by a hwaccel decoder.
> ---
> The YUVJ formats really mess with this.  This patch hacks them out so that the hwaccel works, suggestions welcome on what to actually do about them.

Can you explain what the problem is exactly ?


[...]
diff mbox

Patch

diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index f01d44a169..846dec2f42 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -36,6 +36,7 @@ 
 #include "avcodec.h"
 #include "blockdsp.h"
 #include "copy_block.h"
+#include "hwaccel.h"
 #include "idctdsp.h"
 #include "internal.h"
 #include "jpegtables.h"
@@ -147,6 +148,7 @@  av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx)
     s->org_height    = avctx->coded_height;
     avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
     avctx->colorspace = AVCOL_SPC_BT470BG;
+    s->hwaccel_pix_fmt = s->hwaccel_sw_pix_fmt = AV_PIX_FMT_NONE;
 
     if ((ret = build_basic_mjpeg_vlc(s)) < 0)
         return ret;
@@ -279,6 +281,11 @@  int ff_mjpeg_decode_dht(MJpegDecodeContext *s)
                                  code_max + 1, 0, 0)) < 0)
                 return ret;
         }
+
+        for (i = 0; i < 16; i++)
+            s->raw_huffman_lengths[class][index][i] = bits_table[i + 1];
+        for (i = 0; i < 256; i++)
+            s->raw_huffman_values[class][index][i] = val_table[i];
     }
     return 0;
 }
@@ -636,6 +643,26 @@  unk_pixfmt:
         return AVERROR_BUG;
     }
 
+    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ420P)
+        s->avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+    if (s->avctx->pix_fmt == AV_PIX_FMT_YUVJ422P)
+        s->avctx->pix_fmt = AV_PIX_FMT_YUV422P;
+
+    if (s->avctx->pix_fmt == s->hwaccel_sw_pix_fmt) {
+        s->avctx->pix_fmt = s->hwaccel_pix_fmt;
+    } else {
+        enum AVPixelFormat pix_fmts[] = {
+            s->avctx->pix_fmt,
+            AV_PIX_FMT_NONE,
+        };
+        s->hwaccel_pix_fmt = ff_get_format(s->avctx, pix_fmts);
+        if (s->hwaccel_pix_fmt < 0)
+            return AVERROR(EINVAL);
+
+        s->hwaccel_sw_pix_fmt = s->avctx->pix_fmt;
+        s->avctx->pix_fmt = s->hwaccel_pix_fmt;
+    }
+
     if (s->avctx->skip_frame == AVDISCARD_ALL) {
         s->picture_ptr->pict_type = AV_PICTURE_TYPE_I;
         s->picture_ptr->key_frame = 1;
@@ -683,6 +710,19 @@  unk_pixfmt:
         }
         memset(s->coefs_finished, 0, sizeof(s->coefs_finished));
     }
+
+    if (s->avctx->hwaccel) {
+        s->hwaccel_picture_private =
+            av_mallocz(s->avctx->hwaccel->frame_priv_data_size);
+        if (!s->hwaccel_picture_private)
+            return AVERROR(ENOMEM);
+
+        ret = s->avctx->hwaccel->start_frame(s->avctx, s->raw_buffer,
+                                             s->raw_buffer_size);
+        if (ret < 0)
+            return ret;
+    }
+
     return 0;
 }
 
@@ -1510,7 +1550,7 @@  int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask,
         }
     }
 
-    av_assert0(s->picture_ptr->data[0]);
+    //av_assert0(s->picture_ptr->data[0]);
     /* XXX: verify len field validity */
     len = get_bits(&s->gb, 16);
     nb_components = get_bits(&s->gb, 8);
@@ -1600,7 +1640,18 @@  next_field:
     for (i = 0; i < nb_components; i++)
         s->last_dc[i] = (4 << s->bits);
 
-    if (s->lossless) {
+    if (s->avctx->hwaccel) {
+        int bytes_to_start = get_bits_count(&s->gb) / 8;
+        av_assert0(bytes_to_start >= 0 &&
+                   s->raw_buffer_size >= bytes_to_start);
+
+        ret = s->avctx->hwaccel->decode_slice(s->avctx,
+                                              s->raw_buffer      + bytes_to_start,
+                                              s->raw_buffer_size - bytes_to_start);
+        if (ret < 0)
+            return ret;
+
+    } else if (s->lossless) {
         av_assert0(s->picture_ptr == s->picture);
         if (CONFIG_JPEGLS_DECODER && s->ls) {
 //            for () {
@@ -2226,6 +2277,9 @@  int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
             goto fail;
         }
 
+        s->raw_buffer      = buf_ptr;
+        s->raw_buffer_size = buf_end - buf_ptr;
+
         s->start_code = start_code;
         if (s->avctx->debug & FF_DEBUG_STARTCODE)
             av_log(avctx, AV_LOG_DEBUG, "startcode: %X\n", start_code);
@@ -2349,6 +2403,13 @@  eoi_parser:
                 s->got_picture = 0;
                 goto the_end_no_picture;
             }
+            if (s->avctx->hwaccel) {
+                ret = s->avctx->hwaccel->end_frame(s->avctx);
+                if (ret < 0)
+                    return ret;
+
+                av_freep(&s->hwaccel_picture_private);
+            }
             if ((ret = av_frame_ref(frame, s->picture_ptr)) < 0)
                 return ret;
             *got_frame = 1;
@@ -2673,6 +2734,8 @@  av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx)
 
     reset_icc_profile(s);
 
+    av_freep(&s->hwaccel_picture_private);
+
     return 0;
 }
 
@@ -2713,6 +2776,9 @@  AVCodec ff_mjpeg_decoder = {
     .priv_class     = &mjpegdec_class,
     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
                       FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
+    .hw_configs     = (const AVCodecHWConfigInternal*[]) {
+                        NULL
+                    },
 };
 #endif
 #if CONFIG_THP_DECODER
diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h
index c84a40aa6e..50443937b4 100644
--- a/libavcodec/mjpegdec.h
+++ b/libavcodec/mjpegdec.h
@@ -135,6 +135,17 @@  typedef struct MJpegDecodeContext {
     int *iccdatalens;
     int iccnum;
     int iccread;
+
+    // Raw stream data for hwaccel use.
+    const uint8_t *raw_buffer;
+    size_t         raw_buffer_size;
+
+    uint8_t raw_huffman_lengths[2][4][16];
+    uint8_t raw_huffman_values[2][4][256];
+
+    enum AVPixelFormat hwaccel_sw_pix_fmt;
+    enum AVPixelFormat hwaccel_pix_fmt;
+    void *hwaccel_picture_private;
 } MJpegDecodeContext;
 
 int ff_mjpeg_decode_init(AVCodecContext *avctx);