Skip to content

Commit

Permalink
Merge branch 'dec'
Browse files Browse the repository at this point in the history
  • Loading branch information
wang-bin committed Nov 20, 2014
2 parents bf7e308 + dd51e3c commit 8630801
Show file tree
Hide file tree
Showing 14 changed files with 401 additions and 35 deletions.
41 changes: 41 additions & 0 deletions src/AVCompat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,44 @@ const char *avcodec_get_name(enum AVCodecID id)
return "unknown_codec";
}
#endif

// since libav-11, ffmpeg-2.1
#if !LIBAV_MODULE_CHECK(LIBAVCODEC, 56, 1, 0) && !FFMPEG_MODULE_CHECK(LIBAVCODEC, 55, 39, 100)
int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
{
dst->pts = src->pts;
dst->dts = src->dts;
dst->pos = src->pos;
dst->duration = src->duration;
dst->convergence_duration = src->convergence_duration;
dst->flags = src->flags;
dst->stream_index = src->stream_index;

for (int i = 0; i < src->side_data_elems; i++) {
enum AVPacketSideDataType type = src->side_data[i].type;
int size = src->side_data[i].size;
uint8_t *src_data = src->side_data[i].data;
uint8_t *dst_data = av_packet_new_side_data(dst, type, size);

if (!dst_data) {
av_packet_free_side_data(dst);
return AVERROR(ENOMEM);
}
memcpy(dst_data, src_data, size);
}

return 0;
}

#endif
// since libav-10, ffmpeg-2.1
#if !LIBAV_MODULE_CHECK(LIBAVCODEC, 55, 34, 1) && !FFMPEG_MODULE_CHECK(LIBAVCODEC, 55, 39, 100)
void av_packet_free_side_data(AVPacket *pkt)
{
for (int i = 0; i < pkt->side_data_elems; ++i)
av_freep(&pkt->side_data[i].data);
av_freep(&pkt->side_data);
pkt->side_data_elems = 0;
}
#endif

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
165 changes: 164 additions & 1 deletion src/Packet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,155 @@
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;

class PacketPrivate : public QSharedData
{
public:
PacketPrivate()
: initialized(false)
{
av_init_packet(&avpkt);
}
~PacketPrivate() {
av_free_packet(&avpkt); // free old side data and ref
}

bool initialized;
AVPacket avpkt;
};

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
pkt->dts = pkt->pts;
//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
pkt->d = QSharedDataPointer<PacketPrivate>(new PacketPrivate());
pkt->d->initialized = true;
AVPacket *p = &pkt->d->avpkt;
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;
return true;
}

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


Packet::Packet(const Packet &other)
: hasKeyFrame(other.hasKeyFrame)
, isCorrupt(other.isCorrupt)
, data(other.data)
, pts(other.pts)
, duration(other.duration)
, dts(other.dts)
, position(other.position)
, d(other.d)
{
}

Packet& Packet::operator =(const Packet& other)
{
if (this == &other)
return *this;
d = other.d;
hasKeyFrame = other.hasKeyFrame;
isCorrupt = other.isCorrupt;
pts = other.pts;
duration = other.duration;
dts = other.dts;
position = other.position;
data = other.data;
return *this;
}

Packet::~Packet()
{
}

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

const AVPacket *Packet::asAVPacket() const
{
if (d.constData()) {
if (d->initialized) //d.data() was 0 if d has not been accessed. now only contains avpkt, check d.constData() is engough
return &d->avpkt;
} else {
d = QSharedDataPointer<PacketPrivate>(new PacketPrivate());
}

d->initialized = true;
AVPacket *p = &d->avpkt;
p->pts = pts * 1000.0;
p->dts = dts * 1000.0;
p->duration = duration * 1000.0;
p->pos = position;
if (isCorrupt)
p->flags |= AV_PKT_FLAG_CORRUPT;
if (hasKeyFrame)
p->flags |= AV_PKT_FLAG_KEY;
if (!data.isEmpty()) {
p->data = (uint8_t*)data.constData();
p->size = data.size();
}
return p;
}

} //namespace QtAV
7 changes: 5 additions & 2 deletions src/QtAV/AVDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include <QtAV/QtAV_Global.h>
#include <QtAV/AVError.h>
#include <QtAV/Packet.h>
#include <QtCore/QVariant>
#include <QtCore/QObject>

