Skip to content

Commit

Permalink
fix seek;
Browse files Browse the repository at this point in the history
  • Loading branch information
RealChuan committed Sep 4, 2023
1 parent 693690e commit 3477f1a
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 97 deletions.
10 changes: 0 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,6 @@
2. 在WidgetRender中,尽可能使用QImage::Format_RGB32和QImage::Format_ARGB32_Premultiplied图像格式。如下原因:
1. Avoid most rendering directly to most of these formats using QPainter. Rendering is best optimized to the Format_RGB32 and Format_ARGB32_Premultiplied formats, and secondarily for rendering to the Format_RGB16, Format_RGBX8888, Format_RGBA8888_Premultiplied, Format_RGBX64 and Format_RGBA64_Premultiplied formats.

### ``avformat_seek_file``,当seek的时间点小于当前时间点一些时,比如-5秒、-10秒,seek不到目标时间点

#### 有一种解决方法是:先``seek``到0秒,再``seek``到目标时间点。
这个时候-5秒、-10秒的seek,效果非常好,比之前好很多,之前有时候会卡在当前时间点,无法seek到目标时间点。

```C++
formatCtx->seek(0);
formatCtx->seek(position);
```
### Ffmpeg(5.0)在解码字幕与4.4.3不太一样

### 解码字幕(ffmpeg-n5.0):
Expand Down
32 changes: 19 additions & 13 deletions ffmpeg/audioframeconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ AudioFrameConverter::AudioFrameConverter(CodecContext *codecCtx,
channelLayout,
d_ptr->avSampleFormat,
d_ptr->format.sampleRate(),
avCodecCtx->channel_layout,
avCodecCtx->ch_layout.u.mask,
avCodecCtx->sample_fmt,
avCodecCtx->sample_rate,
0,
Expand All @@ -148,25 +148,31 @@ AudioFrameConverter::~AudioFrameConverter()

auto AudioFrameConverter::convert(Frame *frame) -> QByteArray
{
auto nb_samples = frame->avFrame()->nb_samples;
int size = av_samples_get_buffer_size(nullptr,
d_ptr->format.channelCount(),
nb_samples,
d_ptr->avSampleFormat,
0);
auto avFrame = frame->avFrame();
auto nb_samples = avFrame->nb_samples;
auto out_count = (int64_t) nb_samples * d_ptr->format.sampleRate() / avFrame->sample_rate
+ 256; // 256 copy from ffplay
auto size = av_samples_get_buffer_size(nullptr,
d_ptr->format.channelCount(),
out_count,
d_ptr->avSampleFormat,
0);

QByteArray data(size, Qt::Uninitialized);
quint8 *bufPointer[] = {reinterpret_cast<quint8 *>(data.data())};

int len = swr_convert(d_ptr->swrContext,
bufPointer,
nb_samples,
const_cast<const uint8_t **>(frame->avFrame()->data),
nb_samples);
auto len = swr_convert(d_ptr->swrContext,
bufPointer,
out_count,
const_cast<const uint8_t **>(avFrame->extended_data),
nb_samples);
if (len <= 0) {
data.clear();
SET_ERROR_CODE(len);
} else if (len == out_count) {
qWarning() << "audio buffer is probably too small";
}
size = len * d_ptr->format.channelCount() * av_get_bytes_per_sample(d_ptr->avSampleFormat);
data.resize(size);

return data;
}
Expand Down
2 changes: 1 addition & 1 deletion ffmpeg/clock.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Clock::ClockPrivate

static std::atomic<qint64> s_serial;
static std::atomic<double> s_speed;
static constexpr auto s_diffThreshold = 50 * 1000; // 50 milliseconds
static constexpr auto s_diffThreshold = 200 * 1000; // 200 milliseconds
static Clock *s_clock;
};

Expand Down
10 changes: 5 additions & 5 deletions ffmpeg/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace Ffmpeg {

static const auto s_waitQueueEmptyMilliseconds = 50;
static const auto s_frameQueueSize = 15;
static const auto s_frameQueueSize = 25; // for truehd codec, maybe need more, maybe 500

template<typename T>
class Decoder : public QThread
Expand Down Expand Up @@ -50,12 +50,12 @@ class Decoder : public QThread
void append(const T &t)
{
assertVaild();
m_queue.put(t);
m_queue.append(t);
}
void append(T &&t)
{
assertVaild();
m_queue.put(t);
m_queue.append(t);
}

auto size() -> size_t { return m_queue.size(); }
Expand All @@ -65,7 +65,7 @@ class Decoder : public QThread
void wakeup()
{
if (m_queue.empty()) {
m_queue.putHead(T());
m_queue.insertHead(T());
}
}

Expand All @@ -74,7 +74,7 @@ class Decoder : public QThread
if (!m_contextInfo->isIndexVaild()) {
return;
}
m_eventQueue.put(event);
m_eventQueue.append(event);
wakeup();
}

