diff mbox

[FFmpeg-devel] lavf: Add DICOM demuxer

Message ID 72156996-f1cd-d782-61b6-b9cb983eecc4@iitk.ac.in
State New
Headers show

Commit Message

Shivam Goyal Aug. 24, 2019, 9:52 p.m. UTC
The patch contains DICOM demuxer. I have improved the code as suggested.

Please, push it as soon as possible, as i have to share the commit in 
GSoC final evaluation. if anything remain i would add it after that.

Thank you,

Shivam Goyal

Comments

Moritz Barsnick Aug. 26, 2019, 8:35 p.m. UTC | #1
On Sun, Aug 25, 2019 at 03:22:02 +0530, Shivam wrote:
> The patch contains DICOM demuxer. I have improved the code as suggested.

Second part of my review:

> From: Shivam Goyal <1998.goyal.shivam@gmail.com>
> Date: Sun, 25 Aug 2019 02:57:35 +0530
> Subject: [PATCH] lavf: Add DICOM demuxer
>
> ---
>  Changelog                |   1 +
>  libavformat/Makefile     |   1 +
>  libavformat/allformats.c |   1 +
>  libavformat/dicom.h      | 109 ++++++
>  libavformat/dicomdec.c   | 617 +++++++++++++++++++++++++++++++++
>  libavformat/dicomdict.c  | 711 +++++++++++++++++++++++++++++++++++++++
>  libavformat/version.h    |   2 +-
>  7 files changed, 1441 insertions(+), 1 deletion(-)
>  create mode 100644 libavformat/dicom.h
>  create mode 100644 libavformat/dicomdec.c
>  create mode 100644 libavformat/dicomdict.c

