]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/libx265.c
libx265: Add 4:2:2 support
[ffmpeg] / libavcodec / libx265.c
index 961fc746b63785f698bf7edf522aa0b628c78531..5f2766207925c574519ee12b025d6eb636cb26a1 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#if defined(_MSC_VER)
+#define X265_API_IMPORTS 1
+#endif
+
 #include <x265.h>
 
 #include "libavutil/internal.h"
 #include "avcodec.h"
 #include "internal.h"
 
-#if defined(_MSC_VER)
-#define X265_API_IMPORTS 1
-#endif
-
 typedef struct libx265Context {
     const AVClass *class;
 
     x265_encoder *encoder;
     x265_param   *params;
-    uint8_t      *header;
-    int           header_size;
 
     char *preset;
     char *tune;
@@ -66,7 +64,6 @@ static av_cold int libx265_encode_close(AVCodecContext *avctx)
     libx265Context *ctx = avctx->priv_data;
 
     av_frame_free(&avctx->coded_frame);
-    av_freep(&ctx->header);
 
     x265_param_free(ctx->params);
 
@@ -80,17 +77,14 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx)
 {
     libx265Context *ctx = avctx->priv_data;
     x265_nal *nal;
-    uint8_t *buf;
+    char sar[12];
     int sar_num, sar_den;
     int nnal;
-    int ret;
-    int i;
 
     if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL &&
-        !av_pix_fmt_desc_get(avctx->pix_fmt)->log2_chroma_w &&
-        !av_pix_fmt_desc_get(avctx->pix_fmt)->log2_chroma_h) {
+        !av_pix_fmt_desc_get(avctx->pix_fmt)->log2_chroma_w) {
         av_log(avctx, AV_LOG_ERROR,
-               "4:4:4 support is not fully defined for HEVC yet. "
+               "4:2:2 and 4:4:4 support is not fully defined for HEVC yet. "
                "Set -strict experimental to encode anyway.\n");
         return AVERROR(ENOSYS);
     }
@@ -118,14 +112,16 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx)
     ctx->params->sourceWidth     = avctx->width;
     ctx->params->sourceHeight    = avctx->height;
 
-    av_reduce(&sar_num, &sar_den,
-              avctx->sample_aspect_ratio.num,
-              avctx->sample_aspect_ratio.den, 4096);
-    ctx->params->bEnableVuiParametersPresentFlag = 1;
-    ctx->params->bEnableAspectRatioIdc           = 1;
-    ctx->params->aspectRatioIdc                  = 255;
-    ctx->params->sarWidth                        = sar_num;
-    ctx->params->sarHeight                       = sar_den;
+    if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) {
+        av_reduce(&sar_num, &sar_den,
+                  avctx->sample_aspect_ratio.num,
+                  avctx->sample_aspect_ratio.den, 65535);
+        snprintf(sar, sizeof(sar), "%d:%d", sar_num, sar_den);
+        if (x265_param_parse(ctx->params, "sar", sar) == X265_PARAM_BAD_VALUE) {
+            av_log(avctx, AV_LOG_ERROR, "Invalid SAR: %d:%d.\n", sar_num, sar_den);
+            return AVERROR_INVALIDDATA;
+        }
+    }
 
     if (x265_max_bit_depth == 8)
         ctx->params->internalBitDepth = 8;
@@ -137,6 +133,10 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx)
     case AV_PIX_FMT_YUV420P10:
         ctx->params->internalCsp = X265_CSP_I420;
         break;
+    case AV_PIX_FMT_YUV422P:
+    case AV_PIX_FMT_YUV422P10:
+        ctx->params->internalCsp = X265_CSP_I422;
+        break;
     case AV_PIX_FMT_YUV444P:
     case AV_PIX_FMT_YUV444P10:
         ctx->params->internalCsp = X265_CSP_I444;
@@ -148,6 +148,9 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx)
         ctx->params->rc.rateControlMode = X265_RC_ABR;
     }
 
+    if (!(avctx->flags & CODEC_FLAG_GLOBAL_HEADER))
+        ctx->params->bRepeatHeaders = 1;
+
     if (ctx->x265_opts) {
         AVDictionary *dict    = NULL;
         AVDictionaryEntry *en = NULL;
@@ -180,28 +183,23 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx)
         return AVERROR_INVALIDDATA;
     }
 
-    ret = x265_encoder_headers(ctx->encoder, &nal, &nnal);
-    if (ret < 0) {
-        av_log(avctx, AV_LOG_ERROR, "Cannot encode headers.\n");
-        libx265_encode_close(avctx);
-        return AVERROR_INVALIDDATA;
-    }
-
-    for (i = 0; i < nnal; i++)
-        ctx->header_size += nal[i].sizeBytes;
+    if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
+        avctx->extradata_size = x265_encoder_headers(ctx->encoder, &nal, &nnal);
+        if (avctx->extradata_size <= 0) {
+            av_log(avctx, AV_LOG_ERROR, "Cannot encode headers.\n");
+            libx265_encode_close(avctx);
+            return AVERROR_INVALIDDATA;
+        }
 
-    ctx->header = av_malloc(ctx->header_size);
-    if (!ctx->header) {
-        av_log(avctx, AV_LOG_ERROR,
-               "Cannot allocate HEVC header of size %d.\n", ctx->header_size);
-        libx265_encode_close(avctx);
-        return AVERROR(ENOMEM);
-    }
+        avctx->extradata = av_malloc(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+        if (!avctx->extradata) {
+            av_log(avctx, AV_LOG_ERROR,
+                   "Cannot allocate HEVC header of size %d.\n", avctx->extradata_size);
+            libx265_encode_close(avctx);
+            return AVERROR(ENOMEM);
+        }
 
-    buf = ctx->header;
-    for (i = 0; i < nnal; i++) {
-        memcpy(buf, nal[i].payload, nal[i].sizeBytes);
-        buf += nal[i].sizeBytes;
+        memcpy(avctx->extradata, nal[0].payload, avctx->extradata_size);
     }
 
     return 0;
@@ -243,8 +241,6 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
     for (i = 0; i < nnal; i++)
         payload += nal[i].sizeBytes;
 
-    payload += ctx->header_size;
-
     ret = ff_alloc_packet(pkt, payload);
     if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
@@ -252,14 +248,6 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
     }
     dst = pkt->data;
 
-    if (ctx->header) {
-        memcpy(dst, ctx->header, ctx->header_size);
-        dst += ctx->header_size;
-
-        av_freep(&ctx->header);
-        ctx->header_size = 0;
-    }
-
     for (i = 0; i < nnal; i++) {
         memcpy(dst, nal[i].payload, nal[i].sizeBytes);
         dst += nal[i].sizeBytes;
@@ -277,14 +265,17 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 
 static const enum AVPixelFormat x265_csp_eight[] = {
     AV_PIX_FMT_YUV420P,
+    AV_PIX_FMT_YUV422P,
     AV_PIX_FMT_YUV444P,
     AV_PIX_FMT_NONE
 };
 
 static const enum AVPixelFormat x265_csp_twelve[] = {
     AV_PIX_FMT_YUV420P,
+    AV_PIX_FMT_YUV422P,
     AV_PIX_FMT_YUV444P,
     AV_PIX_FMT_YUV420P10,
+    AV_PIX_FMT_YUV422P10,
     AV_PIX_FMT_YUV444P10,
     AV_PIX_FMT_NONE
 };