From d284cedbea5337a18b5ecb2cdaa94aed79117c47 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 14 Jun 2018 14:19:54 +0200 Subject: [PATCH] movies/ffmpeg: support grayscale and grayscale-alpha videos Fixes #352 --- panda/src/ffmpeg/ffmpegVideoCursor.cxx | 26 ++++++-- panda/src/grutil/movieTexture.cxx | 7 +- panda/src/movies/movieVideoCursor.cxx | 90 ++++++++++++++++++++------ 3 files changed, 93 insertions(+), 30 deletions(-) diff --git a/panda/src/ffmpeg/ffmpegVideoCursor.cxx b/panda/src/ffmpeg/ffmpegVideoCursor.cxx index b7b67a8ecf..2536f85e3c 100644 --- a/panda/src/ffmpeg/ffmpegVideoCursor.cxx +++ b/panda/src/ffmpeg/ffmpegVideoCursor.cxx @@ -112,13 +112,25 @@ init_from(FfmpegVideo *source) { // Check if we got an alpha format. Please note that some video codecs // (eg. libvpx) change the pix_fmt after decoding the first frame, which is // why we didn't do this earlier. - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(_video_ctx->pix_fmt); - if (desc && (desc->flags & AV_PIX_FMT_FLAG_ALPHA) != 0) { - _num_components = 4; - _pixel_format = (int)AV_PIX_FMT_BGRA; - } else { - _num_components = 3; - _pixel_format = (int)AV_PIX_FMT_BGR24; + switch (_video_ctx->pix_fmt) { + case AV_PIX_FMT_GRAY8: + _num_components = 1; + _pixel_format = (int)AV_PIX_FMT_GRAY8; + break; + case AV_PIX_FMT_YA8: + _num_components = 2; + _pixel_format = (int)AV_PIX_FMT_YA8; + break; + default: + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(_video_ctx->pix_fmt); + if (desc && (desc->flags & AV_PIX_FMT_FLAG_ALPHA) != 0) { + _num_components = 4; + _pixel_format = (int)AV_PIX_FMT_BGRA; + } else { + _num_components = 3; + _pixel_format = (int)AV_PIX_FMT_BGR24; + } + break; } #ifdef HAVE_SWSCALE diff --git a/panda/src/grutil/movieTexture.cxx b/panda/src/grutil/movieTexture.cxx index 44f3d541d4..ab8cb390ef 100644 --- a/panda/src/grutil/movieTexture.cxx +++ b/panda/src/grutil/movieTexture.cxx @@ -141,6 +141,7 @@ void MovieTexture:: do_recalculate_image_properties(CData *cdata, Texture::CData *cdata_tex, const LoaderOptions &options) { int x_max = 1; int y_max = 1; + bool rgb = false; bool alpha = false; double len = 0.0; @@ -150,7 +151,8 @@ do_recalculate_image_properties(CData *cdata, Texture::CData *cdata_tex, const L if (t->size_x() > x_max) x_max = t->size_x(); if (t->size_y() > y_max) y_max = t->size_y(); if (t->length() > len) len = t->length(); - if (t->get_num_components() == 4) alpha=true; + if (t->get_num_components() >= 3) rgb=true; + if (t->get_num_components() == 4 || t->get_num_components() == 2) alpha=true; } t = cdata->_pages[i]._alpha; if (t) { @@ -167,7 +169,8 @@ do_recalculate_image_properties(CData *cdata, Texture::CData *cdata_tex, const L do_adjust_this_size(cdata_tex, x_max, y_max, get_name(), true); - do_reconsider_image_properties(cdata_tex, x_max, y_max, alpha?4:3, + int num_components = (rgb ? 3 : 1) + alpha; + do_reconsider_image_properties(cdata_tex, x_max, y_max, num_components, T_unsigned_byte, cdata->_pages.size(), options); cdata_tex->_orig_file_x_size = cdata->_video_width; diff --git a/panda/src/movies/movieVideoCursor.cxx b/panda/src/movies/movieVideoCursor.cxx index 761e7e2fa6..96ead8c8f0 100644 --- a/panda/src/movies/movieVideoCursor.cxx +++ b/panda/src/movies/movieVideoCursor.cxx @@ -60,7 +60,21 @@ setup_texture(Texture *tex) const { int fullx = size_x(); int fully = size_y(); tex->adjust_this_size(fullx, fully, tex->get_name(), true); - Texture::Format fmt = (get_num_components() == 4) ? Texture::F_rgba : Texture::F_rgb; + Texture::Format fmt; + switch (get_num_components()) { + case 1: + fmt = Texture::F_luminance; + break; + case 2: + fmt = Texture::F_luminance_alpha; + break; + default: + fmt = Texture::F_rgb; + break; + case 4: + fmt = Texture::F_rgba; + break; + } tex->setup_texture(Texture::TT_2d_texture, fullx, fully, 1, Texture::T_unsigned_byte, fmt); tex->set_pad_size(fullx - size_x(), fully - size_y()); } @@ -113,7 +127,9 @@ apply_to_texture(const Buffer *buffer, Texture *t, int page) { nassertv(t->get_x_size() >= size_x()); nassertv(t->get_y_size() >= size_y()); - nassertv((t->get_num_components() == 3) || (t->get_num_components() == 4)); + nassertv((t->get_num_components() == 3) || (t->get_num_components() == 4) || + (t->get_num_components() == 1 && get_num_components() == 1) || + (t->get_num_components() == 2 && get_num_components() == 2)); nassertv(t->get_component_width() == 1); nassertv(page < t->get_num_pages()); @@ -132,17 +148,19 @@ apply_to_texture(const Buffer *buffer, Texture *t, int page) { } else { unsigned char *p = buffer->_block; - if (t->get_num_components() == get_num_components()) { - int src_stride = size_x() * get_num_components(); - int dst_stride = t->get_x_size() * t->get_num_components(); + int src_width = get_num_components(); + int dst_width = t->get_num_components(); + if (src_width == dst_width) { + int src_stride = src_width * size_x(); + int dst_stride = dst_width * t->get_x_size(); for (int y=0; yget_num_components(); + nassertv(src_width >= 3); + nassertv(dst_width >= 3); for (int y = 0; y < size_y(); ++y) { for (int x = 0; x < size_x(); ++x) { data[0] = p[0]; @@ -168,9 +186,20 @@ apply_to_texture_alpha(const Buffer *buffer, Texture *t, int page, int alpha_src PStatTimer timer(_copy_pcollector); + // Is this a grayscale texture? + if (get_num_components() < 3) { + if (get_num_components() == 1 || alpha_src < 2 || alpha_src == 3) { + // There's only one "RGB" channel to take from. + alpha_src = 1; + } else { + // Alpha is actually in the second channel for grayscale-alpha. + alpha_src = 2; + } + } + nassertv(t->get_x_size() >= size_x()); nassertv(t->get_y_size() >= size_y()); - nassertv(t->get_num_components() == 4); + nassertv(t->get_num_components() == 4 || t->get_num_components() == 2); nassertv(t->get_component_width() == 1); nassertv(page < t->get_z_size()); nassertv((alpha_src >= 0) && (alpha_src <= get_num_components())); @@ -186,14 +215,16 @@ apply_to_texture_alpha(const Buffer *buffer, Texture *t, int page, int alpha_src PStatTimer timer2(_copy_pcollector_copy); int src_width = get_num_components(); + int dst_width = t->get_num_components(); int src_stride = size_x() * src_width; - int dst_stride = t->get_x_size() * 4; + int dst_stride = t->get_x_size() * dst_width; unsigned char *p = buffer->_block; if (alpha_src == 0) { + nassertv(src_width >= 3); for (int y=0; yget_x_size() >= size_x()); nassertv(t->get_y_size() >= size_y()); - nassertv(t->get_num_components() == 4); + nassertv(t->get_num_components() == 4 || t->get_num_components() == 2); nassertv(t->get_component_width() == 1); nassertv(page < t->get_z_size()); @@ -238,18 +269,35 @@ apply_to_texture_rgb(const Buffer *buffer, Texture *t, int page) { unsigned char *data = img.p() + page * t->get_expected_ram_page_size(); PStatTimer timer2(_copy_pcollector_copy); - int src_stride = size_x() * get_num_components(); int src_width = get_num_components(); - int dst_stride = t->get_x_size() * 4; + int dst_width = t->get_num_components(); + int src_stride = size_x() * src_width; + int dst_stride = t->get_x_size() * dst_width; unsigned char *p = buffer->_block; - for (int y=0; y= 3) { + // It has RGB values. + nassertv(dst_width >= 3); + for (int y = 0; y < size_y(); ++y) { + for (int x = 0; x < size_x(); ++x) { + data[x * dst_width + 0] = p[x * src_width + 0]; + data[x * dst_width + 1] = p[x * src_width + 1]; + data[x * dst_width + 2] = p[x * src_width + 2]; + } + data += dst_stride; + p += src_stride; + } + } else if (dst_width == 4) { + // It has only grayscale. + for (int y = 0; y < size_y(); ++y) { + for (int x = 0; x < size_x(); ++x) { + unsigned char gray = p[x * src_width]; + data[x * dst_width + 0] = gray; + data[x * dst_width + 1] = gray; + data[x * dst_width + 2] = gray; + } + data += dst_stride; + p += src_stride; } - data += dst_stride; - p += src_stride; } }