first commit

This commit is contained in:
2026-02-21 17:11:31 +09:00
commit 18b4338361
4001 changed files with 365464 additions and 0 deletions

View 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