Skip to content

Commit dcf08cd

Browse files
committed
avcodec/qsvdec: Implement SEI parsing for QSV decoders
Signed-off-by: softworkz <[email protected]>
1 parent fb5c3df commit dcf08cd

File tree

1 file changed

+233
-0
lines changed

1 file changed

+233
-0
lines changed

libavcodec/qsvdec.c

+233
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@
4949
#include "hwconfig.h"
5050
#include "qsv.h"
5151
#include "qsv_internal.h"
52+
#include "h264dec.h"
53+
#include "h264_sei.h"
54+
#include "hevcdec.h"
55+
#include "hevc_ps.h"
56+
#include "hevc_sei.h"
57+
#include "mpeg12.h"
5258

5359
static const AVRational mfx_tb = { 1, 90000 };
5460

@@ -60,6 +66,8 @@ static const AVRational mfx_tb = { 1, 90000 };
6066
AV_NOPTS_VALUE : pts_tb.num ? \
6167
av_rescale_q(mfx_pts, mfx_tb, pts_tb) : mfx_pts)
6268

69+
#define PAYLOAD_BUFFER_SIZE 65535
70+
6371
typedef struct QSVAsyncFrame {
6472
mfxSyncPoint *sync;
6573
QSVFrame *frame;
@@ -101,6 +109,9 @@ typedef struct QSVContext {
101109

102110
mfxExtBuffer **ext_buffers;
103111
int nb_ext_buffers;
112+
113+
mfxU8 payload_buffer[PAYLOAD_BUFFER_SIZE];
114+
Mpeg1Context mpeg_ctx;
104115
} QSVContext;
105116

106117
static const AVCodecHWConfigInternal *const qsv_hw_configs[] = {
@@ -599,6 +610,208 @@ static int qsv_export_film_grain(AVCodecContext *avctx, mfxExtAV1FilmGrainParam
599610
return 0;
600611
}
601612
#endif
613+
static int find_start_offset(mfxU8 data[4])
614+
{
615+
if (data[0] == 0 && data[1] == 0 && data[2] == 1)
616+
return 3;
617+
618+
if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 1)
619+
return 4;
620+
621+
return 0;
622+
}
623+
624+
static int parse_sei_h264(AVCodecContext* avctx, QSVContext* q, AVFrame* out)
625+
{
626+
H264SEIContext sei = { 0 };
627+
GetBitContext gb = { 0 };
628+
mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize = sizeof(q->payload_buffer) };
629+
mfxU64 ts;
630+
int ret;
631+
632+
while (1) {
633+
int start;
634+
memset(payload.Data, 0, payload.BufSize);
635+
636+
ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
637+
if (ret != MFX_ERR_NONE) {
638+
av_log(avctx, AV_LOG_WARNING, "error getting SEI payload: %d \n", ret);
639+
return ret;
640+
}
641+
642+
if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8) {
643+
break;
644+
}
645+
646+
start = find_start_offset(payload.Data);
647+
648+
switch (payload.Type) {
649+
case SEI_TYPE_BUFFERING_PERIOD:
650+
case SEI_TYPE_PIC_TIMING:
651+
continue;
652+
}
653+
654+
if (init_get_bits(&gb, &payload.Data[start], payload.NumBit - start * 8) < 0)
655+
av_log(avctx, AV_LOG_ERROR, "Error initializing bitstream reader");
656+
else
657+
ret = ff_h264_sei_decode(&sei, &gb, NULL, avctx);
658+
659+
if (ret < 0)
660+
av_log(avctx, AV_LOG_WARNING, "Error parsing SEI type: %d Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
661+
else
662+
av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d Numbits %d\n", payload.Type, payload.NumBit);
663+
}
664+
665+
if (out)
666+
return ff_h264_export_frame_props(avctx, &sei, NULL, out);
667+
668+
return 0;
669+
}
670+
671+
static int parse_sei_hevc(AVCodecContext* avctx, QSVContext* q, QSVFrame* out)
672+
{
673+
HEVCSEI sei = { 0 };
674+
HEVCParamSets ps = { 0 };
675+
GetBitContext gb = { 0 };
676+
mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize = sizeof(q->payload_buffer) };
677+
mfxFrameSurface1 *surface = &out->surface;
678+
mfxU64 ts;
679+
int ret, has_logged = 0;
680+
681+
while (1) {
682+
int start;
683+
memset(payload.Data, 0, payload.BufSize);
684+
685+
ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
686+
if (ret != MFX_ERR_NONE) {
687+
av_log(avctx, AV_LOG_WARNING, "error getting SEI payload: %d \n", ret);
688+
return 0;
689+
}
690+
691+
if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8) {
692+
break;
693+
}
694+
695+
if (!has_logged) {
696+
has_logged = 1;
697+
av_log(avctx, AV_LOG_VERBOSE, "-----------------------------------------\n");
698+
av_log(avctx, AV_LOG_VERBOSE, "Start reading SEI - payload timestamp: %llu - surface timestamp: %llu\n", ts, surface->Data.TimeStamp);
699+
}
700+
701+
if (ts != surface->Data.TimeStamp) {
702+
av_log(avctx, AV_LOG_WARNING, "GetPayload timestamp (%llu) does not match surface timestamp: (%llu)\n", ts, surface->Data.TimeStamp);
703+
}
704+
705+
start = find_start_offset(payload.Data);
706+
707+
av_log(avctx, AV_LOG_VERBOSE, "parsing SEI type: %3d Numbits %3d Start: %d\n", payload.Type, payload.NumBit, start);
708+
709+
switch (payload.Type) {
710+
case SEI_TYPE_BUFFERING_PERIOD:
711+
case SEI_TYPE_PIC_TIMING:
712+
continue;
713+
case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
714+
// There seems to be a bug in MSDK
715+
payload.NumBit -= 8;
716+
717+
break;
718+
case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO:
719+
// There seems to be a bug in MSDK
720+
payload.NumBit = 48;
721+
722+
break;
723+
case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
724+
// There seems to be a bug in MSDK
725+
if (payload.NumBit == 552)
726+
payload.NumBit = 528;
727+
break;
728+
}
729+
730+
if (init_get_bits(&gb, &payload.Data[start], payload.NumBit - start * 8) < 0)
731+
av_log(avctx, AV_LOG_ERROR, "Error initializing bitstream reader");
732+
else
733+
ret = ff_hevc_decode_nal_sei(&gb, avctx, &sei, &ps, HEVC_NAL_SEI_PREFIX);
734+
735+
if (ret < 0)
736+
av_log(avctx, AV_LOG_WARNING, "error parsing SEI type: %d Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
737+
else
738+
av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d Numbits %d\n", payload.Type, payload.NumBit);
739+
}
740+
741+
if (has_logged) {
742+
av_log(avctx, AV_LOG_VERBOSE, "End reading SEI\n");
743+
}
744+
745+
if (out && out->frame)
746+
return ff_set_side_data(avctx, &sei, NULL, out->frame);
747+
748+
return 0;
749+
}
750+
751+
static int parse_sei_mpeg12(AVCodecContext* avctx, QSVContext* q, AVFrame* out)
752+
{
753+
Mpeg1Context *mpeg_ctx = &q->mpeg_ctx;
754+
mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize = sizeof(q->payload_buffer) };
755+
mfxU64 ts;
756+
int ret;
757+
758+
while (1) {
759+
int start;
760+
761+
memset(payload.Data, 0, payload.BufSize);
762+
ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
763+
if (ret != MFX_ERR_NONE) {
764+
av_log(avctx, AV_LOG_WARNING, "error getting SEI payload: %d \n", ret);
765+
return ret;
766+
}
767+
768+
if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8) {
769+
break;
770+
}
771+
772+
start = find_start_offset(payload.Data);
773+
774+
start++;
775+
776+
ff_mpeg_decode_user_data(avctx, mpeg_ctx, &payload.Data[start], (int)((payload.NumBit + 7) / 8) - start);
777+
778+
if (ret < 0)
779+
av_log(avctx, AV_LOG_WARNING, "error parsing SEI type: %d Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
780+
else
781+
av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d Numbits %d start %d -> %.s\n", payload.Type, payload.NumBit, start, (char *)(&payload.Data[start]));
782+
}
783+
784+
if (!out)
785+
return 0;
786+
787+
if (mpeg_ctx->a53_buf_ref) {
788+
789+
AVFrameSideData *sd = av_frame_new_side_data_from_buf(out, AV_FRAME_DATA_A53_CC, mpeg_ctx->a53_buf_ref);
790+
if (!sd)
791+
av_buffer_unref(&mpeg_ctx->a53_buf_ref);
792+
mpeg_ctx->a53_buf_ref = NULL;
793+
}
794+
795+
if (mpeg_ctx->has_stereo3d) {
796+
AVStereo3D *stereo = av_stereo3d_create_side_data(out);
797+
if (!stereo)
798+
return AVERROR(ENOMEM);
799+
800+
*stereo = mpeg_ctx->stereo3d;
801+
mpeg_ctx->has_stereo3d = 0;
802+
}
803+
804+
if (mpeg_ctx->has_afd) {
805+
AVFrameSideData *sd = av_frame_new_side_data(out, AV_FRAME_DATA_AFD, 1);
806+
if (!sd)
807+
return AVERROR(ENOMEM);
808+
809+
*sd->data = mpeg_ctx->afd;
810+
mpeg_ctx->has_afd = 0;
811+
}
812+
813+
return 0;
814+
}
602815

