[FFmpeg-cvslog] Merge commit '32c8359093d1ff4f45ed19518b449b3ac3769d27'
Hendrik Leppkes
git at videolan.org
Fri Oct 7 14:06:49 EEST 2016
ffmpeg | branch: master | Hendrik Leppkes <h.leppkes at gmail.com> | Fri Oct 7 12:55:50 2016 +0200| [3f9137c57d2344d7613f134128235c18edcede95] | committer: Hendrik Leppkes
Merge commit '32c8359093d1ff4f45ed19518b449b3ac3769d27'
* commit '32c8359093d1ff4f45ed19518b449b3ac3769d27':
lavc: export the timestamps when decoding in AVFrame.pts
Merged-by: Hendrik Leppkes <h.leppkes at gmail.com>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=3f9137c57d2344d7613f134128235c18edcede95
---
doc/APIchanges | 7 +++++++
libavcodec/audiotoolboxdec.c | 5 +++++
libavcodec/crystalhd.c | 5 +++++
libavcodec/cuvid.c | 4 ++++
libavcodec/gifdec.c | 4 ++++
libavcodec/libopenh264dec.c | 4 ++++
libavcodec/libschroedingerdec.c | 7 ++++++-
libavcodec/mediacodecdec.c | 14 ++++++++++++--
libavcodec/mmaldec.c | 7 ++++++-
libavcodec/qsvdec.c | 7 ++++++-
libavcodec/utils.c | 24 ++++++++++++++++++++----
libavcodec/version.h | 4 ++--
libavcodec/vp9.c | 5 +++++
libavutil/frame.c | 10 +++++++++-
libavutil/frame.h | 4 ++++
libavutil/version.h | 3 +++
16 files changed, 102 insertions(+), 12 deletions(-)
diff --git a/doc/APIchanges b/doc/APIchanges
index 7869629..130638b 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -15,6 +15,13 @@ libavutil: 2015-08-28
API changes, most recent first:
+2016-xx-xx - xxxxxxx - lavc 57.61.100 / lavc 57.24.0 - avcodec.h
+ Decoders now export the frame timestamp as AVFrame.pts. It was
+ previously exported as AVFrame.pkt_pts, which is now deprecated.
+
+ Note: When decoding, AVFrame.pts uses the stream/packet timebase,
+ and not the codec timebase.
+
2016-09-xx - xxxxxxx - lavu 55.32.100 / 55.16.0 - hwcontext.h hwcontext_qsv.h
Add AV_HWDEVICE_TYPE_QSV and a new installed header with QSV-specific
hwcontext definitions.
diff --git a/libavcodec/audiotoolboxdec.c b/libavcodec/audiotoolboxdec.c
index 1097668..3066d47 100644
--- a/libavcodec/audiotoolboxdec.c
+++ b/libavcodec/audiotoolboxdec.c
@@ -554,7 +554,12 @@ static int ffat_decode(AVCodecContext *avctx, void *data,
ffat_copy_samples(avctx, frame);
*got_frame_ptr = 1;
if (at->last_pts != AV_NOPTS_VALUE) {
+ frame->pts = at->last_pts;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
frame->pkt_pts = at->last_pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
at->last_pts = avpkt->pts;
}
} else if (ret && ret != 1) {
diff --git a/libavcodec/crystalhd.c b/libavcodec/crystalhd.c
index 59b14b9..0f5101a 100644
--- a/libavcodec/crystalhd.c
+++ b/libavcodec/crystalhd.c
@@ -707,7 +707,12 @@ static inline CopyRet copy_frame(AVCodecContext *avctx,
if (interlaced)
priv->pic->top_field_first = !bottom_first;
+ priv->pic->pts = pkt_pts;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
priv->pic->pkt_pts = pkt_pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
if (!priv->need_second_field) {
*got_frame = 1;
diff --git a/libavcodec/cuvid.c b/libavcodec/cuvid.c
index 56f349c..27a4c30 100644
--- a/libavcodec/cuvid.c
+++ b/libavcodec/cuvid.c
@@ -469,7 +469,11 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame)
/* CUVIDs opaque reordering breaks the internal pkt logic.
* So set pkt_pts and clear all the other pkt_ fields.
*/
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
frame->pkt_pts = frame->pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
av_frame_set_pkt_pos(frame, -1);
av_frame_set_pkt_duration(frame, 0);
av_frame_set_pkt_size(frame, -1);
diff --git a/libavcodec/gifdec.c b/libavcodec/gifdec.c
index 20ae903..48345db 100644
--- a/libavcodec/gifdec.c
+++ b/libavcodec/gifdec.c
@@ -462,7 +462,11 @@ static int gif_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, A
bytestream2_init(&s->gb, avpkt->data, avpkt->size);
s->frame->pts = avpkt->pts;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
s->frame->pkt_pts = avpkt->pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
s->frame->pkt_dts = avpkt->dts;
av_frame_set_pkt_duration(s->frame, avpkt->duration);
diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c
index 6af60af..ab0a84c 100644
--- a/libavcodec/libopenh264dec.c
+++ b/libavcodec/libopenh264dec.c
@@ -221,7 +221,11 @@ static int svc_decode_frame(AVCodecContext *avctx, void *data,
avframe->pts = s->pkt_filtered.pts;
avframe->pkt_dts = s->pkt_filtered.dts;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
avframe->pkt_pts = s->pkt_filtered.pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
*got_frame = 1;
}
diff --git a/libavcodec/libschroedingerdec.c b/libavcodec/libschroedingerdec.c
index 152cbe7..c9930c7 100644
--- a/libavcodec/libschroedingerdec.c
+++ b/libavcodec/libschroedingerdec.c
@@ -326,7 +326,12 @@ static int libschroedinger_decode_frame(AVCodecContext *avctx,
framewithpts->frame->components[2].length);
/* Fill frame with current buffer data from Schroedinger. */
- avframe->pkt_pts = framewithpts->pts;
+ avframe->pts = framewithpts->pts;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
+ avframe->pkt_pts = avframe->pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
avframe->linesize[0] = framewithpts->frame->components[0].stride;
avframe->linesize[1] = framewithpts->frame->components[1].stride;
avframe->linesize[2] = framewithpts->frame->components[2].stride;
diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c
index 223942b..6683de7 100644
--- a/libavcodec/mediacodecdec.c
+++ b/libavcodec/mediacodecdec.c
@@ -202,12 +202,17 @@ static int mediacodec_wrap_hw_buffer(AVCodecContext *avctx,
frame->format = avctx->pix_fmt;
if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) {
- frame->pkt_pts = av_rescale_q(info->presentationTimeUs,
+ frame->pts = av_rescale_q(info->presentationTimeUs,
av_make_q(1, 1000000),
avctx->pkt_timebase);
} else {
- frame->pkt_pts = info->presentationTimeUs;
+ frame->pts = info->presentationTimeUs;
}
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
+ frame->pkt_pts = frame->pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
frame->pkt_dts = AV_NOPTS_VALUE;
buffer = av_mallocz(sizeof(AVMediaCodecBuffer));
@@ -278,7 +283,12 @@ static int mediacodec_wrap_sw_buffer(AVCodecContext *avctx,
* on the last avpacket received which is not in sync with the frame:
* * N avpackets can be pushed before 1 frame is actually returned
* * 0-sized avpackets are pushed to flush remaining frames at EOS */
+ frame->pts = info->presentationTimeUs;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
frame->pkt_pts = info->presentationTimeUs;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
frame->pkt_dts = AV_NOPTS_VALUE;
av_log(avctx, AV_LOG_DEBUG,
diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c
index 56ad948..3f92bf5 100644
--- a/libavcodec/mmaldec.c
+++ b/libavcodec/mmaldec.c
@@ -654,7 +654,12 @@ static int ffmal_copy_frame(AVCodecContext *avctx, AVFrame *frame,
avctx->pix_fmt, avctx->width, avctx->height);
}
- frame->pkt_pts = buffer->pts == MMAL_TIME_UNKNOWN ? AV_NOPTS_VALUE : buffer->pts;
+ frame->pts = buffer->pts == MMAL_TIME_UNKNOWN ? AV_NOPTS_VALUE : buffer->pts;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
+ frame->pkt_pts = frame->pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
frame->pkt_dts = AV_NOPTS_VALUE;
done:
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index b685e0e..6409312 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -443,7 +443,12 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q,
outsurf = out_frame->surface;
- frame->pkt_pts = frame->pts = outsurf->Data.TimeStamp;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
+ frame->pkt_pts = outsurf->Data.TimeStamp;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+ frame->pts = outsurf->Data.TimeStamp;
frame->repeat_pict =
outsurf->Info.PicStruct & MFX_PICSTRUCT_FRAME_TRIPLING ? 4 :
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 1239d49..be1686e 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -768,7 +768,12 @@ int ff_init_buffer_info(AVCodecContext *avctx, AVFrame *frame)
};
if (pkt) {
+ frame->pts = pkt->pts;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
frame->pkt_pts = pkt->pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
av_frame_set_pkt_pos (frame, pkt->pos);
av_frame_set_pkt_duration(frame, pkt->duration);
av_frame_set_pkt_size (frame, pkt->size);
@@ -794,7 +799,12 @@ int ff_init_buffer_info(AVCodecContext *avctx, AVFrame *frame)
frame->flags = (frame->flags & ~AV_FRAME_FLAG_DISCARD);
}
} else {
+ frame->pts = AV_NOPTS_VALUE;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
frame->pkt_pts = AV_NOPTS_VALUE;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
av_frame_set_pkt_pos (frame, -1);
av_frame_set_pkt_duration(frame, 0);
av_frame_set_pkt_size (frame, -1);
@@ -2043,7 +2053,7 @@ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
* which case the output will as well.
*
* @param pts the pts field of the decoded AVPacket, as passed through
- * AVFrame.pkt_pts
+ * AVFrame.pts
* @param dts the dts field of the decoded AVPacket
* @return one of the input values, may be AV_NOPTS_VALUE
*/
@@ -2281,7 +2291,7 @@ fail:
avctx->frame_number++;
av_frame_set_best_effort_timestamp(picture,
guess_correct_pts(avctx,
- picture->pkt_pts,
+ picture->pts,
picture->pkt_dts));
} else
av_frame_unref(picture);
@@ -2354,7 +2364,7 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
avctx->frame_number++;
av_frame_set_best_effort_timestamp(frame,
guess_correct_pts(avctx,
- frame->pkt_pts,
+ frame->pts,
frame->pkt_dts));
if (frame->format == AV_SAMPLE_FMT_NONE)
frame->format = avctx->sample_fmt;
@@ -2396,8 +2406,14 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
int64_t diff_ts = av_rescale_q(avctx->internal->skip_samples,
(AVRational){1, avctx->sample_rate},
avctx->pkt_timebase);
+ if(frame->pts!=AV_NOPTS_VALUE)
+ frame->pts += diff_ts;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
if(frame->pkt_pts!=AV_NOPTS_VALUE)
frame->pkt_pts += diff_ts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
if(frame->pkt_dts!=AV_NOPTS_VALUE)
frame->pkt_dts += diff_ts;
if (av_frame_get_pkt_duration(frame) >= diff_ts)
@@ -2874,7 +2890,7 @@ int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr
if (ret >= 0) {
if (av_frame_get_best_effort_timestamp(frame) == AV_NOPTS_VALUE) {
av_frame_set_best_effort_timestamp(frame,
- guess_correct_pts(avctx, frame->pkt_pts, frame->pkt_dts));
+ guess_correct_pts(avctx, frame->pts, frame->pkt_dts));
}
}
return ret;
diff --git a/libavcodec/version.h b/libavcodec/version.h
index de7280f..9c03364 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,8 +28,8 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 57
-#define LIBAVCODEC_VERSION_MINOR 60
-#define LIBAVCODEC_VERSION_MICRO 101
+#define LIBAVCODEC_VERSION_MINOR 61
+#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index cb2a4a2..779f2d5 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -3992,7 +3992,12 @@ static int vp9_decode_frame(AVCodecContext *ctx, void *frame,
}
if ((res = av_frame_ref(frame, s->s.refs[ref].f)) < 0)
return res;
+ ((AVFrame *)frame)->pts = pkt->pts;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
((AVFrame *)frame)->pkt_pts = pkt->pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
((AVFrame *)frame)->pkt_dts = pkt->dts;
for (i = 0; i < 8; i++) {
if (s->next_refs[i].f->buf[0])
diff --git a/libavutil/frame.c b/libavutil/frame.c
index 3c74931..53e6174 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -99,8 +99,12 @@ static void get_frame_defaults(AVFrame *frame)
memset(frame, 0, sizeof(*frame));
frame->pts =
- frame->pkt_dts =
+ frame->pkt_dts = AV_NOPTS_VALUE;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
frame->pkt_pts = AV_NOPTS_VALUE;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
frame->best_effort_timestamp = AV_NOPTS_VALUE;
frame->pkt_duration = 0;
frame->pkt_pos = -1;
@@ -295,7 +299,11 @@ static int frame_copy_props(AVFrame *dst, const AVFrame *src, int force_copy)
dst->palette_has_changed = src->palette_has_changed;
dst->sample_rate = src->sample_rate;
dst->opaque = src->opaque;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
dst->pkt_pts = src->pkt_pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
dst->pkt_dts = src->pkt_dts;
dst->pkt_pos = src->pkt_pos;
dst->pkt_size = src->pkt_size;
diff --git a/libavutil/frame.h b/libavutil/frame.h
index 1e2691e..a19da2f 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -267,10 +267,14 @@ typedef struct AVFrame {
*/
int64_t pts;
+#if FF_API_PKT_PTS
/**
* PTS copied from the AVPacket that was decoded to produce this frame.
+ * @deprecated use the pts field instead
*/
+ attribute_deprecated
int64_t pkt_pts;
+#endif
/**
* DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used)
diff --git a/libavutil/version.h b/libavutil/version.h
index 787ba58..8a41ef6 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -132,6 +132,9 @@
#ifndef FF_API_CRC_BIG_TABLE
#define FF_API_CRC_BIG_TABLE (LIBAVUTIL_VERSION_MAJOR < 56)
#endif
+#ifndef FF_API_PKT_PTS
+#define FF_API_PKT_PTS (LIBAVUTIL_VERSION_MAJOR < 56)
+#endif
/**
======================================================================
diff --cc doc/APIchanges
index 7869629,1caa1b7..130638b
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@@ -15,7 -13,11 +15,14 @@@ libavutil: 2015-08-2
API changes, most recent first:
-2016-xx-xx - xxxxxxx - lavc 57.24.0 - avcodec.h
++2016-xx-xx - xxxxxxx - lavc 57.61.100 / lavc 57.24.0 - avcodec.h
+ Decoders now export the frame timestamp as AVFrame.pts. It was
+ previously exported as AVFrame.pkt_pts, which is now deprecated.
+
-2016-xx-xx - xxxxxxx - lavu 55.16.0 - hwcontext.h hwcontext_qsv.h
++ Note: When decoding, AVFrame.pts uses the stream/packet timebase,
++ and not the codec timebase.
++
+2016-09-xx - xxxxxxx - lavu 55.32.100 / 55.16.0 - hwcontext.h hwcontext_qsv.h
Add AV_HWDEVICE_TYPE_QSV and a new installed header with QSV-specific
hwcontext definitions.
diff --cc libavcodec/audiotoolboxdec.c
index 1097668,0000000..3066d47
mode 100644,000000..100644
--- a/libavcodec/audiotoolboxdec.c
+++ b/libavcodec/audiotoolboxdec.c
@@@ -1,625 -1,0 +1,630 @@@
+/*
+ * Audio Toolbox system codecs
+ *
+ * copyright (c) 2016 Rodger Combs
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <AudioToolbox/AudioToolbox.h>
+
+#include "config.h"
+#include "avcodec.h"
+#include "ac3_parser.h"
+#include "bytestream.h"
+#include "internal.h"
+#include "mpegaudiodecheader.h"
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "libavutil/log.h"
+
+#ifndef __MAC_10_11
+#define kAudioFormatEnhancedAC3 'ec-3'
+#endif
+
+typedef struct ATDecodeContext {
+ AVClass *av_class;
+
+ AudioConverterRef converter;
+ AudioStreamPacketDescription pkt_desc;
+ AVPacket in_pkt;
+ AVPacket new_in_pkt;
+ AVBSFContext *bsf;
+ char *decoded_data;
+ int channel_map[64];
+
+ uint8_t *extradata;
+ int extradata_size;
+
+ int64_t last_pts;
+ int eof;
+} ATDecodeContext;
+
+static UInt32 ffat_get_format_id(enum AVCodecID codec, int profile)
+{
+ switch (codec) {
+ case AV_CODEC_ID_AAC:
+ return kAudioFormatMPEG4AAC;
+ case AV_CODEC_ID_AC3:
+ return kAudioFormatAC3;
+ case AV_CODEC_ID_ADPCM_IMA_QT:
+ return kAudioFormatAppleIMA4;
+ case AV_CODEC_ID_ALAC:
+ return kAudioFormatAppleLossless;
+ case AV_CODEC_ID_AMR_NB:
+ return kAudioFormatAMR;
+ case AV_CODEC_ID_EAC3:
+ return kAudioFormatEnhancedAC3;
+ case AV_CODEC_ID_GSM_MS:
+ return kAudioFormatMicrosoftGSM;
+ case AV_CODEC_ID_ILBC:
+ return kAudioFormatiLBC;
+ case AV_CODEC_ID_MP1:
+ return kAudioFormatMPEGLayer1;
+ case AV_CODEC_ID_MP2:
+ return kAudioFormatMPEGLayer2;
+ case AV_CODEC_ID_MP3:
+ return kAudioFormatMPEGLayer3;
+ case AV_CODEC_ID_PCM_ALAW:
+ return kAudioFormatALaw;
+ case AV_CODEC_ID_PCM_MULAW:
+ return kAudioFormatULaw;
+ case AV_CODEC_ID_QDMC:
+ return kAudioFormatQDesign;
+ case AV_CODEC_ID_QDM2:
+ return kAudioFormatQDesign2;
+ default:
+ av_assert0(!"Invalid codec ID!");
+ return 0;
+ }
+}
+
+static int ffat_get_channel_id(AudioChannelLabel label)
+{
+ if (label == 0)
+ return -1;
+ else if (label <= kAudioChannelLabel_LFEScreen)
+ return label - 1;
+ else if (label <= kAudioChannelLabel_RightSurround)
+ return label + 4;
+ else if (label <= kAudioChannelLabel_CenterSurround)
+ return label + 1;
+ else if (label <= kAudioChannelLabel_RightSurroundDirect)
+ return label + 23;
+ else if (label <= kAudioChannelLabel_TopBackRight)
+ return label - 1;
+ else if (label < kAudioChannelLabel_RearSurroundLeft)
+ return -1;
+ else if (label <= kAudioChannelLabel_RearSurroundRight)
+ return label - 29;
+ else if (label <= kAudioChannelLabel_RightWide)
+ return label - 4;
+ else if (label == kAudioChannelLabel_LFE2)
+ return ff_ctzll(AV_CH_LOW_FREQUENCY_2);
+ else if (label == kAudioChannelLabel_Mono)
+ return ff_ctzll(AV_CH_FRONT_CENTER);
+ else
+ return -1;
+}
+
+static int ffat_compare_channel_descriptions(const void* a, const void* b)
+{
+ const AudioChannelDescription* da = a;
+ const AudioChannelDescription* db = b;
+ return ffat_get_channel_id(da->mChannelLabel) - ffat_get_channel_id(db->mChannelLabel);
+}
+
+static AudioChannelLayout *ffat_convert_layout(AudioChannelLayout *layout, UInt32* size)
+{
+ AudioChannelLayoutTag tag = layout->mChannelLayoutTag;
+ AudioChannelLayout *new_layout;
+ if (tag == kAudioChannelLayoutTag_UseChannelDescriptions)
+ return layout;
+ else if (tag == kAudioChannelLayoutTag_UseChannelBitmap)
+ AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForBitmap,
+ sizeof(UInt32), &layout->mChannelBitmap, size);
+ else
+ AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForTag,
+ sizeof(AudioChannelLayoutTag), &tag, size);
+ new_layout = av_malloc(*size);
+ if (!new_layout) {
+ av_free(layout);
+ return NULL;
+ }
+ if (tag == kAudioChannelLayoutTag_UseChannelBitmap)
+ AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
+ sizeof(UInt32), &layout->mChannelBitmap, size, new_layout);
+ else
+ AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
+ sizeof(AudioChannelLayoutTag), &tag, size, new_layout);
+ new_layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
+ av_free(layout);
+ return new_layout;
+}
+
+static int ffat_update_ctx(AVCodecContext *avctx)
+{
+ ATDecodeContext *at = avctx->priv_data;
+ AudioStreamBasicDescription format;
+ UInt32 size = sizeof(format);
+ if (!AudioConverterGetProperty(at->converter,
+ kAudioConverterCurrentInputStreamDescription,
+ &size, &format)) {
+ if (format.mSampleRate)
+ avctx->sample_rate = format.mSampleRate;
+ avctx->channels = format.mChannelsPerFrame;
+ avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
+ avctx->frame_size = format.mFramesPerPacket;
+ }
+
+ if (!AudioConverterGetProperty(at->converter,
+ kAudioConverterCurrentOutputStreamDescription,
+ &size, &format)) {
+ format.mSampleRate = avctx->sample_rate;
+ format.mChannelsPerFrame = avctx->channels;
+ AudioConverterSetProperty(at->converter,
+ kAudioConverterCurrentOutputStreamDescription,
+ size, &format);
+ }
+
+ if (!AudioConverterGetPropertyInfo(at->converter, kAudioConverterOutputChannelLayout,
+ &size, NULL) && size) {
+ AudioChannelLayout *layout = av_malloc(size);
+ uint64_t layout_mask = 0;
+ int i;
+ if (!layout)
+ return AVERROR(ENOMEM);
+ AudioConverterGetProperty(at->converter, kAudioConverterOutputChannelLayout,
+ &size, layout);
+ if (!(layout = ffat_convert_layout(layout, &size)))
+ return AVERROR(ENOMEM);
+ for (i = 0; i < layout->mNumberChannelDescriptions; i++) {
+ int id = ffat_get_channel_id(layout->mChannelDescriptions[i].mChannelLabel);
+ if (id < 0)
+ goto done;
+ if (layout_mask & (1 << id))
+ goto done;
+ layout_mask |= 1 << id;
+ layout->mChannelDescriptions[i].mChannelFlags = i; // Abusing flags as index
+ }
+ avctx->channel_layout = layout_mask;
+ qsort(layout->mChannelDescriptions, layout->mNumberChannelDescriptions,
+ sizeof(AudioChannelDescription), &ffat_compare_channel_descriptions);
+ for (i = 0; i < layout->mNumberChannelDescriptions; i++)
+ at->channel_map[i] = layout->mChannelDescriptions[i].mChannelFlags;
+done:
+ av_free(layout);
+ }
+
+ if (!avctx->frame_size)
+ avctx->frame_size = 2048;
+
+ return 0;
+}
+
+static void put_descr(PutByteContext *pb, int tag, unsigned int size)
+{
+ int i = 3;
+ bytestream2_put_byte(pb, tag);
+ for (; i > 0; i--)
+ bytestream2_put_byte(pb, (size >> (7 * i)) | 0x80);
+ bytestream2_put_byte(pb, size & 0x7F);
+}
+
+static uint8_t* ffat_get_magic_cookie(AVCodecContext *avctx, UInt32 *cookie_size)
+{
+ ATDecodeContext *at = avctx->priv_data;
+ if (avctx->codec_id == AV_CODEC_ID_AAC) {
+ char *extradata;
+ PutByteContext pb;
+ *cookie_size = 5 + 3 + 5+13 + 5+at->extradata_size;
+ if (!(extradata = av_malloc(*cookie_size)))
+ return NULL;
+
+ bytestream2_init_writer(&pb, extradata, *cookie_size);
+
+ // ES descriptor
+ put_descr(&pb, 0x03, 3 + 5+13 + 5+at->extradata_size);
+ bytestream2_put_be16(&pb, 0);
+ bytestream2_put_byte(&pb, 0x00); // flags (= no flags)
+
+ // DecoderConfig descriptor
+ put_descr(&pb, 0x04, 13 + 5+at->extradata_size);
+
+ // Object type indication
+ bytestream2_put_byte(&pb, 0x40);
+
+ bytestream2_put_byte(&pb, 0x15); // flags (= Audiostream)
+
+ bytestream2_put_be24(&pb, 0); // Buffersize DB
+
+ bytestream2_put_be32(&pb, 0); // maxbitrate
+ bytestream2_put_be32(&pb, 0); // avgbitrate
+
+ // DecoderSpecific info descriptor
+ put_descr(&pb, 0x05, at->extradata_size);
+ bytestream2_put_buffer(&pb, at->extradata, at->extradata_size);
+ return extradata;
+ } else {
+ *cookie_size = at->extradata_size;
+ return at->extradata;
+ }
+}
+
+static av_cold int ffat_usable_extradata(AVCodecContext *avctx)
+{
+ ATDecodeContext *at = avctx->priv_data;
+ return at->extradata_size &&
+ (avctx->codec_id == AV_CODEC_ID_ALAC ||
+ avctx->codec_id == AV_CODEC_ID_QDM2 ||
+ avctx->codec_id == AV_CODEC_ID_QDMC ||
+ avctx->codec_id == AV_CODEC_ID_AAC);
+}
+
+static int ffat_set_extradata(AVCodecContext *avctx)
+{
+ ATDecodeContext *at = avctx->priv_data;
+ if (ffat_usable_extradata(avctx)) {
+ OSStatus status;
+ UInt32 cookie_size;
+ uint8_t *cookie = ffat_get_magic_cookie(avctx, &cookie_size);
+ if (!cookie)
+ return AVERROR(ENOMEM);
+
+ status = AudioConverterSetProperty(at->converter,
+ kAudioConverterDecompressionMagicCookie,
+ cookie_size, cookie);
+ if (status != 0)
+ av_log(avctx, AV_LOG_WARNING, "AudioToolbox cookie error: %i\n", (int)status);
+
+ if (cookie != at->extradata)
+ av_free(cookie);
+ }
+ return 0;
+}
+
+static av_cold int ffat_create_decoder(AVCodecContext *avctx, AVPacket *pkt)
+{
+ ATDecodeContext *at = avctx->priv_data;
+ OSStatus status;
+ int i;
+
+ enum AVSampleFormat sample_fmt = (avctx->bits_per_raw_sample == 32) ?
+ AV_SAMPLE_FMT_S32 : AV_SAMPLE_FMT_S16;
+
+ AudioStreamBasicDescription in_format = {
+ .mFormatID = ffat_get_format_id(avctx->codec_id, avctx->profile),
+ .mBytesPerPacket = (avctx->codec_id == AV_CODEC_ID_ILBC) ? avctx->block_align : 0,
+ };
+ AudioStreamBasicDescription out_format = {
+ .mFormatID = kAudioFormatLinearPCM,
+ .mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked,
+ .mFramesPerPacket = 1,
+ .mBitsPerChannel = av_get_bytes_per_sample(sample_fmt) * 8,
+ };
+
+ avctx->sample_fmt = sample_fmt;
+
+ if (ffat_usable_extradata(avctx)) {
+ UInt32 format_size = sizeof(in_format);
+ UInt32 cookie_size;
+ uint8_t *cookie = ffat_get_magic_cookie(avctx, &cookie_size);
+ if (!cookie)
+ return AVERROR(ENOMEM);
+ status = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
+ cookie_size, cookie, &format_size, &in_format);
+ if (cookie != at->extradata)
+ av_free(cookie);
+ if (status != 0) {
+ av_log(avctx, AV_LOG_ERROR, "AudioToolbox header-parse error: %i\n", (int)status);
+ return AVERROR_UNKNOWN;
+ }
+#if CONFIG_MP1_AT_DECODER || CONFIG_MP2_AT_DECODER || CONFIG_MP3_AT_DECODER
+ } else if (pkt && pkt->size >= 4 &&
+ (avctx->codec_id == AV_CODEC_ID_MP1 ||
+ avctx->codec_id == AV_CODEC_ID_MP2 ||
+ avctx->codec_id == AV_CODEC_ID_MP3)) {
+ enum AVCodecID codec_id;
+ int bit_rate;
+ if (ff_mpa_decode_header(AV_RB32(pkt->data), &avctx->sample_rate,
+ &in_format.mChannelsPerFrame, &avctx->frame_size,
+ &bit_rate, &codec_id) < 0)
+ return AVERROR_INVALIDDATA;
+ avctx->bit_rate = bit_rate;
+ in_format.mSampleRate = avctx->sample_rate;
+#endif
+#if CONFIG_AC3_AT_DECODER || CONFIG_EAC3_AT_DECODER
+ } else if (pkt && pkt->size >= 7 &&
+ (avctx->codec_id == AV_CODEC_ID_AC3 ||
+ avctx->codec_id == AV_CODEC_ID_EAC3)) {
+ AC3HeaderInfo hdr, *phdr = &hdr;
+ GetBitContext gbc;
+ init_get_bits(&gbc, pkt->data, pkt->size);
+ if (avpriv_ac3_parse_header(&gbc, &phdr) < 0)
+ return AVERROR_INVALIDDATA;
+ in_format.mSampleRate = hdr.sample_rate;
+ in_format.mChannelsPerFrame = hdr.channels;
+ avctx->frame_size = hdr.num_blocks * 256;
+ avctx->bit_rate = hdr.bit_rate;
+#endif
+ } else {
+ in_format.mSampleRate = avctx->sample_rate ? avctx->sample_rate : 44100;
+ in_format.mChannelsPerFrame = avctx->channels ? avctx->channels : 1;
+ }
+
+ avctx->sample_rate = out_format.mSampleRate = in_format.mSampleRate;
+ avctx->channels = out_format.mChannelsPerFrame = in_format.mChannelsPerFrame;
+
+ if (avctx->codec_id == AV_CODEC_ID_ADPCM_IMA_QT)
+ in_format.mFramesPerPacket = 64;
+
+ status = AudioConverterNew(&in_format, &out_format, &at->converter);
+
+ if (status != 0) {
+ av_log(avctx, AV_LOG_ERROR, "AudioToolbox init error: %i\n", (int)status);
+ return AVERROR_UNKNOWN;
+ }
+
+ if ((status = ffat_set_extradata(avctx)) < 0)
+ return status;
+
+ for (i = 0; i < (sizeof(at->channel_map) / sizeof(at->channel_map[0])); i++)
+ at->channel_map[i] = i;
+
+ ffat_update_ctx(avctx);
+
+ if(!(at->decoded_data = av_malloc(av_get_bytes_per_sample(avctx->sample_fmt)
+ * avctx->frame_size * avctx->channels)))
+ return AVERROR(ENOMEM);
+
+ at->last_pts = AV_NOPTS_VALUE;
+
+ return 0;
+}
+
+static av_cold int ffat_init_decoder(AVCodecContext *avctx)
+{
+ ATDecodeContext *at = avctx->priv_data;
+ at->extradata = avctx->extradata;
+ at->extradata_size = avctx->extradata_size;
+
+ if ((avctx->channels && avctx->sample_rate) || ffat_usable_extradata(avctx))
+ return ffat_create_decoder(avctx, NULL);
+ else
+ return 0;
+}
+
+static OSStatus ffat_decode_callback(AudioConverterRef converter, UInt32 *nb_packets,
+ AudioBufferList *data,
+ AudioStreamPacketDescription **packets,
+ void *inctx)
+{
+ AVCodecContext *avctx = inctx;
+ ATDecodeContext *at = avctx->priv_data;
+
+ if (at->eof) {
+ *nb_packets = 0;
+ if (packets) {
+ *packets = &at->pkt_desc;
+ at->pkt_desc.mDataByteSize = 0;
+ }
+ return 0;
+ }
+
+ av_packet_unref(&at->in_pkt);
+ av_packet_move_ref(&at->in_pkt, &at->new_in_pkt);
+
+ if (!at->in_pkt.data) {
+ *nb_packets = 0;
+ return 1;
+ }
+
+ data->mNumberBuffers = 1;
+ data->mBuffers[0].mNumberChannels = 0;
+ data->mBuffers[0].mDataByteSize = at->in_pkt.size;
+ data->mBuffers[0].mData = at->in_pkt.data;
+ *nb_packets = 1;
+
+ if (packets) {
+ *packets = &at->pkt_desc;
+ at->pkt_desc.mDataByteSize = at->in_pkt.size;
+ }
+
+ return 0;
+}
+
+#define COPY_SAMPLES(type) \
+ type *in_ptr = (type*)at->decoded_data; \
+ type *end_ptr = in_ptr + frame->nb_samples * avctx->channels; \
+ type *out_ptr = (type*)frame->data[0]; \
+ for (; in_ptr < end_ptr; in_ptr += avctx->channels, out_ptr += avctx->channels) { \
+ int c; \
+ for (c = 0; c < avctx->channels; c++) \
+ out_ptr[c] = in_ptr[at->channel_map[c]]; \
+ }
+
+static void ffat_copy_samples(AVCodecContext *avctx, AVFrame *frame)
+{
+ ATDecodeContext *at = avctx->priv_data;
+ if (avctx->sample_fmt == AV_SAMPLE_FMT_S32) {
+ COPY_SAMPLES(int32_t);
+ } else {
+ COPY_SAMPLES(int16_t);
+ }
+}
+
+static int ffat_decode(AVCodecContext *avctx, void *data,
+ int *got_frame_ptr, AVPacket *avpkt)
+{
+ ATDecodeContext *at = avctx->priv_data;
+ AVFrame *frame = data;
+ int pkt_size = avpkt->size;
+ AVPacket filtered_packet = {0};
+ OSStatus ret;
+ AudioBufferList out_buffers;
+
+ if (avctx->codec_id == AV_CODEC_ID_AAC && avpkt->size > 2 &&
+ (AV_RB16(avpkt->data) & 0xfff0) == 0xfff0) {
+ AVPacket filter_pkt = {0};
+ if (!at->bsf) {
+ const AVBitStreamFilter *bsf = av_bsf_get_by_name("aac_adtstoasc");
+ if(!bsf)
+ return AVERROR_BSF_NOT_FOUND;
+ if ((ret = av_bsf_alloc(bsf, &at->bsf)))
+ return ret;
+ if (((ret = avcodec_parameters_from_context(at->bsf->par_in, avctx)) < 0) ||
+ ((ret = av_bsf_init(at->bsf)) < 0)) {
+ av_bsf_free(&at->bsf);
+ return ret;
+ }
+ }
+
+ if ((ret = av_packet_ref(&filter_pkt, avpkt)) < 0)
+ return ret;
+
+ if ((ret = av_bsf_send_packet(at->bsf, &filter_pkt)) < 0) {
+ av_packet_unref(&filter_pkt);
+ return ret;
+ }
+
+ if ((ret = av_bsf_receive_packet(at->bsf, &filtered_packet)) < 0)
+ return ret;
+
+ at->extradata = at->bsf->par_out->extradata;
+ at->extradata_size = at->bsf->par_out->extradata_size;
+
+ avpkt = &filtered_packet;
+ }
+
+ if (!at->converter) {
+ if ((ret = ffat_create_decoder(avctx, avpkt)) < 0) {
+ av_packet_unref(&filtered_packet);
+ return ret;
+ }
+ }
+
+ out_buffers = (AudioBufferList){
+ .mNumberBuffers = 1,
+ .mBuffers = {
+ {
+ .mNumberChannels = avctx->channels,
+ .mDataByteSize = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->frame_size
+ * avctx->channels,
+ }
+ }
+ };
+
+ av_packet_unref(&at->new_in_pkt);
+
+ if (avpkt->size) {
+ if (filtered_packet.data) {
+ at->new_in_pkt = filtered_packet;
+ } else if ((ret = av_packet_ref(&at->new_in_pkt, avpkt)) < 0) {
+ return ret;
+ }
+ } else {
+ at->eof = 1;
+ }
+
+ frame->sample_rate = avctx->sample_rate;
+
+ frame->nb_samples = avctx->frame_size;
+
+ out_buffers.mBuffers[0].mData = at->decoded_data;
+
+ ret = AudioConverterFillComplexBuffer(at->converter, ffat_decode_callback, avctx,
+ &frame->nb_samples, &out_buffers, NULL);
+ if ((!ret || ret == 1) && frame->nb_samples) {
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+ ffat_copy_samples(avctx, frame);
+ *got_frame_ptr = 1;
+ if (at->last_pts != AV_NOPTS_VALUE) {
++ frame->pts = at->last_pts;
++#if FF_API_PKT_PTS
++FF_DISABLE_DEPRECATION_WARNINGS
+ frame->pkt_pts = at->last_pts;
++FF_ENABLE_DEPRECATION_WARNINGS
++#endif
+ at->last_pts = avpkt->pts;
+ }
+ } else if (ret && ret != 1) {
+ av_log(avctx, AV_LOG_WARNING, "Decode error: %i\n", ret);
+ } else {
+ at->last_pts = avpkt->pts;
+ }
+
+ return pkt_size;
+}
+
+static av_cold void ffat_decode_flush(AVCodecContext *avctx)
+{
+ ATDecodeContext *at = avctx->priv_data;
+ AudioConverterReset(at->converter);
+ av_packet_unref(&at->new_in_pkt);
+ av_packet_unref(&at->in_pkt);
+}
+
+static av_cold int ffat_close_decoder(AVCodecContext *avctx)
+{
+ ATDecodeContext *at = avctx->priv_data;
+ AudioConverterDispose(at->converter);
+ av_bsf_free(&at->bsf);
+ av_packet_unref(&at->new_in_pkt);
+ av_packet_unref(&at->in_pkt);
+ av_free(at->decoded_data);
+ return 0;
+}
+
+#define FFAT_DEC_CLASS(NAME) \
+ static const AVClass ffat_##NAME##_dec_class = { \
+ .class_name = "at_" #NAME "_dec", \
+ .version = LIBAVUTIL_VERSION_INT, \
+ };
+
+#define FFAT_DEC(NAME, ID) \
+ FFAT_DEC_CLASS(NAME) \
+ AVCodec ff_##NAME##_at_decoder = { \
+ .name = #NAME "_at", \
+ .long_name = NULL_IF_CONFIG_SMALL(#NAME " (AudioToolbox)"), \
+ .type = AVMEDIA_TYPE_AUDIO, \
+ .id = ID, \
+ .priv_data_size = sizeof(ATDecodeContext), \
+ .init = ffat_init_decoder, \
+ .close = ffat_close_decoder, \
+ .decode = ffat_decode, \
+ .flush = ffat_decode_flush, \
+ .priv_class = &ffat_##NAME##_dec_class, \
+ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, \
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, \
+ };
+
+FFAT_DEC(aac, AV_CODEC_ID_AAC)
+FFAT_DEC(ac3, AV_CODEC_ID_AC3)
+FFAT_DEC(adpcm_ima_qt, AV_CODEC_ID_ADPCM_IMA_QT)
+FFAT_DEC(alac, AV_CODEC_ID_ALAC)
+FFAT_DEC(amr_nb, AV_CODEC_ID_AMR_NB)
+FFAT_DEC(eac3, AV_CODEC_ID_EAC3)
+FFAT_DEC(gsm_ms, AV_CODEC_ID_GSM_MS)
+FFAT_DEC(ilbc, AV_CODEC_ID_ILBC)
+FFAT_DEC(mp1, AV_CODEC_ID_MP1)
+FFAT_DEC(mp2, AV_CODEC_ID_MP2)
+FFAT_DEC(mp3, AV_CODEC_ID_MP3)
+FFAT_DEC(pcm_alaw, AV_CODEC_ID_PCM_ALAW)
+FFAT_DEC(pcm_mulaw, AV_CODEC_ID_PCM_MULAW)
+FFAT_DEC(qdmc, AV_CODEC_ID_QDMC)
+FFAT_DEC(qdm2, AV_CODEC_ID_QDM2)
diff --cc libavcodec/crystalhd.c
index 59b14b9,0000000..0f5101a
mode 100644,000000..100644
--- a/libavcodec/crystalhd.c
+++ b/libavcodec/crystalhd.c
@@@ -1,1269 -1,0 +1,1274 @@@
+/*
+ * - CrystalHD decoder module -
+ *
+ * Copyright(C) 2010,2011 Philip Langdale <ffmpeg.philipl at overt.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * - Principles of Operation -
+ *
+ * The CrystalHD decoder operates at the bitstream level - which is an even
+ * higher level than the decoding hardware you typically see in modern GPUs.
+ * This means it has a very simple interface, in principle. You feed demuxed
+ * packets in one end and get decoded picture (fields/frames) out the other.
+ *
+ * Of course, nothing is ever that simple. Due, at the very least, to b-frame
+ * dependencies in the supported formats, the hardware has a delay between
+ * when a packet goes in, and when a picture comes out. Furthermore, this delay
+ * is not just a function of time, but also one of the dependency on additional
+ * frames being fed into the decoder to satisfy the b-frame dependencies.
+ *
+ * As such, a pipeline will build up that is roughly equivalent to the required
+ * DPB for the file being played. If that was all it took, things would still
+ * be simple - so, of course, it isn't.
+ *
+ * The hardware has a way of indicating that a picture is ready to be copied out,
+ * but this is unreliable - and sometimes the attempt will still fail so, based
+ * on testing, the code will wait until 3 pictures are ready before starting
+ * to copy out - and this has the effect of extending the pipeline.
+ *
+ * Finally, while it is tempting to say that once the decoder starts outputting
+ * frames, the software should never fail to return a frame from a decode(),
+ * this is a hard assertion to make, because the stream may switch between
+ * differently encoded content (number of b-frames, interlacing, etc) which
+ * might require a longer pipeline than before. If that happened, you could
+ * deadlock trying to retrieve a frame that can't be decoded without feeding
+ * in additional packets.
+ *
+ * As such, the code will return in the event that a picture cannot be copied
+ * out, leading to an increase in the length of the pipeline. This in turn,
+ * means we have to be sensitive to the time it takes to decode a picture;
+ * We do not want to give up just because the hardware needed a little more
+ * time to prepare the picture! For this reason, there are delays included
+ * in the decode() path that ensure that, under normal conditions, the hardware
+ * will only fail to return a frame if it really needs additional packets to
+ * complete the decoding.
+ *
+ * Finally, to be explicit, we do not want the pipeline to grow without bound
+ * for two reasons: 1) The hardware can only buffer a finite number of packets,
+ * and 2) The client application may not be able to cope with arbitrarily long
+ * delays in the video path relative to the audio path. For example. MPlayer
+ * can only handle a 20 picture delay (although this is arbitrary, and needs
+ * to be extended to fully support the CrystalHD where the delay could be up
+ * to 32 pictures - consider PAFF H.264 content with 16 b-frames).
+ */
+
+/*****************************************************************************
+ * Includes
+ ****************************************************************************/
+
+#define _XOPEN_SOURCE 600
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <libcrystalhd/bc_dts_types.h>
+#include <libcrystalhd/bc_dts_defs.h>
+#include <libcrystalhd/libcrystalhd_if.h>
+
+#include "avcodec.h"
+#include "h264dec.h"
+#include "internal.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/** Timeout parameter passed to DtsProcOutput() in us */
+#define OUTPUT_PROC_TIMEOUT 50
+/** Step between fake timestamps passed to hardware in units of 100ns */
+#define TIMESTAMP_UNIT 100000
+/** Initial value in us of the wait in decode() */
+#define BASE_WAIT 10000
+/** Increment in us to adjust wait in decode() */
+#define WAIT_UNIT 1000
+
+
+/*****************************************************************************
+ * Module private data
+ ****************************************************************************/
+
+typedef enum {
+ RET_ERROR = -1,
+ RET_OK = 0,
+ RET_COPY_AGAIN = 1,
+ RET_SKIP_NEXT_COPY = 2,
+ RET_COPY_NEXT_FIELD = 3,
+} CopyRet;
+
+typedef struct OpaqueList {
+ struct OpaqueList *next;
+ uint64_t fake_timestamp;
+ uint64_t reordered_opaque;
+ uint8_t pic_type;
+} OpaqueList;
+
+typedef struct {
+ AVClass *av_class;
+ AVCodecContext *avctx;
+ AVFrame *pic;
+ HANDLE dev;
+
+ uint8_t *orig_extradata;
+ uint32_t orig_extradata_size;
+
+ AVBSFContext *bsfc;
+ AVCodecParserContext *parser;
+
+ uint8_t is_70012;
+ uint8_t *sps_pps_buf;
+ uint32_t sps_pps_size;
+ uint8_t is_nal;
+ uint8_t output_ready;
+ uint8_t need_second_field;
+ uint8_t skip_next_output;
+ uint64_t decode_wait;
+
+ uint64_t last_picture;
+
+ OpaqueList *head;
+ OpaqueList *tail;
+
+ /* Options */
+ uint32_t sWidth;
+ uint8_t bframe_bug;
+} CHDContext;
+
+static const AVOption options[] = {
+ { "crystalhd_downscale_width",
+ "Turn on downscaling to the specified width",
+ offsetof(CHDContext, sWidth),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT32_MAX,
+ AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM, },
+ { NULL, },
+};
+
+
+/*****************************************************************************
+ * Helper functions
+ ****************************************************************************/
+
+static inline BC_MEDIA_SUBTYPE id2subtype(CHDContext *priv, enum AVCodecID id)
+{
+ switch (id) {
+ case AV_CODEC_ID_MPEG4:
+ return BC_MSUBTYPE_DIVX;
+ case AV_CODEC_ID_MSMPEG4V3:
+ return BC_MSUBTYPE_DIVX311;
+ case AV_CODEC_ID_MPEG2VIDEO:
+ return BC_MSUBTYPE_MPEG2VIDEO;
+ case AV_CODEC_ID_VC1:
+ return BC_MSUBTYPE_VC1;
+ case AV_CODEC_ID_WMV3:
+ return BC_MSUBTYPE_WMV3;
+ case AV_CODEC_ID_H264:
+ return priv->is_nal ? BC_MSUBTYPE_AVC1 : BC_MSUBTYPE_H264;
+ default:
+ return BC_MSUBTYPE_INVALID;
+ }
+}
+
+static inline void print_frame_info(CHDContext *priv, BC_DTS_PROC_OUT *output)
+{
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tYBuffSz: %u\n", output->YbuffSz);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tYBuffDoneSz: %u\n",
+ output->YBuffDoneSz);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tUVBuffDoneSz: %u\n",
+ output->UVBuffDoneSz);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tTimestamp: %"PRIu64"\n",
+ output->PicInfo.timeStamp);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tPicture Number: %u\n",
+ output->PicInfo.picture_number);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tWidth: %u\n",
+ output->PicInfo.width);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tHeight: %u\n",
+ output->PicInfo.height);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tChroma: 0x%03x\n",
+ output->PicInfo.chroma_format);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tPulldown: %u\n",
+ output->PicInfo.pulldown);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tFlags: 0x%08x\n",
+ output->PicInfo.flags);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tFrame Rate/Res: %u\n",
+ output->PicInfo.frame_rate);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tAspect Ratio: %u\n",
+ output->PicInfo.aspect_ratio);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tColor Primaries: %u\n",
+ output->PicInfo.colour_primaries);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tMetaData: %u\n",
+ output->PicInfo.picture_meta_payload);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tSession Number: %u\n",
+ output->PicInfo.sess_num);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tycom: %u\n",
+ output->PicInfo.ycom);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tCustom Aspect: %u\n",
+ output->PicInfo.custom_aspect_ratio_width_height);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tFrames to Drop: %u\n",
+ output->PicInfo.n_drop);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tH264 Valid Fields: 0x%08x\n",
+ output->PicInfo.other.h264.valid);
+}
+
+
+/*****************************************************************************
+ * OpaqueList functions
+ ****************************************************************************/
+
+static uint64_t opaque_list_push(CHDContext *priv, uint64_t reordered_opaque,
+ uint8_t pic_type)
+{
+ OpaqueList *newNode = av_mallocz(sizeof (OpaqueList));
+ if (!newNode) {
+ av_log(priv->avctx, AV_LOG_ERROR,
+ "Unable to allocate new node in OpaqueList.\n");
+ return 0;
+ }
+ if (!priv->head) {
+ newNode->fake_timestamp = TIMESTAMP_UNIT;
+ priv->head = newNode;
+ } else {
+ newNode->fake_timestamp = priv->tail->fake_timestamp + TIMESTAMP_UNIT;
+ priv->tail->next = newNode;
+ }
+ priv->tail = newNode;
+ newNode->reordered_opaque = reordered_opaque;
+ newNode->pic_type = pic_type;
+
+ return newNode->fake_timestamp;
+}
+
+/*
+ * The OpaqueList is built in decode order, while elements will be removed
+ * in presentation order. If frames are reordered, this means we must be
+ * able to remove elements that are not the first element.
+ *
+ * Returned node must be freed by caller.
+ */
+static OpaqueList *opaque_list_pop(CHDContext *priv, uint64_t fake_timestamp)
+{
+ OpaqueList *node = priv->head;
+
+ if (!priv->head) {
+ av_log(priv->avctx, AV_LOG_ERROR,
+ "CrystalHD: Attempted to query non-existent timestamps.\n");
+ return NULL;
+ }
+
+ /*
+ * The first element is special-cased because we have to manipulate
+ * the head pointer rather than the previous element in the list.
+ */
+ if (priv->head->fake_timestamp == fake_timestamp) {
+ priv->head = node->next;
+
+ if (!priv->head->next)
+ priv->tail = priv->head;
+
+ node->next = NULL;
+ return node;
+ }
+
+ /*
+ * The list is processed at arm's length so that we have the
+ * previous element available to rewrite its next pointer.
+ */
+ while (node->next) {
+ OpaqueList *current = node->next;
+ if (current->fake_timestamp == fake_timestamp) {
+ node->next = current->next;
+
+ if (!node->next)
+ priv->tail = node;
+
+ current->next = NULL;
+ return current;
+ } else {
+ node = current;
+ }
+ }
+
+ av_log(priv->avctx, AV_LOG_VERBOSE,
+ "CrystalHD: Couldn't match fake_timestamp.\n");
+ return NULL;
+}
+
+
+/*****************************************************************************
+ * Video decoder API function definitions
+ ****************************************************************************/
+
+static void flush(AVCodecContext *avctx)
+{
+ CHDContext *priv = avctx->priv_data;
+
+ avctx->has_b_frames = 0;
+ priv->last_picture = -1;
+ priv->output_ready = 0;
+ priv->need_second_field = 0;
+ priv->skip_next_output = 0;
+ priv->decode_wait = BASE_WAIT;
+
+ av_frame_unref (priv->pic);
+
+ /* Flush mode 4 flushes all software and hardware buffers. */
+ DtsFlushInput(priv->dev, 4);
+}
+
+
+static av_cold int uninit(AVCodecContext *avctx)
+{
+ CHDContext *priv = avctx->priv_data;
+ HANDLE device;
+
+ device = priv->dev;
+ DtsStopDecoder(device);
+ DtsCloseDecoder(device);
+ DtsDeviceClose(device);
+
+ /*
+ * Restore original extradata, so that if the decoder is
+ * reinitialised, the bitstream detection and filtering
+ * will work as expected.
+ */
+ if (priv->orig_extradata) {
+ av_free(avctx->extradata);
+ avctx->extradata = priv->orig_extradata;
+ avctx->extradata_size = priv->orig_extradata_size;
+ priv->orig_extradata = NULL;
+ priv->orig_extradata_size = 0;
+ }
+
+ av_parser_close(priv->parser);
+ if (priv->bsfc) {
+ av_bsf_free(&priv->bsfc);
+ }
+
+ av_freep(&priv->sps_pps_buf);
+
+ av_frame_free (&priv->pic);
+
+ if (priv->head) {
+ OpaqueList *node = priv->head;
+ while (node) {
+ OpaqueList *next = node->next;
+ av_free(node);
+ node = next;
+ }
+ }
+
+ return 0;
+}
+
+
+static av_cold int init(AVCodecContext *avctx)
+{
+ CHDContext* priv;
+ BC_STATUS ret;
+ BC_INFO_CRYSTAL version;
+ BC_INPUT_FORMAT format = {
+ .FGTEnable = FALSE,
+ .Progressive = TRUE,
+ .OptFlags = 0x80000000 | vdecFrameRate59_94 | 0x40,
+ .width = avctx->width,
+ .height = avctx->height,
+ };
+
+ BC_MEDIA_SUBTYPE subtype;
+
+ uint32_t mode = DTS_PLAYBACK_MODE |
+ DTS_LOAD_FILE_PLAY_FW |
+ DTS_SKIP_TX_CHK_CPB |
+ DTS_PLAYBACK_DROP_RPT_MODE |
+ DTS_SINGLE_THREADED_MODE |
+ DTS_DFLT_RESOLUTION(vdecRESOLUTION_1080p23_976);
+
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD Init for %s\n",
+ avctx->codec->name);
+
+ avctx->pix_fmt = AV_PIX_FMT_YUYV422;
+
+ /* Initialize the library */
+ priv = avctx->priv_data;
+ priv->avctx = avctx;
+ priv->is_nal = avctx->extradata_size > 0 && *(avctx->extradata) == 1;
+ priv->last_picture = -1;
+ priv->decode_wait = BASE_WAIT;
+ priv->pic = av_frame_alloc();
+
+ subtype = id2subtype(priv, avctx->codec->id);
+ switch (subtype) {
+ case BC_MSUBTYPE_AVC1:
+ {
+ const AVBitStreamFilter *bsf;
+ int avret;
+
+ bsf = av_bsf_get_by_name("h264_mp4toannexb");
+ if (!bsf) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Cannot open the h264_mp4toannexb BSF!\n");
+ return AVERROR_BSF_NOT_FOUND;
+ }
+ avret = av_bsf_alloc(bsf, &priv->bsfc);
+ if (avret != 0) {
+ return AVERROR(ENOMEM);
+ }
+ avret = avcodec_parameters_from_context(priv->bsfc->par_in, avctx);
+ if (avret != 0) {
+ return AVERROR(ENOMEM);
+ }
+ avret = av_bsf_init(priv->bsfc);
+ if (avret != 0) {
+ return AVERROR(ENOMEM);
+ }
+
+ format.metaDataSz = priv->bsfc->par_out->extradata_size;
+ format.pMetaData = av_malloc(format.metaDataSz + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!format.pMetaData) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Failed to allocate copy of extradata\n");
+ return AVERROR(ENOMEM);
+ }
+ memcpy(format.pMetaData, priv->bsfc->par_out->extradata, format.metaDataSz);
+
+ /* Back up the extradata so it can be restored at close time. */
+ priv->orig_extradata = avctx->extradata;
+ priv->orig_extradata_size = avctx->extradata_size;
+ avctx->extradata = format.pMetaData;
+ avctx->extradata_size = format.metaDataSz;
+ }
+ subtype = BC_MSUBTYPE_H264;
+ format.startCodeSz = 4;
+ break;
+ case BC_MSUBTYPE_H264:
+ format.startCodeSz = 4;
+ // Fall-through
+ case BC_MSUBTYPE_VC1:
+ case BC_MSUBTYPE_WVC1:
+ case BC_MSUBTYPE_WMV3:
+ case BC_MSUBTYPE_WMVA:
+ case BC_MSUBTYPE_MPEG2VIDEO:
+ case BC_MSUBTYPE_DIVX:
+ case BC_MSUBTYPE_DIVX311:
+ format.pMetaData = avctx->extradata;
+ format.metaDataSz = avctx->extradata_size;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: Unknown codec name\n");
+ return AVERROR(EINVAL);
+ }
+ format.mSubtype = subtype;
+
+ if (priv->sWidth) {
+ format.bEnableScaling = 1;
+ format.ScalingParams.sWidth = priv->sWidth;
+ }
+
+ /* Get a decoder instance */
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: starting up\n");
+ // Initialize the Link and Decoder devices
+ ret = DtsDeviceOpen(&priv->dev, mode);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: DtsDeviceOpen failed\n");
+ goto fail;
+ }
+
+ ret = DtsCrystalHDVersion(priv->dev, &version);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_VERBOSE,
+ "CrystalHD: DtsCrystalHDVersion failed\n");
+ goto fail;
+ }
+ priv->is_70012 = version.device == 0;
+
+ if (priv->is_70012 &&
+ (subtype == BC_MSUBTYPE_DIVX || subtype == BC_MSUBTYPE_DIVX311)) {
+ av_log(avctx, AV_LOG_VERBOSE,
+ "CrystalHD: BCM70012 doesn't support MPEG4-ASP/DivX/Xvid\n");
+ goto fail;
+ }
+
+ ret = DtsSetInputFormat(priv->dev, &format);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: SetInputFormat failed\n");
+ goto fail;
+ }
+
+ ret = DtsOpenDecoder(priv->dev, BC_STREAM_TYPE_ES);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsOpenDecoder failed\n");
+ goto fail;
+ }
+
+ ret = DtsSetColorSpace(priv->dev, OUTPUT_MODE422_YUY2);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsSetColorSpace failed\n");
+ goto fail;
+ }
+ ret = DtsStartDecoder(priv->dev);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsStartDecoder failed\n");
+ goto fail;
+ }
+ ret = DtsStartCapture(priv->dev);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsStartCapture failed\n");
+ goto fail;
+ }
+
+ if (avctx->codec->id == AV_CODEC_ID_H264) {
+ priv->parser = av_parser_init(avctx->codec->id);
+ if (!priv->parser)
+ av_log(avctx, AV_LOG_WARNING,
+ "Cannot open the h.264 parser! Interlaced h.264 content "
+ "will not be detected reliably.\n");
+ priv->parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
+ }
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Init complete.\n");
+
+ return 0;
+
+ fail:
+ uninit(avctx);
+ return -1;
+}
+
+
+static inline CopyRet copy_frame(AVCodecContext *avctx,
+ BC_DTS_PROC_OUT *output,
+ void *data, int *got_frame)
+{
+ BC_STATUS ret;
+ BC_DTS_STATUS decoder_status = { 0, };
+ uint8_t trust_interlaced;
+ uint8_t interlaced;
+
+ CHDContext *priv = avctx->priv_data;
+ int64_t pkt_pts = AV_NOPTS_VALUE;
+ uint8_t pic_type = 0;
+
+ uint8_t bottom_field = (output->PicInfo.flags & VDEC_FLAG_BOTTOMFIELD) ==
+ VDEC_FLAG_BOTTOMFIELD;
+ uint8_t bottom_first = !!(output->PicInfo.flags & VDEC_FLAG_BOTTOM_FIRST);
+
+ int width = output->PicInfo.width;
+ int height = output->PicInfo.height;
+ int bwidth;
+ uint8_t *src = output->Ybuff;
+ int sStride;
+ uint8_t *dst;
+ int dStride;
+
+ if (output->PicInfo.timeStamp != 0) {
+ OpaqueList *node = opaque_list_pop(priv, output->PicInfo.timeStamp);
+ if (node) {
+ pkt_pts = node->reordered_opaque;
+ pic_type = node->pic_type;
+ av_free(node);
+ } else {
+ /*
+ * We will encounter a situation where a timestamp cannot be
+ * popped if a second field is being returned. In this case,
+ * each field has the same timestamp and the first one will
+ * cause it to be popped. To keep subsequent calculations
+ * simple, pic_type should be set a FIELD value - doesn't
+ * matter which, but I chose BOTTOM.
+ */
+ pic_type = PICT_BOTTOM_FIELD;
+ }
+ av_log(avctx, AV_LOG_VERBOSE, "output \"pts\": %"PRIu64"\n",
+ output->PicInfo.timeStamp);
+ av_log(avctx, AV_LOG_VERBOSE, "output picture type %d\n",
+ pic_type);
+ }
+
+ ret = DtsGetDriverStatus(priv->dev, &decoder_status);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR,
+ "CrystalHD: GetDriverStatus failed: %u\n", ret);
+ return RET_ERROR;
+ }
+
+ /*
+ * For most content, we can trust the interlaced flag returned
+ * by the hardware, but sometimes we can't. These are the
+ * conditions under which we can trust the flag:
+ *
+ * 1) It's not h.264 content
+ * 2) The UNKNOWN_SRC flag is not set
+ * 3) We know we're expecting a second field
+ * 4) The hardware reports this picture and the next picture
+ * have the same picture number.
+ *
+ * Note that there can still be interlaced content that will
+ * fail this check, if the hardware hasn't decoded the next
+ * picture or if there is a corruption in the stream. (In either
+ * case a 0 will be returned for the next picture number)
+ */
+ trust_interlaced = avctx->codec->id != AV_CODEC_ID_H264 ||
+ !(output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) ||
+ priv->need_second_field ||
+ (decoder_status.picNumFlags & ~0x40000000) ==
+ output->PicInfo.picture_number;
+
+ /*
+ * If we got a false negative for trust_interlaced on the first field,
+ * we will realise our mistake here when we see that the picture number is that
+ * of the previous picture. We cannot recover the frame and should discard the
+ * second field to keep the correct number of output frames.
+ */
+ if (output->PicInfo.picture_number == priv->last_picture && !priv->need_second_field) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Incorrectly guessed progressive frame. Discarding second field\n");
+ /* Returning without providing a picture. */
+ return RET_OK;
+ }
+
+ interlaced = (output->PicInfo.flags & VDEC_FLAG_INTERLACED_SRC) &&
+ trust_interlaced;
+
+ if (!trust_interlaced && (decoder_status.picNumFlags & ~0x40000000) == 0) {
+ av_log(avctx, AV_LOG_VERBOSE,
+ "Next picture number unknown. Assuming progressive frame.\n");
+ }
+
+ av_log(avctx, AV_LOG_VERBOSE, "Interlaced state: %d | trust_interlaced %d\n",
+ interlaced, trust_interlaced);
+
+ if (priv->pic->data[0] && !priv->need_second_field)
+ av_frame_unref(priv->pic);
+
+ priv->need_second_field = interlaced && !priv->need_second_field;
+
+ if (!priv->pic->data[0]) {
+ if (ff_get_buffer(avctx, priv->pic, AV_GET_BUFFER_FLAG_REF) < 0)
+ return RET_ERROR;
+ }
+
+ bwidth = av_image_get_linesize(avctx->pix_fmt, width, 0);
+ if (priv->is_70012) {
+ int pStride;
+
+ if (width <= 720)
+ pStride = 720;
+ else if (width <= 1280)
+ pStride = 1280;
+ else pStride = 1920;
+ sStride = av_image_get_linesize(avctx->pix_fmt, pStride, 0);
+ } else {
+ sStride = bwidth;
+ }
+
+ dStride = priv->pic->linesize[0];
+ dst = priv->pic->data[0];
+
+ av_log(priv->avctx, AV_LOG_VERBOSE, "CrystalHD: Copying out frame\n");
+
+ if (interlaced) {
+ int dY = 0;
+ int sY = 0;
+
+ height /= 2;
+ if (bottom_field) {
+ av_log(priv->avctx, AV_LOG_VERBOSE, "Interlaced: bottom field\n");
+ dY = 1;
+ } else {
+ av_log(priv->avctx, AV_LOG_VERBOSE, "Interlaced: top field\n");
+ dY = 0;
+ }
+
+ for (sY = 0; sY < height; dY++, sY++) {
+ memcpy(&(dst[dY * dStride]), &(src[sY * sStride]), bwidth);
+ dY++;
+ }
+ } else {
+ av_image_copy_plane(dst, dStride, src, sStride, bwidth, height);
+ }
+
+ priv->pic->interlaced_frame = interlaced;
+ if (interlaced)
+ priv->pic->top_field_first = !bottom_first;
+
++ priv->pic->pts = pkt_pts;
++#if FF_API_PKT_PTS
++FF_DISABLE_DEPRECATION_WARNINGS
+ priv->pic->pkt_pts = pkt_pts;
++FF_ENABLE_DEPRECATION_WARNINGS
++#endif
+
+ if (!priv->need_second_field) {
+ *got_frame = 1;
+ if ((ret = av_frame_ref(data, priv->pic)) < 0) {
+ return ret;
+ }
+ }
+
+ /*
+ * Two types of PAFF content have been observed. One form causes the
+ * hardware to return a field pair and the other individual fields,
+ * even though the input is always individual fields. We must skip
+ * copying on the next decode() call to maintain pipeline length in
+ * the first case.
+ */
+ if (!interlaced && (output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) &&
+ (pic_type == PICT_TOP_FIELD || pic_type == PICT_BOTTOM_FIELD)) {
+ av_log(priv->avctx, AV_LOG_VERBOSE, "Fieldpair from two packets.\n");
+ return RET_SKIP_NEXT_COPY;
+ }
+
+ /*
+ * The logic here is purely based on empirical testing with samples.
+ * If we need a second field, it could come from a second input packet,
+ * or it could come from the same field-pair input packet at the current
+ * field. In the first case, we should return and wait for the next time
+ * round to get the second field, while in the second case, we should
+ * ask the decoder for it immediately.
+ *
+ * Testing has shown that we are dealing with the fieldpair -> two fields
+ * case if the VDEC_FLAG_UNKNOWN_SRC is not set or if the input picture
+ * type was PICT_FRAME (in this second case, the flag might still be set)
+ */
+ return priv->need_second_field &&
+ (!(output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) ||
+ pic_type == PICT_FRAME) ?
+ RET_COPY_NEXT_FIELD : RET_OK;
+}
+
+
+static inline CopyRet receive_frame(AVCodecContext *avctx,
+ void *data, int *got_frame)
+{
+ BC_STATUS ret;
+ BC_DTS_PROC_OUT output = {
+ .PicInfo.width = avctx->width,
+ .PicInfo.height = avctx->height,
+ };
+ CHDContext *priv = avctx->priv_data;
+ HANDLE dev = priv->dev;
+
+ *got_frame = 0;
+
+ // Request decoded data from the driver
+ ret = DtsProcOutputNoCopy(dev, OUTPUT_PROC_TIMEOUT, &output);
+ if (ret == BC_STS_FMT_CHANGE) {
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Initial format change\n");
+ avctx->width = output.PicInfo.width;
+ avctx->height = output.PicInfo.height;
+ switch ( output.PicInfo.aspect_ratio ) {
+ case vdecAspectRatioSquare:
+ avctx->sample_aspect_ratio = (AVRational) { 1, 1};
+ break;
+ case vdecAspectRatio12_11:
+ avctx->sample_aspect_ratio = (AVRational) { 12, 11};
+ break;
+ case vdecAspectRatio10_11:
+ avctx->sample_aspect_ratio = (AVRational) { 10, 11};
+ break;
+ case vdecAspectRatio16_11:
+ avctx->sample_aspect_ratio = (AVRational) { 16, 11};
+ break;
+ case vdecAspectRatio40_33:
+ avctx->sample_aspect_ratio = (AVRational) { 40, 33};
+ break;
+ case vdecAspectRatio24_11:
+ avctx->sample_aspect_ratio = (AVRational) { 24, 11};
+ break;
+ case vdecAspectRatio20_11:
+ avctx->sample_aspect_ratio = (AVRational) { 20, 11};
+ break;
+ case vdecAspectRatio32_11:
+ avctx->sample_aspect_ratio = (AVRational) { 32, 11};
+ break;
+ case vdecAspectRatio80_33:
+ avctx->sample_aspect_ratio = (AVRational) { 80, 33};
+ break;
+ case vdecAspectRatio18_11:
+ avctx->sample_aspect_ratio = (AVRational) { 18, 11};
+ break;
+ case vdecAspectRatio15_11:
+ avctx->sample_aspect_ratio = (AVRational) { 15, 11};
+ break;
+ case vdecAspectRatio64_33:
+ avctx->sample_aspect_ratio = (AVRational) { 64, 33};
+ break;
+ case vdecAspectRatio160_99:
+ avctx->sample_aspect_ratio = (AVRational) {160, 99};
+ break;
+ case vdecAspectRatio4_3:
+ avctx->sample_aspect_ratio = (AVRational) { 4, 3};
+ break;
+ case vdecAspectRatio16_9:
+ avctx->sample_aspect_ratio = (AVRational) { 16, 9};
+ break;
+ case vdecAspectRatio221_1:
+ avctx->sample_aspect_ratio = (AVRational) {221, 1};
+ break;
+ }
+ return RET_COPY_AGAIN;
+ } else if (ret == BC_STS_SUCCESS) {
+ int copy_ret = -1;
+ if (output.PoutFlags & BC_POUT_FLAGS_PIB_VALID) {
+ if (priv->last_picture == -1) {
+ /*
+ * Init to one less, so that the incrementing code doesn't
+ * need to be special-cased.
+ */
+ priv->last_picture = output.PicInfo.picture_number - 1;
+ }
+
+ if (avctx->codec->id == AV_CODEC_ID_MPEG4 &&
+ output.PicInfo.timeStamp == 0 && priv->bframe_bug) {
+ av_log(avctx, AV_LOG_VERBOSE,
+ "CrystalHD: Not returning packed frame twice.\n");
+ priv->last_picture++;
+ DtsReleaseOutputBuffs(dev, NULL, FALSE);
+ return RET_COPY_AGAIN;
+ }
+
+ print_frame_info(priv, &output);
+
+ if (priv->last_picture + 1 < output.PicInfo.picture_number) {
+ av_log(avctx, AV_LOG_WARNING,
+ "CrystalHD: Picture Number discontinuity\n");
+ /*
+ * Have we lost frames? If so, we need to shrink the
+ * pipeline length appropriately.
+ *
+ * XXX: I have no idea what the semantics of this situation
+ * are so I don't even know if we've lost frames or which
+ * ones.
+ *
+ * In any case, only warn the first time.
+ */
+ priv->last_picture = output.PicInfo.picture_number - 1;
+ }
+
+ copy_ret = copy_frame(avctx, &output, data, got_frame);
+ if (*got_frame > 0) {
+ avctx->has_b_frames--;
+ priv->last_picture++;
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Pipeline length: %u\n",
+ avctx->has_b_frames);
+ }
+ } else {
+ /*
+ * An invalid frame has been consumed.
+ */
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput succeeded with "
+ "invalid PIB\n");
+ avctx->has_b_frames--;
+ copy_ret = RET_OK;
+ }
+ DtsReleaseOutputBuffs(dev, NULL, FALSE);
+
+ return copy_ret;
+ } else if (ret == BC_STS_BUSY) {
+ return RET_COPY_AGAIN;
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput failed %d\n", ret);
+ return RET_ERROR;
+ }
+}
+
+
+static int decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
+{
+ BC_STATUS ret;
+ BC_DTS_STATUS decoder_status = { 0, };
+ CopyRet rec_ret;
+ CHDContext *priv = avctx->priv_data;
+ HANDLE dev = priv->dev;
+ uint8_t *in_data = avpkt->data;
+ int len = avpkt->size;
+ int free_data = 0;
+ uint8_t pic_type = 0;
+
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: decode_frame\n");
+
+ if (avpkt->size == 7 && !priv->bframe_bug) {
+ /*
+ * The use of a drop frame triggers the bug
+ */
+ av_log(avctx, AV_LOG_INFO,
+ "CrystalHD: Enabling work-around for packed b-frame bug\n");
+ priv->bframe_bug = 1;
+ } else if (avpkt->size == 8 && priv->bframe_bug) {
+ /*
+ * Delay frames don't trigger the bug
+ */
+ av_log(avctx, AV_LOG_INFO,
+ "CrystalHD: Disabling work-around for packed b-frame bug\n");
+ priv->bframe_bug = 0;
+ }
+
+ if (len) {
+ int32_t tx_free = (int32_t)DtsTxFreeSize(dev);
+
+ if (priv->bsfc) {
+ int ret = 0;
+ AVPacket filter_packet = { 0 };
+ AVPacket filtered_packet = { 0 };
+
+ ret = av_packet_ref(&filter_packet, avpkt);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: mpv4toannexb filter "
+ "failed to ref input packet\n");
+ return ret;
+ }
+
+ ret = av_bsf_send_packet(priv->bsfc, &filter_packet);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: mpv4toannexb filter "
+ "failed to send input packet\n");
+ return ret;
+ }
+
+ ret = av_bsf_receive_packet(priv->bsfc, &filtered_packet);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: mpv4toannexb filter "
+ "failed to receive output packet\n");
+ return ret;
+ }
+
+ in_data = filtered_packet.data;
+ len = filtered_packet.size;
+
+ av_packet_unref(&filter_packet);
+ }
+
+ if (priv->parser) {
+ int ret = 0;
+
+ free_data = ret > 0;
+
+ if (ret >= 0) {
+ uint8_t *pout;
+ int psize;
+ int index;
+ H264Context *h = priv->parser->priv_data;
+
+ index = av_parser_parse2(priv->parser, avctx, &pout, &psize,
+ in_data, len, avctx->internal->pkt->pts,
+ avctx->internal->pkt->dts, 0);
+ if (index < 0) {
+ av_log(avctx, AV_LOG_WARNING,
+ "CrystalHD: Failed to parse h.264 packet to "
+ "detect interlacing.\n");
+ } else if (index != len) {
+ av_log(avctx, AV_LOG_WARNING,
+ "CrystalHD: Failed to parse h.264 packet "
+ "completely. Interlaced frames may be "
+ "incorrectly detected.\n");
+ } else {
+ av_log(avctx, AV_LOG_VERBOSE,
+ "CrystalHD: parser picture type %d\n",
+ h->picture_structure);
+ pic_type = h->picture_structure;
+ }
+ } else {
+ av_log(avctx, AV_LOG_WARNING,
+ "CrystalHD: mp4toannexb filter failed to filter "
+ "packet. Interlaced frames may be incorrectly "
+ "detected.\n");
+ }
+ }
+
+ if (len < tx_free - 1024) {
+ /*
+ * Despite being notionally opaque, either libcrystalhd or
+ * the hardware itself will mangle pts values that are too
+ * small or too large. The docs claim it should be in units
+ * of 100ns. Given that we're nominally dealing with a black
+ * box on both sides, any transform we do has no guarantee of
+ * avoiding mangling so we need to build a mapping to values
+ * we know will not be mangled.
+ */
+ uint64_t pts = opaque_list_push(priv, avctx->internal->pkt->pts, pic_type);
+ if (!pts) {
+ if (free_data) {
+ av_freep(&in_data);
+ }
+ return AVERROR(ENOMEM);
+ }
+ av_log(priv->avctx, AV_LOG_VERBOSE,
+ "input \"pts\": %"PRIu64"\n", pts);
+ ret = DtsProcInput(dev, in_data, len, pts, 0);
+ if (free_data) {
+ av_freep(&in_data);
+ }
+ if (ret == BC_STS_BUSY) {
+ av_log(avctx, AV_LOG_WARNING,
+ "CrystalHD: ProcInput returned busy\n");
+ usleep(BASE_WAIT);
+ return AVERROR(EBUSY);
+ } else if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR,
+ "CrystalHD: ProcInput failed: %u\n", ret);
+ return -1;
+ }
+ avctx->has_b_frames++;
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "CrystalHD: Input buffer full\n");
+ len = 0; // We didn't consume any bytes.
+ }
+ } else {
+ av_log(avctx, AV_LOG_INFO, "CrystalHD: No more input data\n");
+ }
+
+ if (priv->skip_next_output) {
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Skipping next output.\n");
+ priv->skip_next_output = 0;
+ avctx->has_b_frames--;
+ return len;
+ }
+
+ ret = DtsGetDriverStatus(dev, &decoder_status);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: GetDriverStatus failed\n");
+ return -1;
+ }
+
+ /*
+ * No frames ready. Don't try to extract.
+ *
+ * Empirical testing shows that ReadyListCount can be a damn lie,
+ * and ProcOut still fails when count > 0. The same testing showed
+ * that two more iterations were needed before ProcOutput would
+ * succeed.
+ */
+ if (priv->output_ready < 2) {
+ if (decoder_status.ReadyListCount != 0)
+ priv->output_ready++;
+ usleep(BASE_WAIT);
+ av_log(avctx, AV_LOG_INFO, "CrystalHD: Filling pipeline.\n");
+ return len;
+ } else if (decoder_status.ReadyListCount == 0) {
+ /*
+ * After the pipeline is established, if we encounter a lack of frames
+ * that probably means we're not giving the hardware enough time to
+ * decode them, so start increasing the wait time at the end of a
+ * decode call.
+ */
+ usleep(BASE_WAIT);
+ priv->decode_wait += WAIT_UNIT;
+ av_log(avctx, AV_LOG_INFO, "CrystalHD: No frames ready. Returning\n");
+ return len;
+ }
+
+ do {
+ rec_ret = receive_frame(avctx, data, got_frame);
+ if (rec_ret == RET_OK && *got_frame == 0) {
+ /*
+ * This case is for when the encoded fields are stored
+ * separately and we get a separate avpkt for each one. To keep
+ * the pipeline stable, we should return nothing and wait for
+ * the next time round to grab the second field.
+ * H.264 PAFF is an example of this.
+ */
+ av_log(avctx, AV_LOG_VERBOSE, "Returning after first field.\n");
+ avctx->has_b_frames--;
+ } else if (rec_ret == RET_COPY_NEXT_FIELD) {
+ /*
+ * This case is for when the encoded fields are stored in a
+ * single avpkt but the hardware returns then separately. Unless
+ * we grab the second field before returning, we'll slip another
+ * frame in the pipeline and if that happens a lot, we're sunk.
+ * So we have to get that second field now.
+ * Interlaced mpeg2 and vc1 are examples of this.
+ */
+ av_log(avctx, AV_LOG_VERBOSE, "Trying to get second field.\n");
+ while (1) {
+ usleep(priv->decode_wait);
+ ret = DtsGetDriverStatus(dev, &decoder_status);
+ if (ret == BC_STS_SUCCESS &&
+ decoder_status.ReadyListCount > 0) {
+ rec_ret = receive_frame(avctx, data, got_frame);
+ if ((rec_ret == RET_OK && *got_frame > 0) ||
+ rec_ret == RET_ERROR)
+ break;
+ }
+ }
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Got second field.\n");
+ } else if (rec_ret == RET_SKIP_NEXT_COPY) {
+ /*
+ * Two input packets got turned into a field pair. Gawd.
+ */
+ av_log(avctx, AV_LOG_VERBOSE,
+ "Don't output on next decode call.\n");
+ priv->skip_next_output = 1;
+ }
+ /*
+ * If rec_ret == RET_COPY_AGAIN, that means that either we just handled
+ * a FMT_CHANGE event and need to go around again for the actual frame,
+ * we got a busy status and need to try again, or we're dealing with
+ * packed b-frames, where the hardware strangely returns the packed
+ * p-frame twice. We choose to keep the second copy as it carries the
+ * valid pts.
+ */
+ } while (rec_ret == RET_COPY_AGAIN);
+ usleep(priv->decode_wait);
+ return len;
+}
+
+
+#if CONFIG_H264_CRYSTALHD_DECODER
+static AVClass h264_class = {
+ "h264_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_h264_crystalhd_decoder = {
+ .name = "h264_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &h264_class,
+};
+#endif
+
+#if CONFIG_MPEG2_CRYSTALHD_DECODER
+static AVClass mpeg2_class = {
+ "mpeg2_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_mpeg2_crystalhd_decoder = {
+ .name = "mpeg2_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 Video (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MPEG2VIDEO,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &mpeg2_class,
+};
+#endif
+
+#if CONFIG_MPEG4_CRYSTALHD_DECODER
+static AVClass mpeg4_class = {
+ "mpeg4_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_mpeg4_crystalhd_decoder = {
+ .name = "mpeg4_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 Part 2 (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MPEG4,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &mpeg4_class,
+};
+#endif
+
+#if CONFIG_MSMPEG4_CRYSTALHD_DECODER
+static AVClass msmpeg4_class = {
+ "msmpeg4_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_msmpeg4_crystalhd_decoder = {
+ .name = "msmpeg4_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 Part 2 Microsoft variant version 3 (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MSMPEG4V3,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_EXPERIMENTAL,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &msmpeg4_class,
+};
+#endif
+
+#if CONFIG_VC1_CRYSTALHD_DECODER
+static AVClass vc1_class = {
+ "vc1_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_vc1_crystalhd_decoder = {
+ .name = "vc1_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("SMPTE VC-1 (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_VC1,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &vc1_class,
+};
+#endif
+
+#if CONFIG_WMV3_CRYSTALHD_DECODER
+static AVClass wmv3_class = {
+ "wmv3_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_wmv3_crystalhd_decoder = {
+ .name = "wmv3_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_WMV3,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &wmv3_class,
+};
+#endif
diff --cc libavcodec/cuvid.c
index 56f349c,0000000..27a4c30
mode 100644,000000..100644
--- a/libavcodec/cuvid.c
+++ b/libavcodec/cuvid.c
@@@ -1,926 -1,0 +1,930 @@@
+/*
+ * Nvidia CUVID decoder
+ * Copyright (c) 2016 Timo Rothenpieler <timo at rothenpieler.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/buffer.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/hwcontext.h"
+#include "libavutil/hwcontext_cuda.h"
+#include "libavutil/fifo.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+
+#include "avcodec.h"
+#include "internal.h"
+
+#include "compat/cuda/nvcuvid.h"
+
+#define MAX_FRAME_COUNT 25
+
+typedef struct CuvidContext
+{
+ AVClass *avclass;
+
+ CUvideodecoder cudecoder;
+ CUvideoparser cuparser;
+
+ char *cu_gpu;
+
+ AVBufferRef *hwdevice;
+ AVBufferRef *hwframe;
+
+ AVBSFContext *bsf;
+
+ AVFifoBuffer *frame_queue;
+
+ int deint_mode;
+ int64_t prev_pts;
+
+ int internal_error;
+ int decoder_flushing;
+
+ cudaVideoCodec codec_type;
+ cudaVideoChromaFormat chroma_format;
+
+ CUVIDPARSERPARAMS cuparseinfo;
+ CUVIDEOFORMATEX cuparse_ext;
+} CuvidContext;
+
+typedef struct CuvidParsedFrame
+{
+ CUVIDPARSERDISPINFO dispinfo;
+ int second_field;
+ int is_deinterlacing;
+} CuvidParsedFrame;
+
+static int check_cu(AVCodecContext *avctx, CUresult err, const char *func)
+{
+ const char *err_name;
+ const char *err_string;
+
+ av_log(avctx, AV_LOG_TRACE, "Calling %s\n", func);
+
+ if (err == CUDA_SUCCESS)
+ return 0;
+
+ cuGetErrorName(err, &err_name);
+ cuGetErrorString(err, &err_string);
+
+ av_log(avctx, AV_LOG_ERROR, "%s failed", func);
+ if (err_name && err_string)
+ av_log(avctx, AV_LOG_ERROR, " -> %s: %s", err_name, err_string);
+ av_log(avctx, AV_LOG_ERROR, "\n");
+
+ return AVERROR_EXTERNAL;
+}
+
+#define CHECK_CU(x) check_cu(avctx, (x), #x)
+
+static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* format)
+{
+ AVCodecContext *avctx = opaque;
+ CuvidContext *ctx = avctx->priv_data;
+ AVHWFramesContext *hwframe_ctx = (AVHWFramesContext*)ctx->hwframe->data;
+ CUVIDDECODECREATEINFO cuinfo;
+
+ av_log(avctx, AV_LOG_TRACE, "pfnSequenceCallback, progressive_sequence=%d\n", format->progressive_sequence);
+
+ ctx->internal_error = 0;
+
+ avctx->width = format->display_area.right;
+ avctx->height = format->display_area.bottom;
+
+ ff_set_sar(avctx, av_div_q(
+ (AVRational){ format->display_aspect_ratio.x, format->display_aspect_ratio.y },
+ (AVRational){ avctx->width, avctx->height }));
+
+ if (!format->progressive_sequence && ctx->deint_mode == cudaVideoDeinterlaceMode_Weave)
+ avctx->flags |= AV_CODEC_FLAG_INTERLACED_DCT;
+ else
+ avctx->flags &= ~AV_CODEC_FLAG_INTERLACED_DCT;
+
+ if (format->video_signal_description.video_full_range_flag)
+ avctx->color_range = AVCOL_RANGE_JPEG;
+ else
+ avctx->color_range = AVCOL_RANGE_MPEG;
+
+ avctx->color_primaries = format->video_signal_description.color_primaries;
+ avctx->color_trc = format->video_signal_description.transfer_characteristics;
+ avctx->colorspace = format->video_signal_description.matrix_coefficients;
+
+ if (format->bitrate)
+ avctx->bit_rate = format->bitrate;
+
+ if (format->frame_rate.numerator && format->frame_rate.denominator) {
+ avctx->framerate.num = format->frame_rate.numerator;
+ avctx->framerate.den = format->frame_rate.denominator;
+ }
+
+ if (ctx->cudecoder
+ && avctx->coded_width == format->coded_width
+ && avctx->coded_height == format->coded_height
+ && ctx->chroma_format == format->chroma_format
+ && ctx->codec_type == format->codec)
+ return 1;
+
+ if (ctx->cudecoder) {
+ av_log(avctx, AV_LOG_ERROR, "re-initializing decoder is not supported\n");
+ ctx->internal_error = AVERROR(EINVAL);
+ return 0;
+ }
+
+ if (hwframe_ctx->pool && (
+ hwframe_ctx->width < avctx->width ||
+ hwframe_ctx->height < avctx->height ||
+ hwframe_ctx->format != AV_PIX_FMT_CUDA ||
+ hwframe_ctx->sw_format != AV_PIX_FMT_NV12)) {
+ av_log(avctx, AV_LOG_ERROR, "AVHWFramesContext is already initialized with incompatible parameters\n");
+ ctx->internal_error = AVERROR(EINVAL);
+ return 0;
+ }
+
+ if (format->chroma_format != cudaVideoChromaFormat_420) {
+ av_log(avctx, AV_LOG_ERROR, "Chroma formats other than 420 are not supported\n");
+ ctx->internal_error = AVERROR(EINVAL);
+ return 0;
+ }
+
+ avctx->coded_width = format->coded_width;
+ avctx->coded_height = format->coded_height;
+
+ ctx->chroma_format = format->chroma_format;
+
+ memset(&cuinfo, 0, sizeof(cuinfo));
+
+ cuinfo.CodecType = ctx->codec_type = format->codec;
+ cuinfo.ChromaFormat = format->chroma_format;
+ cuinfo.OutputFormat = cudaVideoSurfaceFormat_NV12;
+
+ cuinfo.ulWidth = avctx->coded_width;
+ cuinfo.ulHeight = avctx->coded_height;
+ cuinfo.ulTargetWidth = cuinfo.ulWidth;
+ cuinfo.ulTargetHeight = cuinfo.ulHeight;
+
+ cuinfo.target_rect.left = 0;
+ cuinfo.target_rect.top = 0;
+ cuinfo.target_rect.right = cuinfo.ulWidth;
+ cuinfo.target_rect.bottom = cuinfo.ulHeight;
+
+ cuinfo.ulNumDecodeSurfaces = MAX_FRAME_COUNT;
+ cuinfo.ulNumOutputSurfaces = 1;
+ cuinfo.ulCreationFlags = cudaVideoCreate_PreferCUVID;
+ cuinfo.bitDepthMinus8 = format->bit_depth_luma_minus8;
+
+ if (format->progressive_sequence) {
+ ctx->deint_mode = cuinfo.DeinterlaceMode = cudaVideoDeinterlaceMode_Weave;
+ } else {
+ cuinfo.DeinterlaceMode = ctx->deint_mode;
+ }
+
+ if (ctx->deint_mode != cudaVideoDeinterlaceMode_Weave)
+ avctx->framerate = av_mul_q(avctx->framerate, (AVRational){2, 1});
+
+ ctx->internal_error = CHECK_CU(cuvidCreateDecoder(&ctx->cudecoder, &cuinfo));
+ if (ctx->internal_error < 0)
+ return 0;
+
+ if (!hwframe_ctx->pool) {
+ hwframe_ctx->format = AV_PIX_FMT_CUDA;
+ hwframe_ctx->sw_format = AV_PIX_FMT_NV12;
+ hwframe_ctx->width = avctx->width;
+ hwframe_ctx->height = avctx->height;
+
+ if ((ctx->internal_error = av_hwframe_ctx_init(ctx->hwframe)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "av_hwframe_ctx_init failed\n");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int CUDAAPI cuvid_handle_picture_decode(void *opaque, CUVIDPICPARAMS* picparams)
+{
+ AVCodecContext *avctx = opaque;
+ CuvidContext *ctx = avctx->priv_data;
+
+ av_log(avctx, AV_LOG_TRACE, "pfnDecodePicture\n");
+
+ ctx->internal_error = CHECK_CU(cuvidDecodePicture(ctx->cudecoder, picparams));
+ if (ctx->internal_error < 0)
+ return 0;
+
+ return 1;
+}
+
+static int CUDAAPI cuvid_handle_picture_display(void *opaque, CUVIDPARSERDISPINFO* dispinfo)
+{
+ AVCodecContext *avctx = opaque;
+ CuvidContext *ctx = avctx->priv_data;
+ CuvidParsedFrame parsed_frame = { *dispinfo, 0, 0 };
+
+ ctx->internal_error = 0;
+
+ if (ctx->deint_mode == cudaVideoDeinterlaceMode_Weave) {
+ av_fifo_generic_write(ctx->frame_queue, &parsed_frame, sizeof(CuvidParsedFrame), NULL);
+ } else {
+ parsed_frame.is_deinterlacing = 1;
+ av_fifo_generic_write(ctx->frame_queue, &parsed_frame, sizeof(CuvidParsedFrame), NULL);
+ parsed_frame.second_field = 1;
+ av_fifo_generic_write(ctx->frame_queue, &parsed_frame, sizeof(CuvidParsedFrame), NULL);
+ }
+
+ return 1;
+}
+
+static int cuvid_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
+{
+ CuvidContext *ctx = avctx->priv_data;
+ AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)ctx->hwdevice->data;
+ AVCUDADeviceContext *device_hwctx = device_ctx->hwctx;
+ CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx;
+ CUVIDSOURCEDATAPACKET cupkt;
+ AVPacket filter_packet = { 0 };
+ AVPacket filtered_packet = { 0 };
+ int ret = 0, eret = 0, is_flush = ctx->decoder_flushing;
+
+ av_log(avctx, AV_LOG_TRACE, "cuvid_decode_packet\n");
+
+ if (is_flush && avpkt && avpkt->size)
+ return AVERROR_EOF;
+
+ if (av_fifo_size(ctx->frame_queue) / sizeof(CuvidParsedFrame) > MAX_FRAME_COUNT - 2 && avpkt && avpkt->size)
+ return AVERROR(EAGAIN);
+
+ if (ctx->bsf && avpkt && avpkt->size) {
+ if ((ret = av_packet_ref(&filter_packet, avpkt)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "av_packet_ref failed\n");
+ return ret;
+ }
+
+ if ((ret = av_bsf_send_packet(ctx->bsf, &filter_packet)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "av_bsf_send_packet failed\n");
+ av_packet_unref(&filter_packet);
+ return ret;
+ }
+
+ if ((ret = av_bsf_receive_packet(ctx->bsf, &filtered_packet)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "av_bsf_receive_packet failed\n");
+ return ret;
+ }
+
+ avpkt = &filtered_packet;
+ }
+
+ ret = CHECK_CU(cuCtxPushCurrent(cuda_ctx));
+ if (ret < 0) {
+ av_packet_unref(&filtered_packet);
+ return ret;
+ }
+
+ memset(&cupkt, 0, sizeof(cupkt));
+
+ if (avpkt && avpkt->size) {
+ cupkt.payload_size = avpkt->size;
+ cupkt.payload = avpkt->data;
+
+ if (avpkt->pts != AV_NOPTS_VALUE) {
+ cupkt.flags = CUVID_PKT_TIMESTAMP;
+ if (avctx->pkt_timebase.num && avctx->pkt_timebase.den)
+ cupkt.timestamp = av_rescale_q(avpkt->pts, avctx->pkt_timebase, (AVRational){1, 10000000});
+ else
+ cupkt.timestamp = avpkt->pts;
+ }
+ } else {
+ cupkt.flags = CUVID_PKT_ENDOFSTREAM;
+ ctx->decoder_flushing = 1;
+ }
+
+ ret = CHECK_CU(cuvidParseVideoData(ctx->cuparser, &cupkt));
+
+ av_packet_unref(&filtered_packet);
+
+ if (ret < 0)
+ goto error;
+
+ // cuvidParseVideoData doesn't return an error just because stuff failed...
+ if (ctx->internal_error) {
+ av_log(avctx, AV_LOG_ERROR, "cuvid decode callback error\n");
+ ret = ctx->internal_error;
+ goto error;
+ }
+
+error:
+ eret = CHECK_CU(cuCtxPopCurrent(&dummy));
+
+ if (eret < 0)
+ return eret;
+ else if (ret < 0)
+ return ret;
+ else if (is_flush)
+ return AVERROR_EOF;
+ else
+ return 0;
+}
+
+static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame)
+{
+ CuvidContext *ctx = avctx->priv_data;
+ AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)ctx->hwdevice->data;
+ AVCUDADeviceContext *device_hwctx = device_ctx->hwctx;
+ CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx;
+ CUdeviceptr mapped_frame = 0;
+ int ret = 0, eret = 0;
+
+ av_log(avctx, AV_LOG_TRACE, "cuvid_output_frame\n");
+
+ if (ctx->decoder_flushing) {
+ ret = cuvid_decode_packet(avctx, NULL);
+ if (ret < 0 && ret != AVERROR_EOF)
+ return ret;
+ }
+
+ ret = CHECK_CU(cuCtxPushCurrent(cuda_ctx));
+ if (ret < 0)
+ return ret;
+
+ if (av_fifo_size(ctx->frame_queue)) {
+ CuvidParsedFrame parsed_frame;
+ CUVIDPROCPARAMS params;
+ unsigned int pitch = 0;
+ int offset = 0;
+ int i;
+
+ av_fifo_generic_read(ctx->frame_queue, &parsed_frame, sizeof(CuvidParsedFrame), NULL);
+
+ memset(¶ms, 0, sizeof(params));
+ params.progressive_frame = parsed_frame.dispinfo.progressive_frame;
+ params.second_field = parsed_frame.second_field;
+ params.top_field_first = parsed_frame.dispinfo.top_field_first;
+
+ ret = CHECK_CU(cuvidMapVideoFrame(ctx->cudecoder, parsed_frame.dispinfo.picture_index, &mapped_frame, &pitch, ¶ms));
+ if (ret < 0)
+ goto error;
+
+ if (avctx->pix_fmt == AV_PIX_FMT_CUDA) {
+ ret = av_hwframe_get_buffer(ctx->hwframe, frame, 0);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "av_hwframe_get_buffer failed\n");
+ goto error;
+ }
+
+ ret = ff_decode_frame_props(avctx, frame);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "ff_decode_frame_props failed\n");
+ goto error;
+ }
+
+ for (i = 0; i < 2; i++) {
+ CUDA_MEMCPY2D cpy = {
+ .srcMemoryType = CU_MEMORYTYPE_DEVICE,
+ .dstMemoryType = CU_MEMORYTYPE_DEVICE,
+ .srcDevice = mapped_frame,
+ .dstDevice = (CUdeviceptr)frame->data[i],
+ .srcPitch = pitch,
+ .dstPitch = frame->linesize[i],
+ .srcY = offset,
+ .WidthInBytes = FFMIN(pitch, frame->linesize[i]),
+ .Height = avctx->height >> (i ? 1 : 0),
+ };
+
+ ret = CHECK_CU(cuMemcpy2D(&cpy));
+ if (ret < 0)
+ goto error;
+
+ offset += avctx->coded_height;
+ }
+ } else if (avctx->pix_fmt == AV_PIX_FMT_NV12) {
+ AVFrame *tmp_frame = av_frame_alloc();
+ if (!tmp_frame) {
+ av_log(avctx, AV_LOG_ERROR, "av_frame_alloc failed\n");
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+
+ tmp_frame->format = AV_PIX_FMT_CUDA;
+ tmp_frame->hw_frames_ctx = av_buffer_ref(ctx->hwframe);
+ tmp_frame->data[0] = (uint8_t*)mapped_frame;
+ tmp_frame->linesize[0] = pitch;
+ tmp_frame->data[1] = (uint8_t*)(mapped_frame + avctx->coded_height * pitch);
+ tmp_frame->linesize[1] = pitch;
+ tmp_frame->width = avctx->width;
+ tmp_frame->height = avctx->height;
+
+ ret = ff_get_buffer(avctx, frame, 0);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "ff_get_buffer failed\n");
+ av_frame_free(&tmp_frame);
+ goto error;
+ }
+
+ ret = av_hwframe_transfer_data(frame, tmp_frame, 0);
+ if (ret) {
+ av_log(avctx, AV_LOG_ERROR, "av_hwframe_transfer_data failed\n");
+ av_frame_free(&tmp_frame);
+ goto error;
+ }
+
+ av_frame_free(&tmp_frame);
+ } else {
+ ret = AVERROR_BUG;
+ goto error;
+ }
+
+ frame->width = avctx->width;
+ frame->height = avctx->height;
+ if (avctx->pkt_timebase.num && avctx->pkt_timebase.den)
+ frame->pts = av_rescale_q(parsed_frame.dispinfo.timestamp, (AVRational){1, 10000000}, avctx->pkt_timebase);
+ else
+ frame->pts = parsed_frame.dispinfo.timestamp;
+
+ if (parsed_frame.second_field) {
+ if (ctx->prev_pts == INT64_MIN) {
+ ctx->prev_pts = frame->pts;
+ frame->pts += (avctx->pkt_timebase.den * avctx->framerate.den) / (avctx->pkt_timebase.num * avctx->framerate.num);
+ } else {
+ int pts_diff = (frame->pts - ctx->prev_pts) / 2;
+ ctx->prev_pts = frame->pts;
+ frame->pts += pts_diff;
+ }
+ }
+
+ /* CUVIDs opaque reordering breaks the internal pkt logic.
+ * So set pkt_pts and clear all the other pkt_ fields.
+ */
++#if FF_API_PKT_PTS
++FF_DISABLE_DEPRECATION_WARNINGS
+ frame->pkt_pts = frame->pts;
++FF_ENABLE_DEPRECATION_WARNINGS
++#endif
+ av_frame_set_pkt_pos(frame, -1);
+ av_frame_set_pkt_duration(frame, 0);
+ av_frame_set_pkt_size(frame, -1);
+
+ frame->interlaced_frame = !parsed_frame.is_deinterlacing && !parsed_frame.dispinfo.progressive_frame;
+
+ if (frame->interlaced_frame)
+ frame->top_field_first = parsed_frame.dispinfo.top_field_first;
+ } else if (ctx->decoder_flushing) {
+ ret = AVERROR_EOF;
+ } else {
+ ret = AVERROR(EAGAIN);
+ }
+
+error:
+ if (mapped_frame)
+ eret = CHECK_CU(cuvidUnmapVideoFrame(ctx->cudecoder, mapped_frame));
+
+ eret = CHECK_CU(cuCtxPopCurrent(&dummy));
+
+ if (eret < 0)
+ return eret;
+ else
+ return ret;
+}
+
+static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
+{
+ CuvidContext *ctx = avctx->priv_data;
+ AVFrame *frame = data;
+ int ret = 0;
+
+ av_log(avctx, AV_LOG_TRACE, "cuvid_decode_frame\n");
+
+ if (ctx->deint_mode != cudaVideoDeinterlaceMode_Weave) {
+ av_log(avctx, AV_LOG_ERROR, "Deinterlacing is not supported via the old API\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (!ctx->decoder_flushing) {
+ ret = cuvid_decode_packet(avctx, avpkt);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = cuvid_output_frame(avctx, frame);
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+ *got_frame = 0;
+ } else if (ret < 0) {
+ return ret;
+ } else {
+ *got_frame = 1;
+ }
+
+ return 0;
+}
+
+static av_cold int cuvid_decode_end(AVCodecContext *avctx)
+{
+ CuvidContext *ctx = avctx->priv_data;
+
+ av_fifo_freep(&ctx->frame_queue);
+
+ if (ctx->bsf)
+ av_bsf_free(&ctx->bsf);
+
+ if (ctx->cuparser)
+ cuvidDestroyVideoParser(ctx->cuparser);
+
+ if (ctx->cudecoder)
+ cuvidDestroyDecoder(ctx->cudecoder);
+
+ av_buffer_unref(&ctx->hwframe);
+ av_buffer_unref(&ctx->hwdevice);
+
+ return 0;
+}
+
+static int cuvid_test_dummy_decoder(AVCodecContext *avctx, CUVIDPARSERPARAMS *cuparseinfo)
+{
+ CUVIDDECODECREATEINFO cuinfo;
+ CUvideodecoder cudec = 0;
+ int ret = 0;
+
+ memset(&cuinfo, 0, sizeof(cuinfo));
+
+ cuinfo.CodecType = cuparseinfo->CodecType;
+ cuinfo.ChromaFormat = cudaVideoChromaFormat_420;
+ cuinfo.OutputFormat = cudaVideoSurfaceFormat_NV12;
+
+ cuinfo.ulWidth = 1280;
+ cuinfo.ulHeight = 720;
+ cuinfo.ulTargetWidth = cuinfo.ulWidth;
+ cuinfo.ulTargetHeight = cuinfo.ulHeight;
+
+ cuinfo.target_rect.left = 0;
+ cuinfo.target_rect.top = 0;
+ cuinfo.target_rect.right = cuinfo.ulWidth;
+ cuinfo.target_rect.bottom = cuinfo.ulHeight;
+
+ cuinfo.ulNumDecodeSurfaces = MAX_FRAME_COUNT;
+ cuinfo.ulNumOutputSurfaces = 1;
+ cuinfo.ulCreationFlags = cudaVideoCreate_PreferCUVID;
+ cuinfo.bitDepthMinus8 = 0;
+
+ cuinfo.DeinterlaceMode = cudaVideoDeinterlaceMode_Weave;
+
+ ret = CHECK_CU(cuvidCreateDecoder(&cudec, &cuinfo));
+ if (ret < 0)
+ return ret;
+
+ ret = CHECK_CU(cuvidDestroyDecoder(cudec));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static av_cold int cuvid_decode_init(AVCodecContext *avctx)
+{
+ CuvidContext *ctx = avctx->priv_data;
+ AVCUDADeviceContext *device_hwctx;
+ AVHWDeviceContext *device_ctx;
+ AVHWFramesContext *hwframe_ctx;
+ CUVIDSOURCEDATAPACKET seq_pkt;
+ CUcontext cuda_ctx = NULL;
+ CUcontext dummy;
+ const AVBitStreamFilter *bsf;
+ int ret = 0;
+
+ enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_CUDA,
+ AV_PIX_FMT_NV12,
+ AV_PIX_FMT_NONE };
+
+ ret = ff_get_format(avctx, pix_fmts);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "ff_get_format failed: %d\n", ret);
+ return ret;
+ }
+
+ ctx->frame_queue = av_fifo_alloc(MAX_FRAME_COUNT * sizeof(CuvidParsedFrame));
+ if (!ctx->frame_queue) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+
+ avctx->pix_fmt = ret;
+
+ if (avctx->hw_frames_ctx) {
+ ctx->hwframe = av_buffer_ref(avctx->hw_frames_ctx);
+ if (!ctx->hwframe) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+
+ hwframe_ctx = (AVHWFramesContext*)ctx->hwframe->data;
+
+ ctx->hwdevice = av_buffer_ref(hwframe_ctx->device_ref);
+ if (!ctx->hwdevice) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+ } else {
+ ret = av_hwdevice_ctx_create(&ctx->hwdevice, AV_HWDEVICE_TYPE_CUDA, ctx->cu_gpu, NULL, 0);
+ if (ret < 0)
+ goto error;
+
+ ctx->hwframe = av_hwframe_ctx_alloc(ctx->hwdevice);
+ if (!ctx->hwframe) {
+ av_log(avctx, AV_LOG_ERROR, "av_hwframe_ctx_alloc failed\n");
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+
+ hwframe_ctx = (AVHWFramesContext*)ctx->hwframe->data;
+ }
+
+ device_ctx = hwframe_ctx->device_ctx;
+ device_hwctx = device_ctx->hwctx;
+ cuda_ctx = device_hwctx->cuda_ctx;
+
+ memset(&ctx->cuparseinfo, 0, sizeof(ctx->cuparseinfo));
+ memset(&ctx->cuparse_ext, 0, sizeof(ctx->cuparse_ext));
+ memset(&seq_pkt, 0, sizeof(seq_pkt));
+
+ ctx->cuparseinfo.pExtVideoInfo = &ctx->cuparse_ext;
+
+ switch (avctx->codec->id) {
+#if CONFIG_H263_CUVID_DECODER
+ case AV_CODEC_ID_H263:
+ ctx->cuparseinfo.CodecType = cudaVideoCodec_MPEG4;
+ break;
+#endif
+#if CONFIG_H264_CUVID_DECODER
+ case AV_CODEC_ID_H264:
+ ctx->cuparseinfo.CodecType = cudaVideoCodec_H264;
+ break;
+#endif
+#if CONFIG_HEVC_CUVID_DECODER
+ case AV_CODEC_ID_HEVC:
+ ctx->cuparseinfo.CodecType = cudaVideoCodec_HEVC;
+ break;
+#endif
+#if CONFIG_MJPEG_CUVID_DECODER
+ case AV_CODEC_ID_MJPEG:
+ ctx->cuparseinfo.CodecType = cudaVideoCodec_JPEG;
+ break;
+#endif
+#if CONFIG_MPEG1_CUVID_DECODER
+ case AV_CODEC_ID_MPEG1VIDEO:
+ ctx->cuparseinfo.CodecType = cudaVideoCodec_MPEG1;
+ break;
+#endif
+#if CONFIG_MPEG2_CUVID_DECODER
+ case AV_CODEC_ID_MPEG2VIDEO:
+ ctx->cuparseinfo.CodecType = cudaVideoCodec_MPEG2;
+ break;
+#endif
+#if CONFIG_MPEG4_CUVID_DECODER
+ case AV_CODEC_ID_MPEG4:
+ ctx->cuparseinfo.CodecType = cudaVideoCodec_MPEG4;
+ break;
+#endif
+#if CONFIG_VP8_CUVID_DECODER
+ case AV_CODEC_ID_VP8:
+ ctx->cuparseinfo.CodecType = cudaVideoCodec_VP8;
+ break;
+#endif
+#if CONFIG_VP9_CUVID_DECODER
+ case AV_CODEC_ID_VP9:
+ ctx->cuparseinfo.CodecType = cudaVideoCodec_VP9;
+ break;
+#endif
+#if CONFIG_VC1_CUVID_DECODER
+ case AV_CODEC_ID_VC1:
+ ctx->cuparseinfo.CodecType = cudaVideoCodec_VC1;
+ break;
+#endif
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Invalid CUVID codec!\n");
+ return AVERROR_BUG;
+ }
+
+ if (avctx->codec->id == AV_CODEC_ID_H264 || avctx->codec->id == AV_CODEC_ID_HEVC) {
+ if (avctx->codec->id == AV_CODEC_ID_H264)
+ bsf = av_bsf_get_by_name("h264_mp4toannexb");
+ else
+ bsf = av_bsf_get_by_name("hevc_mp4toannexb");
+
+ if (!bsf) {
+ ret = AVERROR_BSF_NOT_FOUND;
+ goto error;
+ }
+ if (ret = av_bsf_alloc(bsf, &ctx->bsf)) {
+ goto error;
+ }
+ if (((ret = avcodec_parameters_from_context(ctx->bsf->par_in, avctx)) < 0) || ((ret = av_bsf_init(ctx->bsf)) < 0)) {
+ av_bsf_free(&ctx->bsf);
+ goto error;
+ }
+
+ ctx->cuparse_ext.format.seqhdr_data_length = ctx->bsf->par_out->extradata_size;
+ memcpy(ctx->cuparse_ext.raw_seqhdr_data,
+ ctx->bsf->par_out->extradata,
+ FFMIN(sizeof(ctx->cuparse_ext.raw_seqhdr_data), ctx->bsf->par_out->extradata_size));
+ } else if (avctx->extradata_size > 0) {
+ ctx->cuparse_ext.format.seqhdr_data_length = avctx->extradata_size;
+ memcpy(ctx->cuparse_ext.raw_seqhdr_data,
+ avctx->extradata,
+ FFMIN(sizeof(ctx->cuparse_ext.raw_seqhdr_data), avctx->extradata_size));
+ }
+
+ ctx->cuparseinfo.ulMaxNumDecodeSurfaces = MAX_FRAME_COUNT;
+ ctx->cuparseinfo.ulMaxDisplayDelay = 4;
+ ctx->cuparseinfo.pUserData = avctx;
+ ctx->cuparseinfo.pfnSequenceCallback = cuvid_handle_video_sequence;
+ ctx->cuparseinfo.pfnDecodePicture = cuvid_handle_picture_decode;
+ ctx->cuparseinfo.pfnDisplayPicture = cuvid_handle_picture_display;
+
+ ret = CHECK_CU(cuCtxPushCurrent(cuda_ctx));
+ if (ret < 0)
+ goto error;
+
+ ret = cuvid_test_dummy_decoder(avctx, &ctx->cuparseinfo);
+ if (ret < 0)
+ goto error;
+
+ ret = CHECK_CU(cuvidCreateVideoParser(&ctx->cuparser, &ctx->cuparseinfo));
+ if (ret < 0)
+ goto error;
+
+ seq_pkt.payload = ctx->cuparse_ext.raw_seqhdr_data;
+ seq_pkt.payload_size = ctx->cuparse_ext.format.seqhdr_data_length;
+
+ if (seq_pkt.payload && seq_pkt.payload_size) {
+ ret = CHECK_CU(cuvidParseVideoData(ctx->cuparser, &seq_pkt));
+ if (ret < 0)
+ goto error;
+ }
+
+ ret = CHECK_CU(cuCtxPopCurrent(&dummy));
+ if (ret < 0)
+ goto error;
+
+ ctx->prev_pts = INT64_MIN;
+
+ if (!avctx->pkt_timebase.num || !avctx->pkt_timebase.den)
+ av_log(avctx, AV_LOG_WARNING, "Invalid pkt_timebase, passing timestamps as-is.\n");
+
+ return 0;
+
+error:
+ cuvid_decode_end(avctx);
+ return ret;
+}
+
+static void cuvid_flush(AVCodecContext *avctx)
+{
+ CuvidContext *ctx = avctx->priv_data;
+ AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)ctx->hwdevice->data;
+ AVCUDADeviceContext *device_hwctx = device_ctx->hwctx;
+ CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx;
+ CUVIDSOURCEDATAPACKET seq_pkt = { 0 };
+ int ret;
+
+ ret = CHECK_CU(cuCtxPushCurrent(cuda_ctx));
+ if (ret < 0)
+ goto error;
+
+ av_fifo_freep(&ctx->frame_queue);
+
+ ctx->frame_queue = av_fifo_alloc(MAX_FRAME_COUNT * sizeof(CuvidParsedFrame));
+ if (!ctx->frame_queue) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to recreate frame queue on flush\n");
+ return;
+ }
+
+ if (ctx->cudecoder) {
+ cuvidDestroyDecoder(ctx->cudecoder);
+ ctx->cudecoder = NULL;
+ }
+
+ if (ctx->cuparser) {
+ cuvidDestroyVideoParser(ctx->cuparser);
+ ctx->cuparser = NULL;
+ }
+
+ ret = CHECK_CU(cuvidCreateVideoParser(&ctx->cuparser, &ctx->cuparseinfo));
+ if (ret < 0)
+ goto error;
+
+ seq_pkt.payload = ctx->cuparse_ext.raw_seqhdr_data;
+ seq_pkt.payload_size = ctx->cuparse_ext.format.seqhdr_data_length;
+
+ if (seq_pkt.payload && seq_pkt.payload_size) {
+ ret = CHECK_CU(cuvidParseVideoData(ctx->cuparser, &seq_pkt));
+ if (ret < 0)
+ goto error;
+ }
+
+ ret = CHECK_CU(cuCtxPopCurrent(&dummy));
+ if (ret < 0)
+ goto error;
+
+ ctx->prev_pts = INT64_MIN;
+ ctx->decoder_flushing = 0;
+
+ return;
+ error:
+ av_log(avctx, AV_LOG_ERROR, "CUDA reinit on flush failed\n");
+}
+
+#define OFFSET(x) offsetof(CuvidContext, x)
+#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ { "deint", "Set deinterlacing mode", OFFSET(deint_mode), AV_OPT_TYPE_INT, { .i64 = cudaVideoDeinterlaceMode_Weave }, cudaVideoDeinterlaceMode_Weave, cudaVideoDeinterlaceMode_Adaptive, VD, "deint" },
+ { "weave", "Weave deinterlacing (do nothing)", 0, AV_OPT_TYPE_CONST, { .i64 = cudaVideoDeinterlaceMode_Weave }, 0, 0, VD, "deint" },
+ { "bob", "Bob deinterlacing", 0, AV_OPT_TYPE_CONST, { .i64 = cudaVideoDeinterlaceMode_Bob }, 0, 0, VD, "deint" },
+ { "adaptive", "Adaptive deinterlacing", 0, AV_OPT_TYPE_CONST, { .i64 = cudaVideoDeinterlaceMode_Adaptive }, 0, 0, VD, "deint" },
+ { "gpu", "GPU to be used for decoding", OFFSET(cu_gpu), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD },
+ { NULL }
+};
+
+#define DEFINE_CUVID_CODEC(x, X) \
+ static const AVClass x##_cuvid_class = { \
+ .class_name = #x "_cuvid", \
+ .item_name = av_default_item_name, \
+ .option = options, \
+ .version = LIBAVUTIL_VERSION_INT, \
+ }; \
+ AVHWAccel ff_##x##_cuvid_hwaccel = { \
+ .name = #x "_cuvid", \
+ .type = AVMEDIA_TYPE_VIDEO, \
+ .id = AV_CODEC_ID_##X, \
+ .pix_fmt = AV_PIX_FMT_CUDA, \
+ }; \
+ AVCodec ff_##x##_cuvid_decoder = { \
+ .name = #x "_cuvid", \
+ .long_name = NULL_IF_CONFIG_SMALL("Nvidia CUVID " #X " decoder"), \
+ .type = AVMEDIA_TYPE_VIDEO, \
+ .id = AV_CODEC_ID_##X, \
+ .priv_data_size = sizeof(CuvidContext), \
+ .priv_class = &x##_cuvid_class, \
+ .init = cuvid_decode_init, \
+ .close = cuvid_decode_end, \
+ .decode = cuvid_decode_frame, \
+ .send_packet = cuvid_decode_packet, \
+ .receive_frame = cuvid_output_frame, \
+ .flush = cuvid_flush, \
+ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \
+ AV_PIX_FMT_NV12, \
+ AV_PIX_FMT_NONE }, \
+ };
+
+#if CONFIG_HEVC_CUVID_DECODER
+DEFINE_CUVID_CODEC(hevc, HEVC)
+#endif
+
+#if CONFIG_H263_CUVID_DECODER
+DEFINE_CUVID_CODEC(h263, H263)
+#endif
+
+#if CONFIG_H264_CUVID_DECODER
+DEFINE_CUVID_CODEC(h264, H264)
+#endif
+
+#if CONFIG_MJPEG_CUVID_DECODER
+DEFINE_CUVID_CODEC(mjpeg, MJPEG)
+#endif
+
+#if CONFIG_MPEG1_CUVID_DECODER
+DEFINE_CUVID_CODEC(mpeg1, MPEG1VIDEO)
+#endif
+
+#if CONFIG_MPEG2_CUVID_DECODER
+DEFINE_CUVID_CODEC(mpeg2, MPEG2VIDEO)
+#endif
+
+#if CONFIG_MPEG4_CUVID_DECODER
+DEFINE_CUVID_CODEC(mpeg4, MPEG4)
+#endif
+
+#if CONFIG_VP8_CUVID_DECODER
+DEFINE_CUVID_CODEC(vp8, VP8)
+#endif
+
+#if CONFIG_VP9_CUVID_DECODER
+DEFINE_CUVID_CODEC(vp9, VP9)
+#endif
+
+#if CONFIG_VC1_CUVID_DECODER
+DEFINE_CUVID_CODEC(vc1, VC1)
+#endif
diff --cc libavcodec/gifdec.c
index 20ae903,f08d501..48345db
--- a/libavcodec/gifdec.c
+++ b/libavcodec/gifdec.c
@@@ -454,59 -275,30 +454,63 @@@ static av_cold int gif_decode_init(AVCo
return 0;
}
-static int gif_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
- AVPacket *avpkt)
+static int gif_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
{
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
GifState *s = avctx->priv_data;
- AVFrame *picture = data;
int ret;
- bytestream2_init(&s->gb, buf, buf_size);
- if ((ret = gif_read_header1(s)) < 0)
- return ret;
+ bytestream2_init(&s->gb, avpkt->data, avpkt->size);
- avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ s->frame->pts = avpkt->pts;
++#if FF_API_PKT_PTS
++FF_DISABLE_DEPRECATION_WARNINGS
+ s->frame->pkt_pts = avpkt->pts;
++FF_ENABLE_DEPRECATION_WARNINGS
++#endif
+ s->frame->pkt_dts = avpkt->dts;
+ av_frame_set_pkt_duration(s->frame, avpkt->duration);
- if ((ret = ff_set_dimensions(avctx, s->screen_width, s->screen_height)) < 0)
- return ret;
+ if (avpkt->size >= 6) {
+ s->keyframe = memcmp(avpkt->data, gif87a_sig, 6) == 0 ||
+ memcmp(avpkt->data, gif89a_sig, 6) == 0;
+ } else {
+ s->keyframe = 0;
+ }
- if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return ret;
+ if (s->keyframe) {
+ s->keyframe_ok = 0;
+ s->gce_prev_disposal = GCE_DISPOSAL_NONE;
+ if ((ret = gif_read_header1(s)) < 0)
+ return ret;
+
+ if ((ret = ff_set_dimensions(avctx, s->screen_width, s->screen_height)) < 0)
+ return ret;
+
+ av_frame_unref(s->frame);
+ if ((ret = ff_get_buffer(avctx, s->frame, 0)) < 0)
+ return ret;
+
+ av_fast_malloc(&s->idx_line, &s->idx_line_size, s->screen_width);
+ if (!s->idx_line)
+ return AVERROR(ENOMEM);
+
+ s->frame->pict_type = AV_PICTURE_TYPE_I;
+ s->frame->key_frame = 1;
+ s->keyframe_ok = 1;
+ } else {
+ if (!s->keyframe_ok) {
+ av_log(avctx, AV_LOG_ERROR, "cannot decode frame without keyframe\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
+ return ret;
+
+ s->frame->pict_type = AV_PICTURE_TYPE_P;
+ s->frame->key_frame = 0;
}
- s->image_palette = (uint32_t *)picture->data[1];
- ret = gif_parse_next_image(s, picture);
+
+ ret = gif_parse_next_image(s, s->frame);
if (ret < 0)
return ret;
diff --cc libavcodec/libopenh264dec.c
index 6af60af,0000000..ab0a84c
mode 100644,000000..100644
--- a/libavcodec/libopenh264dec.c
+++ b/libavcodec/libopenh264dec.c
@@@ -1,245 -1,0 +1,249 @@@
+/*
+ * OpenH264 video decoder
+ * Copyright (C) 2016 Martin Storsjo
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <wels/codec_api.h>
+#include <wels/codec_ver.h>
+
+#include "libavutil/common.h"
+#include "libavutil/fifo.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+
+#include "avcodec.h"
+#include "internal.h"
+#include "libopenh264.h"
+
+typedef struct SVCContext {
+ ISVCDecoder *decoder;
+ AVBSFContext *bsf;
+ AVFifoBuffer *packet_fifo;
+ AVPacket pkt_filtered;
+} SVCContext;
+
+static av_cold int svc_decode_close(AVCodecContext *avctx)
+{
+ SVCContext *s = avctx->priv_data;
+ AVPacket pkt;
+
+ if (s->decoder)
+ WelsDestroyDecoder(s->decoder);
+
+ while (s->packet_fifo && av_fifo_size(s->packet_fifo) >= sizeof(pkt)) {
+ av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL);
+ av_packet_unref(&pkt);
+ }
+
+ av_bsf_free(&s->bsf);
+ av_packet_unref(&s->pkt_filtered);
+ av_fifo_free(s->packet_fifo);
+
+ return 0;
+}
+
+static av_cold int svc_decode_init(AVCodecContext *avctx)
+{
+ SVCContext *s = avctx->priv_data;
+ SDecodingParam param = { 0 };
+ int err;
+ int log_level;
+ WelsTraceCallback callback_function;
+
+ if ((err = ff_libopenh264_check_version(avctx)) < 0)
+ return err;
+
+ s->packet_fifo = av_fifo_alloc(sizeof(AVPacket));
+ if (!s->packet_fifo) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if (WelsCreateDecoder(&s->decoder)) {
+ av_log(avctx, AV_LOG_ERROR, "Unable to create decoder\n");
+ err = AVERROR_UNKNOWN;
+ goto fail;
+ }
+
+ // Pass all libopenh264 messages to our callback, to allow ourselves to filter them.
+ log_level = WELS_LOG_DETAIL;
+ callback_function = ff_libopenh264_trace_callback;
+ (*s->decoder)->SetOption(s->decoder, DECODER_OPTION_TRACE_LEVEL, &log_level);
+ (*s->decoder)->SetOption(s->decoder, DECODER_OPTION_TRACE_CALLBACK, (void *)&callback_function);
+ (*s->decoder)->SetOption(s->decoder, DECODER_OPTION_TRACE_CALLBACK_CONTEXT, (void *)&avctx);
+
+#if !OPENH264_VER_AT_LEAST(1, 6)
+ param.eOutputColorFormat = videoFormatI420;
+#endif
+ param.eEcActiveIdc = ERROR_CON_DISABLE;
+ param.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
+
+ if ((*s->decoder)->Initialize(s->decoder, ¶m) != cmResultSuccess) {
+ av_log(avctx, AV_LOG_ERROR, "Initialize failed\n");
+ err = AVERROR_UNKNOWN;
+ goto fail;
+ }
+
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+
+fail:
+ return err;
+}
+
+static int init_bsf(AVCodecContext *avctx)
+{
+ SVCContext *s = avctx->priv_data;
+ const AVBitStreamFilter *filter;
+ int ret;
+
+ if (s->bsf)
+ return 0;
+
+ // If the input stream already is annex b, this BSF only passes the
+ // packets through unchanged.
+ filter = av_bsf_get_by_name("h264_mp4toannexb");
+ if (!filter)
+ return AVERROR_BUG;
+
+ ret = av_bsf_alloc(filter, &s->bsf);
+ if (ret < 0)
+ return ret;
+
+ ret = avcodec_parameters_from_context(s->bsf->par_in, avctx);
+ if (ret < 0)
+ return ret;
+
+ s->bsf->time_base_in = avctx->time_base;
+
+ ret = av_bsf_init(s->bsf);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int svc_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ SVCContext *s = avctx->priv_data;
+ SBufferInfo info = { 0 };
+ uint8_t* ptrs[3];
+ int linesize[3];
+ AVFrame *avframe = data;
+ int ret;
+ DECODING_STATE state;
+
+ if ((ret = init_bsf(avctx)) < 0)
+ return ret;
+
+ if (avpkt->size) {
+ AVPacket input_ref = { 0 };
+ if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) {
+ ret = av_fifo_realloc2(s->packet_fifo,
+ av_fifo_size(s->packet_fifo) + sizeof(input_ref));
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = av_packet_ref(&input_ref, avpkt);
+ if (ret < 0)
+ return ret;
+ av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), NULL);
+ }
+
+ while (!*got_frame) {
+ /* prepare the input data -- convert to Annex B if needed */
+ if (s->pkt_filtered.size <= 0) {
+ AVPacket input_ref;
+
+ /* no more data */
+ if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket))
+ return avpkt->size ? avpkt->size : 0;
+
+ av_packet_unref(&s->pkt_filtered);
+
+ av_fifo_generic_read(s->packet_fifo, &input_ref, sizeof(input_ref), NULL);
+ ret = av_bsf_send_packet(s->bsf, &input_ref);
+ if (ret < 0) {
+ av_packet_unref(&input_ref);
+ return ret;
+ }
+
+ ret = av_bsf_receive_packet(s->bsf, &s->pkt_filtered);
+ if (ret < 0)
+ av_packet_move_ref(&s->pkt_filtered, &input_ref);
+ else
+ av_packet_unref(&input_ref);
+ }
+
+ state = (*s->decoder)->DecodeFrame2(s->decoder, s->pkt_filtered.data, s->pkt_filtered.size, ptrs, &info);
+ s->pkt_filtered.size = 0;
+ if (state != dsErrorFree) {
+ av_log(avctx, AV_LOG_ERROR, "DecodeFrame2 failed\n");
+ return AVERROR_UNKNOWN;
+ }
+ if (info.iBufferStatus != 1) {
+ av_log(avctx, AV_LOG_DEBUG, "No frame produced\n");
+ continue;
+ }
+
+ ret = ff_set_dimensions(avctx, info.UsrData.sSystemBuffer.iWidth, info.UsrData.sSystemBuffer.iHeight);
+ if (ret < 0)
+ return ret;
+ // The decoder doesn't (currently) support decoding into a user
+ // provided buffer, so do a copy instead.
+ if (ff_get_buffer(avctx, avframe, 0) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Unable to allocate buffer\n");
+ return AVERROR(ENOMEM);
+ }
+
+ linesize[0] = info.UsrData.sSystemBuffer.iStride[0];
+ linesize[1] = linesize[2] = info.UsrData.sSystemBuffer.iStride[1];
+ av_image_copy(avframe->data, avframe->linesize, (const uint8_t **) ptrs, linesize, avctx->pix_fmt, avctx->width, avctx->height);
+
+ avframe->pts = s->pkt_filtered.pts;
+ avframe->pkt_dts = s->pkt_filtered.dts;
++#if FF_API_PKT_PTS
++FF_DISABLE_DEPRECATION_WARNINGS
+ avframe->pkt_pts = s->pkt_filtered.pts;
++FF_ENABLE_DEPRECATION_WARNINGS
++#endif
+
+ *got_frame = 1;
+ }
+ return avpkt->size;
+}
+
+AVCodec ff_libopenh264_decoder = {
+ .name = "libopenh264",
+ .long_name = NULL_IF_CONFIG_SMALL("OpenH264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .priv_data_size = sizeof(SVCContext),
+ .init = svc_decode_init,
+ .decode = svc_decode_frame,
+ .close = svc_decode_close,
+ // The decoder doesn't currently support B-frames, and the decoder's API
+ // doesn't support reordering/delay, but the BSF could incur delay.
+ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1,
+ .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_THREADSAFE |
+ FF_CODEC_CAP_INIT_CLEANUP,
+};
diff --cc libavcodec/mediacodecdec.c
index 223942b,0000000..6683de7
mode 100644,000000..100644
--- a/libavcodec/mediacodecdec.c
+++ b/libavcodec/mediacodecdec.c
@@@ -1,766 -1,0 +1,776 @@@
+/*
+ * Android MediaCodec decoder
+ *
+ * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include <sys/types.h>
+
+#include "libavutil/atomic.h"
+#include "libavutil/common.h"
+#include "libavutil/mem.h"
+#include "libavutil/log.h"
+#include "libavutil/pixfmt.h"
+#include "libavutil/time.h"
+#include "libavutil/timestamp.h"
+
+#include "avcodec.h"
+#include "internal.h"
+
+#include "mediacodec.h"
+#include "mediacodec_surface.h"
+#include "mediacodec_sw_buffer.h"
+#include "mediacodec_wrapper.h"
+#include "mediacodecdec.h"
+
+/**
+ * OMX.k3.video.decoder.avc, OMX.NVIDIA.* OMX.SEC.avc.dec and OMX.google
+ * codec workarounds used in various place are taken from the Gstreamer
+ * project.
+ *
+ * Gstreamer references:
+ * https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/sys/androidmedia/
+ *
+ * Gstreamer copyright notice:
+ *
+ * Copyright (C) 2012, Collabora Ltd.
+ * Author: Sebastian Dröge <sebastian.droege at collabora.co.uk>
+ *
+ * Copyright (C) 2012, Rafaël Carré <funman at videolanorg>
+ *
+ * Copyright (C) 2015, Sebastian Dröge <sebastian at centricular.com>
+ *
+ * Copyright (C) 2014-2015, Collabora Ltd.
+ * Author: Matthieu Bouron <matthieu.bouron at gcollabora.com>
+ *
+ * Copyright (C) 2015, Edward Hervey
+ * Author: Edward Hervey <bilboed at gmail.com>
+ *
+ * Copyright (C) 2015, Matthew Waters <matthew at centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define INPUT_DEQUEUE_TIMEOUT_US 8000
+#define OUTPUT_DEQUEUE_TIMEOUT_US 8000
+#define OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US 1000000
+
+enum {
+ COLOR_FormatYUV420Planar = 0x13,
+ COLOR_FormatYUV420SemiPlanar = 0x15,
+ COLOR_FormatYCbYCr = 0x19,
+ COLOR_FormatAndroidOpaque = 0x7F000789,
+ COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00,
+ COLOR_QCOM_FormatYUV420SemiPlanar32m = 0x7fa30c04,
+ COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7fa30c03,
+ COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100,
+ COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced = 0x7f000001,
+};
+
+static const struct {
+
+ int color_format;
+ enum AVPixelFormat pix_fmt;
+
+} color_formats[] = {
+
+ { COLOR_FormatYUV420Planar, AV_PIX_FMT_YUV420P },
+ { COLOR_FormatYUV420SemiPlanar, AV_PIX_FMT_NV12 },
+ { COLOR_QCOM_FormatYUV420SemiPlanar, AV_PIX_FMT_NV12 },
+ { COLOR_QCOM_FormatYUV420SemiPlanar32m, AV_PIX_FMT_NV12 },
+ { COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka, AV_PIX_FMT_NV12 },
+ { COLOR_TI_FormatYUV420PackedSemiPlanar, AV_PIX_FMT_NV12 },
+ { COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced, AV_PIX_FMT_NV12 },
+ { 0 }
+};
+
+static enum AVPixelFormat mcdec_map_color_format(AVCodecContext *avctx,
+ MediaCodecDecContext *s,
+ int color_format)
+{
+ int i;
+ enum AVPixelFormat ret = AV_PIX_FMT_NONE;
+
+ if (s->surface) {
+ return AV_PIX_FMT_MEDIACODEC;
+ }
+
+ if (!strcmp(s->codec_name, "OMX.k3.video.decoder.avc") && color_format == COLOR_FormatYCbYCr) {
+ s->color_format = color_format = COLOR_TI_FormatYUV420PackedSemiPlanar;
+ }
+
+ for (i = 0; i < FF_ARRAY_ELEMS(color_formats); i++) {
+ if (color_formats[i].color_format == color_format) {
+ return color_formats[i].pix_fmt;
+ }
+ }
+
+ av_log(avctx, AV_LOG_ERROR, "Output color format 0x%x (value=%d) is not supported\n",
+ color_format, color_format);
+
+ return ret;
+}
+
+static void ff_mediacodec_dec_ref(MediaCodecDecContext *s)
+{
+ avpriv_atomic_int_add_and_fetch(&s->refcount, 1);
+}
+
+static void ff_mediacodec_dec_unref(MediaCodecDecContext *s)
+{
+ if (!s)
+ return;
+
+ if (!avpriv_atomic_int_add_and_fetch(&s->refcount, -1)) {
+ if (s->codec) {
+ ff_AMediaCodec_delete(s->codec);
+ s->codec = NULL;
+ }
+
+ if (s->format) {
+ ff_AMediaFormat_delete(s->format);
+ s->format = NULL;
+ }
+
+ if (s->surface) {
+ ff_mediacodec_surface_unref(s->surface, NULL);
+ s->surface = NULL;
+ }
+
+ av_freep(&s->codec_name);
+ av_freep(&s);
+ }
+}
+
+static void mediacodec_buffer_release(void *opaque, uint8_t *data)
+{
+ AVMediaCodecBuffer *buffer = opaque;
+ MediaCodecDecContext *ctx = buffer->ctx;
+ int released = avpriv_atomic_int_get(&buffer->released);
+
+ if (!released) {
+ ff_AMediaCodec_releaseOutputBuffer(ctx->codec, buffer->index, 0);
+ }
+
+ ff_mediacodec_dec_unref(ctx);
+ av_freep(&buffer);
+}
+
+static int mediacodec_wrap_hw_buffer(AVCodecContext *avctx,
+ MediaCodecDecContext *s,
+ ssize_t index,
+ FFAMediaCodecBufferInfo *info,
+ AVFrame *frame)
+{
+ int ret = 0;
+ int status = 0;
+ AVMediaCodecBuffer *buffer = NULL;
+
+ frame->buf[0] = NULL;
+ frame->width = avctx->width;
+ frame->height = avctx->height;
+ frame->format = avctx->pix_fmt;
+
+ if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) {
- frame->pkt_pts = av_rescale_q(info->presentationTimeUs,
++ frame->pts = av_rescale_q(info->presentationTimeUs,
+ av_make_q(1, 1000000),
+ avctx->pkt_timebase);
+ } else {
- frame->pkt_pts = info->presentationTimeUs;
++ frame->pts = info->presentationTimeUs;
+ }
++#if FF_API_PKT_PTS
++FF_DISABLE_DEPRECATION_WARNINGS
++ frame->pkt_pts = frame->pts;
++FF_ENABLE_DEPRECATION_WARNINGS
++#endif
+ frame->pkt_dts = AV_NOPTS_VALUE;
+
+ buffer = av_mallocz(sizeof(AVMediaCodecBuffer));
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ buffer->released = 0;
+
+ frame->buf[0] = av_buffer_create(NULL,
+ 0,
+ mediacodec_buffer_release,
+ buffer,
+ AV_BUFFER_FLAG_READONLY);
+
+ if (!frame->buf[0]) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+
+ }
+
+ buffer->ctx = s;
+ ff_mediacodec_dec_ref(s);
+
+ buffer->index = index;
+ buffer->pts = info->presentationTimeUs;
+
+ frame->data[3] = (uint8_t *)buffer;
+
+ return 0;
+fail:
+ av_freep(buffer);
+ av_buffer_unref(&frame->buf[0]);
+ status = ff_AMediaCodec_releaseOutputBuffer(s->codec, index, 0);
+ if (status < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to release output buffer\n");
+ ret = AVERROR_EXTERNAL;
+ }
+
+ return ret;
+}
+
+static int mediacodec_wrap_sw_buffer(AVCodecContext *avctx,
+ MediaCodecDecContext *s,
+ uint8_t *data,
+ size_t size,
+ ssize_t index,
+ FFAMediaCodecBufferInfo *info,
+ AVFrame *frame)
+{
+ int ret = 0;
+ int status = 0;
+
+ frame->width = avctx->width;
+ frame->height = avctx->height;
+ frame->format = avctx->pix_fmt;
+
+ /* MediaCodec buffers needs to be copied to our own refcounted buffers
+ * because the flush command invalidates all input and output buffers.
+ */
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer\n");
+ goto done;
+ }
+
+ /* Override frame->pkt_pts as ff_get_buffer will override its value based
+ * on the last avpacket received which is not in sync with the frame:
+ * * N avpackets can be pushed before 1 frame is actually returned
+ * * 0-sized avpackets are pushed to flush remaining frames at EOS */
++ frame->pts = info->presentationTimeUs;
++#if FF_API_PKT_PTS
++FF_DISABLE_DEPRECATION_WARNINGS
+ frame->pkt_pts = info->presentationTimeUs;
++FF_ENABLE_DEPRECATION_WARNINGS
++#endif
+ frame->pkt_dts = AV_NOPTS_VALUE;
+
+ av_log(avctx, AV_LOG_DEBUG,
+ "Frame: width=%d stride=%d height=%d slice-height=%d "
+ "crop-top=%d crop-bottom=%d crop-left=%d crop-right=%d encoder=%s\n"
+ "destination linesizes=%d,%d,%d\n" ,
+ avctx->width, s->stride, avctx->height, s->slice_height,
+ s->crop_top, s->crop_bottom, s->crop_left, s->crop_right, s->codec_name,
+ frame->linesize[0], frame->linesize[1], frame->linesize[2]);
+
+ switch (s->color_format) {
+ case COLOR_FormatYUV420Planar:
+ ff_mediacodec_sw_buffer_copy_yuv420_planar(avctx, s, data, size, info, frame);
+ break;
+ case COLOR_FormatYUV420SemiPlanar:
+ case COLOR_QCOM_FormatYUV420SemiPlanar:
+ case COLOR_QCOM_FormatYUV420SemiPlanar32m:
+ ff_mediacodec_sw_buffer_copy_yuv420_semi_planar(avctx, s, data, size, info, frame);
+ break;
+ case COLOR_TI_FormatYUV420PackedSemiPlanar:
+ case COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced:
+ ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar(avctx, s, data, size, info, frame);
+ break;
+ case COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka:
+ ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar_64x32Tile2m8ka(avctx, s, data, size, info, frame);
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unsupported color format 0x%x (value=%d)\n",
+ s->color_format, s->color_format);
+ ret = AVERROR(EINVAL);
+ goto done;
+ }
+
+ ret = 0;
+done:
+ status = ff_AMediaCodec_releaseOutputBuffer(s->codec, index, 0);
+ if (status < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to release output buffer\n");
+ ret = AVERROR_EXTERNAL;
+ }
+
+ return ret;
+}
+
+static int mediacodec_dec_parse_format(AVCodecContext *avctx, MediaCodecDecContext *s)
+{
+ int width = 0;
+ int height = 0;
+ int32_t value = 0;
+ char *format = NULL;
+
+ if (!s->format) {
+ av_log(avctx, AV_LOG_ERROR, "Output MediaFormat is not set\n");
+ return AVERROR(EINVAL);
+ }
+
+ format = ff_AMediaFormat_toString(s->format);
+ if (!format) {
+ return AVERROR_EXTERNAL;
+ }
+ av_log(avctx, AV_LOG_DEBUG, "Parsing MediaFormat %s\n", format);
+ av_freep(&format);
+
+ /* Mandatory fields */
+ if (!ff_AMediaFormat_getInt32(s->format, "width", &value)) {
+ format = ff_AMediaFormat_toString(s->format);
+ av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "width", format);
+ av_freep(&format);
+ return AVERROR_EXTERNAL;
+ }
+ s->width = value;
+
+ if (!ff_AMediaFormat_getInt32(s->format, "height", &value)) {
+ format = ff_AMediaFormat_toString(s->format);
+ av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "height", format);
+ av_freep(&format);
+ return AVERROR_EXTERNAL;
+ }
+ s->height = value;
+
+ if (!ff_AMediaFormat_getInt32(s->format, "stride", &value)) {
+ format = ff_AMediaFormat_toString(s->format);
+ av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "stride", format);
+ av_freep(&format);
+ return AVERROR_EXTERNAL;
+ }
+ s->stride = value > 0 ? value : s->width;
+
+ if (!ff_AMediaFormat_getInt32(s->format, "slice-height", &value)) {
+ format = ff_AMediaFormat_toString(s->format);
+ av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "slice-height", format);
+ av_freep(&format);
+ return AVERROR_EXTERNAL;
+ }
+ s->slice_height = value > 0 ? value : s->height;
+
+ if (strstr(s->codec_name, "OMX.Nvidia.")) {
+ s->slice_height = FFALIGN(s->height, 16);
+ } else if (strstr(s->codec_name, "OMX.SEC.avc.dec")) {
+ s->slice_height = avctx->height;
+ s->stride = avctx->width;
+ }
+
+ if (!ff_AMediaFormat_getInt32(s->format, "color-format", &value)) {
+ format = ff_AMediaFormat_toString(s->format);
+ av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "color-format", format);
+ av_freep(&format);
+ return AVERROR_EXTERNAL;
+ }
+ s->color_format = value;
+
+ s->pix_fmt = avctx->pix_fmt = mcdec_map_color_format(avctx, s, value);
+ if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
+ av_log(avctx, AV_LOG_ERROR, "Output color format is not supported\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* Optional fields */
+ if (ff_AMediaFormat_getInt32(s->format, "crop-top", &value))
+ s->crop_top = value;
+
+ if (ff_AMediaFormat_getInt32(s->format, "crop-bottom", &value))
+ s->crop_bottom = value;
+
+ if (ff_AMediaFormat_getInt32(s->format, "crop-left", &value))
+ s->crop_left = value;
+
+ if (ff_AMediaFormat_getInt32(s->format, "crop-right", &value))
+ s->crop_right = value;
+
+ width = s->crop_right + 1 - s->crop_left;
+ height = s->crop_bottom + 1 - s->crop_top;
+
+ av_log(avctx, AV_LOG_INFO,
+ "Output crop parameters top=%d bottom=%d left=%d right=%d, "
+ "resulting dimensions width=%d height=%d\n",
+ s->crop_top, s->crop_bottom, s->crop_left, s->crop_right,
+ width, height);
+
+ return ff_set_dimensions(avctx, width, height);
+}
+
+
+static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContext *s)
+{
+ FFAMediaCodec *codec = s->codec;
+ int status;
+
+ s->dequeued_buffer_nb = 0;
+
+ s->draining = 0;
+ s->flushing = 0;
+ s->eos = 0;
+
+ status = ff_AMediaCodec_flush(codec);
+ if (status < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to flush codec\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ s->first_buffer = 0;
+ s->first_buffer_at = av_gettime();
+
+ return 0;
+}
+
+int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
+ const char *mime, FFAMediaFormat *format)
+{
+ int ret = 0;
+ int status;
+ int profile;
+
+ enum AVPixelFormat pix_fmt;
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_MEDIACODEC,
+ AV_PIX_FMT_NONE,
+ };
+
+ s->first_buffer_at = av_gettime();
+ s->refcount = 1;
+
+ pix_fmt = ff_get_format(avctx, pix_fmts);
+ if (pix_fmt == AV_PIX_FMT_MEDIACODEC) {
+ AVMediaCodecContext *user_ctx = avctx->hwaccel_context;
+
+ if (user_ctx && user_ctx->surface) {
+ s->surface = ff_mediacodec_surface_ref(user_ctx->surface, avctx);
+ av_log(avctx, AV_LOG_INFO, "Using surface %p\n", s->surface);
+ }
+ }
+
+ profile = ff_AMediaCodecProfile_getProfileFromAVCodecContext(avctx);
+ if (profile < 0) {
+ av_log(avctx, AV_LOG_WARNING, "Unsupported or unknown profile");
+ }
+
+ s->codec_name = ff_AMediaCodecList_getCodecNameByType(mime, profile, 0, avctx);
+ if (!s->codec_name) {
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "Found decoder %s\n", s->codec_name);
+ s->codec = ff_AMediaCodec_createCodecByName(s->codec_name);
+ if (!s->codec) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to create media decoder for type %s and name %s\n", mime, s->codec_name);
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ status = ff_AMediaCodec_configure(s->codec, format, s->surface, NULL, 0);
+ if (status < 0) {
+ char *desc = ff_AMediaFormat_toString(format);
+ av_log(avctx, AV_LOG_ERROR,
+ "Failed to configure codec (status = %d) with format %s\n",
+ status, desc);
+ av_freep(&desc);
+
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ status = ff_AMediaCodec_start(s->codec);
+ if (status < 0) {
+ char *desc = ff_AMediaFormat_toString(format);
+ av_log(avctx, AV_LOG_ERROR,
+ "Failed to start codec (status = %d) with format %s\n",
+ status, desc);
+ av_freep(&desc);
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ s->format = ff_AMediaCodec_getOutputFormat(s->codec);
+ if (s->format) {
+ if ((ret = mediacodec_dec_parse_format(avctx, s)) < 0) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Failed to configure context\n");
+ goto fail;
+ }
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "MediaCodec %p started successfully\n", s->codec);
+
+ return 0;
+
+fail:
+ av_log(avctx, AV_LOG_ERROR, "MediaCodec %p failed to start\n", s->codec);
+ ff_mediacodec_dec_close(avctx, s);
+ return ret;
+}
+
+int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s,
+ AVFrame *frame, int *got_frame,
+ AVPacket *pkt)
+{
+ int ret;
+ int offset = 0;
+ int need_draining = 0;
+ uint8_t *data;
+ ssize_t index;
+ size_t size;
+ FFAMediaCodec *codec = s->codec;
+ FFAMediaCodecBufferInfo info = { 0 };
+
+ int status;
+
+ int64_t input_dequeue_timeout_us = INPUT_DEQUEUE_TIMEOUT_US;
+ int64_t output_dequeue_timeout_us = OUTPUT_DEQUEUE_TIMEOUT_US;
+
+ if (s->flushing) {
+ av_log(avctx, AV_LOG_ERROR, "Decoder is flushing and cannot accept new buffer "
+ "until all output buffers have been released\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ if (pkt->size == 0) {
+ need_draining = 1;
+ }
+
+ if (s->draining && s->eos) {
+ return 0;
+ }
+
+ while (offset < pkt->size || (need_draining && !s->draining)) {
+
+ index = ff_AMediaCodec_dequeueInputBuffer(codec, input_dequeue_timeout_us);
+ if (ff_AMediaCodec_infoTryAgainLater(codec, index)) {
+ break;
+ }
+
+ if (index < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to dequeue input buffer (status=%zd)\n", index);
+ return AVERROR_EXTERNAL;
+ }
+
+ data = ff_AMediaCodec_getInputBuffer(codec, index, &size);
+ if (!data) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to get input buffer\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ if (need_draining) {
+ int64_t pts = pkt->pts;
+ uint32_t flags = ff_AMediaCodec_getBufferFlagEndOfStream(codec);
+
+ if (s->surface) {
+ pts = av_rescale_q(pts, avctx->pkt_timebase, av_make_q(1, 1000000));
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "Sending End Of Stream signal\n");
+
+ status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, 0, pts, flags);
+ if (status < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to queue input empty buffer (status = %d)\n", status);
+ return AVERROR_EXTERNAL;
+ }
+
+ s->draining = 1;
+ break;
+ } else {
+ int64_t pts = pkt->pts;
+
+ size = FFMIN(pkt->size - offset, size);
+
+ memcpy(data, pkt->data + offset, size);
+ offset += size;
+
+ if (s->surface && avctx->pkt_timebase.num && avctx->pkt_timebase.den) {
+ pts = av_rescale_q(pts, avctx->pkt_timebase, av_make_q(1, 1000000));
+ }
+
+ status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, size, pts, 0);
+ if (status < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to queue input buffer (status = %d)\n", status);
+ return AVERROR_EXTERNAL;
+ }
+ }
+ }
+
+ if (need_draining || s->draining) {
+ /* If the codec is flushing or need to be flushed, block for a fair
+ * amount of time to ensure we got a frame */
+ output_dequeue_timeout_us = OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US;
+ } else if (s->dequeued_buffer_nb == 0) {
+ /* If the codec hasn't produced any frames, do not block so we
+ * can push data to it as fast as possible, and get the first
+ * frame */
+ output_dequeue_timeout_us = 0;
+ }
+
+ index = ff_AMediaCodec_dequeueOutputBuffer(codec, &info, output_dequeue_timeout_us);
+ if (index >= 0) {
+ int ret;
+
+ if (!s->first_buffer++) {
+ av_log(avctx, AV_LOG_DEBUG, "Got first buffer after %fms\n", (av_gettime() - s->first_buffer_at) / 1000);
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "Got output buffer %zd"
+ " offset=%" PRIi32 " size=%" PRIi32 " ts=%" PRIi64
+ " flags=%" PRIu32 "\n", index, info.offset, info.size,
+ info.presentationTimeUs, info.flags);
+
+ if (info.flags & ff_AMediaCodec_getBufferFlagEndOfStream(codec)) {
+ s->eos = 1;
+ }
+
+ if (info.size) {
+ if (s->surface) {
+ if ((ret = mediacodec_wrap_hw_buffer(avctx, s, index, &info, frame)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to wrap MediaCodec buffer\n");
+ return ret;
+ }
+ } else {
+ data = ff_AMediaCodec_getOutputBuffer(codec, index, &size);
+ if (!data) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to get output buffer\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ if ((ret = mediacodec_wrap_sw_buffer(avctx, s, data, size, index, &info, frame)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to wrap MediaCodec buffer\n");
+ return ret;
+ }
+ }
+
+ *got_frame = 1;
+ s->dequeued_buffer_nb++;
+ } else {
+ status = ff_AMediaCodec_releaseOutputBuffer(codec, index, 0);
+ if (status < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to release output buffer\n");
+ }
+ }
+
+ } else if (ff_AMediaCodec_infoOutputFormatChanged(codec, index)) {
+ char *format = NULL;
+
+ if (s->format) {
+ status = ff_AMediaFormat_delete(s->format);
+ if (status < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to delete MediaFormat %p\n", s->format);
+ }
+ }
+
+ s->format = ff_AMediaCodec_getOutputFormat(codec);
+ if (!s->format) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to get output format\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ format = ff_AMediaFormat_toString(s->format);
+ if (!format) {
+ return AVERROR_EXTERNAL;
+ }
+ av_log(avctx, AV_LOG_INFO, "Output MediaFormat changed to %s\n", format);
+ av_freep(&format);
+
+ if ((ret = mediacodec_dec_parse_format(avctx, s)) < 0) {
+ return ret;
+ }
+
+ } else if (ff_AMediaCodec_infoOutputBuffersChanged(codec, index)) {
+ ff_AMediaCodec_cleanOutputBuffers(codec);
+ } else if (ff_AMediaCodec_infoTryAgainLater(codec, index)) {
+ if (s->draining) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to dequeue output buffer within %" PRIi64 "ms "
+ "while draining remaining frames, output will probably lack frames\n",
+ output_dequeue_timeout_us / 1000);
+ } else {
+ av_log(avctx, AV_LOG_DEBUG, "No output buffer available, try again later\n");
+ }
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Failed to dequeue output buffer (status=%zd)\n", index);
+ return AVERROR_EXTERNAL;
+ }
+
+ return offset;
+}
+
+int ff_mediacodec_dec_flush(AVCodecContext *avctx, MediaCodecDecContext *s)
+{
+ if (!s->surface || avpriv_atomic_int_get(&s->refcount) == 1) {
+ int ret;
+
+ /* No frames (holding a reference to the codec) are retained by the
+ * user, thus we can flush the codec and returns accordingly */
+ if ((ret = mediacodec_dec_flush_codec(avctx, s)) < 0) {
+ return ret;
+ }
+
+ return 1;
+ }
+
+ s->flushing = 1;
+ return 0;
+}
+
+int ff_mediacodec_dec_close(AVCodecContext *avctx, MediaCodecDecContext *s)
+{
+ ff_mediacodec_dec_unref(s);
+
+ return 0;
+}
+
+int ff_mediacodec_dec_is_flushing(AVCodecContext *avctx, MediaCodecDecContext *s)
+{
+ return s->flushing;
+}
+
+AVHWAccel ff_h264_mediacodec_hwaccel = {
+ .name = "mediacodec",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .pix_fmt = AV_PIX_FMT_MEDIACODEC,
+};
+
+AVHWAccel ff_hevc_mediacodec_hwaccel = {
+ .name = "mediacodec",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_HEVC,
+ .pix_fmt = AV_PIX_FMT_MEDIACODEC,
+};
diff --cc libavcodec/utils.c
index 1239d49,bc1beee..be1686e
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@@ -760,61 -537,68 +760,71 @@@ int ff_init_buffer_info(AVCodecContext
enum AVPacketSideDataType packet;
enum AVFrameSideDataType frame;
} sd[] = {
- { AV_PKT_DATA_REPLAYGAIN , AV_FRAME_DATA_REPLAYGAIN },
- { AV_PKT_DATA_DISPLAYMATRIX, AV_FRAME_DATA_DISPLAYMATRIX },
- { AV_PKT_DATA_STEREO3D, AV_FRAME_DATA_STEREO3D },
- { AV_PKT_DATA_AUDIO_SERVICE_TYPE, AV_FRAME_DATA_AUDIO_SERVICE_TYPE },
+ { AV_PKT_DATA_REPLAYGAIN , AV_FRAME_DATA_REPLAYGAIN },
+ { AV_PKT_DATA_DISPLAYMATRIX, AV_FRAME_DATA_DISPLAYMATRIX },
+ { AV_PKT_DATA_STEREO3D, AV_FRAME_DATA_STEREO3D },
+ { AV_PKT_DATA_AUDIO_SERVICE_TYPE, AV_FRAME_DATA_AUDIO_SERVICE_TYPE },
+ { AV_PKT_DATA_MASTERING_DISPLAY_METADATA, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA },
};
- frame->color_primaries = avctx->color_primaries;
- frame->color_trc = avctx->color_trc;
- frame->colorspace = avctx->colorspace;
- frame->color_range = avctx->color_range;
- frame->chroma_location = avctx->chroma_sample_location;
-
- frame->reordered_opaque = avctx->reordered_opaque;
- if (!pkt) {
+ if (pkt) {
++ frame->pts = pkt->pts;
+ #if FF_API_PKT_PTS
+ FF_DISABLE_DEPRECATION_WARNINGS
- frame->pkt_pts = AV_NOPTS_VALUE;
+ frame->pkt_pts = pkt->pts;
+ FF_ENABLE_DEPRECATION_WARNINGS
+ #endif
- frame->pts = AV_NOPTS_VALUE;
- return 0;
- }
+ av_frame_set_pkt_pos (frame, pkt->pos);
+ av_frame_set_pkt_duration(frame, pkt->duration);
+ av_frame_set_pkt_size (frame, pkt->size);
+
+ for (i = 0; i < FF_ARRAY_ELEMS(sd); i++) {
+ int size;
+ uint8_t *packet_sd = av_packet_get_side_data(pkt, sd[i].packet, &size);
+ if (packet_sd) {
+ AVFrameSideData *frame_sd = av_frame_new_side_data(frame,
+ sd[i].frame,
+ size);
+ if (!frame_sd)
+ return AVERROR(ENOMEM);
+
+ memcpy(frame_sd->data, packet_sd, size);
+ }
+ }
+ add_metadata_from_side_data(pkt, frame);
+ if (pkt->flags & AV_PKT_FLAG_DISCARD) {
+ frame->flags |= AV_FRAME_FLAG_DISCARD;
+ } else {
+ frame->flags = (frame->flags & ~AV_FRAME_FLAG_DISCARD);
+ }
+ } else {
++ frame->pts = AV_NOPTS_VALUE;
+ #if FF_API_PKT_PTS
+ FF_DISABLE_DEPRECATION_WARNINGS
- frame->pkt_pts = pkt->pts;
+ frame->pkt_pts = AV_NOPTS_VALUE;
+ FF_ENABLE_DEPRECATION_WARNINGS
+ #endif
- frame->pts = pkt->pts;
-
- for (i = 0; i < FF_ARRAY_ELEMS(sd); i++) {
- int size;
- uint8_t *packet_sd = av_packet_get_side_data(pkt, sd[i].packet, &size);
- if (packet_sd) {
- AVFrameSideData *frame_sd = av_frame_new_side_data(frame,
- sd[i].frame,
- size);
- if (!frame_sd)
- return AVERROR(ENOMEM);
-
- memcpy(frame_sd->data, packet_sd, size);
- }
+ av_frame_set_pkt_pos (frame, -1);
+ av_frame_set_pkt_duration(frame, 0);
+ av_frame_set_pkt_size (frame, -1);
}
+ frame->reordered_opaque = avctx->reordered_opaque;
- return 0;
-}
-
-int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
-{
- const AVHWAccel *hwaccel = avctx->hwaccel;
- int override_dimensions = 1;
- int ret;
-
- switch (avctx->codec_type) {
+ if (frame->color_primaries == AVCOL_PRI_UNSPECIFIED)
+ frame->color_primaries = avctx->color_primaries;
+ if (frame->color_trc == AVCOL_TRC_UNSPECIFIED)
+ frame->color_trc = avctx->color_trc;
+ if (av_frame_get_colorspace(frame) == AVCOL_SPC_UNSPECIFIED)
+ av_frame_set_colorspace(frame, avctx->colorspace);
+ if (av_frame_get_color_range(frame) == AVCOL_RANGE_UNSPECIFIED)
+ av_frame_set_color_range(frame, avctx->color_range);
+ if (frame->chroma_location == AVCHROMA_LOC_UNSPECIFIED)
+ frame->chroma_location = avctx->chroma_sample_location;
+
+ switch (avctx->codec->type) {
case AVMEDIA_TYPE_VIDEO:
- if (frame->width <= 0 || frame->height <= 0) {
- frame->width = FFMAX(avctx->width, avctx->coded_width);
- frame->height = FFMAX(avctx->height, avctx->coded_height);
- override_dimensions = 0;
- }
- if (frame->format < 0)
- frame->format = avctx->pix_fmt;
+ frame->format = avctx->pix_fmt;
if (!frame->sample_aspect_ratio.num)
frame->sample_aspect_ratio = avctx->sample_aspect_ratio;
@@@ -2037,42 -1431,6 +2047,42 @@@ int avcodec_encode_subtitle(AVCodecCont
return ret;
}
+/**
+ * Attempt to guess proper monotonic timestamps for decoded video frames
+ * which might have incorrect times. Input timestamps may wrap around, in
+ * which case the output will as well.
+ *
+ * @param pts the pts field of the decoded AVPacket, as passed through
- * AVFrame.pkt_pts
++ * AVFrame.pts
+ * @param dts the dts field of the decoded AVPacket
+ * @return one of the input values, may be AV_NOPTS_VALUE
+ */
+static int64_t guess_correct_pts(AVCodecContext *ctx,
+ int64_t reordered_pts, int64_t dts)
+{
+ int64_t pts = AV_NOPTS_VALUE;
+
+ if (dts != AV_NOPTS_VALUE) {
+ ctx->pts_correction_num_faulty_dts += dts <= ctx->pts_correction_last_dts;
+ ctx->pts_correction_last_dts = dts;
+ } else if (reordered_pts != AV_NOPTS_VALUE)
+ ctx->pts_correction_last_dts = reordered_pts;
+
+ if (reordered_pts != AV_NOPTS_VALUE) {
+ ctx->pts_correction_num_faulty_pts += reordered_pts <= ctx->pts_correction_last_pts;
+ ctx->pts_correction_last_pts = reordered_pts;
+ } else if(dts != AV_NOPTS_VALUE)
+ ctx->pts_correction_last_pts = dts;
+
+ if ((ctx->pts_correction_num_faulty_pts<=ctx->pts_correction_num_faulty_dts || dts == AV_NOPTS_VALUE)
+ && reordered_pts != AV_NOPTS_VALUE)
+ pts = reordered_pts;
+ else
+ pts = dts;
+
+ return pts;
+}
+
static int apply_param_change(AVCodecContext *avctx, AVPacket *avpkt)
{
int size = 0, ret;
@@@ -2279,193 -1593,15 +2289,199 @@@ fail
}
avctx->frame_number++;
+ av_frame_set_best_effort_timestamp(picture,
+ guess_correct_pts(avctx,
- picture->pkt_pts,
++ picture->pts,
+ picture->pkt_dts));
+ } else
+ av_frame_unref(picture);
+ } else
+ ret = 0;
+
+ /* many decoders assign whole AVFrames, thus overwriting extended_data;
+ * make sure it's set correctly */
+ av_assert0(!picture->extended_data || picture->extended_data == picture->data);
+
+#if FF_API_AVCTX_TIMEBASE
+ if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
+ avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1}));
+#endif
+
+ return ret;
+}
+
+int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
+ AVFrame *frame,
+ int *got_frame_ptr,
+ const AVPacket *avpkt)
+{
+ AVCodecInternal *avci = avctx->internal;
+ int ret = 0;
+
+ *got_frame_ptr = 0;
+
+ if (!avctx->codec)
+ return AVERROR(EINVAL);
+
+ if (!avctx->codec->decode) {
+ av_log(avctx, AV_LOG_ERROR, "This decoder requires using the avcodec_send_packet() API.\n");
+ return AVERROR(ENOSYS);
+ }
+
+ if (!avpkt->data && avpkt->size) {
+ av_log(avctx, AV_LOG_ERROR, "invalid packet: NULL data, size != 0\n");
+ return AVERROR(EINVAL);
+ }
+ if (avctx->codec->type != AVMEDIA_TYPE_AUDIO) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid media type for audio\n");
+ return AVERROR(EINVAL);
+ }
+
+ av_frame_unref(frame);
+
+ if ((avctx->codec->capabilities & AV_CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {
+ uint8_t *side;
+ int side_size;
+ uint32_t discard_padding = 0;
+ uint8_t skip_reason = 0;
+ uint8_t discard_reason = 0;
+ // copy to ensure we do not change avpkt
+ AVPacket tmp = *avpkt;
+ int did_split = av_packet_split_side_data(&tmp);
+ ret = apply_param_change(avctx, &tmp);
+ if (ret < 0)
+ goto fail;
+
+ avctx->internal->pkt = &tmp;
+ if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
+ ret = ff_thread_decode_frame(avctx, frame, got_frame_ptr, &tmp);
+ else {
+ ret = avctx->codec->decode(avctx, frame, got_frame_ptr, &tmp);
+ av_assert0(ret <= tmp.size);
+ frame->pkt_dts = avpkt->dts;
+ }
+ if (ret >= 0 && *got_frame_ptr) {
+ avctx->frame_number++;
+ av_frame_set_best_effort_timestamp(frame,
+ guess_correct_pts(avctx,
- frame->pkt_pts,
++ frame->pts,
+ frame->pkt_dts));
+ if (frame->format == AV_SAMPLE_FMT_NONE)
+ frame->format = avctx->sample_fmt;
+ if (!frame->channel_layout)
+ frame->channel_layout = avctx->channel_layout;
+ if (!av_frame_get_channels(frame))
+ av_frame_set_channels(frame, avctx->channels);
+ if (!frame->sample_rate)
+ frame->sample_rate = avctx->sample_rate;
+ }
+
+ side= av_packet_get_side_data(avctx->internal->pkt, AV_PKT_DATA_SKIP_SAMPLES, &side_size);
+ if(side && side_size>=10) {
+ avctx->internal->skip_samples = AV_RL32(side);
+ discard_padding = AV_RL32(side + 4);
+ av_log(avctx, AV_LOG_DEBUG, "skip %d / discard %d samples due to side data\n",
+ avctx->internal->skip_samples, (int)discard_padding);
+ skip_reason = AV_RL8(side + 8);
+ discard_reason = AV_RL8(side + 9);
+ }
+
+ if ((frame->flags & AV_FRAME_FLAG_DISCARD) && *got_frame_ptr &&
+ !(avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL)) {
+ avctx->internal->skip_samples -= frame->nb_samples;
+ *got_frame_ptr = 0;
+ }
+
+ if (avctx->internal->skip_samples > 0 && *got_frame_ptr &&
+ !(avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL)) {
+ if(frame->nb_samples <= avctx->internal->skip_samples){
+ *got_frame_ptr = 0;
+ avctx->internal->skip_samples -= frame->nb_samples;
+ av_log(avctx, AV_LOG_DEBUG, "skip whole frame, skip left: %d\n",
+ avctx->internal->skip_samples);
+ } else {
+ av_samples_copy(frame->extended_data, frame->extended_data, 0, avctx->internal->skip_samples,
+ frame->nb_samples - avctx->internal->skip_samples, avctx->channels, frame->format);
+ if(avctx->pkt_timebase.num && avctx->sample_rate) {
+ int64_t diff_ts = av_rescale_q(avctx->internal->skip_samples,
+ (AVRational){1, avctx->sample_rate},
+ avctx->pkt_timebase);
++ if(frame->pts!=AV_NOPTS_VALUE)
++ frame->pts += diff_ts;
++#if FF_API_PKT_PTS
++FF_DISABLE_DEPRECATION_WARNINGS
+ if(frame->pkt_pts!=AV_NOPTS_VALUE)
+ frame->pkt_pts += diff_ts;
++FF_ENABLE_DEPRECATION_WARNINGS
++#endif
+ if(frame->pkt_dts!=AV_NOPTS_VALUE)
+ frame->pkt_dts += diff_ts;
+ if (av_frame_get_pkt_duration(frame) >= diff_ts)
+ av_frame_set_pkt_duration(frame, av_frame_get_pkt_duration(frame) - diff_ts);
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for skipped samples.\n");
+ }
+ av_log(avctx, AV_LOG_DEBUG, "skip %d/%d samples\n",
+ avctx->internal->skip_samples, frame->nb_samples);
+ frame->nb_samples -= avctx->internal->skip_samples;
+ avctx->internal->skip_samples = 0;
+ }
+ }
+
+ if (discard_padding > 0 && discard_padding <= frame->nb_samples && *got_frame_ptr &&
+ !(avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL)) {
+ if (discard_padding == frame->nb_samples) {
+ *got_frame_ptr = 0;
+ } else {
+ if(avctx->pkt_timebase.num && avctx->sample_rate) {
+ int64_t diff_ts = av_rescale_q(frame->nb_samples - discard_padding,
+ (AVRational){1, avctx->sample_rate},
+ avctx->pkt_timebase);
+ av_frame_set_pkt_duration(frame, diff_ts);
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for discarded samples.\n");
+ }
+ av_log(avctx, AV_LOG_DEBUG, "discard %d/%d samples\n",
+ (int)discard_padding, frame->nb_samples);
+ frame->nb_samples -= discard_padding;
+ }
+ }
+
+ if ((avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL) && *got_frame_ptr) {
+ AVFrameSideData *fside = av_frame_new_side_data(frame, AV_FRAME_DATA_SKIP_SAMPLES, 10);
+ if (fside) {
+ AV_WL32(fside->data, avctx->internal->skip_samples);
+ AV_WL32(fside->data + 4, discard_padding);
+ AV_WL8(fside->data + 8, skip_reason);
+ AV_WL8(fside->data + 9, discard_reason);
+ avctx->internal->skip_samples = 0;
+ }
+ }
+fail:
+ avctx->internal->pkt = NULL;
+ if (did_split) {
+ av_packet_free_side_data(&tmp);
+ if(ret == tmp.size)
+ ret = avpkt->size;
+ }
+
+ if (ret >= 0 && *got_frame_ptr) {
+ if (!avctx->refcounted_frames) {
+ int err = unrefcount_frame(avci, frame);
+ if (err < 0)
+ return err;
+ }
} else
- av_frame_unref(picture);
- } else
- ret = 0;
+ av_frame_unref(frame);
+ }
-#if FF_API_AVCTX_TIMEBASE
- if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
- avctx->time_base = av_inv_q(avctx->framerate);
-#endif
+ av_assert0(ret <= avpkt->size);
+
+ if (!avci->showed_multi_packet_warning &&
+ ret >= 0 && ret != avpkt->size && !(avctx->codec->capabilities & AV_CODEC_CAP_SUBFRAMES)) {
+ av_log(avctx, AV_LOG_WARNING, "Multiple frames in a packet.\n");
+ avci->showed_multi_packet_warning = 1;
+ }
return ret;
}
@@@ -2870,14 -1801,7 +2886,14 @@@ int attribute_align_arg avcodec_receive
if (avctx->codec->receive_frame) {
if (avctx->internal->draining && !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
return AVERROR_EOF;
- return avctx->codec->receive_frame(avctx, frame);
+ ret = avctx->codec->receive_frame(avctx, frame);
+ if (ret >= 0) {
+ if (av_frame_get_best_effort_timestamp(frame) == AV_NOPTS_VALUE) {
+ av_frame_set_best_effort_timestamp(frame,
- guess_correct_pts(avctx, frame->pkt_pts, frame->pkt_dts));
++ guess_correct_pts(avctx, frame->pts, frame->pkt_dts));
+ }
+ }
+ return ret;
}
// Emulation via old API.
diff --cc libavcodec/version.h
index de7280f,3b154f8..9c03364
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@@ -27,9 -27,9 +27,9 @@@
#include "libavutil/version.h"
-#define LIBAVCODEC_VERSION_MAJOR 57
-#define LIBAVCODEC_VERSION_MINOR 24
-#define LIBAVCODEC_VERSION_MICRO 0
+#define LIBAVCODEC_VERSION_MAJOR 57
- #define LIBAVCODEC_VERSION_MINOR 60
- #define LIBAVCODEC_VERSION_MICRO 101
++#define LIBAVCODEC_VERSION_MINOR 61
++#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
diff --cc libavcodec/vp9.c
index cb2a4a2,c11e9b8..779f2d5
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@@ -3969,319 -1213,65 +3969,324 @@@ static av_cold int vp9_decode_free(AVCo
return 0;
}
-static int vp9_decode_packet(AVCodecContext *avctx, void *frame,
- int *got_frame, AVPacket *avpkt)
+
+static int vp9_decode_frame(AVCodecContext *ctx, void *frame,
+ int *got_frame, AVPacket *pkt)
{
- const uint8_t *data = avpkt->data;
- int size = avpkt->size;
- int marker, ret;
-
- /* Read superframe index - this is a collection of individual frames
- * that together lead to one visible frame */
- marker = data[size - 1];
- if ((marker & 0xe0) == 0xc0) {
- int nbytes = 1 + ((marker >> 3) & 0x3);
- int n_frames = 1 + (marker & 0x7);
- int idx_sz = 2 + n_frames * nbytes;
-
- if (size >= idx_sz && data[size - idx_sz] == marker) {
- const uint8_t *idx = data + size + 1 - idx_sz;
-
- while (n_frames--) {
- unsigned sz = AV_RL32(idx);
-
- if (nbytes < 4)
- sz &= (1 << (8 * nbytes)) - 1;
- idx += nbytes;
-
- if (sz > size) {
- av_log(avctx, AV_LOG_ERROR,
- "Superframe packet size too big: %u > %d\n",
- sz, size);
- return AVERROR_INVALIDDATA;
+ const uint8_t *data = pkt->data;
+ int size = pkt->size;
+ VP9Context *s = ctx->priv_data;
+ int res, tile_row, tile_col, i, ref, row, col;
+ int retain_segmap_ref = s->s.frames[REF_FRAME_SEGMAP].segmentation_map &&
+ (!s->s.h.segmentation.enabled || !s->s.h.segmentation.update_map);
+ ptrdiff_t yoff, uvoff, ls_y, ls_uv;
+ AVFrame *f;
+ int bytesperpixel;
+
+ if ((res = decode_frame_header(ctx, data, size, &ref)) < 0) {
+ return res;
+ } else if (res == 0) {
+ if (!s->s.refs[ref].f->buf[0]) {
+ av_log(ctx, AV_LOG_ERROR, "Requested reference %d not available\n", ref);
+ return AVERROR_INVALIDDATA;
+ }
+ if ((res = av_frame_ref(frame, s->s.refs[ref].f)) < 0)
+ return res;
++ ((AVFrame *)frame)->pts = pkt->pts;
++#if FF_API_PKT_PTS
++FF_DISABLE_DEPRECATION_WARNINGS
+ ((AVFrame *)frame)->pkt_pts = pkt->pts;
++FF_ENABLE_DEPRECATION_WARNINGS
++#endif
+ ((AVFrame *)frame)->pkt_dts = pkt->dts;
+ for (i = 0; i < 8; i++) {
+ if (s->next_refs[i].f->buf[0])
+ ff_thread_release_buffer(ctx, &s->next_refs[i]);
+ if (s->s.refs[i].f->buf[0] &&
+ (res = ff_thread_ref_frame(&s->next_refs[i], &s->s.refs[i])) < 0)
+ return res;
+ }
+ *got_frame = 1;
+ return pkt->size;
+ }
+ data += res;
+ size -= res;
+
+ if (!retain_segmap_ref || s->s.h.keyframe || s->s.h.intraonly) {
+ if (s->s.frames[REF_FRAME_SEGMAP].tf.f->buf[0])
+ vp9_unref_frame(ctx, &s->s.frames[REF_FRAME_SEGMAP]);
+ if (!s->s.h.keyframe && !s->s.h.intraonly && !s->s.h.errorres && s->s.frames[CUR_FRAME].tf.f->buf[0] &&
+ (res = vp9_ref_frame(ctx, &s->s.frames[REF_FRAME_SEGMAP], &s->s.frames[CUR_FRAME])) < 0)
+ return res;
+ }
+ if (s->s.frames[REF_FRAME_MVPAIR].tf.f->buf[0])
+ vp9_unref_frame(ctx, &s->s.frames[REF_FRAME_MVPAIR]);
+ if (!s->s.h.intraonly && !s->s.h.keyframe && !s->s.h.errorres && s->s.frames[CUR_FRAME].tf.f->buf[0] &&
+ (res = vp9_ref_frame(ctx, &s->s.frames[REF_FRAME_MVPAIR], &s->s.frames[CUR_FRAME])) < 0)
+ return res;
+ if (s->s.frames[CUR_FRAME].tf.f->buf[0])
+ vp9_unref_frame(ctx, &s->s.frames[CUR_FRAME]);
+ if ((res = vp9_alloc_frame(ctx, &s->s.frames[CUR_FRAME])) < 0)
+ return res;
+ f = s->s.frames[CUR_FRAME].tf.f;
+ f->key_frame = s->s.h.keyframe;
+ f->pict_type = (s->s.h.keyframe || s->s.h.intraonly) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+ ls_y = f->linesize[0];
+ ls_uv =f->linesize[1];
+
+ if (s->s.frames[REF_FRAME_SEGMAP].tf.f->buf[0] &&
+ (s->s.frames[REF_FRAME_MVPAIR].tf.f->width != s->s.frames[CUR_FRAME].tf.f->width ||
+ s->s.frames[REF_FRAME_MVPAIR].tf.f->height != s->s.frames[CUR_FRAME].tf.f->height)) {
+ vp9_unref_frame(ctx, &s->s.frames[REF_FRAME_SEGMAP]);
+ }
+
+ // ref frame setup
+ for (i = 0; i < 8; i++) {
+ if (s->next_refs[i].f->buf[0])
+ ff_thread_release_buffer(ctx, &s->next_refs[i]);
+ if (s->s.h.refreshrefmask & (1 << i)) {
+ res = ff_thread_ref_frame(&s->next_refs[i], &s->s.frames[CUR_FRAME].tf);
+ } else if (s->s.refs[i].f->buf[0]) {
+ res = ff_thread_ref_frame(&s->next_refs[i], &s->s.refs[i]);
+ }
+ if (res < 0)
+ return res;
+ }
+
+ if (ctx->hwaccel) {
+ res = ctx->hwaccel->start_frame(ctx, NULL, 0);
+ if (res < 0)
+ return res;
+ res = ctx->hwaccel->decode_slice(ctx, pkt->data, pkt->size);
+ if (res < 0)
+ return res;
+ res = ctx->hwaccel->end_frame(ctx);
+ if (res < 0)
+ return res;
+ goto finish;
+ }
+
+ // main tile decode loop
+ bytesperpixel = s->bytesperpixel;
+ memset(s->above_partition_ctx, 0, s->cols);
+ memset(s->above_skip_ctx, 0, s->cols);
+ if (s->s.h.keyframe || s->s.h.intraonly) {
+ memset(s->above_mode_ctx, DC_PRED, s->cols * 2);
+ } else {
+ memset(s->above_mode_ctx, NEARESTMV, s->cols);
+ }
+ memset(s->above_y_nnz_ctx, 0, s->sb_cols * 16);
+ memset(s->above_uv_nnz_ctx[0], 0, s->sb_cols * 16 >> s->ss_h);
+ memset(s->above_uv_nnz_ctx[1], 0, s->sb_cols * 16 >> s->ss_h);
+ memset(s->above_segpred_ctx, 0, s->cols);
+ s->pass = s->s.frames[CUR_FRAME].uses_2pass =
+ ctx->active_thread_type == FF_THREAD_FRAME && s->s.h.refreshctx && !s->s.h.parallelmode;
+ if ((res = update_block_buffers(ctx)) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Failed to allocate block buffers\n");
+ return res;
+ }
+ if (s->s.h.refreshctx && s->s.h.parallelmode) {
+ int j, k, l, m;
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 2; j++)
+ for (k = 0; k < 2; k++)
+ for (l = 0; l < 6; l++)
+ for (m = 0; m < 6; m++)
+ memcpy(s->prob_ctx[s->s.h.framectxid].coef[i][j][k][l][m],
+ s->prob.coef[i][j][k][l][m], 3);
+ if (s->s.h.txfmmode == i)
+ break;
+ }
+ s->prob_ctx[s->s.h.framectxid].p = s->prob.p;
+ ff_thread_finish_setup(ctx);
+ } else if (!s->s.h.refreshctx) {
+ ff_thread_finish_setup(ctx);
+ }
+
+ do {
+ yoff = uvoff = 0;
+ s->b = s->b_base;
+ s->block = s->block_base;
+ s->uvblock[0] = s->uvblock_base[0];
+ s->uvblock[1] = s->uvblock_base[1];
+ s->eob = s->eob_base;
+ s->uveob[0] = s->uveob_base[0];
+ s->uveob[1] = s->uveob_base[1];
+
+ for (tile_row = 0; tile_row < s->s.h.tiling.tile_rows; tile_row++) {
+ set_tile_offset(&s->tile_row_start, &s->tile_row_end,
+ tile_row, s->s.h.tiling.log2_tile_rows, s->sb_rows);
+ if (s->pass != 2) {
+ for (tile_col = 0; tile_col < s->s.h.tiling.tile_cols; tile_col++) {
+ int64_t tile_size;
+
+ if (tile_col == s->s.h.tiling.tile_cols - 1 &&
+ tile_row == s->s.h.tiling.tile_rows - 1) {
+ tile_size = size;
+ } else {
+ tile_size = AV_RB32(data);
+ data += 4;
+ size -= 4;
+ }
+ if (tile_size > size) {
+ ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0);
+ return AVERROR_INVALIDDATA;
+ }
+ ff_vp56_init_range_decoder(&s->c_b[tile_col], data, tile_size);
+ if (vp56_rac_get_prob_branchy(&s->c_b[tile_col], 128)) { // marker bit
+ ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0);
+ return AVERROR_INVALIDDATA;
+ }
+ data += tile_size;
+ size -= tile_size;
+ }
+ }
+
+ for (row = s->tile_row_start; row < s->tile_row_end;
+ row += 8, yoff += ls_y * 64, uvoff += ls_uv * 64 >> s->ss_v) {
+ struct VP9Filter *lflvl_ptr = s->lflvl;
+ ptrdiff_t yoff2 = yoff, uvoff2 = uvoff;
+
+ for (tile_col = 0; tile_col < s->s.h.tiling.tile_cols; tile_col++) {
+ set_tile_offset(&s->tile_col_start, &s->tile_col_end,
+ tile_col, s->s.h.tiling.log2_tile_cols, s->sb_cols);
+
+ if (s->pass != 2) {
+ memset(s->left_partition_ctx, 0, 8);
+ memset(s->left_skip_ctx, 0, 8);
+ if (s->s.h.keyframe || s->s.h.intraonly) {
+ memset(s->left_mode_ctx, DC_PRED, 16);
+ } else {
+ memset(s->left_mode_ctx, NEARESTMV, 8);
+ }
+ memset(s->left_y_nnz_ctx, 0, 16);
+ memset(s->left_uv_nnz_ctx, 0, 32);
+ memset(s->left_segpred_ctx, 0, 8);
+
+ memcpy(&s->c, &s->c_b[tile_col], sizeof(s->c));
+ }
+
+ for (col = s->tile_col_start;
+ col < s->tile_col_end;
+ col += 8, yoff2 += 64 * bytesperpixel,
+ uvoff2 += 64 * bytesperpixel >> s->ss_h, lflvl_ptr++) {
+ // FIXME integrate with lf code (i.e. zero after each
+ // use, similar to invtxfm coefficients, or similar)
+ if (s->pass != 1) {
+ memset(lflvl_ptr->mask, 0, sizeof(lflvl_ptr->mask));
+ }
+
+ if (s->pass == 2) {
+ decode_sb_mem(ctx, row, col, lflvl_ptr,
+ yoff2, uvoff2, BL_64X64);
+ } else {
+ decode_sb(ctx, row, col, lflvl_ptr,
+ yoff2, uvoff2, BL_64X64);
+ }
+ }
+ if (s->pass != 2) {
+ memcpy(&s->c_b[tile_col], &s->c, sizeof(s->c));
+ }
+ }
+
+ if (s->pass == 1) {
+ continue;
+ }
+
+ // backup pre-loopfilter reconstruction data for intra
+ // prediction of next row of sb64s
+ if (row + 8 < s->rows) {
+ memcpy(s->intra_pred_data[0],
+ f->data[0] + yoff + 63 * ls_y,
+ 8 * s->cols * bytesperpixel);
+ memcpy(s->intra_pred_data[1],
+ f->data[1] + uvoff + ((64 >> s->ss_v) - 1) * ls_uv,
+ 8 * s->cols * bytesperpixel >> s->ss_h);
+ memcpy(s->intra_pred_data[2],
+ f->data[2] + uvoff + ((64 >> s->ss_v) - 1) * ls_uv,
+ 8 * s->cols * bytesperpixel >> s->ss_h);
+ }
+
+ // loopfilter one row
+ if (s->s.h.filter.level) {
+ yoff2 = yoff;
+ uvoff2 = uvoff;
+ lflvl_ptr = s->lflvl;
+ for (col = 0; col < s->cols;
+ col += 8, yoff2 += 64 * bytesperpixel,
+ uvoff2 += 64 * bytesperpixel >> s->ss_h, lflvl_ptr++) {
+ loopfilter_sb(ctx, lflvl_ptr, row, col, yoff2, uvoff2);
+ }
}
- ret = vp9_decode_frame(avctx, frame, got_frame, data, sz);
- if (ret < 0)
- return ret;
- data += sz;
- size -= sz;
+ // FIXME maybe we can make this more finegrained by running the
+ // loopfilter per-block instead of after each sbrow
+ // In fact that would also make intra pred left preparation easier?
+ ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, row >> 3, 0);
}
- return avpkt->size;
}
+
+ if (s->pass < 2 && s->s.h.refreshctx && !s->s.h.parallelmode) {
+ adapt_probs(s);
+ ff_thread_finish_setup(ctx);
+ }
+ } while (s->pass++ == 1);
+ ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0);
+
+finish:
+ // ref frame setup
+ for (i = 0; i < 8; i++) {
+ if (s->s.refs[i].f->buf[0])
+ ff_thread_release_buffer(ctx, &s->s.refs[i]);
+ if (s->next_refs[i].f->buf[0] &&
+ (res = ff_thread_ref_frame(&s->s.refs[i], &s->next_refs[i])) < 0)
+ return res;
}
- /* If we get here, there was no valid superframe index, i.e. this is just
- * one whole single frame. Decode it as such from the complete input buf. */
- if ((ret = vp9_decode_frame(avctx, frame, got_frame, data, size)) < 0)
- return ret;
- return size;
+ if (!s->s.h.invisible) {
+ if ((res = av_frame_ref(frame, s->s.frames[CUR_FRAME].tf.f)) < 0)
+ return res;
+ *got_frame = 1;
+ }
+
+ return pkt->size;
}
-static av_cold int vp9_decode_free(AVCodecContext *avctx)
+static void vp9_decode_flush(AVCodecContext *ctx)
{
- VP9Context *s = avctx->priv_data;
+ VP9Context *s = ctx->priv_data;
int i;
- for (i = 0; i < FF_ARRAY_ELEMS(s->refs); i++)
- av_frame_free(&s->refs[i]);
+ for (i = 0; i < 3; i++)
+ vp9_unref_frame(ctx, &s->s.frames[i]);
+ for (i = 0; i < 8; i++)
+ ff_thread_release_buffer(ctx, &s->s.refs[i]);
+}
+
+static int init_frames(AVCodecContext *ctx)
+{
+ VP9Context *s = ctx->priv_data;
+ int i;
- av_freep(&s->c_b);
- av_freep(&s->above_partition_ctx);
+ for (i = 0; i < 3; i++) {
+ s->s.frames[i].tf.f = av_frame_alloc();
+ if (!s->s.frames[i].tf.f) {
+ vp9_decode_free(ctx);
+ av_log(ctx, AV_LOG_ERROR, "Failed to allocate frame buffer %d\n", i);
+ return AVERROR(ENOMEM);
+ }
+ }
+ for (i = 0; i < 8; i++) {
+ s->s.refs[i].f = av_frame_alloc();
+ s->next_refs[i].f = av_frame_alloc();
+ if (!s->s.refs[i].f || !s->next_refs[i].f) {
+ vp9_decode_free(ctx);
+ av_log(ctx, AV_LOG_ERROR, "Failed to allocate frame buffer %d\n", i);
+ return AVERROR(ENOMEM);
+ }
+ }
return 0;
}
diff --cc libavutil/frame.c
index 3c74931,1c14f5f..53e6174
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@@ -98,13 -32,7 +98,17 @@@ static void get_frame_defaults(AVFrame
memset(frame, 0, sizeof(*frame));
- frame->pts = AV_NOPTS_VALUE;
+ frame->pts =
- frame->pkt_dts =
++ frame->pkt_dts = AV_NOPTS_VALUE;
++#if FF_API_PKT_PTS
++FF_DISABLE_DEPRECATION_WARNINGS
+ frame->pkt_pts = AV_NOPTS_VALUE;
++FF_ENABLE_DEPRECATION_WARNINGS
++#endif
+ frame->best_effort_timestamp = AV_NOPTS_VALUE;
+ frame->pkt_duration = 0;
+ frame->pkt_pos = -1;
+ frame->pkt_size = -1;
frame->key_frame = 1;
frame->sample_aspect_ratio = (AVRational){ 0, 1 };
frame->format = -1; /* unknown */
@@@ -281,97 -196,6 +285,101 @@@ int av_frame_get_buffer(AVFrame *frame
return AVERROR(EINVAL);
}
+static int frame_copy_props(AVFrame *dst, const AVFrame *src, int force_copy)
+{
+ int i;
+
+ dst->key_frame = src->key_frame;
+ dst->pict_type = src->pict_type;
+ dst->sample_aspect_ratio = src->sample_aspect_ratio;
+ dst->pts = src->pts;
+ dst->repeat_pict = src->repeat_pict;
+ dst->interlaced_frame = src->interlaced_frame;
+ dst->top_field_first = src->top_field_first;
+ dst->palette_has_changed = src->palette_has_changed;
+ dst->sample_rate = src->sample_rate;
+ dst->opaque = src->opaque;
++#if FF_API_PKT_PTS
++FF_DISABLE_DEPRECATION_WARNINGS
+ dst->pkt_pts = src->pkt_pts;
++FF_ENABLE_DEPRECATION_WARNINGS
++#endif
+ dst->pkt_dts = src->pkt_dts;
+ dst->pkt_pos = src->pkt_pos;
+ dst->pkt_size = src->pkt_size;
+ dst->pkt_duration = src->pkt_duration;
+ dst->reordered_opaque = src->reordered_opaque;
+ dst->quality = src->quality;
+ dst->best_effort_timestamp = src->best_effort_timestamp;
+ dst->coded_picture_number = src->coded_picture_number;
+ dst->display_picture_number = src->display_picture_number;
+ dst->flags = src->flags;
+ dst->decode_error_flags = src->decode_error_flags;
+ dst->color_primaries = src->color_primaries;
+ dst->color_trc = src->color_trc;
+ dst->colorspace = src->colorspace;
+ dst->color_range = src->color_range;
+ dst->chroma_location = src->chroma_location;
+
+ av_dict_copy(&dst->metadata, src->metadata, 0);
+
+#if FF_API_ERROR_FRAME
+FF_DISABLE_DEPRECATION_WARNINGS
+ memcpy(dst->error, src->error, sizeof(dst->error));
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+ for (i = 0; i < src->nb_side_data; i++) {
+ const AVFrameSideData *sd_src = src->side_data[i];
+ AVFrameSideData *sd_dst;
+ if ( sd_src->type == AV_FRAME_DATA_PANSCAN
+ && (src->width != dst->width || src->height != dst->height))
+ continue;
+ if (force_copy) {
+ sd_dst = av_frame_new_side_data(dst, sd_src->type,
+ sd_src->size);
+ if (!sd_dst) {
+ wipe_side_data(dst);
+ return AVERROR(ENOMEM);
+ }
+ memcpy(sd_dst->data, sd_src->data, sd_src->size);
+ } else {
+ sd_dst = av_frame_new_side_data(dst, sd_src->type, 0);
+ if (!sd_dst) {
+ wipe_side_data(dst);
+ return AVERROR(ENOMEM);
+ }
+ sd_dst->buf = av_buffer_ref(sd_src->buf);
+ if (!sd_dst->buf) {
+ wipe_side_data(dst);
+ return AVERROR(ENOMEM);
+ }
+ sd_dst->data = sd_dst->buf->data;
+ sd_dst->size = sd_dst->buf->size;
+ }
+ av_dict_copy(&sd_dst->metadata, sd_src->metadata, 0);
+ }
+
+#if FF_API_FRAME_QP
+FF_DISABLE_DEPRECATION_WARNINGS
+ dst->qscale_table = NULL;
+ dst->qstride = 0;
+ dst->qscale_type = 0;
+ av_buffer_unref(&dst->qp_table_buf);
+ if (src->qp_table_buf) {
+ dst->qp_table_buf = av_buffer_ref(src->qp_table_buf);
+ if (dst->qp_table_buf) {
+ dst->qscale_table = dst->qp_table_buf->data;
+ dst->qstride = src->qstride;
+ dst->qscale_type = src->qscale_type;
+ }
+ }
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+ return 0;
+}
+
int av_frame_ref(AVFrame *dst, const AVFrame *src)
{
int i, ret = 0;
diff --cc libavutil/frame.h
index 1e2691e,12624d7..a19da2f
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@@ -267,15 -210,17 +267,19 @@@ typedef struct AVFrame
*/
int64_t pts;
+ #if FF_API_PKT_PTS
/**
* PTS copied from the AVPacket that was decoded to produce this frame.
+ * @deprecated use the pts field instead
*/
+ attribute_deprecated
int64_t pkt_pts;
+ #endif
/**
- * DTS copied from the AVPacket that triggered returning this frame.
+ * DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used)
+ * This is also the Presentation time of this AVFrame calculated from
+ * only AVPacket.dts values without pts values.
*/
int64_t pkt_dts;
diff --cc libavutil/version.h
index 787ba58,40745da..8a41ef6
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@@ -129,9 -99,12 +129,12 @@@
#ifndef FF_API_ERROR_FRAME
#define FF_API_ERROR_FRAME (LIBAVUTIL_VERSION_MAJOR < 56)
#endif
-#ifndef FF_API_VAAPI
-#define FF_API_VAAPI (LIBAVUTIL_VERSION_MAJOR < 56)
+#ifndef FF_API_CRC_BIG_TABLE
+#define FF_API_CRC_BIG_TABLE (LIBAVUTIL_VERSION_MAJOR < 56)
#endif
+ #ifndef FF_API_PKT_PTS
+ #define FF_API_PKT_PTS (LIBAVUTIL_VERSION_MAJOR < 56)
+ #endif
/**
More information about the ffmpeg-cvslog
mailing list