首页 > 其他分享 >记ffmpeg subtitles滤镜切换字幕卡顿

记ffmpeg subtitles滤镜切换字幕卡顿

时间:2024-09-27 23:35:25浏览次数:9  
标签:ass ffmpeg stream fmt 字幕 ret 滤镜 streams subtitles

1.subtitles卡顿

偷懒在项目中使用ffmpeg的subtitles滤镜进行字幕渲染。后来发现,使用滤镜切换字幕时会出现卡顿。经过进一步测试与代码调式确认,在播放一个时长在一个小时以上的视频文件的内挂字幕时,滤镜初始化花费了较长的时间。

使用ffplay + subtitles滤镜播放该文件并显示字幕存在同样的问题。(播放窗口出现前需执行较长时间)(ps:好,第三方开源库问题,下班喽)
注:该问题在ffmpeg5.1存在。6.1不记得了,回头再测下看看。

2.调试ffmpeg滤镜

ffmpeg代码不是很熟,好在手里有跑通的源码可以用来调试。大致定位了下,找到了vf_subtitles.c这个文件,subtitles滤镜的相关代码都在这个文件内。接下来就好找了,我们阅读下代码或者直接调试都可以确定,花费了大量时间的是init_subtitles函数的以下代码:

while (av_read_frame(fmt, &pkt) >= 0) {
        int i, got_subtitle;
        AVSubtitle sub = {0};

        if (pkt.stream_index == sid) {
            ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_subtitle, &pkt);
            if (ret < 0) {
                av_log(ctx, AV_LOG_WARNING, "Error decoding: %s (ignored)\n",
                       av_err2str(ret));
            } else if (got_subtitle) {
                const int64_t start_time = av_rescale_q(sub.pts, AV_TIME_BASE_Q, av_make_q(1, 1000));
                const int64_t duration   = sub.end_display_time;
                for (i = 0; i < sub.num_rects; i++) {
                    char *ass_line = sub.rects[i]->ass;
                    if (!ass_line)
                        break;
                    ass_process_chunk(ass->track, ass_line, strlen(ass_line),
                                      start_time, duration);
                }
            }
        }
        av_packet_unref(&pkt);
        avsubtitle_free(&sub);
    }

这段代码很简单,调用的ffmpeg api解码字幕并将字幕文本传入libass。但是再往上找能看到以下代码:

ret = avformat_open_input(&fmt, ass->filename, NULL, NULL);
    if (ret < 0) {
        av_log(ctx, AV_LOG_ERROR, "Unable to open %s\n", ass->filename);
        goto end;
    }
    ret = avformat_find_stream_info(fmt, NULL);
    if (ret < 0)
        goto end;

    /* Locate subtitles stream */
    if (ass->stream_index < 0)
        ret = av_find_best_stream(fmt, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0);
    else {
        ret = -1;
        if (ass->stream_index < fmt->nb_streams) {
            for (j = 0; j < fmt->nb_streams; j++) {
                if (fmt->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
                    if (ass->stream_index == k) {
                        ret = j;
                        break;
                    }
                    k++;
                }
            }
        }
    }

这里对字幕文件解封装,如果是针对外挂字幕文件,这两段代码是可行的。但如果是内挂字幕,解码前的av_read_frame方法会遍历输入文件的所有包,包括视频流与音频流的包。耗费了大量的时间。

3.解决方法

代码修改如下:

/* Locate subtitles stream */
    if (ass->stream_index < 0)
        ret = av_find_best_stream(fmt, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0);
    else {
        ret = -1;
        if (ass->stream_index < fmt->nb_streams) {
            for (j = 0; j < fmt->nb_streams; j++) {
                if (fmt->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
                    if (ass->stream_index == k) {
                        ret = j;
                        // break;
                    }
                    k++;
                }
            }
        }
    }

删除找到字幕流后的的break,并设置除字幕流外每一条流的flag为discard_all,避免遍历非选定字幕流的包导致耗时。然后重新编译ffmpeg即可。

if (ass->stream_index < 0)
        ret = av_find_best_stream(fmt, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0);
    else {
        ret = -1;
        if (ass->stream_index < fmt->nb_streams) {
            for (j = 0; j < fmt->nb_streams; j++) {
                auto discard = fmt->streams[j]->discard;
                fmt->streams[j]->discard = AVDISCARD_ALL;
                if (fmt->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
                    if (ass->stream_index == k) {
                        ret = j;
                        // break;
                        fmt->streams[j]->discard = discard;
                    }
                    k++;
                }
            }
        }
    }

