From adeb907137439b35704de4cb51e51b09599ef267 Mon Sep 17 00:00:00 2001 From: Baptiste Coudurier Date: Sun, 15 Nov 2009 03:26:47 +0000 Subject: [PATCH] Search relative path according to alias record when opening mov reference files. Based on patch by Maksym Veremeyenko, verem at m1stereo dot tv Originally committed as revision 20539 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/isom.h | 4 ++ libavformat/mov.c | 98 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 92 insertions(+), 10 deletions(-) diff --git a/libavformat/isom.h b/libavformat/isom.h index 7799a09257..abd5f97f56 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -56,6 +56,10 @@ typedef struct { typedef struct { uint32_t type; char *path; + char *dir; + char volume[28]; + char filename[64]; + int16_t nlvl_to, nlvl_from; } MOVDref; typedef struct { diff --git a/libavformat/mov.c b/libavformat/mov.c index 564a1144b0..6a8c14948f 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -274,18 +274,33 @@ static int mov_read_dref(MOVContext *c, ByteIOContext *pb, MOVAtom atom) if (dref->type == MKTAG('a','l','i','s') && size > 150) { /* macintosh alias record */ uint16_t volume_len, len; - char volume[28]; int16_t type; url_fskip(pb, 10); volume_len = get_byte(pb); volume_len = FFMIN(volume_len, 27); - get_buffer(pb, volume, 27); - volume[volume_len] = 0; - av_log(c->fc, AV_LOG_DEBUG, "volume %s, len %d\n", volume, volume_len); + get_buffer(pb, dref->volume, 27); + dref->volume[volume_len] = 0; + av_log(c->fc, AV_LOG_DEBUG, "volume %s, len %d\n", dref->volume, volume_len); - url_fskip(pb, 112); + url_fskip(pb, 12); + + len = get_byte(pb); + len = FFMIN(len, 63); + get_buffer(pb, dref->filename, 63); + dref->filename[len] = 0; + av_log(c->fc, AV_LOG_DEBUG, "filename %s, len %d\n", dref->filename, len); + + url_fskip(pb, 16); + + /* read next level up_from_alias/down_to_target */ + dref->nlvl_from = get_be16(pb); + dref->nlvl_to = get_be16(pb); + av_log(c->fc, AV_LOG_DEBUG, "nlvl from %d, nlvl to %d\n", + dref->nlvl_from, dref->nlvl_to); + + url_fskip(pb, 16); for (type = 0; type != -1 && url_ftell(pb) < next; ) { type = get_be16(pb); @@ -299,7 +314,7 @@ static int mov_read_dref(MOVContext *c, ByteIOContext *pb, MOVAtom atom) if (!dref->path) return AVERROR(ENOMEM); get_buffer(pb, dref->path, len); - if (len > volume_len && !strncmp(dref->path, volume, volume_len)) { + if (len > volume_len && !strncmp(dref->path, dref->volume, volume_len)) { len -= volume_len; memmove(dref->path, dref->path+volume_len, len); dref->path[len] = 0; @@ -308,6 +323,17 @@ static int mov_read_dref(MOVContext *c, ByteIOContext *pb, MOVAtom atom) if (dref->path[j] == ':') dref->path[j] = '/'; av_log(c->fc, AV_LOG_DEBUG, "path %s\n", dref->path); + } else if (type == 0) { // directory name + av_free(dref->dir); + dref->dir = av_malloc(len+1); + if (!dref->dir) + return AVERROR(ENOMEM); + get_buffer(pb, dref->dir, len); + dref->dir[len] = 0; + for (j = 0; j < len; j++) + if (dref->dir[j] == ':') + dref->dir[j] = '/'; + av_log(c->fc, AV_LOG_DEBUG, "dir %s\n", dref->dir); } else url_fskip(pb, len); } @@ -1526,6 +1552,52 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } } +static int mov_open_dref(ByteIOContext **pb, char *src, MOVDref *ref) +{ + /* try absolute path */ + if (!url_fopen(pb, ref->path, URL_RDONLY)) + return 0; + + /* try relative path */ + if (ref->nlvl_to > 0 && ref->nlvl_from > 0) { + char filename[1024]; + char *src_path; + int i, l; + + /* find a source dir */ + src_path = strrchr(src, '/'); + if (src_path) + src_path++; + else + src_path = src; + + /* find a next level down to target */ + for (i = 0, l = strlen(ref->path) - 1; l >= 0; l--) + if (ref->path[l] == '/') { + if (i == ref->nlvl_to - 1) + break; + else + i++; + } + + /* compose filename if next level down to target was found */ + if (i == ref->nlvl_to - 1) { + memcpy(filename, src, src_path - src); + filename[src_path - src] = 0; + + for (i = 1; i < ref->nlvl_from; i++) + av_strlcat(filename, "../", 1024); + + av_strlcat(filename, ref->path + l + 1, 1024); + + if (!url_fopen(pb, filename, URL_RDONLY)) + return 0; + } + } + + return AVERROR(ENOENT); +}; + static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOVAtom atom) { AVStream *st; @@ -1571,9 +1643,13 @@ static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOVAtom atom) mov_build_index(c, st); if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) { - if (url_fopen(&sc->pb, sc->drefs[sc->dref_id-1].path, URL_RDONLY) < 0) - av_log(c->fc, AV_LOG_ERROR, "stream %d, error opening file %s: %s\n", - st->index, sc->drefs[sc->dref_id-1].path, strerror(errno)); + MOVDref *dref = &sc->drefs[sc->dref_id - 1]; + if (mov_open_dref(&sc->pb, c->fc->filename, dref) < 0) + av_log(c->fc, AV_LOG_ERROR, + "stream %d, error opening alias: path='%s', dir='%s', " + "filename='%s', volume='%s', nlvl_from=%d, nlvl_to=%d\n", + st->index, dref->path, dref->dir, dref->filename, + dref->volume, dref->nlvl_from, dref->nlvl_to); } else sc->pb = c->fc->pb; @@ -2244,8 +2320,10 @@ static int mov_read_close(AVFormatContext *s) MOVStreamContext *sc = st->priv_data; av_freep(&sc->ctts_data); - for (j = 0; j < sc->drefs_count; j++) + for (j = 0; j < sc->drefs_count; j++) { av_freep(&sc->drefs[j].path); + av_freep(&sc->drefs[j].dir); + } av_freep(&sc->drefs); if (sc->pb && sc->pb != s->pb) url_fclose(sc->pb);