diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 916771dc71..24ceea2551 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -150,6 +150,8 @@ typedef struct { char *filename; char *mime; EbmlBin bin; + + AVStream *stream; } MatroskaAttachement; typedef struct { @@ -177,6 +179,19 @@ typedef struct { EbmlList sub; } MatroskaTag; +typedef struct { + char *type; + uint64_t typevalue; + uint64_t trackuid; + uint64_t chapteruid; + uint64_t attachuid; +} MatroskaTagTarget; + +typedef struct { + MatroskaTagTarget target; + EbmlList tag; +} MatroskaTags; + typedef struct { uint64_t id; uint64_t pos; @@ -409,14 +424,23 @@ static EbmlSyntax matroska_simpletag[] = { { 0 } }; +static EbmlSyntax matroska_tagtargets[] = { + { MATROSKA_ID_TAGTARGETS_TYPE, EBML_STR, 0, offsetof(MatroskaTagTarget,type) }, + { MATROSKA_ID_TAGTARGETS_TYPEVALUE, EBML_UINT, 0, offsetof(MatroskaTagTarget,typevalue), {.u=50} }, + { MATROSKA_ID_TAGTARGETS_TRACKUID, EBML_UINT, 0, offsetof(MatroskaTagTarget,trackuid) }, + { MATROSKA_ID_TAGTARGETS_CHAPTERUID,EBML_UINT, 0, offsetof(MatroskaTagTarget,chapteruid) }, + { MATROSKA_ID_TAGTARGETS_ATTACHUID, EBML_UINT, 0, offsetof(MatroskaTagTarget,attachuid) }, + { 0 } +}; + static EbmlSyntax matroska_tag[] = { - { MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), 0, {.n=matroska_simpletag} }, - { MATROSKA_ID_TAGTARGETS, EBML_NONE }, + { MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), offsetof(MatroskaTags,tag), {.n=matroska_simpletag} }, + { MATROSKA_ID_TAGTARGETS, EBML_NEST, 0, offsetof(MatroskaTags,target), {.n=matroska_tagtargets} }, { 0 } }; static EbmlSyntax matroska_tags[] = { - { MATROSKA_ID_TAG, EBML_NEST, 0, offsetof(MatroskaDemuxContext,tags), {.n=matroska_tag} }, + { MATROSKA_ID_TAG, EBML_NEST, sizeof(MatroskaTags), offsetof(MatroskaDemuxContext,tags), {.n=matroska_tag} }, { 0 } }; @@ -474,25 +498,6 @@ static EbmlSyntax matroska_clusters[] = { { 0 } }; -#define SIZE_OFF(x) sizeof(((AVFormatContext*)0)->x),offsetof(AVFormatContext,x) -const struct { - const char name[16]; - int size; - int offset; -} metadata[] = { - { "TITLE", SIZE_OFF(title) }, - { "ARTIST", SIZE_OFF(author) }, - { "WRITTEN_BY", SIZE_OFF(author) }, - { "LEAD_PERFORMER", SIZE_OFF(author) }, - { "COPYRIGHT", SIZE_OFF(copyright) }, - { "COMMENT", SIZE_OFF(comment) }, - { "ALBUM", SIZE_OFF(album) }, - { "DATE_WRITTEN", SIZE_OFF(year) }, - { "DATE_RELEASED", SIZE_OFF(year) }, - { "PART_NUMBER", SIZE_OFF(track) }, - { "GENRE", SIZE_OFF(genre) }, -}; - /* * Return: Whether we reached the end of a level in the hierarchy or not. */ @@ -977,24 +982,50 @@ static void matroska_merge_packets(AVPacket *out, AVPacket *in) av_free(in); } -static void matroska_convert_tags(AVFormatContext *s, EbmlList *list) +static void matroska_convert_tag(AVFormatContext *s, EbmlList *list, + AVMetadata **metadata, char *prefix) { MatroskaTag *tags = list->elem; - int i, j; + char key[1024]; + int i; for (i=0; i < list->nb_elem; i++) { - for (j=0; j < FF_ARRAY_ELEMS(metadata); j++){ - if (!strcmp(tags[i].name, metadata[j].name)) { - int *ptr = (int *)((char *)s + metadata[j].offset); - if (*ptr) continue; - if (metadata[j].size > sizeof(int)) - av_strlcpy((char *)ptr, tags[i].string, metadata[j].size); - else - *ptr = atoi(tags[i].string); - } - } + if (prefix) snprintf(key, sizeof(key), "%s/%s", prefix, tags[i].name); + else av_strlcpy(key, tags[i].name, sizeof(key)); + av_metadata_set(metadata, key, tags[i].string); if (tags[i].sub.nb_elem) - matroska_convert_tags(s, &tags[i].sub); + matroska_convert_tag(s, &tags[i].sub, metadata, key); + } +} + +static void matroska_convert_tags(AVFormatContext *s) +{ + MatroskaDemuxContext *matroska = s->priv_data; + MatroskaTags *tags = matroska->tags.elem; + int i, j; + + for (i=0; i < matroska->tags.nb_elem; i++) { + if (tags[i].target.attachuid) { + MatroskaAttachement *attachment = matroska->attachments.elem; + for (j=0; jattachments.nb_elem; j++) + if (attachment[j].uid == tags[i].target.attachuid) + matroska_convert_tag(s, &tags[i].tag, + &attachment[j].stream->metadata, NULL); + } else if (tags[i].target.chapteruid) { + MatroskaChapter *chapter = matroska->chapters.elem; + for (j=0; jchapters.nb_elem; j++) + if (chapter[j].uid == tags[i].target.chapteruid) + matroska_convert_tag(s, &tags[i].tag, + &chapter[j].chapter->metadata, NULL); + } else if (tags[i].target.trackuid) { + MatroskaTrack *track = matroska->tracks.elem; + for (j=0; jtracks.nb_elem; j++) + if (track[j].uid == tags[i].target.trackuid) + matroska_convert_tag(s, &tags[i].tag, + &track[j].stream->metadata, NULL); + } else { + matroska_convert_tag(s, &tags[i].tag, &s->metadata, NULL); + } } } @@ -1109,7 +1140,6 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) matroska->ctx->duration = matroska->duration * matroska->time_scale * 1000 / AV_TIME_BASE; av_metadata_set(&s->metadata, "title", matroska->title); - matroska_convert_tags(s, &matroska->tags); tracks = matroska->tracks.elem; for (i=0; i < matroska->tracks.nb_elem; i++) { @@ -1366,6 +1396,7 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) break; } } + attachements[j].stream = st; } } @@ -1403,6 +1434,8 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) } } + matroska_convert_tags(s); + return 0; }