[Metadata] Aded getFrame method of MetadataFileHandle 71/245071/7
authorPiotr Kosko <p.kosko@samsung.com>
Thu, 1 Oct 2020 06:02:45 +0000 (08:02 +0200)
committerPiotr Kosko <p.kosko@samsung.com>
Thu, 3 Dec 2020 13:19:03 +0000 (14:19 +0100)
[ACR] https://code.sec.samsung.net/jira/browse/TWDAPI-271

[Verification] Code compiles withotu errors.
Works well for mp4 video.
var path = "videos/sample_video.mp4";
function showBlob(bbb) {
    var elem = document.getElementById("blobImage") || document.createElement("img");
    elem.setAttribute("id", "blobImage");
    elem.setAttribute("height", "240");
    elem.setAttribute("width", "240");
    elem.setAttribute("alt", "invalid frame");
    document.getElementById("test").appendChild(elem)

    var objectURL = URL.createObjectURL(bbb);
    elem.src = objectURL;
}
var fileHandle = tizen.metadata.createFileHandle(path);
var frame = fileHandle.getFrame();
console.log(frame);
showBlob(frame)

Change-Id: I2d5e81b19d7f11ff2c08a0096a0b58fb7e3bfc48

packaging/webapi-plugins.spec
src/metadata/metadata.gyp
src/metadata/metadata_api.js
src/metadata/metadata_file_handle.cc
src/metadata/metadata_file_handle.h
src/metadata/metadata_instance.cc
src/metadata/metadata_instance.h

index dbad03b..cebe7f4 100644 (file)
@@ -421,6 +421,9 @@ BuildRequires: pkgconfig(capi-appfw-app-manager)
 BuildRequires: pkgconfig(capi-appfw-package-manager)
 BuildRequires: pkgconfig(capi-content-media-content)
 BuildRequires: pkgconfig(capi-media-metadata-extractor)
+# TODO check support on TV
+BuildRequires: pkgconfig(capi-media-image-util)
+
 BuildRequires: pkgconfig(libtzplatform-config)
 BuildRequires: pkgconfig(appsvc)
 
index 0f43bf8..2b999a7 100644 (file)
@@ -26,6 +26,8 @@
           'variables': {
             'packages': [
               'capi-media-metadata-extractor',
+              # TODO check support on TV
+              'capi-media-image-util',
             ]
           },
         }],
index 66a1fa6..8e78bdb 100755 (executable)
@@ -158,5 +158,20 @@ MetadataFileHandle.prototype.getArtwork = function() {
     return new Blob([encodedData], { type: resultData.mimeType });
 };
 
+MetadataFileHandle.prototype.getThumbnailFrame = function() {
+    var data = {
+        uri: this.uri,
+        id: this._id
+    };
+
+    var result = native_.callSync('MetadataFileHandleGetThumbnailFrame', data);
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+    }
+    var encodedData = StringToArray(native_.getResultObject(result), Uint8Array);
+
+    return new Blob([encodedData]);
+};
+
 // Exports
 exports = new MetadataManager();
index 1e40e4e..9a0ce85 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "metadata/metadata_file_handle.h"
 
+#include <image_util.h>
+
 #include "common/logger.h"
 #include "common/platform_enum.h"
 #include "common/platform_exception.h"
