Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement SEI parsing for QSV decoders #31

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

softworkz
Copy link
Collaborator

@softworkz softworkz commented May 26, 2022

Missing SEI information has always been a major drawback when using the QSV decoders. It turned out that there's a hardly known api method that provides access to all SEI (h264/hevc) or user data (mpeg2video).

This allows to get things like closed captions, frame packing, display orientation, HDR data (mastering display, content light level, etc.) without having to rely on those data being provided by the MSDK as extended buffers.

The commit "Implement SEI parsing for QSV decoders" includes some hard-coded workarounds for MSDK bugs which I reported:
Intel-Media-SDK/MediaSDK#2597 (comment)
If someone is interested in the details please contact me directly.

v5

v4

  • add new dependencies in makefile
    Now, build still works when someone uses configure --disable-decoder=h264 --disable-decoder=hevc --disable-decoder=mpegvideo --disable-decoder=mpeg1video --disable-decoder=mpeg2video --enable-libmfx

v3

  • frame.h: clarify doc text for av_frame_copy_side_data()

v2

  • qsvdec: make error handling consistent and clear
  • qsvdec: remove AV_CODEC_ID_MPEG1VIDEO constants
  • hevcdec: rename function to ff_hevc_set_side_data(), add doc text

v3

  • qsvdec: fix c/p error

cc: Soft Works [email protected]
cc: "Xiang, Haihao" [email protected]
cc: Kieran Kunhya [email protected]
cc: Andreas Rheinhardt [email protected]

@softworkz
Copy link
Collaborator Author

/submit

@ffmpeg-codebot
Copy link

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-31/softworkz/submit_qsv_sei-v1

To fetch this version to local tag pr-ffstaging-31/softworkz/submit_qsv_sei-v1:

git fetch --no-tags https://github.com/ffstaging/FFmpeg tag pr-ffstaging-31/softworkz/submit_qsv_sei-v1

doc/APIchanges Outdated Show resolved Hide resolved
@ffmpeg-codebot
Copy link

User Soft Works <[email protected]> has been added to the cc: list.

libavfilter/qsvvpp.c Outdated Show resolved Hide resolved
@ffmpeg-codebot
Copy link

User "Xiang, Haihao" <[email protected]> has been added to the cc: list.

libavcodec/mpeg12.h Outdated Show resolved Hide resolved
libavcodec/hevcdec.c Outdated Show resolved Hide resolved
libavcodec/hevcdec.c Outdated Show resolved Hide resolved
@softworkz
Copy link
Collaborator Author

/submit

@ffmpeg-codebot
Copy link

ffmpeg-codebot bot commented Jun 1, 2022

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-31/softworkz/submit_qsv_sei-v2

To fetch this version to local tag pr-ffstaging-31/softworkz/submit_qsv_sei-v2:

git fetch --no-tags https://github.com/ffstaging/FFmpeg tag pr-ffstaging-31/softworkz/submit_qsv_sei-v2

@softworkz
Copy link
Collaborator Author

/submit

@ffmpeg-codebot
Copy link

ffmpeg-codebot bot commented Jun 1, 2022

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-31/softworkz/submit_qsv_sei-v3

To fetch this version to local tag pr-ffstaging-31/softworkz/submit_qsv_sei-v3:

git fetch --no-tags https://github.com/ffstaging/FFmpeg tag pr-ffstaging-31/softworkz/submit_qsv_sei-v3

@ffmpeg-codebot
Copy link

ffmpeg-codebot bot commented Jun 1, 2022

On the FFmpeg mailing list, Kieran Kunhya wrote (reply to this):

On Thu, 26 May 2022 at 09:09, ffmpegagent <[email protected]> wrote:

> But that doesn't help. Those bugs exist and I'm sharing my workarounds,
> which are empirically determined by testing a range of files. If someone is
> interested, I can provide private access to a repository where we have been
> testing this. Alternatively, I could also leave those workarounds out, and
> just skip those SEI types.
>

I don't care much for QSV but I would say b-frame reordering heuristics
like the one you are using may not necessarily catch all the possible
structures in the wild from third-party encoders.
VLC had (has?) heuristics for this which would cause captions to not be
frame accurate.

Kieran
_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

@ffmpeg-codebot
Copy link

ffmpeg-codebot bot commented Jun 1, 2022

User Kieran Kunhya <[email protected]> has been added to the cc: list.

@ffmpeg-codebot
Copy link

ffmpeg-codebot bot commented Jun 1, 2022

On the FFmpeg mailing list, Soft Works wrote (reply to this):



From: Kieran Kunhya <[email protected]>
Sent: Wednesday, June 1, 2022 9:16 PM
To: FFmpeg development discussions and patches <[email protected]>
Cc: softworkz <[email protected]>
Subject: Re: [FFmpeg-devel] [PATCH 0/6] Implement SEI parsing for QSV decoders

On Thu, 26 May 2022 at 09:09, ffmpegagent <[email protected]<mailto:[email protected]>> wrote:
But that doesn't help. Those bugs exist and I'm sharing my workarounds,
which are empirically determined by testing a range of files. If someone is
interested, I can provide private access to a repository where we have been
testing this. Alternatively, I could also leave those workarounds out, and
just skip those SEI types.

I don't care much for QSV but I would say b-frame reordering heuristics like the one you are using may not necessarily catch all the possible structures in the wild from third-party encoders.

I am not using any b-frame reordering heuristics, I just take the payloads in the order
in which MSDK(QSV) provides it, and it has turned out that they are reordering
the data according to the display order.

I did some detailed analysis of files with out-of-order B-frames:

https://gist.github.com/softworkz/36c49586a8610813a32270ee3947a932

Did you take a look?


VLC had (has?) heuristics for this which would cause captions to not be frame accurate.

Captions aren’t exactly “frame accurate” anyway as each frame has just a very small piece
of information and only when a certain sequence is complete, it leads to some new letters
or line being ready for display.

But out-of-order would screw this definitely, but I haven’t seen any such cases.
The code I’m submitting has been in testing for quite a while with a bunch of users and
many files and TV streams with MP2Video, H264 and HEVC were tested.

You could still be right, that there is a case. A while ago I had digged through
https://streams.videolan.org/ and downloaded all samples that seemed to have CC,
but maybe I missed one for the case you’re talking about.

Do you have an idea where/how I could find such stream?

Thanks,
softworkz


_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

@ffmpeg-codebot
Copy link

ffmpeg-codebot bot commented Jun 1, 2022

On the FFmpeg mailing list, Kieran Kunhya wrote (reply to this):

>
> Captions aren’t exactly “frame accurate” anyway as each frame has just a
> very small piece
>
> of information and only when a certain sequence is complete, it leads to
> some new letters
>
> or line being ready for display.
>

In many use-cases, you want them to be frame-accurate. Final rendition to
the viewer is only one use-case of FFmpeg (to be fair, the likely use-case
of QSV)
And you don't want errors accumulating across encode cycles.


> Do you have an idea where/how I could find such stream?
>

You would need to record them off various television services as they use a
wide range of encoder manufacturers.
Ideally, you could also inject them into various encoders and force them to
build complex reordering patterns and check they are frame accurate.

Regards,
Kieran

>
_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

@ffmpeg-codebot
Copy link

ffmpeg-codebot bot commented Jun 1, 2022

On the FFmpeg mailing list, Soft Works wrote (reply to this):

--===============3878171516236109284==
Content-Language: en-US
Content-Type: multipart/related;
	boundary="_004_DM8P223MB0365E16BEF7963D534E4797ABADF9DM8P223MB0365NAMP_";
	type="multipart/alternative"

--_004_DM8P223MB0365E16BEF7963D534E4797ABADF9DM8P223MB0365NAMP_
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64

DQoNCkZyb206IEtpZXJhbiBLdW5oeWEgPGtpZXJhbmtAb2JlLnR2Pg0KU2VudDogV2VkbmVzZGF5
LCBKdW5lIDEsIDIwMjIgMTA6MjYgUE0NClRvOiBTb2Z0IFdvcmtzIDxzb2Z0d29ya3pAaG90bWFp
bC5jb20+DQpDYzogS2llcmFuIEt1bmh5YSA8a2llcmFua0BvYmUudHY+OyBGRm1wZWcgZGV2ZWxv
cG1lbnQgZGlzY3Vzc2lvbnMgYW5kIHBhdGNoZXMgPGZmbXBlZy1kZXZlbEBmZm1wZWcub3JnPg0K
U3ViamVjdDogUmU6IFtGRm1wZWctZGV2ZWxdIFtQQVRDSCAwLzZdIEltcGxlbWVudCBTRUkgcGFy
c2luZyBmb3IgUVNWIGRlY29kZXJzDQoNCkNhcHRpb25zIGFyZW7igJl0IGV4YWN0bHkg4oCcZnJh
bWUgYWNjdXJhdGXigJ0gYW55d2F5IGFzIGVhY2ggZnJhbWUgaGFzIGp1c3QgYSB2ZXJ5IHNtYWxs
IHBpZWNlDQpvZiBpbmZvcm1hdGlvbiBhbmQgb25seSB3aGVuIGEgY2VydGFpbiBzZXF1ZW5jZSBp
cyBjb21wbGV0ZSwgaXQgbGVhZHMgdG8gc29tZSBuZXcgbGV0dGVycw0Kb3IgbGluZSBiZWluZyBy
ZWFkeSBmb3IgZGlzcGxheS4NCkFuZCB5b3UgZG9uJ3Qgd2FudCBlcnJvcnMgYWNjdW11bGF0aW5n
IGFjcm9zcyBlbmNvZGUgY3ljbGVzLg0KDQpObyBzdWNoIGVycm9ycyBzZWVuIGF0IGFueSB0aW1l
LCBDQyBleHRyYWN0aW9uIGJlaGF2aW9yIGRvZXNu4oCZdCBhcHBlYXIgdG8gYmUgYW55IGRpZmZl
cmVudA0KdGhhbiBmb3Igb3RoZXIgZmZtcGVnIGRlY29kZXJzIChtcDIsIGgyNjQsIGhldmMg4oCT
IHN3LCBzYW1lIHRocmVlIGZvciBOVkRFQywgc2FtZSB0aHJlZQ0KZm9yIFZBQVBJLCBzYW1lIHRo
cmVlIGZvciBEM0QxMVZBKQ0KDQoNCkluIG1hbnkgdXNlLWNhc2VzLCB5b3Ugd2FudCB0aGVtIHRv
IGJlIGZyYW1lLWFjY3VyYXRlLiBGaW5hbCByZW5kaXRpb24gdG8gdGhlIHZpZXdlciBpcyBvbmx5
IG9uZSB1c2UtY2FzZSBvZiBGRm1wZWcgKHRvIGJlIGZhaXIsIHRoZSBsaWtlbHkgdXNlLWNhc2Ug
b2YgUVNWKQ0KDQoNCldoYXQgdGhpcyBwYXRjaHNldCBwcm92aWRlcyBmb3IgQ0MgaXM6DQoNCg0K
ICAqICAgUVNWIGRlY29kZXJzIGNyZWF0ZSBhbmQgYXR0YWNoIENDIHNpZGUgZGF0YSB0byBBVkZy
YW1lcw0KICAqICAgUVNWIGZpbHRlcnMgcHJlc2VydmUgQ0Mgc2lkZSBkYXRhIGZyb20gaW5wdXQg
dG8gb3V0cHV0DQogICogICBpbiBhbiBlYXJsaWVyIHBhdGNoIHdlIGFscmVhZHkgYWRkZWQgdGhl
IGFiaWxpdHkgdG8gYXR0YWNoIENDIGRhdGEgd2hlbiB1c2luZyBRU1YgZW5jb2RlcnMNCg0KVGhp
cyBhbGxvd3MgZm9yIGV4YW1wbGUgdG8gZG8gUVNWIGh3IGRlY29kaW5nLCBmaWx0ZXJpbmcgYW5k
IGVuY29kaW5nIHdoZXJlIENDIGRhdGENCmlzIHByZXNlcnZlZCBpbiB0aGUgb3V0cHV0IHZpZGVv
IC4NCg0KSW4gY29tYmluYXRpb24gd2l0aCBteSBTdWJ0aXRsZSBGaWx0ZXJpbmcgcGF0Y2hzZXQs
IHlvdSBjYW4gZG8gYWxtb3N0IGFueXRoaW5nIHlvdQ0KbGlrZSB3aXRoIGNsb3NlZCBjYXB0aW9u
cy4NCg0KWW91IGNhbiB3b3JrIHdpdGggdGhlbSBsaWtlIGFueSBvdGhlciBzdWJ0aXRsZSBkYXRh
IGFuZCBwcm9jZXNzIHRoZW0gd2l0aCB0aGUgbmV3DQpmaWx0ZXJzLCBlLmcuIG1hbmlwdWxhdGUg
dGhlIHRleHQgY29udGVudCwgY2hhbmdlIHN0eWxlcyBhbmQgYXBwZWFyYW5jZSwgbGlrZSBmb250
DQpzaXplcywgY29sb3JzLCBvdXRsaW5lcywgYmFja2dyb3VuZCBldGMuDQoNClRoZW4geW91IGNh
biBidXJuLWluIHRoZXNlIGludG8gdGhlIHZpZGVvLCBvciBlbmNvZGUgaW4gYW4gYXJiaXRyYXJ5
IHRleHQgc3VidGl0bGUNCmZvcm1hdC4gVGhlcmUgYXJlIG1hbnkgcG9zc2liaWxpdGllc+KApg0K
SnVzdCBvbmUgZXhhbXBsZToNCg0KW2NpZDppbWFnZTAwMS5wbmdAMDFEODc2MEUuQjE4RjA2RjBd
DQoNCkRvIHlvdSBoYXZlIGFuIGlkZWEgd2hlcmUvaG93IEkgY291bGQgZmluZCBzdWNoIHN0cmVh
bT8NCg0KWW91IHdvdWxkIG5lZWQgdG8gcmVjb3JkIHRoZW0gb2ZmIHZhcmlvdXMgdGVsZXZpc2lv
biBzZXJ2aWNlcyBhcyB0aGV5IHVzZSBhIHdpZGUgcmFuZ2Ugb2YgZW5jb2RlciBtYW51ZmFjdHVy
ZXJzLg0KSWRlYWxseSwgeW91IGNvdWxkIGFsc28gaW5qZWN0IHRoZW0gaW50byB2YXJpb3VzIGVu
Y29kZXJzIGFuZCBmb3JjZSB0aGVtIHRvIGJ1aWxkIGNvbXBsZXggcmVvcmRlcmluZyBwYXR0ZXJu
cyBhbmQgY2hlY2sgdGhleSBhcmUgZnJhbWUgYWNjdXJhdGUuDQoNCldlIGhhdmUgdXNlcnMgZnJv
bSBhbGwgb3ZlciB0aGUgVVMgd2l0aCBkaWZmZXJlbnQgdHVuZXJzIGFuZCBvbiBkaWZmZXJlbnQg
bmV0d29ya3MsDQp0aGVyZSBoYXMgbmV2ZXIgYmVlbiBhbiBpc3N1ZS4NCg0KV2hhdCBJIG1lYW50
IGlzIHRoZSDigJxWTEMgaGV1cmlzdGljc+KAnSBzdWJqZWN0IHlvdSBtZW50aW9uZWQgd2hldGhl
ciB5b3UgbWlnaHQNCmhhdmUgc29tZSBwb2ludGVyIHRvIGEgIGNvbW1pdCwgaXNzdWUsIGJ1ZyBy
ZXBvcnQgb3Igc2ltcGx5IGEgbmFtZSBob3cgdGhleSBjYWxsIHRoaXM/DQoNClRoYW5rcyBhZ2Fp
biwNCnN3DQoNCg0KDQo=