标签:ass,ffmpeg,stream,fmt,字幕,ret,滤镜,streams,subtitles
From: https://www.cnblogs.com/fir-loading/p/18432571

相关文章

  • FFmpeg开发笔记(五十三)移动端的国产直播录制工具EasyPusher
    EasyPusher是一款国产的RTSP直播录制推流客户端工具,它支持Windows、Linux、Android、iOS等操作系统。EasyPusher采用RTSP推流协议,其中安卓版EasyPusher的Github托管地址为https://github.com/EasyDarwin/EasyPusher-Android。不过EasyPusher有好几年没更新了,尤其安卓版的EasyPusher......
  • FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
    FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播 合集-FFmpeg开发实战(55)  ​之前的文章《利用RTMP协议构建电脑与手机的直播Demo》介绍了如何使用RTMPStreamer实现完整的RTMP直播流程,另一篇文章《利用SRT协议构建手机APP的直播Demo》介绍了如何使用SRT......
  • FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播1111
    FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播 合集-FFmpeg开发实战(55)  ​之前的文章《利用RTMP协议构建电脑与手机的直播Demo》介绍了如何使用RTMPStreamer实现完整的RTMP直播流程,另一篇文章《利用SRT协议构建手机APP的直播Demo》介绍了如何使用SRT......
  • ffmpeg如何实现视频推流?
    FFmpeg是一个强大的多媒体框架,用于处理视频和音频数据。它包括了libavcodec(用于解码和编码)、libavformat(用于格式转换)、libavutil(提供一些辅助工具和函数)、libavfilter(用于音视频过滤)等多个库。以下这些都是FFmpeg的特性FFmpeg支持大量的音视频编解码器,如H.264、H.265、VP9、MPEG-2......
  • 用ffmpeg合并截取拆分音频
    转自:http://blog.sina.com.cn/s/blog_50e610900102vkab.html1多个mp3文件合并成一个mp3文件一种方法是连接到一起ffmpeg64.exe-i"concat:123.mp3|124.mp3"-acodeccopyoutput.mp3解释:-i代表输入参数          contact:123.mp3|124.mp3代表着需要连接到一起的......
  • Podcast Subtitles AI Generator All In One
    PodcastSubtitlesAIGeneratorAllInOne播客字幕AI生成器???TranscribePodcasttoTexthttps://www.youtube.com/watch?v=WVhcmJl4ZFwhttps://video.adorilabs.com/https://www.youtube.com/watch?v=h5AEXBS5lf0https://www.media.io/transcribe-podcast-to-texts......
  • 拥抱变化之FFmpeg 7.0与VVC
    IntroductiontoFFmpegFFmpeg isasolutiontorecord,convertandstreamaudioandvideo.Itisaveryfastvideoandaudioconverteranditcanalsoacquirefromaliveaudio/videosource.Designedtobeintuitive,thecommand-lineinterface(ffmpeg)tri......
  • FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
    ​之前的文章《利用RTMP协议构建电脑与手机的直播Demo》介绍了如何使用RTMPStreamer实现完整的RTMP直播流程,另一篇文章《利用SRT协议构建手机APP的直播Demo》介绍了如何使用SRTStreamer实现完整的SRT直播流程,接下来介绍如何使用EasyPusher-Android实现完整的RTSP直播流程。一、......
  • Safari中无法在悬停状态下应用CSS滤镜
    在Safari浏览器中,当鼠标悬停在元素上时,无法应用CSS滤镜效果。这意味着开发者无法通过CSS来实现诸如悬停时的模糊、灰度或颜色变换等常见的交互效果。该问题可能会影响用户体验,特别是对于那些依赖于视觉反馈来增强交互性的网站或应用程序。影响范围该问题主要影响使用Safari......
  • FFmpeg开发笔记(五十三)移动端的国产直播录制工具EasyPusher
    ​EasyPusher是一款国产的RTSP直播录制推流客户端工具,它支持Windows、Linux、Android、iOS等操作系统。EasyPusher采用RTSP推流协议,其中安卓版EasyPusher的Github托管地址为https://github.com/EasyDarwin/EasyPusher-Android。不过EasyPusher有好几年没更新了,尤其安卓版的EasyP......