603816
static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
604817
AVFrame *frame, int *got_frame,
@@ -636,6 +849,8 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
636849
insurf, &outsurf, sync);
637850
if (ret == MFX_WRN_DEVICE_BUSY)
638851
av_usleep(500);
852+
else if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO || avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
853+
parse_sei_mpeg12(avctx, q, NULL);
639854

640855
} while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE);
641856

@@ -677,6 +892,24 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
677892
return AVERROR_BUG;
678893
}
679894

895+
switch (avctx->codec_id) {
896+
case AV_CODEC_ID_MPEG1VIDEO:
897+
case AV_CODEC_ID_MPEG2VIDEO:
898+
ret = parse_sei_mpeg12(avctx, q, out_frame->frame);
899+
break;
900+
case AV_CODEC_ID_H264:
901+
ret = parse_sei_h264(avctx, q, out_frame->frame);
902+
break;
903+
case AV_CODEC_ID_HEVC:
904+
ret = parse_sei_hevc(avctx, q, out_frame);
905+
break;
906+
default:
907+
ret = 0;
908+
}
909+
910+
if (ret < 0)
911+
av_log(avctx, AV_LOG_ERROR, "Error parsing SEI data\n");
912+
680913
out_frame->queued += 1;
681914

682915
aframe = (QSVAsyncFrame){ sync, out_frame };

0 commit comments

Comments
 (0)