X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Futvideoenc.c;h=4eddd98e24f2c3ead1e381f878a40a85f10dd673;hb=851960f6f8cf1f946fe42fa36cf6598fac68072c;hp=18bdec56a45e24244aa8c08c0a33625e781ae6b3;hpb=76fa7e09f18d5efa6b9c8ec5ef8d032a85e15865;p=ffmpeg diff --git a/libavcodec/utvideoenc.c b/libavcodec/utvideoenc.c index 18bdec56a45..4eddd98e24f 100644 --- a/libavcodec/utvideoenc.c +++ b/libavcodec/utvideoenc.c @@ -24,12 +24,16 @@ * Ut Video encoder */ +#include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" + #include "avcodec.h" #include "internal.h" +#include "bswapdsp.h" #include "bytestream.h" #include "put_bits.h" -#include "dsputil.h" +#include "huffyuvencdsp.h" #include "mathops.h" #include "utvideo.h" #include "huffman.h" @@ -46,7 +50,6 @@ static av_cold int utvideo_encode_close(AVCodecContext *avctx) UtvideoContext *c = avctx->priv_data; int i; - av_freep(&avctx->coded_frame); av_freep(&c->slice_bits); for (i = 0; i < 4; i++) av_freep(&c->slice_buffer[i]); @@ -57,7 +60,7 @@ static av_cold int utvideo_encode_close(AVCodecContext *avctx) static av_cold int utvideo_encode_init(AVCodecContext *avctx) { UtvideoContext *c = avctx->priv_data; - int i; + int i, subsampled_height; uint32_t original_format; c->avctx = avctx; @@ -65,34 +68,40 @@ static av_cold int utvideo_encode_init(AVCodecContext *avctx) c->slice_stride = FFALIGN(avctx->width, 32); switch (avctx->pix_fmt) { - case PIX_FMT_RGB24: + case AV_PIX_FMT_RGB24: c->planes = 3; avctx->codec_tag = MKTAG('U', 'L', 'R', 'G'); original_format = UTVIDEO_RGB; break; - case PIX_FMT_RGBA: + case AV_PIX_FMT_RGBA: c->planes = 4; avctx->codec_tag = MKTAG('U', 'L', 'R', 'A'); original_format = UTVIDEO_RGBA; break; - case PIX_FMT_YUV420P: + case AV_PIX_FMT_YUV420P: if (avctx->width & 1 || avctx->height & 1) { av_log(avctx, AV_LOG_ERROR, "4:2:0 video requires even width and height.\n"); return AVERROR_INVALIDDATA; } c->planes = 3; - avctx->codec_tag = MKTAG('U', 'L', 'Y', '0'); + if (avctx->colorspace == AVCOL_SPC_BT709) + avctx->codec_tag = MKTAG('U', 'L', 'H', '0'); + else + avctx->codec_tag = MKTAG('U', 'L', 'Y', '0'); original_format = UTVIDEO_420; break; - case PIX_FMT_YUV422P: + case AV_PIX_FMT_YUV422P: if (avctx->width & 1) { av_log(avctx, AV_LOG_ERROR, "4:2:2 video requires even width.\n"); return AVERROR_INVALIDDATA; } c->planes = 3; - avctx->codec_tag = MKTAG('U', 'L', 'Y', '2'); + if (avctx->colorspace == AVCOL_SPC_BT709) + avctx->codec_tag = MKTAG('U', 'L', 'H', '2'); + else + avctx->codec_tag = MKTAG('U', 'L', 'Y', '2'); original_format = UTVIDEO_422; break; default: @@ -101,8 +110,11 @@ static av_cold int utvideo_encode_init(AVCodecContext *avctx) return AVERROR_INVALIDDATA; } - ff_dsputil_init(&c->dsp, avctx); + ff_bswapdsp_init(&c->bdsp); + ff_huffyuvencdsp_init(&c->hdsp); +#if FF_API_PRIVATE_OPT +FF_DISABLE_DEPRECATION_WARNINGS /* Check the prediction method, and error out if unsupported */ if (avctx->prediction_method < 0 || avctx->prediction_method > 4) { av_log(avctx, AV_LOG_WARNING, @@ -118,26 +130,41 @@ static av_cold int utvideo_encode_init(AVCodecContext *avctx) } /* Convert from libavcodec prediction type to Ut Video's */ - c->frame_pred = ff_ut_pred_order[avctx->prediction_method]; + if (avctx->prediction_method) + c->frame_pred = ff_ut_pred_order[avctx->prediction_method]; +FF_ENABLE_DEPRECATION_WARNINGS +#endif if (c->frame_pred == PRED_GRADIENT) { av_log(avctx, AV_LOG_ERROR, "Gradient prediction is not supported.\n"); return AVERROR_OPTION_NOT_FOUND; } - avctx->coded_frame = avcodec_alloc_frame(); + /* + * Check the asked slice count for obviously invalid + * values (> 256 or negative). + */ + if (avctx->slices > 256 || avctx->slices < 0) { + av_log(avctx, AV_LOG_ERROR, + "Slice count %d is not supported in Ut Video (theoretical range is 0-256).\n", + avctx->slices); + return AVERROR(EINVAL); + } - if (!avctx->coded_frame) { - av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n"); - utvideo_encode_close(avctx); - return AVERROR(ENOMEM); + /* Check that the slice count is not larger than the subsampled height */ + subsampled_height = avctx->height >> av_pix_fmt_desc_get(avctx->pix_fmt)->log2_chroma_h; + if (avctx->slices > subsampled_height) { + av_log(avctx, AV_LOG_ERROR, + "Slice count %d is larger than the subsampling-applied height %d.\n", + avctx->slices, subsampled_height); + return AVERROR(EINVAL); } - /* extradata size is 4 * 32bit */ + /* extradata size is 4 * 32 bits */ avctx->extradata_size = 16; avctx->extradata = av_mallocz(avctx->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (!avctx->extradata) { av_log(avctx, AV_LOG_ERROR, "Could not allocate extradata.\n"); @@ -147,7 +174,7 @@ static av_cold int utvideo_encode_init(AVCodecContext *avctx) for (i = 0; i < c->planes; i++) { c->slice_buffer[i] = av_malloc(c->slice_stride * (avctx->height + 2) + - FF_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE); if (!c->slice_buffer[i]) { av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer 1.\n"); utvideo_encode_close(avctx); @@ -174,9 +201,19 @@ static av_cold int utvideo_encode_init(AVCodecContext *avctx) /* * Set how many slices are going to be used. - * Set one slice for now. + * By default uses multiple slices depending on the subsampled height. + * This enables multithreading in the official decoder. */ - c->slices = 1; + if (!avctx->slices) { + c->slices = subsampled_height / 120; + + if (!c->slices) + c->slices = 1; + else if (c->slices > 256) + c->slices = 256; + } else { + c->slices = avctx->slices; + } /* Set compression mode */ c->compression = COMP_HUFF; @@ -230,20 +267,6 @@ static void mangle_rgb_planes(uint8_t *dst[4], int dst_stride, uint8_t *src, } } -/* Write data to a plane, no prediction applied */ -static void write_plane(uint8_t *src, uint8_t *dst, int stride, - int width, int height) -{ - int i, j; - - for (j = 0; j < height; j++) { - for (i = 0; i < width; i++) - *dst++ = src[i]; - - src += stride; - } -} - /* Write data to a plane with left prediction */ static void left_predict(uint8_t *src, uint8_t *dst, int stride, int width, int height) @@ -289,7 +312,7 @@ static void median_predict(UtvideoContext *c, uint8_t *src, uint8_t *dst, int st /* Rest of the coded part uses median prediction */ for (j = 1; j < height; j++) { - c->dsp.sub_hfyu_median_prediction(dst, src - stride, src, width, &A, &B); + c->hdsp.sub_hfyu_median_pred(dst, src - stride, src, width, &A, &B); dst += width; src += stride; } @@ -348,7 +371,7 @@ static int write_huff_codes(uint8_t *src, uint8_t *dst, int dst_size, src += width; } - /* Pad output to a 32bit boundary */ + /* Pad output to a 32-bit boundary */ count = put_bits_count(&pb) & 0x1F; if (count) @@ -383,8 +406,9 @@ static int encode_plane(AVCodecContext *avctx, uint8_t *src, for (i = 0; i < c->slices; i++) { sstart = send; send = height * (i + 1) / c->slices; - write_plane(src + sstart * stride, dst + sstart * width, - stride, width, send - sstart); + av_image_copy_plane(dst + sstart * width, width, + src + sstart * stride, stride, + width, send - sstart); } break; case PRED_LEFT: @@ -474,9 +498,9 @@ static int encode_plane(AVCodecContext *avctx, uint8_t *src, slice_len = offset - slice_len; /* Byteswap the written huffman codes */ - c->dsp.bswap_buf((uint32_t *) c->slice_bits, - (uint32_t *) c->slice_bits, - slice_len >> 2); + c->bdsp.bswap_buf((uint32_t *) c->slice_bits, + (uint32_t *) c->slice_bits, + slice_len >> 2); /* Write the offset to the stream */ bytestream2_put_le32(pb, offset); @@ -530,7 +554,7 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt, bytestream2_init_writer(&pb, dst, pkt->size); av_fast_malloc(&c->slice_bits, &c->slice_bits_size, - width * height + FF_INPUT_BUFFER_PADDING_SIZE); + width * height + AV_INPUT_BUFFER_PADDING_SIZE); if (!c->slice_bits) { av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer 2.\n"); @@ -538,14 +562,14 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } /* In case of RGB, mangle the planes to Ut Video's format */ - if (avctx->pix_fmt == PIX_FMT_RGBA || avctx->pix_fmt == PIX_FMT_RGB24) + if (avctx->pix_fmt == AV_PIX_FMT_RGBA || avctx->pix_fmt == AV_PIX_FMT_RGB24) mangle_rgb_planes(c->slice_buffer, c->slice_stride, pic->data[0], c->planes, pic->linesize[0], width, height); /* Deal with the planes */ switch (avctx->pix_fmt) { - case PIX_FMT_RGB24: - case PIX_FMT_RGBA: + case AV_PIX_FMT_RGB24: + case AV_PIX_FMT_RGBA: for (i = 0; i < c->planes; i++) { ret = encode_plane(avctx, c->slice_buffer[i] + 2 * c->slice_stride, c->slice_buffer[i], c->slice_stride, @@ -557,7 +581,7 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } } break; - case PIX_FMT_YUV422P: + case AV_PIX_FMT_YUV422P: for (i = 0; i < c->planes; i++) { ret = encode_plane(avctx, pic->data[i], c->slice_buffer[0], pic->linesize[i], width >> !!i, height, &pb); @@ -568,7 +592,7 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } } break; - case PIX_FMT_YUV420P: + case AV_PIX_FMT_YUV420P: for (i = 0; i < c->planes; i++) { ret = encode_plane(avctx, pic->data[i], c->slice_buffer[0], pic->linesize[i], width >> !!i, height >> !!i, @@ -587,7 +611,7 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } /* - * Write frame information (LE 32bit unsigned) + * Write frame information (LE 32-bit unsigned) * into the output packet. * Contains the prediction method. */ @@ -598,9 +622,12 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt, * At least currently Ut Video is IDR only. * Set flags accordingly. */ - avctx->coded_frame->reference = 0; +#if FF_API_CODED_FRAME +FF_DISABLE_DEPRECATION_WARNINGS avctx->coded_frame->key_frame = 1; avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I; +FF_ENABLE_DEPRECATION_WARNINGS +#endif pkt->size = bytestream2_tell_p(&pb); pkt->flags |= AV_PKT_FLAG_KEY; @@ -611,17 +638,37 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } +#define OFFSET(x) offsetof(UtvideoContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { +{ "pred", "Prediction method", OFFSET(frame_pred), AV_OPT_TYPE_INT, { .i64 = PRED_LEFT }, PRED_NONE, PRED_MEDIAN, VE, "pred" }, + { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_NONE }, INT_MIN, INT_MAX, VE, "pred" }, + { "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_LEFT }, INT_MIN, INT_MAX, VE, "pred" }, + { "gradient", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_GRADIENT }, INT_MIN, INT_MAX, VE, "pred" }, + { "median", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRED_MEDIAN }, INT_MIN, INT_MAX, VE, "pred" }, + + { NULL}, +}; + +static const AVClass utvideo_class = { + .class_name = "utvideo", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_utvideo_encoder = { .name = "utvideo", + .long_name = NULL_IF_CONFIG_SMALL("Ut Video"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_UTVIDEO, .priv_data_size = sizeof(UtvideoContext), + .priv_class = &utvideo_class, .init = utvideo_encode_init, .encode2 = utvideo_encode_frame, .close = utvideo_encode_close, - .pix_fmts = (const enum PixelFormat[]) { - PIX_FMT_RGB24, PIX_FMT_RGBA, PIX_FMT_YUV422P, - PIX_FMT_YUV420P, PIX_FMT_NONE + .pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, - .long_name = NULL_IF_CONFIG_SMALL("Ut Video"), };