-
Notifications
You must be signed in to change notification settings - Fork 3.1k
[RFC] Add subrandr SRV3 and WebVTT subtitle renderer #16271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
6129418
7f2ac0a
b2ff81b
42bb934
3a33110
a79c0dd
1241eee
58bb4b9
c92a4dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
/* | ||
* This file is part of mpv. | ||
* | ||
* mpv is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 2.1 of the License, or (at your option) any later version. | ||
* | ||
* mpv is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with mpv. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
// This demuxer is specific to the `sd_sbr` subtitle driver and exists | ||
// so that we can take subtitle files like .srv3 or .vtt in their | ||
// full text form and pass them to subrandr in the subtitle driver. | ||
// | ||
// There are two reasons for this: | ||
// - subrandr doesn't currently support parsing packetized streams like | ||
// what is output by ffmpeg for WebVTT. | ||
// - Demuxing .srv3 is not supported by ffmpeg, it also doesn't really have | ||
// a standard packetized representation that ffmpeg could demux it to | ||
// (that I know of). | ||
// | ||
// Note that for now this demuxer only recognizes srv3, this is to avoid | ||
// regressing the behavior of other formats that were previously rendered | ||
// with libass via ffmpeg conversion. | ||
|
||
#include <limits.h> | ||
#include <math.h> | ||
|
||
#include <subrandr/subrandr.h> | ||
|
||
#include "common/common.h" | ||
#include "demux/packet.h" | ||
#include "misc/bstr.h" | ||
#include "options/m_config.h" | ||
#include "options/m_option.h" | ||
#include "stream/stream.h" | ||
#include "demux.h" | ||
|
||
#define OPT_BASE_STRUCT struct demux_sbr_opts | ||
struct demux_sbr_opts { | ||
int probesize; | ||
}; | ||
|
||
const struct m_sub_options demux_sbr_conf = { | ||
.opts = (const m_option_t[]) { | ||
{"probesize", OPT_INT(probesize), M_RANGE(32, INT_MAX)}, | ||
{0} | ||
}, | ||
.size = sizeof(struct demux_sbr_opts), | ||
.defaults = &(const struct demux_sbr_opts){ | ||
.probesize = 128, | ||
}, | ||
.change_flags = UPDATE_DEMUXER, | ||
}; | ||
|
||
struct format_codec_info { | ||
const char *codec; | ||
const char *codec_desc; | ||
}; | ||
|
||
static const struct format_codec_info fmt_to_codec[] = { | ||
[SBR_SUBTITLE_FORMAT_UNKNOWN] = {NULL, NULL}, | ||
[SBR_SUBTITLE_FORMAT_SRV3 ] = {"subrandr/srv3", "srv3"}, | ||
}; | ||
|
||
struct sub_codec_ext { | ||
const char *ext; | ||
struct format_codec_info codec_info; | ||
}; | ||
|
||
static const struct sub_codec_ext codec_exts[] = { | ||
{".srv3", fmt_to_codec[SBR_SUBTITLE_FORMAT_SRV3]}, | ||
{".ytt", fmt_to_codec[SBR_SUBTITLE_FORMAT_SRV3]}, | ||
{NULL} | ||
}; | ||
|
||
struct demux_sbr_priv { | ||
bstr content; | ||
bool exhausted; | ||
}; | ||
|
||
static int demux_open_sbr(struct demuxer *demuxer, enum demux_check check) | ||
{ | ||
bstr filename = bstr0(demuxer->filename); | ||
struct format_codec_info codec_info = {0}; | ||
struct demux_sbr_opts *opts = mp_get_config_group(demuxer, demuxer->global, &demux_sbr_conf); | ||
|
||
for (const struct sub_codec_ext *ext = codec_exts; ext->ext; ++ext) { | ||
if (bstr_endswith0(filename, ext->ext)) | ||
codec_info = ext->codec_info; | ||
} | ||
|
||
if (!codec_info.codec) { | ||
int probe_size = stream_peek(demuxer->stream, opts->probesize); | ||
uint8_t *probe_buffer = demuxer->stream->buffer; | ||
|
||
sbr_subtitle_format fmt = sbr_probe_text((const char *)probe_buffer, (size_t)probe_size); | ||
if (fmt < MP_ARRAY_SIZE(fmt_to_codec)) | ||
codec_info = fmt_to_codec[fmt]; | ||
} | ||
|
||
if (check != DEMUX_CHECK_REQUEST && !codec_info.codec) | ||
return -1; | ||
|
||
struct demux_sbr_priv *priv = talloc_zero(demuxer, struct demux_sbr_priv); | ||
|
||
priv->content = stream_read_complete(demuxer->stream, priv, 64 * 1024 * 1024); | ||
if (priv->content.start == NULL) | ||
return -1; | ||
demuxer->priv = priv; | ||
|
||
struct sh_stream *stream = demux_alloc_sh_stream(STREAM_SUB); | ||
stream->codec->codec = codec_info.codec; | ||
stream->codec->codec_desc = codec_info.codec_desc; | ||
demux_add_sh_stream(demuxer, stream); | ||
|
||
// Note that while in practice seeking on this stream is not possible, | ||
// if `demuxer->seekable` is `false` then a warning is emitted when one | ||
// tries to seek in the player which is undesirable. Therefore we mark | ||
// it as seekable and make seeking a no-op instead. | ||
demuxer->seekable = true; | ||
demuxer->fully_read = true; | ||
demux_close_stream(demuxer); | ||
|
||
return 0; | ||
} | ||
|
||
static bool demux_read_packet_sbr(struct demuxer *demuxer, struct demux_packet **packet) | ||
{ | ||
struct demux_sbr_priv *priv = demuxer->priv; | ||
|
||
if (priv->exhausted) | ||
return false; | ||
|
||
*packet = new_demux_packet_from(demuxer->packet_pool, priv->content.start, priv->content.len); | ||
if (!*packet) | ||
return true; | ||
|
||
(*packet)->stream = 0; | ||
(*packet)->pts = 0.0; | ||
(*packet)->sub_duration = INFINITY; | ||
priv->exhausted = true; | ||
|
||
return true; | ||
} | ||
|
||
static void demux_seek_sbr(struct demuxer *demuxer, double seek_pts, int flags) | ||
{ | ||
// We only ever emit one packet, no seeking needed or possible. | ||
} | ||
|
||
static void demux_switched_tracks_sbr(struct demuxer *demuxer) | ||
{ | ||
struct demux_sbr_priv *ctx = demuxer->priv; | ||
ctx->exhausted = false; | ||
} | ||
|
||
|
||
const struct demuxer_desc demuxer_desc_sbr = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would be nice to document the reason why this demuxer exists in a short comment in this file or so. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note that I did this with the earlier push at the top of the file, was that fine or do I need to change anything? |
||
.name = "subrandr", | ||
.desc = "subrandr text subtitle demuxer", | ||
.open = demux_open_sbr, | ||
.read_packet = demux_read_packet_sbr, | ||
.seek = demux_seek_sbr, | ||
.switched_tracks = demux_switched_tracks_sbr | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so this should be false according to the comment in
demux_seek_sbr
?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #16271 (comment). Should I add a comment here explaining why this is done this way or is there a way to avoid that warning?
Specifically this warning:
mpv/demux/demux.c
Lines 3842 to 3845 in b9ceaf2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a short comment please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already extended the comment in
demux_seek_sbr
to mention this, but I can move it here if that's what you want.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should be next to the relevant thing IMO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved and slightly changed the comment
can you chime in on #16271 (comment) and let me know what the preferred approach would be?