Expand All @@ -43,9 +44,10 @@ class Q_AV_EXPORT AVDecoder : public QObject
virtual ~AVDecoder();
virtual QString name() const;
virtual QString description() const;
/*
/*!
* default is open FFmpeg codec context
* codec config must be done before open
* NOTE: open() and close() are not thread safe. You'd better call them in the same thread.
*/
virtual bool open();
virtual bool close();
Expand All @@ -67,7 +69,8 @@ class Q_AV_EXPORT AVDecoder : public QObject
/*not available if AVCodecContext == 0*/
bool isAvailable() const;
virtual bool prepare(); //if resampler or image converter set, call it
virtual bool decode(const QByteArray& encoded) = 0; //decode AVPacket?
QTAV_DEPRECATED virtual bool decode(const QByteArray& encoded) = 0;
virtual bool decode(const Packet& packet) = 0;
QByteArray data() const; //decoded data
int undecodedSize() const;

Expand Down
3 changes: 2 additions & 1 deletion src/QtAV/AudioDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class Q_AV_EXPORT AudioDecoder : public AVDecoder
public:
AudioDecoder();
virtual bool prepare();
virtual bool decode(const QByteArray &encoded);
QTAV_DEPRECATED virtual bool decode(const QByteArray &encoded) Q_DECL_OVERRIDE;
virtual bool decode(const Packet& packet) Q_DECL_OVERRIDE;
AudioResampler *resampler();
};

Expand Down
32 changes: 28 additions & 4 deletions src/QtAV/Packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,52 @@
#ifndef QAV_PACKET_H
#define QAV_PACKET_H

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

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

namespace QtAV {

class PacketPrivate;
class Q_AV_EXPORT Packet
{
public:
static Packet fromAVPacket(const AVPacket* avpkt, double time_base);
static bool fromAVPacket(Packet *pkt, const AVPacket *avpkt, double time_base);

Packet();
~Packet();

// required if no defination of PacketPrivate
Packet(const Packet& other);
Packet& operator =(const Packet& other);

inline bool isValid() const;
inline bool isEnd() const;
void markEnd();
/*!
* \brief asAVPacket
* If Packet is constructed from AVPacket, then data and properties are the same as that AVPacket.
* Otherwise, Packet's data and properties are used and no side data.
* Packet takes the owner ship. time unit is always ms even constructed from AVPacket.
*/
const AVPacket* asAVPacket() 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
// we must define default/copy ctor, dtor and operator= so that we can provide only forward declaration of PacketPrivate
mutable QSharedDataPointer<PacketPrivate> d;
};

bool Packet::isValid() const
Expand Down
3 changes: 2 additions & 1 deletion src/QtAV/VideoDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class Q_AV_EXPORT VideoDecoder : public AVDecoder
virtual QString name() const; //name from factory
//virtual bool prepare();
virtual bool prepare();
virtual bool decode(const QByteArray &encoded);
QTAV_DEPRECATED virtual bool decode(const QByteArray &encoded) Q_DECL_OVERRIDE;
virtual bool decode(const Packet& packet) Q_DECL_OVERRIDE;
virtual VideoFrame frame();
//TODO: new api: originalVideoSize()(inSize()), decodedVideoSize()(outSize())
//size: the decoded(actually then resized in ImageConverter) frame size
Expand Down
9 changes: 9 additions & 0 deletions src/QtAV/private/AVCompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,15 @@ typedef enum CodecID AVCodecID;
const char *avcodec_get_name(enum AVCodecID id);
#endif

// since libav-11, ffmpeg-2.1
#if !LIBAV_MODULE_CHECK(LIBAVCODEC, 56, 1, 0) && !FFMPEG_MODULE_CHECK(LIBAVCODEC, 55, 39, 100)
int av_packet_copy_props(AVPacket *dst, const AVPacket *src);
#endif
// since libav-10, ffmpeg-2.1
#if !LIBAV_MODULE_CHECK(LIBAVCODEC, 55, 34, 1) && !FFMPEG_MODULE_CHECK(LIBAVCODEC, 55, 39, 100)
void av_packet_free_side_data(AVPacket *pkt);
#endif

#ifndef FF_API_OLD_GRAPH_PARSE
#define avfilter_graph_parse_ptr(...) avfilter_graph_parse(__VA_ARGS__)
#endif //FF_API_OLD_GRAPH_PARSE
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
Loading

0 comments on commit 8630801

Please sign in to comment.