[Multimedia] Fixed a bug of MetadataExtractor. 50/150650/1
authorcoderhyme <jhyo.kim@samsung.com>
Mon, 18 Sep 2017 06:59:45 +0000 (15:59 +0900)
committercoderhyme <jhyo.kim@samsung.com>
Mon, 18 Sep 2017 06:59:45 +0000 (15:59 +0900)
The issue was an extractor object is collected by GC while the object is still in use by internal members.
It happens only with the release binary and seems the compiler optimization is involved.
By this patch, the internal operation that causes an fatal error, keeps the extractor object until it ends.

Change-Id: Ie44b3207bef44ecd2b47f4f8bce9b919c2a70a40
Signed-off-by: coderhyme <jhyo.kim@samsung.com>
src/Tizen.Multimedia.Metadata/Interop/Interop.MetadataExtractor.cs
src/Tizen.Multimedia.Metadata/MetadataExtractor/Metadata.cs
src/Tizen.Multimedia.Metadata/MetadataExtractor/MetadataExtractor.cs
src/Tizen.Multimedia.Metadata/MetadataExtractor/MetadataExtractorError.cs
src/Tizen.Multimedia.Metadata/MetadataExtractor/MetadataExtractorExtensions.cs [new file with mode: 0644]

index d79e0dd..a696541 100644 (file)
@@ -35,23 +35,7 @@ internal static partial class Interop
         internal static extern MetadataExtractorError Destroy(IntPtr handle);
 
         [DllImport(Libraries.MetadataExtractor, EntryPoint = "metadata_extractor_get_metadata")]
