Amarok – versatile and easy to use audio player
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

376 lines
13 KiB

copyright : (C) 2005 by Paul Cifarelli
email :
* 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 *
* 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 *
* *
* 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: *
* *
* *
* *
#include <config.h>
#include <string.h>
namespace TagLib
class AudioProperties;
namespace RealMedia
#if SIZEOF_LONG == 4
typedef unsigned long UINT32;
#elif SIZEOF_INT == 4
typedef unsigned int UINT32;
#error At least 1 builtin type needs to be 4 bytes!!
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
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.
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
File_Header_Start() : object_id(0), size(0) {}
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
: size(0), object_version(0), name_length(0), name(0), type(0)
, value_length(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
: size(0), object_version(0), num_physical_streams(0)
, physical_stream_numbers(0), data_offsets(0), num_rules(0)
, rule_to_physical_stream_number_map(0), num_properties(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
: object_version(0), stream_number(0), max_bit_rate(0)
, avg_bit_rate(0), max_packet_size(0), avg_packet_size(0)
, start_time(0), preroll(0), duration(0), stream_name_size(0)
, mime_type_size(0), type_specific_len(0), type_specific_data(0), lstr(0)
memset(stream_name, 0, sizeof(UINT8) * 256);
memset(mime_type, 0, sizeof(UINT8) * 256);
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
: object_version(0), title_len(0), title(0), author_len(0)
, author(0), copyright_len(0), copyright(0), comment_len(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
: size(0), type(0), flags(0), value_offset(0)
, subproperties_offset(0), num_subproperties(0), name_length(0)
, name(0), value_length(0), value(0), subproperties_list(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
RMFFile(const char *filename);
virtual ~RMFFile();
bool save();
TagLib::Tag *tag() const { return m_id3tag; }
TagLib::AudioProperties *audioProperties() const { return 0; }
TagLib::ID3v1::Tag *m_id3tag;
class RealMediaFF
RealMediaFF(const char *file, bool readProperties = true,
TagLib::AudioProperties::ReadStyle propertiesStyle = TagLib::AudioProperties::Average);
RealMediaFF(RealMediaFF &src);
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);
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);
} // namespace RealMedia
} // namespace TagLib
#ifdef TESTING
std::ostream &operator<<(std::ostream &os, TagLib::RealMedia::RealMediaFF &rmff);