summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2009-01-04 18:48:37 +0000
committerMichael Niedermayer <michaelni@gmx.at>2009-01-04 18:48:37 +0000
commit47146dfbf6bca94dd0706b4313cc5e26edaf18d4 (patch)
treeba7242f58b79aadcd06267356a5fdc5b08e17130
parent045cbba92dad0728d9c277a6588a6c3e114f3917 (diff)
Generic metadata API.
avi is updated as example. No version bump, the API still might change slightly ... No update to ffmpeg.c as requested by aurel. Originally committed as revision 16424 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r--libavcodec/Makefile1
-rw-r--r--libavcodec/avcodec.h45
-rw-r--r--libavcodec/metadata.c75
-rw-r--r--libavcodec/metadata.h38
-rw-r--r--libavformat/avformat.h2
-rw-r--r--libavformat/avidec.c26
-rw-r--r--libavformat/avienc.c27
-rw-r--r--libavformat/utils.c9
8 files changed, 200 insertions, 23 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index e4217d6af4..d7a1b4ba8e 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -14,6 +14,7 @@ OBJS = allcodecs.o \
faanidct.o \
imgconvert.o \
jrevdct.o \
+ metadata.o \
opt.o \
parser.o \
raw.o \
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index e45f7d6dfb..7038d2d2c4 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -400,6 +400,51 @@ enum SampleFormat {
*/
#define FF_MIN_BUFFER_SIZE 16384
+
+/*
+ * public Metadata API.
+ * Important concepts, to keep in mind
+ * 1. keys are unique, there are never 2 tags with equal keys, this is also
+ * meant semantically that is a demuxer should not knowingly produce
+ * several keys that are litterally different but semantically identical,
+ * like key=Author5, key=Author6.
+ * All authors have to be placed in the same tag for the case of Authors.
+ * 2. Metadata is flat, there are no subtags, if you for whatever obscene
+ * reason want to store the email address of the child of producer alice
+ * and actor bob, that could have key=alice_and_bobs_childs_email_address.
+ * 3. A tag whichs value is translated has the ISO 639 3-letter language code
+ * with a '-' between appended. So for example Author-ger=Michael, Author-eng=Mike
+ * the original/default language is in the unqualified "Author"
+ * A demuxer should set a default if it sets any translated tag.
+ */
+
+#define AV_METADATA_IGNORE_CASE 1
+#define AV_METADATA_IGNORE_SUFFIX 2
+
+typedef struct {
+ char *key;
+ char *value;
+}AVMetaDataTag;
+
+struct AVMetaData;
+
+/**
+ * gets a metadata element with matching key.
+ * @param prev set to the previous matching element to find the next.
+ * @param flags allows case as well as suffix insensitive comparissions.
+ * @return found tag or NULL, changing key or value leads to undefined behavior.
+ */
+AVMetaDataTag *
+av_metadata_get(struct AVMetaData *m, const char *key, const AVMetaDataTag *prev, int flags);
+
+/**
+ * sets the given tag in m, overwriting an existing tag.
+ * @param tag tag to add to m, key and value will be av_strduped.
+ * @return >= 0 if success otherwise error code that is <0.
+ */
+int av_metadata_set(struct AVMetaData **m, AVMetaDataTag tag);
+
+
/**
* motion estimation type.
*/
diff --git a/libavcodec/metadata.c b/libavcodec/metadata.c
new file mode 100644
index 0000000000..d223d7c0d9
--- /dev/null
+++ b/libavcodec/metadata.c
@@ -0,0 +1,75 @@
+/*
+ * copyright (c) 2009 Michael Niedermayer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "metadata.h"
+
+AVMetaDataTag *
+av_metadata_get(struct AVMetaData *m, const char *key, const AVMetaDataTag *prev, int flags)
+{
+ unsigned int i, j;
+
+ if(!m)
+ return NULL;
+
+ if(prev) i= prev - m->elems + 1;
+ else i= 0;
+
+ for(; i<m->count; i++){
+ const char *s= m->elems[i].key;
+ if(flags & AV_METADATA_IGNORE_CASE) for(j=0; toupper(s[j]) == toupper(key[j]) && key[j]; j++);
+ else for(j=0; s[j] == key[j] && key[j]; j++);
+ if(key[j])
+ continue;
+ if(s[j] && !(flags & AV_METADATA_IGNORE_SUFFIX))
+ continue;
+ return &m->elems[i];
+ }
+ return NULL;
+}
+
+int av_metadata_set(struct AVMetaData **pm, AVMetaDataTag elem)
+{
+ struct AVMetaData *m= *pm;
+ AVMetaDataTag *tag= av_metadata_get(m, elem.key, NULL, 0);
+
+ if(!m)
+ m=*pm= av_mallocz(sizeof(*m));
+
+ if(tag){
+ av_free(tag->value);
+ av_free(tag->key);
+ *tag= m->elems[--m->count];
+ }else{
+ AVMetaDataTag *tmp= av_realloc(m->elems, (m->count+1) * sizeof(*m->elems));
+ if(tmp){
+ m->elems= tmp;
+ }else
+ return AVERROR(ENOMEM);
+ }
+ if(elem.value){
+ elem.key = av_strdup(elem.key );
+ elem.value= av_strdup(elem.value);
+ m->elems[m->count++]= elem;
+ }
+ if(!m->count)
+ av_freep(pm);
+
+ return 0;
+}
diff --git a/libavcodec/metadata.h b/libavcodec/metadata.h
new file mode 100644
index 0000000000..0ab39cba26
--- /dev/null
+++ b/libavcodec/metadata.h
@@ -0,0 +1,38 @@
+/*
+ * copyright (c) 2009 Michael Niedermayer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_METADATA_H
+#define AVCODEC_METADATA_H
+
+/**
+ * @file metadata.h
+ * internal metadata API header
+ * see avcodec.h or the public API!
+ */
+
+
+#include "avcodec.h"
+
+struct AVMetaData{
+ int count;
+ AVMetaDataTag *elems;
+};
+
+#endif /* AVCODEC_METADATA_H */
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 3f4271ae5f..46e692452e 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -608,6 +608,8 @@ typedef struct AVFormatContext {
struct AVPacketList *raw_packet_buffer_end;
struct AVPacketList *packet_buffer_end;
+
+ struct AVMetaData *meta_data;
} AVFormatContext;
typedef struct AVPacketList {
diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index 83c01a9826..ebb1a4c674 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -216,13 +216,17 @@ static void clean_index(AVFormatContext *s){
}
}
-static int avi_read_tag(ByteIOContext *pb, char *buf, int maxlen, unsigned int size)
+static int avi_read_tag(AVFormatContext *s, const char *key, unsigned int size)
{
+ ByteIOContext *pb = s->pb;
+ uint8_t value[1024];
+
int64_t i = url_ftell(pb);
size += (size & 1);
- get_strz(pb, buf, maxlen);
+ get_strz(pb, value, sizeof(value));
url_fseek(pb, i+size, SEEK_SET);
- return 0;
+
+ return av_metadata_set(&s->meta_data, (const AVMetaDataTag){key, value});
}
static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
@@ -235,7 +239,6 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
int i;
AVStream *st;
AVIStream *ast = NULL;
- char str_track[4];
int avih_width=0, avih_height=0;
int amv_file_format=0;
@@ -561,26 +564,25 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
url_fseek(pb, size, SEEK_CUR);
break;
case MKTAG('I', 'N', 'A', 'M'):
- avi_read_tag(pb, s->title, sizeof(s->title), size);
+ avi_read_tag(s, "Title", size);
break;
case MKTAG('I', 'A', 'R', 'T'):
- avi_read_tag(pb, s->author, sizeof(s->author), size);
+ avi_read_tag(s, "Artist", size);
break;
case MKTAG('I', 'C', 'O', 'P'):
- avi_read_tag(pb, s->copyright, sizeof(s->copyright), size);
+ avi_read_tag(s, "Copyright", size);
break;
case MKTAG('I', 'C', 'M', 'T'):
- avi_read_tag(pb, s->comment, sizeof(s->comment), size);
+ avi_read_tag(s, "Comment", size);
break;
case MKTAG('I', 'G', 'N', 'R'):
- avi_read_tag(pb, s->genre, sizeof(s->genre), size);
+ avi_read_tag(s, "Genre", size);
break;
case MKTAG('I', 'P', 'R', 'D'):
- avi_read_tag(pb, s->album, sizeof(s->album), size);
+ avi_read_tag(s, "Album", size);
break;
case MKTAG('I', 'P', 'R', 'T'):
- avi_read_tag(pb, str_track, sizeof(str_track), size);
- sscanf(str_track, "%d", &s->track);
+ avi_read_tag(s, "Track", size);
break;
default:
if(size > 1000000){
diff --git a/libavformat/avienc.c b/libavformat/avienc.c
index a672e8d85c..4ae608f780 100644
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@ -103,6 +103,15 @@ static void avi_write_info_tag(ByteIOContext *pb, const char *tag, const char *s
}
}
+static void avi_write_info_tag2(AVFormatContext *s, const char *fourcc, const char *key1, const char *key2)
+{
+ AVMetaDataTag *tag= av_metadata_get(s->meta_data, key1, NULL, AV_METADATA_IGNORE_CASE);
+ if(!tag && key2)
+ tag= av_metadata_get(s->meta_data, key2, NULL, AV_METADATA_IGNORE_CASE);
+ if(tag)
+ avi_write_info_tag(s->pb, fourcc, tag->value);
+}
+
static int avi_write_counters(AVFormatContext* s, int riff_id)
{
ByteIOContext *pb = s->pb;
@@ -332,17 +341,13 @@ static int avi_write_header(AVFormatContext *s)
list2 = start_tag(pb, "LIST");
put_tag(pb, "INFO");
- avi_write_info_tag(pb, "INAM", s->title);
- avi_write_info_tag(pb, "IART", s->author);
- avi_write_info_tag(pb, "ICOP", s->copyright);
- avi_write_info_tag(pb, "ICMT", s->comment);
- avi_write_info_tag(pb, "IPRD", s->album);
- avi_write_info_tag(pb, "IGNR", s->genre);
- if (s->track) {
- char str_track[4];
- snprintf(str_track, 4, "%d", s->track);
- avi_write_info_tag(pb, "IPRT", str_track);
- }
+ avi_write_info_tag2(s, "INAM", "Title", NULL);
+ avi_write_info_tag2(s, "IART", "Artist", "Author");
+ avi_write_info_tag2(s, "ICOP", "Copyright", NULL);
+ avi_write_info_tag2(s, "ICMT", "Comment", NULL);
+ avi_write_info_tag2(s, "IPRD", "Album", NULL);
+ avi_write_info_tag2(s, "IGNR", "Genre", NULL);
+ avi_write_info_tag2(s, "IPRT", "Track", NULL);
if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT))
avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT);
end_tag(pb, list2);
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 80171ca903..9bee5cd7e8 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -21,6 +21,7 @@
#include "avformat.h"
#include "internal.h"
#include "libavcodec/opt.h"
+#include "libavcodec/metadata.h"
#include "libavutil/avstring.h"
#include "riff.h"
#include <sys/time.h>
@@ -2305,6 +2306,14 @@ void av_close_input_stream(AVFormatContext *s)
av_free(s->chapters[s->nb_chapters]);
}
av_freep(&s->chapters);
+ if(s->meta_data){
+ while(s->meta_data->count--){
+ av_freep(&s->meta_data->elems[s->meta_data->count].key);
+ av_freep(&s->meta_data->elems[s->meta_data->count].value);
+ }
+ av_freep(&s->meta_data->elems);
+ }
+ av_freep(&s->meta_data);
av_free(s);
}