-        private static extern MetadataExtractorError GetMetadata(IntPtr handle, MetadataExtractorAttr attribute, out IntPtr value);
-
-        internal static string GetMetadata(IntPtr handle, MetadataExtractorAttr attr)
-        {
-            IntPtr valuePtr = IntPtr.Zero;
-
-            try
-            {
-                var ret = GetMetadata(handle, attr, out valuePtr);
-                MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value for " + attr);
-                return Marshal.PtrToStringAnsi(valuePtr);
-            }
-            finally
-            {
-                Libc.Free(valuePtr);
-            }
-        }
+        internal static extern MetadataExtractorError GetMetadata(IntPtr handle, MetadataExtractorAttr attribute, out IntPtr value);
 
         [DllImport(Libraries.MetadataExtractor, EntryPoint = "metadata_extractor_get_artwork")]
         internal static extern MetadataExtractorError GetArtwork(IntPtr handle, out IntPtr artwork,
index 11b33af..e4da5a0 100755 (executable)
@@ -25,26 +25,25 @@ namespace Tizen.Multimedia
     /// </summary>
     public class VideoMetadata
     {
-        private VideoMetadata(int streamCount, IntPtr handle)
+        private VideoMetadata(int streamCount, MetadataExtractor extractor)
         {
             Debug.Assert(streamCount > 0);
-            Debug.Assert(handle != IntPtr.Zero);
 
             StreamCount = streamCount;
-            BitRate = ValueConverter.ToNullableInt(GetMetadata(handle, MetadataExtractorAttr.VideoBitrate));
-            Fps = ValueConverter.ToNullableInt(GetMetadata(handle, MetadataExtractorAttr.VideoFps));
-            Width = ValueConverter.ToNullableInt(GetMetadata(handle, MetadataExtractorAttr.VideoWidth));
-            Height = ValueConverter.ToNullableInt(GetMetadata(handle, MetadataExtractorAttr.VideoHeight));
-            Codec = GetMetadata(handle, MetadataExtractorAttr.VideoCodec);
+            BitRate = ValueConverter.ToNullableInt(extractor.GetMetadata(MetadataExtractorAttr.VideoBitrate));
+            Fps = ValueConverter.ToNullableInt(extractor.GetMetadata(MetadataExtractorAttr.VideoFps));
+            Width = ValueConverter.ToNullableInt(extractor.GetMetadata(MetadataExtractorAttr.VideoWidth));
+            Height = ValueConverter.ToNullableInt(extractor.GetMetadata(MetadataExtractorAttr.VideoHeight));
+            Codec = extractor.GetMetadata(MetadataExtractorAttr.VideoCodec);
 
             _description = new Lazy<string>(() => ObjectDescriptionBuilder.BuildWithProperties(this));
         }
 
-        internal static VideoMetadata From(IntPtr handle)
+        internal static VideoMetadata From(MetadataExtractor extractor)
         {
-            var streamCount = ValueConverter.ToInt(GetMetadata(handle, MetadataExtractorAttr.VideoStreamCount));
+            var streamCount = ValueConverter.ToInt(extractor.GetMetadata(MetadataExtractorAttr.VideoStreamCount));
 
-            return streamCount > 0 ? new VideoMetadata(streamCount, handle) : null;
+            return streamCount > 0 ? new VideoMetadata(streamCount, extractor) : null;
         }
 
         /// <summary>
@@ -103,26 +102,25 @@ namespace Tizen.Multimedia
     /// </summary>
     public class AudioMetadata
     {
-        private AudioMetadata(int streamCount, IntPtr handle)
+        private AudioMetadata(int streamCount, MetadataExtractor extractor)
         {
             Debug.Assert(streamCount > 0);
-            Debug.Assert(handle != IntPtr.Zero);
 
             StreamCount = streamCount;
-            BitRate = ValueConverter.ToNullableInt(GetMetadata(handle, MetadataExtractorAttr.AudioBitrate));
-            Channels = ValueConverter.ToNullableInt(GetMetadata(handle, MetadataExtractorAttr.AudioChannels));
-            SampleRate = ValueConverter.ToNullableInt(GetMetadata(handle, MetadataExtractorAttr.AudioSamplerate));
-            BitPerSample = ValueConverter.ToNullableInt(GetMetadata(handle, MetadataExtractorAttr.AudioBitPerSample));
-            Codec = GetMetadata(handle, MetadataExtractorAttr.AudioCodec);
+            BitRate = ValueConverter.ToNullableInt(extractor.GetMetadata(MetadataExtractorAttr.AudioBitrate));
+            Channels = ValueConverter.ToNullableInt(extractor.GetMetadata(MetadataExtractorAttr.AudioChannels));
+            SampleRate = ValueConverter.ToNullableInt(extractor.GetMetadata(MetadataExtractorAttr.AudioSamplerate));
+            BitPerSample = ValueConverter.ToNullableInt(extractor.GetMetadata(MetadataExtractorAttr.AudioBitPerSample));
+            Codec = extractor.GetMetadata(MetadataExtractorAttr.AudioCodec);
 
             _description = new Lazy<string>(() => ObjectDescriptionBuilder.BuildWithProperties(this));
         }
 
-        internal static AudioMetadata From(IntPtr handle)
+        internal static AudioMetadata From(MetadataExtractor extractor)
         {
-            var streamCount = ValueConverter.ToInt(GetMetadata(handle, MetadataExtractorAttr.AudioStreamCount));
+            var streamCount = ValueConverter.ToInt(extractor.GetMetadata(MetadataExtractorAttr.AudioStreamCount));
 
-            return streamCount > 0 ? new AudioMetadata(streamCount, handle) : null;
+            return streamCount > 0 ? new AudioMetadata(streamCount, extractor) : null;
         }
 
         /// <summary>
@@ -179,36 +177,36 @@ namespace Tizen.Multimedia
     /// </summary>
     public class Metadata
     {
-        internal Metadata(IntPtr handle)
+        internal Metadata(MetadataExtractor extractor)
         {
-            Debug.Assert(handle != IntPtr.Zero);
-
-            Video = VideoMetadata.From(handle);
-            Audio = AudioMetadata.From(handle);
-
-            Duration = ValueConverter.ToNullableInt(GetMetadata(handle, MetadataExtractorAttr.Duration));
-            Artist = GetMetadata(handle, MetadataExtractorAttr.Artist);
-            Title = GetMetadata(handle, MetadataExtractorAttr.Title);
-            Album = GetMetadata(handle, MetadataExtractorAttr.Album);
-            AlbumArtist = GetMetadata(handle, MetadataExtractorAttr.AlbumArtist);
-            Genre = GetMetadata(handle, MetadataExtractorAttr.Genre);
-            Author = GetMetadata(handle, MetadataExtractorAttr.Author);
-            Copyright = GetMetadata(handle, MetadataExtractorAttr.Copyright);
-            DateReleased = GetMetadata(handle, MetadataExtractorAttr.ReleaseDate);
-            Description = GetMetadata(handle, MetadataExtractorAttr.Description);
-            Comment = GetMetadata(handle, MetadataExtractorAttr.Comment);
-            TrackNumber = GetMetadata(handle, MetadataExtractorAttr.TrackNum);
-            Classification = GetMetadata(handle, MetadataExtractorAttr.Classification);
-            Rating = GetMetadata(handle, MetadataExtractorAttr.Rating);
-            Longitude = ValueConverter.ToNullableDouble(GetMetadata(handle, MetadataExtractorAttr.Longitude));
-            Latitude = ValueConverter.ToNullableDouble(GetMetadata(handle, MetadataExtractorAttr.Latitude));
-            Altitude = ValueConverter.ToNullableDouble(GetMetadata(handle, MetadataExtractorAttr.Altitude));
-            Conductor = GetMetadata(handle, MetadataExtractorAttr.Conductor);
-            UnsyncLyrics = GetMetadata(handle, MetadataExtractorAttr.UnSyncLyrics);
-            SyncLyricsCount = ValueConverter.ToInt(GetMetadata(handle, MetadataExtractorAttr.SyncLyricsNum));
-            DateRecorded = GetMetadata(handle, MetadataExtractorAttr.RecordingDate);
-            Rotation = GetMetadata(handle, MetadataExtractorAttr.Rotate);
-            Content360 = GetMetadata(handle, MetadataExtractorAttr.ContentFor360);
+            Debug.Assert(extractor != null);
+
+            Video = VideoMetadata.From(extractor);
+            Audio = AudioMetadata.From(extractor);
+
+            Duration = ValueConverter.ToNullableInt(extractor.GetMetadata(MetadataExtractorAttr.Duration));
+            Artist = extractor.GetMetadata(MetadataExtractorAttr.Artist);
+            Title = extractor.GetMetadata(MetadataExtractorAttr.Title);
+            Album = extractor.GetMetadata(MetadataExtractorAttr.Album);
+            AlbumArtist = extractor.GetMetadata(MetadataExtractorAttr.AlbumArtist);
+            Genre = extractor.GetMetadata(MetadataExtractorAttr.Genre);
+            Author = extractor.GetMetadata(MetadataExtractorAttr.Author);
+            Copyright = extractor.GetMetadata(MetadataExtractorAttr.Copyright);
+            DateReleased = extractor.GetMetadata(MetadataExtractorAttr.ReleaseDate);
+            Description = extractor.GetMetadata(MetadataExtractorAttr.Description);
+            Comment = extractor.GetMetadata(MetadataExtractorAttr.Comment);
+            TrackNumber = extractor.GetMetadata(MetadataExtractorAttr.TrackNum);
+            Classification = extractor.GetMetadata(MetadataExtractorAttr.Classification);
+            Rating = extractor.GetMetadata(MetadataExtractorAttr.Rating);
+            Longitude = ValueConverter.ToNullableDouble(extractor.GetMetadata(MetadataExtractorAttr.Longitude));
+            Latitude = ValueConverter.ToNullableDouble(extractor.GetMetadata(MetadataExtractorAttr.Latitude));
+            Altitude = ValueConverter.ToNullableDouble(extractor.GetMetadata(MetadataExtractorAttr.Altitude));
+            Conductor = extractor.GetMetadata(MetadataExtractorAttr.Conductor);
+            UnsyncLyrics = extractor.GetMetadata(MetadataExtractorAttr.UnSyncLyrics);
+            SyncLyricsCount = ValueConverter.ToInt(extractor.GetMetadata(MetadataExtractorAttr.SyncLyricsNum));
+            DateRecorded = extractor.GetMetadata(MetadataExtractorAttr.RecordingDate);
+            Rotation = extractor.GetMetadata(MetadataExtractorAttr.Rotate);
+            Content360 = extractor.GetMetadata(MetadataExtractorAttr.ContentFor360);
 
             _description = new Lazy<string>(() => ObjectDescriptionBuilder.BuildWithProperties(this));
         }
index 3086a9b..cb5cb5a 100755 (executable)
@@ -20,11 +20,6 @@ using System.Runtime.InteropServices;
 
 namespace Tizen.Multimedia
 {
-    static internal class MetadataExtractorLog
-    {
-        internal const string Tag = "Tizen.Multimedia.MetadataExtractor";
-    }
-
     /// <summary>
     /// Provides a means to get the metadata from a media file.
     /// </summary>
@@ -43,7 +38,7 @@ namespace Tizen.Multimedia
             {
                 MetadataExtractorRetValidator.ThrowIfError(initFunc(), "Failed to init");
 
-                _metadata = new Lazy<Metadata>(() => new Metadata(Handle));
+                _metadata = new Lazy<Metadata>(() => new Metadata(this));
             }
             catch
             {
@@ -102,7 +97,7 @@ namespace Tizen.Multimedia
             }
         }
 
-        private IntPtr Handle
+        internal IntPtr Handle
         {
             get
             {
@@ -292,12 +287,16 @@ namespace Tizen.Multimedia
             if (_buffer != IntPtr.Zero)
             {
                 Marshal.FreeHGlobal(_buffer);
+                _buffer = IntPtr.Zero;
             }
 
             if (_handle != IntPtr.Zero)
             {
                 var ret = Interop.MetadataExtractor.Destroy(_handle);
-                Log.Error(MetadataExtractorLog.Tag, $"DestroyHandle failed : {ret}.");
+                if (ret != MetadataExtractorError.None)
+                {
+                    Log.Error(typeof(MetadataExtractor).FullName, $"DestroyHandle failed : {ret}.");
+                }
 
                 _handle = IntPtr.Zero;
             }
index 71c8bca..73fd6b4 100644 (file)
@@ -32,7 +32,7 @@ namespace Tizen.Multimedia
         PermissionDenied = ErrorCode.PermissionDenied,
         TizenMetadataExtractorError = -0x01930000,
         OperationFailed = TizenMetadataExtractorError | 0x01  // Invalid operation
-    };
+    }
 
     internal static class MetadataExtractorRetValidator
     {
diff --git a/src/Tizen.Multimedia.Metadata/MetadataExtractor/MetadataExtractorExtensions.cs b/src/Tizen.Multimedia.Metadata/MetadataExtractor/MetadataExtractorExtensions.cs
new file mode 100644 (file)
index 0000000..f3b72ee
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using Native = Interop.MetadataExtractor;
+using static Interop;
+
+namespace Tizen.Multimedia
+{
+    internal static class MetadataExtractorExtensions
+    {
+        internal static string GetMetadata(this MetadataExtractor extractor, MetadataExtractorAttr attr)
+        {
+            Debug.Assert(extractor != null);
+
+            IntPtr valuePtr = IntPtr.Zero;
+
+            try
+            {
+                var ret = Native.GetMetadata(extractor.Handle, attr, out valuePtr);
+                MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value for " + attr);
+                return Marshal.PtrToStringAnsi(valuePtr);
+            }
+            finally
+            {
+                Libc.Free(valuePtr);
+            }
+        }
+
+    }
+}
\ No newline at end of file