diff options
author | Ram Mohan M <ram.mohan@ittiam.com> | 2024-05-06 13:30:19 +0530 |
---|---|---|
committer | DichenZhang1 <140119224+DichenZhang1@users.noreply.github.com> | 2024-05-06 22:52:16 -0700 |
commit | d4c1d7b5b21ffefa1820738b0d10469b6254f131 (patch) | |
tree | e73bb7c2067a81109d2bcd6a58f18e30f9682f52 | |
parent | 489b58d92731646e4a9a7deb927681f2ad8ca81f (diff) | |
download | libultrahdr-d4c1d7b5b21ffefa1820738b0d10469b6254f131.tar.gz |
add support for simple edit effects in encode path
- add mirror, rotate, crop, resize effects in encode path. This change
does not enable effects completely as there are no api calls
advertised to invoke the effects
- improve error logging
Test: Manual
-rw-r--r-- | lib/src/editorhelper.cpp | 9 | ||||
-rw-r--r-- | lib/src/ultrahdr_api.cpp | 214 |
2 files changed, 204 insertions, 19 deletions
diff --git a/lib/src/editorhelper.cpp b/lib/src/editorhelper.cpp index 8625977..603ed1f 100644 --- a/lib/src/editorhelper.cpp +++ b/lib/src/editorhelper.cpp @@ -177,10 +177,10 @@ std::unique_ptr<uhdr_raw_image_ext_t> apply_rotate(ultrahdr::uhdr_rotate_effect_ if (desc->m_degree == 90 || desc->m_degree == 270) { dst = std::make_unique<uhdr_raw_image_ext_t>(src->fmt, src->cg, src->ct, src->range, src->h, - src->w, 1); + src->w, 64); } else if (desc->m_degree == 180) { dst = std::make_unique<uhdr_raw_image_ext_t>(src->fmt, src->cg, src->ct, src->range, src->w, - src->h, 1); + src->h, 64); } else { return nullptr; } @@ -225,7 +225,7 @@ std::unique_ptr<uhdr_raw_image_ext_t> apply_rotate(ultrahdr::uhdr_rotate_effect_ std::unique_ptr<uhdr_raw_image_ext_t> apply_mirror(ultrahdr::uhdr_mirror_effect_t* desc, uhdr_raw_image_t* src) { std::unique_ptr<uhdr_raw_image_ext_t> dst = std::make_unique<uhdr_raw_image_ext_t>( - src->fmt, src->cg, src->ct, src->range, src->w, src->h, 1); + src->fmt, src->cg, src->ct, src->range, src->w, src->h, 64); if (src->fmt == UHDR_IMG_FMT_24bppYCbCrP010) { uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[UHDR_PLANE_Y]); @@ -276,6 +276,7 @@ void apply_crop(uhdr_raw_image_t* src, int left, int top, int wd, int ht) { src->planes[UHDR_PLANE_Y] = &src_buffer[top * src->stride[UHDR_PLANE_Y] + left]; if (src->fmt == UHDR_IMG_FMT_12bppYCbCr420) { for (int i = 1; i < 3; i++) { + src_buffer = static_cast<uint8_t*>(src->planes[i]); src->planes[i] = &src_buffer[(top / 2) * src->stride[i] + (left / 2)]; } } @@ -293,7 +294,7 @@ void apply_crop(uhdr_raw_image_t* src, int left, int top, int wd, int ht) { std::unique_ptr<uhdr_raw_image_ext_t> apply_resize(ultrahdr::uhdr_resize_effect_t* desc, uhdr_raw_image_t* src, int dst_w, int dst_h) { std::unique_ptr<uhdr_raw_image_ext_t> dst = std::make_unique<uhdr_raw_image_ext_t>( - src->fmt, src->cg, src->ct, src->range, dst_w, dst_h, 1); + src->fmt, src->cg, src->ct, src->range, dst_w, dst_h, 64); if (src->fmt == UHDR_IMG_FMT_24bppYCbCrP010) { uint16_t* src_buffer = static_cast<uint16_t*>(src->planes[UHDR_PLANE_Y]); diff --git a/lib/src/ultrahdr_api.cpp b/lib/src/ultrahdr_api.cpp index 95964d9..29d9b91 100644 --- a/lib/src/ultrahdr_api.cpp +++ b/lib/src/ultrahdr_api.cpp @@ -104,6 +104,114 @@ uhdr_compressed_image_ext::uhdr_compressed_image_ext(uhdr_color_gamut_t cg, this->range = range; } +uhdr_error_info_t apply_effects(uhdr_encoder_private* enc) { + for (auto& it : enc->m_effects) { + std::unique_ptr<ultrahdr::uhdr_raw_image_ext_t> hdr_img = nullptr; + std::unique_ptr<ultrahdr::uhdr_raw_image_ext_t> sdr_img = nullptr; + + if (nullptr != dynamic_cast<uhdr_rotate_effect_t*>(it)) { + auto& hdr_raw_entry = enc->m_raw_images.find(UHDR_HDR_IMG)->second; + hdr_img = apply_rotate(dynamic_cast<uhdr_rotate_effect_t*>(it), hdr_raw_entry.get()); + if (enc->m_raw_images.find(UHDR_SDR_IMG) != enc->m_raw_images.end()) { + auto& sdr_raw_entry = enc->m_raw_images.find(UHDR_SDR_IMG)->second; + sdr_img = apply_rotate(dynamic_cast<uhdr_rotate_effect_t*>(it), sdr_raw_entry.get()); + } + } else if (nullptr != dynamic_cast<uhdr_mirror_effect_t*>(it)) { + auto& hdr_raw_entry = enc->m_raw_images.find(UHDR_HDR_IMG)->second; + hdr_img = apply_mirror(dynamic_cast<uhdr_mirror_effect_t*>(it), hdr_raw_entry.get()); + if (enc->m_raw_images.find(UHDR_SDR_IMG) != enc->m_raw_images.end()) { + auto& sdr_raw_entry = enc->m_raw_images.find(UHDR_SDR_IMG)->second; + sdr_img = apply_mirror(dynamic_cast<uhdr_mirror_effect_t*>(it), sdr_raw_entry.get()); + } + } else if (nullptr != dynamic_cast<uhdr_crop_effect_t*>(it)) { + auto crop_effect = dynamic_cast<uhdr_crop_effect_t*>(it); + auto& hdr_raw_entry = enc->m_raw_images.find(UHDR_HDR_IMG)->second; + int left = (std::max)(0, crop_effect->m_left); + int right = (std::min)((int)hdr_raw_entry->w, crop_effect->m_right); + int crop_width = right - left; + if (crop_width <= 0 || (crop_width % 2 != 0)) { + uhdr_error_info_t status; + status.error_code = UHDR_CODEC_INVALID_PARAM; + status.has_detail = 1; + snprintf(status.detail, sizeof status.detail, + "unexpected crop dimensions. crop width is expected to be > 0 and even, crop " + "width is %d", + crop_width); + return status; + } + + int top = (std::max)(0, crop_effect->m_top); + int bottom = (std::min)((int)hdr_raw_entry->h, crop_effect->m_bottom); + int crop_height = bottom - top; + if (crop_height <= 0 || (crop_height % 2 != 0)) { + uhdr_error_info_t status; + status.error_code = UHDR_CODEC_INVALID_PARAM; + status.has_detail = 1; + snprintf(status.detail, sizeof status.detail, + "unexpected crop dimensions. crop height is expected to be > 0 and even, crop " + "height is %d", + crop_height); + return status; + } + apply_crop(hdr_raw_entry.get(), left, top, crop_width, crop_height); + if (enc->m_raw_images.find(UHDR_SDR_IMG) != enc->m_raw_images.end()) { + auto& sdr_raw_entry = enc->m_raw_images.find(UHDR_SDR_IMG)->second; + apply_crop(sdr_raw_entry.get(), left, top, crop_width, crop_height); + } + continue; + } else if (nullptr != dynamic_cast<uhdr_resize_effect_t*>(it)) { + auto resize_effect = dynamic_cast<uhdr_resize_effect_t*>(it); + int dst_w = resize_effect->m_width; + int dst_h = resize_effect->m_height; + if (dst_w == 0 || dst_h == 0 || dst_w % 2 != 0 || dst_h % 2 != 0) { + uhdr_error_info_t status; + status.error_code = UHDR_CODEC_INVALID_PARAM; + snprintf(status.detail, sizeof status.detail, + "destination dimension cannot be zero or odd. dest image width is %d, dest image " + "height is %d", + dst_w, dst_h); + return status; + } + auto& hdr_raw_entry = enc->m_raw_images.find(UHDR_HDR_IMG)->second; + hdr_img = + apply_resize(dynamic_cast<uhdr_resize_effect_t*>(it), hdr_raw_entry.get(), dst_w, dst_h); + if (enc->m_raw_images.find(UHDR_SDR_IMG) != enc->m_raw_images.end()) { + auto& sdr_raw_entry = enc->m_raw_images.find(UHDR_SDR_IMG)->second; + sdr_img = apply_resize(dynamic_cast<uhdr_resize_effect_t*>(it), sdr_raw_entry.get(), dst_w, + dst_h); + } + } + + if (hdr_img == nullptr || + (enc->m_raw_images.find(UHDR_SDR_IMG) != enc->m_raw_images.end() && sdr_img == nullptr)) { + uhdr_error_info_t status; + status.error_code = UHDR_CODEC_UNKNOWN_ERROR; + status.has_detail = 1; + snprintf(status.detail, sizeof status.detail, + "encountered unknown error while applying effect %s", it->to_string().c_str()); + return status; + } + enc->m_raw_images.insert_or_assign(UHDR_HDR_IMG, std::move(hdr_img)); + if (sdr_img != nullptr) { + enc->m_raw_images.insert_or_assign(UHDR_SDR_IMG, std::move(sdr_img)); + } + } + if (enc->m_effects.size() > 0) { + auto it = enc->m_effects.back(); + if (nullptr != dynamic_cast<uhdr_crop_effect_t*>(it) && + enc->m_raw_images.find(UHDR_SDR_IMG) != enc->m_raw_images.end()) { + // As cropping is handled via pointer arithmetic as opposed to buffer copy, u and v data of + // yuv420 inputs are no longer contiguous. As the library does not accept distinct buffer + // pointers for u and v for 420 input, copy the sdr intent to a contiguous buffer + auto& sdr_raw_entry = enc->m_raw_images.find(UHDR_SDR_IMG)->second; + enc->m_raw_images.insert_or_assign(UHDR_SDR_IMG, + convert_raw_input_to_ycbcr(sdr_raw_entry.get())); + } + } + + return g_no_error; +} + uhdr_error_info_t apply_effects(uhdr_decoder_private* dec) { for (auto& it : dec->m_effects) { std::unique_ptr<ultrahdr::uhdr_raw_image_ext_t> disp_img = nullptr; @@ -125,24 +233,60 @@ uhdr_error_info_t apply_effects(uhdr_decoder_private* dec) { uhdr_raw_image_t* gm = dec->m_gainmap_img_buffer.get(); int left = (std::max)(0, crop_effect->m_left); int right = (std::min)((int)disp->w, crop_effect->m_right); + if (right <= left) { + uhdr_error_info_t status; + status.error_code = UHDR_CODEC_INVALID_PARAM; + status.has_detail = 1; + snprintf( + status.detail, sizeof status.detail, + "unexpected crop dimensions. crop right is <= crop left, after crop image width is %d", + right - left); + return status; + } + int top = (std::max)(0, crop_effect->m_top); int bottom = (std::min)((int)disp->h, crop_effect->m_bottom); - int scale_factor = disp->w / gm->w; + if (bottom <= top) { + uhdr_error_info_t status; + status.error_code = UHDR_CODEC_INVALID_PARAM; + status.has_detail = 1; + snprintf( + status.detail, sizeof status.detail, + "unexpected crop dimensions. crop bottom is <= crop top, after crop image height is %d", + bottom - top); + return status; + } + + float wd_ratio = ((float)disp->w) / gm->w; + float ht_ratio = ((float)disp->h) / gm->h; + int gm_left = left / wd_ratio; + int gm_right = right / wd_ratio; + if (gm_right <= gm_left) { + uhdr_error_info_t status; + status.error_code = UHDR_CODEC_INVALID_PARAM; + status.has_detail = 1; + snprintf(status.detail, sizeof status.detail, + "unexpected crop dimensions. crop right is <= crop left for gainmap image, after " + "crop gainmap image width is %d", + gm_right - gm_left); + return status; + } - if (right - left <= scale_factor || bottom - top <= scale_factor) { + int gm_top = top / ht_ratio; + int gm_bottom = bottom / ht_ratio; + if (gm_bottom <= gm_top) { uhdr_error_info_t status; - status.error_code = UHDR_CODEC_UNKNOWN_ERROR; + status.error_code = UHDR_CODEC_INVALID_PARAM; status.has_detail = 1; snprintf(status.detail, sizeof status.detail, - "After crop image dimensions are <= 0, display image dimensions %dx%d, gain map " - "image dimensions %dx%d", - right - left, bottom - top, (right - left) / scale_factor, - (bottom - top) / scale_factor); + "unexpected crop dimensions. crop bottom is <= crop top for gainmap image, after " + "crop gainmap image height is %d", + gm_bottom - gm_top); return status; } + apply_crop(disp, left, top, right - left, bottom - top); - apply_crop(gm, left / scale_factor, top / scale_factor, (right - left) / scale_factor, - (bottom - top) / scale_factor); + apply_crop(gm, gm_left, gm_top, (gm_right - gm_left), (gm_bottom - gm_top)); continue; } else if (nullptr != dynamic_cast<uhdr_resize_effect_t*>(it)) { auto resize_effect = dynamic_cast<uhdr_resize_effect_t*>(it); @@ -158,7 +302,9 @@ uhdr_error_info_t apply_effects(uhdr_decoder_private* dec) { uhdr_error_info_t status; status.error_code = UHDR_CODEC_INVALID_PARAM; snprintf(status.detail, sizeof status.detail, - "destination width or destination height cannot be zero"); + "destination dimension cannot be zero. dest image width is %d, dest image height " + "is %d, dest gainmap width is %d, dest gainmap height is %d", + dst_w, dst_h, dst_gm_w, dst_gm_h); return status; } disp_img = apply_resize(dynamic_cast<uhdr_resize_effect_t*>(it), @@ -737,11 +883,49 @@ uhdr_error_info_t uhdr_encode(uhdr_codec_private_t* enc) { uhdr_error_info_t& status = handle->m_encode_call_status; - if (handle->m_effects.size() != 0) { - status.error_code = UHDR_CODEC_INVALID_PARAM; - status.has_detail = 1; - snprintf(status.detail, sizeof status.detail, "image effects are not currently enabled"); - return status; + if (handle->m_compressed_images.find(UHDR_BASE_IMG) != handle->m_compressed_images.end() && + handle->m_compressed_images.find(UHDR_GAIN_MAP_IMG) != handle->m_compressed_images.end()) { + if (handle->m_effects.size() != 0) { + status.error_code = UHDR_CODEC_INVALID_OPERATION; + status.has_detail = 1; + snprintf(status.detail, sizeof status.detail, + "image effects are not enabled for inputs with compressed intent"); + return status; + } + } else if (handle->m_raw_images.find(UHDR_HDR_IMG) != handle->m_raw_images.end()) { + if (handle->m_compressed_images.find(UHDR_SDR_IMG) == handle->m_compressed_images.end() && + handle->m_raw_images.find(UHDR_SDR_IMG) == handle->m_raw_images.end()) { + // api - 0 + if (handle->m_effects.size() != 0) { + status = ultrahdr::apply_effects(handle); + if (status.error_code != UHDR_CODEC_OK) return status; + } + } else if (handle->m_compressed_images.find(UHDR_SDR_IMG) != + handle->m_compressed_images.end() && + handle->m_raw_images.find(UHDR_SDR_IMG) == handle->m_raw_images.end()) { + if (handle->m_effects.size() != 0) { + status.error_code = UHDR_CODEC_INVALID_OPERATION; + status.has_detail = 1; + snprintf(status.detail, sizeof status.detail, + "image effects are not enabled for inputs with compressed intent"); + return status; + } + } else if (handle->m_raw_images.find(UHDR_SDR_IMG) != handle->m_raw_images.end()) { + if (handle->m_compressed_images.find(UHDR_SDR_IMG) == handle->m_compressed_images.end()) { + if (handle->m_effects.size() != 0) { + status = ultrahdr::apply_effects(handle); + if (status.error_code != UHDR_CODEC_OK) return status; + } + } else { + if (handle->m_effects.size() != 0) { + status.error_code = UHDR_CODEC_INVALID_OPERATION; + status.has_detail = 1; + snprintf(status.detail, sizeof status.detail, + "image effects are not enabled for inputs with compressed intent"); + return status; + } + } + } } ultrahdr::status_t internal_status = ultrahdr::JPEGR_NO_ERROR; |