summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libavformat/isom.h4
-rw-r--r--libavformat/mov.c98
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);