Skip to content

M3U8分段视频在seekTo的时候需要很长时间才能播放,这时间跟拖动距离有关,怎样才能缩短时间? #2874

@drivedreams

Description

@drivedreams

这是我用的M3U8地址:http://hot.vrs.sohu.com/ipad1479474_4601450223274_4680795.m3u8?plat=17&prod=ad

现象:1.播放整个的大视频seekTo时,没有问题,很快就可以继续播放。
2.对M3U8地址视频使用seekTo时可能出现两种情况:1.缓冲很长时间后可以播放 2.缓冲一段时间后视频暂停,点击播放视频从头开始播放。
3.如果seekTo的位置已经预缓冲完成则seekTo可以很快播放。
4.通过Log及播放信息可以看出,缓冲很长时间这个过程中,一直有数据进行下载,且速度并不慢。

请教各位大神帮忙分析下,这个问题很头疼,现在都是用这中分段的视频,缓冲时间过长太影响体验,谢谢了!

Activity

0ct0cat

0ct0cat commented on Mar 22, 2017

@0ct0cat

maybe you need modify the ffmpeg.make the probe size smaller.

0ct0cat

0ct0cat commented on Mar 22, 2017

@0ct0cat

the default probe is 5s. too long

Nimger

Nimger commented on Mar 23, 2017

@Nimger

使用IJKFFMoviePlayerController的话,我也碰到这问题,后来我直接改用IJKAVMoviePlayerController来显示,拖动进度就很快了,看了下IJKFFMoviePlayerController的日志,拖动的时候,会一个个ts请求下去,直到找到需要的ts,这样不慢才怪,不知道有什么法子直接定位到所需要的ts

Android4MediaPlayer

Android4MediaPlayer commented on Mar 25, 2017

@Android4MediaPlayer

有sample url吗

0ct0cat

0ct0cat commented on Mar 27, 2017

@0ct0cat

IJKAVMoviePlayerController use the ios defalut mediaplayer. not ffplay.
if yout want use ffplay,pls use IJKFFMoviePlayerController.
when the play seek to position.Reduced the probe size make it fast.

drivedreams

drivedreams commented on Mar 28, 2017

@drivedreams
Author
drivedreams

drivedreams commented on Mar 28, 2017

@drivedreams
Author

Hi 0ct0cat,
I checked the codes of ijkplayer, IJKFFMoviePlayerController is used in IOS. How to resolve my problem on android?

0ct0cat

0ct0cat commented on Mar 29, 2017

@0ct0cat

there is a member probesize in AVFormatContext ,you can set it's value to control the demuxer probe size.
this method can use on android & ios

aasdsjk

aasdsjk commented on Mar 29, 2017

@aasdsjk

how to set probesize ,and where can i set it's value?

0ct0cat

0ct0cat commented on Mar 30, 2017

@0ct0cat

just like this
pls->ctx->probesize = 32 * 1024;
in hls.c
hls_read_header

aasdsjk

aasdsjk commented on Mar 30, 2017

@aasdsjk

thank you

aasdsjk

aasdsjk commented on Mar 30, 2017

@aasdsjk

I haved tried this, and i make pls->ctx->probesize = 4 * 1024. But it is not helpful. Does it work?

drivedreams

drivedreams commented on Apr 5, 2017

@drivedreams
Author

Hi 0ct0cat,
Could you try my Video address? I has tried a lot of ways to do it, but still can not resolved it. I have to use Vitamio as a temporary resolution.

0ct0cat

0ct0cat commented on Apr 7, 2017

@0ct0cat

@drivedreams
i test this stream,it's can't seek.
maybe there is a problem in mpegts.c.
after seek, hls.c work normal,it's can find right url to read and down ts data.
but the av_read_frame stop work.i think it's demux's bug.

drivedreams

drivedreams commented on Apr 9, 2017

@drivedreams
Author

24 remaining items

drivedreams

drivedreams commented on Nov 14, 2017

@drivedreams
Author

@raymond1012 是否应该把这个bug 上面的解决方案已经验证了

drivedreams

drivedreams commented on Nov 14, 2017

@drivedreams
Author

@raymond1012 是不是应该把上面的解决方案应用到源码中,这样可以关闭很多issue

Android4MediaPlayer

Android4MediaPlayer commented on Nov 14, 2017

@Android4MediaPlayer

能提供下sample url吗

drivedreams

drivedreams commented on Nov 15, 2017

@drivedreams
Author

