Commit adeb9071 authored by Baptiste Coudurier's avatar Baptiste Coudurier

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
parent b154ed5a
......@@ -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 {
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment