Skip to content

Commit

Permalink
store dts, position and AVPacket* in Packet
Browse files Browse the repository at this point in the history
  • Loading branch information
wang-bin committed Nov 18, 2014
1 parent 3e8e133 commit 7c372e6
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/AVThread_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include <QtCore/QMutex>
#include <QtCore/QMutexLocker>
#include <QtCore/QQueue>
#include <QtCore/QWaitCondition>
#include "QtAV/Packet.h"
#include "utils/BlockingQueue.h"
Expand Down
164 changes: 163 additions & 1 deletion src/Packet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,160 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
******************************************************************************/

#include <QtAV/Packet.h>
#include "QtAV/Packet.h"
#include "QtAV/private/AVCompat.h"
#include "utils/Logger.h"

namespace QtAV {

const qreal Packet::kEndPts = -0.618;

Packet Packet::fromAVPacket(const AVPacket *avpkt, double time_base)
{
Packet pkt;
if (fromAVPacket(&pkt, avpkt, time_base))
return pkt;
return Packet();
}

// time_base: av_q2d(format_context->streams[stream_idx]->time_base)
bool Packet::fromAVPacket(Packet* pkt, const AVPacket *avpkt, double time_base)
{
if (!pkt || !avpkt)
return false;

pkt->position = avpkt->pos;
pkt->hasKeyFrame = !!(avpkt->flags & AV_PKT_FLAG_KEY);
// what about marking avpkt as invalid and do not use isCorrupt?
pkt->isCorrupt = !!(avpkt->flags & AV_PKT_FLAG_CORRUPT);
if (pkt->isCorrupt)
qDebug("currupt packet. pts: %f", pkt->pts);

if (avpkt->pts != AV_NOPTS_VALUE)
pkt->pts = avpkt->pts * time_base;
else if (avpkt->dts != AV_NOPTS_VALUE) // is it ok?
pkt->pts = avpkt->dts * time_base;
else
pkt->pts = 0; // TODO: init value
if (avpkt->dts != AV_NOPTS_VALUE) //has B-frames
pkt->dts = avpkt->dts * time_base;
else if (avpkt->pts != AV_NOPTS_VALUE) // is it ok?
pkt->dts = avpkt->pts * time_base;
else
pkt->dts = 0; // TODO: init value
//TODO: pts must >= 0? look at ffplay
pkt->pts = qMax<qreal>(0, pkt->pts);
pkt->dts = qMax<qreal>(0, pkt->dts);


// subtitle always has a key frame? convergence_duration may be 0
if (avpkt->convergence_duration > 0 // mpv demux_lavf only check this
&& pkt->hasKeyFrame
#if 0
&& codec->codec_type == AVMEDIA_TYPE_SUBTITLE
#endif
)
pkt->duration = avpkt->convergence_duration * time_base;
else if (avpkt->duration > 0)
pkt->duration = avpkt->duration * time_base;
else
pkt->duration = 0;

//qDebug("AVPacket.pts=%f, duration=%f, dts=%lld", pkt->pts, pkt->duration, packet.dts);
#if NO_PADDING_DATA
pkt->data.clear();
if (avpkt->data)
pkt->data = QByteArray((const char*)avpkt->data, avpkt->size);
#else
/*!
larger than the actual read bytes because some optimized bitstream readers read 32 or 64 bits at once and could read over the end.
The end of the input buffer avpkt->data should be set to 0 to ensure that no overreading happens for damaged MPEG streams
*/
QByteArray encoded;
if (avpkt->data) {
encoded.reserve(avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
encoded.resize(avpkt->size);
// also copy padding data(usually 0)
memcpy(encoded.data(), avpkt->data, encoded.capacity()); // encoded.capacity() is always > 0 even if packet.data, so must check avpkt->data null
}
pkt->data = encoded;
#endif //NO_PADDING_DATA

// TODO: pkt->avpkt. data is not necessary now. see mpv new_demux_packet_from_avpacket
// copy properties and side data. does not touch data, size and ref
// libav has no av_copy_packet_side_data() in public api
AVPacket *p = new AVPacket();
av_init_packet(p);
av_packet_copy_props(p, avpkt);
if (!pkt->data.isEmpty()) {
p->data = (uint8_t*)pkt->data.constData();
p->size = pkt->data.size();
}
// QtAV always use ms (1/1000s) and s. As a result no time_base is required in Packet
p->pts = pkt->pts * 1000.0;
p->dts = pkt->dts * 1000.0;
p->duration = pkt->duration * 1000.0;
pkt->avpkt = p;
return true;
}

Packet::Packet()
: hasKeyFrame(false)
, isCorrupt(false)
, pts(0)
, duration(0)
, dts(0)
, position(0)
, avpkt(0)
{
}

Packet::Packet(const Packet &other)
{
if (this == &other)
return;
hasKeyFrame = other.hasKeyFrame;
isCorrupt = other.isCorrupt;
pts = other.pts;
duration = other.duration;
dts = other.dts;
position = other.position;
data = other.data;
avpkt = new AVPacket();
av_init_packet(avpkt);
av_packet_copy_props(avpkt, other.toAVPacket());
}

Packet& Packet::operator =(const Packet& other)
{
if (this == &other)
return *this;
hasKeyFrame = other.hasKeyFrame;
isCorrupt = other.isCorrupt;
pts = other.pts;
duration = other.duration;
dts = other.dts;
position = other.position;
data = other.data;
if (!avpkt) {
avpkt = new AVPacket();
av_init_packet(avpkt);
} else {
av_free_packet(avpkt); // free old side data and ref
}
av_packet_copy_props(avpkt, other.toAVPacket());
return *this;
}

Packet::~Packet()
{
if (avpkt) {
// only free side data and ref, does not release data
av_free_packet(avpkt);

delete avpkt;
avpkt = 0;
}
}

void Packet::markEnd()
Expand All @@ -40,4 +181,25 @@ void Packet::markEnd()
pts = kEndPts;
}

AVPacket* Packet::toAVPacket() const
{
if (avpkt)
return avpkt;

avpkt = new AVPacket();
av_init_packet(avpkt);
avpkt->pts = pts * 1000.0;
avpkt->dts = dts * 1000.0;
avpkt->duration = duration * 1000.0;
if (isCorrupt)
avpkt->flags |= AV_PKT_FLAG_CORRUPT;
if (hasKeyFrame)
avpkt->flags |= AV_PKT_FLAG_KEY;
if (!data.isEmpty()) {
avpkt->data = (uint8_t*)data.constData();
avpkt->size = data.size();
}
return avpkt;
}

} //namespace QtAV
24 changes: 20 additions & 4 deletions src/QtAV/Packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,44 @@
#ifndef QAV_PACKET_H
#define QAV_PACKET_H