@Android4MediaPlayer 我提供的Url现在都是动态变化的。给你了也很快就会失效不具备代表性。这个BUG应该对于所有的点播的M3U8视频都都会出现,而且是必现的。随便找个M3U8测试下呗。

yeshibuzhong

yeshibuzhong commented on Jun 21, 2018

@yeshibuzhong

@CloudIAU 你好, 我按照你说的方案添加了以后(我将ffplay里边的几个hls.c都做了修改), 使用编译好的ijk播放视频的时候只要快进就崩溃.信息如下:
c80117f4-e257-4761-afc1-c04b83ff094d
请问哪里出了问题, 万分感谢!!!

linjiansheng

linjiansheng commented on Jun 25, 2018

@linjiansheng
Contributor

@yeshibuzhong 是不是 seq_no >= pls->n_segments?

linjiansheng

linjiansheng commented on Jun 26, 2018

@linjiansheng
Contributor

@Android4MediaPlayer @CloudIAU
ffmpeg 9e9d67d5489be7403017b9279d33334a03835601 vformat/hls: fix duration
这个提交有一些问题:

        if (c->playlists[minplaylist]->finished) {
            struct playlist *pls = c->playlists[minplaylist];
            int seq_no = pls->cur_seq_no - pls->start_seq_no;
            if (seq_no < pls->n_segments && s->streams[pkt->stream_index]) {
                struct segment *seg = pls->segments[seq_no];
                int64_t pred = av_rescale_q(seg->previous_duration,
                                            AV_TIME_BASE_Q,
                                            s->streams[pkt->stream_index]->time_base);
                int64_t max_ts = av_rescale_q(seg->start_time + seg->duration,
                                              AV_TIME_BASE_Q,
                                              s->streams[pkt->stream_index]->time_base);
                /* EXTINF duration is not precise enough */
                max_ts += 2 * AV_TIME_BASE;
                if (s->start_time > 0) {
                    max_ts += av_rescale_q(s->start_time,
                                           AV_TIME_BASE_Q,
                                           s->streams[pkt->stream_index]->time_base);
                }
                if (pkt->dts != AV_NOPTS_VALUE && pkt->dts + pred < max_ts) pkt->dts += pred;
                if (pkt->pts != AV_NOPTS_VALUE && pkt->pts + pred < max_ts) pkt->pts += pred;
            }
        }

