The Problem
I recently developed a video content management system, and rather than store hidden files to track versioning and movement of physical files, I wanted to modify the internal file meta information of the videos themselves. I planned to stuff a database ID into the comment tag within each video file, but this proved to be very challenging given the very disoraganised way in which various operating system handled different file types.
Possible Solutions
MediaInfo -
http://sourceforge.net/projects/mediainfo/. Cool API, updated a lot, but there is no support for setting file meta information. The entire API is READ ONLY!
TagLib -
https://taglib.github.io/. Again, good API with scope to set file tag meta information. So I decided to try this API out and see how far I could get with it. I started hitting it's limits when I couldn't set file meta information for a LOT of video file types: MKV, MOV, 3GP, ASF and more.
DsoFile -
http://support.microsoft.com/en-gb/kb/224351. Microsoft's answer to tagging Microsoft Office file tag information. It's able to set Office file tags but also totally new custom properties within each file. You cannot see these values in Windows Explorer without a handy Powershell script plugin, but it works for ALL file types, not just office documents. It's written in C++ and includes the source code also. The downside is that it's a COM component, 32bit and no longer supported. However, somebody compiled a 64bit version
here
The Ideal Solution
DsoFile seems like a great solution to the problem. TagLib works hard to achieve an ideal solution, but there are too many file types out there ever changing and the library finds it hard to keep up. I decided to use DsoFile for my project for the time being. I have provided some sample code below so you can see how TagLib and DsoFile libraries modify file meta tag information.
TagLib Sample Code - How to Get and Set the Comment File Meta Tag Field
Code Snippet
using System;
using TagLib;
/// <summary>
/// (c) GinkoSolutions.com
/// This sample class enables you to set meta file information within physical files.
/// This is similar to EXIF information for picture files.
/// TagLib doesn't seem to work for a lot of file types: MKV, MOV etc
/// It seems to work ok for MP4 files though.
/// </summary>
public static class TagLibExample
{
/// <summary>
/// Gets the comment tag from a files meta information
/// </summary>
/// <param name="filename">Path to the file</param>
/// <returns>Our custom value stored in the files comment tag</returns>
public static string GetCommentField(string filename)
{
string comment = string.Empty;
TagLib.File file = null;
try
{
file = TagLib.File.Create(filename);
comment = file.Tag.Comment;
}
catch (Exception ex)
{
// This library works with limited file types, so unsupported file types are
// thrown here when trying to use "TagLib.File.Create()"
}
finally
{
if (file != null) file.Dispose(); // Clean up
}
return comment;
}
/// <summary>
/// Sets the comment tag within a files meta information
/// </summary>
/// <param name="filename">Path to the file</param>
/// <param name="value">Value to store in the comment tag</param>
public static void SetCommentField(string filename, string value)
{
TagLib.File file = null;
try
{
file = TagLib.File.Create(filename);
// Set comment tag
// NOTE: file.Tag.Comment cannot be an empty string, it defaults to null if empty
file.Tag.Comment = GetCommentField;
file.Save();
// Check comment was added successfully.
// For some reason, TagLib won't throw an error if the property doesnt save
// for certain file types, yet they appear to be supported.
// So we have to check it actually worked...
file = TagLib.File.Create(filename);
if (file.Tag.Comment != value)
throw new Exception
("Could not set comment tag. This file format is not supported.");
}
catch (Exception ex)
{
// Handle errors here
}
finally // Always called, even when throwing in Exception block
{
if (file != null) file.Dispose(); // Clean up
}
}
}
DsoFile Sample Code - How to Store a Value into a Custom Property and Get it back!
Code Snippet
using System;
using DSOFile;
/// <summary>
/// (c) GinkoSolutions.com
/// This sample class enables you to set meta file information within physical files.
/// This is similar to EXIF information for picture files.
/// DSOFile works for every file type, not just office files.
///
/// NOTE
/// DsoFile is an unmnaged 32bit dll. We need to compile in x86 mode or we get 'class not registered exception'
/// There is a third party 64bit version available online, or recompile the C++ source manually.
/// </summary>
public static class DSOFileExample
{
/// <summary>
/// A property name that this sample code uses to store tag information.
/// </summary>
private static string FILE_PROPERTY = "CustomFileTag";
/// <summary>
/// Gets value stored in a custom tag
/// </summary>
/// <param name="filename">Path to the file</param>
/// <returns>Our custom value stored in the custom file tag</returns>
public static string GetCustomPropertyValue(string filename)
{
string comment = string.Empty;
OleDocumentProperties file
= new DSOFile
.OleDocumentProperties();
try
{
// Open file
file.Open(filename, false, DSOFile.dsoFileOpenOptions.dsoOptionDefault);
comment = GetTagField(file);
}
catch (Exception ex)
{
// Handle errors here
}
finally
{
if (file != null) file.Close(); // Clean up
}
return comment;
}
/// <summary>
/// Sets value stored in a files custom tag
/// </summary>
/// <param name="filename">Path to the file</param>
/// <param name="value">Value to store in the custom file tag</param>
public static void SetCustomPropertyValue(string filename, string value)
{
OleDocumentProperties file
= new DSOFile
.OleDocumentProperties();
try
{
file.Open(filename, false, DSOFile.dsoFileOpenOptions.dsoOptionDefault);
SetTagField(file, value);
}
catch (Exception ex)
{
// Handle errors here
}
finally // Always called, even when throwing in Exception block
{
if (file != null) file.Close(); // Clean up
}
}
/// <summary>
/// Gets the value of the file tag property
/// </summary>
/// <param name="file">Ole Document File</param>
/// <returns>Contents of the file tag property. Can be null or empty.</returns>
private static string GetTagField(DSOFile.OleDocumentProperties file)
{
string result = string.Empty;
foreach (DSOFile.CustomProperty property in file.CustomProperties)
{
if (property.Name == FILE_PROPERTY) // Check property exists
{
result = property.get_Value();
break;
}
}
return result;
}
/// <summary>
/// Sets the value of the file tag property
/// </summary>
/// <param name="file">Ole Document File</param>
/// <param name="value">Value to set as the property value</param>
/// <param name="saveDocument">Saves document if set to true</param>
/// <param name="closeDocument">Closes the document if set to true</param>
private static void SetTagField(DSOFile.OleDocumentProperties file, string value, bool saveDocument = true, bool closeDocument = true)
{
bool found = false;
foreach (DSOFile.CustomProperty property in file.CustomProperties)
{
if (property.Name == FILE_PROPERTY) // Check property exists
{
property.set_Value(value);
found = true;
break;
}
}
if (!found)
file.CustomProperties.Add(FILE_PROPERTY, value);
if (saveDocument)
file.Save();
if (closeDocument)
file.Close();
}
}