diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 19:09:31 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 19:09:31 +0000 |
commit | f2cfda2a54780868dfe0af7bd652fcd4906547da (patch) | |
tree | c6ac23545528f5701818424f2af5f79ce3665e6c /src/metadata/rmff | |
download | soundkonverter-f2cfda2a54780868dfe0af7bd652fcd4906547da.tar.gz soundkonverter-f2cfda2a54780868dfe0af7bd652fcd4906547da.zip |
Added KDE3 version of SoundKonverter
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/soundkonverter@1097614 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/metadata/rmff')
-rw-r--r-- | src/metadata/rmff/Makefile.am | 15 | ||||
-rw-r--r-- | src/metadata/rmff/rmff.cpp | 998 | ||||
-rw-r--r-- | src/metadata/rmff/rmff.h | 348 | ||||
-rw-r--r-- | src/metadata/rmff/taglib_realmediafile.cpp | 213 | ||||
-rw-r--r-- | src/metadata/rmff/taglib_realmediafile.h | 133 | ||||
-rw-r--r-- | src/metadata/rmff/taglib_realmediafiletyperesolver.cpp | 53 | ||||
-rw-r--r-- | src/metadata/rmff/taglib_realmediafiletyperesolver.h | 39 |
7 files changed, 1799 insertions, 0 deletions
diff --git a/src/metadata/rmff/Makefile.am b/src/metadata/rmff/Makefile.am new file mode 100644 index 0000000..b493e66 --- /dev/null +++ b/src/metadata/rmff/Makefile.am @@ -0,0 +1,15 @@ +SUBDIRS = + +INCLUDES = $(all_includes) $(taglib_includes) +METASOURCES = AUTO +libtagrealmedia_la_LDFLAGS = $(all_libraries) +noinst_LTLIBRARIES = libtagrealmedia.la + +libtagrealmedia_la_SOURCES = rmff.cpp \ + taglib_realmediafile.cpp \ + taglib_realmediafiletyperesolver.cpp + +noinst_HEADERS = rmff.h \ + taglib_realmediafile.h \ + taglib_realmediafiletyperesolver.h + diff --git a/src/metadata/rmff/rmff.cpp b/src/metadata/rmff/rmff.cpp new file mode 100644 index 0000000..da0edd5 --- /dev/null +++ b/src/metadata/rmff/rmff.cpp @@ -0,0 +1,998 @@ +/*************************************************************************** + 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 * + * * + ***************************************************************************/ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <netinet/in.h> +#include <taglib.h> +#include <id3v1tag.h> +#include <id3v2tag.h> +#include <tfile.h> +#include <fileref.h> +#include <iostream> + +#include <string.h> + +#include "rmff.h" + +#define UNPACK4(a, buf, i) memcpy((void *)&a, (void *) &buf[i], 4),i+=4,a=ntohl(a) +#define UNPACK2(a, buf, i) memcpy((void *)&a, (void *) &buf[i], 2),i+=2,a=ntohs(a) + +using namespace TagLib; +using namespace TagLib::RealMedia; + +RMFFile::RMFFile(const char *filename) : File(filename), m_id3tag(0) +{ + if (isOpen()) + m_id3tag = new ID3v1::Tag(this, length() - 128); +} + +RMFFile::~RMFFile() +{ + delete m_id3tag; +} + +bool RMFFile::save() +{ + ByteVector bv = m_id3tag->render(); //TODO finish this + return false; +} + + +String RealMediaFF::title () const +{ + return !m_err && m_id3v1tag ? m_id3v1tag->tag()->title() : ""; +} + +String RealMediaFF::artist () const +{ + return !m_err && m_id3v1tag ? m_id3v1tag->tag()->artist() : ""; +} + +String RealMediaFF::album () const +{ + return !m_err && m_id3v1tag ? m_id3v1tag->tag()->album() : ""; +} + +String RealMediaFF::comment() const +{ + return !m_err && m_id3v1tag ? m_id3v1tag->tag()->comment() : ""; +} + +String RealMediaFF::genre() const +{ + return !m_err && m_id3v1tag ? m_id3v1tag->tag()->genre() : ""; +} + +TagLib::uint RealMediaFF::year() const +{ + return !m_err && m_id3v1tag ? m_id3v1tag->tag()->year() : 0; +} + +TagLib::uint RealMediaFF::track() const +{ + return !m_err && m_id3v1tag ? m_id3v1tag->tag()->track() : 0; +} + +// properties +int RealMediaFF::length () const +{ + return m_readProperties && !m_err && m_props ? m_props->duration : 0; +} + +int RealMediaFF::bitrate () const +{ + return m_readProperties && !m_err && m_props ? m_props->avg_bit_rate : 0; +} + +int RealMediaFF::sampleRate () const +{ + return 0; +} + +int RealMediaFF::channels () const +{ + return 0; +} + + +RealMediaFF::RealMediaFF(const char *file, bool readProperties, AudioProperties::ReadStyle /*propertiesStyle*/) +: m_filename(0) +, m_head(0) +, m_tail(0) +, m_err(0) +, m_hdr(0) +, m_props(0) +, media_hdrs(0) +, m_contenthdr(0) +, m_md(0) +, m_title(0) +, m_author(0) +, m_copyright(0) +, m_comment(0) +, m_id3v1tag(0) +, m_flipYearInMetadataSection(0) +, m_readProperties(readProperties) +{ + m_filename = strdup(file); + + m_fd = open(m_filename, O_RDONLY); + if (m_fd < 0) + { + m_err = -1; + return; + } + + // ok, for RM files, the properties are embedded, so we ignore propertiesStyle + if (m_readProperties) + { + init(); + + // and now for the really complicated stuff... + if (initMetadataSection()) + std::cerr << "ERROR reading Metadata\n"; + } + + // now get the ID3v1 tag at the end of this file + m_id3v1tag = new RMFFile(m_filename); +} + + +RealMediaFF::RealMediaFF(RealMediaFF &src) +: m_filename(0) +, m_head(0) +, m_tail(0) +, m_err(0) +, m_hdr(0) +, m_props(0) +, media_hdrs(0) +, m_contenthdr(0) +, m_md(0) +, m_title(0) +, m_author(0) +, m_copyright(0) +, m_comment(0) +, m_id3v1tag(0) +, m_flipYearInMetadataSection(0) +, m_readProperties(src.m_readProperties) +{ + m_filename=strdup(src.m_filename); + + m_fd = open(m_filename, O_RDONLY); + if (m_fd < 0) + { + m_err = -1; + return; + } + + // ok, for RM files, the properties are embedded, so we ignore propertiesStyle + if (m_readProperties) + { + init(); + + // and now for the really complicated stuff... + if (initMetadataSection()) + std::cerr << "ERROR reading Metadata\n"; + } + + // now get the ID3v1 tag at the end of this file + m_id3v1tag = new RMFFile(m_filename); +} + +RealMediaFF::~RealMediaFF() +{ + ::free(m_filename); + + Collectable *hdr = m_head, *next; + while (hdr) + { + next = hdr->fwd; + delete hdr; + hdr = next; + } + + delete m_id3v1tag; + delete m_md; + + close(m_fd); +} + +bool RealMediaFF::isEmpty() const +{ + return m_id3v1tag->tag()->isEmpty(); +} + + +void RealMediaFF::saveHeader(Collectable *hdr) +{ + hdr->fwd = 0; + if (!m_head) + m_head = m_tail = hdr; + else + { + m_tail->fwd = hdr; + m_tail = hdr; + } +} + + +int RealMediaFF::init() +{ + int nbytes; + unsigned char buf[65536]; + UINT32 object_id; + UINT32 sz; + UINT32 consumed = 0; + + off_t s; + if ( (s = lseek(m_fd, 0, SEEK_SET)) ) + { + m_err = -1; + return m_err; + } + + m_hdr = new File_Header_v0_v1; + nbytes = getChunk(buf, 65536, m_hdr->s.object_id, m_hdr->s.size, consumed); + if (nbytes < 0 || m_hdr->s.size != consumed || memcmp((void *)&m_hdr->s.object_id, ".RMF", 4)) + { + //std::cerr << "SERIOUS ERROR - not likely a RealMedia file\n"; + m_err = -1; + return m_err; + } + if (!getRealFileHeader(m_hdr, buf, m_hdr->s.object_id, m_hdr->s.size)) + { + saveHeader(m_hdr); + consumed = 0; + nbytes = getChunk(buf, 65536, object_id, sz, consumed); + if (nbytes < 0 || sz != consumed) + { + m_err = -1; + return m_err; + } + + while (!m_err && memcmp((void *)&object_id, "DATA", 4)) + { + char oid[5]; + memcpy((void *)oid, (void *)&object_id, 4); + oid[4] = 0; + if (!memcmp((void *)&object_id, "PROP", 4)) + { + m_props = new RMProperties; + getRealPropertyHeader(m_props, buf, object_id, sz); + saveHeader(m_props); + } + + if (!memcmp((void *)&object_id, "MDPR", 4)) + { + media_hdrs = new MediaProperties; + getMediaPropHeader(media_hdrs, buf, object_id, sz); + saveHeader(media_hdrs); + } + + if (!memcmp((void *)&object_id, "CONT", 4)) + { + m_contenthdr = new ContentDescription; + getContentDescription(m_contenthdr, buf, object_id, sz); + saveHeader(m_contenthdr); + } + + consumed = 0; + do + { + nbytes = getChunk(buf, 65536, object_id, sz, consumed); + } while ( !m_err && memcmp((void *)&object_id, "DATA", 4) && (consumed < sz) ); + } + } + + return 0; +} + +int RealMediaFF::getHdr(unsigned char *buf, size_t sz, UINT32 &fourcc, UINT32 &csz) +{ + int nbytes = 0, i = 0; + + if (sz < (size_t)RMFF_HDR_SIZE) + return 0; + + if ( (nbytes = read(m_fd, (void *) buf, RMFF_HDR_SIZE)) != RMFF_HDR_SIZE ) + { + m_err = -1; + + return (nbytes); + } + + memcpy((void *)&fourcc, buf, 4); i+=4; + UNPACK4(csz,buf,i); + + return nbytes; +} + +int RealMediaFF::getChunk(unsigned char *buf, size_t sz, UINT32 &fourcc, UINT32 &csz, UINT32 &alreadyconsumed) +{ + int nbytes = 0, i = 0, readamount; + csz = 0; + + if (!alreadyconsumed) + { + if ( (nbytes = getHdr(buf, sz, fourcc, csz)) != RMFF_HDR_SIZE ) + { + m_err = -1; + alreadyconsumed += nbytes > 0 ? nbytes : 0; + return nbytes; + } + alreadyconsumed += RMFF_HDR_SIZE; + readamount = csz - RMFF_HDR_SIZE; + i = RMFF_HDR_SIZE; + } + else + readamount = csz - alreadyconsumed; + + if ( (nbytes = read(m_fd, (void *) &buf[i], readamount > (int)sz - i ? (int)sz - i : readamount )) != readamount ) + { + if (nbytes < 0) + { + m_err = -1; + } + else + alreadyconsumed += nbytes; + + return (nbytes<0 ? i : i + nbytes); + } + + alreadyconsumed += nbytes; + return (csz); +} + +int RealMediaFF::getRealFileHeader(File_Header_v0_v1 *hdr, const unsigned char *buf, UINT32 object_id, int sz) +{ + int i = 0; + + // RealMedia header + hdr->s.object_id = object_id; + hdr->s.size = sz; + + i = RMFF_HDR_SIZE; + UNPACK2(hdr->object_version, buf, i); + + if ( !strncmp((const char *) &hdr->s.object_id, ".RMF", 4) && + (hdr->object_version == 0 || hdr->object_version == 1) ) + { + UNPACK4(hdr->file_version, buf, i); + UNPACK4(hdr->num_headers, buf, i); + } + return 0; +} + +int RealMediaFF::getRealPropertyHeader(RMProperties *props, const unsigned char *buf, UINT32 object_id, int sz) +{ + int i = 0; + + // Properties + props->s.object_id = object_id; + props->s.size = sz; + + i = RMFF_HDR_SIZE; + UNPACK2(props->object_version, buf, i); + + if ( !strncmp((const char *)&props->s.object_id,"PROP",4) && (props->object_version == 0) ) + { + UNPACK4(props->max_bit_rate, buf, i); + UNPACK4(props->avg_bit_rate, buf, i); + UNPACK4(props->max_packet_size, buf, i); + UNPACK4(props->avg_packet_size, buf, i); + UNPACK4(props->num_packets, buf, i); + UNPACK4(props->duration, buf, i); + UNPACK4(props->preroll, buf, i); + UNPACK4(props->index_offset, buf, i); + UNPACK4(props->data_offset, buf, i); + UNPACK2(props->num_streams, buf, i); + UNPACK2(props->flags, buf, i); + } + return 0; +} + + +int RealMediaFF::getMediaPropHeader(MediaProperties *media_hdr, const unsigned char *buf, UINT32 object_id, int sz) +{ + int i = 0; + + // Properties + media_hdr->s.object_id = object_id; + media_hdr->s.size = sz; + + i = RMFF_HDR_SIZE; + UNPACK2(media_hdr->object_version, buf, i); + + if ( !strncmp((const char *)&media_hdr->s.object_id, "MDPR", 4) && media_hdr->object_version == 0) + { + UNPACK2(media_hdr->stream_number, buf, i); + UNPACK4(media_hdr->max_bit_rate, buf, i); + UNPACK4(media_hdr->avg_bit_rate, buf, i); + UNPACK4(media_hdr->max_packet_size, buf, i); + UNPACK4(media_hdr->avg_packet_size, buf, i); + UNPACK4(media_hdr->start_time, buf, i); + UNPACK4(media_hdr->preroll, buf, i); + UNPACK4(media_hdr->duration, buf, i); + media_hdr->stream_name_size = buf[i]; i++; + memcpy(media_hdr->stream_name, &buf[i], media_hdr->stream_name_size); + media_hdr->stream_name[media_hdr->stream_name_size] = 0; + i += media_hdr->stream_name_size; + media_hdr->mime_type_size = buf[i]; i++; + memcpy(media_hdr->mime_type, &buf[i], media_hdr->mime_type_size); + i += media_hdr->mime_type_size; + UNPACK4(media_hdr->type_specific_len, buf, i); + if (media_hdr->type_specific_len) + { + media_hdr->type_specific_data = new UINT8[media_hdr->type_specific_len]; + memcpy(media_hdr->type_specific_data, &buf[i], media_hdr->type_specific_len); + + if (!strncmp((const char *)media_hdr->mime_type, "logical-fileinfo", 16)) + { + media_hdr->lstr = new LogicalStream; + UNPACK4(media_hdr->lstr->size, buf, i); + UNPACK2(media_hdr->lstr->object_version, buf, i); + if (media_hdr->lstr->object_version == 0) + { + UNPACK2(media_hdr->lstr->num_physical_streams, buf, i); + if (media_hdr->lstr->num_physical_streams > 0) + { + media_hdr->lstr->physical_stream_numbers = new UINT16[ media_hdr->lstr->num_physical_streams ]; + media_hdr->lstr->data_offsets = new UINT32[ media_hdr->lstr->num_physical_streams ]; + for (int j=0; j<media_hdr->lstr->num_physical_streams; j++) + { + UNPACK2(media_hdr->lstr->physical_stream_numbers[j], buf, i); + } + for (int j=0; j<media_hdr->lstr->num_physical_streams; j++) + { + UNPACK4(media_hdr->lstr->data_offsets[j], buf, i); + } + } + + UNPACK2(media_hdr->lstr->num_rules, buf, i); + if (media_hdr->lstr->num_rules > 0) + { + media_hdr->lstr->rule_to_physical_stream_number_map = new UINT16[ media_hdr->lstr->num_rules ]; + for (int j=0; j<media_hdr->lstr->num_rules; j++) + { + UNPACK2(media_hdr->lstr->rule_to_physical_stream_number_map[j], buf, i); + } + } + UNPACK2(media_hdr->lstr->num_properties, buf, i); + if (media_hdr->lstr->num_properties > 0) + { + media_hdr->lstr->properties = new NameValueProperty[ media_hdr->lstr->num_properties ]; + for (int j=0; j<media_hdr->lstr->num_properties; j++) + { + UNPACK4(media_hdr->lstr->properties[j].size, buf, i); + UNPACK2(media_hdr->lstr->properties[j].object_version, buf, i); + if (media_hdr->lstr->properties[j].object_version == 0) + { + media_hdr->lstr->properties[j].name_length = buf[i]; i++; + if (media_hdr->lstr->properties[j].name_length) + { + media_hdr->lstr->properties[j].name = new UINT8[ media_hdr->lstr->properties[j].name_length + 1]; + memcpy((void *)media_hdr->lstr->properties[j].name, (void *)&buf[i], + media_hdr->lstr->properties[j].name_length); + media_hdr->lstr->properties[j].name[ media_hdr->lstr->properties[j].name_length ] = 0; + i+=media_hdr->lstr->properties[j].name_length; + } + + UNPACK4(media_hdr->lstr->properties[j].type, buf, i); + UNPACK2(media_hdr->lstr->properties[j].value_length, buf, i); + if (media_hdr->lstr->properties[j].value_length) + { + media_hdr->lstr->properties[j].value_data = new UINT8[ media_hdr->lstr->properties[j].value_length + 1]; + memcpy((void *)media_hdr->lstr->properties[j].value_data, (void *)&buf[i], + media_hdr->lstr->properties[j].value_length); + media_hdr->lstr->properties[j].value_data[ media_hdr->lstr->properties[j].value_length ] = 0; + i+=media_hdr->lstr->properties[j].value_length; + } + } + } + } + } + else + media_hdr->lstr = 0; + } + } + else + media_hdr->type_specific_data = 0; + } + else + { + m_err = -1; + return m_err; + } + + return 0; +} + + +int RealMediaFF::getContentDescription(ContentDescription *cont, const unsigned char *buf, UINT32 object_id, int sz) +{ + int i = 0; + + // Properties + cont->s.object_id = object_id; + cont->s.size = sz; + + i = RMFF_HDR_SIZE; + UNPACK2(cont->object_version, buf, i); + + if ( !strncmp((const char *)&cont->s.object_id, "CONT", 4) && cont->object_version == 0) + { + UNPACK2(cont->title_len, buf, i); + cont->title = new UINT8[cont->title_len + 1]; + memcpy((void *)cont->title, (void *)&buf[i], cont->title_len); i+=cont->title_len; + m_title = (char *)cont->title; + m_title[cont->title_len] = 0; + + UNPACK2(cont->author_len, buf, i); + cont->author = new UINT8[cont->author_len + 1]; + memcpy((void *)cont->author, (void *)&buf[i], cont->author_len); i+=cont->author_len; + m_author = (char *)cont->author; + m_author[cont->author_len] = 0; + + UNPACK2(cont->copyright_len, buf, i); + cont->copyright = new UINT8[cont->copyright_len + 1]; + memcpy((void *)cont->copyright, (void *)&buf[i], cont->copyright_len); i+=cont->copyright_len; + m_copyright = (char *)cont->copyright; + m_copyright[cont->copyright_len] = 0; + + UNPACK2(cont->comment_len, buf, i); + cont->comment = new UINT8[cont->comment_len + 1]; + memcpy((void *)cont->comment, (void *)&buf[i], cont->comment_len); i+=cont->comment_len; + m_comment = (char *)cont->comment; + m_comment[cont->comment_len] = 0; + } + else + { + m_err = -1; + return m_err; + } + + return 0; +} + + +int RealMediaFF::seekChunk(UINT32 object_id) +{ + if (!m_err) + { + off_t s, tot; + UINT32 oid = 0, sz = 0; + unsigned char buf[255]; + int nbytes = 0; + + if ( (s = lseek(m_fd, 0, SEEK_SET)) != 0) + return -1; + + tot = 0; + while( (nbytes = getHdr(buf, 255, oid, sz)) == RMFF_HDR_SIZE && memcmp((void *)&oid, (void *)&object_id, 4) ) + { + tot += sz; + if (sz > (unsigned) RMFF_HDR_SIZE) + { + if ( (s = lseek(m_fd, sz - RMFF_HDR_SIZE, SEEK_CUR)) != tot ) + return -1; + } + else + return -1; // bail in this case, since the chuck sz includes the header size + } + if ( (s = lseek(m_fd, -RMFF_HDR_SIZE, SEEK_CUR)) != tot ) + return -1; + + return s; + } + return -1; +} + +int RealMediaFF::getMDProperties(MDProperties *props, const unsigned char *buf) +{ + int i = 0; + + int start = i; + + UNPACK4(props->size, buf, i); + UNPACK4(props->type, buf, i); + UNPACK4(props->flags, buf, i); + UNPACK4(props->value_offset, buf, i); + UNPACK4(props->subproperties_offset, buf, i); + UNPACK4(props->num_subproperties, buf, i); + UNPACK4(props->name_length, buf, i); + props->name = new UINT8[ props->name_length + 1 ]; + memcpy((void *)props->name, (void *)&buf[i], props->name_length); + props->name[ props->name_length ] = 0; + i+=props->name_length; + + i = start + props->value_offset; + UNPACK4(props->value_length, buf, i); + props->value = new UINT8[ props->value_length ]; + memcpy( (void *) props->value, (void *)&buf[i], props->value_length ); + + if ( (props->type == MPT_ULONG) || (props->type == MPT_FLAG && props->value_length == 4) ) + { + // wOOt! the Year is a ULONG, and its stored little endian?! my guess is this is a bug in + // RealPlayer 10 for Windows (where I created my test files) + // This hack is intended to ensure that we at least interpret the Year properly. + if (!strcmp((char *)props->name, "Year")) + { + if ( *(unsigned long *)props->value > 65536 ) + { + *(unsigned long *)(props->value) = ntohl(*(unsigned long *)(props->value)); + m_flipYearInMetadataSection = true; + } + else + m_flipYearInMetadataSection = false; + } + else + *(unsigned long *)(props->value) = ntohl(*(unsigned long *)(props->value)); + } + + i += props->value_length; + + i = start + props->subproperties_offset; + props->subproperties_list = new PropListEntry[ props->num_subproperties ]; + for (int j=0; j<(int)props->num_subproperties; j++) + { + UNPACK4(props->subproperties_list[j].offset, buf, i); + UNPACK4(props->subproperties_list[j].num_props_for_name, buf, i); + } + + props->subproperties = new MDProperties[ props->num_subproperties ]; + for (int j=0; j<(int)props->num_subproperties; j++) + { + i = start + props->subproperties_list[j].offset; + getMDProperties(&props->subproperties[j], &buf[i]); + } + + return 0; +} + +int RealMediaFF::initMetadataSection() +{ + UINT32 object_id; + off_t s; + int nbytes; + unsigned char buf[65536]; + UINT32 consumed; + + memcpy((void *)&object_id, "RMMD", 4); + if ( (s = seekChunk(object_id)) < 0 ) + { + m_err = -1; + return m_err; + } + + m_md = new MetadataSection; + consumed = 0; + nbytes = getChunk(buf, 65536, m_md->s.object_id, m_md->s.size, consumed); + if (nbytes < 0 || m_md->s.size != consumed || memcmp((void *)&m_md->s.object_id, "RMMD", 4)) + { + //std::cerr << "SERIOUS ERROR - not able to find the chunk I just seek'd to!\n"; + m_err = -1; + return m_err; + } + // Properties + int i = RMFF_HDR_SIZE; + memcpy((void *)&m_md->object_id, (void *)&buf[i], 4); i+=4; + UNPACK4(m_md->object_version, buf, i); + if ( !strncmp((const char *)&m_md->s.object_id, "RMMD", 4) ) + { + if (!getMDProperties(&m_md->properties, &buf[i])) + saveHeader(m_md); + } + else + { + m_err = -1; + return m_err; + } + + return 0; +} + +#ifdef TESTING + +void RealMediaFF::printRealFileHeader(std::ostream &os) +{ + char object_id[5]; + + if (m_hdr) + { + strncpy(object_id, (const char *)&m_hdr->s.object_id, 4); + object_id[4]=0; + + os << "HDR object_id: " << object_id << std::endl; + os << "HDR size: " << m_hdr->s.size << std::endl; + os << "HDR object version: " << m_hdr->object_version << std::endl; + os << "HDR file version: " << m_hdr->file_version << std::endl; + os << "HDR num headers: " << m_hdr->num_headers << std::endl; + } +} + + +void RealMediaFF::printRealPropHeader(std::ostream &os) +{ + char object_id[5]; + + if (m_props) + { + strncpy(object_id, (const char *)&m_props->s.object_id, 4); + object_id[4]=0; + + os << "PROPS object_id: " << object_id << std::endl; + os << "PROPS size: " << m_props->s.size << std::endl; + os << "PROPS object_version: " << m_props->object_version << std::endl; + + os << "PROPS max_bit_rate: " << m_props->max_bit_rate << std::endl; + os << "PROPS avg_bit_rate: " << m_props->avg_bit_rate << std::endl; + os << "PROPS max_packet_size: " << m_props->max_packet_size << std::endl; + os << "PROPS avg_packet_size: " << m_props->avg_packet_size << std::endl; + os << "PROPS num_packets: " << m_props->num_packets << std::endl; + os << "PROPS duration: " << m_props->duration << std::endl; + os << "PROPS preroll: " << m_props->preroll << std::endl; + os << "PROPS index_offset: " << m_props->index_offset << std::endl; + os << "PROPS data_offset: " << m_props->data_offset << std::endl; + os << "PROPS num_streams: " << m_props->num_streams << std::endl; + os << "PROPS flags: " << m_props->flags << std::endl; + } +} + + +void RealMediaFF::printMediaPropHeaders(std::ostream &os) +{ + int i = 0; + char object_id[5]; + MediaProperties *media_hdr = (MediaProperties *)m_head; + + while (media_hdr) + { + strncpy(object_id, (const char *)&media_hdr->s.object_id, 4); + object_id[4]=0; + + if (!strncmp(object_id, "MDPR", 4)) + { + os << "MEDIA HDR" << i << " object_id: " << object_id << std::endl; + os << "MEDIA HDR" << i << " size: " << media_hdr->s.size << std::endl; + os << "MEDIA HDR" << i << " max_bit_rate: " << media_hdr->max_bit_rate << std::endl; + os << "MEDIA HDR" << i << " avg_bit_rate: " << media_hdr->avg_bit_rate << std::endl; + os << "MEDIA HDR" << i << " max_packet_size: " << media_hdr->max_packet_size << std::endl; + os << "MEDIA HDR" << i << " avg_packet_size: " << media_hdr->avg_packet_size << std::endl; + os << "MEDIA HDR" << i << " start_time: " << media_hdr->start_time << std::endl; + os << "MEDIA HDR" << i << " preroll: " << media_hdr->preroll << std::endl; + os << "MEDIA HDR" << i << " duration: " << media_hdr->duration << std::endl; + os << "MEDIA HDR" << i << " stream_name: " << media_hdr->stream_name << std::endl; + os << "MEDIA HDR" << i << " mime type: " << media_hdr->mime_type << std::endl; + + + if (media_hdr->lstr) + { + os << "MEDIA HDR" << i << " LOGSTR info size: " << media_hdr->lstr->size << std::endl; + os << "MEDIA HDR" << i << " LOGSTR info num_physical_streams: " << media_hdr->lstr->num_physical_streams << std::endl; + os << "MEDIA HDR" << i << " LOGSTR info num_rules: " << media_hdr->lstr->num_rules << std::endl; + os << "MEDIA HDR" << i << " LOGSTR info num_properties: " << media_hdr->lstr->num_properties << std::endl; + for (int j=0; media_hdr->lstr->properties && j<media_hdr->lstr->num_properties; j++) + { + if (media_hdr->lstr->properties[j].name) + os << "MEDIA HDR" << i << " LOGSTR info prop name: " << media_hdr->lstr->properties[j].name << std::endl; + os << "MEDIA HDR" << i << " LOGSTR info prop type: " << media_hdr->lstr->properties[j].type << std::endl; + os << "MEDIA HDR" << i << " LOGSTR info prop value_length: " << media_hdr->lstr->properties[j].value_length << std::endl; + if (media_hdr->lstr->properties[j].value_data) + { + if (media_hdr->lstr->properties[j].type == 0) + os << "MEDIA HDR" << i << " LOGSTR info prop value: " << + *(unsigned long *)media_hdr->lstr->properties[j].value_data << std::endl; + else if (media_hdr->lstr->properties[j].type == 2) + os << "MEDIA HDR" << i << " LOGSTR info prop value: " << media_hdr->lstr->properties[j].value_data << std::endl; + else + os << "MEDIA HDR" << i << " LOGSTR info prop value: <binary>\n"; + } + } + } + + i++; + } + media_hdr = (MediaProperties *)media_hdr->fwd; + } +} + + +void RealMediaFF::printContentDescription(std::ostream &os) +{ + char object_id[5]; + + if (m_contenthdr) + { + strncpy(object_id, (const char *)&m_contenthdr->s.object_id, 4); + object_id[4]=0; + + os << "CONT object_id: " << object_id << std::endl; + os << "CONT title(" << m_contenthdr->title_len << "):\t\t<" << m_contenthdr->title << ">" << std::endl; + os << "CONT author(" << m_contenthdr->author_len << "):\t\t<" << m_contenthdr->author << ">" << std::endl; + os << "CONT copyright(" << m_contenthdr->copyright_len << "):\t\t<" << m_contenthdr->copyright << ">" << std::endl; + os << "CONT comment(" << m_contenthdr->comment_len << "):\t\t<" << m_contenthdr->comment << ">" << std::endl; + } +} + +void RealMediaFF::printID3v1Tag(std::ostream &os) +{ + if (m_id3v1tag) + { + os << "ID3 tag : " << ID3v1::Tag::fileIdentifier() << std::endl; + os << "ID3 title : " << m_id3v1tag->tag()->title() << std::endl; + os << "ID3 artist : " << m_id3v1tag->tag()->artist() << std::endl; + os << "ID3 album : " << m_id3v1tag->tag()->album() << std::endl; + os << "ID3 year : " << m_id3v1tag->tag()->year() << std::endl; + os << "ID3 comment : " << m_id3v1tag->tag()->comment() << std::endl; + os << "ID3 track : " << m_id3v1tag->tag()->track() << std::endl; + os << "ID3 genre : " << m_id3v1tag->tag()->genre() << std::endl; + } +} + + +void RealMediaFF::printMDProperties(std::ostream &os, char *nam, MDProperties *props) +{ + char name[8192]; + + strcpy(name, nam); + os << "MDP subproperties for: " << name << std::endl; + + os << "MD properties.size: " << props->size << std::endl; + os << "MD properties.type: " << props->type << std::endl; + os << "MD properties.flags: " << props->flags << std::endl; + os << "MD properties.value_offset: " << props->value_offset << std::endl; + os << "MD properties.subproperties_offset: " << props->subproperties_offset << std::endl; + os << "MD properties.num_subproperties: " << props->num_subproperties << std::endl; + os << "MD properties.name_length: " << props->name_length << std::endl; + os << "MD properties.name: " << (char *)props->name << std::endl; + + os << "MD properties.value_length: " << props->value_length << std::endl; + + switch (props->type) + { + case MPT_TEXT: + case MPT_TEXTLIST: + case MPT_URL: + case MPT_DATE: + case MPT_FILENAME: + os << "MD properties.value: " << (char *)props->value << std::endl; + break; + case MPT_FLAG: + if (props->value_length == 4) + os << "MD properties.value: " << *(unsigned long *)props->value << std::endl; + else + os << "MD properties.value: " << *props->value << std::endl; + break; + case MPT_ULONG: + os << "MD properties.value: " << *(unsigned long *)props->value << std::endl; + break; + case MPT_BINARY: + os << "MD properties.value: <binary>" << std::endl; + break; + case MPT_GROUPING: + os << "MD properties.value: <grouping>" << std::endl; + break; + case MPT_REFERENCE: + os << "MD properties.value: <reference>" << std::endl; + break; + } + + if (props->num_subproperties) + { + strcat(name, (char *)props->name); + strcat(name, "/"); + } + for (int j=0; j<props->num_subproperties; j++) + { + os << "MD properties.sub_properties_list[" << j << "].offset: " << + props->subproperties_list[j].offset << std::endl; + os << "MD properties.sub_properties_list[" << j << "].num_props_for_name: " << + props->subproperties_list[j].num_props_for_name << std::endl; + + os << std::endl; + + printMDProperties(os, name, &props->subproperties[j]); + } +} + + +void RealMediaFF::printMetadataSection(std::ostream &os) +{ + char name[8192]; + char oid[5]; + + memcpy((void *)oid, (void *)&m_md->s.object_id, 4); + oid[4] = 0; + + os << "MetadataSection: "; + os << "MS object_id: " << oid << std::endl; + os << "MS SIZE: " << m_md->s.size << std::endl; + os << "MD object_id: " << (char *)&m_md->object_id << std::endl; + os << "MD object_version: " << m_md->object_version << std::endl; + os << std::endl; + + strcpy(name, ""); + printMDProperties(os, name, &m_md->properties); +} + + +std::ostream &RealMediaFF::operator<<(std::ostream &os) +{ + if (m_readProperties) + { + printRealFileHeader(os); + printRealPropHeader(os); + printMediaPropHeaders(os); + printContentDescription(os); + printMetadataSection(os); + } + printID3v1Tag(os); + + return os; +} + +std::ostream &operator<<(std::ostream &os, RealMediaFF &rmff) +{ + rmff.operator<<(os); + + return os; +} + + +int main(int argc, char *argv[]) +{ + char *m_filen; + + if (argc > 1) + m_filen = argv[1]; + else + m_filen = "./Drown.ra"; + + RealMediaFF rmff(m_filen); + + if (!rmff.err()) + std::cout << rmff; + + /* + UINT32 oid = 0; + memcpy( (void *)&oid, (void *) ".RMF", 4); + off_t pos = rmff.seekChunk(oid); + std::cout << "POS=" << pos << std::endl; + + memcpy( (void *)&oid, (void *) "MDPR", 4); + pos = rmff.seekChunk(oid); + std::cout << "POS=" << pos << std::endl; + + memcpy( (void *)&oid, (void *) "RMMD", 4); + pos = rmff.seekChunk(oid); + std::cout << "POS=" << pos << std::endl; + */ +} +#endif diff --git a/src/metadata/rmff/rmff.h b/src/metadata/rmff/rmff.h new file mode 100644 index 0000000..326b8ae --- /dev/null +++ b/src/metadata/rmff/rmff.h @@ -0,0 +1,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 diff --git a/src/metadata/rmff/taglib_realmediafile.cpp b/src/metadata/rmff/taglib_realmediafile.cpp new file mode 100644 index 0000000..b28c846 --- /dev/null +++ b/src/metadata/rmff/taglib_realmediafile.cpp @@ -0,0 +1,213 @@ +/*************************************************************************** + copyright : (C) 2005 by Paul Cifarelli + email : [email protected] + + copyright : (C) 2005 by Lukas Lalinsky + email : [email protected] + (portions) + ***************************************************************************/ + +/*************************************************************************** + * 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 free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2 or higher as published by the Free Software Foundation. * + * * + * 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 * + ***************************************************************************/ + +#include <tfile.h> +#include <audioproperties.h> +#include <tstring.h> +#include <id3v1tag.h> +#include "rmff.h" +#include "taglib_realmediafile.h" + +using namespace TagLib; +using namespace TagLib::RealMedia; + + +RealMedia::Tag::Tag(RealMediaFF *rmff, bool allocnew) : m_rmff(rmff), m_owner(allocnew) +{ + if (m_owner) + m_rmff = new RealMediaFF(*rmff); +} + +RealMedia::Tag::~Tag () +{ + if (m_owner) + delete m_rmff; +} + +String RealMedia::Tag::title () const +{ + return m_rmff->title(); +} + +String RealMedia::Tag::artist () const +{ + return m_rmff->artist(); +} + +String RealMedia::Tag::album () const +{ + return m_rmff->album(); +} + +String RealMedia::Tag::comment () const +{ + return m_rmff->comment(); +} + +String RealMedia::Tag::genre () const +{ + return m_rmff->genre(); +} + +TagLib::uint RealMedia::Tag::year () const +{ + return m_rmff->year(); +} + +TagLib::uint RealMedia::Tag::track () const +{ + return m_rmff->track(); +} + +void RealMedia::Tag::setTitle (const String &) +{ +// TODO: write support +} + +void RealMedia::Tag::setArtist (const String &) +{ +// TODO: write support +} + +void RealMedia::Tag::setAlbum (const String &) +{ +// TODO: write support +} + +void RealMedia::Tag::setComment (const String &) +{ +// TODO: write support +} + +void RealMedia::Tag::setGenre (const String &) +{ +// TODO: write support +} + +void RealMedia::Tag::setYear (uint) +{ +// TODO: write support +} + +void RealMedia::Tag::setTrack (uint) +{ +// TODO: write support +} + +bool RealMedia::Tag::isEmpty() const +{ + return TagLib::Tag::isEmpty() && m_rmff->isEmpty(); +} + +void RealMedia::Tag::duplicate(const Tag *source, Tag *target, bool overwrite) +{ + TagLib::Tag::duplicate(source, target, overwrite); + if (overwrite) + { + if (target->m_owner) + { + delete target->m_rmff; + target->m_rmff = new RealMediaFF(*source->m_rmff); + } + else + target->m_rmff = source->m_rmff; + } + else + { + if (target->isEmpty()) + if (target->m_owner) + { + delete target->m_rmff; + target->m_rmff = new RealMediaFF(*source->m_rmff); + } + else + target->m_rmff = source->m_rmff; + } +} + + + +int RealMedia::Properties::length () const +{ + return (m_rmff->length() / 1000); +} + +int RealMedia::Properties::bitrate () const +{ + return (m_rmff->bitrate() / 1000); +} + +int RealMedia::Properties::sampleRate () const +{ + return m_rmff->sampleRate(); +} + +int RealMedia::Properties::channels () const +{ + return m_rmff->channels(); +} + + +RealMedia::File::File(const char *file, bool readProperties, Properties::ReadStyle propertiesStyle) + : TagLib::File(file), m_rmfile(0), m_tag(0), m_props(0) +{ + m_rmfile = new RealMediaFF(file, readProperties, propertiesStyle); + m_tag = new RealMedia::Tag(m_rmfile); + m_props = new RealMedia::Properties(m_rmfile); +} + +RealMedia::File::~File() +{ + delete m_props; + delete m_tag; + delete m_rmfile; +} + +TagLib::Tag *RealMedia::File::tag() const +{ + return m_tag; +} + +RealMedia::Tag *RealMedia::File::RealMediaTag() const +{ + return m_tag; +} + +RealMedia::Properties *RealMedia::File::audioProperties() const +{ + return m_props; // m_rmfile->properties; +} + + + + + diff --git a/src/metadata/rmff/taglib_realmediafile.h b/src/metadata/rmff/taglib_realmediafile.h new file mode 100644 index 0000000..0f0ca58 --- /dev/null +++ b/src/metadata/rmff/taglib_realmediafile.h @@ -0,0 +1,133 @@ +/*************************************************************************** + copyright : (C) 2005 by Paul Cifarelli + email : [email protected] + + copyright : (C) 2005 by Lukas Lalinsky + email : [email protected] + (portions) + ***************************************************************************/ + +/*************************************************************************** + * 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 free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2 or higher as published by the Free Software Foundation. * + * * + * 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 * + ***************************************************************************/ +#ifndef _TAGLIB_REALMEDIAFILE_H_ +#define _TAGLIB_REALMEDIAFILE_H_ + +#include <tfile.h> +#include <audioproperties.h> +#include <tag.h> + +#include <iostream> + +class RealMediaFF; +namespace TagLib { + + namespace RealMedia { + + class Tag : public TagLib::Tag + { + public: + Tag(RealMediaFF *rmff, bool allocnew = false); + virtual ~Tag (); + virtual String title () const; + virtual String artist () const; + virtual String album () const; + virtual String comment () const; + virtual String genre () const; + virtual uint year () const; + virtual uint track () const; + virtual void setTitle (const String &s); + virtual void setArtist (const String &s); + virtual void setAlbum (const String &s); + virtual void setComment (const String &s); + virtual void setGenre (const String &s); + virtual void setYear (uint i); + virtual void setTrack (uint i); + + bool isEmpty() const; + void duplicate(const Tag *source, Tag *target, bool overwrite); + + private: + Tag(); + RealMediaFF *m_rmff; + bool m_owner; + }; + + + class Properties : public TagLib::AudioProperties + { + public: + Properties(RealMediaFF *rmff) : TagLib::AudioProperties(Average), m_rmff(rmff) {} + virtual ~Properties() {} // you don't own rmff + virtual int length () const; + virtual int bitrate () const; + virtual int sampleRate () const; + virtual int channels () const; + + private: + Properties(); + RealMediaFF *m_rmff; + }; + + class File : public TagLib::File + { + public: + + File(const char *file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); + + virtual ~File(); + + /* + * Returns the TagLib::Tag for this file. + */ + virtual TagLib::Tag *tag() const; + + /* + * Returns the RealMedia::RealMediaTag for this file. + */ + virtual Tag *RealMediaTag() const; + + /* + * Returns the RealMedia::Properties for this file. + */ + virtual Properties *audioProperties() const; + + + /* + * Save the file. + * + * This returns true if the save was successful. + */ + virtual bool save() { return false; } // for now + + private: + + RealMediaFF *m_rmfile; + Tag *m_tag; + Properties *m_props; + }; + + } + +} + +#endif diff --git a/src/metadata/rmff/taglib_realmediafiletyperesolver.cpp b/src/metadata/rmff/taglib_realmediafiletyperesolver.cpp new file mode 100644 index 0000000..a8660a6 --- /dev/null +++ b/src/metadata/rmff/taglib_realmediafiletyperesolver.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** + 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 * + * * + ***************************************************************************/ + +#include <tfile.h> +#include <audioproperties.h> +#include <id3v1tag.h> +#include "taglib_realmediafiletyperesolver.h" +#include "taglib_realmediafile.h" +#include "rmff.h" + +#include <string.h> + +TagLib::File *RealMediaFileTypeResolver::createFile(const char *fileName, + bool readProperties, + TagLib::AudioProperties::ReadStyle propertiesStyle) const +{ + const char *ext = strrchr(fileName, '.'); + if(ext && (!strcasecmp(ext, ".ra") || !strcasecmp(ext, ".rv") || !strcasecmp(ext, ".rm") || + !strcasecmp(ext, ".rmj") || !strcasecmp(ext, ".rmvb") )) + { + TagLib::RealMedia::File *f = new TagLib::RealMedia::File(fileName, readProperties, propertiesStyle); + if(f->isValid()) + return f; + else + { + delete f; + } + } + + return 0; +} diff --git a/src/metadata/rmff/taglib_realmediafiletyperesolver.h b/src/metadata/rmff/taglib_realmediafiletyperesolver.h new file mode 100644 index 0000000..b292e10 --- /dev/null +++ b/src/metadata/rmff/taglib_realmediafiletyperesolver.h @@ -0,0 +1,39 @@ +/*************************************************************************** + 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 * + * * + ***************************************************************************/ +#ifndef _TAGLIB_REALMEDIAFILETYPERESOLVER_H_ +#define _TAGLIB_REALMEDIAFILETYPERESOLVER_H_ + +#include <taglib/tfile.h> +#include <taglib/fileref.h> + + +class RealMediaFileTypeResolver : public TagLib::FileRef::FileTypeResolver +{ + TagLib::File *createFile(const char *fileName, + bool readAudioProperties, + TagLib::AudioProperties::ReadStyle audioPropertiesStyle) const; +}; + +#endif |