--_004_DM8P223MB0365E16BEF7963D534E4797ABADF9DM8P223MB0365NAMP_
Content-Type: image/png; name="image001.png"
Content-Description: image001.png
Content-Disposition: inline; filename="image001.png"; size=32096;
	creation-date="Wed, 01 Jun 2022 21:24:09 GMT";
	modification-date="Wed, 01 Jun 2022 21:24:10 GMT"
Content-ID: <[email protected]>
Content-Transfer-Encoding: base64

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
RK5CYII=

--_004_DM8P223MB0365E16BEF7963D534E4797ABADF9DM8P223MB0365NAMP_--

--===============3878171516236109284==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

--===============3878171516236109284==--

doc/APIchanges Outdated Show resolved Hide resolved
@softworkz
Copy link
Collaborator Author

/submit

@ffmpeg-codebot
Copy link

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-31/softworkz/submit_qsv_sei-v4

To fetch this version to local tag pr-ffstaging-31/softworkz/submit_qsv_sei-v4:

git fetch --no-tags https://github.com/ffstaging/FFmpeg tag pr-ffstaging-31/softworkz/submit_qsv_sei-v4

@ffmpeg-codebot
Copy link

On the FFmpeg mailing list, "Xiang, Haihao" wrote (reply to this):

On Sun, 2022-06-26 at 23:41 +0000, ffmpegagent wrote:
> Missing SEI information has always been a major drawback when using the QSV
> decoders. I used to think that there's no chance to get at the data without
> explicit implementation from the MSDK side (or doing something weird like
> parsing in parallel). It turned out that there's a hardly known api method
> that provides access to all SEI (h264/hevc) or user data (mpeg2video).
> 
> This allows to get things like closed captions, frame packing, display
> orientation, HDR data (mastering display, content light level, etc.) without
> having to rely on those data being provided by the MSDK as extended buffers.
> 
> The commit "Implement SEI parsing for QSV decoders" includes some hard-coded
> workarounds for MSDK bugs which I reported:
> 
https://github.com/Intel-Media-SDK/MediaSDK/issues/2597#issuecomment-1072795311
> 
> But that doesn't help. Those bugs exist and I'm sharing my workarounds,
> which are empirically determined by testing a range of files. If someone is
> interested, I can provide private access to a repository where we have been
> testing this. Alternatively, I could also leave those workarounds out, and
> just skip those SEI types.
> 
> In a previous version of this patchset, there was a concern that payload
> data might need to be re-ordered. Meanwhile I have researched this carefully
> and the conclusion is that this is not required.
> 
> My detailed analysis can be found here:
> https://gist.github.com/softworkz/36c49586a8610813a32270ee3947a932
> 
> v3
> 
>  * frame.h: clarify doc text for av_frame_copy_side_data()
> 
> v2
> 
>  * qsvdec: make error handling consistent and clear
>  * qsvdec: remove AV_CODEC_ID_MPEG1VIDEO constants
>  * hevcdec: rename function to ff_hevc_set_side_data(), add doc text
> 
> v3
> 
>  * qsvdec: fix c/p error
> 
> softworkz (6):
>   avutil/frame: Add av_frame_copy_side_data() and
>     av_frame_remove_all_side_data()
>   avcodec/vpp_qsv: Copy side data from input to output frame
>   avcodec/mpeg12dec: make mpeg_decode_user_data() accessible
>   avcodec/hevcdec: make set_side_data() accessible
>   avcodec/h264dec: make h264_export_frame_props() accessible
>   avcodec/qsvdec: Implement SEI parsing for QSV decoders
> 
>  doc/APIchanges               |   4 +
>  libavcodec/h264_slice.c      |  98 ++++++++-------
>  libavcodec/h264dec.h         |   2 +
>  libavcodec/hevcdec.c         | 117 +++++++++---------
>  libavcodec/hevcdec.h         |   9 ++
>  libavcodec/mpeg12.h          |  28 +++++
>  libavcodec/mpeg12dec.c       |  40 +-----
>  libavcodec/qsvdec.c          | 234 +++++++++++++++++++++++++++++++++++
>  libavfilter/qsvvpp.c         |   6 +
>  libavfilter/vf_overlay_qsv.c |  19 ++-
>  libavutil/frame.c            |  67 ++++++----
>  libavutil/frame.h            |  32 +++++
>  libavutil/version.h          |   2 +-
>  13 files changed, 485 insertions(+), 173 deletions(-)
> 
> 
> base-commit: 6a82412bf33108111eb3f63076fd5a51349ae114
> Published-As: 
> https://github.com/ffstaging/FFmpeg/releases/tag/pr-ffstaging-31%2Fsoftworkz%2Fsubmit_qsv_sei-v4
> Fetch-It-Via: git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-
> 31/softworkz/submit_qsv_sei-v4
> Pull-Request: https://github.com/ffstaging/FFmpeg/pull/31
> 
> Range-diff vs v3:
> 
>  1:  c442597a35 ! 1:  7656477360 avutil/frame: Add av_frame_copy_side_data()
> and av_frame_remove_all_side_data()
>      @@ doc/APIchanges: libavutil:     2021-04-27
>        
>        API changes, most recent first:
>        
>      -+2022-05-26 - xxxxxxxxx - lavu 57.26.100 - frame.h
>      ++2022-05-26 - xxxxxxxxx - lavu 57.28.100 - frame.h
>       +  Add av_frame_remove_all_side_data(), av_frame_copy_side_data(),
>       +  AV_FRAME_TRANSFER_SD_COPY, and AV_FRAME_TRANSFER_SD_FILTER.
>       +
>      - 2022-05-23 - xxxxxxxxx - lavu 57.25.100 - avutil.h
>      -   Deprecate av_fopen_utf8() without replacement.
>      - 
>      + 2022-06-12 - xxxxxxxxxx - lavf 59.25.100 - avio.h
>      +   Add avio_vprintf(), similar to avio_printf() but allow to use it
>      +   from within a function taking a variable argument list as input.
>       
>        ## libavutil/frame.c ##
>       @@ libavutil/frame.c: FF_ENABLE_DEPRECATION_WARNINGS
>      @@ libavutil/frame.h: int av_frame_copy(AVFrame *dst, const AVFrame
> *src);
>       + * @param src a frame from which to copy the side data.
>       + * @param flags a combination of AV_FRAME_TRANSFER_SD_*
>       + *
>      -+ * @return >= 0 on success, a negative AVERROR on error.
>      ++ * @return 0 on success, a negative AVERROR on error.
>       + *
>       + * @note This function will create new references to side data buffers
> in src,
>       + * unless the AV_FRAME_TRANSFER_SD_COPY flag is passed.
>      @@ libavutil/version.h
>         */
>        
>        #define LIBAVUTIL_VERSION_MAJOR  57
>      --#define LIBAVUTIL_VERSION_MINOR  25
>      -+#define LIBAVUTIL_VERSION_MINOR  26
>      +-#define LIBAVUTIL_VERSION_MINOR  27
>      ++#define LIBAVUTIL_VERSION_MINOR  28
>        #define LIBAVUTIL_VERSION_MICRO 100
>        
>        #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR,
> \
>  2:  6f50d0bd57 = 2:  06976606c5 avcodec/vpp_qsv: Copy side data from input to
> output frame
>  3:  f682b1d695 = 3:  320a8a535c avcodec/mpeg12dec: make
> mpeg_decode_user_data() accessible
>  4:  995d835233 = 4:  e58ad6564f avcodec/hevcdec: make set_side_data()
> accessible
>  5:  ac8dc06395 = 5:  a57bfaebb9 avcodec/h264dec: make
> h264_export_frame_props() accessible
>  6:  27c3dded4d = 6:  3f2588563e avcodec/qsvdec: Implement SEI parsing for QSV
> decoders

Patchset LGTM,

-Haihao

_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

@@ -49,6 +49,12 @@
#include "hwconfig.h"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the FFmpeg mailing list, Andreas Rheinhardt wrote (reply to this):

softworkz:
> From: softworkz <[email protected]>
> 
> Signed-off-by: softworkz <[email protected]>
> ---
>  libavcodec/qsvdec.c | 234 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 234 insertions(+)
> 
> diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
> index 5fc5bed4c8..e854f363ec 100644
> --- a/libavcodec/qsvdec.c
> +++ b/libavcodec/qsvdec.c
> @@ -49,6 +49,12 @@
>  #include "hwconfig.h"
>  #include "qsv.h"
>  #include "qsv_internal.h"
> +#include "h264dec.h"
> +#include "h264_sei.h"
> +#include "hevcdec.h"
> +#include "hevc_ps.h"
> +#include "hevc_sei.h"
> +#include "mpeg12.h"
>  
>  static const AVRational mfx_tb = { 1, 90000 };
>  
> @@ -60,6 +66,8 @@ static const AVRational mfx_tb = { 1, 90000 };
>      AV_NOPTS_VALUE : pts_tb.num ? \
>      av_rescale_q(mfx_pts, mfx_tb, pts_tb) : mfx_pts)
>  
> +#define PAYLOAD_BUFFER_SIZE 65535
> +
>  typedef struct QSVAsyncFrame {
>      mfxSyncPoint *sync;
>      QSVFrame     *frame;
> @@ -101,6 +109,9 @@ typedef struct QSVContext {
>  
>      mfxExtBuffer **ext_buffers;
>      int         nb_ext_buffers;
> +
> +    mfxU8 payload_buffer[PAYLOAD_BUFFER_SIZE];
> +    Mpeg1Context mpeg_ctx;
>  } QSVContext;
>  
>  static const AVCodecHWConfigInternal *const qsv_hw_configs[] = {
> @@ -599,6 +610,210 @@ static int qsv_export_film_grain(AVCodecContext *avctx, mfxExtAV1FilmGrainParam
>      return 0;
>  }
>  #endif
> +static int find_start_offset(mfxU8 data[4])
> +{
> +    if (data[0] == 0 && data[1] == 0 && data[2] == 1)
> +        return 3;
> +
> +    if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 1)
> +        return 4;
> +
> +    return 0;
> +}
> +
> +static int parse_sei_h264(AVCodecContext* avctx, QSVContext* q, AVFrame* out)
> +{
> +    H264SEIContext sei = { 0 };
> +    GetBitContext gb = { 0 };
> +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize = sizeof(q->payload_buffer) };
> +    mfxU64 ts;
> +    int ret;
> +
> +    while (1) {
> +        int start;
> +        memset(payload.Data, 0, payload.BufSize);
> +
> +        ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
> +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q->payload_buffer), payload.BufSize);
> +            return 0;
> +        }
> +        if (ret != MFX_ERR_NONE)
> +            return ret;
> +
> +        if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8)
> +            break;
> +
> +        start = find_start_offset(payload.Data);
> +
> +        switch (payload.Type) {
> +            case SEI_TYPE_BUFFERING_PERIOD:
> +            case SEI_TYPE_PIC_TIMING:
> +                continue;
> +        }
> +
> +        if (init_get_bits(&gb, &payload.Data[start], payload.NumBit - start * 8) < 0)
> +            av_log(avctx, AV_LOG_ERROR, "Error initializing bitstream reader SEI type: %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> +        else {
> +            ret = ff_h264_sei_decode(&sei, &gb, NULL, avctx);
> +
> +            if (ret < 0)
> +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI type: %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> +            else
> +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d  Numbits %d\n", payload.Type, payload.NumBit);
> +        }
> +    }
> +
> +    if (out)
> +        return ff_h264_export_frame_props(avctx, &sei, NULL, out);
> +
> +    return 0;
> +}
> +
> +static int parse_sei_hevc(AVCodecContext* avctx, QSVContext* q, QSVFrame* out)
> +{
> +    HEVCSEI sei = { 0 };
> +    HEVCParamSets ps = { 0 };
> +    GetBitContext gb = { 0 };
> +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize = sizeof(q->payload_buffer) };
> +    mfxFrameSurface1 *surface = &out->surface;
> +    mfxU64 ts;
> +    int ret, has_logged = 0;
> +
> +    while (1) {
> +        int start;
> +        memset(payload.Data, 0, payload.BufSize);
> +
> +        ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
> +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q->payload_buffer), payload.BufSize);
> +            return 0;
> +        }
> +        if (ret != MFX_ERR_NONE)
> +            return ret;
> +
> +        if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8)
> +            break;
> +
> +        if (!has_logged) {
> +            has_logged = 1;
> +            av_log(avctx, AV_LOG_VERBOSE, "-----------------------------------------\n");
> +            av_log(avctx, AV_LOG_VERBOSE, "Start reading SEI - payload timestamp: %llu - surface timestamp: %llu\n", ts, surface->Data.TimeStamp);
> +        }
> +
> +        if (ts != surface->Data.TimeStamp) {
> +            av_log(avctx, AV_LOG_WARNING, "GetPayload timestamp (%llu) does not match surface timestamp: (%llu)\n", ts, surface->Data.TimeStamp);
> +        }
> +
> +        start = find_start_offset(payload.Data);
> +
> +        av_log(avctx, AV_LOG_VERBOSE, "parsing SEI type: %3d  Numbits %3d  Start: %d\n", payload.Type, payload.NumBit, start);
> +
> +        switch (payload.Type) {
> +            case SEI_TYPE_BUFFERING_PERIOD:
> +            case SEI_TYPE_PIC_TIMING:
> +                continue;
> +            case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
> +                // There seems to be a bug in MSDK
> +                payload.NumBit -= 8;
> +
> +                break;
> +            case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO:
> +                // There seems to be a bug in MSDK
> +                payload.NumBit = 48;
> +
> +                break;
> +            case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
> +                // There seems to be a bug in MSDK
> +                if (payload.NumBit == 552)
> +                    payload.NumBit = 528;
> +                break;
> +        }
> +
> +        if (init_get_bits(&gb, &payload.Data[start], payload.NumBit - start * 8) < 0)
> +            av_log(avctx, AV_LOG_ERROR, "Error initializing bitstream reader SEI type: %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> +        else {
> +            ret = ff_hevc_decode_nal_sei(&gb, avctx, &sei, &ps, HEVC_NAL_SEI_PREFIX);
> +
> +            if (ret < 0)
> +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI type: %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> +            else
> +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d  Numbits %d\n", payload.Type, payload.NumBit);
> +        }
> +    }
> +
> +    if (has_logged) {
> +        av_log(avctx, AV_LOG_VERBOSE, "End reading SEI\n");
> +    }
> +
> +    if (out && out->frame)
> +        return ff_hevc_set_side_data(avctx, &sei, NULL, out->frame);
> +
> +    return 0;
> +}
> +
> +static int parse_sei_mpeg12(AVCodecContext* avctx, QSVContext* q, AVFrame* out)
> +{
> +    Mpeg1Context *mpeg_ctx = &q->mpeg_ctx;
> +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize = sizeof(q->payload_buffer) };
> +    mfxU64 ts;
> +    int ret;
> +
> +    while (1) {
> +        int start;
> +
> +        memset(payload.Data, 0, payload.BufSize);
> +        ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
> +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q->payload_buffer), payload.BufSize);
> +            return 0;
> +        }
> +        if (ret != MFX_ERR_NONE)
> +            return ret;
> +
> +        if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8)
> +            break;
> +
> +        start = find_start_offset(payload.Data);
> +
> +        start++;
> +
> +        ff_mpeg_decode_user_data(avctx, mpeg_ctx, &payload.Data[start], (int)((payload.NumBit + 7) / 8) - start);
> +
> +        av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d  Numbits %d start %d -> %.s\n", payload.Type, payload.NumBit, start, (char *)(&payload.Data[start]));
> +    }
> +
> +    if (!out)
> +        return 0;
> +
> +    if (mpeg_ctx->a53_buf_ref) {
> +
> +        AVFrameSideData *sd = av_frame_new_side_data_from_buf(out, AV_FRAME_DATA_A53_CC, mpeg_ctx->a53_buf_ref);
> +        if (!sd)
> +            av_buffer_unref(&mpeg_ctx->a53_buf_ref);
> +        mpeg_ctx->a53_buf_ref = NULL;
> +    }
> +
> +    if (mpeg_ctx->has_stereo3d) {
> +        AVStereo3D *stereo = av_stereo3d_create_side_data(out);
> +        if (!stereo)
> +            return AVERROR(ENOMEM);
> +
> +        *stereo = mpeg_ctx->stereo3d;
> +        mpeg_ctx->has_stereo3d = 0;
> +    }
> +
> +    if (mpeg_ctx->has_afd) {
> +        AVFrameSideData *sd = av_frame_new_side_data(out, AV_FRAME_DATA_AFD, 1);
> +        if (!sd)
> +            return AVERROR(ENOMEM);
> +
> +        *sd->data   = mpeg_ctx->afd;
> +        mpeg_ctx->has_afd = 0;
> +    }
> +
> +    return 0;
> +}
>  
>  static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
>                        AVFrame *frame, int *got_frame,
> @@ -636,6 +851,8 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
>                                                insurf, &outsurf, sync);
>          if (ret == MFX_WRN_DEVICE_BUSY)
>              av_usleep(500);
> +        else if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
> +            parse_sei_mpeg12(avctx, q, NULL);
>  
>      } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE);
>  
> @@ -677,6 +894,23 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
>              return AVERROR_BUG;
>          }
>  
> +        switch (avctx->codec_id) {
> +        case AV_CODEC_ID_MPEG2VIDEO:
> +            ret = parse_sei_mpeg12(avctx, q, out_frame->frame);
> +            break;
> +        case AV_CODEC_ID_H264:
> +            ret = parse_sei_h264(avctx, q, out_frame->frame);
> +            break;
> +        case AV_CODEC_ID_HEVC:
> +            ret = parse_sei_hevc(avctx, q, out_frame);
> +            break;
> +        default:
> +            ret = 0;
> +        }
> +
> +        if (ret < 0)
> +            av_log(avctx, AV_LOG_ERROR, "Error parsing SEI data: %d\n", ret);
> +
>          out_frame->queued += 1;
>  
>          aframe = (QSVAsyncFrame){ sync, out_frame };

You completely forgot necessary changes to configure/the Makefile. The
way you are doing it here means that you basically have the qsv decoders
to rely on the H.264/HEVC/MPEG-1/2 decoders which is way too much.

- Andreas
_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the FFmpeg mailing list, Soft Works wrote (reply to this):



> -----Original Message-----
> From: ffmpeg-devel <[email protected]> On Behalf Of
> Andreas Rheinhardt
> Sent: Tuesday, June 28, 2022 6:17 AM
> To: [email protected]
> Subject: Re: [FFmpeg-devel] [PATCH v4 6/6] avcodec/qsvdec: Implement
> SEI parsing for QSV decoders
> 
> softworkz:
> > From: softworkz <[email protected]>
> >
> > Signed-off-by: softworkz <[email protected]>
> > ---
> >  libavcodec/qsvdec.c | 234
> ++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 234 insertions(+)
> >
> > diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
> > index 5fc5bed4c8..e854f363ec 100644
> > --- a/libavcodec/qsvdec.c
> > +++ b/libavcodec/qsvdec.c
> > @@ -49,6 +49,12 @@
> >  #include "hwconfig.h"
> >  #include "qsv.h"
> >  #include "qsv_internal.h"
> > +#include "h264dec.h"
> > +#include "h264_sei.h"
> > +#include "hevcdec.h"
> > +#include "hevc_ps.h"
> > +#include "hevc_sei.h"
> > +#include "mpeg12.h"
> >
> >  static const AVRational mfx_tb = { 1, 90000 };
> >
> > @@ -60,6 +66,8 @@ static const AVRational mfx_tb = { 1, 90000 };
> >      AV_NOPTS_VALUE : pts_tb.num ? \
> >      av_rescale_q(mfx_pts, mfx_tb, pts_tb) : mfx_pts)
> >
> > +#define PAYLOAD_BUFFER_SIZE 65535
> > +
> >  typedef struct QSVAsyncFrame {
> >      mfxSyncPoint *sync;
> >      QSVFrame     *frame;
> > @@ -101,6 +109,9 @@ typedef struct QSVContext {
> >
> >      mfxExtBuffer **ext_buffers;
> >      int         nb_ext_buffers;
> > +
> > +    mfxU8 payload_buffer[PAYLOAD_BUFFER_SIZE];
> > +    Mpeg1Context mpeg_ctx;
> >  } QSVContext;
> >
> >  static const AVCodecHWConfigInternal *const qsv_hw_configs[] = {
> > @@ -599,6 +610,210 @@ static int
> qsv_export_film_grain(AVCodecContext *avctx, mfxExtAV1FilmGrainParam
> >      return 0;
> >  }
> >  #endif
> > +static int find_start_offset(mfxU8 data[4])
> > +{
> > +    if (data[0] == 0 && data[1] == 0 && data[2] == 1)
> > +        return 3;
> > +
> > +    if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] ==
> 1)
> > +        return 4;
> > +
> > +    return 0;
> > +}
> > +
> > +static int parse_sei_h264(AVCodecContext* avctx, QSVContext* q,
> AVFrame* out)
> > +{
> > +    H264SEIContext sei = { 0 };
> > +    GetBitContext gb = { 0 };
> > +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0],
> .BufSize = sizeof(q->payload_buffer) };
> > +    mfxU64 ts;
> > +    int ret;
> > +
> > +    while (1) {
> > +        int start;
> > +        memset(payload.Data, 0, payload.BufSize);
> > +
> > +        ret = MFXVideoDECODE_GetPayload(q->session, &ts,
> &payload);
> > +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> > +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient
> buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q-
> >payload_buffer), payload.BufSize);
> > +            return 0;
> > +        }
> > +        if (ret != MFX_ERR_NONE)
> > +            return ret;
> > +
> > +        if (payload.NumBit == 0 || payload.NumBit >=
> payload.BufSize * 8)
> > +            break;
> > +
> > +        start = find_start_offset(payload.Data);
> > +
> > +        switch (payload.Type) {
> > +            case SEI_TYPE_BUFFERING_PERIOD:
> > +            case SEI_TYPE_PIC_TIMING:
> > +                continue;
> > +        }
> > +
> > +        if (init_get_bits(&gb, &payload.Data[start],
> payload.NumBit - start * 8) < 0)
> > +            av_log(avctx, AV_LOG_ERROR, "Error initializing
> bitstream reader SEI type: %d  Numbits %d error: %d\n", payload.Type,
> payload.NumBit, ret);
> > +        else {
> > +            ret = ff_h264_sei_decode(&sei, &gb, NULL, avctx);
> > +
> > +            if (ret < 0)
> > +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI
> type: %d  Numbits %d error: %d\n", payload.Type, payload.NumBit,
> ret);
> > +            else
> > +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d
> Numbits %d\n", payload.Type, payload.NumBit);
> > +        }
> > +    }
> > +
> > +    if (out)
> > +        return ff_h264_export_frame_props(avctx, &sei, NULL, out);
> > +
> > +    return 0;
> > +}
> > +
> > +static int parse_sei_hevc(AVCodecContext* avctx, QSVContext* q,
> QSVFrame* out)
> > +{
> > +    HEVCSEI sei = { 0 };
> > +    HEVCParamSets ps = { 0 };
> > +    GetBitContext gb = { 0 };
> > +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0],
> .BufSize = sizeof(q->payload_buffer) };
> > +    mfxFrameSurface1 *surface = &out->surface;
> > +    mfxU64 ts;
> > +    int ret, has_logged = 0;
> > +
> > +    while (1) {
> > +        int start;
> > +        memset(payload.Data, 0, payload.BufSize);
> > +
> > +        ret = MFXVideoDECODE_GetPayload(q->session, &ts,
> &payload);
> > +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> > +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient
> buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q-
> >payload_buffer), payload.BufSize);
> > +            return 0;
> > +        }
> > +        if (ret != MFX_ERR_NONE)
> > +            return ret;
> > +
> > +        if (payload.NumBit == 0 || payload.NumBit >=
> payload.BufSize * 8)
> > +            break;
> > +
> > +        if (!has_logged) {
> > +            has_logged = 1;
> > +            av_log(avctx, AV_LOG_VERBOSE, "-----------------------
> ------------------\n");
> > +            av_log(avctx, AV_LOG_VERBOSE, "Start reading SEI -
> payload timestamp: %llu - surface timestamp: %llu\n", ts, surface-
> >Data.TimeStamp);
> > +        }
> > +
> > +        if (ts != surface->Data.TimeStamp) {
> > +            av_log(avctx, AV_LOG_WARNING, "GetPayload timestamp
> (%llu) does not match surface timestamp: (%llu)\n", ts, surface-
> >Data.TimeStamp);
> > +        }
> > +
> > +        start = find_start_offset(payload.Data);
> > +
> > +        av_log(avctx, AV_LOG_VERBOSE, "parsing SEI type: %3d
> Numbits %3d  Start: %d\n", payload.Type, payload.NumBit, start);
> > +
> > +        switch (payload.Type) {
> > +            case SEI_TYPE_BUFFERING_PERIOD:
> > +            case SEI_TYPE_PIC_TIMING:
> > +                continue;
> > +            case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
> > +                // There seems to be a bug in MSDK
> > +                payload.NumBit -= 8;
> > +
> > +                break;
> > +            case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO:
> > +                // There seems to be a bug in MSDK
> > +                payload.NumBit = 48;
> > +
> > +                break;
> > +            case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
> > +                // There seems to be a bug in MSDK
> > +                if (payload.NumBit == 552)
> > +                    payload.NumBit = 528;
> > +                break;
> > +        }
> > +
> > +        if (init_get_bits(&gb, &payload.Data[start],
> payload.NumBit - start * 8) < 0)
> > +            av_log(avctx, AV_LOG_ERROR, "Error initializing
> bitstream reader SEI type: %d  Numbits %d error: %d\n", payload.Type,
> payload.NumBit, ret);
> > +        else {
> > +            ret = ff_hevc_decode_nal_sei(&gb, avctx, &sei, &ps,
> HEVC_NAL_SEI_PREFIX);
> > +
> > +            if (ret < 0)
> > +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI
> type: %d  Numbits %d error: %d\n", payload.Type, payload.NumBit,
> ret);
> > +            else
> > +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d
> Numbits %d\n", payload.Type, payload.NumBit);
> > +        }
> > +    }
> > +
> > +    if (has_logged) {
> > +        av_log(avctx, AV_LOG_VERBOSE, "End reading SEI\n");
> > +    }
> > +
> > +    if (out && out->frame)
> > +        return ff_hevc_set_side_data(avctx, &sei, NULL, out-
> >frame);
> > +
> > +    return 0;
> > +}
> > +
> > +static int parse_sei_mpeg12(AVCodecContext* avctx, QSVContext* q,
> AVFrame* out)
> > +{
> > +    Mpeg1Context *mpeg_ctx = &q->mpeg_ctx;
> > +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0],
> .BufSize = sizeof(q->payload_buffer) };
> > +    mfxU64 ts;
> > +    int ret;
> > +
> > +    while (1) {
> > +        int start;
> > +
> > +        memset(payload.Data, 0, payload.BufSize);
> > +        ret = MFXVideoDECODE_GetPayload(q->session, &ts,
> &payload);
> > +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> > +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient
> buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q-
> >payload_buffer), payload.BufSize);
> > +            return 0;
> > +        }
> > +        if (ret != MFX_ERR_NONE)
> > +            return ret;
> > +
> > +        if (payload.NumBit == 0 || payload.NumBit >=
> payload.BufSize * 8)
> > +            break;
> > +
> > +        start = find_start_offset(payload.Data);
> > +
> > +        start++;
> > +
> > +        ff_mpeg_decode_user_data(avctx, mpeg_ctx,
> &payload.Data[start], (int)((payload.NumBit + 7) / 8) - start);
> > +
> > +        av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d  Numbits
> %d start %d -> %.s\n", payload.Type, payload.NumBit, start, (char
> *)(&payload.Data[start]));
> > +    }
> > +
> > +    if (!out)
> > +        return 0;
> > +
> > +    if (mpeg_ctx->a53_buf_ref) {
> > +
> > +        AVFrameSideData *sd = av_frame_new_side_data_from_buf(out,
> AV_FRAME_DATA_A53_CC, mpeg_ctx->a53_buf_ref);
> > +        if (!sd)
> > +            av_buffer_unref(&mpeg_ctx->a53_buf_ref);
> > +        mpeg_ctx->a53_buf_ref = NULL;
> > +    }
> > +
> > +    if (mpeg_ctx->has_stereo3d) {
> > +        AVStereo3D *stereo = av_stereo3d_create_side_data(out);
> > +        if (!stereo)
> > +            return AVERROR(ENOMEM);
> > +
> > +        *stereo = mpeg_ctx->stereo3d;
> > +        mpeg_ctx->has_stereo3d = 0;
> > +    }
> > +
> > +    if (mpeg_ctx->has_afd) {
> > +        AVFrameSideData *sd = av_frame_new_side_data(out,
> AV_FRAME_DATA_AFD, 1);
> > +        if (!sd)
> > +            return AVERROR(ENOMEM);
> > +
> > +        *sd->data   = mpeg_ctx->afd;
> > +        mpeg_ctx->has_afd = 0;
> > +    }
> > +
> > +    return 0;
> > +}
> >
> >  static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
> >                        AVFrame *frame, int *got_frame,
> > @@ -636,6 +851,8 @@ static int qsv_decode(AVCodecContext *avctx,
> QSVContext *q,
> >                                                insurf, &outsurf,
> sync);
> >          if (ret == MFX_WRN_DEVICE_BUSY)
> >              av_usleep(500);
> > +        else if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
> > +            parse_sei_mpeg12(avctx, q, NULL);
> >
> >      } while (ret == MFX_WRN_DEVICE_BUSY || ret ==
> MFX_ERR_MORE_SURFACE);
> >
> > @@ -677,6 +894,23 @@ static int qsv_decode(AVCodecContext *avctx,
> QSVContext *q,
> >              return AVERROR_BUG;
> >          }
> >
> > +        switch (avctx->codec_id) {
> > +        case AV_CODEC_ID_MPEG2VIDEO:
> > +            ret = parse_sei_mpeg12(avctx, q, out_frame->frame);
> > +            break;
> > +        case AV_CODEC_ID_H264:
> > +            ret = parse_sei_h264(avctx, q, out_frame->frame);
> > +            break;
> > +        case AV_CODEC_ID_HEVC:
> > +            ret = parse_sei_hevc(avctx, q, out_frame);
> > +            break;
> > +        default:
> > +            ret = 0;
> > +        }
> > +
> > +        if (ret < 0)
> > +            av_log(avctx, AV_LOG_ERROR, "Error parsing SEI data:
> %d\n", ret);
> > +
> >          out_frame->queued += 1;
> >
> >          aframe = (QSVAsyncFrame){ sync, out_frame };
> 
> You completely forgot necessary changes to configure/the Makefile.
> The
> way you are doing it here means that you basically have the qsv
> decoders
> to rely on the H.264/HEVC/MPEG-1/2 decoders which is way too much.

You are referring to the hypothetical case where one would disable
one of the sw decoders while having a qsv decoder enabled, right?

The SEI parsing code is not trivial and tied to those decoders 
(means using these contexts). It would be not a straightforward
task to extract/separate those parts, that's why I preferred to
just make that functionality accessible.
I wouldn't mind when the QSV decoders would be dependent on those
decoders being included in compilation, even more when considering
that so many other hwaccel decoders have the same dependencies;
DXVA2, D3D11VA, NVDEC, VAAPI.

The question would be whether to not build the qsv decoders when
the sw decoders are deselected or whether to build the sw decoder
code even these are disabled. AFAIU, both would be possible?

Or would you have a better idea?

Thanks,
sw







_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

@ffmpeg-codebot
Copy link

User Andreas Rheinhardt <[email protected]> has been added to the cc: list.

@softworkz
Copy link
Collaborator Author

/submit

@ffmpeg-codebot
Copy link

ffmpeg-codebot bot commented Jul 1, 2022

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-31/softworkz/submit_qsv_sei-v5

To fetch this version to local tag pr-ffstaging-31/softworkz/submit_qsv_sei-v5:

git fetch --no-tags https://github.com/ffstaging/FFmpeg tag pr-ffstaging-31/softworkz/submit_qsv_sei-v5

@ffmpeg-codebot
Copy link

On the FFmpeg mailing list, "Xiang, Haihao" wrote (reply to this):

On Fri, 2022-07-01 at 20:48 +0000, ffmpegagent wrote:
> Missing SEI information has always been a major drawback when using the QSV
> decoders. I used to think that there's no chance to get at the data without
> explicit implementation from the MSDK side (or doing something weird like
> parsing in parallel). It turned out that there's a hardly known api method
> that provides access to all SEI (h264/hevc) or user data (mpeg2video).
> 
> This allows to get things like closed captions, frame packing, display
> orientation, HDR data (mastering display, content light level, etc.) without
> having to rely on those data being provided by the MSDK as extended buffers.
> 
> The commit "Implement SEI parsing for QSV decoders" includes some hard-coded
> workarounds for MSDK bugs which I reported:
> 
https://github.com/Intel-Media-SDK/MediaSDK/issues/2597#issuecomment-1072795311
> 
> But that doesn't help. Those bugs exist and I'm sharing my workarounds,
> which are empirically determined by testing a range of files. If someone is
> interested, I can provide private access to a repository where we have been
> testing this. Alternatively, I could also leave those workarounds out, and
> just skip those SEI types.
> 
> In a previous version of this patchset, there was a concern that payload
> data might need to be re-ordered. Meanwhile I have researched this carefully
> and the conclusion is that this is not required.
> 
> My detailed analysis can be found here:
> https://gist.github.com/softworkz/36c49586a8610813a32270ee3947a932
> 
> v4
> 
>  * add new dependencies in makefile Now, build still works when someone uses
>    configure --disable-decoder=h264 --disable-decoder=hevc
>    --disable-decoder=mpegvideo --disable-decoder=mpeg1video
>    --disable-decoder=mpeg2video --enable-libmfx
> 
> v3
> 
>  * frame.h: clarify doc text for av_frame_copy_side_data()
> 
> v2
> 
>  * qsvdec: make error handling consistent and clear
>  * qsvdec: remove AV_CODEC_ID_MPEG1VIDEO constants
>  * hevcdec: rename function to ff_hevc_set_side_data(), add doc text
> 
> v3
> 
>  * qsvdec: fix c/p error
> 
> softworkz (6):
>   avutil/frame: Add av_frame_copy_side_data() and
>     av_frame_remove_all_side_data()
>   avcodec/vpp_qsv: Copy side data from input to output frame
>   avcodec/mpeg12dec: make mpeg_decode_user_data() accessible
>   avcodec/hevcdec: make set_side_data() accessible
>   avcodec/h264dec: make h264_export_frame_props() accessible
>   avcodec/qsvdec: Implement SEI parsing for QSV decoders
> 
>  doc/APIchanges               |   4 +
>  libavcodec/Makefile          |   6 +-
>  libavcodec/h264_slice.c      |  98 ++++++++-------
>  libavcodec/h264dec.h         |   2 +
>  libavcodec/hevcdec.c         | 117 +++++++++---------
>  libavcodec/hevcdec.h         |   9 ++
>  libavcodec/hevcdsp.c         |   4 +
>  libavcodec/mpeg12.h          |  28 +++++
>  libavcodec/mpeg12dec.c       |  40 +-----
>  libavcodec/qsvdec.c          | 234 +++++++++++++++++++++++++++++++++++
>  libavfilter/qsvvpp.c         |   6 +
>  libavfilter/vf_overlay_qsv.c |  19 ++-
>  libavutil/frame.c            |  67 ++++++----
>  libavutil/frame.h            |  32 +++++
>  libavutil/version.h          |   2 +-
>  15 files changed, 494 insertions(+), 174 deletions(-)
> 
> 
> base-commit: 6a82412bf33108111eb3f63076fd5a51349ae114
> Published-As: 
> https://github.com/ffstaging/FFmpeg/releases/tag/pr-ffstaging-31%2Fsoftworkz%2Fsubmit_qsv_sei-v5
> Fetch-It-Via: git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-
> 31/softworkz/submit_qsv_sei-v5
> Pull-Request: https://github.com/ffstaging/FFmpeg/pull/31
> 
> Range-diff vs v4:
> 
>  1:  7656477360 = 1:  7656477360 avutil/frame: Add av_frame_copy_side_data()
> and av_frame_remove_all_side_data()
>  2:  06976606c5 = 2:  06976606c5 avcodec/vpp_qsv: Copy side data from input to
> output frame
>  3:  320a8a535c = 3:  320a8a535c avcodec/mpeg12dec: make
> mpeg_decode_user_data() accessible
>  4:  e58ad6564f = 4:  e58ad6564f avcodec/hevcdec: make set_side_data()
> accessible
>  5:  a57bfaebb9 = 5:  4c0b6eb4cb avcodec/h264dec: make
> h264_export_frame_props() accessible
>  6:  3f2588563e ! 6:  19bc00be4d avcodec/qsvdec: Implement SEI parsing for QSV
> decoders
>      @@ Commit message
>       
>           Signed-off-by: softworkz <[email protected]>
>       
>      + ## libavcodec/Makefile ##
>      +@@ libavcodec/Makefile: OBJS-$(CONFIG_MSS34DSP)                +=
> mss34dsp.o
>      + OBJS-$(CONFIG_PIXBLOCKDSP)             += pixblockdsp.o
>      + OBJS-$(CONFIG_QPELDSP)                 += qpeldsp.o
>      + OBJS-$(CONFIG_QSV)                     += qsv.o
>      +-OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o
>      ++OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o h264_slice.o
> h264_cabac.o h264_cavlc.o \
>      ++                                          h264_direct.o h264_mb.o
> h264_picture.o h264_loopfilter.o \
>      ++                                          h264dec.o h264_refs.o cabac.o
> hevcdec.o hevc_refs.o \
>      ++										
>   hevc_filter.o hevc_cabac.o hevc_mvs.o hevcpred.o hevcdsp.o \
>      ++										
>   h274.o dovi_rpu.o mpeg12dec.o
>      + OBJS-$(CONFIG_QSVENC)                  += qsvenc.o
>      + OBJS-$(CONFIG_RANGECODER)              += rangecoder.o
>      + OBJS-$(CONFIG_RDFT)                    += rdft.o
>      +
>      + ## libavcodec/hevcdsp.c ##
>      +@@
>      +  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-
> 1301 USA
>      +  */
>      + 
>      ++#include "config_components.h"
>      ++
>      + #include "hevcdsp.h"
>      + 
>      + static const int8_t transform[32][32] = {
>      +@@ libavcodec/hevcdsp.c: int i = 0;
>      +         break;
>      +     }
>      + 
>      ++#if CONFIG_HEVC_DECODER
>      + #if ARCH_AARCH64
>      +     ff_hevc_dsp_init_aarch64(hevcdsp, bit_depth);
>      + #elif ARCH_ARM
>      +@@ libavcodec/hevcdsp.c: int i = 0;
>      + #elif ARCH_LOONGARCH
>      +     ff_hevc_dsp_init_loongarch(hevcdsp, bit_depth);
>      + #endif
>      ++#endif
>      + }
>      +
>        ## libavcodec/qsvdec.c ##
>       @@
>        #include "hwconfig.h"


