Skip to content

Commit

Permalink
venc: check requested pixel format. try input format in hw enc
Browse files Browse the repository at this point in the history
vaapi seems only support nv12 input. how libyami encodes yuv420p?
  • Loading branch information
wang-bin committed Sep 11, 2016
1 parent 8a3adac commit 568f8c7
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 21 deletions.
7 changes: 5 additions & 2 deletions src/QtAV/VideoEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,13 @@ class Q_AV_EXPORT VideoEncoder : public AVEncoder
static qreal defaultFrameRate() { return 25;}
/*!
* \brief setPixelFormat
* If not set or set to an invalid format, a supported format will be used and pixelFormat() will be that format after open()
* \param format
* If not set or set to an unsupported format, a supported format will be used and pixelFormat() will be that format after open()
*/
void setPixelFormat(const VideoFormat::PixelFormat format);
/*!
* \brief pixelFormat
* \return user requested format. may be different with actually used format
*/
VideoFormat::PixelFormat pixelFormat() const;
// TODO: supportedPixelFormats() const;
Q_SIGNALS:
Expand Down
56 changes: 37 additions & 19 deletions src/codec/video/VideoEncoderFFmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,18 +137,18 @@ bool VideoEncoderFFmpegPrivate::open()
avctx->width = width; // coded_width works, why?
avctx->height = height;
// reset format_used to user defined format. important to update default format if format is invalid
format_used = format.pixelFormat();
AVPixelFormat hwfmt = AVPixelFormat(-1);
if (format.pixelFormat() == VideoFormat::Format_Invalid) {
if (codec->pix_fmts) {
qDebug("use first supported pixel format: %d", codec->pix_fmts[0]);
format_used = VideoFormat::pixelFormatFromFFmpeg((int)codec->pix_fmts[0]);
} else {
qWarning("pixel format and supported pixel format are not set. use yuv420p");
format_used = VideoFormat::Format_YUV420P;
format_used = VideoFormat::Format_Invalid;
AVPixelFormat fffmt = (AVPixelFormat)format.pixelFormatFFmpeg();
if (codec->pix_fmts && format.isValid()) {
for (int i = 0; codec->pix_fmts[i] != AVPixelFormat(-1); ++i) {
if (fffmt == codec->pix_fmts[i]) {
format_used = format.pixelFormat();
break;
}
}
}
//avctx->sample_aspect_ratio =
AVPixelFormat hwfmt = AVPixelFormat(-1);
if (av_pix_fmt_desc_get(codec->pix_fmts[0])->flags & AV_PIX_FMT_FLAG_HWACCEL)
hwfmt = codec->pix_fmts[0];
bool use_hwctx = false;
Expand All @@ -169,19 +169,24 @@ bool VideoEncoderFFmpegPrivate::open()
const void *hwcfg = NULL;
AVHWFramesConstraints *constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx, hwcfg);
const AVPixelFormat* in_fmts = constraints->valid_sw_formats;
AVPixelFormat sw_fmt = AVPixelFormat(-1);
if (in_fmts) {
sw_fmt = in_fmts[0];
while (*in_fmts != AVPixelFormat(-1)) {
if (*in_fmts == fffmt)
sw_fmt = *in_fmts;
sw_fmts.append(*in_fmts);
++in_fmts;
}
} else {
sw_fmt = QTAV_PIX_FMT_C(YUV420P);
}
av_hwframe_constraints_free(&constraints);
if (format_used == AVPixelFormat(-1))
format_used = VideoFormat::pixelFormatFromFFmpeg(sw_fmts[0]);
format_used = VideoFormat::pixelFormatFromFFmpeg(sw_fmt);
// encoder surface pool parameters
AVHWFramesContext* hwfs = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
hwfs->format = hwfmt; // must the same as avctx->pix_fmt
hwfs->sw_format = sw_fmts[0]; // if it's not set, vaapi will choose the last valid_sw_formats, but that's wrong for vaGetImage/DeriveImage. nvenc always need sw_format
hwfs->sw_format = sw_fmt; // if it's not set, vaapi will choose the last valid_sw_formats, but that's wrong for vaGetImage/DeriveImage. nvenc always need sw_format
// hw upload parameters. encoder's hwframes is just for parameter checking, will never be intialized, so we allocate an individual one.
hwframes_ref = av_hwframe_ctx_alloc(hw_device_ctx);
if (!hwframes_ref) {
Expand All @@ -194,11 +199,24 @@ bool VideoEncoderFFmpegPrivate::open()
#endif //HAVE_AVHWCTX
}

if (!use_hwctx) {
if (!use_hwctx) { // no hw device (videotoolbox, wrong device name etc.), or old ffmpeg
// TODO: check frame is hw frame
if (hwfmt != AVPixelFormat(-1)) {
// FIXME: check whether incoming format is supported
//format_used = VideoFormat::pixelFormatFromFFmpeg((int)codec->pix_fmts[0]);
if (hwfmt == AVPixelFormat(-1)) { // sw enc
if (format_used == VideoFormat::Format_Invalid) {// requested format is not supported by sw enc
if (codec->pix_fmts) { //pix_fmts[0] is always a sw format here
qDebug("use first supported pixel format '%d' for sw encoder", codec->pix_fmts[0]);
format_used = VideoFormat::pixelFormatFromFFmpeg((int)codec->pix_fmts[0]);
}
}
} else {
if (format_used == VideoFormat::Format_Invalid) { // requested format is not supported by hw enc
qDebug("use first supported sw pixel format '%d' for hw encoder", codec->pix_fmts[1]);
if (codec->pix_fmts && codec->pix_fmts[1] != AVPixelFormat(-1))
format_used = VideoFormat::pixelFormatFromFFmpeg(codec->pix_fmts[1]);
}
}
if (format_used == VideoFormat::Format_Invalid) {
qWarning("fallback to yuv420p");
format_used = VideoFormat::Format_YUV420P;
}
avctx->pix_fmt = (AVPixelFormat)VideoFormat::pixelFormatToFFmpeg(format_used);
Expand All @@ -213,8 +231,8 @@ bool VideoEncoderFFmpegPrivate::open()
if(avctx->codec_id == QTAV_CODEC_ID(H264)) {
avctx->gop_size = 10;
//avctx->max_b_frames = 3;//h264
av_dict_set(&dict, "preset", "fast", 0);
av_dict_set(&dict, "tune", "zerolatency", 0);
av_dict_set(&dict, "preset", "fast", 0); //x264
av_dict_set(&dict, "tune", "zerolatency", 0); //x264
//av_dict_set(&dict, "profile", "main", 0); // conflict with vaapi (int values)
}
if(avctx->codec_id == AV_CODEC_ID_HEVC){
Expand Down Expand Up @@ -314,10 +332,10 @@ bool VideoEncoderFFmpeg::encode(const VideoFrame &frame)
// reinit or got an unsupported format. assume parameters will not change, so it's the 1st init
// check constraints
bool init_frames_ctx = d.hwframes->sw_format == AVPixelFormat(-1);
pixfmt = d.sw_fmts[0];
if (d.sw_fmts.contains(pixfmt)) { // format changed
init_frames_ctx = true;
} else { // convert to supported sw format
pixfmt = d.sw_fmts[0];
f->format = pixfmt;
VideoFrame converted = frame.to(VideoFormat::pixelFormatFromFFmpeg(pixfmt));
for (int i = 0; i < converted.planeCount(); ++i) {
Expand Down

0 comments on commit 568f8c7

Please sign in to comment.