From b21e6b707fbc80511f4886d3b272a77b86157a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= <tomas.hardin@codemill.se> Date: Wed, 18 May 2011 13:48:39 +0200 Subject: wav: parse 'bext' metadata Signed-off-by: Anton Khirnov <anton@khirnov.net> --- doc/general.texi | 2 +- libavformat/wav.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/doc/general.texi b/doc/general.texi index 77a54a3fd0..fe314481a3 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -66,7 +66,7 @@ library: @tab Used in Z and Z95 games. @item Brute Force & Ignorance @tab @tab X @tab Used in the game Flash Traffic: City of Angels. -@item BWF @tab X @tab +@item BWF @tab X @tab X @item Interplay C93 @tab @tab X @tab Used in the game Cyberia from Interplay. @item Delphine Software International CIN @tab @tab X diff --git a/libavformat/wav.c b/libavformat/wav.c index a8312e254e..5b9f6e4480 100644 --- a/libavformat/wav.c +++ b/libavformat/wav.c @@ -23,6 +23,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" +#include "libavutil/dict.h" #include "libavutil/log.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" @@ -32,6 +34,7 @@ #include "riff.h" #include "avio.h" #include "avio_internal.h" +#include "metadata.h" typedef struct { const AVClass *class; @@ -284,6 +287,97 @@ static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream **st) return 0; } +static inline int wav_parse_bext_string(AVFormatContext *s, const char *key, + int length) +{ + char temp[257]; + int ret; + + av_assert0(length <= sizeof(temp)); + if ((ret = avio_read(s->pb, temp, length)) < 0) + return ret; + + temp[length] = 0; + + if (strlen(temp)) + return av_dict_set(&s->metadata, key, temp, 0); + + return 0; +} + +static int wav_parse_bext_tag(AVFormatContext *s, int64_t size) +{ + char temp[131], *coding_history; + int ret, x; + uint64_t time_reference; + int64_t umid_parts[8], umid_mask = 0; + + if ((ret = wav_parse_bext_string(s, "description", 256)) < 0 || + (ret = wav_parse_bext_string(s, "originator", 32)) < 0 || + (ret = wav_parse_bext_string(s, "originator_reference", 32)) < 0 || + (ret = wav_parse_bext_string(s, "origination_date", 10)) < 0 || + (ret = wav_parse_bext_string(s, "origination_time", 8)) < 0) + return ret; + + time_reference = avio_rl64(s->pb); + snprintf(temp, sizeof(temp), "%"PRIu64, time_reference); + if ((ret = av_dict_set(&s->metadata, "time_reference", temp, 0)) < 0) + return ret; + + /* check if version is >= 1, in which case an UMID may be present */ + if (avio_rl16(s->pb) >= 1) { + for (x = 0; x < 8; x++) + umid_mask |= umid_parts[x] = avio_rb64(s->pb); + + if (umid_mask) { + /* the string formatting below is per SMPTE 330M-2004 Annex C */ + if (umid_parts[4] == 0 && umid_parts[5] == 0 && umid_parts[6] == 0 && umid_parts[7] == 0) { + /* basic UMID */ + snprintf(temp, sizeof(temp), "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, + umid_parts[0], umid_parts[1], umid_parts[2], umid_parts[3]); + } else { + /* extended UMID */ + snprintf(temp, sizeof(temp), "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64 + "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, + umid_parts[0], umid_parts[1], umid_parts[2], umid_parts[3], + umid_parts[4], umid_parts[5], umid_parts[6], umid_parts[7]); + } + + if ((ret = av_dict_set(&s->metadata, "umid", temp, 0)) < 0) + return ret; + } + + avio_skip(s->pb, 190); + } else + avio_skip(s->pb, 254); + + if (size > 602) { + /* CodingHistory present */ + size -= 602; + + if (!(coding_history = av_malloc(size+1))) + return AVERROR(ENOMEM); + + if ((ret = avio_read(s->pb, coding_history, size)) < 0) + return ret; + + coding_history[size] = 0; + if ((ret = av_dict_set(&s->metadata, "coding_history", coding_history, + AV_METADATA_DONT_STRDUP_VAL)) < 0) + return ret; + } + + return 0; +} + +static const AVMetadataConv wav_metadata_conv[] = { + {"description", "comment" }, + {"originator", "encoded_by" }, + {"origination_date", "date" }, + {"origination_time", "creation_time"}, + {0}, +}; + /* wav input */ static int wav_read_header(AVFormatContext *s, AVFormatParameters *ap) @@ -369,6 +463,10 @@ static int wav_read_header(AVFormatContext *s, if (!sample_count) sample_count = avio_rl32(pb); break; + case MKTAG('b','e','x','t'): + if ((ret = wav_parse_bext_tag(s, size)) < 0) + return ret; + break; } /* seek to next tag unless we know that we'll run into EOF */ @@ -389,6 +487,9 @@ break_loop: sample_count = (data_size<<3) / (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id)); if (sample_count) st->duration = sample_count; + + ff_metadata_conv_ctx(s, NULL, wav_metadata_conv); + return 0; } -- cgit v1.2.3