mirror of
https://github.com/wang-bin/QtAV.git
synced 2026-10-29 11:36:51 +08:00
Merge branch 'dec'
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QMutexLocker>
|
||||
#include <QtCore/QQueue>
|
||||
#include <QtCore/QWaitCondition>
|
||||
#include "QtAV/Packet.h"
|
||||
#include "utils/BlockingQueue.h"
|
||||
|
||||
+164
-1
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <QtAV/QtAV_Global.h>
|
||||
#include <QtAV/AVError.h>
|
||||
#include <QtAV/Packet.h>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
@@ -43,9 +44,10 @@ public:
|
||||
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();
|
||||
@@ -67,7 +69,8 @@ public:
|
||||
/*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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
+28
-4
@@ -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
|
||||
|
||||
@@ -45,7 +45,8 @@ public:
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "QtAV/VideoFrameExtractor.h"
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QQueue>
|
||||
#include <QtCore/QRunnable>
|
||||
#include <QtCore/QScopedPointer>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
@@ -71,6 +71,33 @@ bool AudioDecoder::prepare()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioDecoder::decode(const Packet &packet)
|
||||
{
|
||||
if (!isAvailable())
|
||||
return false;
|
||||
DPTR_D(AudioDecoder);
|
||||
int ret = avcodec_decode_audio4(d.codec_ctx, d.frame, &d.got_frame_ptr, packet.asAVPacket());
|
||||
d.undecoded_size = qMin(packet.data.size() - ret, packet.data.size());
|
||||
if (ret == AVERROR(EAGAIN)) {
|
||||
return false;
|
||||
}
|
||||
if (ret < 0) {
|
||||
qWarning("[AudioDecoder] %s", av_err2str(ret));
|
||||
return false;
|
||||
}
|
||||
if (!d.got_frame_ptr) {
|
||||
qWarning("[AudioDecoder] got_frame_ptr=false. decoded: %d, un: %d", ret, d.undecoded_size);
|
||||
return true;
|
||||
}
|
||||
d.resampler->setInSampesPerChannel(d.frame->nb_samples);
|
||||
if (!d.resampler->convert((const quint8**)d.frame->extended_data)) {
|
||||
return false;
|
||||
}
|
||||
d.decoded = d.resampler->outData();
|
||||
return true;
|
||||
return !d.decoded.isEmpty();
|
||||
}
|
||||
|
||||
//
|
||||
bool AudioDecoder::decode(const QByteArray &encoded)
|
||||
{
|
||||
@@ -91,7 +118,6 @@ bool AudioDecoder::decode(const QByteArray &encoded)
|
||||
packet.size = encoded.size();
|
||||
packet.data = (uint8_t*)encoded.constData();
|
||||
#endif //NO_PADDING_DATA
|
||||
//TODO: use AVPacket directly instead of Packet?
|
||||
int ret = avcodec_decode_audio4(d.codec_ctx, d.frame, &d.got_frame_ptr, &packet);
|
||||
d.undecoded_size = qMin(encoded.size() - ret, encoded.size());
|
||||
av_free_packet(&packet);
|
||||
|
||||
@@ -77,6 +77,7 @@ bool VideoDecoder::prepare()
|
||||
return AVDecoder::prepare();
|
||||
}
|
||||
|
||||
// always keep the following code
|
||||
//TODO: use ipp, cuda decode and yuv functions. is sws_scale necessary?
|
||||
bool VideoDecoder::decode(const QByteArray &encoded)
|
||||
{
|
||||
@@ -97,9 +98,6 @@ bool VideoDecoder::decode(const QByteArray &encoded)
|
||||
packet.size = encoded.size();
|
||||
packet.data = (uint8_t*)encoded.constData();
|
||||
#endif //NO_PADDING_DATA
|
||||
//TODO: use AVPacket directly instead of Packet?
|
||||
//AVStream *stream = format_context->streams[stream_idx];
|
||||
|
||||
//TODO: some decoders might in addition need other fields like flags&AV_PKT_FLAG_KEY
|
||||
int ret = avcodec_decode_video2(d.codec_ctx, d.frame, &d.got_frame_ptr, &packet);
|
||||
//qDebug("pic_type=%c", av_get_picture_type_char(d.frame->pict_type));
|
||||
@@ -123,6 +121,32 @@ bool VideoDecoder::decode(const QByteArray &encoded)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VideoDecoder::decode(const Packet &packet)
|
||||
{
|
||||
if (!isAvailable())
|
||||
return false;
|
||||
DPTR_D(VideoDecoder);
|
||||
// some decoders might in addition need other fields like flags&AV_PKT_FLAG_KEY
|
||||
int ret = avcodec_decode_video2(d.codec_ctx, d.frame, &d.got_frame_ptr, packet.asAVPacket());
|
||||
//qDebug("pic_type=%c", av_get_picture_type_char(d.frame->pict_type));
|
||||
d.undecoded_size = qMin(packet.data.size() - ret, packet.data.size());
|
||||
if (ret < 0) {
|
||||
qWarning("[VideoDecoder] %s", av_err2str(ret));
|
||||
return false;
|
||||
}
|
||||
if (!d.got_frame_ptr) {
|
||||
qWarning("no frame could be decompressed: %s", av_err2str(ret));
|
||||
return true;
|
||||
}
|
||||
if (!d.codec_ctx->width || !d.codec_ctx->height)
|
||||
return false;
|
||||
//qDebug("codec %dx%d, frame %dx%d", d.codec_ctx->width, d.codec_ctx->height, d.frame->width, d.frame->height);
|
||||
d.width = d.frame->width;
|
||||
d.height = d.frame->height;
|
||||
//avcodec_align_dimensions2(d.codec_ctx, &d.width_align, &d.height_align, aligns);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoDecoder::resizeVideoFrame(const QSize &size)
|
||||
{
|
||||
resizeVideoFrame(size.width(), size.height());
|
||||
@@ -152,6 +176,10 @@ int VideoDecoder::height() const
|
||||
VideoFrame VideoDecoder::frame()
|
||||
{
|
||||
DPTR_D(VideoDecoder);
|
||||
/*qDebug("color space: %d, range: %d, prim: %d, t: %d"
|
||||
, d.codec_ctx->colorspace, d.codec_ctx->color_range
|
||||
, d.codec_ctx->color_primaries, d.codec_ctx->color_trc);
|
||||
*/
|
||||
if (d.width <= 0 || d.height <= 0 || !d.codec_ctx)
|
||||
return VideoFrame(0, 0, VideoFormat(VideoFormat::Format_Invalid));
|
||||
//DO NOT make frame as a memeber, because VideoFrame is explictly shared!
|
||||
@@ -164,6 +192,7 @@ VideoFrame VideoDecoder::frame()
|
||||
frame.setDisplayAspectRatio(displayAspectRatio);
|
||||
frame.setBits(d.frame->data);
|
||||
frame.setBytesPerLine(d.frame->linesize);
|
||||
frame.setTimestamp((double)d.frame->pts/1000.0); // in s
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,8 @@ public:
|
||||
virtual QString description() const;
|
||||
virtual void flush();
|
||||
virtual bool prepare();
|
||||
virtual bool decode(const QByteArray &encoded);
|
||||
QTAV_DEPRECATED bool decode(const QByteArray &encoded) Q_DECL_FINAL;
|
||||
bool decode(const Packet &packet) Q_DECL_FINAL;
|
||||
virtual VideoFrame frame();
|
||||
|
||||
// properties
|
||||
@@ -392,6 +393,47 @@ bool VideoDecoderCUDA::decode(const QByteArray &encoded)
|
||||
// video thread: if dec.hasFrame() keep pkt for the next loop and not decode, direct display the frame
|
||||
}
|
||||
|
||||
bool VideoDecoderCUDA::decode(const Packet &packet)
|
||||
{
|
||||
if (!isAvailable())
|
||||
return false;
|
||||
DPTR_D(VideoDecoderCUDA);
|
||||
if (!d.parser) {
|
||||
qWarning("CUVID parser not ready");
|
||||
return false;
|
||||
}
|
||||
uint8_t *outBuf = 0;
|
||||
int outBufSize = 0;
|
||||
// h264_mp4toannexb_filter does not use last parameter 'keyFrame', so just set 0
|
||||
//return: 0: not changed, no outBuf allocated. >0: ok. <0: fail
|
||||
int filtered = av_bitstream_filter_filter(d.bitstream_filter_ctx, d.codec_ctx, NULL, &outBuf, &outBufSize
|
||||
, (const uint8_t*)packet.data.constData(), packet.data.size()
|
||||
, 0);//d.is_keyframe);
|
||||
//qDebug("%s @%d filtered=%d outBuf=%p, outBufSize=%d", __FUNCTION__, __LINE__, filtered, outBuf, outBufSize);
|
||||
if (filtered < 0) {
|
||||
qDebug("failed to filter: %s", av_err2str(filtered));
|
||||
}
|
||||
|
||||
CUVIDSOURCEDATAPACKET cuvid_pkt;
|
||||
memset(&cuvid_pkt, 0, sizeof(CUVIDSOURCEDATAPACKET));
|
||||
cuvid_pkt.payload = outBuf;// (unsigned char *)packet.data.constData();
|
||||
cuvid_pkt.payload_size = outBufSize; //packet.data.size();
|
||||
// TODO: other flags
|
||||
if (packet.pts >= 0.0) {
|
||||
cuvid_pkt.flags = CUVID_PKT_TIMESTAMP;
|
||||
cuvid_pkt.timestamp = packet.pts * 1000.0; // TODO: 10MHz?
|
||||
}
|
||||
//TODO: fill NALU header for h264? https://devtalk.nvidia.com/default/topic/515571/what-the-data-format-34-cuvidparsevideodata-34-can-accept-/
|
||||
d.doParseVideoData(&cuvid_pkt);
|
||||
if (filtered > 0) {
|
||||
av_freep(&outBuf);
|
||||
}
|
||||
// callbacks are in the same thread as this. so no queue is required?
|
||||
//qDebug("frame queue size on decode: %d", d.frame_queue.size());
|
||||
return !d.frame_queue.isEmpty();
|
||||
// video thread: if dec.hasFrame() keep pkt for the next loop and not decode, direct display the frame
|
||||
}
|
||||
|
||||
VideoFrame VideoDecoderCUDA::frame()
|
||||
{
|
||||
DPTR_D(VideoDecoderCUDA);
|
||||
@@ -698,6 +740,7 @@ bool VideoDecoderCUDAPrivate::processDecodedData(CUVIDPARSERDISPINFO *cuviddisp,
|
||||
VideoFrame frame(codec_ctx->width, codec_ctx->height, VideoFormat::Format_NV12);
|
||||
frame.setBits(planes);
|
||||
frame.setBytesPerLine(pitches);
|
||||
frame.setTimestamp((double)cuviddisp->timestamp/1000.0);
|
||||
//TODO: is clone required? may crash on clone, I should review clone()
|
||||
//frame = frame.clone();
|
||||
if (outFrame) {
|
||||
|
||||
@@ -303,7 +303,8 @@ public:
|
||||
return "Allwinner CedarX video hardware acceleration";
|
||||
}
|
||||
bool prepare();
|
||||
bool decode(const QByteArray &encoded);
|
||||
bool decode(const QByteArray &encoded) Q_DECL_FINAL;
|
||||
bool decode(const Packet& packet) Q_DECL_FINAL;
|
||||
VideoFrame frame();
|
||||
|
||||
//properties
|
||||
@@ -434,30 +435,21 @@ bool VideoDecoderCedarv::decode(const QByteArray &encoded)
|
||||
{
|
||||
DPTR_D(VideoDecoderCedarv);
|
||||
|
||||
if (encoded.isEmpty())
|
||||
return true;
|
||||
//d.cedarv->ioctrl(d.cedarv, CEDARV_COMMAND_JUMP, 0);
|
||||
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
packet.size = encoded.size();
|
||||
packet.data = (uint8_t*)encoded.constData();
|
||||
|
||||
|
||||
if (packet.size == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 bufsize0, bufsize1;
|
||||
u8 *buf0, *buf1;
|
||||
|
||||
if (d.cedarv->request_write(d.cedarv, packet.size, &buf0, &bufsize0, &buf1, &bufsize1) >= 0) {
|
||||
memcpy(buf0, packet.data, bufsize0);
|
||||
if ((u32)packet.size > bufsize0) {
|
||||
memcpy(buf1, packet.data + bufsize0, bufsize1);
|
||||
if (d.cedarv->request_write(d.cedarv, encoded.size(), &buf0, &bufsize0, &buf1, &bufsize1) >= 0) {
|
||||
memcpy(buf0, encoded.constData(), bufsize0);
|
||||
if ((u32)encoded.size() > bufsize0) {
|
||||
memcpy(buf1, encoded.constData() + bufsize0, bufsize1);
|
||||
}
|
||||
cedarv_stream_data_info_t stream_data_info;
|
||||
stream_data_info.type = 0;
|
||||
stream_data_info.lengh = packet.size;
|
||||
stream_data_info.pts = packet.pts;
|
||||
stream_data_info.lengh = encoded.size();
|
||||
stream_data_info.pts = 0; //packet.pts;
|
||||
stream_data_info.flags = CEDARV_FLAG_FIRST_PART | CEDARV_FLAG_LAST_PART | CEDARV_FLAG_PTS_VALID;
|
||||
d.cedarv->update_data(d.cedarv, &stream_data_info);
|
||||
if (d.cedarv->decode(d.cedarv) >= 0 && !d.cedarv->display_request(d.cedarv, &d.cedarPicture)) {
|
||||
@@ -472,6 +464,39 @@ bool VideoDecoderCedarv::decode(const QByteArray &encoded)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VideoDecoderCedarv::decode(const Packet &packet)
|
||||
{
|
||||
DPTR_D(VideoDecoderCedarv);
|
||||
|
||||
if (packet.data.isEmpty())
|
||||
return true;
|
||||
//d.cedarv->ioctrl(d.cedarv, CEDARV_COMMAND_JUMP, 0);
|
||||
u32 bufsize0, bufsize1;
|
||||
u8 *buf0, *buf1;
|
||||
|
||||
if (d.cedarv->request_write(d.cedarv, packet.data.size(), &buf0, &bufsize0, &buf1, &bufsize1) >= 0) {
|
||||
memcpy(buf0, packet.data.constData(), bufsize0);
|
||||
if ((u32)packet.data.size() > bufsize0) {
|
||||
memcpy(buf1, packet.data.constData() + bufsize0, bufsize1);
|
||||
}
|
||||
cedarv_stream_data_info_t stream_data_info;
|
||||
stream_data_info.type = 0; // TODO
|
||||
stream_data_info.lengh = packet.data.size();
|
||||
stream_data_info.pts = packet.pts;
|
||||
stream_data_info.flags = CEDARV_FLAG_FIRST_PART | CEDARV_FLAG_LAST_PART | CEDARV_FLAG_PTS_VALID;
|
||||
d.cedarv->update_data(d.cedarv, &stream_data_info);
|
||||
if (d.cedarv->decode(d.cedarv) >= 0 && !d.cedarv->display_request(d.cedarv, &d.cedarPicture)) {
|
||||
}
|
||||
else {
|
||||
if (d.cedarPicture.id) {
|
||||
d.cedarv->display_release(d.cedarv, d.cedarPicture.id);
|
||||
d.cedarPicture.id = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
VideoFrame VideoDecoderCedarv::frame()
|
||||
{
|
||||
@@ -505,10 +530,9 @@ VideoFrame VideoDecoderCedarv::frame()
|
||||
pi_pitch[1] = bitsPerLine_Y / 2;
|
||||
pi_pitch[2] = bitsPerLine_Y / 2;
|
||||
VideoFrame frame = VideoFrame(buf, d.cedarPicture.width, d.cedarPicture.height, VideoFormat(VideoFormat::Format_YUV420P));
|
||||
|
||||
frame.setBits(pp_plane);
|
||||
frame.setBytesPerLine(pi_pitch);
|
||||
|
||||
// TODO: timestamp
|
||||
d.cedarv->display_release(d.cedarv, d.cedarPicture.id);
|
||||
d.cedarPicture.id = 0;
|
||||
return frame;
|
||||
|
||||
@@ -75,7 +75,7 @@ static int ffmpeg_get_va_buffer2(struct AVCodecContext *ctx, AVFrame *frame, int
|
||||
ffmpeg_release_va_buffer2(ref, frame->data[0]);
|
||||
return -1;
|
||||
}
|
||||
Q_ASSERT(frame->data[0] != NULL);
|
||||
Q_ASSERT(frame->data[0] != NULL); // FIXME: VDA may crash in debug mode
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user