1.不用png,用AVFrame
2.合流
3.图片抠图透明 (1.)mp4扣yuv图,(2)用1. (3)用抠图算法函数对yuv进行处理
ffmpeg -y -i TJTV.png -vf colorkey=0x0000FF:0.5:0.0 -c:v png t.png
0x0000FF:六位每两位分别表示红绿蓝,因此它是对rgb像素进行透明标记。
0.5表示蓝色的范围容差值,范围为0.01-1,数值越大,容错越大。
0.0是alpha通道的阀值,为0表示完全透明,实测这个值作用不明显。
对于TJTV.png,可以看到它的编码和封装方式都是png,它的像素格式为rgba。
Stream #0:0: Video: png, rgba(pc), 280x279 [SAR 2835:2835 DAR
280:279], 25 fps, 25 tbr, 25 tbn
这个命令只能对rgb的像素格式进行透明标记,但是对yuv得不能,会导致花屏。只有argb、rgba等带透明度格式的像素格式才能进行抠图透明标记。
透明的原理是对rgb数据逐个像素处理,修改rgb值,达到对特定的像素进行透明标记。
chromakey与colorkey的区别
ffmpeg -h filter=colorkey
Filter colorkey
Turns a certain color into transparency. Operates on RGB colors.
slice threading supported
Inputs:
#0: default (video)
Outputs:
#0: default (video)
colorkey AVOptions:
color <color> ..FV.....T. set the colorkey key color (default "black")
similarity <float> ..FV.....T. set the colorkey similarity value (from 1e-05 to 1) (default 0.01)
blend <float> ..FV.....T. set the colorkey key blend value (from 0 to 1) (default 0)
ffmpeg -h filter=chromakey
Filter chromakey
Turns a certain color into transparency. Operates on YUV colors.
slice threading supported
Inputs:
#0: default (video)
Outputs:
#0: default (video)
chromakey AVOptions:
color <color> ..FV.....T. set the chromakey key color (default "black")
similarity <float> ..FV.....T. set the chromakey similarity value (from 1e-05 to 1) (default 0.01)
blend <float> ..FV.....T. set the chromakey key blend value (from 0 to 1) (default 0)
yuv <boolean> ..FV.....T. color parameter is in yuv instead of rgb (default false)
附录:
1.ffmpeg滤镜chromakey针对yuv处理,将对应像素点标记透明。
static uint8_t do_chromakey_pixel(ChromakeyContext *ctx, uint8_t u[9], uint8_t v[9])
{
double diff = 0.0;
int du, dv, i;
for (i = 0; i < 9; ++i) {
du = (int)u[i] - ctx->chromakey_uv[0];
dv = (int)v[i] - ctx->chromakey_uv[1];
diff += sqrt((du * du + dv * dv) / (255.0 * 255.0 * 2));
}
diff /= 9.0;
if (ctx->blend > 0.0001) {
return av_clipd((diff - ctx->similarity) / ctx->blend, 0.0, 1.0) * 255.0;
} else {
return (diff > ctx->similarity) ? 255 : 0;
}
}
static int do_chromakey_slice(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs)
{
AVFrame *frame = arg;
const int slice_start = (frame->height * jobnr) / nb_jobs;
const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs;
ChromakeyContext *ctx = avctx->priv;
int x, y, xo, yo;
uint8_t u[9], v[9];
memset(u, ctx->chromakey_uv[0], sizeof(u));
memset(v, ctx->chromakey_uv[1], sizeof(v));
for (y = slice_start; y < slice_end; ++y)
{
for (x = 0; x < frame->width; ++x)
{
for (yo = 0; yo < 3; ++yo)
{
for (xo = 0; xo < 3; ++xo)
{
get_pixel_uv(frame, ctx->hsub_log2, ctx->vsub_log2, x + xo - 1, y + yo - 1, &u[yo * 3 + xo], &v[yo * 3 + xo]);
}
}
frame->data[3][frame->linesize[3] * y + x] = do_chromakey_pixel(ctx, u, v);
}
}
return 0;
}
2.ffmpeg滤镜colorkey针对rgb处理,将目标像素点设置为透明。
static uint8_t do_colorkey_pixel(ColorkeyContext *ctx, uint8_t r, uint8_t g, uint8_t b)
{
int dr = (int)r - ctx->colorkey_rgba[0];
int dg = (int)g - ctx->colorkey_rgba[1];
int db = (int)b - ctx->colorkey_rgba[2];
//计算相似度
double diff = sqrt((dr * dr + dg * dg + db * db) / (255.0 * 255.0 * 3.0));
if (ctx->blend > 0.0001) {
return av_clipd((diff - ctx->similarity) / ctx->blend, 0.0, 1.0) * 255.0;
} else {
return (diff > ctx->similarity) ? 255 : 0;
}
}
static int do_colorkey_slice(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs)
{
AVFrame *frame = arg;
const int slice_start = (frame->height * jobnr) / nb_jobs;
const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs;
ColorkeyContext *ctx = avctx->priv;
int o, x, y;
for (y = slice_start; y < slice_end; ++y) {
for (x = 0; x < frame->width; ++x) {
o = frame->linesize[0] * y + x * 4;
// 修改rgba a数据
frame->data[0][o + ctx->co[3]] =
do_colorkey_pixel(ctx,
frame->data[0][o + ctx->co[0]],
frame->data[0][o + ctx->co[1]],
frame->data[0][o + ctx->co[2]]);
}
}
return 0;
}
参考:ffmpeg绿幕抠图原理解析