引用第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++,架构设计等方面的造诣,使我受益匪浅。 再次感谢楼主开源的精神。