ref: 7b5ba33ae15aaa2a01dd04bac88ffa6f0fb09d8c
parent: 976c310f1d8d21d5f76415d124522dbda55f0b79
author: menno <menno>
date: Thu Dec 11 13:32:39 EST 2003
Peter Pawlowski added mp4 tag editing to the new mp4 library!
--- a/common/mp4ff/Makefile.am
+++ b/common/mp4ff/Makefile.am
@@ -2,7 +2,8 @@
include_HEADERS = mp4ff.h
-libmp4ff_la_SOURCES = mp4ff.c mp4atom.c mp4meta.c mp4sample.c mp4util.c mp4ff.h mp4ffint.h
+libmp4ff_la_SOURCES = mp4ff.c mp4atom.c mp4meta.c mp4sample.c mp4util.c \
+ mp4tagupdate.c mp4ff.h mp4ffint.h mp4ff_int_types.h
AM_CFLAGS = -O2 -g -DUSE_TAGGING=1
LIBTOOL_DEPS =
--- a/common/mp4ff/mp4atom.c
+++ b/common/mp4ff/mp4atom.c
@@ -22,7 +22,7 @@
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
-** $Id: mp4atom.c,v 1.6 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4atom.c,v 1.7 2003/12/11 18:32:39 menno Exp $
**/
#include <stdlib.h>
@@ -213,7 +213,7 @@
static int32_t mp4ff_read_esds(mp4ff_t *f)
{
uint8_t tag;
-
+
mp4ff_read_char(f); /* version */
mp4ff_read_int24(f); /* flags */
@@ -246,11 +246,11 @@
}
/* skip 13 bytes */
+ mp4ff_read_char(f);
mp4ff_read_int32(f);
- mp4ff_read_int32(f);
- mp4ff_read_int32(f);
- mp4ff_read_char(f);
-
+ f->track[f->total_tracks - 1]->maxBitrate = mp4ff_read_int32(f);
+ f->track[f->total_tracks - 1]->avgBitrate = mp4ff_read_int32(f);
+
/* get and verify DecSpecificInfoTag */
if (mp4ff_read_char(f) != 0x05)
{
@@ -440,6 +440,75 @@
return 0;
}
+#if 0
+static int32_t mp4ff_read_tkhd(mp4ff_t *f)
+{
+ uint8_t version;
+ uint32_t flags;
+ version = mp4ff_read_char(f); /* version */
+ flags = mp4ff_read_int24(f); /* flags */
+ if (version==1)
+ {
+ mp4ff_read_int64(f);//creation-time
+ mp4ff_read_int64(f);//modification-time
+ mp4ff_read_int32(f);//track-id
+ mp4ff_read_int32(f);//reserved
+ f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);//duration
+ }
+ else //version == 0
+ {
+ mp4ff_read_int32(f);//creation-time
+ mp4ff_read_int32(f);//modification-time
+ mp4ff_read_int32(f);//track-id
+ mp4ff_read_int32(f);//reserved
+ f->track[f->total_tracks - 1]->duration = mp4ff_read_int32(f);//duration
+ if (f->track[f->total_tracks - 1]->duration == 0xFFFFFFFF)
+ f->track[f->total_tracks - 1]->duration = 0xFFFFFFFFFFFFFFFF;
+
+ }
+ mp4ff_read_int32(f);//reserved
+ mp4ff_read_int32(f);//reserved
+ mp4ff_read_int16(f);//layer
+ mp4ff_read_int16(f);//pre-defined
+ mp4ff_read_int16(f);//volume
+ mp4ff_read_int16(f);//reserved
+
+ //matrix
+ mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f);
+ mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f);
+ mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f);
+ mp4ff_read_int32(f);//width
+ mp4ff_read_int32(f);//height
+ return 1;
+}
+#endif
+
+static int32_t mp4ff_read_mdhd(mp4ff_t *f)
+{
+ uint32_t version;
+
+ version = mp4ff_read_int32(f);
+ if (version==1)
+ {
+ mp4ff_read_int64(f);//creation-time
+ mp4ff_read_int64(f);//modification-time
+ f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale
+ f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);//duration
+ }
+ else //version == 0
+ {
+ uint32_t temp;
+
+ mp4ff_read_int32(f);//creation-time
+ mp4ff_read_int32(f);//modification-time
+ f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale
+ temp = mp4ff_read_int32(f);
+ f->track[f->total_tracks - 1]->duration = (temp == (uint32_t)(-1)) ? (uint64_t)(-1) : (uint64_t)(temp);
+ }
+ mp4ff_read_int16(f);
+ mp4ff_read_int16(f);
+ return 1;
+}
#ifdef USE_TAGGING
static int32_t mp4ff_read_meta(mp4ff_t *f, const uint64_t size)
{
@@ -455,7 +524,7 @@
subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
if (atom_type == ATOM_ILST)
{
- mp4ff_parse_metadata(f, subsize-(header_size+4));
+ mp4ff_parse_metadata(f, (uint32_t)(subsize-(header_size+4)));
} else {
mp4ff_set_position(f, mp4ff_position(f)+subsize-header_size);
}
@@ -468,6 +537,7 @@
int32_t mp4ff_atom_read(mp4ff_t *f, const int32_t size, const uint8_t atom_type)
{
+ uint64_t dest_position = mp4ff_position(f)+size-8;
if (atom_type == ATOM_STSZ)
{
/* sample size box */
@@ -487,6 +557,9 @@
} else if (atom_type == ATOM_MVHD) {
/* movie header box */
mp4ff_read_mvhd(f);
+ } else if (atom_type == ATOM_MDHD) {
+ /* track header */
+ mp4ff_read_mdhd(f);
#ifdef USE_TAGGING
} else if (atom_type == ATOM_META) {
/* iTunes Metadata box */
@@ -494,7 +567,7 @@
#endif
} else {
/* skip this atom: not needed for reading */
- mp4ff_set_position(f, mp4ff_position(f)+size-8);
+ mp4ff_set_position(f, dest_position);
}
return 0;
--- a/common/mp4ff/mp4ff.c
+++ b/common/mp4ff/mp4ff.c
@@ -22,7 +22,7 @@
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
-** $Id: mp4ff.c,v 1.6 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4ff.c,v 1.7 2003/12/11 18:32:39 menno Exp $
**/
#include <stdlib.h>
@@ -42,44 +42,6 @@
return ff;
}
-#ifdef USE_TAGGING
-mp4ff_t *mp4ff_open_edit(mp4ff_callback_t *f)
-{
- mp4ff_t *ff = malloc(sizeof(mp4ff_t));
-
- memset(ff, 0, sizeof(mp4ff_t));
-
- ff->stream = f;
-
- parse_atoms(ff);
-
- /* copy moov atom to end of the file */
- if (ff->last_atom != ATOM_MOOV)
- {
- char *free_data = "free";
- char *moov_data;
-
- moov_data = (unsigned char*)malloc(ff->moov_size);
-
- /* read the moov atom */
- mp4ff_set_position(ff, ff->moov_offset);
- mp4ff_read_data(ff, moov_data, ff->moov_size);
-
- /* rename old moov to free */
- mp4ff_set_position(ff, ff->moov_offset + 4);
- mp4ff_write_data(ff, free_data, 4);
-
- /* write old moov at end of file */
- mp4ff_set_position(ff, ff->file_size);
- mp4ff_write_data(ff, moov_data, ff->moov_size);
-
- free(moov_data);
- }
-
- return ff;
-}
-#endif
-
void mp4ff_close(mp4ff_t *ff)
{
int32_t i;
@@ -154,7 +116,7 @@
{
parse_sub_atoms(f, size-header_size);
} else {
- mp4ff_atom_read(f, size, atom_type);
+ mp4ff_atom_read(f, (uint32_t)size, atom_type);
}
}
@@ -162,7 +124,7 @@
}
/* parse root atoms */
-static int32_t parse_atoms(mp4ff_t *f)
+int32_t parse_atoms(mp4ff_t *f)
{
uint64_t size;
uint8_t atom_type = 0;
@@ -205,23 +167,66 @@
int32_t mp4ff_get_sample_duration(const mp4ff_t *f, const int32_t track, const int32_t sample)
{
- int32_t i, ci = 0, co = 0;
+ int32_t i, co = 0;
for (i = 0; i < f->track[track]->stts_entry_count; i++)
{
- int32_t j;
- for (j = 0; j < f->track[track]->stts_sample_count[i]; j++)
- {
- if (co == sample)
- return f->track[track]->stts_sample_delta[ci];
- co++;
- }
- ci++;
+ int32_t delta = f->track[track]->stts_sample_count[i];
+ if (sample < co + delta)
+ return f->track[track]->stts_sample_delta[i];
+ co += delta;
}
+ return (int32_t)(-1);
+}
- return 0;
+int64_t mp4ff_get_sample_offset(const mp4ff_t *f, const int32_t track, const int32_t sample)
+{
+ int32_t i, co = 0;
+ int64_t acc = 0;
+
+ for (i = 0; i < f->track[track]->stts_entry_count; i++)
+ {
+ int32_t delta = f->track[track]->stts_sample_count[i];
+ if (sample < co + delta)
+ {
+ acc += f->track[track]->stts_sample_delta[i] * (sample - co);
+ return acc;
+ }
+ else
+ {
+ acc += f->track[track]->stts_sample_delta[i] * delta;
+ }
+ co += delta;
+ }
+ return (int64_t)(-1);
}
+int32_t mp4ff_find_sample(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip)
+{
+ int32_t i, co = 0;
+ int64_t offset_total = 0;
+
+ for (i = 0; i < f->track[track]->stts_entry_count; i++)
+ {
+ int32_t sample_count = f->track[track]->stts_sample_count[i];
+ int32_t sample_delta = f->track[track]->stts_sample_delta[i];
+ int64_t offset_delta = (int64_t)sample_delta * (int64_t)sample_count;
+ if (offset < offset_total + offset_delta)
+ {
+ int64_t offset_fromstts = offset - offset_total;
+ if (toskip) *toskip = (int32_t)(offset_fromstts % sample_delta);
+ return (int32_t)(offset_fromstts / sample_delta);
+ }
+ else
+ {
+ offset_total += offset_delta;
+ }
+ co += sample_count;
+ }
+ return (int32_t)(-1);
+}
+
+
int32_t mp4ff_read_sample(mp4ff_t *f, const int32_t track, const int32_t sample,
uint8_t **audio_buffer, uint32_t *bytes)
{
@@ -276,9 +281,25 @@
int32_t mp4ff_time_scale(const mp4ff_t *f, const int32_t track)
{
- return f->track[track]->sampleRate;
+ return f->track[track]->timeScale;
}
+uint32_t mp4ff_get_avg_bitrate(const mp4ff_t *f, const int32_t track)
+{
+ return f->track[track]->avgBitrate;
+}
+
+uint32_t mp4ff_get_max_bitrate(const mp4ff_t *f, const int32_t track)
+{
+ return f->track[track]->maxBitrate;
+}
+
+uint64_t mp4ff_get_track_duration(const mp4ff_t *f, const int32_t track)
+{
+ return f->track[track]->duration;
+}
+
+
int32_t mp4ff_num_samples(const mp4ff_t *f, const int32_t track)
{
int32_t i;
@@ -290,3 +311,5 @@
}
return total;
}
+
+
--- a/common/mp4ff/mp4ff.dsp
+++ b/common/mp4ff/mp4ff.dsp
@@ -25,7 +25,7 @@
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
-CPP=xicl6.exe
+CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "mp4ff - Win32 Release"
@@ -105,6 +105,10 @@
# End Source File
# Begin Source File
+SOURCE=.\mp4tagupdate.c
+# End Source File
+# Begin Source File
+
SOURCE=.\mp4util.c
# End Source File
# End Group
@@ -111,6 +115,14 @@
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\mp4ff.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4ff_int_types.h
+# End Source File
# Begin Source File
SOURCE=.\mp4ffint.h
--- a/common/mp4ff/mp4ff.h
+++ b/common/mp4ff/mp4ff.h
@@ -22,7 +22,7 @@
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
-** $Id: mp4ff.h,v 1.9 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4ff.h,v 1.10 2003/12/11 18:32:39 menno Exp $
**/
#ifndef MP4FF_H
@@ -32,35 +32,42 @@
extern "C" {
#endif /* __cplusplus */
+#include "mp4ff_int_types.h"
+
/* file callback structure */
typedef struct
{
- int (*read)(void *user_data, void *buffer, int length);
- int (*write)(void *udata, void *buffer, int length);
- int (*seek)(void *user_data, int position);
+ uint32_t (*read)(void *user_data, void *buffer, uint32_t length);
+ uint32_t (*write)(void *udata, void *buffer, uint32_t length);
+ uint32_t (*seek)(void *user_data, uint64_t position);
+ uint32_t (*truncate)(void *user_data);
void *user_data;
} mp4ff_callback_t;
/* mp4 main file structure */
-typedef void *mp4ff_t;
+typedef void* mp4ff_t;
/* API */
mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f);
-#ifdef USE_TAGGING
-mp4ff_t *mp4ff_open_edit(mp4ff_callback_t *f);
-#endif
void mp4ff_close(mp4ff_t *f);
-int mp4ff_get_sample_duration(const mp4ff_t *f, const int track, const int sample);
-int mp4ff_read_sample(mp4ff_t *f, const int track, const int sample,
+int32_t mp4ff_get_sample_duration(const mp4ff_t *f, const int32_t track, const int32_t sample);
+int64_t mp4ff_get_sample_offset(const mp4ff_t *f, const int32_t track, const int32_t sample);
+int32_t mp4ff_find_sample(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip);
+int32_t mp4ff_read_sample(mp4ff_t *f, const int track, const int sample,
unsigned char **audio_buffer, unsigned int *bytes);
-int mp4ff_get_decoder_config(const mp4ff_t *f, const int track,
+int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int track,
unsigned char** ppBuf, unsigned int* pBufSize);
-int mp4ff_total_tracks(const mp4ff_t *f);
-int mp4ff_time_scale(const mp4ff_t *f, const int track);
-int mp4ff_num_samples(const mp4ff_t *f, const int track);
+int32_t mp4ff_total_tracks(const mp4ff_t *f);
+int32_t mp4ff_num_samples(const mp4ff_t *f, const int track);
+int32_t mp4ff_time_scale(const mp4ff_t *f, const int track);
+uint32_t mp4ff_get_avg_bitrate(const mp4ff_t *f, const int32_t track);
+uint32_t mp4ff_get_max_bitrate(const mp4ff_t *f, const int32_t track);
+uint64_t mp4ff_get_track_duration(const mp4ff_t *f, const int32_t track); //returns (uint64_t)(-1) if unknown
+
+
/* metadata */
int mp4ff_meta_get_num_items(const mp4ff_t *f);
int mp4ff_meta_get_by_index(const mp4ff_t *f, unsigned int index,
@@ -77,6 +84,27 @@
int mp4ff_meta_get_disc(const mp4ff_t *f, char **value);
int mp4ff_meta_get_compilation(const mp4ff_t *f, char **value);
int mp4ff_meta_get_tempo(const mp4ff_t *f, char **value);
+
+#ifdef USE_TAGGING
+
+/* metadata tag structure */
+typedef struct
+{
+ char *item;
+ char *value;
+} mp4ff_tag_t;
+
+/* metadata list structure */
+typedef struct
+{
+ mp4ff_tag_t *tags;
+ uint32_t count;
+} mp4ff_metadata_t;
+
+int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data);
+
+#endif
+
#ifdef __cplusplus
}
--- /dev/null
+++ b/common/mp4ff/mp4ff_int_types.h
@@ -1,0 +1,20 @@
+#ifndef _MP4FF_INT_TYPES_H_
+#define _MP4FF_INT_TYPES_H_
+
+typedef char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef long int32_t;
+typedef unsigned long uint32_t;
+
+#ifdef _WIN32
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+#endif
+
+
+#endif
\ No newline at end of file
--- a/common/mp4ff/mp4ffint.h
+++ b/common/mp4ff/mp4ffint.h
@@ -22,7 +22,7 @@
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
-** $Id: mp4ffint.h,v 1.3 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4ffint.h,v 1.4 2003/12/11 18:32:39 menno Exp $
**/
#ifndef MP4FF_INTERNAL_H
@@ -32,7 +32,9 @@
extern "C" {
#endif /* __cplusplus */
+#include "mp4ff_int_types.h"
+
#define MAX_TRACKS 1024
#define TRACK_UNKNOWN 0
#define TRACK_AUDIO 1
@@ -93,45 +95,21 @@
#define ATOM_GENRE2 20
#define ATOM_TEMPO 21
-
-#ifdef _WIN32
-typedef __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#else
-
-#define stricmp strcasecmp
-
#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#else
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#define u_int8_t uint8_t
-#define u_int16_t uint16_t
-#define u_int32_t uint32_t
-#define u_int64_t uint64_t
-#else
-typedef unsigned long long uint64_t;
-typedef unsigned long uint32_t;
-typedef unsigned short uint16_t;
-typedef unsigned char uint8_t;
-typedef long long int64_t;
-typedef long int32_t;
-typedef short int16_t;
-typedef char int8_t;
-#endif
-#endif
-#endif
+/* file callback structure */
+typedef struct
+{
+ uint32_t (*read)(void *user_data, void *buffer, uint32_t length);
+ uint32_t (*write)(void *udata, void *buffer, uint32_t length);
+ uint32_t (*seek)(void *user_data, uint64_t position);
+ uint32_t (*truncate)(void *user_data);
+ void *user_data;
+} mp4ff_callback_t;
+
+
/* metadata tag structure */
typedef struct
{
@@ -147,17 +125,8 @@
} mp4ff_metadata_t;
-/* file callback structure */
typedef struct
{
- int32_t (*read)(void *udata, void *buffer, int32_t length);
- int32_t (*write)(void *udata, void *buffer, int32_t length);
- int32_t (*seek)(void *udata, int32_t position);
- void *user_data;
-} mp4ff_callback_t;
-
-typedef struct
-{
int32_t type;
int32_t channelCount;
int32_t sampleSize;
@@ -190,6 +159,12 @@
uint8_t *decoderConfig;
int32_t decoderConfigLen;
+ uint32_t maxBitrate;
+ uint32_t avgBitrate;
+
+ uint32_t timeScale;
+ uint64_t duration;
+
} mp4ff_track_t;
/* mp4 main file structure */
@@ -197,7 +172,7 @@
{
/* stream to read from */
mp4ff_callback_t *stream;
- int32_t current_position;
+ int64_t current_position;
int32_t moov_read;
uint64_t moov_offset;
@@ -223,16 +198,19 @@
/* mp4util.c */
-int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, const int32_t size);
-int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, const int32_t size);
+int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, uint32_t size);
+int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, uint32_t size);
uint64_t mp4ff_read_int64(mp4ff_t *f);
uint32_t mp4ff_read_int32(mp4ff_t *f);
uint32_t mp4ff_read_int24(mp4ff_t *f);
uint16_t mp4ff_read_int16(mp4ff_t *f);
uint8_t mp4ff_read_char(mp4ff_t *f);
+int32_t mp4ff_write_int32(mp4ff_t *f,const uint32_t data);
uint32_t mp4ff_read_mp4_descr_length(mp4ff_t *f);
-int32_t mp4ff_position(const mp4ff_t *f);
-int32_t mp4ff_set_position(mp4ff_t *f, const int32_t position);
+int64_t mp4ff_position(const mp4ff_t *f);
+int32_t mp4ff_set_position(mp4ff_t *f, const int64_t position);
+int32_t mp4ff_truncate(mp4ff_t * f);
+char * mp4ff_read_string(mp4ff_t * f,uint32_t length);
/* mp4atom.c */
static int32_t mp4ff_atom_get_size(const int8_t *data);
@@ -266,11 +244,6 @@
/* mp4meta.c */
static int32_t mp4ff_tag_add_field(mp4ff_metadata_t *tags, const char *item, const char *value);
static int32_t mp4ff_tag_set_field(mp4ff_metadata_t *tags, const char *item, const char *value);
-static int32_t GenreToString(char** GenreStr, const uint16_t genre);
-static int32_t StringToGenre(const char* GenreStr);
-static int32_t TrackToString(char** str, const uint16_t track, const uint16_t totalTracks);
-static int32_t StringToTrack(const char *str, uint16_t *track, uint16_t *totalTracks);
-static int32_t TempoToString(char** str, const uint16_t tempo);
static int32_t mp4ff_set_metadata_name(mp4ff_t *f, const uint8_t atom_type, char **name);
static int32_t mp4ff_parse_tag(mp4ff_t *f, const uint8_t parent_atom_type, const int32_t size);
static int32_t mp4ff_meta_find_by_name(const mp4ff_t *f, const char *item, char **value);
@@ -299,10 +272,14 @@
mp4ff_t *mp4ff_open_edit(mp4ff_callback_t *f);
#endif
void mp4ff_close(mp4ff_t *ff);
-static void mp4ff_track_add(mp4ff_t *f);
-static int32_t parse_sub_atoms(mp4ff_t *f, const uint64_t total_size);
-static int32_t parse_atoms(mp4ff_t *f);
+void mp4ff_track_add(mp4ff_t *f);
+int32_t parse_sub_atoms(mp4ff_t *f, const uint64_t total_size);
+int32_t parse_atoms(mp4ff_t *f);
+
int32_t mp4ff_get_sample_duration(const mp4ff_t *f, const int32_t track, const int32_t sample);
+int64_t mp4ff_get_sample_offset(const mp4ff_t *f, const int32_t track, const int32_t sample);
+int32_t mp4ff_find_sample(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip);
+
int32_t mp4ff_read_sample(mp4ff_t *f, const int32_t track, const int32_t sample,
uint8_t **audio_buffer, uint32_t *bytes);
int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int32_t track,
@@ -311,6 +288,8 @@
int32_t mp4ff_time_scale(const mp4ff_t *f, const int32_t track);
int32_t mp4ff_num_samples(const mp4ff_t *f, const int32_t track);
+uint32_t mp4ff_meta_genre_to_index(const char * genrestr);//returns 1-based index, 0 if not found
+const char * mp4ff_meta_index_to_genre(uint32_t idx);//returns pointer to static string
#ifdef __cplusplus
}
--- a/common/mp4ff/mp4meta.c
+++ b/common/mp4ff/mp4meta.c
@@ -22,7 +22,7 @@
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
-** $Id: mp4meta.c,v 1.3 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4meta.c,v 1.4 2003/12/11 18:32:39 menno Exp $
**/
#ifdef USE_TAGGING
@@ -44,12 +44,9 @@
if (backup) free(backup);
return 0;
} else {
- int i_len = strlen(item);
- int v_len = strlen(value);
+ tags->tags[tags->count].item = strdup(item);
+ tags->tags[tags->count].value = strdup(value);
- tags->tags[tags->count].item = (char *)malloc(i_len+1);
- tags->tags[tags->count].value = (char *)malloc(v_len+1);
-
if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
{
if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
@@ -59,11 +56,6 @@
return 0;
}
- memcpy(tags->tags[tags->count].item, item, i_len);
- memcpy(tags->tags[tags->count].value, value, v_len);
- tags->tags[tags->count].item[i_len] = '\0';
- tags->tags[tags->count].value[v_len] = '\0';
-
tags->count++;
return 1;
}
@@ -146,55 +138,37 @@
"SynthPop",
};
-static int32_t GenreToString(char** GenreStr, const uint16_t genre)
+uint32_t mp4ff_meta_genre_to_index(const char * genrestr)
{
- if (genre > 0 && genre <= sizeof(ID3v1GenreList)/sizeof(*ID3v1GenreList))
- {
- *GenreStr = (char*)malloc((strlen(ID3v1GenreList[genre-1])+1)*sizeof(char));
- memset(*GenreStr, 0, (strlen(ID3v1GenreList[genre-1])+1)*sizeof(char));
- strcpy(*GenreStr, ID3v1GenreList[genre-1]);
- return 0;
- }
-
- *GenreStr = NULL;
- return 1;
+ unsigned n;
+ for(n=0;n<sizeof(ID3v1GenreList)/sizeof(ID3v1GenreList[0]);n++)
+ {
+ if (!stricmp(genrestr,ID3v1GenreList[n])) return n+1;
+ }
+ return 0;
}
-static int32_t StringToGenre(const char* GenreStr)
+const char * mp4ff_meta_index_to_genre(uint32_t idx)
{
- int32_t i;
-
- for (i = 0; i < sizeof(ID3v1GenreList)/sizeof(*ID3v1GenreList); i++)
- {
- if (stricmp(GenreStr, ID3v1GenreList[i]) == 0)
- return i+1;
- }
- return 0;
+ if (idx>0 && idx<=sizeof(ID3v1GenreList)/sizeof(ID3v1GenreList[0]))
+ {
+ return ID3v1GenreList[idx-1];
+ }
+ else
+ {
+ return 0;
+ }
}
+
static int32_t TrackToString(char** str, const uint16_t track, const uint16_t totalTracks)
{
- *str = malloc(12);
- sprintf(*str, "%.5u of %.5u", track, totalTracks);
-
+ char temp[32];
+ sprintf(temp, "%.5u of %.5u", track, totalTracks);
+ *str = strdup(temp);
return 0;
}
-static int32_t StringToTrack(const char *str, uint16_t *track, uint16_t *totalTracks)
-{
- sscanf(str, "%.5u of %.5u", &track, &totalTracks);
-
- return 0;
-}
-
-static int32_t TempoToString(char** str, const uint16_t tempo)
-{
- *str = malloc(12);
- sprintf(*str, "%.5u BPM", tempo);
-
- return 0;
-}
-
static int32_t mp4ff_set_metadata_name(mp4ff_t *f, const uint8_t atom_type, char **name)
{
static char *tag_names[] = {
@@ -203,7 +177,6 @@
"disc", "compilation", "genre", "tempo"
};
uint8_t tag_idx = 0;
- uint16_t size;
switch (atom_type)
{
@@ -223,10 +196,7 @@
default: tag_idx = 0; break;
}
- size = strlen(tag_names[tag_idx])+1;
- *name = malloc(size+1);
- memset(*name, 0, size+1);
- memcpy(*name, tag_names[tag_idx], size);
+ *name = strdup(tag_names[tag_idx]);
return 0;
}
@@ -236,77 +206,97 @@
uint8_t atom_type;
uint8_t header_size = 0;
uint64_t subsize, sumsize = 0;
- char *name = NULL;
- char *data = NULL;
+ char * name = NULL;
+ char * data = NULL;
+ uint32_t done = 0;
+
while (sumsize < size)
{
+ uint64_t destpos;
subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
- if (atom_type == ATOM_DATA)
- {
- mp4ff_read_char(f); /* version */
- mp4ff_read_int24(f); /* flags */
- mp4ff_read_int32(f); /* reserved */
- data = malloc(subsize-(header_size+8)+1);
- mp4ff_read_data(f, data, subsize-(header_size+8));
- data[subsize-(header_size+8)] = '\0';
+ destpos = mp4ff_position(f)+subsize-header_size;
+ if (!done)
+ {
+ if (atom_type == ATOM_DATA)
+ {
+ mp4ff_read_char(f); /* version */
+ mp4ff_read_int24(f); /* flags */
+ mp4ff_read_int32(f); /* reserved */
- /* some need special attention */
- if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO)
- {
- uint16_t val = 0;
- char *tmp;
- tmp = data;
+ /* some need special attention */
+ if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO)
+ {
+ if (subsize - header_size >= 8 + 2)
+ {
+ uint16_t val = mp4ff_read_int16(f);
- val = (uint16_t)(tmp[1]);
- val += (uint16_t)(tmp[0]<<8);
+ if (parent_atom_type == ATOM_TEMPO)
+ {
+ char temp[16];
+ sprintf(temp, "%.5u BPM", val);
+ mp4ff_tag_add_field(&(f->tags), "tempo", temp);
+ }
+ else
+ {
+ const char * temp = mp4ff_meta_index_to_genre(val);
+ if (temp)
+ {
+ mp4ff_tag_add_field(&(f->tags), "genre", temp);
+ }
+ }
+ done = 1;
+ }
+ } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
+ if (!done && subsize - header_size >= 8 + 8)
+ {
+ uint16_t index,total;
+ char temp[32];
+ mp4ff_read_int16(f);
+ index = mp4ff_read_int16(f);
+ total = mp4ff_read_int16(f);
+ mp4ff_read_int16(f);
- if (data)
- {
- free(data);
- data = NULL;
- }
- if (parent_atom_type == ATOM_TEMPO)
- TempoToString(&data, val);
- else
- GenreToString(&data, val);
- } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
- uint16_t val1 = 0, val2 = 0;
- char *tmp;
- tmp = data;
-
- val1 = (uint16_t)(tmp[3]);
- val1 += (uint16_t)(tmp[2]<<8);
- val2 = (uint16_t)(tmp[5]);
- val2 += (uint16_t)(tmp[4]<<8);
-
- if (data)
- {
- free(data);
- data = NULL;
- }
- TrackToString(&data, val1, val2);
- }
- } else if (atom_type == ATOM_NAME) {
- mp4ff_read_char(f); /* version */
- mp4ff_read_int24(f); /* flags */
- name = malloc(subsize-(header_size+4)+1);
- mp4ff_read_data(f, name, subsize-(header_size+4));
- name[subsize-12] = '\0';
- } else {
- mp4ff_set_position(f, mp4ff_position(f)+subsize-header_size);
- }
- sumsize += subsize;
+ itoa(index,temp,10);
+ mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "track" : "disc", temp);
+ if (total>0)
+ {
+ itoa(total,temp,10);
+ mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "totaltracks" : "totaldiscs", temp);
+ }
+ done = 1;
+ }
+ } else
+ {
+ if (data) {free(data);data = NULL;}
+ data = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+8)));
+ }
+ } else if (atom_type == ATOM_NAME) {
+ if (!done)
+ {
+ mp4ff_read_char(f); /* version */
+ mp4ff_read_int24(f); /* flags */
+ if (name) free(name);
+ name = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+4)));
+ }
+ }
+ mp4ff_set_position(f, destpos);
+ sumsize += subsize;
+ }
}
- if (name == NULL)
- {
- mp4ff_set_metadata_name(f, parent_atom_type, &name);
- }
+ if (data)
+ {
+ if (!done)
+ {
+ if (name == NULL) mp4ff_set_metadata_name(f, parent_atom_type, &name);
+ if (name) mp4ff_tag_add_field(&(f->tags), name, data);
+ }
- mp4ff_tag_set_field(&(f->tags), (const char*)name, (const char*)data);
-
- return 0;
+ free(data);
+ }
+ if (name) free(name);
+ return 1;
}
int32_t mp4ff_parse_metadata(mp4ff_t *f, const int32_t size)
@@ -318,7 +308,7 @@
while (sumsize < size)
{
subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
- mp4ff_parse_tag(f, atom_type, subsize-header_size);
+ mp4ff_parse_tag(f, atom_type, (uint32_t)(subsize-header_size));
sumsize += subsize;
}
@@ -335,13 +325,8 @@
{
if (!stricmp(f->tags.tags[i].item, item))
{
- int v_len = strlen(f->tags.tags[i].value);
-
- *value = (char*)malloc(v_len + 1);
- memcpy(*value, f->tags.tags[i].value, v_len);
- (*value)[v_len] = '\0';
-
- return 0;
+ *value = strdup(f->tags.tags[i].value);
+ return 1;
}
}
@@ -348,7 +333,7 @@
*value = NULL;
/* not found */
- return 1;
+ return 0;
}
int32_t mp4ff_meta_get_num_items(const mp4ff_t *f)
@@ -363,20 +348,12 @@
{
*item = NULL;
*value = NULL;
- return 1;
+ return 0;
} else {
- int i_len = strlen(f->tags.tags[index].item);
- int v_len = strlen(f->tags.tags[index].value);
-
- *item = (char*)malloc(i_len + 1);
- memcpy(*item, f->tags.tags[index].item, i_len);
- (*item)[i_len] = '\0';
- *value = (char*)malloc(v_len + 1);
- memcpy(*value, f->tags.tags[index].value, v_len);
- (*value)[v_len] = '\0';
+ *item = strdup(f->tags.tags[index].item);
+ *value = strdup(f->tags.tags[index].value);
+ return 1;
}
-
- return 0;
}
int32_t mp4ff_meta_get_title(const mp4ff_t *f, char **value)
--- a/common/mp4ff/mp4sample.c
+++ b/common/mp4ff/mp4sample.c
@@ -22,7 +22,7 @@
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
-** $Id: mp4sample.c,v 1.4 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4sample.c,v 1.10 2003/12/23 18:53:24 menno Exp $
**/
#include <stdlib.h>
@@ -77,11 +77,13 @@
static int32_t mp4ff_chunk_to_offset(const mp4ff_t *f, const int32_t track, const int32_t chunk)
{
- if (f->track[track]->stco_entry_count && (chunk > f->track[track]->stco_entry_count))
+ const mp4ff_track_t * p_track = f->track[track];
+
+ if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count))
{
- return f->track[track]->stco_chunk_offset[f->track[track]->stco_entry_count - 1];
- } else if (f->track[track]->stco_entry_count) {
- return f->track[track]->stco_chunk_offset[chunk - 1];
+ return p_track->stco_chunk_offset[p_track->stco_entry_count - 1];
+ } else if (p_track->stco_entry_count) {
+ return p_track->stco_chunk_offset[chunk - 1];
} else {
return 8;
}
@@ -93,14 +95,15 @@
const int32_t chunk_sample, const int32_t sample)
{
int32_t i, total;
+ const mp4ff_track_t * p_track = f->track[track];
- if (f->track[track]->stsz_sample_size)
+ if (p_track->stsz_sample_size)
{
- return sample * f->track[track]->channelCount * f->track[track]->sampleSize/8;
+ return sample * p_track->channelCount * p_track->sampleSize/8;
} else {
for(i = chunk_sample, total = 0; i < sample; i++)
{
- total += f->track[track]->stsz_table[i];
+ total += p_track->stsz_table[i];
}
}
@@ -122,12 +125,13 @@
int32_t mp4ff_audio_frame_size(const mp4ff_t *f, const int32_t track, const int32_t sample)
{
int32_t bytes;
+ const mp4ff_track_t * p_track = f->track[track];
- if (f->track[track]->stsz_sample_size)
+ if (p_track->stsz_sample_size)
{
- bytes = f->track[track]->stsz_sample_size;
+ bytes = p_track->stsz_sample_size;
} else {
- bytes = f->track[track]->stsz_table[sample];
+ bytes = p_track->stsz_table[sample];
}
return bytes;
--- /dev/null
+++ b/common/mp4ff/mp4tagupdate.c
@@ -1,0 +1,644 @@
+#include <stdlib.h>
+#include <string.h>
+#include "mp4ffint.h"
+
+#ifdef USE_TAGGING
+
+static uint32_t fix_byte_order_32(uint32_t src)
+{
+ uint32_t result;
+ uint32_t a, b, c, d;
+ int8_t data[4];
+
+ memcpy(data,&src,sizeof(src));
+ a = (uint8_t)data[0];
+ b = (uint8_t)data[1];
+ c = (uint8_t)data[2];
+ d = (uint8_t)data[3];
+
+ result = (a<<24) | (b<<16) | (c<<8) | d;
+ return (uint32_t)result;
+}
+
+static uint16_t fix_byte_order_16(uint16_t src)
+{
+ uint16_t result;
+ uint16_t a, b;
+ int8_t data[2];
+
+ memcpy(data,&src,sizeof(src));
+ a = (uint8_t)data[0];
+ b = (uint8_t)data[1];
+
+ result = (a<<8) | b;
+ return (uint16_t)result;
+}
+
+
+typedef struct
+{
+ void * data;
+ unsigned written;
+ unsigned allocated;
+ unsigned error;
+} membuffer;
+
+unsigned membuffer_write(membuffer * buf,const void * ptr,unsigned bytes)
+{
+ unsigned dest_size = buf->written + bytes;
+
+ if (buf->error) return 0;
+ if (dest_size > buf->allocated)
+ {
+ do
+ {
+ buf->allocated <<= 1;
+ } while(dest_size > buf->allocated);
+
+ {
+ void * newptr = realloc(buf->data,buf->allocated);
+ if (newptr==0)
+ {
+ free(buf->data);
+ buf->data = 0;
+ buf->error = 1;
+ return 0;
+ }
+ buf->data = newptr;
+ }
+ }
+
+ if (ptr) memcpy((char*)buf->data + buf->written,ptr,bytes);
+ buf->written += bytes;
+ return bytes;
+}
+
+#define membuffer_write_data membuffer_write
+
+unsigned membuffer_write_int32(membuffer * buf,uint32_t data)
+{
+ uint8_t temp[4] = {(uint8_t)(data>>24),(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data};
+ return membuffer_write_data(buf,temp,4);
+}
+
+unsigned membuffer_write_int24(membuffer * buf,uint32_t data)
+{
+ uint8_t temp[3] = {(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data};
+ return membuffer_write_data(buf,temp,3);
+}
+
+unsigned membuffer_write_int16(membuffer * buf,uint16_t data)
+{
+ uint8_t temp[2] = {(uint8_t)(data>>8),(uint8_t)data};
+ return membuffer_write_data(buf,temp,2);
+}
+
+unsigned membuffer_write_atom_name(membuffer * buf,const char * data)
+{
+ return membuffer_write_data(buf,data,4)==4 ? 1 : 0;
+}
+
+void membuffer_write_atom(membuffer * buf,const char * name,unsigned size,const void * data)
+{
+ membuffer_write_int32(buf,size + 8);
+ membuffer_write_atom_name(buf,name);
+ membuffer_write_data(buf,data,size);
+}
+
+unsigned membuffer_write_string(membuffer * buf,const char * data)
+{
+ return membuffer_write_data(buf,data,strlen(data));
+}
+
+unsigned membuffer_write_int8(membuffer * buf,uint8_t data)
+{
+ return membuffer_write_data(buf,&data,1);
+}
+
+void * membuffer_get_ptr(const membuffer * buf)
+{
+ return buf->data;
+}
+
+unsigned membuffer_get_size(const membuffer * buf)
+{
+ return buf->written;
+}
+
+unsigned membuffer_error(const membuffer * buf)
+{
+ return buf->error;
+}
+
+void membuffer_set_error(membuffer * buf) {buf->error = 1;}
+
+unsigned membuffer_transfer_from_file(membuffer * buf,mp4ff_t * src,unsigned bytes)
+{
+ unsigned oldsize;
+ void * bufptr;
+
+ oldsize = membuffer_get_size(buf);
+ if (membuffer_write_data(buf,0,bytes) != bytes) return 0;
+
+ bufptr = membuffer_get_ptr(buf);
+ if (bufptr==0) return 0;
+
+ if ((unsigned)mp4ff_read_data(src,(char*)bufptr + oldsize,bytes)!=bytes)
+ {
+ membuffer_set_error(buf);
+ return 0;
+ }
+
+ return bytes;
+}
+
+
+membuffer * membuffer_create()
+{
+ const unsigned initial_size = 256;
+
+ membuffer * buf = (membuffer *) malloc(sizeof(membuffer));
+ buf->data = malloc(initial_size);
+ buf->written = 0;
+ buf->allocated = initial_size;
+ buf->error = buf->data == 0 ? 1 : 0;
+
+ return buf;
+}
+
+void membuffer_free(membuffer * buf)
+{
+ if (buf->data) free(buf->data);
+ free(buf);
+}
+
+void * membuffer_detach(membuffer * buf)
+{
+ void * ret;
+
+ if (buf->error) return 0;
+
+ ret = realloc(buf->data,buf->written);
+
+ if (ret == 0) free(buf->data);
+
+ buf->data = 0;
+ buf->error = 1;
+
+ return ret;
+}
+
+#if 0
+/* metadata tag structure */
+typedef struct
+{
+ char *item;
+ char *value;
+} mp4ff_tag_t;
+
+/* metadata list structure */
+typedef struct
+{
+ mp4ff_tag_t *tags;
+ uint32_t count;
+} mp4ff_metadata_t;
+#endif
+
+typedef struct
+{
+ const char * atom;
+ const char * name;
+} stdmeta_entry;
+
+static stdmeta_entry stdmetas[] =
+{
+ {"�nam","title"},
+ {"�ART","artist"},
+ {"�wrt","writer"},
+ {"�alb","album"},
+ {"�day","date"},
+ {"�too","tool"},
+ {"�cmt","comment"},
+// {"�gen","genre"},
+ {"cpil","compilation"},
+// {"trkn","track"},
+// {"disk","disc"},
+// {"gnre","genre"},
+};
+
+
+static const char* find_standard_meta(const char * name) //returns atom name if found, 0 if not
+{
+ unsigned n;
+ for(n=0;n<sizeof(stdmetas)/sizeof(stdmetas[0]);n++)
+ {
+ if (!stricmp(name,stdmetas[n].name)) return stdmetas[n].atom;
+ }
+ return 0;
+}
+
+static void membuffer_write_track_tag(membuffer * buf,const char * name,uint32_t index,uint32_t total)
+{
+ membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
+ membuffer_write_atom_name(buf,name);
+ membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
+ membuffer_write_atom_name(buf,"data");
+ membuffer_write_int32(buf,0);//flags
+ membuffer_write_int32(buf,0);//reserved
+ membuffer_write_int16(buf,0);
+ membuffer_write_int16(buf,(uint16_t)index);//track number
+ membuffer_write_int16(buf,(uint16_t)total);//total tracks
+ membuffer_write_int16(buf,0);
+}
+
+static void membuffer_write_int16_tag(membuffer * buf,const char * name,uint16_t value)
+{
+ membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
+ membuffer_write_atom_name(buf,name);
+ membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
+ membuffer_write_atom_name(buf,"data");
+ membuffer_write_int32(buf,0);//flags
+ membuffer_write_int32(buf,0);//reserved
+ membuffer_write_int16(buf,value);//value
+}
+
+static void membuffer_write_std_tag(membuffer * buf,const char * name,const char * value)
+{
+ membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value) );
+ membuffer_write_atom_name(buf,name);
+ membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
+ membuffer_write_atom_name(buf,"data");
+ membuffer_write_int32(buf,1);//flags
+ membuffer_write_int32(buf,0);//reserved
+ membuffer_write_data(buf,value,strlen(value));
+}
+
+static void membuffer_write_custom_tag(membuffer * buf,const char * name,const char * value)
+{
+ membuffer_write_int32(buf,8 /*atom header*/ + 0x1C /*weirdo itunes atom*/ + 12 /*name atom header*/ + strlen(name) + 16 /*data atom header + flags*/ + strlen(value) );
+ membuffer_write_atom_name(buf,"----");
+ membuffer_write_int32(buf,0x1C);//weirdo itunes atom
+ membuffer_write_atom_name(buf,"mean");
+ membuffer_write_int32(buf,0);
+ membuffer_write_data(buf,"com.apple.iTunes",16);
+ membuffer_write_int32(buf,12 + strlen(name));
+ membuffer_write_atom_name(buf,"name");
+ membuffer_write_int32(buf,0);
+ membuffer_write_data(buf,name,strlen(name));
+ membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
+ membuffer_write_atom_name(buf,"data");
+ membuffer_write_int32(buf,1);//flags
+ membuffer_write_int32(buf,0);//reserved
+ membuffer_write_data(buf,value,strlen(value));
+
+}
+
+static uint32_t myatoi(const char * param)
+{
+ return param ? atoi(param) : 0;
+}
+
+static uint32_t create_ilst(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
+{
+ membuffer * buf = membuffer_create();
+ unsigned metaptr;
+ char * mask = (char*)malloc(data->count);
+ memset(mask,0,data->count);
+
+ {
+ const char * tracknumber_ptr = 0, * totaltracks_ptr = 0;
+ const char * discnumber_ptr = 0, * totaldiscs_ptr = 0;
+ const char * genre_ptr = 0, * tempo_ptr = 0;
+ for(metaptr = 0; metaptr < data->count; metaptr++)
+ {
+ mp4ff_tag_t * tag = &data->tags[metaptr];
+ if (!stricmp(tag->item,"tracknumber") || !stricmp(tag->item,"track"))
+ {
+ if (tracknumber_ptr==0) tracknumber_ptr = tag->value;
+ mask[metaptr] = 1;
+ }
+ else if (!stricmp(tag->item,"totaltracks"))
+ {
+ if (totaltracks_ptr==0) totaltracks_ptr = tag->value;
+ mask[metaptr] = 1;
+ }
+ else if (!stricmp(tag->item,"discnumber") || !stricmp(tag->item,"disc"))
+ {
+ if (discnumber_ptr==0) discnumber_ptr = tag->value;
+ mask[metaptr] = 1;
+ }
+ else if (!stricmp(tag->item,"totaldiscs"))
+ {
+ if (totaldiscs_ptr==0) totaldiscs_ptr = tag->value;
+ mask[metaptr] = 1;
+ }
+ else if (!stricmp(tag->item,"genre"))
+ {
+ if (genre_ptr==0) genre_ptr = tag->value;
+ mask[metaptr] = 1;
+ }
+ else if (!stricmp(tag->item,"tempo"))
+ {
+ if (tempo_ptr==0) tempo_ptr = tag->value;
+ mask[metaptr] = 1;
+ }
+
+ }
+
+ if (tracknumber_ptr) membuffer_write_track_tag(buf,"trkn",myatoi(tracknumber_ptr),myatoi(totaltracks_ptr));
+ if (discnumber_ptr) membuffer_write_track_tag(buf,"disk",myatoi(discnumber_ptr),myatoi(totaldiscs_ptr));
+ if (tempo_ptr) membuffer_write_int16_tag(buf,"tmpo",(uint16_t)myatoi(tempo_ptr));
+
+ if (genre_ptr)
+ {
+ uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
+ if (index==0)
+ membuffer_write_std_tag(buf,"gnre",genre_ptr);
+ else
+ membuffer_write_int16_tag(buf,"�gen",(uint16_t)index);
+ }
+ }
+
+ for(metaptr = 0; metaptr < data->count; metaptr++)
+ {
+ if (!mask[metaptr])
+ {
+ mp4ff_tag_t * tag = &data->tags[metaptr];
+ const char * std_meta_atom = find_standard_meta(tag->item);
+ if (std_meta_atom)
+ {
+ membuffer_write_std_tag(buf,std_meta_atom,tag->value);
+ }
+ else
+ {
+ membuffer_write_custom_tag(buf,tag->item,tag->value);
+ }
+ }
+ }
+
+ free(mask);
+
+ if (membuffer_error(buf))
+ {
+ membuffer_free(buf);
+ return 0;
+ }
+
+ *out_size = membuffer_get_size(buf);
+ *out_buffer = membuffer_detach(buf);
+ membuffer_free(buf);
+
+ return 1;
+}
+
+static uint32_t find_atom(mp4ff_t * f,uint64_t base,uint32_t size,const char * name)
+{
+ uint32_t remaining = size;
+ uint64_t atom_offset = base;
+ for(;;)
+ {
+ char atom_name[4];
+ uint32_t atom_size;
+
+ mp4ff_set_position(f,atom_offset);
+
+ if (remaining < 8) break;
+ atom_size = mp4ff_read_int32(f);
+ if (atom_size > remaining || atom_size < 8) break;
+ mp4ff_read_data(f,atom_name,4);
+
+ if (!memcmp(atom_name,name,4))
+ {
+ mp4ff_set_position(f,atom_offset);
+ return 1;
+ }
+
+ remaining -= atom_size;
+ atom_offset += atom_size;
+ }
+ return 0;
+}
+
+static uint32_t find_atom_v2(mp4ff_t * f,uint64_t base,uint32_t size,const char * name,uint32_t extraheaders,const char * name_inside)
+{
+ uint64_t first_base = (uint64_t)(-1);
+ while(find_atom(f,base,size,name))//try to find atom <name> with atom <name_inside> in it
+ {
+ uint64_t mybase = mp4ff_position(f);
+ uint32_t mysize = mp4ff_read_int32(f);
+
+ if (first_base == (uint64_t)(-1)) first_base = mybase;
+
+ if (mysize < 8 + extraheaders) break;
+
+ if (find_atom(f,mybase+(8+extraheaders),mysize-(8+extraheaders),name_inside))
+ {
+ mp4ff_set_position(f,mybase);
+ return 2;
+ }
+ base += mysize;
+ if (size<=mysize) {size=0;break;}
+ size -= mysize;
+ }
+
+ if (first_base != (uint64_t)(-1))//wanted atom inside not found
+ {
+ mp4ff_set_position(f,first_base);
+ return 1;
+ }
+ else return 0;
+}
+
+static uint32_t create_meta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
+{
+ membuffer * buf;
+ uint32_t ilst_size;
+ void * ilst_buffer;
+
+ if (!create_ilst(data,&ilst_buffer,&ilst_size)) return 0;
+
+ buf = membuffer_create();
+
+ membuffer_write_int32(buf,0);
+ membuffer_write_atom(buf,"ilst",ilst_size,ilst_buffer);
+ free(ilst_buffer);
+
+ *out_size = membuffer_get_size(buf);
+ *out_buffer = membuffer_detach(buf);
+ membuffer_free(buf);
+ return 1;
+}
+
+static uint32_t create_udta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
+{
+ membuffer * buf;
+ uint32_t meta_size;
+ void * meta_buffer;
+
+ if (!create_meta(data,&meta_buffer,&meta_size)) return 0;
+
+ buf = membuffer_create();
+
+ membuffer_write_atom(buf,"meta",meta_size,meta_buffer);
+
+ free(meta_buffer);
+
+ *out_size = membuffer_get_size(buf);
+ *out_buffer = membuffer_detach(buf);
+ membuffer_free(buf);
+ return 1;
+}
+
+static uint32_t modify_moov(mp4ff_t * f,const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
+{
+ uint64_t total_base = f->moov_offset + 8;
+ uint32_t total_size = (uint32_t)(f->moov_size - 8);
+
+ uint64_t udta_offset,meta_offset,ilst_offset;
+ uint32_t udta_size, meta_size, ilst_size;
+
+ uint32_t new_ilst_size;
+ void * new_ilst_buffer;
+
+ uint8_t * p_out;
+ int32_t size_delta;
+
+
+ if (!find_atom_v2(f,total_base,total_size,"udta",0,"meta"))
+ {
+ membuffer * buf;
+ void * new_udta_buffer;
+ uint32_t new_udta_size;
+ if (!create_udta(data,&new_udta_buffer,&new_udta_size)) return 0;
+
+ buf = membuffer_create();
+ mp4ff_set_position(f,total_base);
+ membuffer_transfer_from_file(buf,f,total_size);
+
+ membuffer_write_atom(buf,"udta",new_udta_size,new_udta_buffer);
+
+ free(new_udta_buffer);
+
+ *out_size = membuffer_get_size(buf);
+ *out_buffer = membuffer_detach(buf);
+ membuffer_free(buf);
+ return 1;
+ }
+ else
+ {
+ udta_offset = mp4ff_position(f);
+ udta_size = mp4ff_read_int32(f);
+ if (find_atom_v2(f,udta_offset+8,udta_size-8,"meta",4,"ilst")<2)
+ {
+ membuffer * buf;
+ void * new_meta_buffer;
+ uint32_t new_meta_size;
+ if (!create_meta(data,&new_meta_buffer,&new_meta_size)) return 0;
+
+ buf = membuffer_create();
+ mp4ff_set_position(f,total_base);
+ membuffer_transfer_from_file(buf,f,(uint32_t)(udta_offset - total_base));
+
+ membuffer_write_int32(buf,udta_size + 8 + new_meta_size);
+ membuffer_write_atom_name(buf,"udta");
+ membuffer_transfer_from_file(buf,f,udta_size);
+
+ membuffer_write_atom(buf,"meta",new_meta_size,new_meta_buffer);
+ free(new_meta_buffer);
+
+ *out_size = membuffer_get_size(buf);
+ *out_buffer = membuffer_detach(buf);
+ membuffer_free(buf);
+ return 1;
+ }
+ meta_offset = mp4ff_position(f);
+ meta_size = mp4ff_read_int32(f);
+ if (!find_atom(f,meta_offset+12,meta_size-12,"ilst")) return 0;//shouldn't happen, find_atom_v2 above takes care of it
+ ilst_offset = mp4ff_position(f);
+ ilst_size = mp4ff_read_int32(f);
+
+ if (!create_ilst(data,&new_ilst_buffer,&new_ilst_size)) return 0;
+
+ size_delta = new_ilst_size - (ilst_size - 8);
+
+ *out_size = total_size + size_delta;
+ *out_buffer = malloc(*out_size);
+ if (*out_buffer == 0)
+ {
+ free(new_ilst_buffer);
+ return 0;
+ }
+
+ p_out = (uint8_t*)*out_buffer;
+
+ mp4ff_set_position(f,total_base);
+ mp4ff_read_data(f,p_out,(uint32_t)(udta_offset - total_base )); p_out += (uint32_t)(udta_offset - total_base );
+ *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
+ mp4ff_read_data(f,p_out,4); p_out += 4;
+ mp4ff_read_data(f,p_out,(uint32_t)(meta_offset - udta_offset - 8)); p_out += (uint32_t)(meta_offset - udta_offset - 8);
+ *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
+ mp4ff_read_data(f,p_out,4); p_out += 4;
+ mp4ff_read_data(f,p_out,(uint32_t)(ilst_offset - meta_offset - 8)); p_out += (uint32_t)(ilst_offset - meta_offset - 8);
+ *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
+ mp4ff_read_data(f,p_out,4); p_out += 4;
+
+ memcpy(p_out,new_ilst_buffer,new_ilst_size);
+ p_out += new_ilst_size;
+
+ mp4ff_set_position(f,ilst_offset + ilst_size);
+ mp4ff_read_data(f,p_out,(uint32_t)(total_size - (ilst_offset - total_base) - ilst_size));
+
+ free(new_ilst_buffer);
+ }
+ return 1;
+
+}
+
+int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data)
+{
+ void * new_moov_data;
+ uint32_t new_moov_size;
+
+ mp4ff_t *ff = malloc(sizeof(mp4ff_t));
+
+ memset(ff, 0, sizeof(mp4ff_t));
+ ff->stream = f;
+ mp4ff_set_position(ff,0);
+
+ parse_atoms(ff);
+
+
+ if (!modify_moov(ff,data,&new_moov_data,&new_moov_size))
+ {
+ mp4ff_close(ff);
+ return 0;
+ }
+
+ /* copy moov atom to end of the file */
+ if (ff->last_atom != ATOM_MOOV)
+ {
+ char *free_data = "free";
+
+ /* rename old moov to free */
+ mp4ff_set_position(ff, ff->moov_offset + 4);
+ mp4ff_write_data(ff, free_data, 4);
+
+ mp4ff_set_position(ff, ff->file_size);
+ mp4ff_write_int32(ff,new_moov_size + 8);
+ mp4ff_write_data(ff,"moov",4);
+ mp4ff_write_data(ff, new_moov_data, new_moov_size);
+ }
+ else
+ {
+ mp4ff_set_position(ff, ff->moov_offset);
+ mp4ff_write_int32(ff,new_moov_size + 8);
+ mp4ff_write_data(ff,"moov",4);
+ mp4ff_write_data(ff, new_moov_data, new_moov_size);
+ }
+
+ mp4ff_truncate(ff);
+
+ mp4ff_close(ff);
+ return 1;
+}
+#endif
--- a/common/mp4ff/mp4util.c
+++ b/common/mp4ff/mp4util.c
@@ -22,12 +22,13 @@
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
-** $Id: mp4util.c,v 1.5 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4util.c,v 1.11 2003/12/23 18:53:24 menno Exp $
**/
#include "mp4ffint.h"
+#include <stdlib.h>
-int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, const int32_t size)
+int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, uint32_t size)
{
int32_t result = 1;
@@ -38,8 +39,13 @@
return result;
}
-int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, const int32_t size)
+int32_t mp4ff_truncate(mp4ff_t * f)
{
+ return f->stream->truncate(f->stream->user_data);
+}
+
+int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, uint32_t size)
+{
int32_t result = 1;
result = f->stream->write(f->stream->user_data, data, size);
@@ -49,8 +55,25 @@
return result;
}
-int32_t mp4ff_set_position(mp4ff_t *f, const int32_t position)
+int32_t mp4ff_write_int32(mp4ff_t *f,const uint32_t data)
{
+ uint32_t result;
+ uint32_t a, b, c, d;
+ int8_t temp[4];
+
+ *(uint32_t*)temp = data;
+ a = (uint8_t)temp[0];
+ b = (uint8_t)temp[1];
+ c = (uint8_t)temp[2];
+ d = (uint8_t)temp[3];
+
+ result = (a<<24) | (b<<16) | (c<<8) | d;
+
+ return mp4ff_write_data(f,(uint8_t*)&result,sizeof(result));
+}
+
+int32_t mp4ff_set_position(mp4ff_t *f, const int64_t position)
+{
f->stream->seek(f->stream->user_data, position);
f->current_position = position;
@@ -57,7 +80,7 @@
return 0;
}
-int32_t mp4ff_position(const mp4ff_t *f)
+int64_t mp4ff_position(const mp4ff_t *f)
{
return f->current_position;
}
@@ -64,7 +87,7 @@
uint64_t mp4ff_read_int64(mp4ff_t *f)
{
- int8_t data[8];
+ uint8_t data[8];
uint64_t result = 0;
int8_t i;
@@ -121,6 +144,24 @@
result = (a<<8) | b;
return (uint16_t)result;
+}
+
+char * mp4ff_read_string(mp4ff_t * f,uint32_t length)
+{
+ char * str = (char*)malloc(length + 1);
+ if (str!=0)
+ {
+ if ((uint32_t)mp4ff_read_data(f,str,length)!=length)
+ {
+ free(str);
+ str = 0;
+ }
+ else
+ {
+ str[length] = 0;
+ }
+ }
+ return str;
}
uint8_t mp4ff_read_char(mp4ff_t *f)