MP4点播精准SEEK功能

借助ZLMediaKit配合;功能流程如下

 

涉及到的代码功能:

1、ZLM是支持更新时钟读取MP4数据的;修改成多文件连续读取即可

uint32_t getCurrentStamp() {
    return (uint32_t)(_seek_to【seek的那个P帧的时间戳】 + !_paused * _speed * _seek_ticker.elapsedTime());
}

-----------------------------
void MP4Reader::startReadMP4(uint64_t sample_ms, bool ref_self, bool file_repeat) {
    GET_CONFIG(uint32_t, sampleMS, Record::kSampleMS);
    auto strong_self = shared_from_this();
    if (_muxer) {
        //一直读到所有track就绪为止
        while (!_muxer->isAllTrackReady() && readNextSample());
        //注册后再切换OwnerPoller
        _muxer->setMediaListener(strong_self);
    }

    auto timer_sec = (sample_ms ? sample_ms : sampleMS) / 1000.0f;

    //启动定时器
    if (ref_self) {
        _timer = std::make_shared<Timer>(timer_sec, [strong_self]() {
            lock_guard<recursive_mutex> lck(strong_self->_mtx);
            return strong_self->readSample();//需要做一点修改,能连续都多个文件,而不是读完一个文件就结束
        }, _poller);
    } else {
        weak_ptr<MP4Reader> weak_self = strong_self;
        _timer = std::make_shared<Timer>(timer_sec, [weak_self]() {
            auto strong_self = weak_self.lock();
            if (!strong_self) {
                return false;
            }
            lock_guard<recursive_mutex> lck(strong_self->_mtx);
            return strong_self->readSample();
        }, _poller);
    }

    _file_repeat = file_repeat;
}

 

2、借助老陈的media -server。修改成前向查找GOP

3、播放端要注意:

  3.1:SEEk前,暂停播放器解析,解码,渲染线程;清空解析,解码,渲染缓冲,避免seek后播放一段缓冲部分数据在播放SEEk;设置显示标记,和显示起始位置

      不同播放器,内部线程不一样,但是一般解码和渲染肯定是生产者消费者,解析和解码可能共用一条线程,音视频解码有各自不同的线程(避免解码阻塞)

       3.2:恢复解析解码渲染线程;根据设置的显示标记,flag=精准SEEk,等解码输出到设置的SEEk位置(时间)才输出给渲染线程,其他的直接解码后丢掉;开始播放;

 

static int mov_stss_seek(struct mov_track_t* track, int64_t *timestamp)
{
    int64_t clock;
    size_t start, end, mid;
    size_t idx, prev, next;
    struct mov_sample_t* sample;

    idx = mid = start = 0;
    end = track->stbl.stss_count;
    assert(track->stbl.stss_count > 0);
    clock = *timestamp * track->mdhd.timescale / 1000; // mvhd timescale

    while (start < end)
    {
        mid = (start + end) / 2;
        idx = track->stbl.stss[mid];

        if (idx < 1 || idx > track->sample_count)
        {
            // start from 1
            assert(0);
            return -1;
        }
        idx -= 1;
        sample = &track->samples[idx];
        
        if (sample->dts > clock)
            end = mid;
        else if (sample->dts < clock)
            start = mid + 1;
        else
            break;
    }

    prev = track->stbl.stss[mid > 0 ? mid - 1 : mid] - 1;
    next = track->stbl.stss[mid + 1 < track->stbl.stss_count ? mid + 1 : mid] - 1;
    /*if (DIFF(track->samples[prev].dts, clock) < DIFF(track->samples[idx].dts, clock))
        idx = prev;
    if (DIFF(track->samples[next].dts, clock) < DIFF(track->samples[idx].dts, clock))
        idx = next;*/
    if (DIFF(track->samples[prev].dts, clock) < DIFF(track->samples[next].dts, clock))
    {
        idx = prev;
    } *timestamp = track->samples[idx].dts * 1000 / track->mdhd.timescale;
    track->sample_offset = idx;
    return 0;
}

 

posted on 2024-05-23 10:04  邗影  阅读(96)  评论(0编辑  收藏  举报

导航