Skip to content

Commit 99f713a

Browse files
committed
avcodec/qsvdec: Implement SEI parsing for QSV decoders
Signed-off-by: softworkz <softworkz@hotmail.com>
1 parent a57bfae commit 99f713a

File tree

2 files changed

+235
-1
lines changed

2 files changed

+235
-1
lines changed

libavcodec/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ OBJS-$(CONFIG_MSS34DSP) += mss34dsp.o
144144
OBJS-$(CONFIG_PIXBLOCKDSP) += pixblockdsp.o
145145
OBJS-$(CONFIG_QPELDSP) += qpeldsp.o
146146
OBJS-$(CONFIG_QSV) += qsv.o
147-
OBJS-$(CONFIG_QSVDEC) += qsvdec.o
147+
OBJS-$(CONFIG_QSVDEC) += qsvdec.o h264_slice.o hevcdec.o mpeg12dec.o
148148
OBJS-$(CONFIG_QSVENC) += qsvenc.o
149149
OBJS-$(CONFIG_RANGECODER) += rangecoder.o
150150
OBJS-$(CONFIG_RDFT) += rdft.o

libavcodec/qsvdec.c

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

603818
static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
604819
AVFrame *frame, int *got_frame,
@@ -636,6 +851,8 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
636851
insurf, &outsurf, sync);
637852
if (ret == MFX_WRN_DEVICE_BUSY)
638853
av_usleep(500);
854+
else if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
855+
parse_sei_mpeg12(avctx, q, NULL);
639856

640857
} while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE);
641858

@@ -677,6 +894,23 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
677894
return AVERROR_BUG;
678895
}
679896

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

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

0 commit comments

Comments
 (0)