[FFmpeg-cvslog] avcodec/v210dec: add support for frame and slice threading
Limin Wang
git at videolan.org
Mon Nov 25 10:58:01 EET 2019
ffmpeg | branch: master | Limin Wang <lance.lmwang at gmail.com> | Mon Nov 25 11:45:10 2019 +0800| [d07d1c1dd06541b3b48f3eacb7d8747a3456c6ad] | committer: Michael Niedermayer
avcodec/v210dec: add support for frame and slice threading
1, Test server configure:
[root at localhost ~]# cat /proc/cpuinfo |grep "model name"
model name : Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz
model name : Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz
...
[root at localhost ~]# free -h
total used free shared buff/cache available
Mem: 102G 1.1G 100G 16M 657M 100G
Swap: 4.0G 0B 4.0G
2, Test result:
encode the v210 input data for testing:
./ffmpeg -y -i 4k_422.ts -c:v v210 -vframes 10 test.avi
master:
./ffmpeg -y -threads 1 -stream_loop 1000 -i ./test.avi -benchmark -f null -
frame=10010 fps= 60 q=-0.0 Lsize=N/A time=00:38:26.30 bitrate=N/A speed=13.7x
video:5240kB audio:432432kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
bench: utime=101.869s stime=66.181s rtime=167.996s
bench: maxrss=186552kB
patch applied:
./ffmpeg -y -threads 2 -thread_type slice -stream_loop 1000 -i ./test.avi -benchmark -f null -
frame=10010 fps= 72 q=-0.0 Lsize=N/A time=00:38:26.30 bitrate=N/A speed=16.5x
video:5240kB audio:432432kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
bench: utime=103.562s stime=74.858s rtime=139.599s
bench: maxrss=188616kB
./ffmpeg -y -threads 2 -thread_type frame -stream_loop 1000 -i ./test.avi -benchmark -f null -
frame=10010 fps= 85 q=-0.0 Lsize=N/A time=00:38:26.30 bitrate=N/A speed=19.6x
video:5240kB audio:432432kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
bench: utime=114.310s stime=92.685s rtime=117.693s
bench: maxrss=231896kB
Signed-off-by: Limin Wang <lance.lmwang at gmail.com>
Signed-off-by: Michael Niedermayer <michael at niedermayer.cc>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=d07d1c1dd06541b3b48f3eacb7d8747a3456c6ad
---
libavcodec/v210dec.c | 126 +++++++++++++++++++++++++++++++--------------------
libavcodec/v210dec.h | 1 +
2 files changed, 79 insertions(+), 48 deletions(-)
diff --git a/libavcodec/v210dec.c b/libavcodec/v210dec.c
index 5a33d8c089..8483023815 100644
--- a/libavcodec/v210dec.c
+++ b/libavcodec/v210dec.c
@@ -28,6 +28,7 @@
#include "libavutil/internal.h"
#include "libavutil/mem.h"
#include "libavutil/intreadwrite.h"
+#include "thread.h"
#define READ_PIXELS(a, b, c) \
do { \
@@ -37,6 +38,12 @@
*c++ = (val >> 20) & 0x3FF; \
} while (0)
+typedef struct ThreadData {
+ AVFrame *frame;
+ uint8_t *buf;
+ int stride;
+} ThreadData;
+
static void v210_planar_unpack_c(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width)
{
uint32_t val;
@@ -64,21 +71,81 @@ static av_cold int decode_init(AVCodecContext *avctx)
avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
avctx->bits_per_raw_sample = 10;
+ s->thread_count = av_clip(avctx->thread_count, 1, avctx->height/4);
s->aligned_input = 0;
ff_v210dec_init(s);
return 0;
}
+static int v210_decode_slice(AVCodecContext *avctx, void *arg, int jobnr, int threadnr)
+{
+ V210DecContext *s = avctx->priv_data;
+ int h, w;
+ ThreadData *td = arg;
+ AVFrame *frame = td->frame;
+ int stride = td->stride;
+ int slice_start = (avctx->height * jobnr) / s->thread_count;
+ int slice_end = (avctx->height * (jobnr+1)) / s->thread_count;
+ uint8_t *psrc = td->buf + stride * slice_start;
+ uint16_t *y, *u, *v;
+
+ y = (uint16_t*)frame->data[0] + slice_start * frame->linesize[0] / 2;
+ u = (uint16_t*)frame->data[1] + slice_start * frame->linesize[1] / 2;
+ v = (uint16_t*)frame->data[2] + slice_start * frame->linesize[2] / 2;
+ for (h = slice_start; h < slice_end; h++) {
+ const uint32_t *src = (const uint32_t*)psrc;
+ uint32_t val;
+
+ w = (avctx->width / 12) * 12;
+ s->unpack_frame(src, y, u, v, w);
+
+ y += w;
+ u += w >> 1;
+ v += w >> 1;
+ src += (w << 1) / 3;
+
+ if (w < avctx->width - 5) {
+ READ_PIXELS(u, y, v);
+ READ_PIXELS(y, u, y);
+ READ_PIXELS(v, y, u);
+ READ_PIXELS(y, v, y);
+ w += 6;
+ }
+
+ if (w < avctx->width - 1) {
+ READ_PIXELS(u, y, v);
+
+ val = av_le2ne32(*src++);
+ *y++ = val & 0x3FF;
+ if (w < avctx->width - 3) {
+ *u++ = (val >> 10) & 0x3FF;
+ *y++ = (val >> 20) & 0x3FF;
+
+ val = av_le2ne32(*src++);
+ *v++ = val & 0x3FF;
+ *y++ = (val >> 10) & 0x3FF;
+ }
+ }
+
+ psrc += stride;
+ y += frame->linesize[0] / 2 - avctx->width + (avctx->width & 1);
+ u += frame->linesize[1] / 2 - avctx->width / 2;
+ v += frame->linesize[2] / 2 - avctx->width / 2;
+ }
+
+ return 0;
+}
+
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
V210DecContext *s = avctx->priv_data;
-
- int h, w, ret, stride, aligned_input;
+ ThreadData td;
+ int ret, stride, aligned_input;
+ ThreadFrame frame = { .f = data };
AVFrame *pic = data;
const uint8_t *psrc = avpkt->data;
- uint16_t *y, *u, *v;
if (s->custom_stride )
stride = s->custom_stride;
@@ -86,6 +153,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
int aligned_width = ((avctx->width + 47) / 48) * 48;
stride = aligned_width * 8 / 3;
}
+ td.stride = stride;
if (avpkt->size < stride * avctx->height) {
if ((((avctx->width + 23) / 24) * 24 * 8) / 3 * avctx->height == avpkt->size) {
@@ -110,55 +178,15 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
ff_v210dec_init(s);
}
- if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
return ret;
- y = (uint16_t*)pic->data[0];
- u = (uint16_t*)pic->data[1];
- v = (uint16_t*)pic->data[2];
pic->pict_type = AV_PICTURE_TYPE_I;
pic->key_frame = 1;
- for (h = 0; h < avctx->height; h++) {
- const uint32_t *src = (const uint32_t*)psrc;
- uint32_t val;
-
- w = (avctx->width / 12) * 12;
- s->unpack_frame(src, y, u, v, w);
-
- y += w;
- u += w >> 1;
- v += w >> 1;
- src += (w << 1) / 3;
-
- if (w < avctx->width - 5) {
- READ_PIXELS(u, y, v);
- READ_PIXELS(y, u, y);
- READ_PIXELS(v, y, u);
- READ_PIXELS(y, v, y);
- w += 6;
- }
-
- if (w < avctx->width - 1) {
- READ_PIXELS(u, y, v);
-
- val = av_le2ne32(*src++);
- *y++ = val & 0x3FF;
- if (w < avctx->width - 3) {
- *u++ = (val >> 10) & 0x3FF;
- *y++ = (val >> 20) & 0x3FF;
-
- val = av_le2ne32(*src++);
- *v++ = val & 0x3FF;
- *y++ = (val >> 10) & 0x3FF;
- }
- }
-
- psrc += stride;
- y += pic->linesize[0] / 2 - avctx->width + (avctx->width & 1);
- u += pic->linesize[1] / 2 - avctx->width / 2;
- v += pic->linesize[2] / 2 - avctx->width / 2;
- }
+ td.buf = (uint8_t*)psrc;
+ td.frame = pic;
+ avctx->execute2(avctx, v210_decode_slice, &td, NULL, s->thread_count);
if (avctx->field_order > AV_FIELD_PROGRESSIVE) {
/* we have interlaced material flagged in container */
@@ -194,6 +222,8 @@ AVCodec ff_v210_decoder = {
.priv_data_size = sizeof(V210DecContext),
.init = decode_init,
.decode = decode_frame,
- .capabilities = AV_CODEC_CAP_DR1,
+ .capabilities = AV_CODEC_CAP_DR1 |
+ AV_CODEC_CAP_SLICE_THREADS |
+ AV_CODEC_CAP_FRAME_THREADS,
.priv_class = &v210dec_class,
};
diff --git a/libavcodec/v210dec.h b/libavcodec/v210dec.h
index cfdb29da09..662e266315 100644
--- a/libavcodec/v210dec.h
+++ b/libavcodec/v210dec.h
@@ -27,6 +27,7 @@ typedef struct {
AVClass *av_class;
int custom_stride;
int aligned_input;
+ int thread_count;
int stride_warning_shown;
void (*unpack_frame)(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width);
} V210DecContext;
More information about the ffmpeg-cvslog
mailing list