@@ -221,5 +223,94 @@ PlatformResult MetadataFileHandle::GetArtwork(std::vector<std::uint8_t>* artwork
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
+// convert frame buffer from raw RGB888 to JPG encoding
+PlatformResult MetadataFileHandle::EncodeJPEG(unsigned char* frame, size_t frame_size,
+                                              std::uint8_t** uint8_frame, size_t* buffer_size) {
+  ScopeLogger();
+  image_util_type_e encoder_type = IMAGE_UTIL_JPEG;
+  image_util_encode_h encode_handle = nullptr;
+  image_util_image_h image = nullptr;
+  SCOPE_EXIT {
+    image_util_encode_destroy(encode_handle);
+    image_util_destroy_image(image);
+  };
+
+  int ret = image_util_encode_create(encoder_type, &encode_handle);
+  if (IMAGE_UTIL_ERROR_NONE != ret) {
+    LoggerE("Error during jpg encoding: %d", ret);
+    return convertErrorCode(ret);
+  }
+
+  char* value = nullptr;
+  int native_res = metadata_extractor_get_metadata(handle_, METADATA_VIDEO_WIDTH, &value);
+  if (METADATA_EXTRACTOR_ERROR_NONE != native_res) {
+    LoggerE("Error during getting metadata: %d", native_res);
+    return convertErrorCode(native_res);
+  }
+  unsigned int width = (unsigned long)atoi(value);
+  free(value);
+  value = nullptr;
+
+  native_res = metadata_extractor_get_metadata(handle_, METADATA_VIDEO_HEIGHT, &value);
+  if (METADATA_EXTRACTOR_ERROR_NONE != native_res) {
+    LoggerE("Error during getting metadata: %d", native_res);
+    return convertErrorCode(native_res);
+  }
+  unsigned int height = (unsigned long)atoi(value);
+  free(value);
+  value = nullptr;
+
+  ret = image_util_create_image(width, height, IMAGE_UTIL_COLORSPACE_RGB888, frame, frame_size,
+                                &image);
+  if (IMAGE_UTIL_ERROR_NONE != ret) {
+    LoggerE("Error during jpg encoding: %d", ret);
+    return convertErrorCode(ret);
+  }
+
+  unsigned char* jpg_buffer = nullptr;
+  ret = image_util_encode_run_to_buffer(encode_handle, image, &jpg_buffer, buffer_size);
+  if (IMAGE_UTIL_ERROR_NONE != ret) {
+    LoggerE("Error during jpg encoding: %d", ret);
+    return convertErrorCode(ret);
+  }
+
+  // jpg_buffer is passed outside function and need to be released after usage
+  *uint8_frame = (std::uint8_t*)jpg_buffer;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult MetadataFileHandle::GetFrame(std::vector<std::uint8_t>* frame_array) {
+  ScopeLogger();
+  int size = 0;
+  size_t buffer_size = 0;
+  void* frame = nullptr;
+  char* mime_type = nullptr;
+  std::uint8_t* uint8_frame = nullptr;
+  SCOPE_EXIT {
+    free(frame);
+    free(mime_type);
+    free(uint8_frame);
+  };
+
+  int native_res = metadata_extractor_get_frame(handle_, &frame, &size);
+  if (METADATA_EXTRACTOR_ERROR_NONE != native_res) {
+    LoggerE("Error during getting metadata: %d", native_res);
+    return convertErrorCode(native_res);
+  }
+  LoggerD("Frame size %d", size);
+
+  // encode as JPEG
+  auto ret = EncodeJPEG((unsigned char*)frame, (size_t)size, &uint8_frame, &buffer_size);
+  if (!ret) {
+    return ret;
+  }
+
+  // convert frame to vector
+  std::vector<std::uint8_t> out_buf(uint8_frame, uint8_frame + buffer_size);
+
+  *frame_array = std::move(out_buf);
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 }  // namespace metadata
 }  // namespace extension
index 67d31c5..e7bcca8 100644 (file)
@@ -39,6 +39,9 @@ class MetadataFileHandle {
   common::PlatformResult Get(const std::string& type, std::string* result);
 
   common::PlatformResult GetArtwork(std::vector<std::uint8_t>* data, std::string* mime_type);
+  common::PlatformResult EncodeJPEG(unsigned char* frame, size_t frame_size,
+                                    std::uint8_t** uint8_frame, size_t* buffer_size);
+  common::PlatformResult GetFrame(std::vector<std::uint8_t>* frame_array);
 
  private:
   metadata_extractor_h handle_;
index 5e1db6b..449b9fc 100644 (file)
@@ -35,6 +35,7 @@ MetadataInstance::MetadataInstance() : next_handle_id_(1) {
   REGISTER_METHOD(MetadataManagerCreateFileHandle);
   REGISTER_METHOD(MetadataFileHandleGet);
   REGISTER_METHOD(MetadataFileHandleGetArtwork);
+  REGISTER_METHOD(MetadataFileHandleGetThumbnailFrame);
   REGISTER_METHOD(MetadataFileHandleRelease);
 #undef REGISTER_METHOD
 }
@@ -168,6 +169,41 @@ void MetadataInstance::MetadataFileHandleGetArtwork(const picojson::value& args,
   ReportSuccess(result_artwork, out);
 }
 
+void MetadataInstance::MetadataFileHandleGetThumbnailFrame(const picojson::value& args,
+                                                  picojson::object& out) {
+  ScopeLogger();
+  const std::string& uri = args.get("uri").get<std::string>();
+  const int id = static_cast<int>(args.get("id").get<double>());
+
+  auto res = InitializeHandleIfNeeded(uri, id);
+  if (!res) {
+    LogAndReportError(res, &out);
+    return;
+  }
+
+  std::vector<std::uint8_t> data;
+  std::string mime_type;
+  try {
+    MetadataFileHandle& m = handles_map_.at(id);
+
+    auto res = m.GetFrame(&data);
+    if (!res) {
+      LogAndReportError(res, &out);
+      return;
+    }
+  } catch (...) {
+    // this should never happen
+    LogAndReportError(
+        PlatformResult(ErrorCode::ABORT_ERR, "Unknown error during accessing a file."), &out);
+    return;
+  }
+
+  std::string result_artwork;
+  encode_binary_in_string(data, result_artwork);
+
+  ReportSuccess(picojson::value(result_artwork), out);
+}
+
 void MetadataInstance::MetadataFileHandleRelease(const picojson::value& args,
                                                  picojson::object& out) {
   ScopeLogger();
index 68eeddc..14e6535 100644 (file)
@@ -33,6 +33,7 @@ class MetadataInstance : public common::ParsedInstance {
   common::PlatformResult InitializeHandleIfNeeded(const std::string& uri, const int id);
   void MetadataFileHandleGet(const picojson::value& args, picojson::object& out);
   void MetadataFileHandleGetArtwork(const picojson::value& args, picojson::object& out);
+  void MetadataFileHandleGetThumbnailFrame(const picojson::value& args, picojson::object& out);
   void MetadataFileHandleRelease(const picojson::value& args, picojson::object& out);
 
   std::map<int, MetadataFileHandle> handles_map_;