From 67a4892ee3142e0dd6eacb82ee1b36c64c3ec711 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 11 Dec 2015 20:48:43 +0100 Subject: mixer: minor simplification (Why is this code so complex?) --- audio/mixer.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/audio/mixer.c b/audio/mixer.c index 26f426c2b4..3aa06f6c62 100644 --- a/audio/mixer.c +++ b/audio/mixer.c @@ -120,8 +120,11 @@ void mixer_getvolume(struct mixer *mixer, float *l, float *r) *r = mixer->vol_r; } -static void setvolume_internal(struct mixer *mixer, float l, float r) +static void setvolume_internal(struct mixer *mixer) { + float l = mixer->vol_l, r = mixer->vol_r; + if (mixer->emulate_mute && mixer->muted) + l = r = 0; if (!mixer->softvol) { MP_DBG(mixer, "Setting volume on AO.\n"); struct ao_control_vol vol = {.left = l, .right = r}; @@ -147,8 +150,8 @@ void mixer_setvolume(struct mixer *mixer, float l, float r) float max = mixer_getmaxvolume(mixer); mixer->vol_l = MPCLAMP(l, 0, max); mixer->vol_r = MPCLAMP(r, 0, max); - if (mixer->ao && !(mixer->emulate_mute && mixer->muted)) - setvolume_internal(mixer, mixer->vol_l, mixer->vol_r); + if (mixer->ao) + setvolume_internal(mixer); } void mixer_getbothvolume(struct mixer *mixer, float *b) @@ -167,7 +170,7 @@ void mixer_setmute(struct mixer *mixer, bool mute) mixer->muted = mute; mixer->muted_by_us = mute; if (mixer->emulate_mute) { - setvolume_internal(mixer, mixer->vol_l*!mute, mixer->vol_r*!mute); + setvolume_internal(mixer); } else { ao_control(mixer->ao, AOCONTROL_SET_MUTE, &mute); } -- cgit v1.2.3 From 000285ee8e077f5b0cd391ffc30cc71e5a3c728d Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 11 Dec 2015 20:51:32 +0100 Subject: mixer: fix volume initialization with --af=volume A manually added af_volume could lead to muted audio when switching to a new file. af_volume keeps the last volume set by AF_CONTROL_SET_VOLUME to return it with AF_CONTROL_GET_VOLUME, but the initial value is 0. So the mixer volume was forced to 0 when unintializing the filter chain and reading back the previously set volume. --- audio/mixer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/audio/mixer.c b/audio/mixer.c index 3aa06f6c62..deeea1b3e5 100644 --- a/audio/mixer.c +++ b/audio/mixer.c @@ -296,6 +296,8 @@ static void restore_volume(struct mixer *mixer) const char *prev_driver = mixer->driver; mixer->driver = mixer->softvol ? "softvol" : ao_get_name(ao); + if (!prev_driver[0]) + prev_driver = mixer->driver; // Restore old parameters if volume won't survive reinitialization. // But not if volume scale is possibly different. -- cgit v1.2.3 From f24ba544cd03261f25dab8ab564d832c28233079 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 12 Dec 2015 14:47:30 +0100 Subject: vo_opengl: enable brightness/contrast controls for RGB Why not. Also, instead of disabling hue/saturation for RGB, just don't apply them. (They don't make sense for conversion matrixes other than YUV, but I can't be bothered to keep the fine-grained disabling of UI controls either.) --- video/csputils.c | 21 +++++++++++++-------- video/out/opengl/video.c | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/video/csputils.c b/video/csputils.c index fb9d971517..d6e80e0c16 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -652,14 +652,19 @@ void mp_get_csp_matrix(struct mp_csp_params *params, struct mp_cmat *m) abort(); }; - // Hue is equivalent to rotating input [U, V] subvector around the origin. - // Saturation scales [U, V]. - float huecos = params->gray ? 0 : params->saturation * cos(params->hue); - float huesin = params->gray ? 0 : params->saturation * sin(params->hue); - for (int i = 0; i < 3; i++) { - float u = m->m[i][1], v = m->m[i][2]; - m->m[i][1] = huecos * u - huesin * v; - m->m[i][2] = huesin * u + huecos * v; + if ((colorspace == MP_CSP_BT_601 || colorspace == MP_CSP_BT_709 || + colorspace == MP_CSP_SMPTE_240M || colorspace == MP_CSP_BT_2020_NC) + && !params->gray) + { + // Hue is equivalent to rotating input [U, V] subvector around the origin. + // Saturation scales [U, V]. + float huecos = params->saturation * cos(params->hue); + float huesin = params->saturation * sin(params->hue); + for (int i = 0; i < 3; i++) { + float u = m->m[i][1], v = m->m[i][2]; + m->m[i][1] = huecos * u - huesin * v; + m->m[i][2] = huesin * u + huecos * v; + } } // The values below are written in 0-255 scale - thus bring s into range. diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index ff4c7a25aa..d2fb4ac38c 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -753,7 +753,7 @@ static void init_video(struct gl_video *p) mp_image_params_guess_csp(&p->image_params); int eq_caps = MP_CSP_EQ_CAPS_GAMMA; - if (p->is_yuv && p->image_params.colorspace != MP_CSP_BT_2020_C) + if (p->image_params.colorspace != MP_CSP_BT_2020_C) eq_caps |= MP_CSP_EQ_CAPS_COLORMATRIX; if (p->image_desc.flags & MP_IMGFLAG_XYZ) eq_caps |= MP_CSP_EQ_CAPS_BRIGHTNESS; -- cgit v1.2.3 From 8d0a6cd03560ed8d20efb57c5e38a980380a1a1e Mon Sep 17 00:00:00 2001 From: James Ross-Gowan Date: Mon, 14 Dec 2015 00:45:49 +1100 Subject: vo_opengl: dxinterop: prevent crash with 0-size window Direct3D doesn't like 0-sized swapchain dimensions, even when those dimensions are automatically set. Manually set them to a size that isn't zero instead. --- video/out/opengl/dxinterop.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/video/out/opengl/dxinterop.c b/video/out/opengl/dxinterop.c index 04518714d1..bfbde88182 100644 --- a/video/out/opengl/dxinterop.c +++ b/video/out/opengl/dxinterop.c @@ -366,6 +366,8 @@ static void fill_presentparams(MPGLContext *ctx, D3DPRESENT_PARAMETERS *pparams) *pparams = (D3DPRESENT_PARAMETERS) { .Windowed = TRUE, + .BackBufferWidth = ctx->vo->dwidth ? ctx->vo->dwidth : 1, + .BackBufferHeight = ctx->vo->dheight ? ctx->vo->dheight : 1, // The length of the backbuffer queue shouldn't affect latency because // swap_buffers() always uses the backbuffer at the head of the queue // and presents it immediately. MSDN says there is a performance @@ -374,8 +376,7 @@ static void fill_presentparams(MPGLContext *ctx, D3DPRESENT_PARAMETERS *pparams) // very high CPU usage. Use six to be safe. .BackBufferCount = 6, .SwapEffect = D3DSWAPEFFECT_FLIPEX, - // Automatically get the backbuffer format from the display format. The - // size of the backbuffer is automatically determined too. + // Automatically get the backbuffer format from the display format .BackBufferFormat = D3DFMT_UNKNOWN, .PresentationInterval = presentation_interval, .hDeviceWindow = vo_w32_hwnd(ctx->vo), -- cgit v1.2.3 From d0fd68f6dfeac03d07a005f230cdec0756636075 Mon Sep 17 00:00:00 2001 From: James Ross-Gowan Date: Mon, 14 Dec 2015 00:54:57 +1100 Subject: vo_opengl: dxinterop: prevent crash after lost device When a Direct3D 9Ex device fails to reset, it gets put into the lost state, so set the lost_device flag and don't attempt to present until the device moves out of that state. Failure to recreate the size- dependent objects should set lost_device as well, since we shouldn't try to present in that state. Also, it looks like I was too eager to remove code that sets priv members to NULL and I accidentally removed some that was needed. --- video/out/opengl/dxinterop.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/video/out/opengl/dxinterop.c b/video/out/opengl/dxinterop.c index bfbde88182..bc302629aa 100644 --- a/video/out/opengl/dxinterop.c +++ b/video/out/opengl/dxinterop.c @@ -341,14 +341,19 @@ static void d3d_size_dependent_destroy(MPGLContext *ctx) gl->DXUnlockObjectsNV(p->device_h, 1, &p->rtarget_h); gl->DXUnregisterObjectNV(p->device_h, p->rtarget_h); } + p->rtarget_h = 0; if (p->texture) gl->DeleteTextures(1, &p->texture); + p->texture = 0; if (p->rtarget) IDirect3DSurface9_Release(p->rtarget); + p->rtarget = NULL; if (p->backbuffer) IDirect3DSurface9_Release(p->backbuffer); + p->backbuffer = NULL; if (p->swapchain) IDirect3DSwapChain9Ex_Release(p->swapchain); + p->swapchain = NULL; } static void fill_presentparams(MPGLContext *ctx, D3DPRESENT_PARAMETERS *pparams) @@ -500,11 +505,13 @@ static void dxinterop_reset(struct MPGLContext *ctx) hr = IDirect3DDevice9Ex_ResetEx(p->device, &pparams, NULL); if (FAILED(hr)) { + p->lost_device = true; MP_FATAL(ctx->vo, "Couldn't reset device\n"); return; } if (d3d_size_dependent_create(ctx) < 0) { + p->lost_device = true; MP_FATAL(ctx->vo, "Couldn't recreate Direct3D objects after reset\n"); return; } @@ -585,6 +592,12 @@ static void dxinterop_swap_buffers(MPGLContext *ctx) pump_message_loop(); + // If the device is still lost, try to reset it again + if (p->lost_device) + dxinterop_reset(ctx); + if (p->lost_device) + return; + if (!gl->DXUnlockObjectsNV(p->device_h, 1, &p->rtarget_h)) { MP_FATAL(ctx->vo, "Couldn't unlock rendertarget for present\n"); return; -- cgit v1.2.3 From 29226e6a994e829c637f04cfd7f3574f0699885c Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 15 Dec 2015 21:03:34 +0100 Subject: sub: remove sd_movtext.c libavcodec's movtext-to-ass converter does the same and has more features. On Libav, this commit disables mp4 subtitle display. --- TOOLS/old-makefile | 1 - demux/demux_lavf.c | 16 ++++++++++++---- sub/dec_sub.c | 8 +------- sub/sd_movtext.c | 56 ------------------------------------------------------ wscript_build.py | 1 - 5 files changed, 13 insertions(+), 69 deletions(-) delete mode 100644 sub/sd_movtext.c diff --git a/TOOLS/old-makefile b/TOOLS/old-makefile index c1b5079973..cf51483dd5 100644 --- a/TOOLS/old-makefile +++ b/TOOLS/old-makefile @@ -226,7 +226,6 @@ SOURCES = audio/audio.c \ sub/sd_lavc_conv.c \ sub/sd_lavf_srt.c \ sub/sd_microdvd.c \ - sub/sd_movtext.c \ sub/sd_srt.c \ ta/ta.c \ ta/ta_utils.c \ diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 2d12f5cfa2..9aa71fcaf1 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -109,6 +109,7 @@ struct format_hack { bool use_stream_ids : 1; // export the native stream IDs bool fully_read : 1; // set demuxer.fully_read flag bool image_format : 1; // expected to contain exactly 1 frame + bool utf8_subs : 1; // subtitles are (mostly) guaranteed UTF-8 // Do not confuse player's position estimation (position is into external // segment, with e.g. HLS, player knows about the playlist main file only). bool clear_filepos : 1; @@ -116,6 +117,7 @@ struct format_hack { #define BLACKLIST(fmt) {fmt, .ignore = true} #define TEXTSUB(fmt) {fmt, .fully_read = true} +#define TEXTSUB_UTF8(fmt) {fmt, .fully_read = true, .utf8_subs = true} #define IMAGEFMT(fmt) {fmt, .image_format = true} static const struct format_hack format_hacks[] = { @@ -135,10 +137,17 @@ static const struct format_hack format_hacks[] = { {"h264", .if_flags = AVFMT_NOTIMESTAMPS }, {"hevc", .if_flags = AVFMT_NOTIMESTAMPS }, - TEXTSUB("aqtitle"), TEXTSUB("ass"), TEXTSUB("jacosub"), TEXTSUB("microdvd"), + TEXTSUB("aqtitle"), TEXTSUB("jacosub"), TEXTSUB("microdvd"), TEXTSUB("mpl2"), TEXTSUB("mpsub"), TEXTSUB("pjs"), TEXTSUB("realtext"), TEXTSUB("sami"), TEXTSUB("srt"), TEXTSUB("stl"), TEXTSUB("subviewer"), - TEXTSUB("subviewer1"), TEXTSUB("vplayer"), TEXTSUB("webvtt"), + TEXTSUB("subviewer1"), TEXTSUB("vplayer"), + + TEXTSUB_UTF8("webvtt"), + TEXTSUB_UTF8("ass"), + + // Formats which support muxed subtitles, and always use UTF-8 for them. + {"mov", .utf8_subs = true}, + {"mkv", .utf8_subs = true}, // Useless non-sense, sometimes breaks MLP2 subreader.c fallback BLACKLIST("tty"), @@ -613,8 +622,7 @@ static void handle_stream(demuxer_t *demuxer, int i) } } - if (matches_avinputformat_name(priv, "ass")) - sh_sub->is_utf8 = true; + sh_sub->is_utf8 = priv->format_hack.utf8_subs; break; } diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 44c1d0a8a7..dffec03983 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -34,7 +34,6 @@ extern const struct sd_functions sd_ass; extern const struct sd_functions sd_lavc; -extern const struct sd_functions sd_movtext; extern const struct sd_functions sd_srt; extern const struct sd_functions sd_microdvd; extern const struct sd_functions sd_lavf_srt; @@ -45,7 +44,6 @@ static const struct sd_functions *const sd_list[] = { &sd_ass, #endif &sd_lavc, - &sd_movtext, &sd_srt, &sd_lavf_srt, &sd_microdvd, @@ -391,11 +389,7 @@ bool sub_read_all_packets(struct dec_sub *sub, struct sh_stream *sh) talloc_free(pkt); } - // movtext is currently the only subtitle format that has text output, - // but binary input. Skip charset conversion (they're UTF-8 anyway). - bool binary = sub->sd[0]->driver == &sd_movtext; - - if (opts->sub_cp && !sh->sub->is_utf8 && !binary) + if (opts->sub_cp && !sh->sub->is_utf8) sub->charset = guess_sub_cp(sub->log, sub, subs, opts->sub_cp); if (sub->charset && sub->charset[0] && !mp_charset_is_utf8(sub->charset)) diff --git a/sub/sd_movtext.c b/sub/sd_movtext.c deleted file mode 100644 index 3038a4c132..0000000000 --- a/sub/sd_movtext.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include - -#include -#include - -#include "sd.h" - -static bool supports_format(const char *format) -{ - return format && strcmp(format, "mov_text") == 0; -} - -static int init(struct sd *sd) -{ - sd->output_codec = "text"; - return 0; -} - -static void decode(struct sd *sd, struct demux_packet *packet) -{ - unsigned char *data = packet->buffer; - int len = packet->len; - if (len < 2) - return; - len = FFMIN(len - 2, AV_RB16(data)); - data += 2; - if (len > 0) - sd_conv_add_packet(sd, data, len, packet->pts, packet->duration); -} - -const struct sd_functions sd_movtext = { - .name = "movtext", - .supports_format = supports_format, - .init = init, - .decode = decode, - .get_converted = sd_conv_def_get_converted, - .reset = sd_conv_def_reset, -}; diff --git a/wscript_build.py b/wscript_build.py index 12199f1e86..7ac33c8764 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -262,7 +262,6 @@ def build(ctx): ( "sub/sd_lavc_conv.c" ), ( "sub/sd_lavf_srt.c" ), ( "sub/sd_microdvd.c" ), - ( "sub/sd_movtext.c" ), ( "sub/sd_srt.c" ), ## Video -- cgit v1.2.3 From c7985fe5f705523fe2fd150b1c50de9185e512e6 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 15 Dec 2015 21:03:42 +0100 Subject: sub: remove sd_lavf_srt.c This restored timestamps when demuxing srt subtitles in Libav, which was important for avoiding slightly overlapping subtitles. Since the way this works was changed, there is no real reason to maintain proper timestamps anymore on this level - this can be dropped without issues. --- TOOLS/old-makefile | 1 - sub/dec_sub.c | 2 -- sub/sd_lavf_srt.c | 94 ------------------------------------------------------ wscript_build.py | 1 - 4 files changed, 98 deletions(-) delete mode 100644 sub/sd_lavf_srt.c diff --git a/TOOLS/old-makefile b/TOOLS/old-makefile index cf51483dd5..3865666e02 100644 --- a/TOOLS/old-makefile +++ b/TOOLS/old-makefile @@ -224,7 +224,6 @@ SOURCES = audio/audio.c \ sub/osd.c \ sub/sd_lavc.c \ sub/sd_lavc_conv.c \ - sub/sd_lavf_srt.c \ sub/sd_microdvd.c \ sub/sd_srt.c \ ta/ta.c \ diff --git a/sub/dec_sub.c b/sub/dec_sub.c index dffec03983..3a2136f302 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -36,7 +36,6 @@ extern const struct sd_functions sd_ass; extern const struct sd_functions sd_lavc; extern const struct sd_functions sd_srt; extern const struct sd_functions sd_microdvd; -extern const struct sd_functions sd_lavf_srt; extern const struct sd_functions sd_lavc_conv; static const struct sd_functions *const sd_list[] = { @@ -45,7 +44,6 @@ static const struct sd_functions *const sd_list[] = { #endif &sd_lavc, &sd_srt, - &sd_lavf_srt, &sd_microdvd, &sd_lavc_conv, NULL diff --git a/sub/sd_lavf_srt.c b/sub/sd_lavf_srt.c deleted file mode 100644 index 8f1f7de78b..0000000000 --- a/sub/sd_lavf_srt.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file is part of mpv. - * - * SRT timestamp parsing code lifted from FFmpeg srtdec.c (LGPL). - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include -#include - -#include "misc/bstr.h" -#include "sd.h" - -/* - * Background: - * - * Libav's .srt demuxer outputs packets that contain parts of the subtitle - * event header. Also, the packet duration is not set (they don't parse it - * on the demuxer side). As a result, the srt demuxer is useless. - * - * However, we can fix it by parsing the header, which spares us from writing - * a full SRT demuxer. - * - * Newer versions of FFmpeg do not have this problem. To avoid compatibility - * problems, they changed the codec name from "srt" to "subrip". - * - * Summary: this is a hack for broken SRT stuff in Libav. - * - */ - -static bool supports_format(const char *format) -{ - return format && strcmp(format, "srt") == 0; -} - -static int init(struct sd *sd) -{ - sd->output_codec = "subrip"; - return 0; -} - -static bool parse_pts(bstr header, double *duration) -{ - char buf[200]; - snprintf(buf, sizeof(buf), "%.*s", BSTR_P(header)); - int hh1, mm1, ss1, ms1; - int hh2, mm2, ss2, ms2; - if (sscanf(buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d", - &hh1, &mm1, &ss1, &ms1, &hh2, &mm2, &ss2, &ms2) >= 8) - { - int64_t start = (hh1*3600LL + mm1*60LL + ss1) * 1000LL + ms1; - int64_t end = (hh2*3600LL + mm2*60LL + ss2) * 1000LL + ms2; - *duration = (end - start) / 1000.0; - return true; - } - return false; -} - -static void decode(struct sd *sd, struct demux_packet *packet) -{ - bstr data = {packet->buffer, packet->len}; - // Remove the broken header. It's usually on the second or first line. - bstr left = data; - while (left.len) { - bstr line = bstr_getline(left, &left); - if (parse_pts(line, &packet->duration)) { - data = left; - break; - } - } - sd_conv_add_packet(sd, data.start, data.len, packet->pts, packet->duration); -} - -const struct sd_functions sd_lavf_srt = { - .name = "lavf_srt", - .supports_format = supports_format, - .init = init, - .decode = decode, - .get_converted = sd_conv_def_get_converted, - .reset = sd_conv_def_reset, -}; diff --git a/wscript_build.py b/wscript_build.py index 7ac33c8764..148f59d5d9 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -260,7 +260,6 @@ def build(ctx): ( "sub/sd_ass.c", "libass" ), ( "sub/sd_lavc.c" ), ( "sub/sd_lavc_conv.c" ), - ( "sub/sd_lavf_srt.c" ), ( "sub/sd_microdvd.c" ), ( "sub/sd_srt.c" ), -- cgit v1.2.3 From cab942acae8772f638a0bb392a4d04ca21bea224 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 15 Dec 2015 21:04:07 +0100 Subject: sub: remove sd_microdvd.c This can be dropped for the same reasons as in the previous commits. It removes MicroDVD conversion support on Libav, although MicroDVD files couldn't be read in the first place ever since demux_subreader.c was removed. --- TOOLS/old-makefile | 1 - sub/dec_sub.c | 2 - sub/sd_microdvd.c | 344 ----------------------------------------------------- wscript_build.py | 1 - 4 files changed, 348 deletions(-) delete mode 100644 sub/sd_microdvd.c diff --git a/TOOLS/old-makefile b/TOOLS/old-makefile index 3865666e02..43b996f96f 100644 --- a/TOOLS/old-makefile +++ b/TOOLS/old-makefile @@ -224,7 +224,6 @@ SOURCES = audio/audio.c \ sub/osd.c \ sub/sd_lavc.c \ sub/sd_lavc_conv.c \ - sub/sd_microdvd.c \ sub/sd_srt.c \ ta/ta.c \ ta/ta_utils.c \ diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 3a2136f302..59e994d4f4 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -35,7 +35,6 @@ extern const struct sd_functions sd_ass; extern const struct sd_functions sd_lavc; extern const struct sd_functions sd_srt; -extern const struct sd_functions sd_microdvd; extern const struct sd_functions sd_lavc_conv; static const struct sd_functions *const sd_list[] = { @@ -44,7 +43,6 @@ static const struct sd_functions *const sd_list[] = { #endif &sd_lavc, &sd_srt, - &sd_microdvd, &sd_lavc_conv, NULL }; diff --git a/sub/sd_microdvd.c b/sub/sd_microdvd.c deleted file mode 100644 index b6e3a93091..0000000000 --- a/sub/sd_microdvd.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Subtitles converter to SSA/ASS in order to allow special formatting - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "common/msg.h" -#include "misc/bstr.h" -#include "sd.h" - -struct line { - char *buf; - int bufsize; - int len; -}; - -#ifdef __GNUC__ -static void append_text(struct line *dst, char *fmt, ...) __attribute__ ((format(printf, 2, 3))); -#endif - -static void append_text(struct line *dst, char *fmt, ...) -{ - va_list va; - va_start(va, fmt); - int ret = vsnprintf(dst->buf + dst->len, dst->bufsize - dst->len, fmt, va); - if (ret < 0) - goto out; - dst->len += ret; - if (dst->len > dst->bufsize) - dst->len = dst->bufsize; - out: - va_end(va); -} - -static int indexof(const char *s, int c) -{ - char *f = strchr(s, c); - return f ? (f - s) : -1; -} - -/* - * MicroDVD - * - * Based on the specifications found here: - * https://trac.videolan.org/vlc/ticket/1825#comment:6 - */ - -struct microdvd_tag { - char key; - int persistent; - uint32_t data1; - uint32_t data2; - struct bstr data_string; -}; - -#define MICRODVD_PERSISTENT_OFF 0 -#define MICRODVD_PERSISTENT_ON 1 -#define MICRODVD_PERSISTENT_OPENED 2 - -// Color, Font, Size, cHarset, stYle, Position, cOordinate -#define MICRODVD_TAGS "cfshyYpo" - -static void microdvd_set_tag(struct microdvd_tag *tags, struct microdvd_tag tag) -{ - int tag_index = indexof(MICRODVD_TAGS, tag.key); - - if (tag_index < 0) - return; - memcpy(&tags[tag_index], &tag, sizeof(tag)); -} - -// italic, bold, underline, strike-through -#define MICRODVD_STYLES "ibus" - -static char *microdvd_load_tags(struct microdvd_tag *tags, char *s) -{ - while (*s == '{') { - char *start = s; - char tag_char = *(s + 1); - struct microdvd_tag tag = {0}; - - if (!tag_char || *(s + 2) != ':') - break; - s += 3; - - switch (tag_char) { - - /* Style */ - case 'Y': - tag.persistent = MICRODVD_PERSISTENT_ON; - case 'y': - while (*s && *s != '}') { - int style_index = indexof(MICRODVD_STYLES, *s); - - if (style_index >= 0) - tag.data1 |= (1 << style_index); - s++; - } - if (*s != '}') - break; - /* We must distinguish persistent and non-persistent styles - * to handle this kind of style tags: {y:ib}{Y:us} */ - tag.key = tag_char; - break; - - /* Color */ - case 'C': - tag.persistent = MICRODVD_PERSISTENT_ON; - case 'c': - tag.data1 = strtol(s, &s, 16) & 0x00ffffff; - if (*s != '}') - break; - tag.key = 'c'; - break; - - /* Font name */ - case 'F': - tag.persistent = MICRODVD_PERSISTENT_ON; - case 'f': - { - int len = indexof(s, '}'); - if (len < 0) - break; - tag.data_string.start = s; - tag.data_string.len = len; - s += len; - tag.key = 'f'; - break; - } - - /* Font size */ - case 'S': - tag.persistent = MICRODVD_PERSISTENT_ON; - case 's': - tag.data1 = strtol(s, &s, 10); - if (*s != '}') - break; - tag.key = 's'; - break; - - /* Charset */ - case 'H': - { - //TODO: not yet handled, just parsed. - int len = indexof(s, '}'); - if (len < 0) - break; - tag.data_string.start = s; - tag.data_string.len = len; - s += len; - tag.key = 'h'; - break; - } - - /* Position */ - case 'P': - tag.persistent = MICRODVD_PERSISTENT_ON; - tag.data1 = (*s++ == '1'); - if (*s != '}') - break; - tag.key = 'p'; - break; - - /* Coordinates */ - case 'o': - tag.persistent = MICRODVD_PERSISTENT_ON; - tag.data1 = strtol(s, &s, 10); - if (*s != ',') - break; - s++; - tag.data2 = strtol(s, &s, 10); - if (*s != '}') - break; - tag.key = 'o'; - break; - - default: /* Unknown tag, we consider it to be text */ - break; - } - - if (tag.key == 0) - return start; - - microdvd_set_tag(tags, tag); - s++; - } - return s; -} - -static void microdvd_open_tags(struct line *new_line, struct microdvd_tag *tags) -{ - for (int i = 0; i < sizeof(MICRODVD_TAGS) - 1; i++) { - if (tags[i].persistent == MICRODVD_PERSISTENT_OPENED) - continue; - switch (tags[i].key) { - case 'Y': - case 'y': - for (int sidx = 0; sidx < sizeof(MICRODVD_STYLES) - 1; sidx++) - if (tags[i].data1 & (1 << sidx)) - append_text(new_line, "{\\%c1}", MICRODVD_STYLES[sidx]); - break; - - case 'c': - append_text(new_line, "{\\c&H%06X&}", tags[i].data1); - break; - - case 'f': - append_text(new_line, "{\\fn%.*s}", BSTR_P(tags[i].data_string)); - break; - - case 's': - append_text(new_line, "{\\fs%d}", tags[i].data1); - break; - - case 'p': - if (tags[i].data1 == 0) - append_text(new_line, "{\\an8}"); - break; - - case 'o': - append_text(new_line, "{\\pos(%d,%d)}", - tags[i].data1, tags[i].data2); - break; - } - if (tags[i].persistent == MICRODVD_PERSISTENT_ON) - tags[i].persistent = MICRODVD_PERSISTENT_OPENED; - } -} - -static void microdvd_close_no_persistent_tags(struct line *new_line, - struct microdvd_tag *tags) -{ - int i; - - for (i = sizeof(MICRODVD_TAGS) - 2; i; i--) { - if (tags[i].persistent != MICRODVD_PERSISTENT_OFF) - continue; - switch (tags[i].key) { - - case 'y': - for (int sidx = sizeof(MICRODVD_STYLES) - 2; sidx >= 0; sidx--) - if (tags[i].data1 & (1 << sidx)) - append_text(new_line, "{\\%c0}", MICRODVD_STYLES[sidx]); - break; - - case 'c': - append_text(new_line, "{\\c}"); - break; - - case 'f': - append_text(new_line, "{\\fn}"); - break; - - case 's': - append_text(new_line, "{\\fs}"); - break; - } - tags[i].key = 0; - } -} - -static void convert_microdvd(const char *orig, char *dest, int dest_buffer_size) -{ - /* line is not const to avoid warnings with strtol, etc. - * orig content won't be changed */ - char *line = (char *)orig; - struct line new_line = { - .buf = dest, - .bufsize = dest_buffer_size, - }; - struct microdvd_tag tags[sizeof(MICRODVD_TAGS) - 1] = {{0}}; - - while (*line) { - line = microdvd_load_tags(tags, line); - microdvd_open_tags(&new_line, tags); - - while (*line && *line != '|') - new_line.buf[new_line.len++] = *line++; - - if (*line == '|') { - microdvd_close_no_persistent_tags(&new_line, tags); - append_text(&new_line, "\\N"); - line++; - } - } - new_line.buf[new_line.len] = 0; -} - -static const char *const microdvd_ass_extradata = - "[Script Info]\n" - "ScriptType: v4.00+\n" - "PlayResX: 384\n" - "PlayResY: 288\n"; - -static bool supports_format(const char *format) -{ - return format && strcmp(format, "microdvd") == 0; -} - -static int init(struct sd *sd) -{ - sd->output_codec = "ass-text"; - sd->output_extradata = (char *)microdvd_ass_extradata; - sd->output_extradata_len = strlen(sd->output_extradata); - return 0; -} - -static void decode(struct sd *sd, struct demux_packet *packet) -{ - char dest[SD_MAX_LINE_LEN]; - // Assume input buffer is padded with 0 - convert_microdvd(packet->buffer, dest, sizeof(dest)); - sd_conv_add_packet(sd, dest, strlen(dest), packet->pts, packet->duration); -} - -const struct sd_functions sd_microdvd = { - .name = "microdvd", - .supports_format = supports_format, - .init = init, - .decode = decode, - .get_converted = sd_conv_def_get_converted, - .reset = sd_conv_def_reset, -}; diff --git a/wscript_build.py b/wscript_build.py index 148f59d5d9..ccc991dd16 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -260,7 +260,6 @@ def build(ctx): ( "sub/sd_ass.c", "libass" ), ( "sub/sd_lavc.c" ), ( "sub/sd_lavc_conv.c" ), - ( "sub/sd_microdvd.c" ), ( "sub/sd_srt.c" ), ## Video -- cgit v1.2.3 From e798cf1ff64527cd2ed9fc3bab8dbc2d0c7a52de Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 15 Dec 2015 21:05:09 +0100 Subject: sub: remove sd_srt.c The FFmpeg subtitle converter does the same. There used to be some deficiencies in FFmpeg's code, but it seems at least some of them have been fixed. There also used to be the timestamp issue (see previous commit messages), but this doesn't matter anymore. So no reason to keep this code - get rid of it. --- TOOLS/old-makefile | 1 - sub/dec_sub.c | 2 - sub/sd_srt.c | 477 ----------------------------------------------------- wscript_build.py | 1 - 4 files changed, 481 deletions(-) delete mode 100644 sub/sd_srt.c diff --git a/TOOLS/old-makefile b/TOOLS/old-makefile index 43b996f96f..c5bb33c0bb 100644 --- a/TOOLS/old-makefile +++ b/TOOLS/old-makefile @@ -224,7 +224,6 @@ SOURCES = audio/audio.c \ sub/osd.c \ sub/sd_lavc.c \ sub/sd_lavc_conv.c \ - sub/sd_srt.c \ ta/ta.c \ ta/ta_utils.c \ ta/ta_talloc.c \ diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 59e994d4f4..615e95e730 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -34,7 +34,6 @@ extern const struct sd_functions sd_ass; extern const struct sd_functions sd_lavc; -extern const struct sd_functions sd_srt; extern const struct sd_functions sd_lavc_conv; static const struct sd_functions *const sd_list[] = { @@ -42,7 +41,6 @@ static const struct sd_functions *const sd_list[] = { &sd_ass, #endif &sd_lavc, - &sd_srt, &sd_lavc_conv, NULL }; diff --git a/sub/sd_srt.c b/sub/sd_srt.c deleted file mode 100644 index 5c5cff52c4..0000000000 --- a/sub/sd_srt.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Subtitles converter to SSA/ASS in order to allow special formatting - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "common/common.h" -#include "common/msg.h" -#include "misc/bstr.h" -#include "misc/ctype.h" -#include "sd.h" - -struct line { - char *buf; - int bufsize; - int len; -}; - -#ifdef __GNUC__ -static void append_text(struct line *dst, char *fmt, ...) __attribute__ ((format(printf, 2, 3))); -#endif - -static void append_text(struct line *dst, char *fmt, ...) -{ - va_list va; - va_start(va, fmt); - int ret = vsnprintf(dst->buf + dst->len, dst->bufsize - dst->len, fmt, va); - if (ret < 0) - goto out; - dst->len += ret; - if (dst->len > dst->bufsize) - dst->len = dst->bufsize; - out: - va_end(va); -} - -static void append_text_n(struct line *dst, char *start, size_t length) -{ - append_text(dst, "%.*s", (int)length, start); -} - - -/* - * SubRip - * - * Support basic tags (italic, bold, underline, strike-through) - * and font tag with size, color and face attributes. - * - */ - -struct font_tag { - int size; - uint32_t color; - struct bstr face; - bool has_size : 1; - bool has_color : 1; - bool has_face : 1; -}; - -static const struct tag_conv { - char *from; - char *to; -} subrip_basic_tags[] = { - {"", "{\\i1}"}, {"", "{\\i0}"}, - {"", "{\\b1}"}, {"", "{\\b0}"}, - {"", "{\\u1}"}, {"", "{\\u0}"}, - {"", "{\\s1}"}, {"", "{\\s0}"}, - {"}", "\\}"}, - {"\r\n", "\\N"}, {"\n", "\\N"}, {"\r", "\\N"}, -}; - -static const struct { - char *s; - uint32_t v; -} subrip_web_colors[] = { - /* Named CSS3 colors in RGB format; a subset of those - at http://www.w3.org/TR/css3-color/#svg-color */ - {"aliceblue", 0xF0F8FF}, - {"antiquewhite", 0xFAEBD7}, - {"aqua", 0x00FFFF}, - {"aquamarine", 0x7FFFD4}, - {"azure", 0xF0FFFF}, - {"beige", 0xF5F5DC}, - {"bisque", 0xFFE4C4}, - {"black", 0x000000}, - {"blanchedalmond", 0xFFEBCD}, - {"blue", 0x0000FF}, - {"blueviolet", 0x8A2BE2}, - {"brown", 0xA52A2A}, - {"burlywood", 0xDEB887}, - {"cadetblue", 0x5F9EA0}, - {"chartreuse", 0x7FFF00}, - {"chocolate", 0xD2691E}, - {"coral", 0xFF7F50}, - {"cornflowerblue", 0x6495ED}, - {"cornsilk", 0xFFF8DC}, - {"crimson", 0xDC143C}, - {"cyan", 0x00FFFF}, - {"darkblue", 0x00008B}, - {"darkcyan", 0x008B8B}, - {"darkgoldenrod", 0xB8860B}, - {"darkgray", 0xA9A9A9}, - {"darkgreen", 0x006400}, - {"darkgrey", 0xA9A9A9}, - {"darkkhaki", 0xBDB76B}, - {"darkmagenta", 0x8B008B}, - {"darkolivegreen", 0x556B2F}, - {"darkorange", 0xFF8C00}, - {"darkorchid", 0x9932CC}, - {"darkred", 0x8B0000}, - {"darksalmon", 0xE9967A}, - {"darkseagreen", 0x8FBC8F}, - {"darkslateblue", 0x483D8B}, - {"darkslategray", 0x2F4F4F}, - {"darkslategrey", 0x2F4F4F}, - {"darkturquoise", 0x00CED1}, - {"darkviolet", 0x9400D3}, - {"deeppink", 0xFF1493}, - {"deepskyblue", 0x00BFFF}, - {"dimgray", 0x696969}, - {"dimgrey", 0x696969}, - {"dodgerblue", 0x1E90FF}, - {"firebrick", 0xB22222}, - {"floralwhite", 0xFFFAF0}, - {"forestgreen", 0x228B22}, - {"fuchsia", 0xFF00FF}, - {"gainsboro", 0xDCDCDC}, - {"ghostwhite", 0xF8F8FF}, - {"gold", 0xFFD700}, - {"goldenrod", 0xDAA520}, - {"gray", 0x808080}, - {"green", 0x008000}, - {"greenyellow", 0xADFF2F}, - {"grey", 0x808080}, - {"honeydew", 0xF0FFF0}, - {"hotpink", 0xFF69B4}, - {"indianred", 0xCD5C5C}, - {"indigo", 0x4B0082}, - {"ivory", 0xFFFFF0}, - {"khaki", 0xF0E68C}, - {"lavender", 0xE6E6FA}, - {"lavenderblush", 0xFFF0F5}, - {"lawngreen", 0x7CFC00}, - {"lemonchiffon", 0xFFFACD}, - {"lightblue", 0xADD8E6}, - {"lightcoral", 0xF08080}, - {"lightcyan", 0xE0FFFF}, - {"lightgoldenrodyellow", 0xFAFAD2}, - {"lightgray", 0xD3D3D3}, - {"lightgreen", 0x90EE90}, - {"lightgrey", 0xD3D3D3}, - {"lightpink", 0xFFB6C1}, - {"lightsalmon", 0xFFA07A}, - {"lightseagreen", 0x20B2AA}, - {"lightskyblue", 0x87CEFA}, - {"lightslategray", 0x778899}, - {"lightslategrey", 0x778899}, - {"lightsteelblue", 0xB0C4DE}, - {"lightyellow", 0xFFFFE0}, - {"lime", 0x00FF00}, - {"limegreen", 0x32CD32}, - {"linen", 0xFAF0E6}, - {"magenta", 0xFF00FF}, - {"maroon", 0x800000}, - {"mediumaquamarine", 0x66CDAA}, - {"mediumblue", 0x0000CD}, - {"mediumorchid", 0xBA55D3}, - {"mediumpurple", 0x9370DB}, - {"mediumseagreen", 0x3CB371}, - {"mediumslateblue", 0x7B68EE}, - {"mediumspringgreen", 0x00FA9A}, - {"mediumturquoise", 0x48D1CC}, - {"mediumvioletred", 0xC71585}, - {"midnightblue", 0x191970}, - {"mintcream", 0xF5FFFA}, - {"mistyrose", 0xFFE4E1}, - {"moccasin", 0xFFE4B5}, - {"navajowhite", 0xFFDEAD}, - {"navy", 0x000080}, - {"oldlace", 0xFDF5E6}, - {"olive", 0x808000}, - {"olivedrab", 0x6B8E23}, - {"orange", 0xFFA500}, - {"orangered", 0xFF4500}, - {"orchid", 0xDA70D6}, - {"palegoldenrod", 0xEEE8AA}, - {"palegreen", 0x98FB98}, - {"paleturquoise", 0xAFEEEE}, - {"palevioletred", 0xDB7093}, - {"papayawhip", 0xFFEFD5}, - {"peachpuff", 0xFFDAB9}, - {"peru", 0xCD853F}, - {"pink", 0xFFC0CB}, - {"plum", 0xDDA0DD}, - {"powderblue", 0xB0E0E6}, - {"purple", 0x800080}, - {"red", 0xFF0000}, - {"rosybrown", 0xBC8F8F}, - {"royalblue", 0x4169E1}, - {"saddlebrown", 0x8B4513}, - {"salmon", 0xFA8072}, - {"sandybrown", 0xF4A460}, - {"seagreen", 0x2E8B57}, - {"seashell", 0xFFF5EE}, - {"sienna", 0xA0522D}, - {"silver", 0xC0C0C0}, - {"skyblue", 0x87CEEB}, - {"slateblue", 0x6A5ACD}, - {"slategray", 0x708090}, - {"slategrey", 0x708090}, - {"snow", 0xFFFAFA}, - {"springgreen", 0x00FF7F}, - {"steelblue", 0x4682B4}, - {"tan", 0xD2B48C}, - {"teal", 0x008080}, - {"thistle", 0xD8BFD8}, - {"tomato", 0xFF6347}, - {"turquoise", 0x40E0D0}, - {"violet", 0xEE82EE}, - {"wheat", 0xF5DEB3}, - {"white", 0xFFFFFF}, - {"whitesmoke", 0xF5F5F5}, - {"yellow", 0xFFFF00}, - {"yellowgreen", 0x9ACD32}, -}; - -#define SUBRIP_MAX_STACKED_FONT_TAGS 16 - -/* Read the HTML-style attribute starting at *s, and skip *s past the value. - * Set attr and val to the parsed attribute name and value. - * Return 0 on success, or -1 if no valid attribute was found. - */ -static int read_attr(char **s, struct bstr *attr, struct bstr *val) -{ - char *eq = strchr(*s, '='); - if (!eq) - return -1; - attr->start = *s; - attr->len = eq - *s; - for (int i = 0; i < attr->len; i++) - if (!mp_isalnum(attr->start[i])) - return -1; - val->start = eq + 1; - bool quoted = val->start[0] == '"'; - if (quoted) - val->start++; - unsigned char *end = strpbrk(val->start, quoted ? "\"" : " >"); - if (!end) - return -1; - val->len = end - val->start; - *s = end + quoted; - return 0; -} - -static void convert_subrip(struct sd *sd, const char *orig, - char *dest, int dest_buffer_size) -{ - /* line is not const to avoid warnings with strtol, etc. - * orig content won't be changed */ - char *line = (char *)orig; - struct line new_line = { - .buf = dest, - .bufsize = dest_buffer_size, - }; - struct font_tag font_stack[SUBRIP_MAX_STACKED_FONT_TAGS + 1]; - font_stack[0] = (struct font_tag){0}; // type with all defaults - int sp = 0; - - while (*line && new_line.len < new_line.bufsize - 1) { - char *orig_line = line; - - for (int i = 0; i < MP_ARRAY_SIZE(subrip_basic_tags); i++) { - const struct tag_conv *tag = &subrip_basic_tags[i]; - int from_len = strlen(tag->from); - if (strncmp(line, tag->from, from_len) == 0) { - append_text(&new_line, "%s", tag->to); - line += from_len; - } - } - - if (strncmp(line, "", 7) == 0) { - /* Closing font tag */ - line += 7; - - if (sp > 0) { - struct font_tag *tag = &font_stack[sp]; - struct font_tag *last_tag = &tag[-1]; - sp--; - - if (tag->has_size) { - if (!last_tag->has_size) - append_text(&new_line, "{\\fs}"); - else if (last_tag->size != tag->size) - append_text(&new_line, "{\\fs%d}", last_tag->size); - } - - if (tag->has_color) { - if (!last_tag->has_color) - append_text(&new_line, "{\\c}"); - else if (last_tag->color != tag->color) - append_text(&new_line, "{\\c&H%06X&}", last_tag->color); - } - - if (tag->has_face) { - if (!last_tag->has_face) - append_text(&new_line, "{\\fn}"); - else if (bstrcmp(last_tag->face, tag->face) != 0) - append_text(&new_line, "{\\fn%.*s}", - BSTR_P(last_tag->face)); - } - } - } else if (strncmp(line, "size = bstrtoll(val, &val, 10); - if (val.len) - break; - append_text(&new_line, "{\\fs%d}", tag->size); - tag->has_size = true; - has_valid_attr = true; - } else if (!bstrcmp0(attr, "color")) { - int found = 0; - - // Try to lookup the string in standard web colors - for (int i = 0; i < MP_ARRAY_SIZE(subrip_web_colors); i++) { - char *color = subrip_web_colors[i].s; - if (bstrcasecmp(val, bstr0(color)) == 0) { - uint32_t xcolor = subrip_web_colors[i].v; - tag->color = ((xcolor & 0xff) << 16) - | (xcolor & 0xff00) - | ((xcolor & 0xff0000) >> 16); - found = 1; - } - } - - // If it's not a web color it must be a HEX RGB value - if (!found) { - // Remove the leading '#' - bstr_eatstart(&val, bstr0("#")); - // Sometimes there are two '#' - bstr_eatstart(&val, bstr0("#")); - - // Parse RRGGBB format - tag->color = bstrtoll(val, &val, 16) & 0x00ffffff; - if (!val.len) { - tag->color = ((tag->color & 0xff) << 16) - | (tag->color & 0xff00) - | ((tag->color & 0xff0000) >> 16); - found = 1; - } - } - - if (found) { - append_text(&new_line, "{\\c&H%06X&}", tag->color); - tag->has_color = true; - } else { - // We didn't find any matching color - MP_WARN(sd, "unknown font color in subtitle: >%s<\n", - orig); - append_text(&new_line, "{\\c}"); - } - - has_valid_attr = true; - } else if (!bstrcmp0(attr, "face")) { - /* Font face attribute */ - tag->face = val; - append_text(&new_line, "{\\fn%.*s}", BSTR_P(tag->face)); - tag->has_face = true; - has_valid_attr = true; - } else - MP_WARN(sd, "unrecognized attribute \"%.*s\" in font tag\n", - BSTR_P(attr)); - } - - if (!has_valid_attr || *line != '>') { /* Not valid font tag */ - line = potential_font_tag_start; - new_line.len = len_backup; - } else { - sp++; - line++; - } - } else if (*line == '{') { - char *end = strchr(line, '}'); - if (line[1] == '\\' && end) { - // Likely ASS tag, pass them through - // Note that ASS tags like {something\an8} are legal too (i.e. - // the first character after '{' doesn't have to be '\'), but - // consider these fringe cases not worth supporting. - append_text_n(&new_line, line, end - line + 1); - line = end + 1; - } else { - append_text(&new_line, "\\{"); - line++; - } - } - - /* Tag conversion code didn't match */ - if (line == orig_line) - new_line.buf[new_line.len++] = *line++; - } - new_line.buf[new_line.len] = 0; -} - -static const char *const srt_ass_extradata = - "[Script Info]\n" - "ScriptType: v4.00+\n" - "PlayResX: 384\n" - "PlayResY: 288\n"; - -static bool supports_format(const char *format) -{ - return format && (strcmp(format, "subrip") == 0 || - strcmp(format, "text") == 0); -} - -static int init(struct sd *sd) -{ - sd->output_codec = "ass-text"; - sd->output_extradata = (char *)srt_ass_extradata; - sd->output_extradata_len = strlen(sd->output_extradata); - return 0; -} - -static void decode(struct sd *sd, struct demux_packet *packet) -{ - char dest[SD_MAX_LINE_LEN]; - // Assume input buffer is padded with 0 - convert_subrip(sd, packet->buffer, dest, sizeof(dest)); - sd_conv_add_packet(sd, dest, strlen(dest), packet->pts, packet->duration); -} - -const struct sd_functions sd_srt = { - .name = "srt", - .supports_format = supports_format, - .init = init, - .decode = decode, - .get_converted = sd_conv_def_get_converted, - .reset = sd_conv_def_reset, -}; diff --git a/wscript_build.py b/wscript_build.py index ccc991dd16..f04a610b83 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -260,7 +260,6 @@ def build(ctx): ( "sub/sd_ass.c", "libass" ), ( "sub/sd_lavc.c" ), ( "sub/sd_lavc_conv.c" ), - ( "sub/sd_srt.c" ), ## Video ( "video/csputils.c" ), -- cgit v1.2.3 From 74c11f0c841d0b81a6ea759c7eb131d2c2e02ec3 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 16 Dec 2015 23:54:25 +0100 Subject: sub: detect charset in demuxer Slightly simpler, and removes the need to pre-read all subtitle packets. This still does the subtitle charset conversion on the packet level (instead converting when parsing the file), so in theory this still could provide a way to change the charset at runtime. But maybe even this should be removed, as FFmpeg is somewhat likely to get its own charset detection and conversion mechanism in the future. (Would have to keep the subtitle file in memory to allow changing the charset on the fly, I guess.) --- demux/demux_lavf.c | 34 ++++++++++++++++++++++++++-------- demux/stheader.h | 2 +- misc/charset_conv.c | 7 +++++++ misc/charset_conv.h | 1 + sub/dec_sub.c | 47 +++++------------------------------------------ 5 files changed, 40 insertions(+), 51 deletions(-) diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 9aa71fcaf1..5383b93934 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -40,6 +40,7 @@ #include "common/tags.h" #include "common/av_common.h" #include "misc/bstr.h" +#include "misc/charset_conv.h" #include "stream/stream.h" #include "demux.h" @@ -108,16 +109,16 @@ struct format_hack { bool no_stream : 1; // do not wrap struct stream as AVIOContext bool use_stream_ids : 1; // export the native stream IDs bool fully_read : 1; // set demuxer.fully_read flag + bool detect_charset : 1; // format is a small text file, possibly not UTF8 bool image_format : 1; // expected to contain exactly 1 frame - bool utf8_subs : 1; // subtitles are (mostly) guaranteed UTF-8 // Do not confuse player's position estimation (position is into external // segment, with e.g. HLS, player knows about the playlist main file only). bool clear_filepos : 1; }; #define BLACKLIST(fmt) {fmt, .ignore = true} -#define TEXTSUB(fmt) {fmt, .fully_read = true} -#define TEXTSUB_UTF8(fmt) {fmt, .fully_read = true, .utf8_subs = true} +#define TEXTSUB(fmt) {fmt, .fully_read = true, .detect_charset = true} +#define TEXTSUB_UTF8(fmt) {fmt, .fully_read = true} #define IMAGEFMT(fmt) {fmt, .image_format = true} static const struct format_hack format_hacks[] = { @@ -145,10 +146,6 @@ static const struct format_hack format_hacks[] = { TEXTSUB_UTF8("webvtt"), TEXTSUB_UTF8("ass"), - // Formats which support muxed subtitles, and always use UTF-8 for them. - {"mov", .utf8_subs = true}, - {"mkv", .utf8_subs = true}, - // Useless non-sense, sometimes breaks MLP2 subreader.c fallback BLACKLIST("tty"), // Let's open files with extremely generic extensions (.bin) with a @@ -174,6 +171,7 @@ typedef struct lavf_priv { int cur_program; char *mime_type; bool merge_track_metadata; + char *file_charset; } lavf_priv_t; // At least mp4 has name="mov,mp4,m4a,3gp,3g2,mj2", so we split the name @@ -262,6 +260,23 @@ static void list_formats(struct demuxer *demuxer) MP_INFO(demuxer, "%15s : %s\n", fmt->name, fmt->long_name); } +static void detect_charset(struct demuxer *demuxer) +{ + lavf_priv_t *priv = demuxer->priv; + char *cp = demuxer->opts->sub_cp; + if (mp_charset_requires_guess(cp)) { + bstr data = stream_peek(demuxer->stream, STREAM_MAX_BUFFER_SIZE); + cp = (char *)mp_charset_guess(priv, demuxer->log, data, cp, 0); + MP_VERBOSE(demuxer, "Detected charset: %s\n", cp ? cp : "(unknown)"); + } + if (cp && !mp_charset_is_utf8(cp)) + MP_INFO(demuxer, "Using subtitle charset: %s\n", cp); + // libavformat transparently converts UTF-16 to UTF-8 + if (mp_charset_is_utf16(priv->file_charset)) + cp = NULL; + priv->file_charset = cp; +} + static char *remove_prefix(char *s, const char *const *prefixes) { for (int n = 0; prefixes[n]; n++) { @@ -402,6 +417,9 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check) demuxer->filetype = priv->avif->name; + if (priv->format_hack.detect_charset) + detect_charset(demuxer); + return 0; } @@ -622,7 +640,7 @@ static void handle_stream(demuxer_t *demuxer, int i) } } - sh_sub->is_utf8 = priv->format_hack.utf8_subs; + sh_sub->charset = priv->file_charset; break; } diff --git a/demux/stheader.h b/demux/stheader.h index a615867685..7a11832c24 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -93,7 +93,7 @@ typedef struct sh_video { typedef struct sh_sub { double frame_based; // timestamps are frame-based (and this is the // fallback framerate used for timestamps) - bool is_utf8; // if false, subtitle packet charset is unknown + char *charset; // assumed 8 bit subtitle charset (can be NULL) struct dec_sub *dec_sub; // decoder context } sh_sub_t; diff --git a/misc/charset_conv.c b/misc/charset_conv.c index 3e7e47cc58..8181b1392e 100644 --- a/misc/charset_conv.c +++ b/misc/charset_conv.c @@ -52,6 +52,13 @@ bool mp_charset_is_utf8(const char *user_cp) strcasecmp(user_cp, "utf-8") == 0); } +bool mp_charset_is_utf16(const char *user_cp) +{ + bstr s = bstr0(user_cp); + return bstr_case_startswith(s, bstr0("utf16")) || + bstr_case_startswith(s, bstr0("utf-16")); +} + // Split the string on ':' into components. // out_arr is at least max entries long. // Return number of out_arr entries filled. diff --git a/misc/charset_conv.h b/misc/charset_conv.h index 3d3520fb2b..ddfabbe49e 100644 --- a/misc/charset_conv.h +++ b/misc/charset_conv.h @@ -13,6 +13,7 @@ enum { }; bool mp_charset_is_utf8(const char *user_cp); +bool mp_charset_is_utf16(const char *user_cp); bool mp_charset_requires_guess(const char *user_cp); const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf, const char *user_cp, int flags); diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 615e95e730..68f3c159d2 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -54,7 +54,7 @@ struct dec_sub { struct MPOpts *opts; struct sd init_sd; - const char *charset; + struct sh_stream *sh; struct sd *sd[MAX_NUM_SD]; int num_sd; @@ -195,6 +195,8 @@ void sub_init_from_sh(struct dec_sub *sub, struct sh_stream *sh) pthread_mutex_lock(&sub->lock); + sub->sh = sh; + if (sh->extradata && !sub->init_sd.extradata) sub_set_extradata(sub, sh->extradata, sh->extradata_size); struct sd init_sd = sub->init_sd; @@ -282,8 +284,8 @@ static void decode_chain_recode(struct dec_sub *sub, struct demux_packet *packet { if (sub->num_sd > 0) { struct demux_packet *recoded = NULL; - if (sub->charset) - recoded = recode_packet(sub->log, packet, sub->charset); + if (sub->sh && sub->sh->sub->charset) + recoded = recode_packet(sub->log, packet, sub->sh->sub->charset); decode_chain(sub->sd, sub->num_sd, recoded ? recoded : packet); talloc_free(recoded); } @@ -296,38 +298,6 @@ void sub_decode(struct dec_sub *sub, struct demux_packet *packet) pthread_mutex_unlock(&sub->lock); } -static const char *guess_sub_cp(struct mp_log *log, void *talloc_ctx, - struct packet_list *subs, const char *usercp) -{ - if (!mp_charset_requires_guess(usercp)) - return usercp; - - // Concat all subs into a buffer. We can't probably do much better without - // having the original data (which we don't, not anymore). - int max_size = 2 * 1024 * 1024; - const char *sep = "\n\n"; // In utf-16: U+0A0A GURMUKHI LETTER UU - int sep_len = strlen(sep); - int num_pkt = 0; - int size = 0; - for (int n = 0; n < subs->num_packets; n++) { - struct demux_packet *pkt = subs->packets[n]; - if (size + pkt->len > max_size) - break; - size += pkt->len + sep_len; - num_pkt++; - } - bstr text = {talloc_size(NULL, size), 0}; - for (int n = 0; n < num_pkt; n++) { - struct demux_packet *pkt = subs->packets[n]; - memcpy(text.start + text.len, pkt->buffer, pkt->len); - memcpy(text.start + text.len + pkt->len, sep, sep_len); - text.len += pkt->len + sep_len; - } - const char *guess = mp_charset_guess(talloc_ctx, log, text, usercp, 0); - talloc_free(text.start); - return guess; -} - static void add_sub_list(struct dec_sub *sub, struct packet_list *subs) { struct sd *sd = sub_get_last_sd(sub); @@ -362,7 +332,6 @@ static void add_packet(struct packet_list *subs, struct demux_packet *pkt) bool sub_read_all_packets(struct dec_sub *sub, struct sh_stream *sh) { assert(sh && sh->sub); - struct MPOpts *opts = sub->opts; pthread_mutex_lock(&sub->lock); @@ -383,12 +352,6 @@ bool sub_read_all_packets(struct dec_sub *sub, struct sh_stream *sh) talloc_free(pkt); } - if (opts->sub_cp && !sh->sub->is_utf8) - sub->charset = guess_sub_cp(sub->log, sub, subs, opts->sub_cp); - - if (sub->charset && sub->charset[0] && !mp_charset_is_utf8(sub->charset)) - MP_INFO(sub, "Using subtitle charset: %s\n", sub->charset); - add_sub_list(sub, subs); pthread_mutex_unlock(&sub->lock); -- cgit v1.2.3 From 04af005c35ee11d227a758d7b4e9e6c9558c8409 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 17 Dec 2015 00:46:07 +0100 Subject: sd_ass: remove dead code With the FFmpeg subtitle decoder used for _all_ non-ASS text subtitle format, this code is simply unused now. Ironically, the FFmpeg subtitle decoder does not handle things correctly in a bunch of cases. Should it turn out they actually matter, they will have to hack back. The extend_event one is a candidate, although even though there were allegedly files which need it, I couldn't get samples from the user who originally reported such files. As such, extend_event was only confirmed to handle trailing events with no (endless) duration like with MicroDVD and LRC, but FFmpeg "fudges" these anyway, so no special handling is needed. This code also had logic to handle seeking with muxed srt subtitles, which made the sub-seek command work. But this has been broken before this commit already. Currently, seeking with muxed srt subs will clear all subtitles, as the broken FFmpeg ASS format output by the libavcodec subtitle converters does not check for duplicates. Since the subtitles are all cleared, ass_step_sub() can not work properly and sub-seek can not seek to already seen subtitles. --- sub/dec_sub.c | 4 ---- sub/sd.h | 4 ---- sub/sd_ass.c | 64 +++++++---------------------------------------------------- 3 files changed, 7 insertions(+), 65 deletions(-) diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 68f3c159d2..451a5cab38 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -303,8 +303,6 @@ static void add_sub_list(struct dec_sub *sub, struct packet_list *subs) struct sd *sd = sub_get_last_sd(sub); assert(sd); - sd->no_remove_duplicates = true; - for (int n = 0; n < subs->num_packets; n++) decode_chain_recode(sub, subs->packets[n]); @@ -314,8 +312,6 @@ static void add_sub_list(struct dec_sub *sub, struct packet_list *subs) // but this is obviously unwanted in this case. if (sd->driver->fix_events) sd->driver->fix_events(sd); - - sd->no_remove_duplicates = false; } static void add_packet(struct packet_list *subs, struct demux_packet *pkt) diff --git a/sub/sd.h b/sub/sd.h index f7f0d320b4..d2f22c5828 100644 --- a/sub/sd.h +++ b/sub/sd.h @@ -39,10 +39,6 @@ struct sd { struct ass_renderer *ass_renderer; pthread_mutex_t *ass_lock; - // If false, try to remove multiple subtitles. - // (Only for decoders which have accept_packets_in_advance set.) - bool no_remove_duplicates; - // Set by sub converter const char *output_codec; char *output_extradata; diff --git a/sub/sd_ass.c b/sub/sd_ass.c index 2948475e7a..4c6296b2f4 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -43,7 +43,6 @@ struct sd_ass_priv { bool on_top; struct sub_bitmap *parts; bool flush_on_seek; - int extend_event; char last_text[500]; struct mp_image_params video_params; struct mp_image_params last_params; @@ -79,12 +78,9 @@ static void mp_ass_add_default_styles(ASS_Track *track, struct MPOpts *opts) static bool supports_format(const char *format) { - // ass-text is produced by converters and the subreader.c ssa parser; this - // format has ASS tags, but doesn't start with any prelude, nor does it - // have extradata. + // "ssa" is used for the FFmpeg subtitle converter output return format && (strcmp(format, "ass") == 0 || - strcmp(format, "ssa") == 0 || - strcmp(format,