From: Yukinori Yamazoe <[email protected]> AVPacket on MPEG-2 PS that it has dts is exist and pts is AV_NOPTS_VALUE. Could not be added in the case of AV_NOPTS_VALUE because pts was key in put_dts()/get_dts(). So, sequential number is key in put_dts()/get_dts(). Then input the bitstream with the TimeStamp of the sequential number to QSV decoder, it output the TimeStamp strange value of (+3002) only the last frame. So, TimeStamp the bitstream has is calculated in 90KHz.
The timing when from decoder input bitstream to output frame is different per video stream. Further, there may be necessary to back up max 32 packet timestamp of the Frame reordering in H.264, from being decoded output. Number of timestamps may be insufficient when it is a fixed value. So, timestamp table was to be extended as needed. Signed-off-by: Luca Barbato <[email protected]> --- How can you get into this situation? If the packet has a duration we can guess the pts somehow anyway. libavcodec/qsv.c | 123 +++++++++++++++++++++++++++----------------------- libavcodec/qsv.h | 12 ++++- libavcodec/qsv_h264.c | 4 ++ 3 files changed, 80 insertions(+), 59 deletions(-) diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index 1fa8fa7..4634bcc 100644 --- a/libavcodec/qsv.c +++ b/libavcodec/qsv.c @@ -84,29 +84,10 @@ static int codec_id_to_mfx(enum AVCodecID codec_id) return AVERROR(ENOSYS); } -static int qsv_timestamps_alloc(QSVContext *q, mfxFrameAllocRequest *req) +static void reset_timestamps(QSVContext *q) { - int ret = AVERROR(ENOMEM); - - q->dts = av_mallocz_array(q->nb_timestamps, sizeof(*q->dts)); - q->pts = av_mallocz_array(q->nb_timestamps, sizeof(*q->pts)); - - if (!q->dts || !q->pts) - goto fail; - for (int i = 0; i < q->nb_timestamps; i++) - q->pts[i] = q->dts[i] = AV_NOPTS_VALUE; - - if ((ret = MFXVideoDECODE_Init(q->session, &q->param))) - ret = ff_qsv_error(ret); - -fail: - if (ret) { - av_free(q->dts); - av_free(q->pts); - } - - return ret; + q->timestamps[i].id = -1; } int ff_qsv_init(AVCodecContext *c, QSVContext *q) @@ -151,9 +132,21 @@ int ff_qsv_init(AVCodecContext *c, QSVContext *q) return ff_qsv_error(ret); q->nb_timestamps = req.NumFrameSuggested + q->param.AsyncDepth; + q->put_dts_count = 0; + q->decoded_count = 0; q->last_decode_status = MFX_ERR_MORE_DATA; - return qsv_timestamps_alloc(q, &req); + q->timestamp_id_magic_factor = 90000 * c->time_base.num * c->ticks_per_frame / c->time_base.den; + + if (!(q->timestamps = av_mallocz_array(q->nb_timestamps, sizeof(*q->timestamps)))) + return AVERROR(ENOMEM); + + reset_timestamps(q); + + if ((ret = MFXVideoDECODE_Init(q->session, &q->param))) + ret = ff_qsv_error(ret); + + return ret; } static int bitstream_realloc(mfxBitstream *bs, int size) @@ -264,47 +257,58 @@ static mfxFrameSurface1 *get_surface(AVCodecContext *avctx, QSVContext *q) return &sl->surface; } -static int get_dts(QSVContext *q, int64_t pts, int64_t *dts) +static int realloc_timestamps(QSVContext *q, int old_nmemb, int new_nmemb) { - int i; + QSVTimeStamp *tmp = av_realloc_array(q->timestamps, new_nmemb, sizeof(*q->timestamps)); + if (!tmp) + return AVERROR(ENOMEM); - if (pts == AV_NOPTS_VALUE) { - *dts = AV_NOPTS_VALUE; - return 0; - } + q->timestamps = tmp; + q->nb_timestamps = new_nmemb; - for (i = 0; i < q->nb_timestamps; i++) { - if (q->pts[i] == pts) - break; - } - if (i == q->nb_timestamps) { + for (int i = old_nmemb; i < q->nb_timestamps; i++) + q->timestamps[i].id = -1; + + return 0; +} + +static int get_dts(QSVContext *q, int64_t id, int64_t *pts, int64_t *dts) +{ + int i = id % q->nb_timestamps; + + if (id >= q->put_dts_count || id < 0 || q->timestamps[i].id != id) { av_log(q, AV_LOG_ERROR, - "Requested pts %"PRId64" does not match any dts\n", - pts); + "Requested timestamp id %"PRId64" does not exist\n", + id); return AVERROR_BUG; } - *dts = q->dts[i]; - q->pts[i] = AV_NOPTS_VALUE; + *pts = q->timestamps[i].pts; + *dts = q->timestamps[i].dts; return 0; } -static int put_dts(QSVContext *q, int64_t pts, int dts) +static int put_dts(QSVContext *q, int64_t pts, int64_t dts, int64_t *id) { - int i; - for (i = 0; i < q->nb_timestamps; i++) { - if (q->pts[i] == AV_NOPTS_VALUE) - break; - } + int ret, i; - if (i == q->nb_timestamps) { - av_log(q, AV_LOG_INFO, "No slot available.\n"); - return AVERROR_BUG; + if (!q->decoded_count && q->nb_timestamps == q->put_dts_count) { + // For decoder delay + if ((ret = realloc_timestamps(q, q->nb_timestamps, q->nb_timestamps * 2)) < 0) + return ret; + } else if (q->decoded_count == 1 && q->nb_timestamps < (q->put_dts_count + 32)) { + // For frame reordering + // I[31]P[30]B[29]B[28] ... B[1]B[0] (Number in [] is display order) + if ((ret = realloc_timestamps(q, q->nb_timestamps, q->put_dts_count + 32)) < 0) + return ret; } - q->pts[i] = pts; - q->dts[i] = dts; + i = q->put_dts_count % q->nb_timestamps; + q->timestamps[i].id = *id = q->put_dts_count; + q->timestamps[i].pts = pts; + q->timestamps[i].dts = dts; + q->put_dts_count++; return 0; } @@ -319,6 +323,7 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q, mfxBitstream *bs = &q->bs; int size = avpkt->size; int ret; + int64_t timestamp_id; AVPacket pkt; *got_frame = 0; @@ -332,12 +337,10 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q, if (q->pending) { ff_packet_list_get(&q->pending, &q->pending_end, &pkt); - if ((ret = put_dts(q, pkt.pts, pkt.dts)) < 0) - return ret; - - q->bs.TimeStamp = pkt.pts; - - ret = bitstream_enqueue(&q->bs, pkt.data, pkt.size); + if (!(ret = put_dts(q, pkt.pts, pkt.dts, ×tamp_id))) { + q->bs.TimeStamp = timestamp_id * q->timestamp_id_magic_factor; + ret = bitstream_enqueue(&q->bs, pkt.data, pkt.size); + } av_packet_unref(&pkt); @@ -378,11 +381,12 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q, } if (sync) { - int64_t dts; + int64_t pts, dts; MFXVideoCORE_SyncOperation(q->session, sync, 60000); - if ((ret = get_dts(q, outsurf->Data.TimeStamp, &dts)) < 0) + timestamp_id = outsurf->Data.TimeStamp / q->timestamp_id_magic_factor; + if ((ret = get_dts(q, timestamp_id, &pts, &dts)) < 0) return ret; AVFrame *workframe = outsurf->Data.MemId; @@ -395,8 +399,9 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q, outsurf->Data.UV = workframe->data[1]; *got_frame = 1; + q->decoded_count++; - frame->pkt_pts = frame->pts = outsurf->Data.TimeStamp; + frame->pkt_pts = frame->pts = pts; frame->pkt_dts = dts; frame->repeat_pict = @@ -424,6 +429,8 @@ int ff_qsv_flush(QSVContext *q) q->bs.DataOffset = q->bs.DataLength = 0; + reset_timestamps(q); + ff_packet_list_free(&q->pending, &q->pending_end); return ret; @@ -435,6 +442,8 @@ int ff_qsv_close(QSVContext *q) free_surface_list(q); + av_freep(&q->timestamps); + ff_packet_list_free(&q->pending, &q->pending_end); return ff_qsv_error(ret); diff --git a/libavcodec/qsv.h b/libavcodec/qsv.h index f7a8d9b..895eb93 100644 --- a/libavcodec/qsv.h +++ b/libavcodec/qsv.h @@ -36,6 +36,12 @@ #define SYNC_TIME_DEFAULT 5 * 1000 // 5s +typedef struct QSVTimeStamp { + int64_t id; + int64_t pts; + int64_t dts; +} QSVTimeStamp; + typedef struct QSVSurfaceList { mfxFrameSurface1 surface; struct QSVSurfaceList *next; @@ -46,9 +52,11 @@ typedef struct QSVContext { mfxSession session; mfxVideoParam param; QSVSurfaceList *surflist; - int64_t *dts; - int64_t *pts; + QSVTimeStamp *timestamps; int nb_timestamps; + int timestamp_id_magic_factor; + int put_dts_count; + int decoded_count; mfxSyncPoint sync; mfxBitstream bs; int last_decode_status; diff --git a/libavcodec/qsv_h264.c b/libavcodec/qsv_h264.c index 3c3ca31..f07e770 100644 --- a/libavcodec/qsv_h264.c +++ b/libavcodec/qsv_h264.c @@ -44,6 +44,10 @@ static av_cold int qsv_dec_init(AVCodecContext *avctx) mfxBitstream *bs = &q->qsv.bs; int ret; + if (avctx->ticks_per_frame == 1) + avctx->time_base.den *= 2; + avctx->ticks_per_frame = 2; + avctx->pix_fmt = AV_PIX_FMT_NV12; if (!(q->bsf = av_bitstream_filter_init("h264_mp4toannexb"))) -- 1.8.3.2 _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
