summaryrefslogtreecommitdiff
path: root/libavcodec/crystalhd.c
diff options
context:
space:
mode:
authorPhilip Langdale <philipl@overt.org>2011-03-16 22:27:51 -0700
committerPhilip Langdale <philipl@overt.org>2011-03-26 15:55:47 -0700
commit4ab57cffba1d151898837a9a07a6a72f78716702 (patch)
tree7ed550a817c8b9960962fbb7d45145e8f1c921be /libavcodec/crystalhd.c
parente44073ca5e7143934ffa79d317dc65150db1637c (diff)
CrystalHD: Add heuristics to try and distinguish h.264 PAFF variants.
As previously discussed, the CrystalHD hardware treats some PAFF clips different from others; even when input fields are always in separate packets, the hardware might return a single fieldpair for one clip and individual fields for another. Given the bogus flags set by the hardware, it is impossible to distinguish these two cases without knowing about the current picture and the next one. The hardware can usually provide the picture number of the next picture and when that is available, we can detect the two cases. When it is not available, we have to guess - and find out later if we were right or wrong. With this change, clips will play correctly unless they are PAFF where individual fields are returned *and* no next picture number is available. Generally speaking, the incorrect cases arise in the first couple of seconds of a clip as the delay calibration takes place. Once that's set, things work fine.
Diffstat (limited to 'libavcodec/crystalhd.c')
-rw-r--r--libavcodec/crystalhd.c59
1 files changed, 44 insertions, 15 deletions
diff --git a/libavcodec/crystalhd.c b/libavcodec/crystalhd.c
index 452edeff43..132923cd02 100644
--- a/libavcodec/crystalhd.c
+++ b/libavcodec/crystalhd.c
@@ -506,23 +506,13 @@ static av_cold int init(AVCodecContext *avctx)
}
-/*
- * The CrystalHD doesn't report interlaced H.264 content in a way that allows
- * us to distinguish between specific cases that require different handling.
- * So, for now, we have to hard-code the behaviour we want.
- *
- * Specifically, there are PAFF samples where input is always separate fields
- * but the hardware returns separate fields on one occasion and a field-pair
- * on another. The code assumes the first case and define
- * ASSUME_TWO_INPUTS_ONE_OUTPUT to assume the second case.
- */
-#define ASSUME_TWO_INPUTS_ONE_OUTPUT 0
static inline CopyRet copy_frame(AVCodecContext *avctx,
BC_DTS_PROC_OUT *output,
void *data, int *data_size)
{
BC_STATUS ret;
BC_DTS_STATUS decoder_status;
+ uint8_t confirmed_interlaced;
uint8_t ignore_interlaced;
uint8_t interlaced;
@@ -571,15 +561,47 @@ static inline CopyRet copy_frame(AVCodecContext *avctx,
}
/*
+ * If we're expecting a second field, or we know that the next
+ * picture has the same number as the current picture, then we're
+ * definitely interlaced.
+ *
+ * Note that this test can return false negatives 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)
+ */
+ confirmed_interlaced = ((decoder_status.picNumFlags & ~0x40000000) ==
+ output->PicInfo.picture_number) ||
+ priv->need_second_field;
+
+ /*
+ * If we got a false negative for confirmed_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 progressie frame. Discarding second field\n");
+ /* Returning without providing a picture. */
+ return RET_OK;
+ }
+
+ /*
* Testing has, so far, shown that we can't trust the interlaced flag for
* H.264 content when VDEC_FLAG_UNKNOWN_SRC is set.
*/
ignore_interlaced = avctx->codec->id == CODEC_ID_H264 &&
(output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) &&
(pic_type == 0 || pic_type == PICT_FRAME ||
- ASSUME_TWO_INPUTS_ONE_OUTPUT);
+ !confirmed_interlaced);
interlaced = (output->PicInfo.flags & VDEC_FLAG_INTERLACED_SRC) &&
- !ignore_interlaced;
+ (!ignore_interlaced || confirmed_interlaced);
+
+ if (ignore_interlaced && (decoder_status.picNumFlags & ~0x40000000) == 0) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Next picture number unknown. Assuming progressive frame.\n");
+ }
av_log(avctx, AV_LOG_VERBOSE, "Interlaced state: %d | ignore_interlaced %d\n",
interlaced, ignore_interlaced);
@@ -650,8 +672,15 @@ static inline CopyRet copy_frame(AVCodecContext *avctx,
*(AVFrame *)data = priv->pic;
}
- if (ASSUME_TWO_INPUTS_ONE_OUTPUT &&
- output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) {
+ /*
+ * 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;
}