Expand Down
21 changes: 12 additions & 9 deletions ffmpeg/formatcontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class FormatContext::FormatContextPrivate
avformat_network_init();
}

~FormatContextPrivate() {}
~FormatContextPrivate() = default;

void initStreamInfo()
{
Expand Down Expand Up @@ -377,19 +377,22 @@ auto FormatContext::seek(qint64 timestamp) -> bool
Q_ASSERT(d_ptr->formatCtx != nullptr);
Q_ASSERT(timestamp >= 0);
auto seekMin = timestamp - d_ptr->seekOffset;
if (seekMin < 0) {
seekMin = 0;
}
auto seekMax = timestamp + d_ptr->seekOffset;
if (seekMax > d_ptr->formatCtx->duration) {
seekMax = d_ptr->formatCtx->duration;
}
// qDebug() << "seekMin:" << seekMin << "seekMax:" << seekMax << "timestamp:" << timestamp;
auto ret = avformat_seek_file(d_ptr->formatCtx, -1, seekMin, timestamp, seekMax, 0);
ERROR_RETURN(ret)
}

auto FormatContext::seek(int index, qint64 timestamp) -> bool
auto FormatContext::seek(qint64 timestamp, bool forward) -> bool
{
Q_ASSERT(d_ptr->formatCtx != nullptr);
Q_ASSERT(timestamp >= 0);
auto seekMin = forward ? INT64_MIN : timestamp - d_ptr->seekOffset;
auto seekMax = forward ? timestamp + d_ptr->seekOffset : INT64_MAX;
auto ret = avformat_seek_file(d_ptr->formatCtx, -1, seekMin, timestamp, seekMax, 0);
ERROR_RETURN(ret)
}

