Skip to content

Commit 61626eb

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

File tree

2 files changed

+322
-1
lines changed

2 files changed

+322
-1
lines changed

libavcodec/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ OBJS-$(CONFIG_MSS34DSP) += mss34dsp.o
146146
OBJS-$(CONFIG_PIXBLOCKDSP) += pixblockdsp.o
147147
OBJS-$(CONFIG_QPELDSP) += qpeldsp.o
148148
OBJS-$(CONFIG_QSV) += qsv.o
149-
OBJS-$(CONFIG_QSVDEC) += qsvdec.o
149+
OBJS-$(CONFIG_QSVDEC) += qsvdec.o h264_sei.o hevc_sei.o
150150
OBJS-$(CONFIG_QSVENC) += qsvenc.o
151151
OBJS-$(CONFIG_RANGECODER) += rangecoder.o
152152
OBJS-$(CONFIG_RDFT) += rdft.o

libavcodec/qsvdec.c

+321
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "libavutil/time.h"
4242
#include "libavutil/imgutils.h"
4343
#include "libavutil/film_grain_params.h"
44+
#include <libavutil/reverse.h>
4445

4546
#include "avcodec.h"
4647
#include "codec_internal.h"
@@ -49,6 +50,9 @@
4950
#include "hwconfig.h"
5051
#include "qsv.h"
5152
#include "qsv_internal.h"
53+
#include "h264_sei.h"
54+
#include "hevc_ps.h"
55+
#include "hevc_sei.h"
5256

5357
#if QSV_ONEVPL
5458
#include <mfxdispatcher.h>
@@ -66,6 +70,8 @@ static const AVRational mfx_tb = { 1, 90000 };
6670
AV_NOPTS_VALUE : pts_tb.num ? \
6771
av_rescale_q(mfx_pts, mfx_tb, pts_tb) : mfx_pts)
6872

