1 /**
2  * Object oriented wrapper for $(LINK2 http://mediainfo.sourceforge.net/Support/SDK, MediaInfo)
3  * License:
4  * This wrapper $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
5  * MediaInfo $(LINK2 http://www.gnu.org/licenses/lgpl-3.0.txt, LGPL 3.0)
6  * Authors: Johannes Pfau, Carsten Schlote
7  */
8 module mediainfo;
9 
10 import std.string;
11 import std.conv;
12 import std.typecons;
13 
14 import mediainfodll;
15 
16 //public alias MediaInfo_stream_t Stream;
17 //public alias MediaInfo_info_t Info;
18 
19 /** A exception of the mediainfo wrapper */
20 public class MediaInfoException : Exception
21 {
22     /// Constuctor
23     public this(string msg)
24     {
25         super(msg);
26     }
27 }
28 
29 /** This is the UTF Wrapper for libmediainfo */
30 public struct MediaInfo
31 {
32 private:
33     struct Payload
34     {
35         void* _payload;
36         this(void* h)
37         {
38             _payload = h;
39         }
40         ~this()
41         {
42             if(_payload)
43             {
44                 mediainfo_FunctionTable.MediaInfo_Delete(_payload);
45                 _payload = null;
46 				MediaInfoDLL_UnLoad();
47             }
48         }
49         // Should never perform these operations
50         this(this) { assert(false); }
51         void opAssign(MediaInfo.Payload rhs) { assert(false); }
52     }
53 
54     alias Data = RefCounted!(Payload, RefCountedAutoInitialize.no);
55     Data _data;
56 
57     @property void* handle()
58     {
59         return _data._payload;
60     }
61 
62 public:
63 
64     /** Use call operator to initialize resource */
65     static MediaInfo opCall()
66     {
67         MediaInfo info;
68         const auto rc = MediaInfoDLL_Load();
69         if(rc != 1) {
70             throw new MediaInfoException("Couldn't open mediainfo library");
71         }
72 
73         const auto h = mediainfo_FunctionTable.MediaInfo_New();
74         info._data.refCountedStore.ensureInitialized();
75         info._data._payload = cast(void*)h;
76         return info;
77     }
78 
79     /**
80      * Open a file.
81      * Open a file and collect information about it (technical information and tags)
82      *
83      * Parameters:
84      * fileName = Full name of file to open
85      */
86     void open(string fileName)
87     {
88         version(Workaround_UTF_Bug) {
89             import std.stdio : File;
90             auto fh = File(fileName);
91             scope(exit) fh.close;
92             this.openBufferInit(fh.size, 0);
93 
94             //The parsing loop
95             ubyte[4096] rawbuffer;
96             ubyte[] buffer;
97             do
98             {
99                 // Read some data to buffer...
100                 buffer = fh.rawRead(rawbuffer);
101                 // Sending the buffer to MediaInfo
102                 const auto status = this.openBufferContinue(buffer.ptr, buffer.length);
103                 if (status&0x08) //Bit3=Finished
104                     break;
105                 // Testing if there is a MediaInfo request to go elsewhere
106                 if (this.openBufferContinueGoToGet() != -1 )
107                 {
108                     // Position the file
109                     import core.stdc.stdio : SEEK_SET;
110                     fh.seek(this.openBufferContinueGoToGet(), SEEK_SET);
111                     // Informing MediaInfo we have seek
112                     this.openBufferInit(fh.size, fh.tell);
113                 }
114             }
115             while (buffer.length > 0);
116             //This is the end of the stream, MediaInfo must finnish some work
117             this.openBufferFinalize();
118         }
119         else {
120             static MediaInfo_Char* _fileNameRef;
121             import std.utf : toUTFz;
122             auto  filename = fileName.toUTFz!(MediaInfo_Char*);
123             const auto rc = mediainfo_FunctionTable.MediaInfo_Open(handle, filename);
124             if(!rc)
125             {
126                 throw new MediaInfoException("Couldn't open file: " ~ fileName);
127             }
128             _fileNameRef = fileName;
129         }
130     }
131 /+        /**
132      * Open a buffer.
133      * Open a Buffer (Begin and end of the stream) and collect information about it (technical information and tags)
134      * Params:
135      * begin = First bytes of the buffer
136      * begin_size = Size of Begin
137      * end = Last bytes of the buffer
138      * end_size = Size of End
139      * file_size = Total size of the file
140      */
141     void open(ubyte* begin, size_t begin_size, ubyte* end, size_t end_size)
142     {
143         if(MediaInfo_Open_Buffer(handle, begin, begin_size, end, end_size))
144         {
145             throw new MediaInfoException("Couldn't open file from buffer");
146         }
147     }
148 +/
149     /**
150      * Open a stream (Init).
151      *
152      * Open a stream and collect information about it (technical information and tags)
153      *
154      * Params:
155      * fileSize = Estimated file size
156      * fileOffset = Offset of the file (if we don't have the beginning of the file)
157      */
158     size_t openBufferInit(long fileSize = -1, long fileOffset = 0)
159     {
160         return mediainfo_FunctionTable.MediaInfo_Open_Buffer_Init(handle, fileSize, fileOffset);
161     }
162     /**
163      * Open a stream (Continue).
164      *
165      * Open a stream and collect information about it (technical information and tags)
166      *
167      * Params:
168      * buffer = pointer to the stream
169      * size =Count of bytes to read
170      */
171     size_t openBufferContinue(ubyte* buffer, size_t size)
172     {
173         return mediainfo_FunctionTable.MediaInfo_Open_Buffer_Continue(handle, buffer, size);
174     }
175     /**
176      * Open a stream (Get the needed file Offset).
177      *
178      * Open a stream and collect information about it (technical information and tags)
179      *
180      * Returns:
181      * the needed offset of the file
182      * File size if no more bytes are needed
183      */
184     long openBufferContinueGoToGet()
185     {
186         return mediainfo_FunctionTable.MediaInfo_Open_Buffer_Continue_GoTo_Get(handle);
187     }
188     /**
189      * Open a stream (Finalize).
190      *
191      * Open a stream and collect information about it (technical information and tags)
192      */
193     size_t openBufferFinalize()
194     {
195         return mediainfo_FunctionTable.MediaInfo_Open_Buffer_Finalize(handle);
196     }
197 /+        /**
198      * (NOT IMPLEMENTED YET) Save the file
199      *
200      * (NOT IMPLEMENTED YET) Save the file opened before with Open() (modifications of tags)
201      */
202     void save()
203     {
204         if(mediainfo_FunctionTable.MediaInfo_Save(handle))
205         {
206             throw new MediaInfoException("Couldn't save file");
207         }
208     }
209 +/
210     /**
211      * Close a file.
212      *
213      * Close a file opened before with Open() (without saving)
214      *
215      * Warning:
216      * without have saved before, modifications are lost
217      */
218     void close()
219     {
220         mediainfo_FunctionTable.MediaInfo_Close(handle);
221         version(Workaround_UTF_Bug) {} else _fileNameRef = null;
222     }
223     /**
224      * String MediaInfoLib::MediaInfo::Inform   (   size_t  Reserved = 0     )
225      * Get all details about a file.
226      *
227      * Get all details about a file in one string
228      *
229      * Precondition:
230      * You can change default presentation with Inform_Set()
231      */
232     string inform(size_t reserved = 0)
233     {
234         import std.utf : toUTFz;
235         const auto strptr = mediainfo_FunctionTable.MediaInfo_Inform(handle, reserved);
236         auto str = strptr.fromStringz;
237         return to!string(str);
238     }
239     /**
240      * Get a piece of information about a file (parameter is an integer).
241      *
242      * Get a piece of information about a file (parameter is an integer)
243      *
244      * Params:
245      * streamKind = Kind of stream (general, video, audio...)
246      * streamNumber = Stream number in Kind of stream (first, second...)
247      * parameter = Parameter you are looking for in the stream (Codec, width, bitrate...), in integer format (first parameter, second parameter...)
248      * infoKind = Kind of information you want about the parameter (the text, the measure, the help...)
249      * Returns:
250      * a string about information you search
251      * an empty string if there is a problem
252      */
253     string get(MediaInfo_stream_t streamKind, size_t streamNumber, size_t parameter,
254         MediaInfo_info_t infoKind = MediaInfo_info_t.MediaInfo_Info_Text)
255     {
256         import std.utf : toUTFz;
257         const auto strptr = mediainfo_FunctionTable.MediaInfo_GetI(handle, streamKind, streamNumber,
258             parameter, infoKind);
259         auto str = strptr.fromStringz;
260         return to!string(str);
261     }
262     /**
263      * Get a piece of information about a file (parameter is a string).
264      *
265      * Get a piece of information about a file (parameter is a string)
266      *
267      * Params:
268      * streamKind = Kind of stream (general, video, audio...)
269      * streamNumber = Stream number in Kind of stream (first, second...)
270      * parameter = Parameter you are looking for in the stream (Codec, width, bitrate...), in string format ("Codec", "Width"...)
271      * See MediaInfo::Option("Info_Parameters") to have the full list
272      * infoKind = Kind of information you want about the parameter (the text, the measure, the help...)
273      * searchKind = Where to look for the parameter
274      * Returns:
275      * a string about information you search
276      * an empty string if there is a problem
277      */
278     string get(MediaInfo_stream_t streamKind, size_t streamNumber,
279         string parameter, MediaInfo_info_t infoKind = MediaInfo_info_t.MediaInfo_Info_Text,
280         MediaInfo_info_t searchKind = MediaInfo_info_t.MediaInfo_Info_Name)
281     {
282         import std.utf : toUTFz;
283         MediaInfo_Char* parameterZ = parameter.toUTFz!(MediaInfo_Char*);
284         const auto strptr = mediainfo_FunctionTable.MediaInfo_Get(handle, 
285             streamKind, streamNumber, parameterZ, infoKind, searchKind);
286         auto str = strptr.fromStringz;
287         return to!string(str);
288     }
289 /+        /**
290      * (NOT IMPLEMENTED YET) Set a piece of information about a file (parameter is an int)
291      *
292      * (NOT IMPLEMENTED YET) Set a piece of information about a file (parameter is an integer)
293      *
294      * Warning:
295      * Not yet implemented, do not use it
296      * Params:
297      * toSet = Piece of information
298      * streamKind = Kind of stream (general, video, audio...)
299      * streamNumber = Stream number in Kind of stream (first, second...)
300      * parameter = Parameter you are looking for in the stream (Codec, width, bitrate...), in integer format (first parameter, second parameter...)
301      * oldValue = The old value of the parameter
302      * if OldValue is empty and ToSet is filled: tag is added
303      * if OldValue is filled and ToSet is filled: tag is replaced
304      * if OldValue is filled and ToSet is empty: tag is deleted
305      */
306     void set(const(string) toSet, Stream streamKind, size_t streamNumber,
307         size_t parameter, const(string) oldValue = "")
308     {
309         if(!mediainfo_FunctionTable.MediaInfo_SetI(handle, toStringz(toSet), streamKind, streamNumber,
310             parameter, toStringz(oldValue)))
311         {
312             throw new MediaInfoException("Couldn't set parameter");
313         }
314     }
315     /**
316      * (NOT IMPLEMENTED YET) Set information about a file (parameter is a string)
317      *
318      * (NOT IMPLEMENTED YET) Set a piece of information about a file (parameter is a string)
319      *
320      * Warning:
321      * Not yet implemented, do not use it
322      * Params:
323      * toSet = Piece of information
324      * streamKind = Kind of stream (general, video, audio...)
325      * streamNumber = Stream number in Kind of stream (first, second...)
326      * parameter = Parameter you are looking for in the stream (Codec, width, bitrate...), in string format
327      * oldValue = The old value of the parameter
328      * if OldValue is empty and ToSet is filled: tag is added
329      * if OldValue is filled and ToSet is filled: tag is replaced
330      * if OldValue is filled and ToSet is empty: tag is deleted
331      */
332     void set(const(string) toSet, Stream streamKind, size_t streamNumber,
333         const(string) parameter, const(string) oldValue = "")
334     {
335         if(!mediainfo_FunctionTable.MediaInfo_Set(handle, toStringz(toSet), streamKind, streamNumber,
336             toStringz(parameter), toStringz(oldValue)))
337         {
338             throw new MediaInfoException("Couldn't set parameter");
339         }
340     }
341 +/
342     /**
343      * Output the written size when "File_Duplicate" option is used.
344      *
345      * Output the written size when "File_Duplicate" option is used.
346      *
347      * Params:
348      * value = The unique name of the duplicated stream (begin with "memory://")
349      * Returns:
350      * The size of the used buffer
351      */
352     size_t outputBufferGet(const(string) value)
353     {
354         import std.utf : toUTFz;
355         MediaInfo_Char* valueZ = value.toUTFz!(MediaInfo_Char*);
356         return mediainfo_FunctionTable.MediaInfo_Output_Buffer_Get(handle, valueZ);
357     }
358     /**
359      * Output the written size when "File_Duplicate" option is used.
360      *
361      * Output the written size when "File_Duplicate" option is used.
362      *
363      * Params:
364      * pos = The position ?
365      * Returns:
366      * The size of the used buffer
367      */
368     size_t outputBufferGet(size_t pos)
369     {
370         return mediainfo_FunctionTable.MediaInfo_Output_Buffer_GetI(handle, pos);
371     }
372     /**
373      * Configure or get information about MediaInfoLib
374      *
375      * Params:
376      * option = The name of option
377      * value = The value of option
378      * Returns:
379      * Depend of the option: by default "" (nothing) means No, other means Yes
380      */
381     string option(const(string) option, const(string) value = "")
382     {
383         import std.utf : toUTFz;
384         MediaInfo_Char* optionZ = option.toUTFz!(MediaInfo_Char*);
385         MediaInfo_Char* valueZ = value.toUTFz!(MediaInfo_Char*);
386         const auto strptr = mediainfo_FunctionTable.MediaInfo_Option(handle, optionZ, valueZ);
387         auto str = strptr.fromStringz;
388         return to!string(str);
389     }
390 
391     /*
392     static string optionStatic(const(string) option, const(string) value = "")
393     {
394         return to!string(mediainfo_FunctionTable.MediaInfo_Option_Static(handle, toStringz(option), toStringz(value)));
395     }*/
396 
397     /**
398      * (NOT IMPLEMENTED YET) Get the state of the library
399      *
400      * Return values:
401      * <1000    No information is available for the file yet
402      * >=1000_<5000     Only local (into the file) information is available, getting Internet information (titles only) is no finished yet
403      * 5000     (only if Internet connection is accepted) User interaction is needed (use Option() with "Internet_Title_Get")
404      * Warning: even there is only one possible, user interaction (or the software) is needed
405      * >5000<=10000     Only local (into the file) information is available, getting Internet information (all) is no finished yet
406      * <10000   Done
407      */
408     size_t getState()
409     {
410         return mediainfo_FunctionTable.MediaInfo_State_Get(handle);
411     }
412     /**
413      * Count of streams of a stream kind (StreamNumber not filled), or count of piece of information in this stream.
414      *
415      * Params:
416      * streamKind = Kind of stream (general, video, audio...)
417      * streamNumber = Stream number in this kind of stream (first, second...)
418      */
419     size_t getCount(MediaInfo_stream_t streamKind, size_t streamNumber = -1)
420     {
421         return mediainfo_FunctionTable.MediaInfo_Count_Get(handle, streamKind, streamNumber);
422     }
423 }