From f3f1983b3156a97b8e2f492dd9e1db31cd2e4817 Mon Sep 17 00:00:00 2001 From: waker Date: Wed, 22 Aug 2012 22:27:36 +0200 Subject: aac: added chapters support --- plugins/libmp4ff/mp4atom.c | 162 +++++++++++++++++++++++++++++++++++++++++--- plugins/libmp4ff/mp4ff.c | 10 ++- plugins/libmp4ff/mp4ff.h | 35 +++------- plugins/libmp4ff/mp4ffint.h | 29 +++++++- 4 files changed, 198 insertions(+), 38 deletions(-) (limited to 'plugins/libmp4ff') diff --git a/plugins/libmp4ff/mp4atom.c b/plugins/libmp4ff/mp4atom.c index 823fa056..692b5a9a 100644 --- a/plugins/libmp4ff/mp4atom.c +++ b/plugins/libmp4ff/mp4atom.c @@ -42,6 +42,7 @@ # include #endif #include "mp4ffint.h" +#include #define COPYRIGHT_SYMBOL ((int8_t)0xA9) @@ -226,6 +227,18 @@ static uint8_t mp4ff_atom_name_to_type(const int8_t a, const int8_t b, return ATOM_PODCAST; else if (mp4ff_atom_compare(a,b,c,d, '-','-','-','-')) return ATOM_CUSTOM; + else if (mp4ff_atom_compare(a,b,c,d, 'c','h','p','l')) + return ATOM_CHPL; + else if (mp4ff_atom_compare(a,b,c,d, 'c','h','a','p')) + return ATOM_CHAP; + else if (mp4ff_atom_compare(a,b,c,d, 't','e','x','t')) + return ATOM_TEXT; + else if (mp4ff_atom_compare(a,b,c,d, 's','u','b','p')) + return ATOM_TEXT; + else if (mp4ff_atom_compare(a,b,c,d, 't','x','3','g')) + return ATOM_TEXT; + else if (mp4ff_atom_compare(a,b,c,d, 's','b','t','l')) + return ATOM_TEXT; else return ATOM_UNKNOWN; } @@ -251,7 +264,7 @@ uint64_t mp4ff_atom_read_header(mp4ff_t *f, uint8_t *atom_type, uint8_t *header_ size = mp4ff_read_int64(f); } - //printf("%c%c%c%c\n", atom_header[4], atom_header[5], atom_header[6], atom_header[7]); +// printf("%c%c%c%c\n", atom_header[4], atom_header[5], atom_header[6], atom_header[7]); *atom_type = mp4ff_atom_name_to_type(atom_header[4], atom_header[5], atom_header[6], atom_header[7]); @@ -403,6 +416,8 @@ static int32_t mp4ff_read_stsd(mp4ff_t *f) f->track[f->total_tracks - 1]->type = TRACK_VIDEO; } else if (atom_type == ATOM_MP4S) { f->track[f->total_tracks - 1]->type = TRACK_SYSTEM; + } else if (atom_type == ATOM_TEXT) { + f->track[f->total_tracks - 1]->type = TRACK_TEXT; } else { f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN; } @@ -552,7 +567,6 @@ static int32_t mp4ff_read_mvhd(mp4ff_t *f) return 0; } -#if 0 static int32_t mp4ff_read_tkhd(mp4ff_t *f) { uint8_t version; @@ -563,21 +577,22 @@ static int32_t mp4ff_read_tkhd(mp4ff_t *f) { mp4ff_read_int64(f);//creation-time mp4ff_read_int64(f);//modification-time - mp4ff_read_int32(f);//track-id + f->track[f->total_tracks - 1]->id = mp4ff_read_int32(f);//track-id mp4ff_read_int32(f);//reserved - f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);//duration +// 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 + f->track[f->total_tracks - 1]->id = 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; +// 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; } +#if 0 mp4ff_read_int32(f);//reserved mp4ff_read_int32(f);//reserved mp4ff_read_int16(f);//layer @@ -591,9 +606,9 @@ static int32_t mp4ff_read_tkhd(mp4ff_t *f) mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f);//width mp4ff_read_int32(f);//height +#endif return 1; } -#endif static int32_t mp4ff_read_mdhd(mp4ff_t *f) { @@ -649,6 +664,129 @@ static int32_t mp4ff_read_meta(mp4ff_t *f, const uint64_t size) } #endif +static int32_t mp4ff_read_chpl(mp4ff_t *f, const uint64_t size) +{ + int i; + int i_read = size; + + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + + mp4ff_chapterdata_t *p_chpl = &f->chapters; + + p_chpl->i_chapter = mp4ff_read_char (f); + i_read -= 5; + + for( i = 0; i < p_chpl->i_chapter; i++ ) + { + uint64_t i_start; + uint8_t i_len; + int i_copy; + i_start = mp4ff_read_int64 (f); + i_read -= 8; + i_len = mp4ff_read_char (f); + i_read -= 1; + + p_chpl->chapter[i].psz_name = malloc( i_len + 1 ); + if( !p_chpl->chapter[i].psz_name ) + goto error; + + i_copy = i_len < i_read ? i_len : i_read; + if( i_copy > 0 ) + mp4ff_read_data (f, p_chpl->chapter[i].psz_name, i_copy); + p_chpl->chapter[i].psz_name[i_copy] = '\0'; + p_chpl->chapter[i].i_start = i_start; + + i_read -= i_copy; + } + /* Bubble sort by increasing start date */ + do + { + for( i = 0; i < p_chpl->i_chapter - 1; i++ ) + { + if( p_chpl->chapter[i].i_start > p_chpl->chapter[i+1].i_start ) + { + char *psz = p_chpl->chapter[i+1].psz_name; + int64_t i64 = p_chpl->chapter[i+1].i_start; + + p_chpl->chapter[i+1].psz_name = p_chpl->chapter[i].psz_name; + p_chpl->chapter[i+1].i_start = p_chpl->chapter[i].i_start; + + p_chpl->chapter[i].psz_name = psz; + p_chpl->chapter[i].i_start = i64; + + i = -1; + break; + } + } + } while( i == -1 ); + + return 0; + +error: + return -1; +} + +int32_t mp4ff_chapters_get_num_items (mp4ff_t *f) +{ + return f->chapters.i_chapter; +} + +const char *mp4ff_chapters_get_item (mp4ff_t *f, int i) +{ + return f->chapters.chapter[i].psz_name; +} + +void mp4ff_chapters_free (mp4ff_t *f) +{ + int i; + for (i = 0; i < f->chapters.i_chapter; i++) + { + free (f->chapters.chapter[i].psz_name); + f->chapters.chapter[i].psz_name = NULL; + } +} + +static int32_t mp4ff_read_tref(mp4ff_t *f, const uint64_t size) +{ + int i; + + mp4ff_trefdata_t *p_tref = &f->tref; + + p_tref->i_track_ID = NULL; + p_tref->i_entry_count = (size-8)/ sizeof(uint32_t); + if( p_tref->i_entry_count > 0 ) { + p_tref->i_track_ID = calloc( p_tref->i_entry_count, sizeof(uint32_t) ); + } + if( p_tref->i_track_ID == NULL ) + return -1; + + for( i = 0; i < p_tref->i_entry_count; i++ ) + { + p_tref->i_track_ID[i] = mp4ff_read_int32 (f); + } + + return 0; +} + +void mp4ff_tref_free (mp4ff_t *f) +{ + if (f->tref.i_track_ID) { + free (f->tref.i_track_ID); + f->tref.i_track_ID = NULL; + } +} + +int32_t mp4ff_chap_get_num_tracks (mp4ff_t *f) +{ + return f->tref.i_entry_count; +} + +int32_t mp4ff_chap_get_track_id (mp4ff_t *f, int t) +{ + return f->tref.i_track_ID[t]; +} + 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; @@ -682,6 +820,12 @@ int32_t mp4ff_atom_read(mp4ff_t *f, const int32_t size, const uint8_t atom_type) /* iTunes Metadata box */ mp4ff_read_meta(f, size); #endif + } else if (atom_type == ATOM_CHPL) { + mp4ff_read_chpl(f, size); + } else if (atom_type == ATOM_CHAP) { + mp4ff_read_tref(f, size); + } else if (atom_type == ATOM_TKHD) { + mp4ff_read_tkhd(f); } mp4ff_set_position(f, dest_position); diff --git a/plugins/libmp4ff/mp4ff.c b/plugins/libmp4ff/mp4ff.c index ce33aad5..311746f2 100644 --- a/plugins/libmp4ff/mp4ff.c +++ b/plugins/libmp4ff/mp4ff.c @@ -99,6 +99,9 @@ void mp4ff_close(mp4ff_t *ff) mp4ff_tag_delete(&(ff->tags)); #endif + mp4ff_chapters_free (ff); + mp4ff_tref_free (ff); + if (ff) free(ff); } @@ -255,6 +258,11 @@ int32_t mp4ff_get_track_type(const mp4ff_t *f, const int track) return f->track[track]->type; } +int32_t mp4ff_get_track_id(const mp4ff_t *f, const int track) +{ + return f->track[track]->id; +} + int32_t mp4ff_total_tracks(const mp4ff_t *f) { return f->total_tracks; @@ -428,7 +436,7 @@ int32_t mp4ff_read_sample(mp4ff_t *f, const int32_t track, const int32_t sample, *audio_buffer = (uint8_t*)malloc(*bytes); if (!(*audio_buffer)) { - fprintf (stderr, "mp4ff_read_sample: malloc failure (tried to alloc %d bytes). possible mp4ff bug or memleak! please report a bug to deadbeef developers (i'm serious).\n", *bytes); + //fprintf (stderr, "mp4ff_read_sample: malloc failure (tried to alloc %d bytes). possible mp4ff bug or memleak! please report a bug to deadbeef developers (i'm serious).\n", *bytes); return 0; } diff --git a/plugins/libmp4ff/mp4ff.h b/plugins/libmp4ff/mp4ff.h index f8828f4f..0b2ac985 100644 --- a/plugins/libmp4ff/mp4ff.h +++ b/plugins/libmp4ff/mp4ff.h @@ -40,20 +40,7 @@ extern "C" { #else #include "mp4ff_int_types.h" #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; - -/* mp4 main file structure */ -typedef void* mp4ff_t; - +#include "mp4ffint.h" /* API */ @@ -78,6 +65,9 @@ int32_t mp4ff_read_sample_getsize(mp4ff_t *f, const int track, const int sample) int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int track, unsigned char** ppBuf, unsigned int* pBufSize); int32_t mp4ff_get_track_type(const mp4ff_t *f, const int track); +int32_t mp4ff_get_track_id(const mp4ff_t *f, const int track); +int32_t mp4ff_get_track_fmt_cat(const mp4ff_t *f, const int track); +int32_t mp4ff_get_track_fmt_codec(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); @@ -113,19 +103,10 @@ int mp4ff_meta_get_tempo(const mp4ff_t *f, char **value); int32_t mp4ff_meta_get_coverart(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_chapters_get_num_items (mp4ff_t *f); +const char *mp4ff_chapters_get_item (mp4ff_t *f, int i); +int32_t mp4ff_chap_get_num_tracks (mp4ff_t *f); +int32_t mp4ff_chap_get_track_id (mp4ff_t *f, int t); int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data); diff --git a/plugins/libmp4ff/mp4ffint.h b/plugins/libmp4ff/mp4ffint.h index ec0b51bb..bfe157a6 100644 --- a/plugins/libmp4ff/mp4ffint.h +++ b/plugins/libmp4ff/mp4ffint.h @@ -43,7 +43,9 @@ extern "C" { #define TRACK_AUDIO 1 #define TRACK_VIDEO 2 #define TRACK_SYSTEM 3 +#define TRACK_TEXT 4 +#define ATOM_TREF 100 #define SUBATOMIC 128 @@ -52,7 +54,6 @@ extern "C" { #define ATOM_MDAT 130 #define ATOM_MVHD 131 #define ATOM_TKHD 132 -#define ATOM_TREF 133 #define ATOM_MDHD 134 #define ATOM_VMHD 135 #define ATOM_SMHD 136 @@ -76,6 +77,7 @@ extern "C" { #define ATOM_PRIV 154 #define ATOM_USER 155 #define ATOM_KEY 156 +#define ATOM_TEXT 157 #define ATOM_ALBUM_ARTIST 157 #define ATOM_CONTENTGROUP 158 @@ -94,6 +96,8 @@ extern "C" { #define ATOM_EPISODE 171 #define ATOM_PODCAST 172 #define ATOM_CUSTOM 173 +#define ATOM_CHPL 174 +#define ATOM_CHAP 175 #define ATOM_UNKNOWN 255 #define ATOM_FREE ATOM_UNKNOWN @@ -166,6 +170,7 @@ typedef struct typedef struct { int32_t type; + int32_t id; int32_t channelCount; int32_t sampleSize; uint16_t sampleRate; @@ -211,6 +216,22 @@ typedef struct } mp4ff_track_t; +typedef struct +{ + uint8_t i_chapter; + struct + { + char *psz_name; + int64_t i_start; + } chapter[256]; +} mp4ff_chapterdata_t; + +typedef struct +{ + uint32_t i_entry_count; + uint32_t *i_track_ID; +} mp4ff_trefdata_t; + /* mp4 main file structure */ typedef struct { @@ -236,6 +257,10 @@ typedef struct /* metadata */ mp4ff_metadata_t tags; + + /* chapters */ + mp4ff_chapterdata_t chapters; + mp4ff_trefdata_t tref; } mp4ff_t; @@ -337,6 +362,8 @@ 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 +void mp4ff_chapters_free (mp4ff_t *f); +void mp4ff_tref_free (mp4ff_t *f); #ifdef __cplusplus } -- cgit v1.2.3