/*
* 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.IO;
using System.Runtime.InteropServices;
namespace Tizen.Multimedia
{
static internal class MetadataExtractorLog
{
internal const string Tag = "Tizen.Multimedia.MetadataExtractor";
}
///
/// Provides a means to get the metadata from a media file.
///
public class MetadataExtractor : IDisposable
{
private bool _disposed = false;
private IntPtr _handle = IntPtr.Zero;
private IntPtr _buffer = IntPtr.Zero;
private void Create(Func initFunc)
{
MetadataExtractorRetValidator.ThrowIfError(
Interop.MetadataExtractor.Create(out _handle), "Failed to create metadata");
try
{
MetadataExtractorRetValidator.ThrowIfError(initFunc(), "Failed to init");
_metadata = new Lazy(() => new Metadata(Handle));
}
catch
{
Release();
throw;
}
}
///
/// Initializes a new instance of the MetadataExtractor class with the specified path.
///
/// 3
/// The path for the file to extract the metadata.
/// is null.
/// does not exist.
public MetadataExtractor(string path)
{
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}
Create(() => Interop.MetadataExtractor.SetPath(_handle, path));
}
///
/// Initializes a new instance of the MetadataExtractor class with the specified buffer.
///
/// 3
/// The buffer to extract the metadata.
/// is null.
/// The length of is zero.
public MetadataExtractor(byte[] buffer)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
if (buffer.Length == 0)
{
throw new ArgumentException("buffer length is zero.", nameof(buffer));
}
_buffer = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, _buffer, buffer.Length);
try
{
Create(() => Interop.MetadataExtractor.SetBuffer(_handle, _buffer, buffer.Length));
}
catch (Exception)
{
Marshal.FreeHGlobal(_buffer);
throw;
}
}
private IntPtr Handle
{
get
{
if (_disposed)
{
throw new ObjectDisposedException(nameof(MetadataExtractor));
}
return _handle;
}
}
private Lazy _metadata;
///
/// Retrieves the .
///
/// 3
/// The for the given source.
/// An internal process error occurs.
/// The has been already disposed of.
public Metadata GetMetadata()
{
if (_disposed)
{
throw new ObjectDisposedException(nameof(MetadataExtractor));
}
return _metadata.Value;
}
///
/// Gets the artwork image in the source.
///
/// 3
/// The if it exists, otherwise null.
/// An internal process error occurs.
/// The has been already disposed of.
public Artwork GetArtwork()
{
IntPtr data = IntPtr.Zero;
IntPtr mimeType = IntPtr.Zero;
try
{
int size = 0;
var ret = Interop.MetadataExtractor.GetArtwork(Handle, out data, out size, out mimeType);
MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
if (size > 0)
{
var buf = new byte[size];
Marshal.Copy(data, buf, 0, size);
return new Artwork(buf, Marshal.PtrToStringAnsi(mimeType));
}
return null;
}
finally
{
Interop.Libc.Free(data);
Interop.Libc.Free(mimeType);
}
}
///
/// Gets the sync lyrics of the source.
///
/// 3
/// The index of lyrics to retrieve.
/// The object if is valid, otherwise null.
/// An internal process error occurs.
/// The has been already disposed of.
public SyncLyrics GetSyncLyrics(int index)
{
IntPtr lyrics = IntPtr.Zero;
try
{
uint timestamp = 0;
var ret = Interop.MetadataExtractor.GetSynclyrics(Handle, index, out timestamp, out lyrics);
MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get sync lyrics");
if (lyrics == IntPtr.Zero)
{
return null;
}
return new SyncLyrics(Marshal.PtrToStringAnsi(lyrics), timestamp);
}
finally
{
Interop.Libc.Free(lyrics);
}
}
///
/// Gets the frame of a video media.
///
/// 3
/// The raw thumbnail data in RGB888 if it exists, otherwise null.
/// An internal process error occurs.
/// The has been already disposed of.
public byte[] GetVideoThumbnail()
{
IntPtr data = IntPtr.Zero;
try
{
int size = 0;
var ret = Interop.MetadataExtractor.GetFrame(Handle, out data, out size);
MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
if (size == 0)
{
return null;
}
var buf = new byte[size];
Marshal.Copy(data, buf, 0, size);
return buf;
}
finally
{
Interop.Libc.Free(data);
}
}
///
/// Gets the frame of a video media.
///
/// 3
/// The timestamp in milliseconds.
/// true to get an accurate frame for the given timestamp,
/// otherwise false to get the nearest i-frame of the video rapidly.
/// The raw frame data in RGB888 if a frame at specified time exists, otherwise null.
/// An internal error occurs.
/// The has been already disposed of.
public byte[] GetFrameAt(uint timeStamp, bool accurate)
{
IntPtr data = IntPtr.Zero;
try
{
int size = 0;
var ret = Interop.MetadataExtractor.GetFrameAtTime(Handle, timeStamp, accurate, out data, out size);
MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
if (size == 0)
{
return null;
}
var buf = new byte[size];
Marshal.Copy(data, buf, 0, size);
return buf;
}
finally
{
Interop.Libc.Free(data);
}
}
~MetadataExtractor()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
Release();
_disposed = true;
}
}
private void Release()
{
if (_buffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(_buffer);
}
if (_handle != IntPtr.Zero)
{
var ret = Interop.MetadataExtractor.Destroy(_handle);
Log.Error(MetadataExtractorLog.Tag, $"DestroyHandle failed : {ret}.");
_handle = IntPtr.Zero;
}
}
///
/// Releases all resources used by the object.
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}