上面这段代码目的是为了在有 #EXT-X-DISCONTINUITY 修复pts,加上 previous_duration。
1,上面修复pts代码应该放在 av_read_frame 后面,即

                ret = av_read_frame(pls->ctx, &pls->pkt);
                if (ret < 0) {
                    if (!avio_feof(&pls->pb) && ret != AVERROR_EOF)
                        return ret;
                    reset_packet(&pls->pkt);
                    break;
                } else {
                    /* stream_index check prevents matching picture attachments etc. */
                    if (pls->is_id3_timestamped && pls->pkt.stream_index == 0) {
                        /* audio elementary streams are id3 timestamped */
                        fill_timing_for_id3_timestamped_stream(pls);
                    }
                    // 修复pts代码应该放在这里,否则 seek 到下一个 #EXT-X-DISCONTINUITY pts 会陷入死循环
                    if (pls->pkt.pts != AV_NOPTS_VALUE)
                        pkt_ts =  pls->pkt.pts;
                    else if (pls->pkt.dts != AV_NOPTS_VALUE)
                        pkt_ts =  pls->pkt.dts;
                    else
                        pkt_ts = AV_NOPTS_VALUE;


                    c->first_timestamp = s->start_time != AV_NOPTS_VALUE ? s->start_time : 0;

                }

                if (pls->seek_timestamp == AV_NOPTS_VALUE)
                    break;
                
                if (pls->seek_stream_index < 0 ||

另外一个问题就是为什么要做这个判断 seq_no < pls->n_segments?
这边测试 发现 seg no 没有对上,看过去像是 pls->cur_seq_no 已经+1, open 了新的 ts文件, 但是 av_read_frame 返回的还是 上一个 ts文件的最后一个包。这个是不是因为 read_data 读取buf 在ffmpeg io 中被缓存了?日志如下:

 E/IJKMEDIA: 6666 pkt->pts=-9223372036854775808, pkt->dts=-9223372036854775808, seq_no=23, previous_duration=300002000,
 E/IJKMEDIA: 6666 pkt->pts=-9223372036854775808, pkt->dts=-9223372036854775808, seq_no=23, previous_duration=300002000,
 E/IJKMEDIA: 6666 pkt->pts=-9223372036854775808, pkt->dts=-9223372036854775808, seq_no=23, previous_duration=300002000,
 E/IJKMEDIA: 6666 pkt->pts=-9223372036854775808, pkt->dts=-9223372036854775808, seq_no=23, previous_duration=300002000,
 E/IJKMEDIA: 6666 pkt->pts=-9223372036854775808, pkt->dts=-9223372036854775808, seq_no=23, previous_duration=300002000,
 E/IJKMEDIA: 6666 cur_seq_no=24
 I/IJKMEDIA: Opening 'http://vipgdbgp.vod.tv.itc.cn/m3u8?&start=0&end=5.32&k=hWODtfkIlB6OWhcsWFvHbD168Vebz89bDEWNoL8VP6kRDEKNPFXUyYbS0pbcWOoGyG
tUJlzSwdoSwdomNGopwGopxVoSrGoSrBhRODOpCCqmvm0pvUhRYRzSwWj9lvzSvUqCPCJSX3Tkk7oL1gqpxmqK3KJvsUTka5qkkBxvqfomkCo
ding
 I/lebotv.danmaku.ijk.media.player.IjkMediaPlayer: onNativeInvoke 1
 I/IJKMEDIA: Hit DNS cache hostname = vipgdbgp.vod.tv.itc.cn
 I/lebotv.danmaku.ijk.media.player.IjkMediaPlayer: onNativeInvoke 131073
 I/lebotv.danmaku.ijk.media.player.IjkMediaPlayer: onNativeInvoke 131074
 I/lebotv.danmaku.ijk.media.player.IjkMediaPlayer: onNativeInvoke 131073
 I/lebotv.danmaku.ijk.media.player.IjkMediaPlayer: onNativeInvoke 131074
 I/lebotv.danmaku.ijk.media.player.IjkMediaPlayer: onNativeInvoke 2

这里刚刚好是遇到#EXT-X-DISCONTINUITY,打开下一个 ts文件
pts 27907200 明显是没有修复成功

 E/IJKMEDIA: 6666 pkt->pts=27907200, pkt->dts=27903600, seq_no=24, previous_duration=600004000,
 E/IJKMEDIA: 6666 pkt->pts=54914760, pkt->dts=54907560, seq_no=24, previous_duration=600004000,
 I/hpplay-java: [main]:PhoenixPlayer:onBufferingUpdate percent: 24
 E/IJKMEDIA: 6666 pkt->pts=54929160, pkt->dts=54911160, seq_no=24, previous_duration=600004000,
 E/IJKMEDIA: 6666 pkt->pts=54921960, pkt->dts=54914760, seq_no=24, previous_duration=600004000,
 E/IJKMEDIA: 6666 pkt->pts=54918360, pkt->dts=54918360, seq_no=24, previous_duration=600004000,
yeshibuzhong

yeshibuzhong commented on Jun 30, 2018

@yeshibuzhong

@drivedreams 你好, 我按照CloudIAU方法, 快进的时候回崩溃掉, 我用的是ijk0.88 最新版, 请问你知道怎么回事吗?
上边有我的崩溃信息

xm2017

xm2017 commented on Oct 18, 2018

@xm2017

@CloudIAU 大佬这段代码有pull 到源码上么

chenzh2017

chenzh2017 commented on Nov 18, 2019

@chenzh2017

各位大佬,这个问题解决了吗,现在测试的情况来看,拖放的时候加载依然缓慢,比mp4格式的拖放要慢很多

longshao1234

longshao1234 commented on Jan 10, 2020

@longshao1234

@chenzh2017,一样的,遇到了,mp4播放不会慢,但是用么m3u8播放就会加长,让后循环播放不得行

shenhuihui

shenhuihui commented on Oct 26, 2020

@shenhuihui

@CloudIAU 按照你的修改后Seek正常了

你好,请问iOS上怎么解决这个问题

nicolasiJasica

nicolasiJasica commented on Apr 6, 2021

@nicolasiJasica

播放M3u8的视频的时候,最好:
1.将max-buffer-size探测的长度尽可能的缩小
2.enable-accurate-seek关闭这个属性

其他的都是用默认配置就好,亲测有效,播放下载的M3u8视频 拖动进度, 效果挺好(大概1-2秒),没那么长的缓冲时间了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @nicolasiJasica@drivedreams@0ct0cat@linjiansheng@dongdong945

        Issue actions

          M3U8分段视频在seekTo的时候需要很长时间才能播放,这时间跟拖动距离有关,怎样才能缩短时间? · Issue #2874 · bilibili/ijkplayer