73+
#define PAYLOAD_BUFFER_SIZE 65535
74+
6975
typedef struct QSVAsyncFrame {
7076
mfxSyncPoint *sync;
7177
QSVFrame *frame;
@@ -107,6 +113,9 @@ typedef struct QSVContext {
107113

108114
mfxExtBuffer **ext_buffers;
109115
int nb_ext_buffers;
116+
117+
mfxU8 payload_buffer[PAYLOAD_BUFFER_SIZE];
118+
AVBufferRef *a53_buf_ref;
110119
} QSVContext;
111120

112121
static const AVCodecHWConfigInternal *const qsv_hw_configs[] = {
@@ -628,6 +637,299 @@ static int qsv_export_film_grain(AVCodecContext *avctx, mfxExtAV1FilmGrainParam
628637
}
629638
#endif
630639

640+
static int find_start_offset(mfxU8 data[4])
641+
{
642+
if (data[0] == 0 && data[1] == 0 && data[2] == 1)
643+
return 3;
644+
645+
if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 1)
646+
return 4;
647+
648+
return 0;
649+
}
650+
651+
static int parse_sei_h264(AVCodecContext* avctx, QSVContext* q, AVFrame* out)
652+
{
653+
H264SEIContext sei = { 0 };
654+
GetBitContext gb = { 0 };
655+
mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize = sizeof(q->payload_buffer) - AV_INPUT_BUFFER_PADDING_SIZE };
656+
mfxU64 ts;
657+
int ret;
658+
659+
while (1) {
660+
int start;
661+
memset(payload.Data, 0, payload.BufSize);
662+
663+
ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
664+
if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
665+
av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q->payload_buffer), payload.BufSize);
666+
return 0;
667+
}
668+
if (ret != MFX_ERR_NONE)
669+
return ret;
670+
671+
if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8)
672+
break;
673+
674+
start = find_start_offset(payload.Data);
675+
676+
switch (payload.Type) {
677+
case SEI_TYPE_BUFFERING_PERIOD:
678+
case SEI_TYPE_PIC_TIMING:
679+
continue;
680+
}
681+
682+
if (init_get_bits(&gb, &payload.Data[start], payload.NumBit - start * 8) < 0)
683+
av_log(avctx, AV_LOG_ERROR, "Error initializing bitstream reader SEI type: %d Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
684+
else {
685+
ret = ff_h264_sei_decode(&sei, &gb, NULL, avctx);
686+
687+
if (ret < 0)
688+
av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI type: %d Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
689+
else
690+
av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d Numbits %d\n", payload.Type, payload.NumBit);
691+
}
692+
}
693+
694+
if (out)
695+
return ff_h264_set_sei_to_frame(avctx, &sei, out, NULL, 0);
696+
697+
return 0;
698+
}
699+
700+
static int parse_sei_hevc(AVCodecContext* avctx, QSVContext* q, QSVFrame* out)
701+
{
702+
HEVCSEI sei = { 0 };
703+
HEVCParamSets ps = { 0 };
704+
GetBitContext gb = { 0 };
705+
mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize = sizeof(q->payload_buffer) - AV_INPUT_BUFFER_PADDING_SIZE };
706+
mfxFrameSurface1 *surface = &out->surface;
707+
mfxU64 ts;
708+
int ret, has_logged = 0;
709+
710+
while (1) {
711+
int start;
712+
memset(payload.Data, 0, payload.BufSize);
713+
714+
ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
715+
if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
716+
av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q->payload_buffer), payload.BufSize);
717+
return 0;
718+
}
719+
if (ret != MFX_ERR_NONE)
720+
return ret;
721+
722+
if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8)
723+
break;
724+
725+
if (!has_logged) {
726+
has_logged = 1;
727+
av_log(avctx, AV_LOG_VERBOSE, "-----------------------------------------\n");
728+
av_log(avctx, AV_LOG_VERBOSE, "Start reading SEI - payload timestamp: %llu - surface timestamp: %llu\n", ts, surface->Data.TimeStamp);
729+
}
730+
731+
if (ts != surface->Data.TimeStamp) {
732+
av_log(avctx, AV_LOG_WARNING, "GetPayload timestamp (%llu) does not match surface timestamp: (%llu)\n", ts, surface->Data.TimeStamp);
733+
}
734+
735+
start = find_start_offset(payload.Data);
736+
737+
av_log(avctx, AV_LOG_VERBOSE, "parsing SEI type: %3d Numbits %3d Start: %d\n", payload.Type, payload.NumBit, start);
738+
739+
switch (payload.Type) {
740+
case SEI_TYPE_BUFFERING_PERIOD:
741+
case SEI_TYPE_PIC_TIMING:
742+
continue;
743+
case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
744+
// There seems to be a bug in MSDK
745+
payload.NumBit -= 8;
746+
747+
break;
748+
case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO:
749+
// There seems to be a bug in MSDK
750+
payload.NumBit = 48;
751+
752+
break;
753+
case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
754+
// There seems to be a bug in MSDK
755+
if (payload.NumBit == 552)
756+
payload.NumBit = 528;
757+
break;
758+
}
759+
760+
if (init_get_bits(&gb, &payload.Data[start], payload.NumBit - start * 8) < 0)
761+
av_log(avctx, AV_LOG_ERROR, "Error initializing bitstream reader SEI type: %d Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
762+
else {
763+
ret = ff_hevc_decode_nal_sei(&gb, avctx, &sei, &ps, HEVC_NAL_SEI_PREFIX);
764+
765+
if (ret < 0)
766+
av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI type: %d Numbits %d error: %d\n", payload.Type, payload.NumBit, ret);
767+
else
768+
av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d Numbits %d\n", payload.Type, payload.NumBit);
769+
}
770+
}
771+
772+
if (has_logged) {
773+
av_log(avctx, AV_LOG_VERBOSE, "End reading SEI\n");
774+
}
775+
776+
if (out && out->frame)
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);
778+
779+
return 0;
780+
}
781+
782+
#define A53_MAX_CC_COUNT 2000
783+
784+
static int mpeg_decode_a53_cc(AVCodecContext *avctx, QSVContext *s,
785+
const uint8_t *p, int buf_size)
786+
{
787+
if (buf_size >= 6 &&
788+
p[0] == 'G' && p[1] == 'A' && p[2] == '9' && p[3] == '4' &&
789+
p[4] == 3 && (p[5] & 0x40)) {
790+
/* extract A53 Part 4 CC data */
791+
unsigned cc_count = p[5] & 0x1f;
792+
if (cc_count > 0 && buf_size >= 7 + cc_count * 3) {
793+
const uint64_t old_size = s->a53_buf_ref ? s->a53_buf_ref->size : 0;
794+
const uint64_t new_size = (old_size + cc_count
795+
* UINT64_C(3));
796+
int ret;
797+
798+
if (new_size > 3*A53_MAX_CC_COUNT)
799+
return AVERROR(EINVAL);
800+
801+
ret = av_buffer_realloc(&s->a53_buf_ref, new_size);
802+
if (ret >= 0)
803+
memcpy(s->a53_buf_ref->data + old_size, p + 7, cc_count * UINT64_C(3));
804+
805+
avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
806+
}
807+
return 1;
808+
} else if (buf_size >= 2 && p[0] == 0x03 && (p[1]&0x7f) == 0x01) {
809+
/* extract SCTE-20 CC data */
810+
GetBitContext gb;
811+
unsigned cc_count = 0;
812+
int ret;
813+
814+
init_get_bits8(&gb, p + 2, buf_size - 2);
815+
cc_count = get_bits(&gb, 5);
816+
if (cc_count > 0) {
817+
uint64_t old_size = s->a53_buf_ref ? s->a53_buf_ref->size : 0;
818+
uint64_t new_size = (old_size + cc_count * UINT64_C(3));
819+
if (new_size > 3 * A53_MAX_CC_COUNT)
820+
return AVERROR(EINVAL);
821+
822+
ret = av_buffer_realloc(&s->a53_buf_ref, new_size);
823+
if (ret >= 0) {
824+
uint8_t field, cc1, cc2;
825+
uint8_t *cap = s->a53_buf_ref->data;
826+
827+
memset(s->a53_buf_ref->data + old_size, 0, cc_count * 3);
828+
for (unsigned i = 0; i < cc_count && get_bits_left(&gb) >= 26; i++) {
829+
skip_bits(&gb, 2); // priority
830+
field = get_bits(&gb, 2);
831+
skip_bits(&gb, 5); // line_offset
832+
cc1 = get_bits(&gb, 8);
833+
cc2 = get_bits(&gb, 8);
834+
skip_bits(&gb, 1); // marker
835+
836+
if (!field) { // forbidden
837+
cap[0] = cap[1] = cap[2] = 0x00;
838+
} else {
839+
field = (field == 2 ? 1 : 0);
840+
////if (!s1->mpeg_enc_ctx.top_field_first) field = !field;
841+
cap[0] = 0x04 | field;
842+
cap[1] = ff_reverse[cc1];
843+
cap[2] = ff_reverse[cc2];
844+
}
845+
cap += 3;
846+
}
847+
}
848+
avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
849+
}
850+
return 1;
851+
} else if (buf_size >= 11 && p[0] == 'C' && p[1] == 'C' && p[2] == 0x01 && p[3] == 0xf8) {
852+
int cc_count = 0;
853+
int i, ret;
854+
// There is a caption count field in the data, but it is often
855+
// incorrect. So count the number of captions present.
856+
for (i = 5; i + 6 <= buf_size && ((p[i] & 0xfe) == 0xfe); i += 6)
857+
cc_count++;
858+
// Transform the DVD format into A53 Part 4 format
859+
if (cc_count > 0) {
860+
int old_size = s->a53_buf_ref ? s->a53_buf_ref->size : 0;
861+
uint64_t new_size = (old_size + cc_count
862+
* UINT64_C(6));
863+
if (new_size > 3*A53_MAX_CC_COUNT)
864+
return AVERROR(EINVAL);
865+
866+
ret = av_buffer_realloc(&s->a53_buf_ref, new_size);
867+
if (ret >= 0) {
868+
uint8_t field1 = !!(p[4] & 0x80);
869+
uint8_t *cap = s->a53_buf_ref->data;
870+
p += 5;
871+
for (i = 0; i < cc_count; i++) {
872+
cap[0] = (p[0] == 0xff && field1) ? 0xfc : 0xfd;
873+
cap[1] = p[1];
874+
cap[2] = p[2];
875+
cap[3] = (p[3] == 0xff && !field1) ? 0xfc : 0xfd;
876+
cap[4] = p[4];
877+
cap[5] = p[5];
878+
cap += 6;
879+
p += 6;
880+
}
881+
}
882+
avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
883+
}
884+
return 1;
885+
}
886+
return 0;
887+
}
888+
889+
static int parse_sei_mpeg12(AVCodecContext* avctx, QSVContext* q, AVFrame* out)
890+
{
891+
mfxPayload payload = { 0, .Data = &q->payload_buffer[0], .BufSize = sizeof(q->payload_buffer) - AV_INPUT_BUFFER_PADDING_SIZE };
892+
mfxU64 ts;
893+
int ret;
894+
895+
while (1) {
896+
int start;
897+
898+
memset(payload.Data, 0, payload.BufSize);
899+
ret = MFXVideoDECODE_GetPayload(q->session, &ts, &payload);
900+
if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
901+
av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q->payload_buffer), payload.BufSize);
902+
return 0;
903+
}
904+
if (ret != MFX_ERR_NONE)
905+
return ret;
906+
907+
if (payload.NumBit == 0 || payload.NumBit >= payload.BufSize * 8)
908+
break;
909+
910+
start = find_start_offset(payload.Data);
911+
912+
start++;
913+
914+
mpeg_decode_a53_cc(avctx, q, &payload.Data[start], (int)((payload.NumBit + 7) / 8) - start);
915+
916+
av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d Numbits %d start %d -> %.s\n", payload.Type, payload.NumBit, start, (char *)(&payload.Data[start]));
917+
}
918+
919+
if (!out)
920+
return 0;
921+
922+
if (q->a53_buf_ref) {
923+
924+
AVFrameSideData *sd = av_frame_new_side_data_from_buf(out, AV_FRAME_DATA_A53_CC, q->a53_buf_ref);
925+
if (!sd)
926+
av_buffer_unref(&q->a53_buf_ref);
927+
q->a53_buf_ref = NULL;
928+
}
929+
930+
return 0;
931+
}
932+
631933
static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
632934
AVFrame *frame, int *got_frame,
633935
const AVPacket *avpkt)
@@ -664,6 +966,8 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
664966
insurf, &outsurf, sync);
665967
if (ret == MFX_WRN_DEVICE_BUSY)
666968
av_usleep(500);
969+
else if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
970+
parse_sei_mpeg12(avctx, q, NULL);
667971

668972
} while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE);
669973

@@ -705,6 +1009,23 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
7051009
return AVERROR_BUG;
7061010
}
7071011

1012+
switch (avctx->codec_id) {
1013+
case AV_CODEC_ID_MPEG2VIDEO:
1014+
ret = parse_sei_mpeg12(avctx, q, out_frame->frame);
1015+
break;
1016+
case AV_CODEC_ID_H264:
1017+
ret = parse_sei_h264(avctx, q, out_frame->frame);
1018+
break;
1019+
case AV_CODEC_ID_HEVC:
1020+
ret = parse_sei_hevc(avctx, q, out_frame);
1021+
break;
1022+
default:
1023+
ret = 0;
1024+
}
1025+
1026+
if (ret < 0)
1027+
av_log(avctx, AV_LOG_ERROR, "Error parsing SEI data: %d\n", ret);
1028+
7081029
out_frame->queued += 1;
7091030

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

0 commit comments

Comments
 (0)