mirror of
https://github.com/mpv-player/mpv
synced 2025-03-25 04:38:01 +00:00
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:
parent
64456488b3
commit
5824eb7107
@ -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},
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user