|
|
|
@ -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_tag(s, &tags[i].sub, metadata, key); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (tags[i].sub.nb_elem) |
|
|
|
|
matroska_convert_tags(s, &tags[i].sub); |
|
|
|
|
|
|
|
|
|
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; j<matroska->attachments.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; j<matroska->chapters.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; j<matroska->tracks.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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|