first commit
This commit is contained in:
254
project/fm_viewer/fav/VideoDecoderFFmpegBase.cpp
Normal file
254
project/fm_viewer/fav/VideoDecoderFFmpegBase.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2014)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
|
||||
#include "VideoDecoderFFmpegBase.h"
|
||||
#include "Packet.h"
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
namespace FAV {
|
||||
|
||||
extern ColorSpace colorSpaceFromFFmpeg(AVColorSpace cs);
|
||||
extern ColorRange colorRangeFromFFmpeg(AVColorRange cr);
|
||||
|
||||
static void SetColorDetailsByFFmpeg(VideoFrame *f, AVFrame* frame, AVCodecContext* codec_ctx)
|
||||
{
|
||||
ColorSpace cs = colorSpaceFromFFmpeg(av_frame_get_colorspace(frame));
|
||||
if (cs == ColorSpace_Unknown)
|
||||
{
|
||||
cs = colorSpaceFromFFmpeg(codec_ctx->colorspace);
|
||||
}
|
||||
f->setColorSpace(cs);
|
||||
ColorRange cr = colorRangeFromFFmpeg(av_frame_get_color_range(frame));
|
||||
if (cr == ColorRange_Unknown)
|
||||
{
|
||||
// check yuvj format. TODO: deprecated, check only for old ffmpeg?
|
||||
const AVPixelFormat pixfmt = ((AVPixelFormat)frame->format) == AV_PIX_FMT_NONE ? ((AVPixelFormat)codec_ctx->pix_fmt) : ((AVPixelFormat)frame->format);
|
||||
switch (pixfmt) {
|
||||
//case QTAV_PIX_FMT_C(YUVJ411P): //not in ffmpeg<2 and libav
|
||||
case QTAV_PIX_FMT_C(YUVJ420P):
|
||||
case QTAV_PIX_FMT_C(YUVJ422P):
|
||||
case QTAV_PIX_FMT_C(YUVJ440P):
|
||||
case QTAV_PIX_FMT_C(YUVJ444P):
|
||||
cr = ColorRange_Full;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cr == ColorRange_Unknown)
|
||||
{
|
||||
cr = colorRangeFromFFmpeg(codec_ctx->color_range);
|
||||
if (cr == ColorRange_Unknown)
|
||||
{
|
||||
if (f->format().isXYZ())
|
||||
{
|
||||
cr = ColorRange_Full;
|
||||
cs = ColorSpace_XYZ; // not here
|
||||
}
|
||||
else if (!f->format().isRGB())
|
||||
{
|
||||
// qDebug("prefer limited yuv range");
|
||||
cr = ColorRange_Limited;
|
||||
}
|
||||
}
|
||||
}
|
||||
f->setColorRange(cr);
|
||||
}
|
||||
|
||||
void VideoDecoderFFmpegBasePrivate::updateColorDetails(VideoFrame *f)
|
||||
{
|
||||
if (f->format().pixelFormatFFmpeg() == frame->format)
|
||||
{
|
||||
SetColorDetailsByFFmpeg(f, frame, codec_ctx);
|
||||
return;
|
||||
}
|
||||
// hw decoder output frame may have a different format, e.g. gl interop frame may have rgb format for rendering(stored as yuv)
|
||||
const bool rgb_frame = f->format().isRGB();
|
||||
if (rgb_frame)
|
||||
{
|
||||
//qDebug("rgb output frame (yuv coded)");
|
||||
f->setColorSpace(f->format().isPlanar() ? ColorSpace_GBR : ColorSpace_RGB);
|
||||
f->setColorRange(ColorRange_Full);
|
||||
return;
|
||||
}
|
||||
// yuv frame. When happens?
|
||||
const bool rgb_coded = (av_pix_fmt_desc_get(codec_ctx->pix_fmt)->flags & AV_PIX_FMT_FLAG_RGB) == AV_PIX_FMT_FLAG_RGB;
|
||||
if (rgb_coded)
|
||||
{
|
||||
if (f->width() >= 1280 && f->height() >= 576)
|
||||
{
|
||||
f->setColorSpace(ColorSpace_BT709);
|
||||
}
|
||||
else
|
||||
{
|
||||
f->setColorSpace(ColorSpace_BT601);
|
||||
}
|
||||
f->setColorRange(ColorRange_Limited);
|
||||
} else {
|
||||
SetColorDetailsByFFmpeg(f, frame, codec_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
qreal VideoDecoderFFmpegBasePrivate::getDAR(AVFrame *f)
|
||||
{
|
||||
// lavf 54.5.100 av_guess_sample_aspect_ratio: stream.sar > frame.sar
|
||||
qreal dar = 0;
|
||||
if (f->height > 0)
|
||||
{
|
||||
dar = (qreal)f->width/(qreal)f->height;
|
||||
}
|
||||
// prefer sar from AVFrame if sar != 1/1
|
||||
if (f->sample_aspect_ratio.num > 1)
|
||||
{
|
||||
dar *= av_q2d(f->sample_aspect_ratio);
|
||||
}
|
||||
else if (codec_ctx && codec_ctx->sample_aspect_ratio.num > 1) // skip 1/1
|
||||
{
|
||||
dar *= av_q2d(codec_ctx->sample_aspect_ratio);
|
||||
}
|
||||
return dar;
|
||||
}
|
||||
|
||||
VideoDecoderFFmpegBase::VideoDecoderFFmpegBase(VideoDecoderFFmpegBasePrivate &d):
|
||||
VideoDecoder(d)
|
||||
{
|
||||
}
|
||||
#if (PLAY_SYNC_FIX2)
|
||||
bool VideoDecoderFFmpegBase::send(const Packet* packet) {
|
||||
if (!isAvailable())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DPTR_D(VideoDecoderFFmpegBase);
|
||||
|
||||
int ret = 0;
|
||||
if(packet == NULL) {
|
||||
ret = avcodec_send_packet(d.codec_ctx,NULL);
|
||||
} else {
|
||||
if (packet->isEOF())
|
||||
{
|
||||
AVPacket eofpkt;
|
||||
av_init_packet(&eofpkt);
|
||||
eofpkt.data = NULL;
|
||||
eofpkt.size = 0;
|
||||
ret = avcodec_send_packet(d.codec_ctx,&eofpkt);
|
||||
//qInfo() << "SEND EOF PACKET" << ret << __FUNCTION__;
|
||||
}
|
||||
else
|
||||
{
|
||||
AVPacket* avpacket = (AVPacket*)packet->asAVPacket();
|
||||
ret = avcodec_send_packet(d.codec_ctx,avpacket);
|
||||
}
|
||||
}
|
||||
return (ret == 0);
|
||||
}
|
||||
bool VideoDecoderFFmpegBase::receive() {
|
||||
DPTR_D(VideoDecoderFFmpegBase);
|
||||
int ret = avcodec_receive_frame(d.codec_ctx,d.frame);
|
||||
if (!d.codec_ctx->width || !d.codec_ctx->height)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
d.width = d.frame->width;
|
||||
d.height = d.frame->height;
|
||||
// if(ret != 0) {
|
||||
// qInfo() << "RECEVIE ERROR" << ret << __FUNCTION__;
|
||||
// }
|
||||
return (ret == 0);
|
||||
}
|
||||
#endif // PLAY_SYNC_FIX2
|
||||
bool VideoDecoderFFmpegBase::decode(const Packet &packet)
|
||||
{
|
||||
if (!isAvailable())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DPTR_D(VideoDecoderFFmpegBase);
|
||||
|
||||
// some decoders might need other fields like flags&AV_PKT_FLAG_KEY
|
||||
// const AVPacket*: ffmpeg >= 1.0. no libav
|
||||
int got_frame_ptr = 0;
|
||||
int ret = 0;
|
||||
if (packet.isEOF())
|
||||
{
|
||||
AVPacket eofpkt;
|
||||
av_init_packet(&eofpkt);
|
||||
eofpkt.data = NULL;
|
||||
eofpkt.size = 0;
|
||||
ret = avcodec_decode_video2(d.codec_ctx, d.frame, &got_frame_ptr, &eofpkt);
|
||||
}
|
||||
else
|
||||
{
|
||||
AVPacket* avpacket = (AVPacket*)packet.asAVPacket();
|
||||
ret = avcodec_decode_video2(d.codec_ctx, d.frame, &got_frame_ptr, avpacket);
|
||||
if(got_frame_ptr == 0)
|
||||
{
|
||||
// av_free_packet(avpacket);
|
||||
}
|
||||
#if (DEBUG_PLAYER_AVPACKET)
|
||||
|
||||
qInfo() << "---------------------------------------------------" <<
|
||||
"\ngot_frame_ptr:" << got_frame_ptr <<
|
||||
"\nstream:" << avpacket->stream_index <<
|
||||
"\ndts:" << avpacket->dts <<
|
||||
"\npts:" << avpacket->pts <<
|
||||
"\nduration:" << avpacket->duration;
|
||||
#endif
|
||||
}
|
||||
|
||||
//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("[VideoDecoderFFmpegBase] %s", av_err2str(ret));
|
||||
return false;
|
||||
}
|
||||
if (!got_frame_ptr)
|
||||
{
|
||||
#if (DEBUG_PLAYER_AVPACKET)
|
||||
qInfo() << "packet.data.size()" << packet.data.size() <<
|
||||
"ret" << ret <<
|
||||
"undecoded_size:" << d.undecoded_size;
|
||||
#endif
|
||||
|
||||
#if (SKIP_FIRST_CORRUPT_FRAME)
|
||||
return false;
|
||||
#else
|
||||
qWarning("no frame could be decompressed: %s %d/%d", av_err2str(ret), d.undecoded_size, packet.data.size());
|
||||
return !packet.isEOF();
|
||||
#endif
|
||||
}
|
||||
if (!d.codec_ctx->width || !d.codec_ctx->height)
|
||||
{
|
||||
// qWarning("codec width height 0");
|
||||
return false;
|
||||
}
|
||||
d.width = d.frame->width; // TODO: remove? used in hwdec
|
||||
d.height = d.frame->height;
|
||||
//avcodec_align_dimensions2(d.codec_ctx, &d.width_align, &d.height_align, aligns);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} //namespace FAV
|
||||
Reference in New Issue
Block a user