总都督 2024-03-13 16:39 采纳率: 50%
浏览 11
已结题

FFmpeg 内嵌字幕无法获取字幕的持续时间

我目前在用FFmpeg库实现视频播放等功能,在实现内嵌字幕播放的时候遇到,图片基字幕播放时获取不到字幕持续时间Packet.duration和subtitle.end_display_time , subtitle.start_display_time等值都是0或者-1

if (mSubtitleInfo.isEnabled && mPacket.stream_index == mSubtitleStream->index) {
            AVSubtitle subtitle;
            int gotSubtitle = 1;
            if (avcodec_decode_subtitle2(mSubtitleCodecContext, &subtitle, &gotSubtitle, &mPacket) < 0) {
                LOG("Error decoding subtitle \n");
                return false;
            }
            LOG("subtitle gotSubtitle:%d pts:%d duration:%d startTime:%d endTime:%d time_base.num:%d time_base.den:%d\n", gotSubtitle, mPacket.pts, mPacket.duration, subtitle.start_display_time, subtitle.end_display_time, mSubtitleStream->time_base.num, mSubtitleStream->time_base.den);
            mSubtitleInfo.subtitleType = subtitle.format;
            // 处理解码后的字幕  
            for (int i = 0; i < subtitle.num_rects; i++) {
                if (subtitle.format != 0) {
                    if (textSubtitleCallbackFunc != nullptr) {
                        char* bytes;
                        if (subtitle.rects[i]->ass != NULL) bytes = subtitle.rects[i]->ass;
                        else if (subtitle.rects[i]->text != NULL) bytes = subtitle.rects[i]->text;
                        mSubtitleInfo.pts = mPacket.pts;
                        mSubtitleInfo.duration = mPacket.duration;
                        
                        if (bytes != NULL) textSubtitleCallbackFunc(bytes, mPacket.pts, mPacket.duration);
                    }
                }
                else {
                    AVSubtitleRect* sub_rect = subtitle.rects[i];

                    int dst_linesize[4];
                    uint8_t* dst_data[4];
                    av_image_alloc(dst_data, dst_linesize, sub_rect->w, sub_rect->h, AV_PIX_FMT_RGBA, 1);
                    SwsContext* swsContext = sws_getContext(sub_rect->w, sub_rect->h, AV_PIX_FMT_PAL8,
                                                            sub_rect->w, sub_rect->h, AV_PIX_FMT_RGBA,
                                                            SWS_BILINEAR, nullptr, nullptr, nullptr);
                    sws_scale(swsContext, sub_rect->data, sub_rect->linesize, 0, sub_rect->h, dst_data, dst_linesize);
                    sws_freeContext(swsContext);

                    mSubtitleInfo.pts = mPacket.pts;
                    if (subtitle.end_display_time - subtitle.start_display_time > 0)
                        mSubtitleInfo.duration = (subtitle.end_display_time - subtitle.start_display_time);
                    else
                        mSubtitleInfo.duration = -1;

                    if (imgSubtitleCallbackFunc != nullptr) {
                        imgSubtitleCallbackFunc(dst_data[0], sub_rect->w, sub_rect->h, mSubtitleInfo.pts, mSubtitleInfo.duration);
                    }

                    for (size_t j = 0; j < 4; j++)
                    {
                        av_freep(&dst_data[j]);
                    }
                }
            }
            avsubtitle_free(&subtitle);
  • 写回答

22条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-03-13 16:39
    关注
    获得0.30元问题酬金

    引自免费微信小程序:皆我百晓生

    在FFmpeg中处理内嵌字幕时,对于图像(bitmap)类型的字幕,AVSubtitle结构体中的start_display_timeend_display_time可能并不会被填充。这是因为这些字段主要依赖于外部时间戳信息或者ASS/SSA等格式的特殊标记来决定字幕的显示开始和结束时间。

    要解决这个问题,你需要从包(packet)的时间戳PTS以及解码上下文(mSubtitleCodecContext)中的时间基(time_base)计算出字幕的实际持续时间。通常情况下,你可以尝试以下方式:

    // 计算字幕的显示开始时间戳(单位:秒)
    double start_time = static_cast<double>(mPacket.pts) / av_q2d(mSubtitleStream->time_base);
    
    // 如果end_display_time为0或-1,则需要根据相邻字幕包的时间戳差值估算持续时间
    double duration = -1.0;
    if (mNextSubtitlePacket.pts != AV_NOPTS_VALUE && mPacket.pts != AV_NOPTS_VALUE) {
        double end_time = static_cast<double>(mNextSubtitlePacket.pts) / av_q2d(mSubtitleStream->time_base);
        duration = end_time - start_time;
    }
    
    // 使用计算得到的duration
    mSubtitleInfo.duration = static_cast<int64_t>(duration * av_q2d(mSubtitleStream->time_base)); // 转换回内部时间单位
    
    // 然后在回调函数中使用这个计算得到的duration
    

    请注意,这里的逻辑假设你有一个有序且连续的字幕包流,可以根据前后两个包的时间戳差异来估算当前字幕的持续时间。实际应用中,你可能需要根据具体的字幕格式和编码器行为调整这种方法,确保正确地解析和同步字幕显示时间。

    另外,在播放过程中,应确保正确处理无后续字幕包的情况,避免因无法获取结束时间导致的问题。

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 3月21日
  • 创建了问题 3月13日

悬赏问题

  • ¥15 keil的map文件中Image component sizes各项意思
  • ¥30 BC260Y用MQTT向阿里云发布主题消息一直错误
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)