summaryrefslogtreecommitdiff
path: root/libavformat
diff options
context:
space:
mode:
authorBaptiste Coudurier <baptiste.coudurier@gmail.com>2009-11-15 03:26:47 +0000
committerBaptiste Coudurier <baptiste.coudurier@gmail.com>2009-11-15 03:26:47 +0000
commitadeb907137439b35704de4cb51e51b09599ef267 (patch)
tree73969b5d881f5599d8c7659fe422fe6b35bb82f3 /libavformat
parentb154ed5abe137a54715ddd15dcc658bf04b16557 (diff)
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
Diffstat (limited to 'libavformat')
-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);