Is there any comment on this patchset ? If not, I'd like to merge it to make QSV
decoders works with SEI info.

Thanks
Haihao


> 
_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

@ffmpeg-codebot
Copy link

On the FFmpeg mailing list, Soft Works wrote (reply to this):



> -----Original Message-----
> From: Xiang, Haihao <[email protected]>
> Sent: Tuesday, July 19, 2022 8:55 AM
> To: [email protected]
> Cc: [email protected]; [email protected]; haihao.xiang-at-
> [email protected]; [email protected]
> Subject: Re: [FFmpeg-devel] [PATCH v5 0/6] Implement SEI parsing for
> QSV decoders
> 
> On Fri, 2022-07-01 at 20:48 +0000, ffmpegagent wrote:
> > Missing SEI information has always been a major drawback when using
> the QSV
> > decoders. I used to think that there's no chance to get at the data
> without
> > explicit implementation from the MSDK side (or doing something
> weird like
> > parsing in parallel). It turned out that there's a hardly known api
> method
> > that provides access to all SEI (h264/hevc) or user data
> (mpeg2video).
> >
> > This allows to get things like closed captions, frame packing,
> display
> > orientation, HDR data (mastering display, content light level,
> etc.) without
> > having to rely on those data being provided by the MSDK as extended
> buffers.
> >
> > The commit "Implement SEI parsing for QSV decoders" includes some
> hard-coded
> > workarounds for MSDK bugs which I reported:
> >
> https://github.com/Intel-Media-SDK/MediaSDK/issues/2597#issuecomment-
> 1072795311
> >
> > But that doesn't help. Those bugs exist and I'm sharing my
> workarounds,
> > which are empirically determined by testing a range of files. If
> someone is
> > interested, I can provide private access to a repository where we
> have been
> > testing this. Alternatively, I could also leave those workarounds
> out, and
> > just skip those SEI types.
> >
> > In a previous version of this patchset, there was a concern that
> payload
> > data might need to be re-ordered. Meanwhile I have researched this
> carefully
> > and the conclusion is that this is not required.
> >
> > My detailed analysis can be found here:
> > https://gist.github.com/softworkz/36c49586a8610813a32270ee3947a932
> >
> > v4
> >
> >  * add new dependencies in makefile Now, build still works when
> someone uses
> >    configure --disable-decoder=h264 --disable-decoder=hevc
> >    --disable-decoder=mpegvideo --disable-decoder=mpeg1video
> >    --disable-decoder=mpeg2video --enable-libmfx
> >
> > v3
> >
> >  * frame.h: clarify doc text for av_frame_copy_side_data()
> >
> > v2
> >
> >  * qsvdec: make error handling consistent and clear
> >  * qsvdec: remove AV_CODEC_ID_MPEG1VIDEO constants
> >  * hevcdec: rename function to ff_hevc_set_side_data(), add doc
> text
> >
> > v3
> >
> >  * qsvdec: fix c/p error
> >
> > softworkz (6):
> >   avutil/frame: Add av_frame_copy_side_data() and
> >     av_frame_remove_all_side_data()
> >   avcodec/vpp_qsv: Copy side data from input to output frame
> >   avcodec/mpeg12dec: make mpeg_decode_user_data() accessible
> >   avcodec/hevcdec: make set_side_data() accessible
> >   avcodec/h264dec: make h264_export_frame_props() accessible
> >   avcodec/qsvdec: Implement SEI parsing for QSV decoders
> >
> >  doc/APIchanges               |   4 +
> >  libavcodec/Makefile          |   6 +-
> >  libavcodec/h264_slice.c      |  98 ++++++++-------
> >  libavcodec/h264dec.h         |   2 +
> >  libavcodec/hevcdec.c         | 117 +++++++++---------
> >  libavcodec/hevcdec.h         |   9 ++
> >  libavcodec/hevcdsp.c         |   4 +
> >  libavcodec/mpeg12.h          |  28 +++++
> >  libavcodec/mpeg12dec.c       |  40 +-----
> >  libavcodec/qsvdec.c          | 234
> +++++++++++++++++++++++++++++++++++
> >  libavfilter/qsvvpp.c         |   6 +
> >  libavfilter/vf_overlay_qsv.c |  19 ++-
> >  libavutil/frame.c            |  67 ++++++----
> >  libavutil/frame.h            |  32 +++++
> >  libavutil/version.h          |   2 +-
> >  15 files changed, 494 insertions(+), 174 deletions(-)
> >
> >
> > base-commit: 6a82412bf33108111eb3f63076fd5a51349ae114
> > Published-As:
> > https://github.com/ffstaging/FFmpeg/releases/tag/pr-ffstaging-
> 31%2Fsoftworkz%2Fsubmit_qsv_sei-v5
> > Fetch-It-Via: git fetch https://github.com/ffstaging/FFmpeg pr-
> ffstaging-
> > 31/softworkz/submit_qsv_sei-v5
> > Pull-Request: https://github.com/ffstaging/FFmpeg/pull/31
> >
> > Range-diff vs v4:
> >
> >  1:  7656477360 = 1:  7656477360 avutil/frame: Add
> av_frame_copy_side_data()
> > and av_frame_remove_all_side_data()
> >  2:  06976606c5 = 2:  06976606c5 avcodec/vpp_qsv: Copy side data
> from input to
> > output frame
> >  3:  320a8a535c = 3:  320a8a535c avcodec/mpeg12dec: make
> > mpeg_decode_user_data() accessible
> >  4:  e58ad6564f = 4:  e58ad6564f avcodec/hevcdec: make
> set_side_data()
> > accessible
> >  5:  a57bfaebb9 = 5:  4c0b6eb4cb avcodec/h264dec: make
> > h264_export_frame_props() accessible
> >  6:  3f2588563e ! 6:  19bc00be4d avcodec/qsvdec: Implement SEI
> parsing for QSV
> > decoders
> >      @@ Commit message
> >
> >           Signed-off-by: softworkz <[email protected]>
> >
> >      + ## libavcodec/Makefile ##
> >      +@@ libavcodec/Makefile: OBJS-$(CONFIG_MSS34DSP)
> +=
> > mss34dsp.o
> >      + OBJS-$(CONFIG_PIXBLOCKDSP)             += pixblockdsp.o
> >      + OBJS-$(CONFIG_QPELDSP)                 += qpeldsp.o
> >      + OBJS-$(CONFIG_QSV)                     += qsv.o
> >      +-OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o
> >      ++OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o
> h264_slice.o
> > h264_cabac.o h264_cavlc.o \
> >      ++                                          h264_direct.o
> h264_mb.o
> > h264_picture.o h264_loopfilter.o \
> >      ++                                          h264dec.o
> h264_refs.o cabac.o
> > hevcdec.o hevc_refs.o \
> >      ++
> 
> >   hevc_filter.o hevc_cabac.o hevc_mvs.o hevcpred.o hevcdsp.o \
> >      ++
> 
> >   h274.o dovi_rpu.o mpeg12dec.o
> >      + OBJS-$(CONFIG_QSVENC)                  += qsvenc.o
> >      + OBJS-$(CONFIG_RANGECODER)              += rangecoder.o
> >      + OBJS-$(CONFIG_RDFT)                    += rdft.o
> >      +
> >      + ## libavcodec/hevcdsp.c ##
> >      +@@
> >      +  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
> Boston, MA 02110-
> > 1301 USA
> >      +  */
> >      +
> >      ++#include "config_components.h"
> >      ++
> >      + #include "hevcdsp.h"
> >      +
> >      + static const int8_t transform[32][32] = {
> >      +@@ libavcodec/hevcdsp.c: int i = 0;
> >      +         break;
> >      +     }
> >      +
> >      ++#if CONFIG_HEVC_DECODER
> >      + #if ARCH_AARCH64
> >      +     ff_hevc_dsp_init_aarch64(hevcdsp, bit_depth);
> >      + #elif ARCH_ARM
> >      +@@ libavcodec/hevcdsp.c: int i = 0;
> >      + #elif ARCH_LOONGARCH
> >      +     ff_hevc_dsp_init_loongarch(hevcdsp, bit_depth);
> >      + #endif
> >      ++#endif
> >      + }
> >      +
> >        ## libavcodec/qsvdec.c ##
> >       @@
> >        #include "hwconfig.h"
> 
> 
> Is there any comment on this patchset ? If not, I'd like to merge it
> to make QSV
> decoders works with SEI info.
> 
> Thanks
> Haihao


