引用第39楼novesky于2013-12-15 19:18发表的 回 38楼(carmen816) 的帖子 :
这个还真不知道,为什么要这么做?
不同步音频的话应该同步什么?系统时间?我现在的是有问题,来不及画的就丢掉 

 VideoThread.cpp
        qreal pts = pkt.pts;
        d.delay = pts - d.clock->value();
        /*
         *after seeking forward, a packet may be the old, v packet may be
         *the new packet, then the d.delay is very large, omit it.
         *TODO: 1. how to choose the value
         * 2. use last delay when seeking
        */
        bool skip_render = false;
        if (qAbs(d.delay) < 2.718) {
            if (d.delay < -kSyncThreshold) { //Speed up. drop frame?
                //continue;
            }
            while (d.delay > kSyncThreshold) { //Slow down
                //d.delay_cond.wait(&d.mutex, d.delay*1000); //replay may fail. why?
                //qDebug("~~~~~wating for %f msecs", d.delay*1000);
                usleep(kSyncThreshold * 1000000UL);
                if (d.stop)
                    d.delay = 0;
                else
                    d.delay -= kSyncThreshold;
            }
            if (d.delay > 0)
                usleep(d.delay * 1000000UL);
        } else { //when to drop off?
            qDebug("delay %f/%f", d.delay, d.clock->value());
            if (d.delay > 0) {
                msleep(64);
            } else {
                // FIXME: if continue without decoding, hw decoding may crash, why?
                //audio packet not cleaned up?
                //continue;
                skip_render = true;
            }
        }
        d.clock->updateVideoPts(pts); //here?
        if (d.stop) {
            qDebug("video thread stop before decode()");
            break;
        } 
        if (!dec->decode(pkt.data)) {
            pkt = Packet();
            continue;
        } else {
            int undecoded = dec->undecodedSize();
            if (undecoded > 0) {
                pkt.data.remove(0, pkt.data.size() - undecoded);
            } else {
                pkt = Packet();
            }
        }  
        if (skip_render)
            continue;  
msleep(64); 25帧为例,1000 / 25 = 40,这边的64值得商榷。
您将解码和帧的刷新放在一个线程中,会影响同步。
解码过程消耗时间比较长,而且解码耗时不是个固定值。会影响“与kSyncThreshold比较”。
所以那些播放器会缓冲解码后的原始音视频数据
ffplay中,使用video_thread解码后queue_picture,放入队列。在video_refresh(另一个线程)中刷视频。  
PS:FIXME: if continue without decoding, hw decoding may crash, why?
        软件解码不crash,播放也会出现花屏(或者是黑屏几帧,直到下个I帧出现,看解码器的优化程度)。
        因为视频的解码时,通常解码器会参考上一个包的结果。“hw decoder”或者“hw decoder与ffmpeg之间的连接”写的不健壮那就只能crash了。。。   
AudioThread.cpp
        if (!dec->decode(pkt.data)) {
            qWarning("Decode audio failed");
            qreal dt = pkt.pts - d.last_pts;
            if (dt > 0.618 || dt < 0) {
                dt = 0;
            }
            //qDebug("sleep %f", dt);
            //TODO: avoid acummulative error. External clock?
            msleep((unsigned long)(dt*1000.0));
            pkt = Packet();
            d.last_pts = d.clock->value(); //not pkt.pts! the delay is updated!
            continue;
        }
        QByteArray decoded(dec->data());
        int decodedSize = decoded.size();
        int decodedPos = 0;
        qreal delay =0;
        //AudioFormat.durationForBytes() calculates int type internally. not accurate
        AudioFormat &af = dec->resampler()->inAudioFormat();
        qreal byte_rate = af.bytesPerSecond();
        while (decodedSize > 0) {
            if (d.stop) {
                qDebug("audio thread stop after decode()");
                break;
            }
            int chunk = qMin(decodedSize, int(max_len*byte_rate));
            //AudioFormat.bytesForDuration
            qreal chunk_delay = (qreal)chunk/(qreal)byte_rate;
            pkt.pts += chunk_delay;
            d.clock->updateDelay(delay += chunk_delay); 
AVClock 默认是 ClockType AudioClock
int chunk = qMin(decodedSize, int(max_len*byte_rate)); --->>> 意味着AVClock每0.02秒更新一次。
这导致您设计的AVClock不是线性的,而是离散的(相对视频而言,如果视频帧是30帧,每个视频帧间隔0.033秒,时钟和帧间隔处于同一数量级。。。),造成丢帧。  
不同步音频的话应该同步什么?系统时间?音频时间和系统时间结合。。。
下面文章的方案和ffplay所使用的如出一辙
http://www.rosoo.net/a/201203/15806.html   (三、音视频同步) 
PS:十分惊叹楼主在QT,C++,架构设计等方面的造诣,使我受益匪浅。        再次感谢楼主开源的精神。