summaryrefslogtreecommitdiffstats
path: root/src/metadata/rmff/rmff.h
blob: 326b8ae0730e5ed80ef3fbc6c51091b040089157 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
/***************************************************************************
      copyright            : (C) 2005 by Paul Cifarelli
      email                : [email protected]
 ***************************************************************************/

/***************************************************************************
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 51 Franklin St, 5th fl, Boston, MA 02110-1301,      *
 *   USA, or check http://www.fsf.org/about/contact.html                   *
 *                                                                         *
 *   Note that no RealNetworks code appears or is duplicated, copied, or   *
 +   used as a template in this code.  The code was written from scratch   *
 *   using the reference documentation found at:                           *
 *                                                                         *
 *   https://common.helixcommunity.org/nonav/2003/HCS_SDK_r5/helixsdk.htm  *
 *                                                                         *
 ***************************************************************************/
#ifndef _RMFF_H_INCLUDED_
#define _RMFF_H_INCLUDED_

#include <config.h>

namespace TagLib
{
   namespace RealMedia
   {
#if SIZEOF_LONG == 4
      typedef unsigned long  UINT32;
#elif SIZEOF_INT == 4
      typedef unsigned int  UINT32;
#else
#error At least 1 builtin type needs to be 4 bytes!!
#endif
      typedef unsigned short UINT16;
      typedef unsigned char  UINT8;

      static const int RMFF_HDR_SIZE = 8;  // packed hdr size

      // some assumptions on these 2 enum defs, based solely on the order they are listed on the website
      enum PROPERTY_TYPES
      {
         MPT_TEXT = 1, // The value is string data.
         MPT_TEXTLIST, // The value is a separated list of strings, 
                       // separator specified as sub-property/type descriptor.
         MPT_FLAG,     // The value is a boolean flag-either 1 byte or 4 bytes, check size value.
         MPT_ULONG,    // The value is a four-byte integer.
         MPT_BINARY,   // The value is a byte stream.
         MPT_URL,      // The value is string data.
         MPT_DATE,     // The value is a string representation of the date in the form: 
                       // YYYYmmDDHHMMSS (m = month, M = minutes).
         MPT_FILENAME, // The value is string data.
         MPT_GROUPING, // This property has subproperties, but its own value is empty.
         MPT_REFERENCE // The value is a large buffer of data, use sub-properties/type 
                       // descriptors to identify mime-type.
      };

      enum PROPERTY_FLAGS
      {
         MPT_READONLY = 1,       // Read only, cannot be modified.
         MPT_PRIVATE = 2,        // Private, do not expose to users.
         MPT_TYPE_DESCRIPTOR = 4 // Type descriptor used to further define type of value.
      };
      
      struct Collectable
      {
         Collectable() : fwd(0) {}
         virtual ~Collectable() {}
         Collectable *fwd;
      };
      
      struct File_Header_Start
      {
         UINT32    object_id;
         UINT32    size;
      };
      
      struct File_Header_v0_v1 : public Collectable
      {
         File_Header_Start s;
         UINT16   object_version;
         
         UINT32   file_version;
         UINT32   num_headers;
      };
      
      struct RMProperties : public Collectable
      {
         File_Header_Start s;
         UINT16   object_version;
         
         UINT32   max_bit_rate;
         UINT32   avg_bit_rate;
         UINT32   max_packet_size;
         UINT32   avg_packet_size;
         UINT32   num_packets;
         UINT32   duration;
         UINT32   preroll;
         UINT32   index_offset;
         UINT32   data_offset;
         UINT16   num_streams;
         UINT16   flags;
      };


      struct NameValueProperty
      {
         NameValueProperty() : name(0), value_data(0) {}
         virtual ~NameValueProperty() { delete [] name; delete [] value_data; }

         UINT32   size;
         UINT16   object_version;

         UINT8    name_length;
         UINT8   *name;
         UINT32   type;
         UINT16   value_length;
         UINT8   *value_data;
      }; 


      struct LogicalStream
      {
         LogicalStream() : physical_stream_numbers(0), data_offsets(0), rule_to_physical_stream_number_map(0), properties(0) {}
         virtual ~LogicalStream() 
            { delete [] physical_stream_numbers; delete [] data_offsets; 
            delete [] rule_to_physical_stream_number_map; delete [] properties; }

         UINT32  size;
         UINT16  object_version;

         UINT16              num_physical_streams;
         UINT16             *physical_stream_numbers;
         UINT32             *data_offsets;
         UINT16              num_rules;
         UINT16             *rule_to_physical_stream_number_map;
         UINT16              num_properties;
         NameValueProperty  *properties;
      }; 
      
      struct MediaProperties : public Collectable
      {
         MediaProperties() : type_specific_data(0), lstr(0) {}
         virtual ~MediaProperties() { delete lstr; delete [] type_specific_data;  }
         
         File_Header_Start s;
         UINT16   object_version;
         
         UINT16   stream_number;
         UINT32   max_bit_rate;
         UINT32   avg_bit_rate;
         UINT32   max_packet_size;
         UINT32   avg_packet_size;
         UINT32   start_time;
         UINT32   preroll;
         UINT32   duration;
         UINT8    stream_name_size;
         UINT8    stream_name[256];
         UINT8    mime_type_size;
         UINT8    mime_type[256];
         UINT32   type_specific_len;
         UINT8   *type_specific_data;