There's a conflicting (but reasonable and useful) patchset from Andreas:

https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=6959


Even though this is open for so long already, it think it makes more
sense to merge Andreas' first and adapt mine to be applied on top
of it.

@Andreas - any news on that patchset of yours?

Thanks,
softworkz


_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

@ffmpeg-codebot
Copy link

On the FFmpeg mailing list, Andreas Rheinhardt wrote (reply to this):

Xiang, Haihao:
> On Fri, 2022-07-01 at 20:48 +0000, ffmpegagent wrote:
>> Missing SEI information has always been a major drawback when using the QSV
>> decoders. I used to think that there's no chance to get at the data without
>> explicit implementation from the MSDK side (or doing something weird like
>> parsing in parallel). It turned out that there's a hardly known api method
>> that provides access to all SEI (h264/hevc) or user data (mpeg2video).
>>
>> This allows to get things like closed captions, frame packing, display
>> orientation, HDR data (mastering display, content light level, etc.) without
>> having to rely on those data being provided by the MSDK as extended buffers.
>>
>> The commit "Implement SEI parsing for QSV decoders" includes some hard-coded
>> workarounds for MSDK bugs which I reported:
>>
> https://github.com/Intel-Media-SDK/MediaSDK/issues/2597#issuecomment-1072795311
>>
>> But that doesn't help. Those bugs exist and I'm sharing my workarounds,
>> which are empirically determined by testing a range of files. If someone is
>> interested, I can provide private access to a repository where we have been
>> testing this. Alternatively, I could also leave those workarounds out, and
>> just skip those SEI types.
>>
>> In a previous version of this patchset, there was a concern that payload
>> data might need to be re-ordered. Meanwhile I have researched this carefully
>> and the conclusion is that this is not required.
>>
>> My detailed analysis can be found here:
>> https://gist.github.com/softworkz/36c49586a8610813a32270ee3947a932
>>
>> v4
>>
>>  * add new dependencies in makefile Now, build still works when someone uses
>>    configure --disable-decoder=h264 --disable-decoder=hevc
>>    --disable-decoder=mpegvideo --disable-decoder=mpeg1video
>>    --disable-decoder=mpeg2video --enable-libmfx
>>
>> v3
>>
>>  * frame.h: clarify doc text for av_frame_copy_side_data()
>>
>> v2
>>
>>  * qsvdec: make error handling consistent and clear
>>  * qsvdec: remove AV_CODEC_ID_MPEG1VIDEO constants
>>  * hevcdec: rename function to ff_hevc_set_side_data(), add doc text
>>
>> v3
>>
>>  * qsvdec: fix c/p error
>>
>> softworkz (6):
>>   avutil/frame: Add av_frame_copy_side_data() and
>>     av_frame_remove_all_side_data()
>>   avcodec/vpp_qsv: Copy side data from input to output frame
>>   avcodec/mpeg12dec: make mpeg_decode_user_data() accessible
>>   avcodec/hevcdec: make set_side_data() accessible
>>   avcodec/h264dec: make h264_export_frame_props() accessible
>>   avcodec/qsvdec: Implement SEI parsing for QSV decoders
>>
>>  doc/APIchanges               |   4 +
>>  libavcodec/Makefile          |   6 +-
>>  libavcodec/h264_slice.c      |  98 ++++++++-------
>>  libavcodec/h264dec.h         |   2 +
>>  libavcodec/hevcdec.c         | 117 +++++++++---------
>>  libavcodec/hevcdec.h         |   9 ++
>>  libavcodec/hevcdsp.c         |   4 +
>>  libavcodec/mpeg12.h          |  28 +++++
>>  libavcodec/mpeg12dec.c       |  40 +-----
>>  libavcodec/qsvdec.c          | 234 +++++++++++++++++++++++++++++++++++
>>  libavfilter/qsvvpp.c         |   6 +
>>  libavfilter/vf_overlay_qsv.c |  19 ++-
>>  libavutil/frame.c            |  67 ++++++----
>>  libavutil/frame.h            |  32 +++++
>>  libavutil/version.h          |   2 +-
>>  15 files changed, 494 insertions(+), 174 deletions(-)
>>
>>
>> base-commit: 6a82412bf33108111eb3f63076fd5a51349ae114
>> Published-As: 
>> https://github.com/ffstaging/FFmpeg/releases/tag/pr-ffstaging-31%2Fsoftworkz%2Fsubmit_qsv_sei-v5
>> Fetch-It-Via: git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-
>> 31/softworkz/submit_qsv_sei-v5
>> Pull-Request: https://github.com/ffstaging/FFmpeg/pull/31
>>
>> Range-diff vs v4:
>>
>>  1:  7656477360 = 1:  7656477360 avutil/frame: Add av_frame_copy_side_data()
>> and av_frame_remove_all_side_data()
>>  2:  06976606c5 = 2:  06976606c5 avcodec/vpp_qsv: Copy side data from input to
>> output frame
>>  3:  320a8a535c = 3:  320a8a535c avcodec/mpeg12dec: make
>> mpeg_decode_user_data() accessible
>>  4:  e58ad6564f = 4:  e58ad6564f avcodec/hevcdec: make set_side_data()
>> accessible
>>  5:  a57bfaebb9 = 5:  4c0b6eb4cb avcodec/h264dec: make
>> h264_export_frame_props() accessible
>>  6:  3f2588563e ! 6:  19bc00be4d avcodec/qsvdec: Implement SEI parsing for QSV
>> decoders
>>      @@ Commit message
>>       
>>           Signed-off-by: softworkz <[email protected]>
>>       
>>      + ## libavcodec/Makefile ##
>>      +@@ libavcodec/Makefile: OBJS-$(CONFIG_MSS34DSP)                +=
>> mss34dsp.o
>>      + OBJS-$(CONFIG_PIXBLOCKDSP)             += pixblockdsp.o
>>      + OBJS-$(CONFIG_QPELDSP)                 += qpeldsp.o
>>      + OBJS-$(CONFIG_QSV)                     += qsv.o
>>      +-OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o
>>      ++OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o h264_slice.o
>> h264_cabac.o h264_cavlc.o \
>>      ++                                          h264_direct.o h264_mb.o
>> h264_picture.o h264_loopfilter.o \
>>      ++                                          h264dec.o h264_refs.o cabac.o
>> hevcdec.o hevc_refs.o \
>>      ++										
>>   hevc_filter.o hevc_cabac.o hevc_mvs.o hevcpred.o hevcdsp.o \
>>      ++										
>>   h274.o dovi_rpu.o mpeg12dec.o
>>      + OBJS-$(CONFIG_QSVENC)                  += qsvenc.o
>>      + OBJS-$(CONFIG_RANGECODER)              += rangecoder.o
>>      + OBJS-$(CONFIG_RDFT)                    += rdft.o
>>      +
>>      + ## libavcodec/hevcdsp.c ##
>>      +@@
>>      +  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-
>> 1301 USA
>>      +  */
>>      + 
>>      ++#include "config_components.h"
>>      ++
>>      + #include "hevcdsp.h"
>>      + 
>>      + static const int8_t transform[32][32] = {
>>      +@@ libavcodec/hevcdsp.c: int i = 0;
>>      +         break;
>>      +     }
>>      + 
>>      ++#if CONFIG_HEVC_DECODER
>>      + #if ARCH_AARCH64
>>      +     ff_hevc_dsp_init_aarch64(hevcdsp, bit_depth);
>>      + #elif ARCH_ARM
>>      +@@ libavcodec/hevcdsp.c: int i = 0;
>>      + #elif ARCH_LOONGARCH
>>      +     ff_hevc_dsp_init_loongarch(hevcdsp, bit_depth);
>>      + #endif
>>      ++#endif
>>      + }
>>      +
>>        ## libavcodec/qsvdec.c ##
>>       @@
>>        #include "hwconfig.h"
> 
> 
> Is there any comment on this patchset ? If not, I'd like to merge it to make QSV
> decoders works with SEI info.
> 
> Thanks
> Haihao
> 

This patchset has several issues, namely:
1. It tries to share the functions that are used for processing user/SEI
data as they are, even the parts that are not intended to be used by QSV
(like the picture structure stuff for H.264 or tmpgexs in case of MPEG-1/2).
2. It tries to keep the functions where they are, leading to the
insanely long Makefile line in patch 6/6 (which I believe to be still
incomplete: mpeg12dec.o pulls in mpegvideo.o mpegvideo_dec.o (which in
turn pull in lots of dsp stuff) and where is h264dsp.o? (it seems like
there is a reliance on the H.264 parser for this)). This is the opposite
of modularity.
3. It just puts a huge Mpeg1Context in the QSVContext, although only a
miniscule part of it is actually used. One should use a small context of
its own instead.
4. It does not take into account that buffers need to be padded to be
usable by the GetBit-API.

(I have made an attempt to factor out the common parts of H.264 and
H.265 SEI handling, which should make this here much easier.)

- Andreas
_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

@ffmpeg-codebot
Copy link

On the FFmpeg mailing list, Soft Works wrote (reply to this):



> -----Original Message-----
> From: ffmpeg-devel <[email protected]> On Behalf Of
> Andreas Rheinhardt
> Sent: Thursday, July 21, 2022 11:56 PM
> To: Xiang, Haihao <[email protected]>; [email protected]
> Subject: Re: [FFmpeg-devel] [PATCH v5 0/6] Implement SEI parsing for
> QSV decoders
> 
> Xiang, Haihao:
> > On Fri, 2022-07-01 at 20:48 +0000, ffmpegagent wrote:
> >> Missing SEI information has always been a major drawback when
> using the QSV
> >> decoders. I used to think that there's no chance to get at the
> data without
> >> explicit implementation from the MSDK side (or doing something
> weird like
> >> parsing in parallel). It turned out that there's a hardly known
> api method
> >> that provides access to all SEI (h264/hevc) or user data
> (mpeg2video).
> >>
> >> This allows to get things like closed captions, frame packing,
> display
> >> orientation, HDR data (mastering display, content light level,
> etc.) without
> >> having to rely on those data being provided by the MSDK as
> extended buffers.
> >>
> >> The commit "Implement SEI parsing for QSV decoders" includes some
> hard-coded
> >> workarounds for MSDK bugs which I reported:
> >>
> > https://github.com/Intel-Media-
> SDK/MediaSDK/issues/2597#issuecomment-1072795311
> >>
> >> But that doesn't help. Those bugs exist and I'm sharing my
> workarounds,
> >> which are empirically determined by testing a range of files. If
> someone is
> >> interested, I can provide private access to a repository where we
> have been
> >> testing this. Alternatively, I could also leave those workarounds
> out, and
> >> just skip those SEI types.
> >>
> >> In a previous version of this patchset, there was a concern that
> payload
> >> data might need to be re-ordered. Meanwhile I have researched this
> carefully
> >> and the conclusion is that this is not required.
> >>
> >> My detailed analysis can be found here:
> >> https://gist.github.com/softworkz/36c49586a8610813a32270ee3947a932
> >>
> >> v4
> >>
> >>  * add new dependencies in makefile Now, build still works when
> someone uses
> >>    configure --disable-decoder=h264 --disable-decoder=hevc
> >>    --disable-decoder=mpegvideo --disable-decoder=mpeg1video
> >>    --disable-decoder=mpeg2video --enable-libmfx
> >>
> >> v3
> >>
> >>  * frame.h: clarify doc text for av_frame_copy_side_data()
> >>
> >> v2
> >>
> >>  * qsvdec: make error handling consistent and clear
> >>  * qsvdec: remove AV_CODEC_ID_MPEG1VIDEO constants
> >>  * hevcdec: rename function to ff_hevc_set_side_data(), add doc
> text
> >>
> >> v3
> >>
> >>  * qsvdec: fix c/p error
> >>
> >> softworkz (6):
> >>   avutil/frame: Add av_frame_copy_side_data() and
> >>     av_frame_remove_all_side_data()
> >>   avcodec/vpp_qsv: Copy side data from input to output frame
> >>   avcodec/mpeg12dec: make mpeg_decode_user_data() accessible
> >>   avcodec/hevcdec: make set_side_data() accessible
> >>   avcodec/h264dec: make h264_export_frame_props() accessible
> >>   avcodec/qsvdec: Implement SEI parsing for QSV decoders
> >>
> >>  doc/APIchanges               |   4 +
> >>  libavcodec/Makefile          |   6 +-
> >>  libavcodec/h264_slice.c      |  98 ++++++++-------
> >>  libavcodec/h264dec.h         |   2 +
> >>  libavcodec/hevcdec.c         | 117 +++++++++---------
> >>  libavcodec/hevcdec.h         |   9 ++
> >>  libavcodec/hevcdsp.c         |   4 +
> >>  libavcodec/mpeg12.h          |  28 +++++
> >>  libavcodec/mpeg12dec.c       |  40 +-----
> >>  libavcodec/qsvdec.c          | 234
> +++++++++++++++++++++++++++++++++++
> >>  libavfilter/qsvvpp.c         |   6 +
> >>  libavfilter/vf_overlay_qsv.c |  19 ++-
> >>  libavutil/frame.c            |  67 ++++++----
> >>  libavutil/frame.h            |  32 +++++
> >>  libavutil/version.h          |   2 +-
> >>  15 files changed, 494 insertions(+), 174 deletions(-)
> >>
> >>
> >> base-commit: 6a82412bf33108111eb3f63076fd5a51349ae114
> >> Published-As:
> >> https://github.com/ffstaging/FFmpeg/releases/tag/pr-ffstaging-
> 31%2Fsoftworkz%2Fsubmit_qsv_sei-v5
> >> Fetch-It-Via: git fetch https://github.com/ffstaging/FFmpeg pr-
> ffstaging-
> >> 31/softworkz/submit_qsv_sei-v5
> >> Pull-Request: https://github.com/ffstaging/FFmpeg/pull/31
> >>
> >> Range-diff vs v4:
> >>
> >>  1:  7656477360 = 1:  7656477360 avutil/frame: Add
> av_frame_copy_side_data()
> >> and av_frame_remove_all_side_data()
> >>  2:  06976606c5 = 2:  06976606c5 avcodec/vpp_qsv: Copy side data
> from input to
> >> output frame
> >>  3:  320a8a535c = 3:  320a8a535c avcodec/mpeg12dec: make
> >> mpeg_decode_user_data() accessible
> >>  4:  e58ad6564f = 4:  e58ad6564f avcodec/hevcdec: make
> set_side_data()
> >> accessible
> >>  5:  a57bfaebb9 = 5:  4c0b6eb4cb avcodec/h264dec: make
> >> h264_export_frame_props() accessible
> >>  6:  3f2588563e ! 6:  19bc00be4d avcodec/qsvdec: Implement SEI
> parsing for QSV
> >> decoders
> >>      @@ Commit message
> >>
> >>           Signed-off-by: softworkz <[email protected]>
> >>
> >>      + ## libavcodec/Makefile ##
> >>      +@@ libavcodec/Makefile: OBJS-$(CONFIG_MSS34DSP)
> +=
> >> mss34dsp.o
> >>      + OBJS-$(CONFIG_PIXBLOCKDSP)             += pixblockdsp.o
> >>      + OBJS-$(CONFIG_QPELDSP)                 += qpeldsp.o
> >>      + OBJS-$(CONFIG_QSV)                     += qsv.o
> >>      +-OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o
> >>      ++OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o
> h264_slice.o
> >> h264_cabac.o h264_cavlc.o \
> >>      ++                                          h264_direct.o
> h264_mb.o
> >> h264_picture.o h264_loopfilter.o \
> >>      ++                                          h264dec.o
> h264_refs.o cabac.o
> >> hevcdec.o hevc_refs.o \
> >>      ++
> 
> >>   hevc_filter.o hevc_cabac.o hevc_mvs.o hevcpred.o hevcdsp.o \
> >>      ++
> 
> >>   h274.o dovi_rpu.o mpeg12dec.o
> >>      + OBJS-$(CONFIG_QSVENC)                  += qsvenc.o
> >>      + OBJS-$(CONFIG_RANGECODER)              += rangecoder.o
> >>      + OBJS-$(CONFIG_RDFT)                    += rdft.o
> >>      +
> >>      + ## libavcodec/hevcdsp.c ##
> >>      +@@
> >>      +  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
> Boston, MA 02110-
> >> 1301 USA
> >>      +  */
> >>      +
> >>      ++#include "config_components.h"
> >>      ++
> >>      + #include "hevcdsp.h"
> >>      +
> >>      + static const int8_t transform[32][32] = {
> >>      +@@ libavcodec/hevcdsp.c: int i = 0;
> >>      +         break;
> >>      +     }
> >>      +
> >>      ++#if CONFIG_HEVC_DECODER
> >>      + #if ARCH_AARCH64
> >>      +     ff_hevc_dsp_init_aarch64(hevcdsp, bit_depth);
> >>      + #elif ARCH_ARM
> >>      +@@ libavcodec/hevcdsp.c: int i = 0;
> >>      + #elif ARCH_LOONGARCH
> >>      +     ff_hevc_dsp_init_loongarch(hevcdsp, bit_depth);
> >>      + #endif
> >>      ++#endif
> >>      + }
> >>      +
> >>        ## libavcodec/qsvdec.c ##
> >>       @@
> >>        #include "hwconfig.h"
> >
> >
> > Is there any comment on this patchset ? If not, I'd like to merge
> it to make QSV
> > decoders works with SEI info.
> >
> > Thanks
> > Haihao
> >
> 
> This patchset has several issues, namely:
> 1. It tries to share the functions that are used for processing
> user/SEI
> data as they are, even the parts that are not intended to be used by
> QSV
> (like the picture structure stuff for H.264 or tmpgexs in case of
> MPEG-1/2).
> 2. It tries to keep the functions where they are, leading to the
> insanely long Makefile line in patch 6/6 (which I believe to be still
> incomplete: mpeg12dec.o pulls in mpegvideo.o mpegvideo_dec.o (which
> in
> turn pull in lots of dsp stuff) and where is h264dsp.o? (it seems
> like
> there is a reliance on the H.264 parser for this)). This is the
> opposite
> of modularity.
> 3. It just puts a huge Mpeg1Context in the QSVContext, although only
> a
> miniscule part of it is actually used. One should use a small context
> of
> its own instead.
> 4. It does not take into account that buffers need to be padded to be
> usable by the GetBit-API.