You still need to document the options in doc/*.texi.

> diff --git a/Changelog b/Changelog
> index 52096eed0e..5e5a8c5c6c 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -5,6 +5,7 @@ version <next>:
>  - v360 filter
>  - Intel QSV-accelerated MJPEG decoding
>  - Intel QSV-accelerated VP9 decoding
> +- DICOM demuxer

Here, this patch doesn't apply in top of the DICOM decoder, even though
it requires the decoder, because the decoder patch already adds another
line to the Changelog.

> --- /dev/null
> +++ b/libavformat/dicomdec.c
[...]
> +static void free_seq(DataElement *de) {
> +    int i = 0;
> +    DataElement *seq_data = de->bytes;
> +    for(; i < MAX_UNDEF_LENGTH; ++i) {

BTW, ffmpeg prefers the "i++" style.

[...]
> +// detects transfer syntax
> +static TransferSyntax get_transfer_sytax (const char *ts) {

There's still a typo in the name of the function, sytax -> syntax.
Please fix.

[...]
> +static int set_multiframe_data(AVFormatContext *s, AVStream* st, DataElement *de)
> +{

The return value still is always 0 and isn't being used for anything.
(I'm saying, this function could return void, unless it can be expanded
to something more later.)

> +    DICOMContext *dicom = s->priv_data;
> +
> +    if (de->GroupNumber != MF_GR_NB)
> +        return 0;
> +
> +    switch (de->ElementNumber) {
> +    case 0x1063: // frame time
> +        dicom->delay = conv_DS(de);
> +        dicom->duration = dicom->delay * dicom->nb_frames;
> +        break;
> +    }

Again, here, I expect this to be a switch/case with one case only if it
can be expanded later, i.e. de->ElementNumber has multiple meanings
which aren't covered here.

> +    return 0;
> +}
> +
> +
> +static int read_de_metainfo(AVFormatContext *s, DataElement *de)
> +{
[...]
> +    if (de->VL < 0)
> +        return AVERROR_INVALIDDATA;
> +    if (de->VL != UNDEFINED_VL && de->VL % 2)
> +        av_log(s, AV_LOG_WARNING,"Data Element Value length: %"PRIi64" can't be odd\n", de->VL);
                                    ^
Still missing a space here.

> +    return bytes_read;
> +}
> +
> +static int read_de(AVFormatContext *s, DataElement *de)
> +{
> +    int ret;
> +    uint32_t len = de->VL;
> +    de->bytes = av_malloc(len);
> +    ret = avio_read(s->pb, de->bytes, len);
> +    return ret;
> +}
> +
> +static int read_implicit_seq_item(AVFormatContext *s, DataElement *de)
> +{
> +    int ret, f = -2, i = 0;
> +    uint8_t *bytes = de->bytes;
> +
> +    bytes = av_malloc(MAX_UNDEF_LENGTH);

You're still not checking the return value and returning an error on
failure.

> +    for(; i < MAX_UNDEF_LENGTH; ++i) {

ffmpeg prefers the "i++" style.

[...]
> +static int read_seq(AVFormatContext *s, DataElement *de) {
> +    int i = 0, ret;
> +    DICOMContext *dicom = s->priv_data;
> +    DataElement *seq_data = av_malloc_array(MAX_SEQ_LENGTH, sizeof(DataElement));
> +
> +    de->bytes = seq_data;
> +    dicom->inseq = 1;
> +    for (;i < MAX_SEQ_LENGTH; ++i) {

ffmpeg prefers the "i++" style. (And missing a space after the first
semicolon.)

> +        seq_data[i].bytes = NULL;
> +        seq_data[i].desc = NULL;
> +        seq_data[i].is_found = 0;
> +        read_de_metainfo(s, seq_data + i);
> +        if (seq_data[i].GroupNumber == SEQ_GR_NB
> +            && seq_data[i].ElementNumber == SEQ_DEL_EL_NB) {
> +            ret = i;
> +            break;
> +        }
> +        if (seq_data[i].VL == UNDEFINED_VL)
> +            ret = read_implicit_seq_item(s, seq_data + i);

I believe these array elements are still not freed.

> +        else
> +            ret = read_de(s, seq_data + i);
> +        if (ret < 0)
> +            break;
> +    }
> +
> +    dicom->inseq = 0;
> +    return ret;
> +}
[...]
> +static int dicom_read_header(AVFormatContext *s)
> +{
> +    AVIOContext  *pb = s->pb;
> +    AVDictionary **m = &s->metadata;
> +    DICOMContext *dicom = s->priv_data;
> +    DataElement *de;
> +    char *key, *value;
> +    uint32_t header_size, bytes_read = 0;
> +    int ret;
> +
> +    ret = avio_skip(pb, DICOM_PREAMBLE_SIZE + DICOM_PREFIX_SIZE);
> +    if (ret < 0)
> +        return ret;
> +    dicom->inheader = 1;
> +    de = alloc_de();
> +    if (!de)
> +        return AVERROR(ENOMEM);
> +    ret = read_de_metainfo(s, de);
> +    if (ret < 0) {
> +        free_de(de);
> +        return ret;
> +    }
> +
> +    ret = read_de_valuefield(s, de);
> +    if (ret < 0) {
> +        free_de(de);
> +        return ret;
> +    }
> +    if (de->GroupNumber != 0x02 || de->ElementNumber != 0x00) {
> +        av_log(s, AV_LOG_WARNING, "First data element is not File MetaInfo Group Length, may fail to demux\n");
> +        header_size = 200; // Fallback to default length
> +    } else
> +        header_size = AV_RL32(de->bytes);
> +
> +    free_de(de);
> +    while (bytes_read < header_size) {
> +        de = alloc_de();

This can fail, like 20 lines above, so you also need to check for error
and return:
    if (!de)
        return AVERROR(ENOMEM);

> +        ret = read_de_metainfo(s, de);
> +        if (ret < 0) {
> +            free_de(de);
> +            return ret;
> +        }
> +        bytes_read += ret;
> +        dicom_dict_find_elem_info(de);
> +        key = get_key_str(de);
> +        ret = read_de_valuefield(s, de);
> +        if (ret < 0) {
> +            free_de(de);
> +            return ret;
> +        }
> +        bytes_read += ret;
> +        value = get_val_str(de);

a) get_val_str() tries to allocate memory, which may fail. Its return
value needs to be checked, and you need to return on failure.

b) This call of get_val_str() allocates memory assigned to "value", so
you need to av_free "value" on every possible exit path of this function.

> +        if (de->GroupNumber == TS_GR_NB && de->ElementNumber == TS_EL_NB) {
> +            dicom->transfer_syntax = get_transfer_sytax(value);
> +            if (dicom->transfer_syntax == UNSUPPORTED_TS) {
> +                free_de(de);
> +                av_log(s, AV_LOG_ERROR, "Provided Transfer syntax is not supported\n");
> +                return AVERROR_INVALIDDATA;
> +            }
> +        }
> +
> +        av_dict_set(m, key, value, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
> +        free_de(de);
> +    }
> +    set_context_defaults(dicom);
> +    s->ctx_flags |= AVFMTCTX_NOHEADER;
> +    s->start_time = 0;
> +    return 0;
> +}
> +
> +static int dicom_read_packet(AVFormatContext *s, AVPacket *pkt)
> +{
[...]
> +        inside_pix_data:
> +            if (av_new_packet(pkt, dicom->frame_size) < 0)
> +                return AVERROR(ENOMEM);
> +            pkt->pos = avio_tell(s->pb);
> +            pkt->stream_index = 0;
> +            pkt->size = dicom->frame_size;
> +            pkt->duration = dicom->delay;
> +            ret = avio_read(s->pb, pkt->data, dicom->frame_size);
> +            if (ret < 0) {
> +                av_packet_unref(pkt);
> +                break;
> +            }
> +            dicom->frame_nb ++;
> +            return ret;

The pkt still needs to be av_packet_unref()'d here, I believe.

[...]
> diff --git a/libavformat/version.h b/libavformat/version.h
> index 57002d25c8..c8f27cebf9 100644
> --- a/libavformat/version.h
> +++ b/libavformat/version.h
> @@ -32,7 +32,7 @@
>  // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
>  // Also please add any ticket numbers that you believe might be affected here
>  #define LIBAVFORMAT_VERSION_MAJOR  58
> -#define LIBAVFORMAT_VERSION_MINOR  31
> +#define LIBAVFORMAT_VERSION_MINOR  32
>  #define LIBAVFORMAT_VERSION_MICRO 102

When bumping MINOR, you need to reset MICRO to 100. But this part
doesn't apply anymore anyway, since MICRO has changed on master since.
You may need to rebase, but this will likely also be done by whoever
pushes to master once your patch is acknowledged.

Regards,
Moritz
Shivam Goyal Aug. 27, 2019, 7:14 p.m. UTC | #2
On 8/27/19 2:05 AM, Moritz Barsnick wrote:
> On Sun, Aug 25, 2019 at 03:22:02 +0530, Shivam wrote:
>> The patch contains DICOM demuxer. I have improved the code as suggested.
> Second part of my review:
>
>> From: Shivam Goyal <1998.goyal.shivam@gmail.com>
>> Date: Sun, 25 Aug 2019 02:57:35 +0530
>> Subject: [PATCH] lavf: Add DICOM demuxer
>>
>> ---
>>   Changelog                |   1 +
>>   libavformat/Makefile     |   1 +
>>   libavformat/allformats.c |   1 +
>>   libavformat/dicom.h      | 109 ++++++
>>   libavformat/dicomdec.c   | 617 +++++++++++++++++++++++++++++++++
>>   libavformat/dicomdict.c  | 711 +++++++++++++++++++++++++++++++++++++++
>>   libavformat/version.h    |   2 +-
>>   7 files changed, 1441 insertions(+), 1 deletion(-)
>>   create mode 100644 libavformat/dicom.h
>>   create mode 100644 libavformat/dicomdec.c
>>   create mode 100644 libavformat/dicomdict.c
> You still need to document the options in doc/*.texi.
Ok, i would add this.
>
>> diff --git a/Changelog b/Changelog
>> index 52096eed0e..5e5a8c5c6c 100644
>> --- a/Changelog
>> +++ b/Changelog
>> @@ -5,6 +5,7 @@ version <next>:
>>   - v360 filter
>>   - Intel QSV-accelerated MJPEG decoding
>>   - Intel QSV-accelerated VP9 decoding
>> +- DICOM demuxer
> Here, this patch doesn't apply in top of the DICOM decoder, even though
> it requires the decoder, because the decoder patch already adds another
> line to the Changelog.
>
>> --- /dev/null
>> +++ b/libavformat/dicomdec.c
> [...]
>> +static void free_seq(DataElement *de) {
>> +    int i = 0;
>> +    DataElement *seq_data = de->bytes;
>> +    for(; i < MAX_UNDEF_LENGTH; ++i) {
> BTW, ffmpeg prefers the "i++" style.
ok , would change this
>
> [...]
>> +// detects transfer syntax
>> +static TransferSyntax get_transfer_sytax (const char *ts) {
> There's still a typo in the name of the function, sytax -> syntax.
> Please fix.
Ok,l would change this
>
> [...]
>> +static int set_multiframe_data(AVFormatContext *s, AVStream* st, DataElement *de)
>> +{
> The return value still is always 0 and isn't being used for anything.
> (I'm saying, this function could return void, unless it can be expanded
> to something more later.)
Ok, would change this too
>
>> +    DICOMContext *dicom = s->priv_data;
>> +
>> +    if (de->GroupNumber != MF_GR_NB)
>> +        return 0;
>> +
>> +    switch (de->ElementNumber) {
>> +    case 0x1063: // frame time
>> +        dicom->delay = conv_DS(de);
>> +        dicom->duration = dicom->delay * dicom->nb_frames;
>> +        break;
>> +    }
> Again, here, I expect this to be a switch/case with one case only if it
> can be expanded later, i.e. de->ElementNumber has multiple meanings
> which aren't covered here.
This would be expanded in my next patch, so, i thought this may be correct.
>
>> +    return 0;
>> +}
>> +
>> +
>> +static int read_de_metainfo(AVFormatContext *s, DataElement *de)
>> +{
> [...]
>> +    if (de->VL < 0)
>> +        return AVERROR_INVALIDDATA;
>> +    if (de->VL != UNDEFINED_VL && de->VL % 2)
>> +        av_log(s, AV_LOG_WARNING,"Data Element Value length: %"PRIi64" can't be odd\n", de->VL);
>                                      ^
> Still missing a space here.
Ok, I would change this
>
>> +    return bytes_read;
>> +}
>> +
>> +static int read_de(AVFormatContext *s, DataElement *de)
>> +{
>> +    int ret;
>> +    uint32_t len = de->VL;
>> +    de->bytes = av_malloc(len);
>> +    ret = avio_read(s->pb, de->bytes, len);
>> +    return ret;
>> +}
>> +
>> +static int read_implicit_seq_item(AVFormatContext *s, DataElement *de)
>> +{
>> +    int ret, f = -2, i = 0;
>> +    uint8_t *bytes = de->bytes;
>> +
>> +    bytes = av_malloc(MAX_UNDEF_LENGTH);
> You're still not checking the return value and returning an error on
> failure.
>
>> +    for(; i < MAX_UNDEF_LENGTH; ++i) {
> ffmpeg prefers the "i++" style.
>
> [...]
>> +static int read_seq(AVFormatContext *s, DataElement *de) {
>> +    int i = 0, ret;
>> +    DICOMContext *dicom = s->priv_data;
>> +    DataElement *seq_data = av_malloc_array(MAX_SEQ_LENGTH, sizeof(DataElement));
>> +
>> +    de->bytes = seq_data;
>> +    dicom->inseq = 1;
>> +    for (;i < MAX_SEQ_LENGTH; ++i) {
> ffmpeg prefers the "i++" style. (And missing a space after the first
> semicolon.)
>
>> +        seq_data[i].bytes = NULL;
>> +        seq_data[i].desc = NULL;
>> +        seq_data[i].is_found = 0;
>> +        read_de_metainfo(s, seq_data + i);
>> +        if (seq_data[i].GroupNumber == SEQ_GR_NB
>> +            && seq_data[i].ElementNumber == SEQ_DEL_EL_NB) {
>> +            ret = i;
>> +            break;
>> +        }
>> +        if (seq_data[i].VL == UNDEFINED_VL)
>> +            ret = read_implicit_seq_item(s, seq_data + i);
> I believe these array elements are still not freed.
These should be freed as i have debugged it and changed the free_de() 
function, it detects if the DE is an array or not and handles it that way.
>
>> +        else
>> +            ret = read_de(s, seq_data + i);
>> +        if (ret < 0)
>> +            break;
>> +    }
>> +
>> +    dicom->inseq = 0;
>> +    return ret;
>> +}
> [...]
>> +static int dicom_read_header(AVFormatContext *s)
>> +{
>> +    AVIOContext  *pb = s->pb;
>> +    AVDictionary **m = &s->metadata;
>> +    DICOMContext *dicom = s->priv_data;
>> +    DataElement *de;
>> +    char *key, *value;
>> +    uint32_t header_size, bytes_read = 0;
>> +    int ret;
>> +
>> +    ret = avio_skip(pb, DICOM_PREAMBLE_SIZE + DICOM_PREFIX_SIZE);
>> +    if (ret < 0)
>> +        return ret;
>> +    dicom->inheader = 1;
>> +    de = alloc_de();
>> +    if (!de)
>> +        return AVERROR(ENOMEM);
>> +    ret = read_de_metainfo(s, de);
>> +    if (ret < 0) {
>> +        free_de(de);
>> +        return ret;
>> +    }
>> +
>> +    ret = read_de_valuefield(s, de);
>> +    if (ret < 0) {
>> +        free_de(de);
>> +        return ret;
>> +    }
>> +    if (de->GroupNumber != 0x02 || de->ElementNumber != 0x00) {
>> +        av_log(s, AV_LOG_WARNING, "First data element is not File MetaInfo Group Length, may fail to demux\n");
>> +        header_size = 200; // Fallback to default length
>> +    } else
>> +        header_size = AV_RL32(de->bytes);
>> +
>> +    free_de(de);
>> +    while (bytes_read < header_size) {
>> +        de = alloc_de();
> This can fail, like 20 lines above, so you also need to check for error
> and return:
>      if (!de)
>          return AVERROR(ENOMEM);
Ok, would change this too
>
>> +        ret = read_de_metainfo(s, de);
>> +        if (ret < 0) {
>> +            free_de(de);
>> +            return ret;
>> +        }
>> +        bytes_read += ret;
>> +        dicom_dict_find_elem_info(de);
>> +        key = get_key_str(de);
>> +        ret = read_de_valuefield(s, de);
>> +        if (ret < 0) {
>> +            free_de(de);
>> +            return ret;
>> +        }
>> +        bytes_read += ret;
>> +        value = get_val_str(de);
> a) get_val_str() tries to allocate memory, which may fail. Its return
> value needs to be checked, and you need to return on failure.
>
> b) This call of get_val_str() allocates memory assigned to "value", so
> you need to av_free "value" on every possible exit path of this function.

I am using the av_dict_set function with "AV_DICT_DONT_STRDUP_KEY" below 
so, should i still need to free the key and value at the bottom.

(I mean i understood that i should free them on every error or Invalid 
data.)

>> +        if (de->GroupNumber == TS_GR_NB && de->ElementNumber == TS_EL_NB) {
>> +            dicom->transfer_syntax = get_transfer_sytax(value);
>> +            if (dicom->transfer_syntax == UNSUPPORTED_TS) {
>> +                free_de(de);
>> +                av_log(s, AV_LOG_ERROR, "Provided Transfer syntax is not supported\n");
>> +                return AVERROR_INVALIDDATA;
>> +            }
>> +        }
>> +
>> +        av_dict_set(m, key, value, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
>> +        free_de(de);
>> +    }
>> +    set_context_defaults(dicom);
>> +    s->ctx_flags |= AVFMTCTX_NOHEADER;
>> +    s->start_time = 0;
>> +    return 0;
>> +}
>> +
>> +static int dicom_read_packet(AVFormatContext *s, AVPacket *pkt)
>> +{
> [...]
>> +        inside_pix_data:
>> +            if (av_new_packet(pkt, dicom->frame_size) < 0)
>> +                return AVERROR(ENOMEM);
>> +            pkt->pos = avio_tell(s->pb);
>> +            pkt->stream_index = 0;
>> +            pkt->size = dicom->frame_size;
>> +            pkt->duration = dicom->delay;
>> +            ret = avio_read(s->pb, pkt->data, dicom->frame_size);
>> +            if (ret < 0) {
>> +                av_packet_unref(pkt);
>> +                break;
>> +            }
>> +            dicom->frame_nb ++;
>> +            return ret;
> The pkt still needs to be av_packet_unref()'d here, I believe
should the packet needs to cleaned after filling the pixel data inside it ?
>
> [...]
>> diff --git a/libavformat/version.h b/libavformat/version.h
>> index 57002d25c8..c8f27cebf9 100644
>> --- a/libavformat/version.h
>> +++ b/libavformat/version.h
>> @@ -32,7 +32,7 @@
>>   // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
>>   // Also please add any ticket numbers that you believe might be affected here
>>   #define LIBAVFORMAT_VERSION_MAJOR  58
>> -#define LIBAVFORMAT_VERSION_MINOR  31
>> +#define LIBAVFORMAT_VERSION_MINOR  32
>>   #define LIBAVFORMAT_VERSION_MICRO 102
> When bumping MINOR, you need to reset MICRO to 100. But this part
> doesn't apply anymore anyway, since MICRO has changed on master since.
> You may need to rebase, but this will likely also be done by whoever
> pushes to master once your patch is acknowledged.

Ok,

Thanks for the review

Shivam Goyal
Moritz Barsnick Aug. 28, 2019, 10:16 p.m. UTC | #3
On Wed, Aug 28, 2019 at 00:44:24 +0530, Shivam wrote:
> > Again, here, I expect this to be a switch/case with one case only if it
> > can be expanded later, i.e. de->ElementNumber has multiple meanings
> > which aren't covered here.
> This would be expanded in my next patch, so, i thought this may be correct.

It's okay then, as far as I'm concerned.
> >> +        if (seq_data[i].VL == UNDEFINED_VL)
> >> +            ret = read_implicit_seq_item(s, seq_data + i);
> > I believe these array elements are still not freed.
> These should be freed as i have debugged it and changed the free_de()
> function, it detects if the DE is an array or not and handles it that way.

Okay, I didn't see that. Fine then.

> > a) get_val_str() tries to allocate memory, which may fail. Its return
> > value needs to be checked, and you need to return on failure.
> >
> > b) This call of get_val_str() allocates memory assigned to "value", so
> > you need to av_free "value" on every possible exit path of this function.
>
> I am using the av_dict_set function with "AV_DICT_DONT_STRDUP_KEY" below
> so, should i still need to free the key and value at the bottom.

I didn't see the use of AV_DICT_DONT_STRDUP_KEY. I assume it's fine
then.

> >> +            }
> >> +            dicom->frame_nb ++;
> >> +            return ret;
> > The pkt still needs to be av_packet_unref()'d here, I believe
> should the packet needs to cleaned after filling the pixel data inside it ?

Hmm, not sure.

> Thanks for the review

Please do make sure you get some other reviews. I'm not always 100 %
right, obviously, and not always 100 % sure.

Cheers,
Moritz
diff mbox

Patch

From e76ce45b2f7c0e6ce9706cbcb62da147e56e3e61 Mon Sep 17 00:00:00 2001
From: Shivam Goyal <1998.goyal.shivam@gmail.com>
Date: Sun, 25 Aug 2019 02:57:35 +0530
Subject: [PATCH] lavf: Add DICOM demuxer

---
 Changelog                |   1 +
 libavformat/Makefile     |   1 +
 libavformat/allformats.c |   1 +
 libavformat/dicom.h      | 109 ++++++
 libavformat/dicomdec.c   | 617 +++++++++++++++++++++++++++++++++
 libavformat/dicomdict.c  | 711 +++++++++++++++++++++++++++++++++++++++
 libavformat/version.h    |   2 +-
 7 files changed, 1441 insertions(+), 1 deletion(-)
 create mode 100644 libavformat/dicom.h
 create mode 100644 libavformat/dicomdec.c
 create mode 100644 libavformat/dicomdict.c

diff --git a/Changelog b/Changelog
index 52096eed0e..5e5a8c5c6c 100644
--- a/Changelog
+++ b/Changelog
@@ -5,6 +5,7 @@  version <next>:
 - v360 filter
 - Intel QSV-accelerated MJPEG decoding
 - Intel QSV-accelerated VP9 decoding
+- DICOM demuxer
 
 version 4.2:
 - tpad filter
diff --git a/libavformat/Makefile b/libavformat/Makefile
index a434b005a4..58ba6a4c36 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -150,6 +150,7 @@  OBJS-$(CONFIG_DAUD_MUXER)                += daudenc.o
 OBJS-$(CONFIG_DCSTR_DEMUXER)             += dcstr.o
 OBJS-$(CONFIG_DFA_DEMUXER)               += dfa.o
 OBJS-$(CONFIG_DHAV_DEMUXER)              += dhav.o
+OBJS-$(CONFIG_DICOM_DEMUXER)             += dicomdec.o dicomdict.o
 OBJS-$(CONFIG_DIRAC_DEMUXER)             += diracdec.o rawdec.o
 OBJS-$(CONFIG_DIRAC_MUXER)               += rawenc.o
 OBJS-$(CONFIG_DNXHD_DEMUXER)             += dnxhddec.o rawdec.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index cd00834807..c5120ef1df 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -111,6 +111,7 @@  extern AVOutputFormat ff_daud_muxer;
 extern AVInputFormat  ff_dcstr_demuxer;
 extern AVInputFormat  ff_dfa_demuxer;
 extern AVInputFormat  ff_dhav_demuxer;
+extern AVInputFormat  ff_dicom_demuxer;
 extern AVInputFormat  ff_dirac_demuxer;
 extern AVOutputFormat ff_dirac_muxer;
 extern AVInputFormat  ff_dnxhd_demuxer;
diff --git a/libavformat/dicom.h b/libavformat/dicom.h
new file mode 100644
index 0000000000..e9a8a8dc70
--- /dev/null
+++ b/libavformat/dicom.h
@@ -0,0 +1,109 @@ 
+/*
+ * DICOM demuxer
+ *
+ * Copyright (c) 2019 Shivam Goyal
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#define DICOM_PREAMBLE_SIZE 128
+#define DICOM_PREFIX_SIZE   4
+
+#define IMAGE_GR_NB     0x0028
+#define MF_GR_NB        0x0018
+#define PIXEL_GR_NB     0x7FE0
+#define PIXELDATA_EL_NB 0x0010
+#define TS_GR_NB        0x0002
+#define TS_EL_NB        0x0010
+#define UNDEFINED_VL    0xFFFFFFFF
+#define DEFAULT_WINDOW  1100
+#define DEFAULT_LEVEL   125
+#define DECODER_ED_SIZE 20
+
+#define SEQ_GR_NB           0xFFFE
+#define SEQ_DEL_EL_NB       0xE0DD
+#define SEQ_ITEM_BEG_EL_NB  0xE000
+#define SEQ_ITEM_DEL_EL_NB  0xE00D
+#define MAX_UNDEF_LENGTH    5000   // max undefined length
+#define MAX_SEQ_LENGTH      20     // max sequence length (items)
+
+typedef enum {
+    UNSUPPORTED_TS = 0,
+    IMPLICIT_VR = 1,
+    EXPLICIT_VR = 2,
+    DEFLATE_EXPLICIT_VR = 3,
+    JPEG_BASE_8 = 4,
+    JPEG_EXT_12 = 5,
+    JPEG_LOSSLESS_NH_P14 = 6,
+    JPEG_LOSSLESS_NH_P14_S1 = 7,
+    JPEG_LS_LOSSLESS = 8,
+    JPEG_LS_LOSSY = 9,
+    JPEG2000_LOSSLESS = 10,
+    JPEG2000 = 11,
+    RLE = 12
+} TransferSyntax;
+
+typedef enum {
+    AE = 0x4145,
+    AS = 0x4153,
+    AT = 0x4154,
+    CS = 0x4353,
+    DA = 0x4441,
+    DS = 0x4453,
+    DT = 0x4454,
+    FD = 0x4644,
+    FL = 0x464c,
+    IS = 0x4953,
+    LO = 0x4c4f,
+    LT = 0x4c54,
+    OB = 0x4f42,
+    OD = 0x4f44,
+    OF = 0x4f46,
+    OL = 0x4f4c,
+    OV = 0x4f56,
+    OW = 0x4f57,
+    PN = 0x504e,
+    SH = 0x5348,
+    SL = 0x534c,
+    SQ = 0x5351,
+    SS = 0x5353,
+    ST = 0x5354,
+    SV = 0x5356,
+    TM = 0x544d,
+    UC = 0x5543,
+    UI = 0x5549,
+    UL = 0x554c,
+    UN = 0x554e,
+    UR = 0x5552,
+    US = 0x5553,
+    UT = 0x5554,
+    UV = 0x5556
+} ValueRepresentation;
+
+
+typedef struct DataElement {
+    uint16_t GroupNumber;
+    uint16_t ElementNumber;
+    ValueRepresentation VR;
+    int64_t VL;
+    void *bytes;
+    int is_found; // is found in DICOM dictionary
+    char *desc; // description (from dicom dictionary)
+} DataElement;
+
+int dicom_dict_find_elem_info (DataElement *de);
diff --git a/libavformat/dicomdec.c b/libavformat/dicomdec.c
new file mode 100644
index 0000000000..d288f79da2
--- /dev/null
+++ b/libavformat/dicomdec.c
@@ -0,0 +1,617 @@ 
+/*
+ * DICOM demuxer
+ *
+ * Copyright (c) 2019 Shivam Goyal
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/dict.h"
+#include "libavutil/opt.h"
+#include "libavutil/bprint.h"
+#include "libavcodec/bytestream.h"
+#include "avformat.h"
+#include "internal.h"
+#include "dicom.h"
+
+
+typedef struct DICOMContext {
+    const AVClass *class;
+
+    int interpret, pixrep, slope, intcpt, samples_ppix;
+    uint16_t width;
+    uint16_t height;
+    uint64_t nb_frames;
+    uint64_t frame_size;
+    int frame_nb;
+    double delay;
+    int duration;
+    int inheader;
+    int inseq;
+    int32_t pixpad;
+    TransferSyntax transfer_syntax;
+
+    int window; // Options
+    int level;
+    int metadata;
+} DICOMContext;
+
+
+static int dicom_probe(const AVProbeData *p)
+{
+    if (!strncmp(p->buf + DICOM_PREAMBLE_SIZE, "DICM", 4))
+        return AVPROBE_SCORE_MAX;
+    return 0;
+}
+
+static DataElement *alloc_de(void) {
+    DataElement *de = (DataElement *) av_malloc(sizeof(DataElement));
+    de->is_found = 0;
+    de->desc = NULL;
+    de->bytes = NULL;
+    return de;
+}
+
+static void free_seq(DataElement *de) {
+    int i = 0;
+    DataElement *seq_data = de->bytes;
+    for(; i < MAX_UNDEF_LENGTH; ++i) {
+        if (seq_data[i].ElementNumber == SEQ_DEL_EL_NB)
+            return;
+        av_free(seq_data[i].bytes);
+    }
+}
+
+static void free_de(DataElement *de) {
+    if (!de)
+        return;
+    if (de->VL == UNDEFINED_VL)
+        free_seq(de);
+    av_free(de->bytes);
+    av_free(de->desc);
+    av_free(de);
+}
+
+static void set_context_defaults(DICOMContext *dicom) {
+    dicom->interpret = 0x02; // 2 for MONOCHROME2, 1 for MONOCHROME1
+    dicom->pixrep = 1;
+    dicom->pixpad = 1 << 31;
+    dicom->slope = 1;
+    dicom->intcpt = 0;
+    dicom->samples_ppix = 1;
+
+    dicom->delay = 100;
+    dicom->frame_nb = 1;
+    dicom->nb_frames = 1;
+    dicom->inseq = 0;
+}
+
+// detects transfer syntax
+static TransferSyntax get_transfer_sytax (const char *ts) {
+    if (!strcmp(ts, "1.2.840.10008.1.2"))
+        return IMPLICIT_VR;
+    else if (!strcmp(ts, "1.2.840.10008.1.2.1"))
+        return EXPLICIT_VR;
+    else
+        return UNSUPPORTED_TS;
+}
+
+static int find_PI(const char *pi) {
+    if (!strcmp(pi, "MONOCHROME1 "))
+        return 0x01;
+    else if (!strcmp(pi, "MONOCHROME2 "))
+        return 0x02;
+    else if (!strcmp(pi, "PALETTE COLOR "))
+        return 0x03;
+    else if (!strcmp(pi, "RGB "))
+        return 0x04;
+    else return 0x00;
+}
+
+static void set_dec_extradata(AVFormatContext *s, AVStream *st) {
+    DICOMContext *dicom = s->priv_data;
+    uint8_t *edp;
+    int size = DECODER_ED_SIZE + AV_INPUT_BUFFER_PADDING_SIZE;
+
+    st->codecpar->extradata = (uint8_t *)av_malloc(size);
+    edp = st->codecpar->extradata;
+    bytestream_put_le32(&edp, dicom->interpret);
+    bytestream_put_le32(&edp, dicom->pixrep);
+    bytestream_put_le32(&edp, dicom->pixpad);
+    bytestream_put_le32(&edp, dicom->slope);
+    bytestream_put_le32(&edp, dicom->intcpt);
+    st->codecpar->extradata_size = size;
+}
+
+static double conv_DS(DataElement *de) {
+    double ret;
+    char *cbytes = av_malloc(de->VL + 1);
+
+    memcpy(cbytes, de->bytes, de->VL);
+    cbytes[de->VL] = 0;
+    ret = atof(cbytes);
+    av_free(cbytes);
+    return ret;
+}
+
+static int conv_IS(DataElement *de) {
+    int ret;
+    char *cbytes = av_malloc(de->VL + 1);
+
+    memcpy(cbytes, de->bytes, de->VL);
+    cbytes[de->VL] = 0;
+    ret = atoi(cbytes);
+    av_free(cbytes);
+    return ret;
+}
+
+
+static char *get_key_str(DataElement *de) {
+    int len;
+    char *key;
+    if (!de->GroupNumber || !de->ElementNumber)
+        return 0;
+    len = 15 + strlen(de->desc);
+    key = (char *) av_malloc(len);
+    snprintf(key, len, "(%04x,%04x) %s", de->GroupNumber, de->ElementNumber, de->desc);
+    return key;
+}
+
+static char *get_val_str(DataElement *de) {
+    char *val;
+
+    switch(de->VR) {
+    case AT:
+    case OB:
+    case OD:
+    case OF:
+    case OL:
+    case OV:
+    case OW:
+        val = av_strdup("[Binary data]");
+        break;
+    case UN:
+    case SQ:
+        val = av_strdup("[Sequence of items]");
+        break;
+    case FL:
+        val = (char *) av_malloc(15);
+        snprintf(val, 15, "%.3f", ((float *)de->bytes)[0]);
+        break;
+    case FD:
+        val = (char *) av_malloc(20);
+        snprintf(val, 20, "%.3lf", ((double *)de->bytes)[0]);
+        break;
+    case SL:
+        val = (char *) av_malloc(15);
+        snprintf(val, 15, "%d", AV_RL32(de->bytes));
+        break;
+    case SS:
+        val = (char *) av_malloc(10);
+        snprintf(val, 10, "%d", AV_RL16(de->bytes));
+        break;
+    case SV:
+        val = (char *) av_malloc(25);
+        snprintf(val, 25, "%"PRId64, AV_RL64(de->bytes));
+        break;
+    case UL:
+        val = (char *) av_malloc(15);
+        snprintf(val, 15, "%u", AV_RL32(de->bytes));
+        break;
+    case US:
+        val = (char *) av_malloc(10);
+        snprintf(val, 10, "%u", AV_RL16(de->bytes));
+        break;
+    case UV:
+        val = (char *) av_malloc(25);
+        snprintf(val, 25, "%"PRId64, AV_RL64(de->bytes));
+        break;
+    default:
+        val = (char *) av_malloc(de->VL + 1);
+        memcpy(val, de->bytes, de->VL);
+        val[de->VL] = 0;
+        break;
+    }
+    return val;
+}
+
+static int set_imagegroup_data(AVFormatContext *s, AVStream* st, DataElement *de)
+{
+    DICOMContext *dicom = s->priv_data;
+    void *bytes = de->bytes;
+    int len = de->VL;
+    char *cbytes;
+
+    if (de->GroupNumber != IMAGE_GR_NB)
+        return 0;
+
+    switch (de->ElementNumber) {
+    case 0x0010: // rows
+        dicom->height = AV_RL16(bytes);
+        st->codecpar->height = dicom->height;
+        break;
+    case 0x0011: // columns
+        dicom->width = AV_RL16(bytes);
+        st->codecpar->width = dicom->width;
+        break;
+    case 0x0100: // bits allocated
+        st->codecpar->bits_per_raw_sample = AV_RL16(bytes);
+        break;
+    case 0x0101: // bits stored
+        st->codecpar->bits_per_coded_sample = AV_RL16(bytes);
+        break;
+    case 0x0008: // number of frames
+        dicom->nb_frames = conv_IS(de);
+        st->nb_frames = dicom->nb_frames;
+        st->duration = dicom->delay * dicom->nb_frames;
+        break;
+    case 0x1050: // window center/level
+        if (dicom->level == -1) {
+            st->codecpar->level = conv_IS(de);
+            dicom->level = st->codecpar->level;
+        }
+        break;
+    case 0x1051: // window width/window
+        if (dicom->window == -1) {
+            st->codecpar->profile = conv_IS(de);
+            dicom->window = st->codecpar->profile;
+        }
+        break;
+    case 0x0120: // pixel padding
+        dicom->pixpad = AV_RL16(bytes);
+        break;
+    case 0x0004: // photometric interpret
+        cbytes = av_malloc(len + 1);
+        memcpy(cbytes, bytes, len);
+        cbytes[len] = 0;
+        dicom->interpret = find_PI(cbytes);
+        av_free(cbytes);
+        break;
+    case 0x0103: // pix rep
+        dicom->pixrep = AV_RL16(bytes);
+        break;
+    case 0x1053: // rescale slope
+        dicom->slope = conv_IS(de);
+        break;
+    case 0x1052: // rescale intercept
+        dicom->intcpt = conv_IS(de);
+        break;
+    }
+    return 0;
+}
+
+static int set_multiframe_data(AVFormatContext *s, AVStream* st, DataElement *de)
+{
+    DICOMContext *dicom = s->priv_data;
+
+    if (de->GroupNumber != MF_GR_NB)
+        return 0;
+
+    switch (de->ElementNumber) {
+    case 0x1063: // frame time
+        dicom->delay = conv_DS(de);
+        dicom->duration = dicom->delay * dicom->nb_frames;
+        break;
+    }
+    return 0;
+}
+
+
+static int read_de_metainfo(AVFormatContext *s, DataElement *de)
+{
+    DICOMContext *dicom = s->priv_data;
+    ValueRepresentation vr;
+    int ret;
+    int bytes_read = 0;
+
+    ret = avio_rl16(s->pb);
+    if (ret < 0)
+        return ret;
+    de->GroupNumber = ret;
+    de->ElementNumber =  avio_rl16(s->pb);
+    if (dicom->inseq || (dicom->transfer_syntax == IMPLICIT_VR && !dicom->inheader)) {
+        de->VL = avio_rl32(s->pb);
+        bytes_read += 8;
+        return bytes_read;
+    }
+    vr = avio_rb16(s->pb); // Stored in Big Endian in dicom.h
+    de->VR = vr;
+    bytes_read += 6;
+    switch (vr) {
+    case OB:
+    case OD:
+    case OF:
+    case OL:
+    case OV:
+    case OW:
+    case SQ:
+    case SV:
+    case UC:
+    case UR:
+    case UT:
+    case UN:
+    case UV:
+        avio_skip(s->pb, 2); // Padding always 0x0000
+        de->VL = avio_rl32(s->pb);
+        bytes_read += 6;
+        break;
+    default:
+        de->VL = avio_rl16(s->pb);
+        bytes_read += 2;
+        break;
+    }
+    if (de->VL < 0)
+        return AVERROR_INVALIDDATA;
+    if (de->VL != UNDEFINED_VL && de->VL % 2)
+        av_log(s, AV_LOG_WARNING,"Data Element Value length: %"PRIi64" can't be odd\n", de->VL);
+    return bytes_read;
+}
+
+static int read_de(AVFormatContext *s, DataElement *de)
+{
+    int ret;
+    uint32_t len = de->VL;
+    de->bytes = av_malloc(len);
+    ret = avio_read(s->pb, de->bytes, len);
+    return ret;
+}
+
+static int read_implicit_seq_item(AVFormatContext *s, DataElement *de)
+{
+    int ret, f = -2, i = 0;
+    uint8_t *bytes = de->bytes;
+
+    bytes = av_malloc(MAX_UNDEF_LENGTH);
+    for(; i < MAX_UNDEF_LENGTH; ++i) {
+        ret = avio_rl16(s->pb);
+        if (ret < 0)
+            return ret;
+
+        if (ret == SEQ_GR_NB)
+            f = i;
+        else if (ret == SEQ_ITEM_DEL_EL_NB && f == i - 1) {
+            avio_skip(s->pb, 4);
+            break;
+        }
+        bytestream_put_le16(&bytes, ret);
+    }
+    de->VL = (i - 1) * 2;
+    return 0;
+}
+
+static int read_seq(AVFormatContext *s, DataElement *de) {
+    int i = 0, ret;
+    DICOMContext *dicom = s->priv_data;
+    DataElement *seq_data = av_malloc_array(MAX_SEQ_LENGTH, sizeof(DataElement));
+
+    de->bytes = seq_data;
+    dicom->inseq = 1;
+    for (;i < MAX_SEQ_LENGTH; ++i) {
+        seq_data[i].bytes = NULL;
+        seq_data[i].desc = NULL;
+        seq_data[i].is_found = 0;
+        read_de_metainfo(s, seq_data + i);
+        if (seq_data[i].GroupNumber == SEQ_GR_NB
+            && seq_data[i].ElementNumber == SEQ_DEL_EL_NB) {
+            ret = i;
+            break;
+        }
+        if (seq_data[i].VL == UNDEFINED_VL)
+            ret = read_implicit_seq_item(s, seq_data + i);
+        else
+            ret = read_de(s, seq_data + i);
+        if (ret < 0)
+            break;
+    }
+
+    dicom->inseq = 0;
+    return ret;
+}
+
+static int read_de_valuefield(AVFormatContext *s, DataElement *de) {
+    if (de->VL == UNDEFINED_VL)
+        return read_seq(s, de);
+    else
+        return read_de(s, de);
+}
+
+static int dicom_read_header(AVFormatContext *s)
+{
+    AVIOContext  *pb = s->pb;
+    AVDictionary **m = &s->metadata;
+    DICOMContext *dicom = s->priv_data;
+    DataElement *de;
+    char *key, *value;
+    uint32_t header_size, bytes_read = 0;
+    int ret;
+
+    ret = avio_skip(pb, DICOM_PREAMBLE_SIZE + DICOM_PREFIX_SIZE);
+    if (ret < 0)
+        return ret;
+    dicom->inheader = 1;
+    de = alloc_de();
+    if (!de)
+        return AVERROR(ENOMEM);
+    ret = read_de_metainfo(s, de);
+    if (ret < 0) {
+        free_de(de);
+        return ret;
+    }
+
+    ret = read_de_valuefield(s, de);
+    if (ret < 0) {
+        free_de(de);
+        return ret;
+    }
+    if (de->GroupNumber != 0x02 || de->ElementNumber != 0x00) {
+        av_log(s, AV_LOG_WARNING, "First data element is not File MetaInfo Group Length, may fail to demux\n");
+        header_size = 200; // Fallback to default length
+    } else
+        header_size = AV_RL32(de->bytes);
+
+    free_de(de);
+    while (bytes_read < header_size) {
+        de = alloc_de();
+        ret = read_de_metainfo(s, de);
+        if (ret < 0) {
+            free_de(de);
+            return ret;
+        }
+        bytes_read += ret;
+        dicom_dict_find_elem_info(de);
+        key = get_key_str(de);
+        ret = read_de_valuefield(s, de);
+        if (ret < 0) {
+            free_de(de);
+            return ret;
+        }
+        bytes_read += ret;
+        value = get_val_str(de);
+        if (de->GroupNumber == TS_GR_NB && de->ElementNumber == TS_EL_NB) {
+            dicom->transfer_syntax = get_transfer_sytax(value);
+            if (dicom->transfer_syntax == UNSUPPORTED_TS) {
+                free_de(de);
+                av_log(s, AV_LOG_ERROR, "Provided Transfer syntax is not supported\n");
+                return AVERROR_INVALIDDATA;
+            }
+        }
+
+        av_dict_set(m, key, value, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
+        free_de(de);
+    }
+    set_context_defaults(dicom);
+    s->ctx_flags |= AVFMTCTX_NOHEADER;
+    s->start_time = 0;
+    return 0;
+}
+
+static int dicom_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    DICOMContext *dicom = s->priv_data;
+    int metadata = dicom->metadata, ret;
+    AVDictionary **st_md;
+    char *key, *value;
+    AVStream  *st;
+    DataElement *de;
+
+    if (s->nb_streams < 1) {
+        st = avformat_new_stream(s, NULL);
+        if (!st)
+            return AVERROR(ENOMEM);
+        st->codecpar->codec_id   = AV_CODEC_ID_DICOM;
+        st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+        st->start_time = 0;
+        avpriv_set_pts_info(st, 64, 1, 1000);
+        if (dicom->window != -1)
+            st->codecpar->profile = dicom->window;
+        if (dicom->level != -1)
+            st->codecpar->level = dicom->level;
+    } else
+        st = s->streams[0];
+
+    st_md = &st->metadata;
+    dicom->inheader = 0;
+    if (dicom->frame_nb > 1 && dicom->frame_nb <= dicom->nb_frames)
+        goto inside_pix_data;
+
+    for (;;) {
+        ret = avio_feof(s->pb);
+        if (ret)
+            return AVERROR_EOF;
+
+        de = alloc_de();
+        if (!de)
+            return AVERROR(ENOMEM);
+
+        ret = read_de_metainfo(s,de);
+        if (ret < 0)
+            break;
+
+        if (de->GroupNumber == PIXEL_GR_NB && de->ElementNumber == PIXELDATA_EL_NB) {
+            dicom->frame_size = de->VL / dicom->nb_frames;
+            free_de(de);
+            set_dec_extradata(s, st);
+        inside_pix_data:
+            if (av_new_packet(pkt, dicom->frame_size) < 0)
+                return AVERROR(ENOMEM);
+            pkt->pos = avio_tell(s->pb);
+            pkt->stream_index = 0;
+            pkt->size = dicom->frame_size;
+            pkt->duration = dicom->delay;
+            ret = avio_read(s->pb, pkt->data, dicom->frame_size);
+            if (ret < 0) {
+                av_packet_unref(pkt);
+                break;
+            }
+            dicom->frame_nb ++;
+            return ret;
+        } else if (de->GroupNumber == IMAGE_GR_NB || de->GroupNumber == MF_GR_NB) {
+            ret = read_de_valuefield(s, de);
+            if (ret < 0)
+                break;
+            set_imagegroup_data(s, st, de);
+            set_multiframe_data(s, st, de);
+        } else {
+            if (metadata || de->VL == UNDEFINED_VL)
+                ret = read_de_valuefield(s, de);
+            else
+                ret = avio_skip(s->pb, de->VL); // skip other elements
+            if (ret < 0)
+                break;
+        }
+        if (metadata) {
+            ret = dicom_dict_find_elem_info(de);
+            if (ret < 0)
+                goto end_de;
+            key = get_key_str(de);
+            value = get_val_str(de);
+            av_dict_set(st_md, key, value, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
+        }
+    end_de:
+        free_de(de);
+    }
+    free_de(de);
+    if (ret < 0)
+        return ret;
+    return AVERROR_EOF;
+}
+
+static const AVOption options[] = {
+    { "window"  , "Override default window found in file" , offsetof(DICOMContext, window), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 99999, AV_OPT_FLAG_DECODING_PARAM },
+    { "level"   , "Override default level found in file"  , offsetof(DICOMContext, level), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 99999, AV_OPT_FLAG_DECODING_PARAM },
+    { "metadata", "Set true to decode metadata (info about the patient, medical procedure)", offsetof(DICOMContext, metadata), AV_OPT_TYPE_BOOL,{.i64 = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
+    { NULL },
+};
+
+static const AVClass dicom_class = {
+    .class_name = "DICOM demuxer",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_dicom_demuxer = {
+    .name           = "dicom",
+    .long_name      = NULL_IF_CONFIG_SMALL("DICOM (Digital Imaging and Communications in Medicine)"),
+    .priv_data_size = sizeof(DICOMContext),
+    .read_probe     = dicom_probe,
+    .read_header    = dicom_read_header,
+    .read_packet    = dicom_read_packet,
+    .extensions     = "dcm",
+    .priv_class     = &dicom_class,
+};
diff --git a/libavformat/dicomdict.c b/libavformat/dicomdict.c
new file mode 100644
index 0000000000..c043e320ac
--- /dev/null
+++ b/libavformat/dicomdict.c
@@ -0,0 +1,711 @@ 
+/*
+ * DICOM Dictionary
+ *
+ * Copyright (c) 2019 Shivam Goyal
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/mem.h"
+#include "dicom.h"
+
+typedef struct DICOMDictionary {
+    uint16_t GroupNumber;
+    uint16_t ElementNumber;
+    ValueRepresentation vr;
+    const char *desc;
+} DICOMDictionary;
+
+/**
+ * dicom_dictionary[] to store dicom tags value rep
+ * and desc.
+ *
+ * On adding new data elements to dicom_dictionary[]
+ * always keep them in ascending order of GroupNumber
+ * and ElementNumber
+*/
+DICOMDictionary dicom_dictionary[] = {
+    {0x0002, 0x0000, UL, "File Meta Elements Group Len"},
+    {0x0002, 0x0001, OB, "File Meta Information Version"},
+    {0x0002, 0x0002, UI, "Media Storage SOP Class UID"},
+    {0x0002, 0x0003, UI, "Media Storage SOP Inst UID"},
+    {0x0002, 0x0010, UI, "Transfer Syntax UID"},
+    {0x0002, 0x0012, UI, "Implementation Class UID"},
+    {0x0002, 0x0013, SH, "Implementation Version Name"},
+    {0x0002, 0x0016, AE, "Source Application Entity Title"},
+    {0x0002, 0x0017, AE, "Sending Application Entity Title"},
+    {0x0002, 0x0018, AE, "Receiving Application Entity Title"},
+    {0x0002, 0x0100, UI, "Private Information Creator UID"},
+    {0x0002, 0x0102, OB, "Private Information"},
+    {0x0004, 0x1130, CS, "File-set ID"},
+    {0x0004, 0x1141, CS, "File-set Descriptor File ID"},
+    {0x0004, 0x1142, CS, "Specific Character Set of File-set Descriptor File"},
+    {0x0004, 0x1200, UL, "Offset of the First Directory Record of the Root Directory Entity"},
+    {0x0004, 0x1202, UL, "Offset of the Last Directory Record of the Root Directory Entity"},
+    {0x0004, 0x1212, US, "File-set Consistency Flag"},
+    {0x0004, 0x1220, SQ, "Directory Record Sequence"},
+    {0x0004, 0x1400, UL, "Offset of the Next Directory Record"},
+    {0x0004, 0x1410, US, "Record In-use Flag"},
+    {0x0004, 0x1420, UL, "Offset of Referenced Lower-Level Directory Entity"},
+    {0x0004, 0x1430, CS, "Directory Record Type"},
+    {0x0004, 0x1432, UI, "Private Record UID"},
+    {0x0004, 0x1500, CS, "Referenced File ID"},
+    {0x0004, 0x1504, UL, "MRDR Directory Record Offset"},
+    {0x0004, 0x1510, UI, "Referenced SOP Class UID in File"},
+    {0x0004, 0x1511, UI, "Referenced SOP Instance UID in File"},
+    {0x0004, 0x1512, UI, "Referenced Transfer Syntax UID in File"},
+    {0x0004, 0x151A, UI, "Referenced Related General SOP Class UID in File"},
+    {0x0004, 0x1600, UL, "Number of References"},
+    {0x0008, 0x0001, UL, "Length to End"},
+    {0x0008, 0x0005, CS, "Specific Character Set"},
+    {0x0008, 0x0006, SQ, "Language Code Sequence"},
+    {0x0008, 0x0008, CS, "Image Type"},
+    {0x0008, 0x0010, SH, "Recognition Code"},
+    {0x0008, 0x0012, DA, "Instance Creation Date"},
+    {0x0008, 0x0013, TM, "Instance Creation Time"},
+    {0x0008, 0x0014, UI, "Instance Creator UID"},
+    {0x0008, 0x0015, DT, "Instance Create UID"},
+    {0x0008, 0x0016, UI, "SOP Class UID"},
+    {0x0008, 0x0018, UI, "SOP Instance UID"},
+    {0x0008, 0x001A, UI, "Related General SOP Class UID"},
+    {0x0008, 0x001B, UI, "Original Specialized SOP Class UID"},
+    {0x0008, 0x0020, DA, "Study Date"},
+    {0x0008, 0x0021, DA, "Series Date"},
+    {0x0008, 0x0022, DA, "Acquisition Date"},
+    {0x0008, 0x0023, DA, "Content Date"},
+    {0x0008, 0x0024, DA, "Overlay Date"},
+    {0x0008, 0x0025, DA, "Curve Date"},
+    {0x0008, 0x002A, DT, "Acquisition DateTime"},
+    {0x0008, 0x0030, TM, "Study Time"},
+    {0x0008, 0x0031, TM, "Series Time"},
+    {0x0008, 0x0032, TM, "Acquisition Time"},
+    {0x0008, 0x0033, TM, "Content Time"},
+    {0x0008, 0x0034, TM, "Overlay Time"},
+    {0x0008, 0x0035, TM, "Curve Time"},
+    {0x0008, 0x0040, US, "Data Set Type"},
+    {0x0008, 0x0041, LO, "Data Set Subtype"},
+    {0x0008, 0x0042, CS, "Nuclear Medicine Series Type"},
+    {0x0008, 0x0050, SH, "Accession Number"},
+    {0x0008, 0x0051, SQ, "Issuer of Accession Number Sequence"},
+    {0x0008, 0x0052, CS, "Query/Retrieve Level"},
+    {0x0008, 0x0053, CS, "Query/Retrieve View"},
+    {0x0008, 0x0054, AE, "Retrieve AE Title"},
+    {0x0008, 0x0055, AE, "Station AE Title"},
+    {0x0008, 0x0056, CS, "Instance Availability"},
+    {0x0008, 0x0058, UI, "Failed SOP Instance UID List"},
+    {0x0008, 0x0060, CS, "Modality"},
+    {0x0008, 0x0061, CS, "Modalities in Study"},
+    {0x0008, 0x0062, UI, "SOP Classes in Study"},
+    {0x0008, 0x0064, CS, "Conversion Type"},
+    {0x0008, 0x0068, CS, "Presentation Intent Type"},
+    {0x0008, 0x0070, LO, "Manufacturer"},
+    {0x0008, 0x0080, LO, "Institution Name"},
+    {0x0008, 0x0081, ST, "Institution Address"},
+    {0x0008, 0x0082, SQ, "Institution Code Sequence"},
+    {0x0008, 0x0090, PN, "Referring Physician's Name"},
+    {0x0008, 0x0092, ST, "Referring Physician's Address"},
+    {0x0008, 0x0094, SH, "Referring Physician's Telephone Numbers"},
+    {0x0008, 0x0096, SQ, "Referring Physician Identification Sequence"},
+    {0x0008, 0x009C, PN, "Consulting Physician's Name"},
+    {0x0008, 0x009D, SQ, "Consulting Physician Identification Sequence"},
+    {0x0008, 0x0100, SH, "Code Value"},
+    {0x0008, 0x0101, LO, "Extended Code Value"},
+    {0x0008, 0x0102, SH, "Coding Scheme Designator"},
+    {0x0008, 0x0104, LO, "Code Meaning"},
+    {0x0008, 0x0105, CS, "Mapping Resource"},
+    {0x0008, 0x0106, DT, "Context Group Version"},
+    {0x0008, 0x0107, DT, "Context Group Local Version"},
+    {0x0008, 0x0108, LT, "Extended Code Meaning"},
+    {0x0008, 0x010C, UI, "Coding Scheme UID"},
+    {0x0008, 0x010D, UI, "Context Group Extension Creator UID"},
+    {0x0008, 0x010F, CS, "Context Identifier"},
+    {0x0008, 0x0110, SQ, "Coding Scheme Identification Sequence"},
+    {0x0008, 0x0112, LO, "Coding Scheme Registry"},
+    {0x0008, 0x0114, ST, "Coding Scheme External ID"},
+    {0x0008, 0x0115, ST, "Coding Scheme Name"},
+    {0x0008, 0x0116, ST, "Coding Scheme Responsible Organization"},
+    {0x0008, 0x0117, UI, "Context UID"},
+    {0x0008, 0x0118, UI, "Mapping Resource UID"},
+    {0x0008, 0x0119, UC, "Long Code Value"},
+    {0x0008, 0x0120, UR, "URN Code Value"},
+    {0x0008, 0x0121, SQ, "Equivalent Code Sequence"},
+    {0x0008, 0x0122, LO, "Mapping Resource Name"},
+    {0x0008, 0x0123, SQ, "Context Group Identification Sequence"},
+    {0x0008, 0x0124, SQ, "Mapping Resource Identification Sequence"},
+    {0x0008, 0x0201, SH, "Timezone Offset From UTC"},
+    {0x0008, 0x0300, SQ, "Private Data Element Characteristics Sequence"},
+    {0x0008, 0x0301, US, "Private Group Reference"},
+    {0x0008, 0x0302, LO, "Private Creator Reference"},
+    {0x0008, 0x0303, CS, "Block Identifying Information Status"},
+    {0x0008, 0x0304, US, "Nonidentifying PrivateElements"},
+    {0x0008, 0x0305, SQ, "Deidentification ActionSequence"},
+    {0x0008, 0x0306, US, "Identifying PrivateElements"},
+    {0x0008, 0x0307, CS, "Deidentification Action"},
+    {0x0008, 0x1000, AE, "Network ID"},
+    {0x0008, 0x1010, SH, "Station Name"},
+    {0x0008, 0x1030, LO, "Study Description"},
+    {0x0008, 0x1032, SQ, "Procedure Code Sequence"},
+    {0x0008, 0x103E, LO, "Series Description"},
+    {0x0008, 0x103F, SQ, "Series Description CodeSequence"},
+    {0x0008, 0x1040, LO, "Institutional Department Name"},
+    {0x0008, 0x1048, PN, "Physician(s) of Record"},
+    {0x0008, 0x1049, SQ, "Physician(s) of Record Identification Sequence"},
+    {0x0008, 0x1050, PN, "Attending Physician's Name"},
+    {0x0008, 0x1052, SQ, "Performing Physician Identification Sequence"},
+    {0x0008, 0x1060, PN, "Name of Physician(s) Reading Study"},
+    {0x0008, 0x1062, SQ, "Physician(s) ReadingStudy Identification Sequenc"},
+    {0x0008, 0x1070, PN, "Operator's Name"},
+    {0x0008, 0x1072, SQ, "Operator Identification Sequence"},
+    {0x0008, 0x1080, LO, "Admitting Diagnosis Description"},
+    {0x0008, 0x1084, SQ, "Admitting Diagnosis Code Sequence"},
+    {0x0008, 0x1090, LO, "Manufacturer's Model Name"},
+    {0x0008, 0x1100, SQ, "Referenced Results Sequence"},
+    {0x0008, 0x1110, SQ, "Referenced Study Sequence"},
+    {0x0008, 0x1111, SQ, "Referenced Study Component Sequence"},
+    {0x0008, 0x1115, SQ, "Referenced Series Sequence"},
+    {0x0008, 0x1120, SQ, "Referenced Patient Sequence"},
+    {0x0008, 0x1125, SQ, "Referenced Visit Sequence"},
+    {0x0008, 0x1130, SQ, "Referenced Overlay Sequence"},
+    {0x0008, 0x1134, SQ, "Referenced Stereometric Instance Sequence"},
+    {0x0008, 0x113A, SQ, "Referenced Waveform Sequence"},
+    {0x0008, 0x1140, SQ, "Referenced Image Sequence"},
+    {0x0008, 0x1145, SQ, "Referenced Curve Sequence"},
+    {0x0008, 0x114A, SQ, "Referenced InstanceSequence"},
+    {0x0008, 0x114B, SQ, "Referenced Real World Value Mapping InstanceSequence"},
+    {0x0008, 0x1150, UI, "Referenced SOP Class UID"},
+    {0x0008, 0x1155, UI, "Referenced SOP Instance UID"},
+    {0x0008, 0x115A, UI, "SOP Classes Supported"},
+    {0x0008, 0x1160, IS, "Referenced Frame Number"},
+    {0x0008, 0x1161, UL, "Simple Frame List"},
+    {0x0008, 0x1162, UL, "Calculated Frame List"},
+    {0x0008, 0x1163, FD, "Time Range"},
+    {0x0008, 0x1164, SQ, "Frame Extraction Sequence"},
+    {0x0008, 0x1167, UI, "Multi-frame Source SOP Instance UID"},
+    {0x0008, 0x1190, UR, "Retrieve URL"},
+    {0x0008, 0x1195, UI, "Transaction UID"},
+    {0x0008, 0x1196, US, "Warning Reason"},
+    {0x0008, 0x1197, US, "Failure Reason"},
+    {0x0008, 0x1198, SQ, "Failed SOP Sequence"},
+    {0x0008, 0x1199, SQ, "Referenced SOP Sequence"},
+    {0x0008, 0x119A, SQ, "Other Failures Sequence"},
+    {0x0008, 0x1200, SQ, "Studies Containing OtherReferenced InstancesSequence"},
+    {0x0008, 0x1250, SQ, "Related Series Sequence"},
+    {0x0008, 0x2110, CS, "Lossy Image Compression(Retired)"},
+    {0x0008, 0x2111, ST, "Derivation Description"},
+    {0x0008, 0x2112, SQ, "Source Image Sequence"},
+    {0x0008, 0x2120, SH, "Stage Name"},
+    {0x0008, 0x2122, IS, "Stage Number"},
+    {0x0008, 0x2124, IS, "Number of Stages"},
+    {0x0008, 0x2127, SH, "View Name"},
+    {0x0008, 0x2128, IS, "View Number"},
+    {0x0008, 0x2129, IS, "Number of Event Timers"},
+    {0x0008, 0x212A, IS, "Number of Views in Stage"},
+    {0x0008, 0x2130, DS, "Event Elapsed Time(s)"},
+    {0x0008, 0x2132, LO, "Event Timer Name(s)"},
+    {0x0008, 0x2133, SQ, "Event Timer Sequence"},
+    {0x0008, 0x2134, FD, "Event Time Offset"},
+    {0x0008, 0x2135, SQ, "Event Code Sequence"},
+    {0x0008, 0x2142, IS, "Start Trim"},
+    {0x0008, 0x2143, IS, "Stop Trim"},
+    {0x0008, 0x2144, IS, "Recommended Display Frame Rate"},
+    {0x0008, 0x2200, CS, "Transducer Position"},
+    {0x0008, 0x2204, CS, "Transducer Orientation"},
+    {0x0008, 0x2208, CS, "Anatomic Structure"},
+    {0x0008, 0x2218, SQ, "Anatomic RegionSequence"},
+    {0x0008, 0x2220, SQ, "Anatomic Region ModifierSequence"},
+    {0x0008, 0x2228, SQ, "Primary Anatomic Structure Sequence"},
+    {0x0008, 0x2229, SQ, "Anatomic Structure, Spaceor Region Sequence"},
+    {0x0008, 0x2230, SQ, "Primary Anatomic Structure ModifierSequence"},
+    {0x0008, 0x2240, SQ, "Transducer Position Sequence"},
+    {0x0008, 0x2242, SQ, "Transducer Position Modifier Sequence"},
+    {0x0008, 0x2244, SQ, "Transducer Orientation Sequence"},
+    {0x0008, 0x2246, SQ, "Transducer Orientation Modifier Sequence"},
+    {0x0008, 0x2251, SQ, "Anatomic Structure SpaceOr Region Code Sequence(Trial)"},
+    {0x0008, 0x2253, SQ, "Anatomic Portal Of Entrance Code Sequence(Trial)"},
+    {0x0008, 0x2255, SQ, "Anatomic ApproachDirection Code Sequence(Trial)"},
+    {0x0008, 0x2256, ST, "Anatomic Perspective Description (Trial)"},
+    {0x0008, 0x2257, SQ, "Anatomic Perspective Code Sequence (Trial)"},
+    {0x0008, 0x2258, ST, "Anatomic Location Of Examining InstrumentDescription (Trial)"},
+    {0x0008, 0x2259, SQ, "Anatomic Location Of Examining InstrumentCode Sequence (Trial)"},
+    {0x0008, 0x225A, SQ, "Anatomic Structure SpaceOr Region Modifier CodeSequence (Trial)"},
+    {0x0008, 0x225C, SQ, "On Axis Background Anatomic Structure CodeSequence (Trial)"},
+    {0x0008, 0x3001, SQ, "Alternate Representation Sequence"},
+    {0x0008, 0x3010, UI, "Irradiation Event UID"},
+    {0x0008, 0x3011, SQ, "Source Irradiation Event Sequence"},
+    {0x0008, 0x2012, UI, "Radiopharmaceutical Administration Event UID"},
+    {0x0008, 0x4000, LT, "Identifying Comments"},
+    {0x0008, 0x9007, CS, "Frame Type"},
+    {0x0008, 0x9092, SQ, "Referenced ImageEvidence Sequence"},
+    {0x0008, 0x9121, SQ, "Referenced Raw DataSequence"},
+    {0x0008, 0x9123, UI, "Creator-Version UID"},
+    {0x0008, 0x9124, SQ, "Derivation ImageSequence"},
+    {0x0008, 0x9154, SQ, "Source Image EvidenceSequence"},
+    {0x0008, 0x9205, CS, "Pixel Presentation"},
+    {0x0008, 0x9206, CS, "Volumetric Properties"},
+    {0x0008, 0x9207, CS, "Volume Based Calculation Technique"},
+    {0x0008, 0x9208, CS, "Complex Image Component"},
+    {0x0008, 0x9209, CS, "Acquisition Contrast"},
+    {0x0008, 0x9215, SQ, "Derivation Code Sequence"},
+    {0x0008, 0x9237, SQ, "Referenced Presentation State Sequence"},
+    {0x0008, 0x9410, SQ, "Referenced Other Plane Sequence"},
+    {0x0008, 0x9458, SQ, "Frame Display Sequence"},
+    {0x0008, 0x9459, FL, "Recommended DisplayFrame Rate in Float"},
+    {0x0008, 0x9460, CS, "Skip Frame Range Flag"},
+
+    // Group Number 0x0010, Patient's Info (incomplete / only main elems)
+    {0x0010, 0x0010, PN, "Patient's Name"},
+    {0x0010, 0x0020, LO, "Patient ID"},
+    {0x0010, 0x0021, LO, "Issuer of Patient ID"},
+    {0x0010, 0x0022, CS, "Type of Patient ID"},
+    {0x0010, 0x0024, SQ, "Issuer of Patient ID Qualifiers Sequence"},
+    {0x0010, 0x0026, SQ, "Source Patient Group Identification Sequence"},
+    {0x0010, 0x0027, SQ, "Group of Patients Identification Sequence"},
+    {0x0010, 0x0028, US, "Subject Relative Position in Image"},
+    {0x0010, 0x0038, DA, "Patient's Birth Date"},
+    {0x0010, 0x0032, TM, "Patient's Birth Time"},
+    {0x0010, 0x0033, LO, "Patient's Birth Date in Alternative Calendar"},
+    {0x0010, 0x0034, LO, "Patient's Death Date in Alternative Calendar"},
+    {0x0010, 0x0035, CS, "Patient's Alternative Calendar"},
+    {0x0010, 0x0040, CS, "Patient's Sex"},
+    {0x0010, 0x0050, SQ, "Patient's Insurance PlanCode Sequence"},
+
+    // Group Number 0x0028, Image Group Number
+    {0x0028, 0x0002, US, "Samples per Pixel"},
+    {0x0028, 0x0003, US, "Samples per Pixel Used"},
+    {0x0028, 0x0004, CS, "Photometric Interpretation"},
+    {0x0028, 0x0005, US, "Image Dimensions"},
+    {0x0028, 0x0006, US, "Planar Configuration"},
+    {0x0028, 0x0008, IS, "Number of Frames"},
+    {0x0028, 0x0009, AT, "Frame Increment Pointer"},
+    {0x0028, 0x000A, AT, "Frame Dimension Pointer"},
+    {0x0028, 0x0010, US, "Rows"},
+    {0x0028, 0x0011, US, "Columns"},
+    {0x0028, 0x0012, US, "Planes"},
+    {0x0028, 0x0014, US, "Ultrasound Color DataPresent"},
+    {0x0028, 0x0030, DS, "Pixel Spacing"},
+    {0x0028, 0x0031, DS, "Zoom Factor"},
+    {0x0028, 0x0032, DS, "Zoom Center"},
+    {0x0028, 0x0034, IS, "Pixel Aspect Ratio"},
+    {0x0028, 0x0040, CS, "Image Format"},
+    {0x0028, 0x0050, LO, "Manipulated Image"},
+    {0x0028, 0x0051, CS, "Corrected Image"},
+    {0x0028, 0x005F, LO, "Compression Recognition Code"},
+    {0x0028, 0x0060, CS, "Compression Code"},
+    {0x0028, 0x0061, SH, "Compression Originator"},
+    {0x0028, 0x0062, LO, "Compression Label"},
+    {0x0028, 0x0063, SH, "Compression Description"},
+    {0x0028, 0x0065, CS, "Compression Sequence"},
+    {0x0028, 0x0066, AT, "Compression Step Pointers"},
+    {0x0028, 0x0068, US, "Repeat Interval"},
+    {0x0028, 0x0069, US, "Bits Grouped"},
+    {0x0028, 0x0070, US, "Perimeter Table"},
+    {0x0028, 0x0071, US, "Perimeter Value"},
+    {0x0028, 0x0071, SS, "Perimeter Value"},
+    {0x0028, 0x0080, US, "Predictor Rows"},
+    {0x0028, 0x0081, US, "Predictor Columns"},
+    {0x0028, 0x0082, US, "Predictor Constants"},
+    {0x0028, 0x0090, CS, "Blocked Pixels"},
+    {0x0028, 0x0091, US, "Block Rows"},
+    {0x0028, 0x0092, US, "Block Columns"},
+    {0x0028, 0x0093, US, "Row Overlap"},
+    {0x0028, 0x0094, US, "Column Overlap"},
+    {0x0028, 0x0100, US, "Bits Allocated"},
+    {0x0028, 0x0101, US, "Bits Stored"},
+    {0x0028, 0x0102, US, "High Bit"},
+    {0x0028, 0x0103, US, "Pixel Representation"},
+    {0x0028, 0x0104, US, "Smallest Valid Pixel Value"},
+    {0x0028, 0x0104, SS, "Smallest Valid Pixel Value"},
+    {0x0028, 0x0105, US, "Largest Valid Pixel Value"},
+    {0x0028, 0x0105, SS, "Largest Valid Pixel Value"},
+    {0x0028, 0x0106, US, "Smallest Image Pixel Value"},
+    {0x0028, 0x0106, SS, "Smallest Image Pixel Value"},
+    {0x0028, 0x0107, US, "Largest Image Pixel Value"},
+    {0x0028, 0x0107, SS, "Largest Image Pixel Value"},
+    {0x0028, 0x0108, US, "Smallest Pixel Value in Series"},
+    {0x0028, 0x0108, SS, "Smallest Pixel Value in Series"},
+    {0x0028, 0x0109, US, "Largest Pixel Value in Series"},
+    {0x0028, 0x0109, SS, "Largest Pixel Value in Series"},
+    {0x0028, 0x0120, US, "Pixel Padding Value"},
+    {0x0028, 0x0120, SS, "Pixel Padding Value"},
+    {0x0028, 0x0121, US, "Pixel Padding Range Limit"},
+    {0x0028, 0x0121, SS, "Pixel Padding Range Limit"},
+    {0x0028, 0x0122, FL, "Float Pixel Padding Value"},
+    {0x0028, 0x0123, FD, "Double Float Pixel PaddingValue"},
+    {0x0028, 0x0124, FL, "Float Pixel Padding RangeLimit"},
+    {0x0028, 0x0125, FD, "Double Float Pixel PaddingRange Limit"},
+    {0x0028, 0x0200, US, "Image Location"},
+    {0x0028, 0x0300, CS, "Quality Control Image"},
+    {0x0028, 0x0301, CS, "Burned In Annotation"},
+    {0x0028, 0x0302, CS, "Recognizable VisualFeatures"},
+    {0x0028, 0x0303, CS, "Longitudinal Temporal Information Modified"},
+    {0x0028, 0x0304, UI, "Referenced Color Palette Instance UID"},
+    {0x0028, 0x0400, LO, "Transform Label"},
+    {0x0028, 0x0401, LO, "Transform Version Number"},
+    {0x0028, 0x0402, US, "Number of Transform Steps"},
+    {0x0028, 0x0403, LO, "Sequence of CompressedData"},
+    {0x0028, 0x0404, AT, "Details of Coefficients"},
+    {0x0028, 0x0410, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x0420, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x0430, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x0440, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x0450, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x0460, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x0470, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x0480, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x0490, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x04A0, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x04B0, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x04C0, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x04D0, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x04E0, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x04F0, US, "Rows For Nth OrderCoefficients"},
+    {0x0028, 0x0411, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x0421, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x0431, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x0441, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x0451, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x0461, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x0471, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x0481, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x0491, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x04A1, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x04B1, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x04C1, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x04D1, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x04E1, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x04F1, US, "Columns For Nth OrderCoefficients"},
+    {0x0028, 0x0412, US, "Coefficient Coding"},
+    {0x0028, 0x0422, US, "Coefficient Coding"},
+    {0x0028, 0x0432, US, "Coefficient Coding"},
+    {0x0028, 0x0442, US, "Coefficient Coding"},
+    {0x0028, 0x0452, US, "Coefficient Coding"},
+    {0x0028, 0x0462, US, "Coefficient Coding"},
+    {0x0028, 0x0472, US, "Coefficient Coding"},
+    {0x0028, 0x0482, US, "Coefficient Coding"},
+    {0x0028, 0x0492, US, "Coefficient Coding"},
+    {0x0028, 0x04A2, US, "Coefficient Coding"},
+    {0x0028, 0x04B2, US, "Coefficient Coding"},
+    {0x0028, 0x04C2, US, "Coefficient Coding"},
+    {0x0028, 0x04D2, US, "Coefficient Coding"},
+    {0x0028, 0x04E2, US, "Coefficient Coding"},
+    {0x0028, 0x04F2, US, "Coefficient Coding"},
+    {0x0028, 0x0413, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x0423, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x0433, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x0443, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x0453, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x0463, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x0473, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x0483, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x0493, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x04A3, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x04B3, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x04C3, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x04D3, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x04E3, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x04F3, AT, "Coefficient Coding Pointers"},
+    {0x0028, 0x0700, LO, "DCT Label"},
+    {0x0028, 0x0701, CS, "Data Block Description"},
+    {0x0028, 0x0702, AT, "Data Block"},
+    {0x0028, 0x0710, US, "Normalization FactorFormat"},
+    {0x0028, 0x0720, US, "Zonal Map Number Format"},
+    {0x0028, 0x0721, AT, "Zonal Map Location"},
+    {0x0028, 0x0722, US, "Zonal Map Format"},
+    {0x0028, 0x0730, US, "Adaptive Map Format"},
+    {0x0028, 0x0740, US, "Code Number Format"},
+    {0x0028, 0x0800, CS, "Code Label"},
+    {0x0028, 0x0810, CS, "Code Label"},
+    {0x0028, 0x0820, CS, "Code Label"},
+    {0x0028, 0x0830, CS, "Code Label"},
+    {0x0028, 0x0840, CS, "Code Label"},
+    {0x0028, 0x0850, CS, "Code Label"},
+    {0x0028, 0x0860, CS, "Code Label"},
+    {0x0028, 0x0870, CS, "Code Label"},
+    {0x0028, 0x0880, CS, "Code Label"},
+    {0x0028, 0x0890, CS, "Code Label"},
+    {0x0028, 0x08A0, CS, "Code Label"},
+    {0x0028, 0x08B0, CS, "Code Label"},
+    {0x0028, 0x08C0, CS, "Code Label"},
+    {0x0028, 0x08D0, CS, "Code Label"},
+    {0x0028, 0x08E0, CS, "Code Label"},
+    {0x0028, 0x08F0, CS, "Code Label"},
+    {0x0028, 0x0802, US, "Number of Tables"},
+    {0x0028, 0x0812, US, "Number of Tables"},
+    {0x0028, 0x0822, US, "Number of Tables"},
+    {0x0028, 0x0832, US, "Number of Tables"},
+    {0x0028, 0x0842, US, "Number of Tables"},
+    {0x0028, 0x0852, US, "Number of Tables"},
+    {0x0028, 0x0862, US, "Number of Tables"},
+    {0x0028, 0x0872, US, "Number of Tables"},
+    {0x0028, 0x0882, US, "Number of Tables"},
+    {0x0028, 0x0892, US, "Number of Tables"},
+    {0x0028, 0x08A2, US, "Number of Tables"},
+    {0x0028, 0x08B2, US, "Number of Tables"},
+    {0x0028, 0x08C2, US, "Number of Tables"},
+    {0x0028, 0x08D2, US, "Number of Tables"},
+    {0x0028, 0x08E2, US, "Number of Tables"},
+    {0x0028, 0x08F2, US, "Number of Tables"},
+    {0x0028, 0x0803, AT, "Code Table Location"},
+    {0x0028, 0x0813, AT, "Code Table Location"},
+    {0x0028, 0x0823, AT, "Code Table Location"},
+    {0x0028, 0x0833, AT, "Code Table Location"},
+    {0x0028, 0x0843, AT, "Code Table Location"},
+    {0x0028, 0x0853, AT, "Code Table Location"},
+    {0x0028, 0x0863, AT, "Code Table Location"},
+    {0x0028, 0x0873, AT, "Code Table Location"},
+    {0x0028, 0x0883, AT, "Code Table Location"},
+    {0x0028, 0x0893, AT, "Code Table Location"},
+    {0x0028, 0x08A3, AT, "Code Table Location"},
+    {0x0028, 0x08B3, AT, "Code Table Location"},
+    {0x0028, 0x08C3, AT, "Code Table Location"},
+    {0x0028, 0x08D3, AT, "Code Table Location"},
+    {0x0028, 0x08E3, AT, "Code Table Location"},
+    {0x0028, 0x08F3, AT, "Code Table Location"},
+    {0x0028, 0x0804, US, "Bits For Code Word"},
+    {0x0028, 0x0814, US, "Bits For Code Word"},
+    {0x0028, 0x0824, US, "Bits For Code Word"},
+    {0x0028, 0x0834, US, "Bits For Code Word"},
+    {0x0028, 0x0844, US, "Bits For Code Word"},
+    {0x0028, 0x0854, US, "Bits For Code Word"},
+    {0x0028, 0x0864, US, "Bits For Code Word"},
+    {0x0028, 0x0874, US, "Bits For Code Word"},
+    {0x0028, 0x0884, US, "Bits For Code Word"},
+    {0x0028, 0x0894, US, "Bits For Code Word"},
+    {0x0028, 0x08A4, US, "Bits For Code Word"},
+    {0x0028, 0x08B4, US, "Bits For Code Word"},
+    {0x0028, 0x08C4, US, "Bits For Code Word"},
+    {0x0028, 0x08D4, US, "Bits For Code Word"},
+    {0x0028, 0x08E4, US, "Bits For Code Word"},
+    {0x0028, 0x08F4, US, "Bits For Code Word"},
+    {0x0028, 0x0808, AT, "Image Data Location"},
+    {0x0028, 0x0818, AT, "Image Data Location"},
+    {0x0028, 0x0828, AT, "Image Data Location"},
+    {0x0028, 0x0838, AT, "Image Data Location"},
+    {0x0028, 0x0848, AT, "Image Data Location"},
+    {0x0028, 0x0858, AT, "Image Data Location"},
+    {0x0028, 0x0868, AT, "Image Data Location"},
+    {0x0028, 0x0878, AT, "Image Data Location"},
+    {0x0028, 0x0888, AT, "Image Data Location"},
+    {0x0028, 0x0898, AT, "Image Data Location"},
+    {0x0028, 0x08A8, AT, "Image Data Location"},
+    {0x0028, 0x08B8, AT, "Image Data Location"},
+    {0x0028, 0x08C8, AT, "Image Data Location"},
+    {0x0028, 0x08D8, AT, "Image Data Location"},
+    {0x0028, 0x08E8, AT, "Image Data Location"},
+    {0x0028, 0x08F8, AT, "Image Data Location"},
+    {0x0028, 0x0A02, CS, "Pixel Spacing Calibration Type"},
+    {0x0028, 0x0A04, LO, "Pixel Spacing Calibration Description"},
+    {0x0028, 0x1040, CS, "Pixel Intensity Relationship"},
+    {0x0028, 0x1041, SS, "Pixel Intensity Relationship Sign"},
+    {0x0028, 0x1050, DS, "Window Center"},
+    {0x0028, 0x1051, DS, "Window Width"},
+    {0x0028, 0x1052, DS, "Rescale Intercept"},
+    {0x0028, 0x1053, DS, "Rescale Slope"},
+    {0x0028, 0x1054, LO, "Rescale Type"},
+    {0x0028, 0x1055, LO, "Window Center & Width Explanation"},
+    {0x0028, 0x1056, CS, "VOI LUT Function"},
+    {0x0028, 0x1080, CS, "Gray Scale"},
+    {0x0028, 0x1090, CS, "Recommended Viewing Mode"},
+    {0x0028, 0x1100, US, "Gray Lookup Table Descriptor"},
+    {0x0028, 0x1100, SS, "Gray Lookup Table Descriptor"},
+    {0x0028, 0x1101, US, "Red Palette Color Lookup Table Descriptor"},
+    {0x0028, 0x1101, SS, "Red Palette Color Lookup Table Descriptor"},
+    {0x0028, 0x1102, US, "Green Palette Color Lookup Table Descriptor"},
+    {0x0028, 0x1102, SS, "Green Palette Color Lookup Table Descriptor"},
+    {0x0028, 0x1103, US, "Blue Palette Color Lookup Table Descriptor"},
+    {0x0028, 0x1103, SS, "Blue Palette Color Lookup Table Descriptor"},
+    {0x0028, 0x1104, US, "Alpha Palette Color Lookup Table Descriptor"},
+    {0x0028, 0x1111, US, "Large Red Palette ColorLookup Table Descriptor"},
+    {0x0028, 0x1111, SS, "Large Red Palette ColorLookup Table Descriptor"},
+    {0x0028, 0x1112, US, "Large Green Palette ColorLookup Table Descriptor"},
+    {0x0028, 0x1112, SS, "Large Green Palette ColorLookup Table Descriptor"},
+    {0x0028, 0x1113, US, "Large Blue Palette ColorLookup Table Descriptor"},
+    {0x0028, 0x1113, SS, "Large Blue Palette ColorLookup Table Descriptor"},
+    {0x0028, 0x1199, UI, "Palette Color Lookup TableUID"},
+    {0x0028, 0x1200, US, "Gray Lookup Table Data"},
+    {0x0028, 0x1200, SS, "Gray Lookup Table Data"},
+    {0x0028, 0x1200, OW, "Gray Lookup Table Data"},
+    {0x0028, 0x1201, OW, "Red Palette Color Lookup Table Data"},
+    {0x0028, 0x1202, OW, "Green Palette Color Lookup Table Data"},
+    {0x0028, 0x1203, OW, "Blue Palette Color Lookup Table Data"},
+    {0x0028, 0x1204, OW, "Alpha Palette Color LookupTable Data"},
+    {0x0028, 0x1211, OW, "Large Red Palette ColorLookup Table Data"},
+    {0x0028, 0x1212, OW, "Large Green Palette ColorLookup Table Data"},
+    {0x0028, 0x1213, OW, "Large Blue Palette ColorLookup Table Data"},
+    {0x0028, 0x1214, UI, "Large Palette Color LookupTable UID"},
+    {0x0028, 0x1221, OW, "Segmented Red PaletteColor Lookup Table Data"},
+    {0x0028, 0x1222, OW, "Segmented Green PaletteColor Lookup Table Data"},
+    {0x0028, 0x1223, OW, "Segmented Blue PaletteColor Lookup Table Data"},
+    {0x0028, 0x1224, OW, "Segmented Alpha PaletteColor Lookup Table Data"},
+    {0x0028, 0x1300, CS, "Breast Implant Present"},
+    {0x0028, 0x1350, CS, "Partial View"},
+    {0x0028, 0x1351, ST, "Partial View Description"},
+    {0x0028, 0x1352, SQ, "Partial View CodeSequence"},
+    {0x0028, 0x135A, CS, "Spatial LocationsPreserved"},
+    {0x0028, 0x1401, SQ, "Data Frame Assignment Sequence"},
+    {0x0028, 0x1402, CS, "Data Path Assignment"},
+    {0x0028, 0x1403, US, "Bits Mapped to Color Lookup Table"},
+    {0x0028, 0x1404, SQ, "Blending LUT 1 Sequence"},
+    {0x0028, 0x1405, CS, "Blending LUT 1 Transfer Function"},
+    {0x0028, 0x1406, FD, "Blending Weight Constant"},
+    {0x0028, 0x1407, US, "Blending Lookup Table Descriptor"},
+    {0x0028, 0x1408, OW, "Blending Lookup Table Data"},
+    {0x0028, 0x140B, SQ, "Enhanced Palette Color Lookup Table Sequence"},
+    {0x0028, 0x140C, SQ, "Blending LUT 2 Sequence"},
+    {0x0028, 0x140D, CS, "Blending LUT 2 Transfer Function"},
+    {0x0028, 0x140E, CS, "Data Path ID"},
+    {0x0028, 0x140F, CS, "RGB LUT Transfer Function"},
+    {0x0028, 0x1410, CS, "Alpha LUT Transfer Function"},
+    {0x0028, 0x2000, OB, "ICC Profile"},
+    {0x0028, 0x2002, CS, "Color Space"},
+    {0x0028, 0x2110, CS, "Lossy Image Compression"},
+    {0x0028, 0x2112, DS, "Lossy Image Compression Ratio"},
+    {0x0028, 0x2114, CS, "Lossy Image Compression Method"},
+    {0x0028, 0x3000, SQ, "Modality LUT Sequence"},
+    {0x0028, 0x3002, US, "LUT Descriptor"},
+    {0x0028, 0x3002, SS, "LUT Descriptor"},
+    {0x0028, 0x3003, LO, "LUT Explanation"},
+    {0x0028, 0x3004, LO, "Modality LUT Type"},
+    {0x0028, 0x3006, US, "LUT Data"},
+    {0x0028, 0x3006, OW, "LUT Data"},
+    {0x0028, 0x3010, SQ, "VOI LUT Sequence"},
+    {0x0028, 0x4000, LT, "Image Presentation Comments"},
+    {0x0028, 0x5000, SQ, "Bi-Plane Acquisition Sequence"},
+    {0x0028, 0x6010, US, "Representative Frame Number"},
+    {0x0028, 0x6020, US, "Frame Numbers of Interest(FOI)"},
+    {0x0028, 0x6022, LO, "Frame of Interest Description"},
+    {0x0028, 0x6023, CS, "Frame of Interest Type "},
+    {0x0028, 0x6030, US, "Mask Pointer(s)"},
+    {0x0028, 0x6040, US, "R Wave Pointer"},
+    {0x0028, 0x6100, SQ, "Mask Subtraction Sequence"},
+    {0x0028, 0x6101, CS, "Mask Operation"},
+    {0x0028, 0x6102, US, "Applicable Frame Range"},
+    {0x0028, 0x6110, US, "Mask Frame Numbers"},
+    {0x0028, 0x6112, US, "Contrast Frame Averaging"},
+    {0x0028, 0x6114, FL, "Mask Sub-pixel Shift "},
+    {0x0028, 0x6120, SS, "TID Offset"},
+    {0x0028, 0x6190, ST, "Mask Operation Explanation"},
+    {0x0028, 0x7000, SQ, "Equipment Administrator Sequence"},
+    {0x0028, 0x7001, US, "Number Of Display Subsystems"},
+    {0x0028, 0x7002, US, "Current Configuration ID"},
+    {0x0028, 0x7003, US, "Display Subsystem ID"},
+    {0x0028, 0x7004, SH, "Display Subsystem Name"},
+    {0x0028, 0x7005, LO, "Display Subsystem Description"},
+    {0x0028, 0x7006, CS, "System Status"},
+    {0x0028, 0x7007, LO, "System Status Comment"},
+    {0x0028, 0x7008, SQ, "Target Luminance Characteristics Sequence"},
+    {0x0028, 0x7009, US, "Luminance Characteristics ID"},
+    {0x0028, 0x700A, SQ, "Display Subsystem Configuration Sequence"},
+    {0x0028, 0x700B, US, "Configuration ID"},
+    {0x0028, 0x700C, SH, "Configuration Name"},
+    {0x0028, 0x700D, LO, "Configuration Description"},
+    {0x0028, 0x700E, US, "Referenced Target Luminance Characteristics ID"},
+    {0x0028, 0x700F, SQ, "QA Results Sequence"},
+    {0x0028, 0x7010, SQ, "Display Subsystem QA Results Sequence"},
+    {0x0028, 0x7011, SQ, "Configuration QA Results Sequence"},
+    {0x0028, 0x7012, SQ, "Measurement Equipment Sequence"},
+    {0x0028, 0x7013, CS, "Measurement Functions"},
+    {0x0028, 0x7014, CS, "Measurement Equipment Type"},
+    {0x0028, 0x7015, SQ, "Visual Evaluation Result Sequence"},
+    {0x0028, 0x7016, SQ, "Display Calibration Result Sequence"},
+    {0x0028, 0x7017, US, "DDL Value"},
+    {0x0028, 0x7018, FL, "CIExy White Point"},
+    {0x0028, 0x7019, CS, "Display Function Type"},
+    {0x0028, 0x701A, FL, "Gamma Value"},
+    {0x0028, 0x701B, US, "Number Of Luminance Points"},
+    {0x0028, 0x701C, SQ, "Luminance Response Sequence"},
+    {0x0028, 0x701D, FL, "Target Minimum Luminance"},
+    {0x0028, 0x701E, FL, "Target Maximum Luminance"},
+    {0x0028, 0x701F, FL, "Luminance Value"},
+    {0x0028, 0x7020, LO, "Luminance Response Description"},
+    {0x0028, 0x7021, CS, "White Point Flag"},
+    {0x0028, 0x7022, SQ, "Display Device Type Code Sequence"},
+    {0x0028, 0x7023, SQ, "Display Subsystem Sequence"},
+    {0x0028, 0x7024, SQ, "Luminance Result Sequence"},
+    {0x0028, 0x7025, CS, "Ambient Light Value Source"},
+    {0x0028, 0x7026, CS, "Measured Characteristics"},
+    {0x0028, 0x7027, SQ, "Luminance Uniformity Result Sequence"},
+    {0x0028, 0x7028, SQ, "Visual Evaluation Test Sequence"},
+    {0x0028, 0x7029, CS, "Test Result"},
+    {0x0028, 0x702A, LO, "Test Result Comment"},
+    {0x0028, 0x702B, CS, "Test Image Validation"},
+    {0x0028, 0x702C, SQ, "Test Pattern Code Sequence"},
+    {0x0028, 0x702D, SQ, "Measurement Pattern Code Sequence"},
+    {0x0028, 0x702E, SQ, "Visual Evaluation Method Code Sequence"},
+    {0x0028, 0x7FE0, UR, "Pixel Data Provider URL"},
+    {0x0028, 0x9001, UL, "Data Point Rows"},
+    {0x0028, 0x9002, UL, "Data Point Columns"},
+    {0x0028, 0x9003, CS, "Signal Domain Columns"},
+    {0x0028, 0x9099, US, "Largest Monochrome Pixel Value"},
+    {0x0028, 0x9108, CS, "Data Representation"},
+    {0x0028, 0x9110, SQ, "Pixel Measures Sequence"},
+    {0x0028, 0x9132, SQ, "Frame VOILUT Sequence"},
+    {0x0028, 0x9145, SQ, "Pixel Value Transformation Sequence"},
+    {0x0028, 0x9235, CS, "Signal Domain Rows"},
+    {0x0028, 0x9411, FL, "Display Filter Percentage"},
+    {0x0028, 0x9415, SQ, "Frame Pixel Shift Sequence"},
+    {0x0028, 0x9416, US, "Subtraction Item ID"},
+    {0x0028, 0x9422, SQ, "Pixel Intensity Relationship LUT Sequence"},
+    {0x0028, 0x9443, SQ, "Frame Pixel Data Properties Sequence"},
+    {0x0028, 0x9444, CS, "Geometrical Properties"},
+    {0x0028, 0x9445, FL, "Geometric Maximum Distortion"},
+    {0x0028, 0x9446, CS, "Image Processing Applied"},
+    {0x0028, 0x9454, CS, "Mask Selection Mode"},
+    {0x0028, 0x9474, CS, "LUT Function"},
+    {0x0028, 0x9478, FL, "Mask Visibility Percentage"},
+    {0x0028, 0x9501, SQ, "Pixel Shift Sequence"},
+    {0x0028, 0x9502, SQ, "Region Pixel Shift Sequence"},
+    {0x0028, 0x9503, SS, "Vertices Of The Region"},
+    {0x0028, 0x9505, SQ, "Multi Frame Presentation Sequence"},
+    {0x0028, 0x9506, US, "Pixel Shift Frame Range"},
+    {0x0028, 0x9507, US, "LUT Frame Range"},
+    {0x0028, 0x9520, DS, "Image To Equipment Mapping Matrix"},
+    {0x0028, 0x9537, CS, "Equipment Coordinate System Identification"}
+};
+
+static int dcm_dict_comp(const void *vde, const void *vDd) {
+    int ret;
+    DataElement *de = (DataElement *) vde;
+    DICOMDictionary *Dd = (DICOMDictionary *) vDd;
+
+    ret = FFDIFFSIGN(de->GroupNumber, Dd->GroupNumber);
+    if (!ret)
+        ret = FFDIFFSIGN(de->ElementNumber, Dd->ElementNumber);
+    return ret;
+}
+
+int dicom_dict_find_elem_info(DataElement *de) {
+    int len;
+    DICOMDictionary *out;
+
+    if (!de->GroupNumber || !de->ElementNumber)
+        return -1;
+    len = FF_ARRAY_ELEMS(dicom_dictionary);
+
+    out = (DICOMDictionary *) bsearch(de, &dicom_dictionary, len,
+                                      sizeof(dicom_dictionary[0]), dcm_dict_comp);
+
+    if (!out)
+        return -1;
+    de->VR = out->vr;
+    de->desc = av_strdup(out->desc);
+    if (!de->desc)
+        return AVERROR(ENOMEM);
+    de->is_found = 1;
+    return 0;
+}
diff --git a/libavformat/version.h b/libavformat/version.h
index 57002d25c8..c8f27cebf9 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -32,7 +32,7 @@ 
 // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
 // Also please add any ticket numbers that you believe might be affected here
 #define LIBAVFORMAT_VERSION_MAJOR  58
-#define LIBAVFORMAT_VERSION_MINOR  31
+#define LIBAVFORMAT_VERSION_MINOR  32
 #define LIBAVFORMAT_VERSION_MICRO 102
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
-- 
2.22.0