         LogicalStream *lstr; // only one of these
      };
      
      
      struct ContentDescription : public Collectable
      {
         ContentDescription() : title(0), author(0), copyright(0), comment(0) {}
         virtual ~ContentDescription() { delete [] title; delete [] author; delete [] copyright; delete [] comment; }
         
         File_Header_Start s;
         UINT16   object_version;
         
         UINT16   title_len;
         UINT8   *title;
         UINT16   author_len;
         UINT8   *author;
         UINT16   copyright_len;
         UINT8   *copyright;
         UINT16   comment_len;
         UINT8   *comment;
      };
      
      
      struct PropListEntry
      {
         UINT32 offset;
         UINT32 num_props_for_name;
      };
      
      struct MDProperties
      {
         MDProperties() : name(0), value(0), subproperties(0) {}
         virtual ~MDProperties() 
            { delete [] name; delete [] value; delete [] subproperties_list; delete [] subproperties; }
         
         UINT32            size;
         UINT32            type;
         UINT32            flags;
         UINT32            value_offset;
         UINT32            subproperties_offset;
         UINT32            num_subproperties;
         UINT32            name_length;
         UINT8            *name;
         UINT32            value_length;
         UINT8            *value;
         PropListEntry    *subproperties_list; // num_subproperties 
         MDProperties     *subproperties;      // num_subproperties
      };
      
      struct MetadataSection : public Collectable
      {
         File_Header_Start s;
         
         UINT32  object_id;
         UINT32  object_version;

         // this is the 1 "unnamed root property"         
         MDProperties properties;
      };
      
      class Tag;
      class File;
      
      // RealMedia File Format contains a normal ID3v1 Tag at the end of the file
      // no sense reinventing the wheel, so this class is just so we can use TagLib
      // to manage it
      class RMFFile : public TagLib::File
      {
      public:
         RMFFile(const char *filename);
         virtual ~RMFFile();
         bool save();
         TagLib::Tag *tag() const { return m_id3tag; }
         TagLib::AudioProperties *audioProperties() const { return 0; }
         
      private:
         TagLib::ID3v1::Tag *m_id3tag;
      };
      
      class TagLib::AudioProperties;
      
      class RealMediaFF
      {
      public:
         RealMediaFF(const char *file, bool readProperties = true, 
                     TagLib::AudioProperties::ReadStyle propertiesStyle = TagLib::AudioProperties::Average);
         RealMediaFF(RealMediaFF &src);
         ~RealMediaFF();
         
         int err() const { return m_err; }
         bool isEmpty() const;
         
         // tag
         TagLib::String   title () const;
         TagLib::String   artist () const;
         TagLib::String   album () const;
         TagLib::String   comment () const;
         TagLib::String   genre () const;
         TagLib::uint     year () const;
         TagLib::uint     track () const;
         // TODO write support
         //void     setTitle (const String &s);
         //void     setArtist (const String &s);
         //void     setAlbum (const String &s);
         //void     setComment (const String &s);
         //void     setGenre (const String &s);
         //void     setYear (uint i);
         //void     setTrack (uint i);
         
         // properties
         int length () const;
         int bitrate () const;
         int sampleRate () const;
         int channels () const;
         
#ifdef TESTING
         std::ostream &operator<<(std::ostream &os);
#endif
         
      private:
         RealMediaFF();
         char               *m_filename;
         Collectable        *m_head;
         Collectable        *m_tail;
         int                 m_fd;
         int                 m_err;
         
         File_Header_v0_v1  *m_hdr;
         RMProperties       *m_props;
         MediaProperties    *media_hdrs;
         ContentDescription *m_contenthdr;
         MetadataSection    *m_md;
         
         char               *m_title;
         char               *m_author;
         char               *m_copyright;
         char               *m_comment;
         
         RMFFile            *m_id3v1tag;

         bool                m_flipYearInMetadataSection;
         bool                m_readProperties;

         int init();
         int initMetadataSection();
         void saveHeader(Collectable *hdr);
         int seekChunk(UINT32 object_id);
         
         int getHdr(unsigned char *buf, size_t sz, UINT32 &fourcc, UINT32 &csz);
         int getChunk(unsigned char *buf, size_t sz, UINT32 &fourcc, UINT32 &csz, UINT32 &consumed);
         int getRealFileHeader(File_Header_v0_v1 *hdr, const unsigned char *buf, UINT32 object_id, int sz);
         int getRealPropertyHeader(RMProperties *props, const unsigned char *buf, UINT32 object_id, int sz);
         int getMediaPropHeader(MediaProperties *mh, const unsigned char *buf, UINT32 object_id, int sz);
         int getContentDescription(ContentDescription *cont, const unsigned char *buf, UINT32 object_id, int sz);
         int getMDProperties(MDProperties *md, const unsigned char *buf);

#ifdef TESTING         
         void printRealFileHeader(std::ostream &os);
         void printRealPropHeader(std::ostream &os);
         void printMediaPropHeaders(std::ostream &os);
         void printContentDescription(std::ostream &os);
         void printID3v1Tag(std::ostream &os);
         void printMetadataSection(std::ostream &os);
         void printMDProperties(std::ostream &os, char *name, MDProperties *props);
#endif
      };
      
   } // namespace RealMedia
} // namespace TagLib

#ifdef TESTING
std::ostream &operator<<(std::ostream &os, TagLib::RealMedia::RealMediaFF &rmff);
#endif

#endif