stream_rar: treat rar files as playlists

Refactors an older hack, which for some reason used a more complicated
way. This generates the playlist representing the contents of the rar
file in demux_playlist.c. The pseudo-demuxer could easily be separate
from the the playlist parsers (and in fact there's almost no shared
code), but I don't think this obscure feature deserves a separate file.

Sample files created with:

    rar a -v20000k -m0 files.rar file1.mkv file1.mkv
This commit is contained in:
wm4 2015-02-27 19:44:39 +01:00
parent 64456488b3
commit 5824eb7107
3 changed files with 33 additions and 77 deletions

View File

@ -23,6 +23,7 @@
#include "common/playlist.h"
#include "options/path.h"
#include "stream/stream.h"
#include "stream/rar.h"
#include "demux.h"
#define PROBE_SIZE (8 * 1024)
@ -188,6 +189,29 @@ static int parse_pls(struct pl_parser *p)
return 0;
}
static int parse_rar(struct pl_parser *p)
{
if (RarProbe(p->s))
return -1;
if (p->probing)
return 0;
int count;
rar_file_t **files;
if (RarParse(p->s, &count, &files))
return -1;
char *prefix = mp_url_escape(p, p->real_stream->url, "~|");
for (int n = 0; n < count; n++) {
// stream_rar.c does the real work
playlist_add_file(p->pl,
talloc_asprintf(p, "rar://%s|%s", prefix, files[n]->name));
RarFileDelete(files[n]);
}
talloc_free(files);
return 0;
}
static int parse_txt(struct pl_parser *p)
{
if (!p->force)
@ -220,6 +244,7 @@ static const struct pl_format formats[] = {
{"mov", parse_mov_rtsptext},
{"pls", parse_pls,
MIME_TYPES("audio/x-scpls")},
{"rar", parse_rar},
{"txt", parse_txt},
};

View File

@ -74,8 +74,7 @@ extern const stream_info_t stream_info_dvdnav;
extern const stream_info_t stream_info_bdmv_dir;
extern const stream_info_t stream_info_bluray;
extern const stream_info_t stream_info_bdnav;
extern const stream_info_t stream_info_rar_filter;
extern const stream_info_t stream_info_rar_entry;
extern const stream_info_t stream_info_rar;
extern const stream_info_t stream_info_edl;
static const stream_info_t *const stream_list[] = {
@ -115,8 +114,7 @@ static const stream_info_t *const stream_list[] = {
&stream_info_null,
&stream_info_mf,
&stream_info_edl,
&stream_info_rar_filter,
&stream_info_rar_entry,
&stream_info_rar,
&stream_info_file,
NULL
};

View File

@ -43,11 +43,10 @@ This works as follows:
- stream_open() with file01.rar
- is opened as normal file (stream_file.c or others) first
- stream_info_rar_filter stream filter applies
- leads to rar_filter_open()
- the rar code in demux_playlist.c detects it
- if multi-part, opens file02.rar, file03.rar, etc. as actual streams
(recursive opening is prevented with the STREAM_NO_FILTERS flag)
- read accesses return a m3u playlist with entries like:
- it returns a playlist like this to the player:
rar://bla01.rar|subfile.mkv
(one such entry for each file contained in the rar)
- stream_open() with the playlist entry, e.g. rar://bla01.rar|subfile.mkv
@ -143,76 +142,10 @@ static int rar_entry_open(stream_t *stream)
return STREAM_OK;
}
static int rar_filter_fill_buffer(stream_t *s, char *buffer, int max_len)
{
struct stream *m = s->priv;
return stream_read_partial(m, buffer, max_len);
}
static int rar_filter_seek(stream_t *s, int64_t newpos)
{
struct stream *m = s->priv;
return stream_seek(m, newpos);
}
static void rar_filter_close(stream_t *s)
{
struct stream *m = s->priv;
free_stream(m);
}
static int rar_filter_control(stream_t *s, int cmd, void *arg)
{
struct stream *m = s->priv;
return stream_control(m, cmd, arg);
}
static int rar_filter_open(stream_t *stream)
{
struct stream *rar = stream->source;
if (!rar)
return STREAM_UNSUPPORTED;
int count;
rar_file_t **files;
if (!rar || RarProbe(rar) || RarParse(rar, &count, &files))
return STREAM_UNSUPPORTED;
void *tmp = talloc_new(NULL);
// Create a playlist containing all entries of the .rar file. The URLs
// link to rar_entry_open().
char *prefix = mp_url_escape(tmp, stream->url, "~|");
char *pl = talloc_strdup(tmp, "#EXTM3U\n");
for (int n = 0; n < count; n++) {
pl = talloc_asprintf_append_buffer(pl, "rar://%s|%s\n",
prefix, files[n]->name);
RarFileDelete(files[n]);
}
talloc_free(files);
struct stream *m = open_memory_stream(pl, strlen(pl));
stream->priv = m;
stream->fill_buffer = rar_filter_fill_buffer;
stream->seek = rar_filter_seek;
stream->seekable = true;
stream->close = rar_filter_close;
stream->control = rar_filter_control;
stream->safe_origin = true;
talloc_free(tmp);
return STREAM_OK;
}
const stream_info_t stream_info_rar_entry = {
.name = "rar_entry",
const stream_info_t stream_info_rar = {
.name = "rar",
.open = rar_entry_open,
.protocols = (const char*const[]){ "rar", NULL },
};
const stream_info_t stream_info_rar_filter = {
.name = "rar_filter",
.open = rar_filter_open,
.stream_filter = true,
.is_safe = true,
.is_network = true, // safe over network
};