Hi Andreas,

thanks for pointing out (4), in fact I wasn't aware of this.

I agree to your other points (1-3). Not that I wouldn't have been 
aware of those implications, I've just been afraid that larger refactorings
could have minimized acceptance.


> (I have made an attempt to factor out the common parts of H.264 and
> H.265 SEI handling, which should make this here much easier.)

Your patchset would in fact be very helpful and allow me to provide 
a much better and focused revision.
Though, it is still pending at this time - are you planning to push it?


Thanks,
softworkz

_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

@softworkz
Copy link
Collaborator Author

/submit

@ffmpeg-codebot
Copy link

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-31/softworkz/submit_qsv_sei-v6

To fetch this version to local tag pr-ffstaging-31/softworkz/submit_qsv_sei-v6:

git fetch --no-tags https://github.com/ffstaging/FFmpeg tag pr-ffstaging-31/softworkz/submit_qsv_sei-v6

@@ -146,7 +146,7 @@ OBJS-$(CONFIG_MSS34DSP) += mss34dsp.o
OBJS-$(CONFIG_PIXBLOCKDSP) += pixblockdsp.o

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the FFmpeg mailing list, "Xiang, Haihao" wrote (reply to this):

On Tue, 2022-10-25 at 04:03 +0000, softworkz wrote:
> From: softworkz <[email protected]>
> 
> Signed-off-by: softworkz <[email protected]>
> ---
>  libavcodec/Makefile |   2 +-
>  libavcodec/qsvdec.c | 321 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 322 insertions(+), 1 deletion(-)
> 
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 90c7f113a3..cbddbb0ace 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -146,7 +146,7 @@ OBJS-$(CONFIG_MSS34DSP)                += mss34dsp.o
>  OBJS-$(CONFIG_PIXBLOCKDSP)             += pixblockdsp.o
>  OBJS-$(CONFIG_QPELDSP)                 += qpeldsp.o
>  OBJS-$(CONFIG_QSV)                     += qsv.o
> -OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o
> +OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o h264_sei.o hevc_sei.o
>  OBJS-$(CONFIG_QSVENC)                  += qsvenc.o
>  OBJS-$(CONFIG_RANGECODER)              += rangecoder.o
>  OBJS-$(CONFIG_RDFT)                    += rdft.o
> diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
> index 73405b5747..467a248224 100644
> --- a/libavcodec/qsvdec.c
> +++ b/libavcodec/qsvdec.c
> @@ -41,6 +41,7 @@
>  #include "libavutil/time.h"
>  #include "libavutil/imgutils.h"
>  #include "libavutil/film_grain_params.h"
> +#include <libavutil/reverse.h>
>  
>  #include "avcodec.h"
>  #include "codec_internal.h"
> @@ -49,6 +50,9 @@
>  #include "hwconfig.h"
>  #include "qsv.h"
>  #include "qsv_internal.h"
> +#include "h264_sei.h"
> +#include "hevc_ps.h"
> +#include "hevc_sei.h"
>  
>  #if QSV_ONEVPL
>  #include <mfxdispatcher.h>
> @@ -66,6 +70,8 @@ static const AVRational mfx_tb = { 1, 90000 };
>      AV_NOPTS_VALUE : pts_tb.num ? \
>      av_rescale_q(mfx_pts, mfx_tb, pts_tb) : mfx_pts)
>  
> +#define PAYLOAD_BUFFER_SIZE 65535
> +
>  typedef struct QSVAsyncFrame {
>      mfxSyncPoint *sync;
>      QSVFrame     *frame;
> @@ -107,6 +113,9 @@ typedef struct QSVContext {
>  
>      mfxExtBuffer **ext_buffers;
>      int         nb_ext_buffers;
> +
> +    mfxU8 payload_buffer[PAYLOAD_BUFFER_SIZE];
> +    AVBufferRef *a53_buf_ref;
>  } QSVContext;
>  
>  static const AVCodecHWConfigInternal *const qsv_hw_configs[] = {
> @@ -628,6 +637,299 @@ static int qsv_export_film_grain(AVCodecContext *avctx,
> mfxExtAV1FilmGrainParam
>  }
>  #endif
>  
> +static int find_start_offset(mfxU8 data[4])
> +{
> +    if (data[0] == 0 && data[1] == 0 && data[2] == 1)
> +        return 3;
> +
> +    if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 1)
> +        return 4;
> +
> +    return 0;
> +}
> +
> +static int parse_sei_h264(AVCodecContext* avctx, QSVContext* q, AVFrame* out)
> +{
> +    H264SEIContext sei = { 0 };
> +    GetBitContext gb = { 0 };
> +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize =
> sizeof(q->payload_buffer) - AV_INPUT_BUFFER_PADDING_SIZE };
> +    mfxU64 ts;
> +    int ret;
> +
> +    while (1) {
> +        int start;
> +        memset(payload.Data, 0, payload.BufSize);
> +
> +        ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
> +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient buffer on
> GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q->payload_buffer),
> payload.BufSize);
> +            return 0;
> +        }
> +        if (ret != MFX_ERR_NONE)
> +            return ret;
> +
> +        if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8)
> +            break;
> +
> +        start = find_start_offset(payload.Data);
> +
> +        switch (payload.Type) {
> +            case SEI_TYPE_BUFFERING_PERIOD:
> +            case SEI_TYPE_PIC_TIMING:
> +                continue;
> +        }
> +
> +        if (init_get_bits(&gb, &payload.Data[start], payload.NumBit - start *
> 8) < 0)
> +            av_log(avctx, AV_LOG_ERROR, "Error initializing bitstream reader
> SEI type: %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> +        else {
> +            ret = ff_h264_sei_decode(&sei, &gb, NULL, avctx);
> +
> +            if (ret < 0)
> +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI type:
> %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> +            else
> +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d  Numbits
> %d\n", payload.Type, payload.NumBit);
> +        }
> +    }
> +
> +    if (out)
> +        return ff_h264_set_sei_to_frame(avctx, &sei, out, NULL, 0);
> +
> +    return 0;
> +}
> +
> +static int parse_sei_hevc(AVCodecContext* avctx, QSVContext* q, QSVFrame*
> out)
> +{
> +    HEVCSEI sei = { 0 };
> +    HEVCParamSets ps = { 0 };
> +    GetBitContext gb = { 0 };
> +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize =
> sizeof(q->payload_buffer) - AV_INPUT_BUFFER_PADDING_SIZE };
> +    mfxFrameSurface1 *surface = &out->surface;
> +    mfxU64 ts;
> +    int ret, has_logged = 0;
> +
> +    while (1) {
> +        int start;
> +        memset(payload.Data, 0, payload.BufSize);
> +
> +        ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
> +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient buffer on
> GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q->payload_buffer),
> payload.BufSize);
> +            return 0;
> +        }
> +        if (ret != MFX_ERR_NONE)
> +            return ret;
> +
> +        if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8)
> +            break;
> +
> +        if (!has_logged) {
> +            has_logged = 1;
> +            av_log(avctx, AV_LOG_VERBOSE, "--------------------------------
> ---------\n");
> +            av_log(avctx, AV_LOG_VERBOSE, "Start reading SEI - payload
> timestamp: %llu - surface timestamp: %llu\n", ts, surface->Data.TimeStamp);
> +        }
> +
> +        if (ts != surface->Data.TimeStamp) {
> +            av_log(avctx, AV_LOG_WARNING, "GetPayload timestamp (%llu) does
> not match surface timestamp: (%llu)\n", ts, surface->Data.TimeStamp);
> +        }
> +
> +        start = find_start_offset(payload.Data);
> +
> +        av_log(avctx, AV_LOG_VERBOSE, "parsing SEI type: %3d  Numbits
> %3d  Start: %d\n", payload.Type, payload.NumBit, start);
> +
> +        switch (payload.Type) {
> +            case SEI_TYPE_BUFFERING_PERIOD:
> +            case SEI_TYPE_PIC_TIMING:
> +                continue;
> +            case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
> +                // There seems to be a bug in MSDK
> +                payload.NumBit -= 8;
> +
> +                break;
> +            case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO:
> +                // There seems to be a bug in MSDK
> +                payload.NumBit = 48;
> +
> +                break;
> +            case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
> +                // There seems to be a bug in MSDK
> +                if (payload.NumBit == 552)
> +                    payload.NumBit = 528;
> +                break;
> +        }
> +
> +        if (init_get_bits(&gb, &payload.Data[start], payload.NumBit - start *
> 8) < 0)
> +            av_log(avctx, AV_LOG_ERROR, "Error initializing bitstream reader
> SEI type: %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> +        else {
> +            ret = ff_hevc_decode_nal_sei(&gb, avctx, &sei, &ps,
> HEVC_NAL_SEI_PREFIX);
> +
> +            if (ret < 0)
> +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI type:
> %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> +            else
> +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d  Numbits
> %d\n", payload.Type, payload.NumBit);
> +        }
> +    }
> +
> +    if (has_logged) {
> +        av_log(avctx, AV_LOG_VERBOSE, "End reading SEI\n");
> +    }
> +
> +    if (out && out->frame)
> +        return ff_hevc_set_sei_to_frame(avctx, &sei, out->frame, avctx-
> >framerate, 0, &ps.sps->vui, ps.sps->bit_depth, ps.sps->bit_depth_chroma);

I got segfault when trying your patchset, 

Thread 1 "ffmpeg" received signal SIGSEGV, Segmentation fault.
0x00007ffff67c0497 in parse_sei_hevc (avctx=avctx@entry=0x5555555e4280, q=q@entry=0x555555625288, out=out@entry=0x5555559b6f80) at libavcodec/qsvdec.c:777
777             return ff_hevc_set_sei_to_frame(avctx, &sei, out->frame, avctx->framerate, 0, &ps.sps->vui, ps.sps->bit_depth, ps.sps->bit_depth_chroma);
(gdb) bt
#0  0x00007ffff67c0497 in parse_sei_hevc (avctx=avctx@entry=0x5555555e4280, q=q@entry=0x555555625288, out=out@entry=0x5555559b6f80) at libavcodec/qsvdec.c:777
#1  0x00007ffff67c1afe in qsv_decode (avctx=avctx@entry=0x5555555e4280, q=q@entry=0x555555625288, frame=frame@entry=0x5555556df740, got_frame=got_frame@entry=0x7fffffffd6bc,
    avpkt=avpkt@entry=0x555555635398) at libavcodec/qsvdec.c:1020

BTW the SDK provides support for hevc HDR metadata, we needn't parse SEI payload
in qsvdec and may get the corresponding info from the SDK, see 
https://ffmpeg.org/pipermail/ffmpeg-devel/2022-November/304142.html 

Thanks
Haihao


> +
> +    return 0;
> +}
> +
> +#define A53_MAX_CC_COUNT 2000
> +
> +static int mpeg_decode_a53_cc(AVCodecContext *avctx, QSVContext *s,
> +                              const uint8_t *p, int buf_size)
> +{
> +    if (buf_size >= 6 &&
> +        p[0] == 'G' && p[1] == 'A' && p[2] == '9' && p[3] == '4' &&
> +        p[4] == 3 && (p[5] & 0x40)) {
> +        /* extract A53 Part 4 CC data */
> +        unsigned cc_count = p[5] & 0x1f;
> +        if (cc_count > 0 && buf_size >= 7 + cc_count * 3) {
> +            const uint64_t old_size = s->a53_buf_ref ? s->a53_buf_ref->size :
> 0;
> +            const uint64_t new_size = (old_size + cc_count
> +                                            * UINT64_C(3));
> +            int ret;
> +
> +            if (new_size > 3*A53_MAX_CC_COUNT)
> +                return AVERROR(EINVAL);
> +
> +            ret = av_buffer_realloc(&s->a53_buf_ref, new_size);
> +            if (ret >= 0)
> +                memcpy(s->a53_buf_ref->data + old_size, p + 7, cc_count *
> UINT64_C(3));
> +
> +            avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
> +        }
> +        return 1;
> +    } else if (buf_size >= 2 && p[0] == 0x03 && (p[1]&0x7f) == 0x01) {
> +        /* extract SCTE-20 CC data */
> +        GetBitContext gb;
> +        unsigned cc_count = 0;
> +        int ret;
> +
> +        init_get_bits8(&gb, p + 2, buf_size - 2);
> +        cc_count = get_bits(&gb, 5);
> +        if (cc_count > 0) {
> +            uint64_t old_size = s->a53_buf_ref ? s->a53_buf_ref->size : 0;
> +            uint64_t new_size = (old_size + cc_count * UINT64_C(3));
> +            if (new_size > 3 * A53_MAX_CC_COUNT)
> +                return AVERROR(EINVAL);
> +
> +            ret = av_buffer_realloc(&s->a53_buf_ref, new_size);
> +            if (ret >= 0) {
> +                uint8_t field, cc1, cc2;
> +                uint8_t *cap = s->a53_buf_ref->data;
> +
> +                memset(s->a53_buf_ref->data + old_size, 0, cc_count * 3);
> +                for (unsigned i = 0; i < cc_count && get_bits_left(&gb) >=
> 26; i++) {
> +                    skip_bits(&gb, 2); // priority
> +                    field = get_bits(&gb, 2);
> +                    skip_bits(&gb, 5); // line_offset
> +                    cc1 = get_bits(&gb, 8);
> +                    cc2 = get_bits(&gb, 8);
> +                    skip_bits(&gb, 1); // marker
> +
> +                    if (!field) { // forbidden
> +                        cap[0] = cap[1] = cap[2] = 0x00;
> +                    } else {
> +                        field = (field == 2 ? 1 : 0);
> +                        ////if (!s1->mpeg_enc_ctx.top_field_first) field =
> !field;
> +                        cap[0] = 0x04 | field;
> +                        cap[1] = ff_reverse[cc1];
> +                        cap[2] = ff_reverse[cc2];
> +                    }
> +                    cap += 3;
> +                }
> +            }
> +            avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
> +        }
> +        return 1;
> +    } else if (buf_size >= 11 && p[0] == 'C' && p[1] == 'C' && p[2] == 0x01
> && p[3] == 0xf8) {
> +        int cc_count = 0;
> +        int i, ret;
> +        // There is a caption count field in the data, but it is often
> +        // incorrect.  So count the number of captions present.
> +        for (i = 5; i + 6 <= buf_size && ((p[i] & 0xfe) == 0xfe); i += 6)
> +            cc_count++;
> +        // Transform the DVD format into A53 Part 4 format
> +        if (cc_count > 0) {
> +            int old_size = s->a53_buf_ref ? s->a53_buf_ref->size : 0;
> +            uint64_t new_size = (old_size + cc_count
> +                                            * UINT64_C(6));
> +            if (new_size > 3*A53_MAX_CC_COUNT)
> +                return AVERROR(EINVAL);
> +
> +            ret = av_buffer_realloc(&s->a53_buf_ref, new_size);
> +            if (ret >= 0) {
> +                uint8_t field1 = !!(p[4] & 0x80);
> +                uint8_t *cap = s->a53_buf_ref->data;
> +                p += 5;
> +                for (i = 0; i < cc_count; i++) {
> +                    cap[0] = (p[0] == 0xff && field1) ? 0xfc : 0xfd;
> +                    cap[1] = p[1];
> +                    cap[2] = p[2];
> +                    cap[3] = (p[3] == 0xff && !field1) ? 0xfc : 0xfd;
> +                    cap[4] = p[4];
> +                    cap[5] = p[5];
> +                    cap += 6;
> +                    p += 6;
> +                }
> +            }
> +            avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
> +        }
> +        return 1;
> +    }
> +    return 0;
> +}
> +
> +static int parse_sei_mpeg12(AVCodecContext* avctx, QSVContext* q, AVFrame*
> out)
> +{
> +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize =
> sizeof(q->payload_buffer) - AV_INPUT_BUFFER_PADDING_SIZE };
> +    mfxU64 ts;
> +    int ret;
> +
> +    while (1) {
> +        int start;
> +
> +        memset(payload.Data, 0, payload.BufSize);
> +        ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
> +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient buffer on
> GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q->payload_buffer),
> payload.BufSize);
> +            return 0;
> +        }
> +        if (ret != MFX_ERR_NONE)
> +            return ret;
> +
> +        if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8)
> +            break;
> +
> +        start = find_start_offset(payload.Data);
> +
> +        start++;
> +
> +        mpeg_decode_a53_cc(avctx, q, &payload.Data[start],
> (int)((payload.NumBit + 7) / 8) - start);
> +
> +        av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d  Numbits %d start %d
> -> %.s\n", payload.Type, payload.NumBit, start, (char
> *)(&payload.Data[start]));
> +    }
> +
> +    if (!out)
> +        return 0;
> +
> +    if (q->a53_buf_ref) {
> +
> +        AVFrameSideData *sd = av_frame_new_side_data_from_buf(out,
> AV_FRAME_DATA_A53_CC, q->a53_buf_ref);
> +        if (!sd)
> +            av_buffer_unref(&q->a53_buf_ref);
> +        q->a53_buf_ref = NULL;
> +    }
> +
> +    return 0;
> +}
> +
>  static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
>                        AVFrame *frame, int *got_frame,
>                        const AVPacket *avpkt)
> @@ -664,6 +966,8 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext
> *q,
>                                                insurf, &outsurf, sync);
>          if (ret == MFX_WRN_DEVICE_BUSY)
>              av_usleep(500);
> +        else if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
> +            parse_sei_mpeg12(avctx, q, NULL);
>  
>      } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE);
>  
> @@ -705,6 +1009,23 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext
> *q,
>              return AVERROR_BUG;
>          }
>  
> +        switch (avctx->codec_id) {
> +        case AV_CODEC_ID_MPEG2VIDEO:
> +            ret = parse_sei_mpeg12(avctx, q, out_frame->frame);
> +            break;
> +        case AV_CODEC_ID_H264:
> +            ret = parse_sei_h264(avctx, q, out_frame->frame);
> +            break;
> +        case AV_CODEC_ID_HEVC:
> +            ret = parse_sei_hevc(avctx, q, out_frame);
> +            break;
> +        default:
> +            ret = 0;
> +        }
> +
> +        if (ret < 0)
> +            av_log(avctx, AV_LOG_ERROR, "Error parsing SEI data: %d\n", ret);
> +
>          out_frame->queued += 1;
>  
>          aframe = (QSVAsyncFrame){ sync, out_frame };
_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the FFmpeg mailing list, Soft Works wrote (reply to this):



