Merge branch 'dec'

This commit is contained in:
wang-bin
2014-11-20 14:45:04 +08:00
14 changed files with 401 additions and 35 deletions
+41
View File
@@ -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
View File
@@ -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
View File
@@ -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
+5 -2
View File
@@ -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;
+2 -1
View File
@@ -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
View File
@@ -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
+2 -1
View File
@@ -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
+9
View File
@@ -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
View File
@@ -1,5 +1,6 @@
#include "QtAV/VideoFrameExtractor.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QQueue>
#include <QtCore/QRunnable>
#include <QtCore/QScopedPointer>
#include <QtCore/QStringList>
+27 -1
View File
@@ -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);
+32 -3
View File
@@ -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;
}
+44 -1
View File
@@ -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) {
+44 -20
View File
@@ -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;
+1 -1
View File
@@ -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