#include <queue>
#include <QtCore/QByteArray>
#include <QtCore/QQueue>
#include <QtCore/QMutex>
#include <QtAV/QtAV_Global.h>

//TODO: init from AVPacket and store ptr?
struct AVPacket;

namespace QtAV {

class Q_AV_EXPORT Packet
{
public:
//const avpkt? if no use ref
static Packet fromAVPacket(const AVPacket* avpkt, double time_base);
static bool fromAVPacket(Packet *pkt, const AVPacket *avpkt, double time_base);

Packet();
Packet(const Packet& other);
~Packet();

Packet& operator =(const Packet& other);

inline bool isValid() const;
inline bool isEnd() const;
void markEnd();
/// Packet takes the owner ship. time unit is ms
AVPacket* toAVPacket() const;

bool hasKeyFrame;
bool isCorrupt;
QByteArray data;
// time unit is s.
qreal pts, duration;
qreal dts;
qint64 position; // position in source file byte stream

private:
static const qreal kEndPts;
// TODO: implicity shared. can not use QSharedData
mutable AVPacket *avpkt;
};

bool Packet::isValid() const
Expand Down
1 change: 1 addition & 0 deletions src/VideoFrameExtractor.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "QtAV/VideoFrameExtractor.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QQueue>
#include <QtCore/QRunnable>
#include <QtCore/QScopedPointer>
#include <QtCore/QStringList>
Expand Down

0 comments on commit 7c372e6

Please sign in to comment.