> -----Original Message-----
> From: Xiang, Haihao <[email protected]>
> Sent: Monday, November 21, 2022 3:45 AM
> To: [email protected]
> Cc: [email protected]; [email protected]; haihao.xiang-at-
> [email protected]; [email protected]
> Subject: Re: [FFmpeg-devel] [PATCH v6 3/3] avcodec/qsvdec: Implement
> SEI parsing for QSV decoders
> 
> On Tue, 2022-10-25 at 04:03 +0000, softworkz wrote:
> > From: softworkz <[email protected]>
> >
> > Signed-off-by: softworkz <[email protected]>
> > ---
> >  libavcodec/Makefile |   2 +-
> >  libavcodec/qsvdec.c | 321
> ++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 322 insertions(+), 1 deletion(-)
> >
> > diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> > index 90c7f113a3..cbddbb0ace 100644
> > --- a/libavcodec/Makefile
> > +++ b/libavcodec/Makefile
> > @@ -146,7 +146,7 @@ OBJS-$(CONFIG_MSS34DSP)                +=
> mss34dsp.o
> >  OBJS-$(CONFIG_PIXBLOCKDSP)             += pixblockdsp.o
> >  OBJS-$(CONFIG_QPELDSP)                 += qpeldsp.o
> >  OBJS-$(CONFIG_QSV)                     += qsv.o
> > -OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o
> > +OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o h264_sei.o
> hevc_sei.o
> >  OBJS-$(CONFIG_QSVENC)                  += qsvenc.o
> >  OBJS-$(CONFIG_RANGECODER)              += rangecoder.o
> >  OBJS-$(CONFIG_RDFT)                    += rdft.o
> > diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
> > index 73405b5747..467a248224 100644
> > --- a/libavcodec/qsvdec.c
> > +++ b/libavcodec/qsvdec.c
> > @@ -41,6 +41,7 @@
> >  #include "libavutil/time.h"
> >  #include "libavutil/imgutils.h"
> >  #include "libavutil/film_grain_params.h"
> > +#include <libavutil/reverse.h>
> >
> >  #include "avcodec.h"
> >  #include "codec_internal.h"
> > @@ -49,6 +50,9 @@
> >  #include "hwconfig.h"
> >  #include "qsv.h"
> >  #include "qsv_internal.h"
> > +#include "h264_sei.h"
> > +#include "hevc_ps.h"
> > +#include "hevc_sei.h"
> >
> >  #if QSV_ONEVPL
> >  #include <mfxdispatcher.h>
> > @@ -66,6 +70,8 @@ static const AVRational mfx_tb = { 1, 90000 };
> >      AV_NOPTS_VALUE : pts_tb.num ? \
> >      av_rescale_q(mfx_pts, mfx_tb, pts_tb) : mfx_pts)
> >
> > +#define PAYLOAD_BUFFER_SIZE 65535
> > +
> >  typedef struct QSVAsyncFrame {
> >      mfxSyncPoint *sync;
> >      QSVFrame     *frame;
> > @@ -107,6 +113,9 @@ typedef struct QSVContext {
> >
> >      mfxExtBuffer **ext_buffers;
> >      int         nb_ext_buffers;
> > +
> > +    mfxU8 payload_buffer[PAYLOAD_BUFFER_SIZE];
> > +    AVBufferRef *a53_buf_ref;
> >  } QSVContext;
> >
> >  static const AVCodecHWConfigInternal *const qsv_hw_configs[] = {
> > @@ -628,6 +637,299 @@ static int
> qsv_export_film_grain(AVCodecContext *avctx,
> > mfxExtAV1FilmGrainParam
> >  }
> >  #endif
> >
> > +static int find_start_offset(mfxU8 data[4])
> > +{
> > +    if (data[0] == 0 && data[1] == 0 && data[2] == 1)
> > +        return 3;
> > +
> > +    if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] ==
> 1)
> > +        return 4;
> > +
> > +    return 0;
> > +}
> > +
> > +static int parse_sei_h264(AVCodecContext* avctx, QSVContext* q,
> AVFrame* out)
> > +{
> > +    H264SEIContext sei = { 0 };
> > +    GetBitContext gb = { 0 };
> > +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0],
> .BufSize =
> > sizeof(q->payload_buffer) - AV_INPUT_BUFFER_PADDING_SIZE };
> > +    mfxU64 ts;
> > +    int ret;
> > +
> > +    while (1) {
> > +        int start;
> > +        memset(payload.Data, 0, payload.BufSize);
> > +
> > +        ret = MFXVideoDECODE_GetPayload(q->session, &ts,
> &payload);
> > +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> > +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient
> buffer on
> > GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q-
> >payload_buffer),
> > payload.BufSize);
> > +            return 0;
> > +        }
> > +        if (ret != MFX_ERR_NONE)
> > +            return ret;
> > +
> > +        if (payload.NumBit == 0 || payload.NumBit >=
> payload.BufSize * 8)
> > +            break;
> > +
> > +        start = find_start_offset(payload.Data);
> > +
> > +        switch (payload.Type) {
> > +            case SEI_TYPE_BUFFERING_PERIOD:
> > +            case SEI_TYPE_PIC_TIMING:
> > +                continue;
> > +        }
> > +
> > +        if (init_get_bits(&gb, &payload.Data[start],
> payload.NumBit - start *
> > 8) < 0)
> > +            av_log(avctx, AV_LOG_ERROR, "Error initializing
> bitstream reader
> > SEI type: %d  Numbits %d error: %d\n", payload.Type,
> payload.NumBit, ret);
> > +        else {
> > +            ret = ff_h264_sei_decode(&sei, &gb, NULL, avctx);
> > +
> > +            if (ret < 0)
> > +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI
> type:
> > %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> > +            else
> > +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d
> Numbits
> > %d\n", payload.Type, payload.NumBit);
> > +        }
> > +    }
> > +
> > +    if (out)
> > +        return ff_h264_set_sei_to_frame(avctx, &sei, out, NULL,
> 0);
> > +
> > +    return 0;
> > +}
> > +
> > +static int parse_sei_hevc(AVCodecContext* avctx, QSVContext* q,
> QSVFrame*
> > out)
> > +{
> > +    HEVCSEI sei = { 0 };
> > +    HEVCParamSets ps = { 0 };
> > +    GetBitContext gb = { 0 };
> > +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0],
> .BufSize =
> > sizeof(q->payload_buffer) - AV_INPUT_BUFFER_PADDING_SIZE };
> > +    mfxFrameSurface1 *surface = &out->surface;
> > +    mfxU64 ts;
> > +    int ret, has_logged = 0;
> > +
> > +    while (1) {
> > +        int start;
> > +        memset(payload.Data, 0, payload.BufSize);
> > +
> > +        ret = MFXVideoDECODE_GetPayload(q->session, &ts,
> &payload);
> > +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> > +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient
> buffer on
> > GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q-
> >payload_buffer),
> > payload.BufSize);
> > +            return 0;
> > +        }
> > +        if (ret != MFX_ERR_NONE)
> > +            return ret;
> > +
> > +        if (payload.NumBit == 0 || payload.NumBit >=
> payload.BufSize * 8)
> > +            break;
> > +
> > +        if (!has_logged) {
> > +            has_logged = 1;
> > +            av_log(avctx, AV_LOG_VERBOSE, "-----------------------
> ---------
> > ---------\n");
> > +            av_log(avctx, AV_LOG_VERBOSE, "Start reading SEI -
> payload
> > timestamp: %llu - surface timestamp: %llu\n", ts, surface-
> >Data.TimeStamp);
> > +        }
> > +
> > +        if (ts != surface->Data.TimeStamp) {
> > +            av_log(avctx, AV_LOG_WARNING, "GetPayload timestamp
> (%llu) does
> > not match surface timestamp: (%llu)\n", ts, surface-
> >Data.TimeStamp);
> > +        }
> > +
> > +        start = find_start_offset(payload.Data);
> > +
> > +        av_log(avctx, AV_LOG_VERBOSE, "parsing SEI type: %3d
> Numbits
> > %3d  Start: %d\n", payload.Type, payload.NumBit, start);
> > +
> > +        switch (payload.Type) {
> > +            case SEI_TYPE_BUFFERING_PERIOD:
> > +            case SEI_TYPE_PIC_TIMING:
> > +                continue;
> > +            case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
> > +                // There seems to be a bug in MSDK
> > +                payload.NumBit -= 8;
> > +
> > +                break;
> > +            case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO:
> > +                // There seems to be a bug in MSDK
> > +                payload.NumBit = 48;
> > +
> > +                break;
> > +            case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
> > +                // There seems to be a bug in MSDK
> > +                if (payload.NumBit == 552)
> > +                    payload.NumBit = 528;
> > +                break;
> > +        }
> > +
> > +        if (init_get_bits(&gb, &payload.Data[start],
> payload.NumBit - start *
> > 8) < 0)
> > +            av_log(avctx, AV_LOG_ERROR, "Error initializing
> bitstream reader
> > SEI type: %d  Numbits %d error: %d\n", payload.Type,
> payload.NumBit, ret);
> > +        else {
> > +            ret = ff_hevc_decode_nal_sei(&gb, avctx, &sei, &ps,
> > HEVC_NAL_SEI_PREFIX);
> > +
> > +            if (ret < 0)
> > +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI
> type:
> > %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> > +            else
> > +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d
> Numbits
> > %d\n", payload.Type, payload.NumBit);
> > +        }
> > +    }
> > +
> > +    if (has_logged) {
> > +        av_log(avctx, AV_LOG_VERBOSE, "End reading SEI\n");
> > +    }
> > +
> > +    if (out && out->frame)
> > +        return ff_hevc_set_sei_to_frame(avctx, &sei, out->frame,
> avctx-
> > >framerate, 0, &ps.sps->vui, ps.sps->bit_depth, ps.sps-
> >bit_depth_chroma);
> 
> I got segfault when trying your patchset,
> 
> Thread 1 "ffmpeg" received signal SIGSEGV, Segmentation fault.
> 0x00007ffff67c0497 in parse_sei_hevc
> (avctx=avctx@entry=0x5555555e4280, q=q@entry=0x555555625288,
> out=out@entry=0x5555559b6f80) at libavcodec/qsvdec.c:777
> 777             return ff_hevc_set_sei_to_frame(avctx, &sei, out-
> >frame, avctx->framerate, 0, &ps.sps->vui, ps.sps->bit_depth, ps.sps-
> >bit_depth_chroma);
> (gdb) bt
> #0  0x00007ffff67c0497 in parse_sei_hevc
> (avctx=avctx@entry=0x5555555e4280, q=q@entry=0x555555625288,
> out=out@entry=0x5555559b6f80) at libavcodec/qsvdec.c:777
> #1  0x00007ffff67c1afe in qsv_decode
> (avctx=avctx@entry=0x5555555e4280, q=q@entry=0x555555625288,
> frame=frame@entry=0x5555556df740,
> got_frame=got_frame@entry=0x7fffffffd6bc,
>     avpkt=avpkt@entry=0x555555635398) at libavcodec/qsvdec.c:1020


> BTW the SDK provides support for hevc HDR metadata, we needn't parse
> SEI payload
> in qsvdec and may get the corresponding info from the SDK, see
> https://ffmpeg.org/pipermail/ffmpeg-devel/2022-November/304142.html

I know. I was the one who had requested this to be added to MSDK :-)