auto FormatContext::seekFrame(int index, qint64 timestamp) -> bool
{
Q_ASSERT(d_ptr->formatCtx != nullptr);
int ret = av_seek_frame(d_ptr->formatCtx, index, timestamp, AVSEEK_FLAG_BACKWARD);
Expand Down
5 changes: 3 additions & 2 deletions ffmpeg/formatcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ class FFMPEG_EXPORT FormatContext : public QObject
void discardStreamExcluded(QVector<int> indexs);

auto seekFirstFrame() -> bool;
auto seek(qint64 timestamp) -> bool; // microsecond
auto seek(int index, qint64 timestamp) -> bool; // microsecond
auto seek(qint64 timestamp) -> bool;
auto seek(qint64 timestamp, bool forward) -> bool; // microsecond
auto seekFrame(int index, qint64 timestamp) -> bool; // microsecond

auto readFrame(Packet *packet) -> bool;

Expand Down
23 changes: 12 additions & 11 deletions ffmpeg/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ class Player::PlayerPrivate

void addPropertyChangeEventEvent(PropertyChangeEvent *event)
{
propertyChangeEventQueue.put(PropertyChangeEventPtr(event));
propertyChangeEventQueue.append(PropertyChangeEventPtr(event));
while (propertyChangeEventQueue.size() > maxPropertyEventQueueSize.load()) {
propertyChangeEventQueue.take();
}
Expand All @@ -256,7 +256,7 @@ class Player::PlayerPrivate

void addEvent(const EventPtr &eventPtr)
{
eventQueue.put(eventPtr);
eventQueue.append(eventPtr);
while (eventQueue.size() > maxEventQueueSize.load()) {
eventQueue.take();
}
Expand All @@ -266,7 +266,7 @@ class Player::PlayerPrivate
switch (eventPtr->type()) {
case Event::EventType::Pause: break;
default: {
eventQueue.put(EventPtr(new PauseEvent(true)));
eventQueue.append(EventPtr(new PauseEvent(true)));
} break;
}
wakePause();
Expand All @@ -288,7 +288,10 @@ class Player::PlayerPrivate
void processEvent(const EventPtr &eventPtr)
{
switch (eventPtr->type()) {
case Event::EventType::OpenMedia: processOpenMediaEvent(eventPtr); break;
case Event::EventType::OpenMedia:
processCloseMediaEvent();
processOpenMediaEvent(eventPtr);
break;
case Event::EventType::CloseMedia: processCloseMediaEvent(); break;
case Event::EventType::AudioTarck:
case Event::EventType::VideoTrack:
Expand Down Expand Up @@ -345,10 +348,8 @@ class Player::PlayerPrivate
subtitleDecoder->addEvent(eventPtr);
auto position = seekEvent->position();
seekEvent->wait();
// before add this line, seek position less than current position, it wiil not accurate,
// and now first seek to 0, then seek to position, it will be very good
formatCtx->seek(0);
formatCtx->seek(position);

formatCtx->seek(position, position < this->position);
if (audioInfo->isIndexVaild()) {
audioInfo->codecCtx()->flush();
}
Expand Down Expand Up @@ -378,7 +379,7 @@ class Player::PlayerPrivate
} else if (position > q_ptr->duration()) {
position = q_ptr->duration();
}
eventQueue.putHead(EventPtr(new SeekEvent(position)));
eventQueue.insertHead(EventPtr(new SeekEvent(position)));
}

void processGpuEvent(const EventPtr &eventPtr)
Expand All @@ -401,7 +402,7 @@ class Player::PlayerPrivate

q_ptr->addEvent(EventPtr(new CloseMediaEvent));
q_ptr->addEvent(EventPtr(new OpenMediaEvent(filepath)));
eventQueue.putHead(EventPtr(new SeekEvent(position)));
eventQueue.insertHead(EventPtr(new SeekEvent(position)));
}

void processSelectedMediaTrackEvent(const EventPtr &eventPtr)
Expand Down Expand Up @@ -435,7 +436,7 @@ class Player::PlayerPrivate

q_ptr->addEvent(EventPtr(new CloseMediaEvent));
q_ptr->addEvent(EventPtr(new OpenMediaEvent(filepath)));
eventQueue.putHead(EventPtr(new SeekEvent(position)));
eventQueue.insertHead(EventPtr(new SeekEvent(position)));
}

void processOpenMediaEvent(const EventPtr &eventPtr)
Expand Down
45 changes: 23 additions & 22 deletions utils/boundedblockingqueue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

#include <QMutex>
#include <QWaitCondition>
#include <queue>

#include <deque>

namespace Utils {

Expand All @@ -18,49 +19,43 @@ class BoundedBlockingQueue
: m_maxSize(maxSize)
{}

void put(const T &x)
void append(const T &x)
{
QMutexLocker locker(&m_mutex);
while (m_queue.size() >= m_maxSize) {
m_notFull.wait(&m_mutex);
}
m_queue.push(x);
m_queue.push_back(x);
m_notEmpty.wakeOne();
}

void put(T &&x)
void append(T &&x)
{
QMutexLocker locker(&m_mutex);
while (m_queue.size() >= m_maxSize) {
m_notFull.wait(&m_mutex);
}
m_queue.push(std::move(x));
m_queue.push_back(std::move(x));
m_notEmpty.wakeOne();
}

void putHead(const T &x)
void insertHead(const T &x)
{
std::queue<T> temp;
temp.push(x);
QMutexLocker locker(&m_mutex);
while (!m_queue.empty()) {
temp.push(m_queue.front());
m_queue.pop();
while (m_queue.size() >= m_maxSize) {
m_notFull.wait(&m_mutex);
}
m_queue.swap(temp);
m_queue.push_front(x);
m_notEmpty.wakeOne();
}

void putHead(T &&x)
void insertHead(T &&x)
{
std::queue<T> temp;
temp.push(x);
QMutexLocker locker(&m_mutex);
while (!m_queue.empty()) {
temp.push(m_queue.front());
m_queue.pop();
while (m_queue.size() >= m_maxSize) {
m_notFull.wait(&m_mutex);
}
m_queue.swap(temp);
m_queue.push_front(std::move(x));
m_notEmpty.wakeOne();
}

Expand All @@ -71,7 +66,7 @@ class BoundedBlockingQueue
m_notEmpty.wait(&m_mutex);
}
T front(std::move(m_queue.front()));
m_queue.pop();
m_queue.pop_front();
m_notFull.wakeOne();
return front;
}
Expand All @@ -83,7 +78,7 @@ class BoundedBlockingQueue
if (callback != nullptr) {
callback(m_queue.front());
}
m_queue.pop();
m_queue.pop_front();
}
m_notFull.wakeAll();
}
Expand All @@ -106,6 +101,12 @@ class BoundedBlockingQueue
return m_queue.size();
}

void setMaxSize(int maxSize)
{
QMutexLocker locker(&m_mutex);
m_maxSize = maxSize;
}

[[nodiscard]] size_t maxSize() const
{
QMutexLocker locker(&m_mutex);
Expand All @@ -116,7 +117,7 @@ class BoundedBlockingQueue
mutable QMutex m_mutex;
QWaitCondition m_notEmpty;
QWaitCondition m_notFull;
std::queue<T> m_queue;
std::deque<T> m_queue;
int m_maxSize;
};

Expand Down
Loading

0 comments on commit 3477f1a

Please sign in to comment.