summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2014-09-27 02:42:30 +0200
committerMichael Niedermayer <michaelni@gmx.at>2014-09-27 02:42:30 +0200
commit01831fd004908f9dbc3777400169505a63a7adef (patch)
tree26be552bd1dced251a55dbcf81d3fb95f30e4273
parenteb1ac04e59cbba7743c10dd5854b6efdfb6a2ebe (diff)
parent1c80c9d7ef809180042257200c7b5f6b81d0b0e2 (diff)
Merge commit '1c80c9d7ef809180042257200c7b5f6b81d0b0e2'
* commit '1c80c9d7ef809180042257200c7b5f6b81d0b0e2': hwaccel: Call ->get_format again if hwaccel init fails Conflicts: libavcodec/utils.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--libavcodec/avcodec.h4
-rw-r--r--libavcodec/utils.c97
2 files changed, 71 insertions, 30 deletions
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index e14abd22df..94e82f73f9 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1480,6 +1480,10 @@ typedef struct AVCodecContext {
* @param fmt is the list of formats which are supported by the codec,
* it is terminated by -1 as 0 is a valid format, the formats are ordered by quality.
* The first is always the native one.
+ * @note The callback may be called again immediately if initialization for
+ * the selected (hardware-accelerated) pixel format failed.
+ * @warning Behavior is undefined if the callback returns a value not
+ * in the fmt list of formats.
* @return the chosen format
* - encoding: unused
* - decoding: Set by user, if not set the native format will be chosen.
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 28c5785398..b27f918105 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -1152,50 +1152,87 @@ static AVHWAccel *find_hwaccel(enum AVCodecID codec_id,
return NULL;
}
+static int setup_hwaccel(AVCodecContext *avctx,
+ const enum AVPixelFormat fmt,
+ const char *name)
+{
+ AVHWAccel *hwa = find_hwaccel(avctx->codec_id, fmt);
+ int ret = 0;
+
+ if (!hwa) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Could not find an AVHWAccel for the pixel format: %s",
+ name);
+ return AVERROR(ENOENT);
+ }
+
+ if (hwa->priv_data_size) {
+ avctx->internal->hwaccel_priv_data = av_mallocz(hwa->priv_data_size);
+ if (!avctx->internal->hwaccel_priv_data)
+ return AVERROR(ENOMEM);
+ }
+
+ if (hwa->init) {
+ ret = hwa->init(avctx);
+ if (ret < 0) {
+ av_freep(&avctx->internal->hwaccel_priv_data);
+ return ret;
+ }
+ }
+
+ avctx->hwaccel = hwa;
+
+ return 0;
+}
int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
{
const AVPixFmtDescriptor *desc;
- enum AVPixelFormat ret = avctx->get_format(avctx, fmt);
+ enum AVPixelFormat *choices;
+ enum AVPixelFormat ret;
+ unsigned n = 0;
+
+ while (fmt[n] != AV_PIX_FMT_NONE)
+ ++n;
- desc = av_pix_fmt_desc_get(ret);
- if (!desc)
+ choices = av_malloc_array(n + 1, sizeof(*choices));
+ if (!choices)
return AV_PIX_FMT_NONE;
- if (avctx->hwaccel && avctx->hwaccel->uninit)
- avctx->hwaccel->uninit(avctx);
- av_freep(&avctx->internal->hwaccel_priv_data);
- avctx->hwaccel = NULL;
+ memcpy(choices, fmt, (n + 1) * sizeof(*choices));
- if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL &&
- !(avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)) {
- AVHWAccel *hwaccel;
- int err;
+ for (;;) {
+ ret = avctx->get_format(avctx, choices);
- hwaccel = find_hwaccel(avctx->codec_id, ret);
- if (!hwaccel) {
- av_log(avctx, AV_LOG_ERROR,
- "Could not find an AVHWAccel for the pixel format: %s",
- desc->name);
- return AV_PIX_FMT_NONE;
+ desc = av_pix_fmt_desc_get(ret);
+ if (!desc) {
+ ret = AV_PIX_FMT_NONE;
+ break;
}
- if (hwaccel->priv_data_size) {
- avctx->internal->hwaccel_priv_data = av_mallocz(hwaccel->priv_data_size);
- if (!avctx->internal->hwaccel_priv_data)
- return AV_PIX_FMT_NONE;
- }
+ if (avctx->hwaccel && avctx->hwaccel->uninit)
+ avctx->hwaccel->uninit(avctx);
+ av_freep(&avctx->internal->hwaccel_priv_data);
+ avctx->hwaccel = NULL;
- if (hwaccel->init) {
- err = hwaccel->init(avctx);
- if (err < 0) {
- av_freep(&avctx->internal->hwaccel_priv_data);
- return AV_PIX_FMT_NONE;
- }
- }
- avctx->hwaccel = hwaccel;
+ if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
+ break;
+ if (avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
+ break;
+
+ if (!setup_hwaccel(avctx, ret, desc->name))
+ break;
+
+ /* Remove failed hwaccel from choices */
+ for (n = 0; choices[n] != ret; n++)
+ av_assert0(choices[n] != AV_PIX_FMT_NONE);
+
+ do
+ choices[n] = choices[n + 1];
+ while (choices[n] != AV_PIX_FMT_NONE);
}
+ av_freep(&choices);
return ret;
}