But it's just one small part of SEI information, it's limited to
the latest MSDK versions and I'm not sure whether it's working
as reliably as this implementation. This would need to be tested.

You should still have access to the repo with the test files for 
demoing the offset problems (which my patchset is working around).

But it's also about dynamic HDR data, dovi data, etc. - which 
MSDK doesn't provide, so this single bit of SEI data doesn't 
help much.

Best regards,
softworkz



_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the FFmpeg mailing list, "Xiang, Haihao" wrote (reply to this):

On Mon, 2022-11-21 at 15:58 +0000, Soft Works wrote:
> > -----Original Message-----
> > From: Xiang, Haihao <[email protected]>
> > Sent: Monday, November 21, 2022 3:45 AM
> > To: [email protected]
> > Cc: [email protected]; [email protected]; haihao.xiang-at-
> > [email protected]; [email protected]
> > Subject: Re: [FFmpeg-devel] [PATCH v6 3/3] avcodec/qsvdec: Implement
> > SEI parsing for QSV decoders
> > 
> > On Tue, 2022-10-25 at 04:03 +0000, softworkz wrote:
> > > From: softworkz <[email protected]>
> > > 
> > > Signed-off-by: softworkz <[email protected]>
> > > ---
> > >  libavcodec/Makefile |   2 +-
> > >  libavcodec/qsvdec.c | 321
> > ++++++++++++++++++++++++++++++++++++++++++++
> > >  2 files changed, 322 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> > > index 90c7f113a3..cbddbb0ace 100644
> > > --- a/libavcodec/Makefile
> > > +++ b/libavcodec/Makefile
> > > @@ -146,7 +146,7 @@ OBJS-$(CONFIG_MSS34DSP)                +=
> > mss34dsp.o
> > >  OBJS-$(CONFIG_PIXBLOCKDSP)             += pixblockdsp.o
> > >  OBJS-$(CONFIG_QPELDSP)                 += qpeldsp.o
> > >  OBJS-$(CONFIG_QSV)                     += qsv.o
> > > -OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o
> > > +OBJS-$(CONFIG_QSVDEC)                  += qsvdec.o h264_sei.o
> > hevc_sei.o
> > >  OBJS-$(CONFIG_QSVENC)                  += qsvenc.o
> > >  OBJS-$(CONFIG_RANGECODER)              += rangecoder.o
> > >  OBJS-$(CONFIG_RDFT)                    += rdft.o
> > > diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
> > > index 73405b5747..467a248224 100644
> > > --- a/libavcodec/qsvdec.c
> > > +++ b/libavcodec/qsvdec.c
> > > @@ -41,6 +41,7 @@
> > >  #include "libavutil/time.h"
> > >  #include "libavutil/imgutils.h"
> > >  #include "libavutil/film_grain_params.h"
> > > +#include <libavutil/reverse.h>
> > > 
> > >  #include "avcodec.h"
> > >  #include "codec_internal.h"
> > > @@ -49,6 +50,9 @@
> > >  #include "hwconfig.h"
> > >  #include "qsv.h"
> > >  #include "qsv_internal.h"
> > > +#include "h264_sei.h"
> > > +#include "hevc_ps.h"
> > > +#include "hevc_sei.h"
> > > 
> > >  #if QSV_ONEVPL
> > >  #include <mfxdispatcher.h>
> > > @@ -66,6 +70,8 @@ static const AVRational mfx_tb = { 1, 90000 };
> > >      AV_NOPTS_VALUE : pts_tb.num ? \
> > >      av_rescale_q(mfx_pts, mfx_tb, pts_tb) : mfx_pts)
> > > 
> > > +#define PAYLOAD_BUFFER_SIZE 65535
> > > +
> > >  typedef struct QSVAsyncFrame {
> > >      mfxSyncPoint *sync;
> > >      QSVFrame     *frame;
> > > @@ -107,6 +113,9 @@ typedef struct QSVContext {
> > > 
> > >      mfxExtBuffer **ext_buffers;
> > >      int         nb_ext_buffers;
> > > +
> > > +    mfxU8 payload_buffer[PAYLOAD_BUFFER_SIZE];
> > > +    AVBufferRef *a53_buf_ref;
> > >  } QSVContext;
> > > 
> > >  static const AVCodecHWConfigInternal *const qsv_hw_configs[] = {
> > > @@ -628,6 +637,299 @@ static int
> > qsv_export_film_grain(AVCodecContext *avctx,
> > > mfxExtAV1FilmGrainParam
> > >  }
> > >  #endif
> > > 
> > > +static int find_start_offset(mfxU8 data[4])
> > > +{
> > > +    if (data[0] == 0 && data[1] == 0 && data[2] == 1)
> > > +        return 3;
> > > +
> > > +    if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] ==
> > 1)
> > > +        return 4;
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int parse_sei_h264(AVCodecContext* avctx, QSVContext* q,
> > AVFrame* out)
> > > +{
> > > +    H264SEIContext sei = { 0 };
> > > +    GetBitContext gb = { 0 };
> > > +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0],
> > .BufSize =
> > > sizeof(q->payload_buffer) - AV_INPUT_BUFFER_PADDING_SIZE };
> > > +    mfxU64 ts;
> > > +    int ret;
> > > +
> > > +    while (1) {
> > > +        int start;
> > > +        memset(payload.Data, 0, payload.BufSize);
> > > +
> > > +        ret = MFXVideoDECODE_GetPayload(q->session, &ts,
> > &payload);
> > > +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> > > +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient
> > buffer on
> > > GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q-
> > > payload_buffer),
> > > payload.BufSize);
> > > +            return 0;
> > > +        }
> > > +        if (ret != MFX_ERR_NONE)
> > > +            return ret;
> > > +
> > > +        if (payload.NumBit == 0 || payload.NumBit >=
> > payload.BufSize * 8)
> > > +            break;
> > > +
> > > +        start = find_start_offset(payload.Data);
> > > +
> > > +        switch (payload.Type) {
> > > +            case SEI_TYPE_BUFFERING_PERIOD:
> > > +            case SEI_TYPE_PIC_TIMING:
> > > +                continue;
> > > +        }
> > > +
> > > +        if (init_get_bits(&gb, &payload.Data[start],
> > payload.NumBit - start *
> > > 8) < 0)
> > > +            av_log(avctx, AV_LOG_ERROR, "Error initializing
> > bitstream reader
> > > SEI type: %d  Numbits %d error: %d\n", payload.Type,
> > payload.NumBit, ret);
> > > +        else {
> > > +            ret = ff_h264_sei_decode(&sei, &gb, NULL, avctx);
> > > +
> > > +            if (ret < 0)
> > > +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI
> > type:
> > > %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> > > +            else
> > > +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d
> > Numbits
> > > %d\n", payload.Type, payload.NumBit);
> > > +        }
> > > +    }
> > > +
> > > +    if (out)
> > > +        return ff_h264_set_sei_to_frame(avctx, &sei, out, NULL,
> > 0);
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int parse_sei_hevc(AVCodecContext* avctx, QSVContext* q,
> > QSVFrame*
> > > out)
> > > +{
> > > +    HEVCSEI sei = { 0 };
> > > +    HEVCParamSets ps = { 0 };
> > > +    GetBitContext gb = { 0 };
> > > +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0],
> > .BufSize =
> > > sizeof(q->payload_buffer) - AV_INPUT_BUFFER_PADDING_SIZE };
> > > +    mfxFrameSurface1 *surface = &out->surface;
> > > +    mfxU64 ts;
> > > +    int ret, has_logged = 0;
> > > +
> > > +    while (1) {
> > > +        int start;
> > > +        memset(payload.Data, 0, payload.BufSize);
> > > +
> > > +        ret = MFXVideoDECODE_GetPayload(q->session, &ts,
> > &payload);
> > > +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> > > +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient
> > buffer on
> > > GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q-
> > > payload_buffer),
> > > payload.BufSize);
> > > +            return 0;
> > > +        }
> > > +        if (ret != MFX_ERR_NONE)
> > > +            return ret;
> > > +
> > > +        if (payload.NumBit == 0 || payload.NumBit >=
> > payload.BufSize * 8)
> > > +            break;
> > > +
> > > +        if (!has_logged) {
> > > +            has_logged = 1;
> > > +            av_log(avctx, AV_LOG_VERBOSE, "-----------------------
> > ---------
> > > ---------\n");
> > > +            av_log(avctx, AV_LOG_VERBOSE, "Start reading SEI -
> > payload
> > > timestamp: %llu - surface timestamp: %llu\n", ts, surface-
> > > Data.TimeStamp);
> > > +        }
> > > +
> > > +        if (ts != surface->Data.TimeStamp) {
> > > +            av_log(avctx, AV_LOG_WARNING, "GetPayload timestamp
> > (%llu) does
> > > not match surface timestamp: (%llu)\n", ts, surface-
> > > Data.TimeStamp);
> > > +        }
> > > +
> > > +        start = find_start_offset(payload.Data);
> > > +
> > > +        av_log(avctx, AV_LOG_VERBOSE, "parsing SEI type: %3d
> > Numbits
> > > %3d  Start: %d\n", payload.Type, payload.NumBit, start);
> > > +
> > > +        switch (payload.Type) {
> > > +            case SEI_TYPE_BUFFERING_PERIOD:
> > > +            case SEI_TYPE_PIC_TIMING:
> > > +                continue;
> > > +            case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
> > > +                // There seems to be a bug in MSDK
> > > +                payload.NumBit -= 8;
> > > +
> > > +                break;
> > > +            case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO:
> > > +                // There seems to be a bug in MSDK
> > > +                payload.NumBit = 48;
> > > +
> > > +                break;
> > > +            case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
> > > +                // There seems to be a bug in MSDK
> > > +                if (payload.NumBit == 552)
> > > +                    payload.NumBit = 528;
> > > +                break;
> > > +        }
> > > +
> > > +        if (init_get_bits(&gb, &payload.Data[start],
> > payload.NumBit - start *
> > > 8) < 0)
> > > +            av_log(avctx, AV_LOG_ERROR, "Error initializing
> > bitstream reader
> > > SEI type: %d  Numbits %d error: %d\n", payload.Type,
> > payload.NumBit, ret);
> > > +        else {
> > > +            ret = ff_hevc_decode_nal_sei(&gb, avctx, &sei, &ps,
> > > HEVC_NAL_SEI_PREFIX);
> > > +
> > > +            if (ret < 0)
> > > +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI
> > type:
> > > %d  Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
> > > +            else
> > > +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d
> > Numbits
> > > %d\n", payload.Type, payload.NumBit);
> > > +        }
> > > +    }
> > > +
> > > +    if (has_logged) {
> > > +        av_log(avctx, AV_LOG_VERBOSE, "End reading SEI\n");
> > > +    }
> > > +
> > > +    if (out && out->frame)
> > > +        return ff_hevc_set_sei_to_frame(avctx, &sei, out->frame,
> > avctx-
> > > > framerate, 0, &ps.sps->vui, ps.sps->bit_depth, ps.sps-
> > > bit_depth_chroma);
> > 
> > I got segfault when trying your patchset,
> > 
> > Thread 1 "ffmpeg" received signal SIGSEGV, Segmentation fault.
> > 0x00007ffff67c0497 in parse_sei_hevc
> > (avctx=avctx@entry=0x5555555e4280, q=q@entry=0x555555625288,
> > out=out@entry=0x5555559b6f80) at libavcodec/qsvdec.c:777
> > 777             return ff_hevc_set_sei_to_frame(avctx, &sei, out-
> > > frame, avctx->framerate, 0, &ps.sps->vui, ps.sps->bit_depth, ps.sps-
> > > bit_depth_chroma);
> > (gdb) bt
> > #0  0x00007ffff67c0497 in parse_sei_hevc
> > (avctx=avctx@entry=0x5555555e4280, q=q@entry=0x555555625288,
> > out=out@entry=0x5555559b6f80) at libavcodec/qsvdec.c:777
> > #1  0x00007ffff67c1afe in qsv_decode
> > (avctx=avctx@entry=0x5555555e4280, q=q@entry=0x555555625288,
> > frame=frame@entry=0x5555556df740,
> > got_frame=got_frame@entry=0x7fffffffd6bc,
> >     avpkt=avpkt@entry=0x555555635398) at libavcodec/qsvdec.c:1020
> > BTW the SDK provides support for hevc HDR metadata, we needn't parse
> > SEI payload
> > in qsvdec and may get the corresponding info from the SDK, see
> > https://ffmpeg.org/pipermail/ffmpeg-devel/2022-November/304142.html
> 
> I know. I was the one who had requested this to be added to MSDK :-)
> 
> But it's just one small part of SEI information, it's limited to
> the latest MSDK versions and I'm not sure whether it's working
> as reliably as this implementation. This would need to be tested.
> 
> You should still have access to the repo with the test files for 
> demoing the offset problems (which my patchset is working around).


I worked out a patchset (https://github.com/intel-media-ci/ffmpeg/pull/518),
including https://ffmpeg.org/pipermail/ffmpeg-devel/2022-November/304142.html an
d others. I may use your command (with some changes) to convert all HDR clips in
your repo to SDR clips except one clip (w/wo my changes, there is a GPU hang
issue with this clip). 

We may only do a small update to support AV1 HDR in the future if applying 
https://ffmpeg.org/pipermail/ffmpeg-devel/2022-November/304142.html.

Note the command below doesn't work with all test files in your repo with your
patchset v6.

$ ffmpeg -hwaccel qsv -c:v hevc_qsv -i input.mp4 -f null -

Thanks
Haihao

> 
> But it's also about dynamic HDR data, dovi data, etc. - which 
> MSDK doesn't provide, so this single bit of SEI data doesn't 
> help much.
> 
> Best regards,
> softworkz
> 
> 
> 
_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant